32 Commits

Author SHA1 Message Date
Ralf Zerres
85d9216fc1 upgrade to v0.6.10
* update README
2025-08-05 12:00:24 +02:00
Ralf Zerres
6982aafaff shellcheck corrections 2025-08-05 01:14:31 +02:00
Ralf Zerres
e8d5576e02 print out return value of btrfs send-revieve pipe 2025-08-05 01:14:31 +02:00
Ralf Zerres
b90e34e596 adapt transfer_size calculation
- only used when using interactive mode
- consume precise values when using btrfs qgroup functionality
- consume btrfs df values otherwise
- convert 1000 as base values (kB, MB,GB, TB) to be handled via
  via pv (B,M,G,T)
2025-08-05 01:14:13 +02:00
Ralf Zerres
9e7e5b4d28 correct bug handling subvolume creation on target 2025-08-04 10:27:18 +02:00
Ralf Zerres
01f37814d7 Examples.md: Describe inclusion of existing snapper config caches 2025-08-04 10:27:17 +02:00
Ralf Zerres
050ee9a23a dsnap-sync: update handling of ssh-command 2025-08-04 10:27:17 +02:00
Ralf Zerres
4e162f5df3 README: bump version to v0.6.9 2025-08-04 10:27:16 +02:00
Ralf Zerres
29020bcdbf dsnap-sync: update to v0.6.9
- improve handling of incemental snapshots
- update documenting strings
2025-08-04 10:27:16 +02:00
Ralf Zerres
12c0543752 README: bump version to v0.6.8 2025-08-04 10:27:16 +02:00
Ralf Zerres
56bfaf7a8f dsnap-sync: update PKGBUILD for 0.6.8 2025-08-04 10:27:15 +02:00
Ralf Zerres
96d4238c59 dsnyp-sync: update to v0.6.8
- cleanup quoting/indenting
- typo correction
- temporary directory output
- introduce calculate-btrfs-size flag
2025-08-04 10:27:15 +02:00
Ralf Zerres
56ea8181e4 dsnap-sync: new flags --calculate-btrfs-size, --no-btrfs-quota 2025-08-04 10:26:57 +02:00
Ralf Zerres
52ac00b354 update for v.0.6.7 2025-08-04 10:26:20 +02:00
173f8624bb PKGBUILD: update arch build version
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:20 +02:00
aaad72e2d6 TODO: update wording
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:19 +02:00
0aefc86116 Makefile: update year for Copyright
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:19 +02:00
43469d52c9 update .gitignore
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:19 +02:00
b840aa4372 debian: update build files
* bump version to 0.6.6
* update install directories

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:18 +02:00
837dc27a56 README: bump version to v0.6.6
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:18 +02:00
1bbe32fec8 function update for v.0.6.6
* code cleanup (using `shellcheck`)
* SUBVOLUME check (omitting double leading /)
* get_snapper_sync_id()

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:17 +02:00
5c03be6fe9 find_snapper_config: update file mode
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:17 +02:00
5644f009f7 dsnap-sync: update documentation to comply with v0.6.5
* english README.md
* german README.md

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:17 +02:00
261756df64 dsnap-sync: update PKGBUILD
* pkgver: 0.6.5

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:16 +02:00
97e99fb458 dsnap-sync: Documentation update
* update to v6.5.1

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:16 +02:00
76cd41e7d8 Documentation: update README in line with v6.5.0
* README.md (english)
* README.md (german)
* correction the relative path selection

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:15 +02:00
66e483ddf1 README.md: explain restore method for saved files on LTFS tape
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:15 +02:00
5c9dc9c45b dsnap-sync: correction for tranfer_size calculation
* adapt btrfs output to be compatible with pv requested format
  convert MiB or GiB to M or G

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:15 +02:00
48c784b35d dsnap-sync: handle transfer size
* new function check_transfer_size()
  will calculate the transfer size send via btrfs-send
* update run_backup()
  - handle dryrun
  - handle crate-pv_cmd()
  - send incremantal size

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:14 +02:00
01c9e511a5 tape-admin: 0.0.15 version bump
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:14 +02:00
015b8b212e tape-admin: indentation update
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:26:13 +02:00
a82fa5bbe1 tape-admin: basic function feedback
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2025-08-04 10:25:59 +02:00
15 changed files with 3259 additions and 2959 deletions

3
.gitignore vendored
View File

@@ -0,0 +1,3 @@
*.html
*.bak
*~

View File

@@ -1,7 +1,7 @@
# dsnap-sync
# https://github.com/rzerres/dsnap-sync
# Copyright (C) 2016, 2017 James W. Barnett
# Copyright (C) 2017 - 2019 Ralf Zerres
# Copyright (C) 2017 - 2021 Ralf Zerres
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by

View File

