|
|
|
@@ -3,9 +3,23 @@
|
|
|
|
|
import { program } from "commander"
|
|
|
|
|
import { parseJSON, parseTOML, stringifyJSON } from "confbox"
|
|
|
|
|
import fs from "node:fs"
|
|
|
|
|
import path from "node:path"
|
|
|
|
|
import strftime from 'strftime'
|
|
|
|
|
import { spawnSync } from "node:child_process"
|
|
|
|
|
|
|
|
|
|
function logToFile() {
|
|
|
|
|
// Source - https://stackoverflow.com/a/35542360
|
|
|
|
|
// Posted by Anatol - user3173842
|
|
|
|
|
// Retrieved 2026-01-14, License - CC BY-SA 3.0
|
|
|
|
|
|
|
|
|
|
var access = fs.createWriteStream('/etc/snapback/log.txt');
|
|
|
|
|
process.stdout.write = process.stderr.write = access.write.bind(access);
|
|
|
|
|
|
|
|
|
|
process.on('uncaughtException', function (err) {
|
|
|
|
|
console.error((err && err.stack) ? err.stack : err);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let config: { [key: string]: string } = {}
|
|
|
|
|
let index: { [key: string]: { [key: string]: string } } = {}
|
|
|
|
|
|
|
|
|
@@ -35,43 +49,58 @@ program.command('*').description('snapback ignores unknown commands')
|
|
|
|
|
program.command('install').description('installs snapback on your system')
|
|
|
|
|
.action(function () {
|
|
|
|
|
const template = fs.readFileSync(import.meta.dirname + '/snapper-template.txt')
|
|
|
|
|
const service = fs.readFileSync(import.meta.dirname + '/snapper@.service')
|
|
|
|
|
const service = fs.readFileSync(import.meta.dirname + '/snapback@.service')
|
|
|
|
|
let lib_snapper = '/usr/libexec/snapper'
|
|
|
|
|
if (!fs.existsSync(lib_snapper)) lib_snapper = '/usr/lib/snapper'
|
|
|
|
|
if (!fs.existsSync('/etc/snapper/config-templates')) fs.mkdirSync('/etc/snapper/config-templates')
|
|
|
|
|
fs.writeFileSync('/etc/snapper/config-templates/snapback', template, 'utf8')
|
|
|
|
|
fs.writeFileSync('/etc/systemd/system/snapper@.service', service, 'utf8')
|
|
|
|
|
fs.writeFileSync('/etc/systemd/system/snapback@.service', service, 'utf8')
|
|
|
|
|
fs.mkdirSync(lib_snapper + '/plugins', { recursive: true })
|
|
|
|
|
fs.renameSync(import.meta.url, lib_snapper + '/plugins/99-snapback')
|
|
|
|
|
let argv0 = process.argv0
|
|
|
|
|
if (['node','deno','bun'].includes(path.basename(argv0).replace('.exe',''))) {
|
|
|
|
|
argv0 = import.meta.url
|
|
|
|
|
}
|
|
|
|
|
fs.renameSync(argv0, lib_snapper + '/plugins/99-snapback')
|
|
|
|
|
sugoiSpawn('chmod', '+x', lib_snapper + '/plugins/99-snapback')
|
|
|
|
|
sugoiSpawn('systemctl','daemon-reload')
|
|
|
|
|
console.log('snapback installed')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
program.command('create-snapshot-post <subvolume> <fstype> <number>')
|
|
|
|
|
.description('create a backup after a snapshot')
|
|
|
|
|
.action(function (subvolume, fstype, number) {
|
|
|
|
|
logToFile()
|
|
|
|
|
if (!config[subvolume]) return
|
|
|
|
|
const destination = strftime(config[subvolume])
|
|
|
|
|
const dirname = path.dirname(destination)
|
|
|
|
|
try { fs.mkdirSync(dirname, { 'recursive': true }) } catch {}
|
|
|
|
|
sugoiSpawn('tar',
|
|
|
|
|
`--directory=${subvolume}/.snapshots/${number}/snapshot`,
|
|
|
|
|
'--create', '--file', destination,
|
|
|
|
|
'--auto-compress', '--dereference', '.'
|
|
|
|
|
)
|
|
|
|
|
index[subvolume][number] = destination
|
|
|
|
|
console.log('created backup at '+destination)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
program.command('delete-snapshot-post <subvolume> <fstype> <number>')
|
|
|
|
|
.description('delete a backup after deleting a snapshot')
|
|
|
|
|
.action(function (subvolume, fstype, number) {
|
|
|
|
|
logToFile()
|
|
|
|
|
const destination = index[subvolume][number]
|
|
|
|
|
fs.unlinkSync(destination)
|
|
|
|
|
delete index[subvolume][number]
|
|
|
|
|
console.log('deleted backup at '+destination)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
program.command('delete-config-post <subvolume> <fstype>')
|
|
|
|
|
.description('delete metadata of deleted subvolume, retaining backups')
|
|
|
|
|
.action(function (subvolume, fstype) {
|
|
|
|
|
logToFile()
|
|
|
|
|
delete index[subvolume]
|
|
|
|
|
const destination = strftime(config[subvolume])
|
|
|
|
|
const dirname = path.dirname(destination)
|
|
|
|
|
console.log('existing backups remain at '+dirname)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
program.parse()
|
|
|
|
|