@@ -1,8 +1,8 @@
# Maintainer: Ralf Zerres <ralf.zerres.de at gmail dot com>
# Maintainer: Ralf Zerres <ralf.zerres at mail dot de>
pkgname=dsnap-sync
pkgver=0.6.0
pkgver=0.6.8
pkgrel=1
pkgdesc="Use snapper snapshots to backup to external drive"
pkgdesc="BTRFS centric backups tool supporting snapper history for snapshot backups"
arch=(any)
url="https://github.com/rzerres/dsnap-sync"
license=('GPL')
@@ -11,7 +11,7 @@ optdepends=('attr' 'ionice' 'jq: for "MediaPool" functionality' 'libnotify' 'ltf
source=(${url}/releases/download/$pkgver/$pkgname-$pkgver.tar.gz{,.sig})
#validpgpkeys=('8535CEF3F3C38EE69555BF67E4B5E45AA3B8C5C3')
sha512sums=('SKIP')
'SKIP')
'SKIP')
package() {
cd $pkgname

146
README.md
View File

@@ -1,12 +1,12 @@
<!-- dsnap-sync README.md -->
<!-- version: 0.5.9 -->
<!-- version: 0.6.10 -->
# dsnap-sync
<p align="center">
<span>English</span> |
<!-- a href="lang/spanish#dsnap-sync">Spanish</a> | -->
<a href="lang/german#dsnap-sync">Deutsch</a>
<!-- a href="lang/spanish">Spanish</a> | -->
<a href="lang/german">Deutsch</a>
</p>
## About
@@ -140,17 +140,17 @@ Following tools are used:
`dsnap-sync` is a shell script. Thus no compilation is required.
To simplify correct target locations, this project uses a Makefile.
# make install
# make install
If your system uses a non-default location for the snapper
configuration defaults, specify the location with an environment variable
(`SNAPPER_CONFIG`).
Arch Linux/Fedora/Gentoo:
# make SNAPPER_CONFIG=/etc/conf.d/snapper install
Arch Linux/Fedora/Gentoo:
# make SNAPPER_CONFIG=/etc/conf.d/snapper install
Debian/Ubuntu:
# make SNAPPER_CONFIG=/etc/default/snapper install
Debian/Ubuntu:
# make SNAPPER_CONFIG=/etc/default/snapper install
The local `snapper` configuration will be extended to make use
of a new template 'dsnap-sync'.
@@ -172,41 +172,43 @@ Please use your host software package manager.
## Options
Usage: dsnap-sync [options]
Usage: dsnap-sync [options]
Options:
-a, --automount <path> start automount for given path to get a valid target mountpoint.
-b, --backupdir <prefix> backupdir is a relative path that will be appended to target backup-root
--backuptype <type> Specify backup type <archive | child | parent>
--batch no user interaction
-d, --description <desc> Change the snapper description. Default: "latest incremental backup"
--label-finished <desc> snapper description tagging successful jobs. Default: "dsnap-sync backup"
--label-running <desc> snapper description tagging active jobs. Default: "dsnap-sync in progress"
--label-synced <desc> snapper description tagging last synced jobs.
Default: "dsnap-sync last incremental"
--color Enable colored output messages
-c, --config <config> Specify the snapper configuration to use. Otherwise will perform for each snapper
configuration. You can select multiple configurations
(e.g. -c "root" -c "home"; --config root --config home)
--config-postfix <name> Specify a postfix that will be appended to the destination snapper config name.
--dry-run perform a trial run (no changes are written).
--mediapool Specify the name of the tape MediaPool
-n, --noconfirm Do not ask for confirmation for each configuration. Will still prompt for backup
--nonotify Disable graphical notification (via dbus)
--nopv Disable graphical progress output (disable pv)
--noionice Disable setting of I/O class and priority options on target
-r, --remote <address> Send the snapshot backup to a remote machine. The snapshot will be sent via ssh
You should specify the remote machine's hostname or ip address. The 'root' user
must be permitted to login on the remote machine
-p, --port <port> The remote port
-s, --subvolid <subvlid> Specify the subvolume id of the mounted BTRFS subvolume to back up to. Defaults to 5.
--use-btrfs-quota use btrfs-quota to calculate snapshot size
-u, --uuid <UUID> Specify the UUID of the mounted BTRFS subvolume to back up to. Otherwise will prompt
If multiple mount points are found with the same UUID, will prompt for user selection
-t, --target <target> Specify the mountpoint of the backup device
--volumename Specify the name of the tape volume
-v, --verbose Be verbose on what's going on (min: --verbose=1, max: --verbose=3)
--version show program version
Options:
-a, --automount <path> start automount for given path to get a valid target mountpoint.
-b, --backupdir <prefix> backupdir is a relative path that will be appended to target backup-root
--backuptype <type> Specify backup type <archive | child | parent>
--batch no user interaction
-d, --description <desc> Change the snapper description. Default: "latest incremental backup"
--label-finished <desc> snapper description tagging successful jobs. Default: "dsnap-sync backup"
--label-running <desc> snapper description tagging active jobs. Default: "dsnap-sync in progress"
--label-synced <desc> snapper description tagging last synced jobs.
Default: "dsnap-sync last incremental"
--calculate-btrfs-size Enable calculation of sync-size for given snapshots
--color Enable colored output messages
-c, --config <config> Specify the snapper configuration to use. Otherwise will perform for each snapper
configuration. You can select multiple configurations
(e.g. -c "root" -c "home"; --config root --config home)
--config-postfix <name> Specify a postfix that will be appended to the destination snapper config name.
--dry-run perform a trial run (no changes are written).
--mediapool Specify the name of the tape MediaPool
--no-btrfs-quota don't consume btrfs-quota to estimate snapshot size
-n, --noconfirm Do not ask for confirmation for each configuration. Will still prompt for backup
--nonotify Disable graphical notification (via dbus)
--nopv Disable graphical progress output (disable pv)
--noionice Disable setting of I/O class and priority options on target
-r, --remote <address> Send the snapshot backup to a remote machine. The snapshot will be sent via ssh
You should specify the remote machine's hostname or ip address. The 'root' user
must be permitted to login on the remote machine
-p, --port <port> The remote port
-s, --subvolid <subvlid> Specify the subvolume id of the mounted BTRFS subvolume to back up to. Defaults to 5.
--use-btrfs-quota use btrfs-quota to calculate snapshot size
-u, --uuid <UUID> Specify the UUID of the mounted BTRFS subvolume to back up to. Otherwise will prompt
If multiple mount points are found with the same UUID, will prompt for user selection
-t, --target <target> Specify the mountpoint of the backup device
--volumename Specify the name of the tape volume
-v, --verbose Be verbose on what's going on (min: --verbose=1, max: --verbose=3)
--version show program version
## First run
@@ -259,7 +261,7 @@ backup types are differenciated:
* create a config specific subdirectory (`archive-<config-name>`)
* create a snapshot-id subdirectory (`<snapper-id>`)
* create the btrfs stream file inside the subdirectory
(`<snapper-id>_[full | incremental].btrfs`)
(`<snapper-id>_[full | incremental].btrfs`)
* the proccess metadata are saved to a file called `info.xml`
If you enabled the `ltfs` package, support for backups to tape is possible.
@@ -304,6 +306,62 @@ FUSE). Read and write access can be managed using common OS tools.
An open-source implementation can be found at
[LinearTapeFileSystem](https://github.com/LinearTapeFileSystem/ltfs).
## Restore
### From Snapshot
When `dsnap-sync` did save the data using a native btrfs method
(`btrfs-snapshot` or `btrfs-clone`), data will be stored in a snapper compatible
directory structure on the target.
The structure may look like:
* └ backups
* └ @\<server-name\>
* └ \<subvol-name\>
* └ \<subvol-id\>
* ├ \.snapshot\>
* └ info.xml
To restore the data, you may either use `snapper` methods or copy back
the needed files using standard OS tools.
* using snapper
You may use `snapper diff <id1>..<id2> [files]` to compare the differences
between the given suvol-id's.
You may use `snapper rollback <id> ` to restore all data from the given \<id\>
* using OS tools
Use your favorit file-manager and change into the directory storing your
target backup subvol-id. The snapshots are stored in **read-only** mode.
Data are presented flat file and can be copied to any desired destination.
### From Tape
When `dsnap-sync` did save the data with method `btrfs-archive`, you will find
the corresponding data in a snapper compatible directory structure on the tape.
The structure may look like:
* └ backups
* └ @\<server-name\>
* └ archive-\<subvol-name\>
* └ \<subvol-id\>
* ├ \<subvol-id\>_full.btrfs
* └ info.xml
The file `info.xml` provides the metadata corresponding to the snapshot.
The data of the snapshot is stored in the file `<subvol-id>_full.btrfs`.
This file has to be decrypted with btrfs tool `btrfs-send` to a btrfs
restore directory:
cd /target_btrfs_path
cp /path_to_tape_root/backups/@<server-name>/archive-<subvol-name>/<subvol-id>_full.btrfs .
cat <subvol-id>_full.btrfs | btrfs receive -v .
rm <subvol-id>_full.btrfs
Please consult btrfs-send man-page for further info.
## Contributing
Help is very welcome! Feel free to fork and issue a pull request to add
@@ -331,4 +389,4 @@ This work is licensed under a [Creative Common License 4.0][License-CC_BY]
![Creative Common Logo][Logo-CC_BY]
© 2016, 2017 James W. Barnett;
© 2017 - 2018 Ralf Zerres
© 2017 - 2025 Ralf Zerres

10
TODO.md
View File

@@ -4,14 +4,14 @@
- dsnap-sync: restore btrfs-streams from archive backups
* find last full
* iterate oval available incrementals
* iterate over available incremental snapshots
- dsnap-sync: restore btrfs snapshot from snapshot backups
* $ssh btrfs send `<snapshot_path>/<snapshot-id>/snapshot_ro` | btrfs receive `/<btrfs-restore-dir>/`
(`recieved_uuid` attribte of `<btrfs-restore-dir>/snapshot_ro` will be imported from `<snapshot_path>/<snapshot-id>/snapshot_ro`)
(`recieved_uuid` attribte of `<btrfs-restore-dir>/snapshot_ro` will be imported from `<snapshot_path>/<snapshot-id>/snapshot_ro`)
* btrfs sub snap `<btrfs-restore-dir>/snapshot_ro` `<btrfs-restore-dir>/snapshot_rw`
(create a writable `snapshot_rw`; its attibute `received_uuid` isn't set anymore)
(create a writable `snapshot_rw`; its attibute `received_uuid` isn't set anymore)
* sub delete `<btrfs-restore-dir>/snapshot_ro`
now you are able to mount the snapshot for further processing
now you are able to mount the snapshot for further processing
- dsnap-sync: parallel tasks per config
- consider mbuffer for splitting up btrfs streams
@@ -50,7 +50,7 @@
- download Source code (zip-file | tar.gz file) to local dir
- on local dir
* gpg --sign-with `<secret package-signing-key id>`
--armor
--armor
--detach-sign dsnap-sync-`<tag>`.tar.gz
- on github: create/edit release
* attach binaries by dropping them here or `selecting them`

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,7 @@
# Helper routines for tape handling
progname="${0##*/}"
version="0.0.14"
version="0.0.15"
# global variables
color=0
@@ -140,7 +140,7 @@ add_retensiondays_to_retensiondate () {
if [ $? -eq 0 ]; then
cmd="jq --monochrome-output --ascii-output '(.MediaPool[] \
| select(.Name == \"$mediapool_name\") \
| .Member[$tape_index] \
| .Member[$tape_index] \
| .RetensionDate) \
|= \"$volume_retensiondate\" ' \
${mediapools_json} > $XDG_RUNTIME_DIR/$json_file"
@@ -148,10 +148,10 @@ add_retensiondays_to_retensiondate () {
if [ $? -eq 0 ]; then
cp "$XDG_RUNTIME_DIR/$json_file" "$mediapools_json"
else
if [ $verbose -ge 1 ]; then
printf "${RED}Error:${MAGENTA} Can't update RetensionDate ${GREEN}'%s'${MAGENTA} for Tape ${GREEN}'%s'${NO_COLOR}\n" \
"$volume_retensiondate" "$volume_name"
fi
if [ $verbose -ge 1 ]; then
printf "${RED}Error:${MAGENTA} Can't update RetensionDate ${GREEN}'%s'${MAGENTA} for Tape ${GREEN}'%s'${NO_COLOR}\n" \
"$volume_retensiondate" "$volume_name"
fi
return 1
fi
else
@@ -294,15 +294,15 @@ get_lastwrite () {
# select last write date for given volume
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
| select(.Name == \"${mediapool_name}\") \
| select(.Name == \"${mediapool_name}\") \
| .Member[] \
| select(.VolumeName == \"${volume_name}\") \
| select(.VolumeName == \"${volume_name}\") \
| .LastWrite ' \
${mediapools_json}"
else
# select volume with latest write date
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
| select(.Name == \"${mediapool_name}\") \
| select(.Name == \"${mediapool_name}\") \
| .Member \
| map({ \"VolumeName\" : .VolumeName, \"LastWrite\" : ( .LastWrite | scan(\"[0-9]{14}\")) }) \
| sort_by(.LastWrite) \
@@ -312,7 +312,7 @@ get_lastwrite () {
volume_name=$(eval $cmd)
volume_name=$(echo $volume_name | sed -e 's/"//g')
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
| select(.Name == \"${mediapool_name}\") \
| select(.Name == \"${mediapool_name}\") \
| .Member \
| map({ \"VolumeName\" : .VolumeName, \"LastWrite\" : ( .LastWrite | scan(\"[0-9]{14}\")) }) \
| sort_by(.LastWrite) \
@@ -351,9 +351,9 @@ get_mediapolicy () {
fi
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
| select(.Name == \"${mediapool_name}\") \
| select(.Name == \"${mediapool_name}\") \
| .Member[] \
| select(.VolumeName == \"${volume_name}\") \
| select(.VolumeName == \"${volume_name}\") \
| .MediaPolicy ' \
${mediapools_json}"
volume_mediapolicy=$(eval $cmd)
@@ -444,8 +444,8 @@ get_mediapool_retensiondays () {
if [ ${#mediapool_name} -ge 1 ]; then
# select default retension days for given pool
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
| select(.Name == \"${mediapool_name}\") \
| .DefaultRetensionDays ' \
| select(.Name == \"${mediapool_name}\") \
| .DefaultRetensionDays ' \
${mediapools_json}"
fi
mediapool_defaultretensiondays=$(eval $cmd)
@@ -483,8 +483,8 @@ get_poolmember () {
fi
cmd="jq --monochrome-output --ascii-output '.MediaPool[] \
| select(.Name == \"${mediapool_name}\") \
| .Member[].VolumeName' \
| select(.Name == \"${mediapool_name}\") \
| .Member[].VolumeName' \
${mediapools_json}"
poolmember=$(eval $cmd)
poolmember=$(echo $poolmember | sed -e 's/"//g')
@@ -496,16 +496,16 @@ get_poolmember () {
i=0
for i in $poolmember ; do
if [ "$volume_name" = "any" ]; then
volume_name=$i
if [ "$volume_name" = "any" ]; then
volume_name=$i
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}selecting first volume_name ${GREEN}'%s'${MAGENTA} from media-pool ${GREEN}'%s'${NO_COLOR}\n" \
"$i" "$mediapool_name"
fi
return 0
break
fi
if test "$i" = "${volume_name}"; then
fi
if test "$i" = "${volume_name}"; then
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}volume_name ${GREEN}'%s'${MAGENTA} is member of media-pool ${GREEN}'%s'${NO_COLOR}\n" \
"$i" "$mediapool_name"
@@ -541,7 +541,7 @@ get_poolmember_next () {
return 1
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
| select(.Name == \"${mediapool_name}\") \
| select(.Name == \"${mediapool_name}\") \
| .Member \
| map({ \"VolumeName\" : .VolumeName, \"LastWrite\" : ( .LastWrite | scan(\"[0-9]{14}\")) }) \
| sort_by(.LastWrite) \
@@ -601,9 +601,9 @@ get_slot () {
return 1
cmd="jq --monochrome-output --ascii-output ' .MediaPool[] \
| select(.Name == \"${mediapool_name}\") \
| select(.Name == \"${mediapool_name}\") \
| .Member[] \
| select(.VolumeName == \"${volume_name}\") \
| select(.VolumeName == \"${volume_name}\") \
| .Slot ' \
${mediapools_json}"
volume_slot=$(eval $cmd)
@@ -639,9 +639,9 @@ get_retensiondate () {
return 1
cmd="jq --monochrome-output --ascii-output '(.MediaPool[] \
| select(.Name == \"${mediapool_name}\") \
| select(.Name == \"${mediapool_name}\") \
| .Member[] \
| select(.VolumeName == \"${volume_name}\")) \
| select(.VolumeName == \"${volume_name}\")) \
| .RetensionDate ' \
${mediapools_json}"
volume_retensiondate=$(eval $cmd)
@@ -724,8 +724,8 @@ ltfs_format () {
fi
if [ ${#volume_serial} -eq 0 ]; then
tape_id=$(echo $volume_name | sed -e 's/\([[:alpha:]]*-\)//g')
# tape_id needs to be exactly 6 character long
tape_id=$(echo $volume_name | sed -e 's/\([[:alpha:]]*-\)//g')
# tape_id needs to be exactly 6 character long
volume_serial=$(printf "%0.s0" $(seq 1 $((6 - ${#tape_id}))))
volume_serial="${volume_serial}${tape_id}"
fi
@@ -778,7 +778,7 @@ ltfs_mount () {
if [ ! -d $ltfs_mountpoint ]; then
mkdir -p $ltfs_mountpoint
fi
make_err_file
make_err_file
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}LTFS mounting tape ${GREEN}'%s'${MAGENTA} to ${GREEN}'%s'${NO_COLOR}\n" \
"$ltfs_devname" "$ltfs_mountpoint"
@@ -791,16 +791,16 @@ ltfs_mount () {
return 0
else
# format tape if needed
if [ -z $volume_name_active ]; then
slot_source="0"
mtx_getlabel $slot_source
fi
need_format=$(grep "medium is not partitioned" ${ERRFILE})
rm -f ${ERRFILE}
if [ ${#need_format} -ge 1 ]; then
if [ -z $volume_name_active ]; then
slot_source="0"
mtx_getlabel $slot_source
fi
need_format=$(grep "medium is not partitioned" ${ERRFILE})
rm -f ${ERRFILE}
if [ ${#need_format} -ge 1 ]; then
ltfs_format ${volume_name_active}
ltfs_mount
fi
ltfs_mount
fi
return $?
fi
else
@@ -901,8 +901,8 @@ ltfs_reformat () {
fi
# wiping: put tape in an unformatted state
ltfs_wipe
# RET = 8 -> error?
if [ $? -eq 0 ]; then
# format: create the ltfs partitions
ltfs_format $volume_name_active $volume_serial
if [ $? -eq 0 ]; then
ltfs_mount
@@ -1091,7 +1091,7 @@ mount_tape () {
ltfs_is_mounted
if test $? -eq 0; then
# get date from last written tape in given mediapool
# if no explicit tape should be mounted, get date from last written tape in given mediapool
if [ "${#volume_name}" -eq 0 ]; then
get_lastwrite ${mediapool_name}
if [ $? != 0 ]; then
@@ -1106,7 +1106,7 @@ mount_tape () {
printf "${MAGENTA}Active tape in drive: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name_active}"
fi
if [ "${#volume_name_active}" -ge 1 ] && [ "${volume_name_active}" != "${volume_name}" ]; then
if [ "${#volume_name_active}" -ge 1 ] && [ "${volume_name_active}" != "${volume_name}" ]; then
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}Re-Mounting requested Tape: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name}"
@@ -1128,92 +1128,94 @@ mount_tape () {
# check if given tape is poolmember of selected pool
get_poolmember ${mediapool_name} ${volume_name}
if [ $? -eq 0 ]; then
# volume_name is member of given mediapool
# check the mediapolicy for given volume_name
get_mediapolicy ${mediapool_name} ${volume_name_active}
if [ ${#volume_mediapolicy} -gt 0 ]; then
if [ ${volume_mediapolicy} = "append" ] ; then
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}Valid tape mediapolicy: ${GREEN}%s${NO_COLOR}\n" \
"${volume_mediapolicy}"
fi
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}Valid tape mediapolicy: ${GREEN}%s${NO_COLOR}\n" \
"${volume_mediapolicy}"
fi
volume_retensiondate="20180101000000"
get_retensiondate ${mediapool_name} ${volume_name}
if [ $? -eq 0 ]; then
if [ $? -eq 0 ]; then
date_now=$($date_cmd)
compare_date $date_now $volume_retensiondate
if [ $? -eq 2 ]; then
compare_date $date_now $volume_retensiondate
if [ $? -eq 2 ]; then
# retensiondate has exposed: use it
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Valid tape, retensiondate has exposed: ${GREEN}%s${NO_COLOR}\n" \
"${volume_retensiondate}"
fi
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Valid tape, retensiondate has exposed: ${GREEN}%s${NO_COLOR}\n" \
"${volume_retensiondate}"
fi
#ltfs_format ${volume_name_active}
ltfs_reformat ${volume_name_active}
return 0
fi
if [ $? -eq 1 ]; then
fi
if [ $? -eq 1 ]; then
# respect active retensiondate: unload given tape
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Invalid tape ${GREEN}%s${MAGANTA}, respect retensiondate: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name}" "${volume_retensiondate}"
fi
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Invalid tape ${GREEN}%s${MAGANTA}, respect retensiondate: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name}" "${volume_retensiondate}"
fi
ltfs_umount
mtx_unload
# use next volume_name from pool
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Get next tape from MediaPool ${GREEN}%s${MAGANTA}\n" \
"${mediapool_name}"
fi
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Get next tape from MediaPool ${GREEN}%s${MAGANTA}\n" \
"${mediapool_name}"
fi
get_poolmember_next ${mediapool_name} ${volume_name}
get_slot ${mediapool_name} ${volume_name_next}
mtx_load ${volume_slot}
ltfs_mount
if [ $? -eq 0 ]; then
return 0
return 0
fi
fi
fi
return 0
fi
if [ ${volume_mediapolicy} = "overwrite" ] ; then
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}Valid tape mediapolicy: ${GREEN}%s${NO_COLOR}\n" \
"${volume_mediapolicy}"
fi
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}Valid tape mediapolicy: ${GREEN}%s${NO_COLOR}\n" \
"${volume_mediapolicy}"
fi
volume_retensiondate="20180101000000"
get_retensiondate ${mediapool_name} ${volume_name}
date_now=$($date_cmd)
compare_date $date_now $volume_retensiondate
if [ $? -eq 2 ]; then
date_now=$($date_cmd)
compare_date $date_now $volume_retensiondate
if [ $? -eq 2 ]; then
# retensiondate has exposed: wipe given tape
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Valid tape, wipe and reformat: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name}"
fi
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Valid tape, wipe and reformat: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name}"
fi
ltfs_wipe
#ltfs_format ${volume_name} ${volume_serial}
if [ $? -eq 0 ]; then
return 0
fi
fi
if [ $? -eq 1 ]; then
#ltfs_reformat ${volume_name_active}
if [ $? -eq 0 ]; then
return 0
fi
fi
if [ $? -eq 1 ]; then
# respect active retensiondate: unload given tape
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Invalid tape ${GREEN}%s${MAGANTA}, respect retensiondate: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name}" "${volume_retensiondate}"
fi
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Invalid tape ${GREEN}%s${MAGANTA}, respect retensiondate: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name}" "${volume_retensiondate}"
fi
ltfs_umount
mtx_unload
# use next volume_name from pool
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Get next tape from MediaPool ${GREEN}%s${MAGANTA}\n" \
"${mediapool_name}"
fi
if [ $verbose -ge 3 ]; then
printf "${MAGENTA}Get next tape from MediaPool ${GREEN}%s${MAGANTA}\n" \
"${mediapool_name}"
fi
get_poolmember_next ${mediapool_name} ${volume_name}
get_slot ${mediapool_name} ${volume_name_next}
mtx_load ${volume_slot}
ltfs_mount
if [ $? -eq 0 ]; then
if [ $? -eq 0 ]; then
return 0
fi
fi
fi
fi
fi
fi
fi
@@ -1258,14 +1260,14 @@ mount_tape () {
printf "${MAGENTA}Tape in drive: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name_active}"
fi
if [ "${#volume_name_active}" -gt 1 ] && [ "${volume_name_active}" != "${volume_name}" ]; then
if [ "${#volume_name_active}" -gt 1 ] && [ "${volume_name_active}" != "${volume_name}" ]; then
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}Active tape ${GREEN}%s${MAGENTA} needs to be exchanged with ${GREEN}%s${NO_COLOR}\n" \
"${volume_name_active}" "${volume_name}"
fi
mtx_unload
if [ $? -eq 0 ]; then
mount_tape "${mediapool_name}" "${volume_name}"
mount_tape "${mediapool_name}" "${volume_name}"
if [ $? -eq 0 ]; then
return 0
else
@@ -1287,25 +1289,25 @@ mount_tape () {
get_mediapolicy ${mediapool_name} ${volume_name}
if [ ${#volume_mediapolicy} -gt 0 ]; then
if [ ${volume_mediapolicy} = "append" ] ; then
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}Valid tape mediapolicy: ${GREEN}%s${NO_COLOR}\n" \
"${volume_mediapolicy}"
fi
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}Valid tape mediapolicy: ${GREEN}%s${NO_COLOR}\n" \
"${volume_mediapolicy}"
fi
#volume_retensiondate="20180101000000"
get_retensiondate ${mediapool_name} ${volume_name}
date_now=$($date_cmd)
compare_date $date_now $volume_retensiondate
RET=$?
date_now=$($date_cmd)
compare_date $date_now $volume_retensiondate
RET=$?
if [ $RET -eq 2 ]; then
if [ $verbose -ge 1 ]; then
printf "${MAGENTA}RetensionDate has exposed, mount the tape\n"
fi
printf "${MAGENTA}RetensionDate has exposed, mount the tape${NO_COLOR}\n"
fi
ltfs_mount
return 0
elif [ $RET -eq 1 ]; then
if [ $verbose -ge 1 ]; then
printf "${MAGENTA}Tape is bocked via RetensionDate.\n"
fi
fi
get_poolmember_next "${mediapool_name}"
if test $? -eq 0; then
if [ $verbose -ge 2 ]; then
@@ -1316,22 +1318,22 @@ mount_tape () {
mount_tape "${mediapool_name}" "${volume_name_next}"
return 0
fi
fi
fi
fi
if [ ${volume_mediapolicy} = "overwrite" ] ; then
volume_retensiondate="20180101000000"
get_retensiondate ${mediapool_name} ${volume_name}
date_now=$($date_cmd)
compare_date $date_now $volume_retensiondate
if [ $? -eq 2 ]; then
date_now=$($date_cmd)
compare_date $date_now $volume_retensiondate
if [ $? -eq 2 ]; then
# retensiondate has exposed: wipe given tape
ltfs_wipe
#ltfs_format ${volume_name} ${volume_serial}
ltfs_format ${volume_name} ${volume_serial}
if [ $? -eq 0 ]; then
return 0
return 0
fi
fi
if [ $? -eq 1 ]; then
fi
if [ $? -eq 1 ]; then
# respect active retensiondate: unload given tape
mtx_unload
if [ $? -eq 0 ]; then
@@ -1384,9 +1386,9 @@ mtx_getlabel () {
"${MTX}" "${changer_device}" "${slot_source}"
fi
volume_name_active=$(perl -ne '
/Data Transfer Element (\d+):Full \(Storage Element (\d+) Loaded\)(:VolumeTag =\s*(.+))?/ && print "$4\n";' ${TMPFILE})
volume_name_active=$(echo $volume_name_active | sed -e 's/ *$//g')
if [ $verbose -ge 2 ]; then
/Data Transfer Element (\d+):Full \(Storage Element (\d+) Loaded\)(:VolumeTag =\s*(.+))?/ && print "$4\n";' ${TMPFILE})
volume_name_active=$(echo $volume_name_active | sed -e 's/ *$//g')
if [ $verbose -ge 2 ] && [ ${#volume_name_active} -gt 0 ]; then
printf "${MAGENTA}Tape in slot ${GREEN}%s${MAGENTA} has Label: ${GREEN}%s${NO_COLOR}\n" \
"${slot_source}" "${volume_name_active}"
fi
@@ -1397,8 +1399,8 @@ mtx_getlabel () {
"${MTX}" "${changer_device}" "${slot_source}"
fi
volume_name=$(perl -ne '
/Storage Element ($ENV{"slot_source"}):Full( :VolumeTag=(.+))?/ && print "$3\n";' ${TMPFILE})
volume_name=$(echo $volume_name | sed -e 's/ *$//g')
/Storage Element ($ENV{"slot_source"}):Full( :VolumeTag=(.+))?/ && print "$3\n";' ${TMPFILE})
volume_name=$(echo $volume_name | sed -e 's/ *$//g')
if [ $verbose -ge 2 ]; then
printf "${MAGENTA}Tape in slot ${GREEN}%s${MAGENTA} has Label: ${GREEN}%s${NO_COLOR}\n" \
"${slot_source}" "${volume_name}"
@@ -2030,7 +2032,7 @@ update_lastwrite () {
if [ $? -eq 0 ]; then
cmd="jq --monochrome-output --ascii-output '(.MediaPool[] \
| select(.Name == \"$mediapool_name\") \
| .Member[$tape_index] \
| .Member[$tape_index] \
| .LastWrite) \
|= \"$volume_lastwrite\" ' \
${mediapools_json} > $XDG_RUNTIME_DIR/$json_file"
@@ -2082,10 +2084,10 @@ update_mediapool_retensiondays () {
if [ $? -eq 0 ]; then
cp "$XDG_RUNTIME_DIR/$json_file" "$mediapools_json"
else
if [ $verbose -ge 1 ]; then
printf "${RED}Error:${MAGENTA} Can't update DefaultRetensinDays ${GREEN}'%s'${MAGENTA} in media-pool file ${GREEN}'%s'${NO_COLOR}\n" \
"$mediapool_defaultretensiondays" "$mediapools_json"
fi
if [ $verbose -ge 1 ]; then
printf "${RED}Error:${MAGENTA} Can't update DefaultRetensinDays ${GREEN}'%s'${MAGENTA} in media-pool file ${GREEN}'%s'${NO_COLOR}\n" \
"$mediapool_defaultretensiondays" "$mediapools_json"
fi
return 1
fi
else
@@ -2138,7 +2140,7 @@ update_retensiondate () {
if [ $? -eq 0 ]; then
cmd="jq --monochrome-output --ascii-output '(.MediaPool[] \
| select(.Name == \"$mediapool_name\") \
| .Member[$tape_index] \
| .Member[$tape_index] \
| .RetensionDate) \
|= \"$volume_retensiondate\" ' \
${mediapools_json} > $XDG_RUNTIME_DIR/$json_file"
@@ -2146,10 +2148,10 @@ update_retensiondate () {
if [ $? -eq 0 ]; then
cp "$XDG_RUNTIME_DIR/$json_file" "$mediapools_json"
else
if [ $verbose -ge 1 ]; then
printf "${RED}Error:${MAGENTA} Can't update RetensionDate ${GREEN}'%s'${MAGENTA} for Tape ${GREEN}'%s'${NO_COLOR}\n" \
"$volume_retensiondate" "$volume_name"
fi
if [ $verbose -ge 1 ]; then
printf "${RED}Error:${MAGENTA} Can't update RetensionDate ${GREEN}'%s'${MAGENTA} for Tape ${GREEN}'%s'${NO_COLOR}\n" \
"$volume_retensiondate" "$volume_name"
fi
return 1
fi
else
@@ -2171,62 +2173,62 @@ Usage: $progname [options]
Options:
--add-retensiondays add RetensionDays to LastWrite attribute for given TapeName in Pool (JSON-File)
(input attribute: <mediapool> <volume_name> <days>)
(input attribute: <mediapool> <volume_name> <days>)
--color Enable colored output messages
--get-lastwrite extract LastWrite attribute from given Pool member (JSON-File)
(input attribute: <mediapool> [<volume_name>])
without given volume_name, extract Pool member that was last witten to
(input attribute: <mediapool> [<volume_name>])
without given volume_name, extract Pool member that was last witten to
--get-mediapool-name extract MediaPool name for given VolumeName from configuration (JSON-File)
(input attribute: <volume_name>)
(input attribute: <volume_name>)
--get-mediapools extract MediaPool names from configuration (JSON-File)
--get-mediapolicy extract MediaPolicy attribute from Pool configuration (JSON-File)
(input attribute: <mediapool> [<volume_name>])
(input attribute: <mediapool> [<volume_name>])
--get-poolmember extract VolumeName attribute from Pool configuration (JSON-File)
(input attribute: <mediapool> [<volume_name>])
(input attribute: <mediapool> [<volume_name>])
--get-poolmember-next extract VolumeName for next usable Pool member (JSON-File)
(input attribute: <mediapool> [volume_name])
(input attribute: <mediapool> [volume_name])
--get-retensiondate extract RetensionDate attribute from Pool configuration (JSON-File)
(input attribute: <mediapool> [<volume_name>])
(input attribute: <mediapool> [<volume_name>])
--get-retensiondays extract DefaultRetensionDays attribute from Pool configuration (JSON-File)
(input attribute: <mediapool>)
(input attribute: <mediapool>)
--get-slot extract Slot attribute from Pool configuration (JSON-File)
(input attribute: <mediapool> [<volume_name>])
(input attribute: <mediapool> [<volume_name>])
--ltfs-getattribute report ltfs extended attribute for mounted tape
(input attribute: <ltfs_attribute>)
(input attribute: <ltfs_attribute>)
--ltfs-format format tape
(input attribute: <volume_name> <tape_id>)
(input attribute: <volume_name> <tape_id>)
--ltfs-is-mounted returns true, if ltfs tape is already mounted
--ltfs-mount mount a ltfs tape (returns true on success)
--ltfs-reformat reformat mounted tape
(input attribute: [<volume_name>])
(input attribute: [<volume_name>])
--ltfs-umount unmount a ltfs tape (returns true on success)
--media-change Update RetensionDate for last written Pool-Tape and und exchange tapes in slots
(input attribute: <mediapool> [<volume_name>])
(input attribute: <mediapool> [<volume_name>])
--mtx-exchange exchange tapes in slots
(input attribute: <slot_source> <slot_target>)
(input attribute: <slot_source> <slot_target>)
--mtx-getlabel report tape label/barcode for tape in drive
(input attribute: <slot_source>)
(input attribute: <slot_source>)
--mtx-inventory run inquriy task for tape-changer
--mtx-load load a tape to target slot
(input attribute: <slot_source>)
(input attribute: <slot_source>)
--mtx-status list changer slot status
--mtx-transfer transfer a tape to target slot
(input attribute: <slot_source> <slot_target>)
(input attribute: <slot_source> <slot_target>)
--mtx-unload unload a tape
(input attribute: slot_source drive)
(input attribute: slot_source drive)
--mount make tape accessible for OS
(input attribute: <mediapool_name> [<volume_name>])
(input attribute: <mediapool_name> [<volume_name>])
-q, --quiet Be quiet
--update-lastwrite update LastWrite attribute for given TapeName in Pool (JSON-File)
if no datestring is specified, use "now"
if no datestring is specified, use "now"
(input attribute: <mediapool> <volume_name> [<YYYYMMDDHHMMSS> )
--update-retensiondate update RetensionDate attribute for given TapeName in Pool (JSON-File)
if no datestring is specified, use "now"
if no datestring is specified, use "now"
(input attribute: <mediapool> <volume_name> [<YYYYMMDDHHMMSS> )
--update-retensiondays update DefaultRetensionDays attribute for given Pool (JSON-File)
(input attribute: <mediapool>)
(input attribute: <mediapool>)
--use-mtx use mtx loader handling. If not specified, all mtx commands will use
default device ($default_changer_device)
default device ($default_changer_device)
-v, --verbose Be verbose on what's going on (min: --verbose=1, max: --verbose=3)
--version show program version
EOF
@@ -2273,7 +2275,7 @@ case $cmd in
"${volume_name}" "${volume_date}"
fi
fi
;;
;;
get-lastwrite)
valid_member=0
get_lastwrite "${mediapool_name}" "${volume_name}"
@@ -2289,7 +2291,7 @@ case $cmd in
fi
fi
fi
;;
;;
get-mediapolicy)
get_mediapolicy "${mediapool_name}" "${volume_name}"
if test $? -gt 0; then
@@ -2300,7 +2302,7 @@ case $cmd in
"${volume_name}" "${volume_mediapolicy}"
fi
fi
;;
;;
get-mediapool-name)
get_mediapool_name "${volume_name}"
if test $? -gt 0; then
@@ -2311,7 +2313,7 @@ case $cmd in
"${mediapool_name}"
fi
fi
;;
;;
get-mediapools)
get_mediapool_names
if test $? -gt 0; then
@@ -2322,7 +2324,7 @@ case $cmd in
"${mediapool_names}"
fi
fi
;;
;;
get-poolmember)
valid_member=0
get_poolmember "${mediapool_name}" "${volume_name}"
@@ -2335,7 +2337,7 @@ case $cmd in
fi
valid_member=1
fi
;;
;;
get-poolmember-next)
valid_member=0
get_poolmember_next "${mediapool_name}" "${volume_name}"
@@ -2347,7 +2349,7 @@ case $cmd in
"${mediapool_name}" "${volume_name_next}"
fi
fi
;;
;;
get-mediapool-retensiondays)
get_mediapool_retensiondays "${mediapool_name}"
if test $? -gt 0; then
@@ -2358,7 +2360,7 @@ case $cmd in
"${mediapool_name}" "${mediapool_defaultretensiondays}"
fi
fi
;;
;;
get-retensiondate)
get_retensiondate "${mediapool_name}" "${volume_name}"
if test $? -gt 0; then
@@ -2371,7 +2373,7 @@ case $cmd in
"${volume_name}" "${volume_date}"
fi
fi
;;
;;
get-slot)
get_slot "${mediapool_name}" "${volume_name}"
if test $? -eq 0; then
@@ -2381,7 +2383,7 @@ case $cmd in
fi
fi
exit $?
;;
;;
ltfs-format)
ltfs_format "${volume_name}" "${tape_id}"
if test $? -gt 0; then
@@ -2405,78 +2407,72 @@ case $cmd in
fi
;;
ltfs-is-mounted)
if ! $quiet; then
printf "${MAGENTA}LTFS tape mount checke\n"
fi
ltfs_is_mounted
if test $? -gt 0; then
exit 1
else
if ! $quiet; then
printf "${MAGENTA}LTFS Tape is-mounted: ${GREEN}true${NO_COLOR}\n"
fi
fi
;;
ltfs-mount)
if ! $quiet; then
printf "${MAGENTA}LTFS mount Tape\n"
fi
ltfs_mount
if test $? -gt 0; then
exit 1
else
if ! $quiet; then
printf "${MAGENTA}LTFS Tape mount: ${GREEN}true${NO_COLOR}\n"
fi
fi
;;
ltfs-reformat)
if ! $quiet; then
printf "${MAGENTA}LTFS Tape reformat: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name}"
fi
ltfs_reformat "${volume_name}"
if test $? -gt 0; then
return 1
else
if ! $quiet; then
printf "${MAGENTA}LTFS Tape reformat: ${GREEN}%s${NO_COLOR}\n" \
"${volume_name}"
fi
fi
;;
ltfs-umount)
if ! $quiet; then
printf "${MAGENTA}LTFS Tape unmount: ${GREEN}true${NO_COLOR}\n"
fi
ltfs_umount
if test $? -gt 0; then
exit 1
else
if ! $quiet; then
printf "${MAGENTA}LTFS Tape unmount: ${GREEN}true${NO_COLOR}\n"
fi
fi
;;
media-change)
if ! $quiet; then
if [ ${#volume_name} -ge 1 ]; then
printf "${MAGENTA}Media change in pool: ${GREEN}%s${NO_COLOR} (Volume-Name: ${GREEN}%s${NO_COLOR})\n" \
"${mediapool_name}" "${volume_name}"
else
printf "${MAGENTA}Media change in pool: ${GREEN}%s${NO_COLOR}\n" \
"${mediapool_name}"
fi
fi
media_change $mediapool_name $volume_name
if test $? -gt 0; then
return 1
else
if ! $quiet; then
if [ ${#volume_name} -ge 1 ]; then
printf "${MAGENTA}Media changed in pool: ${GREEN}%s${NO_COLOR} (Volume-Name: ${GREEN}%s${NO_COLOR})\n" \
"${mediapool_name}" "${volume_name}"
else
printf "${MAGENTA}Media changed in pool: ${GREEN}%s${NO_COLOR}\n" \
"${mediapool_name}"
fi
fi
fi
;;
mount)
mount_tape "${mediapool_name}" "${volume_name}"
if test $? -gt 0; then
exit 1
else
if ! $quiet; then
if test ${#volume_name} -ge 1; then
printf "${MAGENTA}Tape ${GREEN}'%s'${MAGENTA} for ${GREEN}'%s'${MAGENTA} mounted${NO_COLOR}\n" \
"${volume_name}" "${mediapool_name}"
else
printf "${MAGENTA}Next tape for mediapool ${GREEN}'%s'${MAGENTA} mounted${NO_COLOR}\n" \
"${mediapool_name}"
fi
if ! $quiet; then
if test ${#volume_name} -ge 1; then
printf "${MAGENTA}Mount tape ${GREEN}'%s'${MAGENTA} for ${GREEN}'%s'${NO_COLOR}\n" \
"${volume_name}" "${mediapool_name}"
else
printf "${MAGENTA}Mount next tape for mediapool ${GREEN}'%s'${NO_COLOR}\n" \
"${mediapool_name}"
fi
fi
;;
mount_tape "${mediapool_name}" "${volume_name}"
if test $? -gt 0; then
exit 1
fi
;;
mtx-exchange)
mtx_exchange "${slot_source}" "${slot_target}"
exit $?
@@ -2519,7 +2515,7 @@ case $cmd in
fi
fi
fi
;;
;;
update-mediapool-retensiondays)
update_mediapool_retensiondays "${mediapool_name}" "${mediapool_defaultretensiondays}"
if test $? -gt 0; then
@@ -2530,7 +2526,7 @@ case $cmd in
"${mediapool_name}" "${mediapool_defaultretensiondays}"
fi
fi
;;
;;
update-retensiondate)
update_retensiondate "${mediapool_name}" "${volume_name}" "${date_string}"
if test $? -gt 0; then
@@ -2545,5 +2541,5 @@ case $cmd in
fi
fi
fi
;;
;;
esac

37
debian/changelog vendored
View File

@@ -1,37 +0,0 @@
dsnap-sync (0.6.4) unstable; urgency=low
[Ralf Zerres]
* branch: master
-- Ralf Zerres <rzerres@networkx.de> Thu, 14 Mar 2019 09:20:02 +0100
dsnap-sync (0.6.0) unstable; urgency=low
[Ralf Zerres]
* branch: master
* multi-config: handling of multiple configurations as a group
* btrfs-archive: full and incremental stream files
* tape: handling of LTFS tapes
* ionice: optional use in target streams
-- Ralf Zerres <rzerres@networkx.de> Sat, 21 Sep 2018 20:00:00 +0200
dsnap-sync (0.5.9) unstable; urgency=low
[Ralf Zerres]
* branch: wip-d2d
* initial tape-admin wrapper
* automounter support for target devices
* bugfixes
* btrfs quota to read valid snapshot size / change size
* color handling in verbosity-levels
-- Ralf Zerres <rzerres@networkx.de> Sat, 25 Aug 2018 20:00:00 +0200
dsnap-sync (0.5.3) unstable; urgency=low
[Ralf Zerres]
* initial package
* adapt compilation to support ubuntu bionic
-- Ralf Zerres <rzerres@networkx.de> Fri, 1 Jun 2018 21:00:01 +0000

1
debian/compat vendored
View File

@@ -1 +0,0 @@
10

25
debian/control vendored
View File

@@ -1,25 +0,0 @@
Source: dsnap-sync
Section: admin
Priority: optional
Maintainer: Networkx GmbH <support@networkx.de>
Build-Depends: debhelper (>= 10), dh-exec
Uploaders: Ralf Zerres <ralf.zerres@networkx.de>
Standards-Version: 4.1.4.1
Homepage: https://github.com/rzerres/dsnap-sync.git
Package: dsnap-sync
Architecture: amd64
Conflicts: snap-sync
Depends: dash, snapper, btrfs-progs, systemd
Suggests: pv, libnotify-bin, mtx, jq, ltfs
Description: Backup and synchronize btrfs filesystems
dsnap-sync is designed to backup btrfs formated filesystems. It takes
advantage of the specific snapshots functionality btrfs offers and i
combines it with managemnet functionality of snapper.
.
dsnap-sync creates backups as btrfs-snapshots on a selectable target
device. Plug in and mount any btrfs-formatted device to your system.
Supported devices may be either local USB drives, but can be as well
remote accessible RAID drives. If possible the backup process will send
incremental snapshots to the target drive. If the snapshot will be
stored on a remote host, it is secured with ssh.

View File

@@ -1,3 +0,0 @@
bin/
etc/
usr/

22
debian/rules vendored
View File

@@ -1,22 +0,0 @@
#!/usr/bin/make -f
# debian/rules
# -*- mode: makefile; coding: utf-8 -*-
export DH_VERBOSE=1
#export DESTROOT=$(CURDIR)/debian/dsnap-sync
export DESTDIR=$(CURDIR)/debian/dsnap-sync
%:
# dh $@ --sourcedirectory=src
dh $@
#override_dh_auto_configure:
# dh_auto_configure --sourcedirectory=src -- --prefix=/usr
override_dh_auto_install:
dh_auto_install -- prefix=/usr
#override_dh_install:
# dh_install
# dh_missing --fail-missing

0
find_snapper_config Normal file → Executable file
View File

View File

@@ -1,8 +1,14 @@
<!-- dsnap-sync README.md -->
<!-- version: 0.5.9 -->
<!-- version: 0.6.9 -->
# dsnap-sync
<p align="center">
<span>English</span> |
<a href="../..">Englisch</a>
<!-- a href="../spanish">Spanisch</a> | -->
</p>
## Über
`dsnap-sync` ist konzipiert, um Backups für btrfs formatierte Dateisysteme
@@ -138,17 +144,17 @@ Folgende Tools werden verwendet:
erforderlich. Über ein Makefile wird die Installation an den
richtigen Ziel-Pfad gesteuert.
# make install
# make install
Sollte Ihr System einen unüblichen Speicherort für die snapper
Konfigurationen verwenden, kann der Pfad in einer Umgebungs-Variable
für die Installation einbezogen werden (`SNAPPER_CONFIG`).
Arch Linux/Fedora/Gentoo:
# make SNAPPER_CONFIG=/etc/conf.d/snapper install
Arch Linux/Fedora/Gentoo:
# make SNAPPER_CONFIG=/etc/conf.d/snapper install
Debian/Ubuntu:
# make SNAPPER_CONFIG=/etc/default/snapper install
Debian/Ubuntu:
# make SNAPPER_CONFIG=/etc/default/snapper install
Die lokalen `snapper` Konfiguration werden um ein neues Template
'dsnap-sync' ergänzt.
@@ -172,41 +178,42 @@ Software Paket Manager.
## Optionen
Usage: dsnap-sync [options]
Usage: dsnap-sync [options]
Options:
-a, --automount <path> start automount for given path to get a valid target mountpoint.
-b, --backupdir <prefix> backupdir is a relative path that will be appended to target backup-root
--backuptype <type> Specify backup type <archive | child | parent>
--batch no user interaction
-d, --description <desc> Change the snapper description. Default: "latest incremental backup"
--label-finished <desc> snapper description tagging successful jobs. Default: "dsnap-sync backup"
--label-running <desc> snapper description tagging active jobs. Default: "dsnap-sync in progress"
--label-synced <desc> snapper description tagging last synced jobs.
Default: "dsnap-sync last incremental"
--color Enable colored output messages
-c, --config <config> Specify the snapper configuration to use. Otherwise will perform for each snapper
configuration. You can select multiple configurations
(e.g. -c "root" -c "home"; --config root --config home)
--config-postfix <name> Specify a postfix that will be appended to the destination snapper config name.
--dry-run perform a trial run (no changes are written).
--mediapool Specify the name of the tape MediaPool
-n, --noconfirm Do not ask for confirmation for each configuration. Will still prompt for backup
--nonotify Disable graphical notification (via dbus)
--nopv Disable graphical progress output (disable pv)
--noionice Disable setting of I/O class and priority options on target
-r, --remote <address> Send the snapshot backup to a remote machine. The snapshot will be sent via ssh
You should specify the remote machine's hostname or ip address. The 'root' user
must be permitted to login on the remote machine
-p, --port <port> The remote port
-s, --subvolid <subvlid> Specify the subvolume id of the mounted BTRFS subvolume to back up to. Defaults to 5.
--use-btrfs-quota use btrfs-quota to calculate snapshot size
-u, --uuid <UUID> Specify the UUID of the mounted BTRFS subvolume to back up to. Otherwise will prompt
If multiple mount points are found with the same UUID, will prompt for user selection
-t, --target <target> Specify the mountpoint of the backup device
--volumename Specify the name of the tape volume
-v, --verbose Be verbose on what's going on (min: --verbose=1, max: --verbose=3)
--version show program version
Options:
-a, --automount <path> start automount for given path to get a valid target mountpoint.
-b, --backupdir <prefix> backupdir is a relative path that will be appended to target backup-root
--backuptype <type> Specify backup type <archive | child | parent>
--batch no user interaction
-d, --description <desc> Change the snapper description. Default: "latest incremental backup"
--label-finished <desc> snapper description tagging successful jobs. Default: "dsnap-sync backup"
--label-running <desc> snapper description tagging active jobs. Default: "dsnap-sync in progress"
--label-synced <desc> snapper description tagging last synced jobs.
Default: "dsnap-sync last incremental"
--calculate-btrfs-size Enable calculation of sync-size for given snapshots
--color Enable colored output messages
-c, --config <config> Specify the snapper configuration to use. Otherwise will perform for each snapper
configuration. You can select multiple configurations
(e.g. -c "root" -c "home"; --config root --config home)
--config-postfix <name> Specify a postfix that will be appended to the destination snapper config name.
--dry-run perform a trial run (no changes are written).
--mediapool Specify the name of the tape MediaPool
-n, --noconfirm Do not ask for confirmation for each configuration. Will still prompt for backup
--nonotify Disable graphical notification (via dbus)
--nopv Disable graphical progress output (disable pv)
--noionice Disable setting of I/O class and priority options on target
-r, --remote <address> Send the snapshot backup to a remote machine. The snapshot will be sent via ssh
You should specify the remote machine's hostname or ip address. The 'root' user
must be permitted to login on the remote machine
-p, --port <port> The remote port
-s, --subvolid <subvlid> Specify the subvolume id of the mounted BTRFS subvolume to back up to. Defaults to 5.
--use-btrfs-quota use btrfs-quota to calculate snapshot size
-u, --uuid <UUID> Specify the UUID of the mounted BTRFS subvolume to back up to. Otherwise will prompt
If multiple mount points are found with the same UUID, will prompt for user selection
-t, --target <target> Specify the mountpoint of the backup device
--volumename Specify the name of the tape volume
-v, --verbose Be verbose on what's going on (min: --verbose=1, max: --verbose=3)
--version show program version
## Erster Sicherungslauf
@@ -264,7 +271,7 @@ sorgen. Folgende Sicherungstypen werden unterschieden:
* ein Unterverzeichnis des Konfigurations-Namens (`archive-<config-name>`)
* ein Unterverzeichnis der Snapshot-ID (`<snapper-id>`)
* der aktuelle btrfs Stream wird im Unterverzeichnis abgelegt
(`<snapper-id>_[full | incremental].btrfs`)
(`<snapper-id>_[full | incremental].btrfs`)
* die Metadaten des Prozesses werden in der Datei `info.xml` abgelegt
Steht `ltfs` zur Verfügung, ist ein Backup auf Bänder möglich.
@@ -326,6 +333,66 @@ dann mit den gewohnten Betriebssystem Tools. Eine Open-Source Implementierung
finden Sie z.B. unter
[LinearTapeFileSystem](https://github.com/LinearTapeFileSystem/ltfs).
## Rücksicherung (restore)
### Dateisystem (target)
Wurden Daten mit einer nativen btrfs Methode (`btrfs-snapshot`,
`btrfs-clone`) gesichert, befinden sie sich in einer `snapper` kompatiblen
Verzeichnisstruktur auf dem gewählten Target.
Diese Struktur könnte so aussehen:
* └ backups
* └ @\<server-name\>
* └ \<subvol-name\>
* └ \<subvol-id\>
* ├ \.snapshot\>
* └ info.xml
Um Daten zurückzusichern, können Sie entweder native `snapper` Methoden verwenden,
oder auf Betriebssystem Programme zurückgreifen.
* native snapper Methoden
Verwenden Sie `snapper diff <id1>..<id2> [Dateien]`, um Unterschiede in den
gewählten subvol-id's aufzuzeigen.
Verwenden Sie `snapper rollback <id>`, um alle Daten der Sicherung (\<subvol-id\>)
an den Ursprungsort zurückzusichern.
* Betriebssystem Programme
Verwenden Sie Ihren bevorzugten Datei-Manager und wechseln Sie in das
Verzeichnis, in dem sich die Daten des gewünschten Backups (\<subvol-id\>)
befinden. Die Daten wurden als **read-only** Snapshot gesichert.
Sie können von hier aus in jedes gewünsche Zielverzeichnis kopiert werden.
### Band-Sicherung (tape)
Wurden Daten mit der Methode `btrfs-archive` gesichert, speichert `dsnap-sync`
diese in einer `snapper` kompatiblen Datei-Struktur auf dem Band.
Dies Struktur könnte so aussehen:
* └ backups
* └ @\<server-name\>
* └ archive-\<subvol-name\>
* └ \<subvol-id\>
* ├ \<subvol-id\>_full.btrfs
* └ info.xml
In der Datei `info.xml` werden die Metadaten zum Snapshot gespeichert.
Die Bewegungsdaten des snapshots befinden sich in der Datei `\<subvol-id\>_full.btrfs`.
Diese Datei muss mit dem btrfs programm `btrfs-send` auf ein btrfs Verzeichnis zurück
geschrieben werden:
cd /target_btrfs_path
cp /path_to_tape_root/backups/@<server-name>/archive-<subvol-name>/<subvol-id>_full.btrfs .
cat <subvol-id>_full.btrfs | btrfs receive -v .
rm <subvol-id>_full.btrfs
Die man-page zu `btrfs-send` enthält weiterführende Informationen.
## Mitarbeit
Hilfe ist sehr willkommen! Gerne könnt Ihr das Projekt forken und PR's einreichen,
@@ -357,4 +424,4 @@ Diese Arbeit ist unter der [Creative Common License 4.0][License-CC_BY] lizensie
![Creative Common Logo][Logo-CC_BY]
© 2016, 2017 James W. Barnett;
© 2017 - 2018 Ralf Zerres
© 2017 - 2023 Ralf Zerres

View File

@@ -1,5 +1,25 @@
# Examples
## Snapper configs cache
To integrate already existing snapshop subfolders located on a given
filesystem, you need to add the snapper config name to the config
file. Then restart the snapper service to reread the config list.
```
[root@dwsbackup dsnap-sync]# cat /etc/conf.d/snapper
## Path: System/Snapper
## Type: string
## Default: ""
# List of snapper configurations.
#SNAPPER_CONFIGS="root data.dwssrv1 home.dwssrv1 machines.dwssrv1 root.dwssrv1 libvirt.dwssrv1 data2.dwssrv1 lxd.dwssrv1 archiv2.dwssrv1 archiv3.dwssrv1 root.dwssrv2"
SNAPPER_CONFIGS="root data.dwssrv1"
[root@dwsbackup dsnap-snyc]# systemctl restart snapperd
```
## Automounter
`dsnap-sync` will take advantage of systemd automount units to incorporate external,