Compare commits

..

56 Commits

Author SHA1 Message Date
Jonathan Carter
92db087bb0
Merge pull request #109 from mergwyn/master
Correct incorrect sh syntax
2019-09-30 09:30:55 +02:00
mergwyn
f938d9cc1c
Correct incorrect sh syntax
'==' is not valid in sh
2019-09-25 23:13:21 +01:00
Jonathan Carter
4538217932 Clear trailing whitespaces 2019-09-25 13:30:46 +00:00
Jonathan Carter
99e1a6103d Initiate changelog 2019-09-25 13:25:05 +00:00
Jonathan Carter
86a95095ee
Add note about macos compatibility 2019-09-25 15:13:00 +02:00
Jonathan Carter
363a847ee3
Merge pull request #94 from aimileus/macos
Support macOS with Homebrew gnu-getopt
2019-09-25 15:10:13 +02:00
Jonathan Carter
12945110d3
Merge pull request #107 from ArakniD/master
Updated zfs-auto-snapshot.sh
2019-09-25 15:08:23 +02:00
Jonathan Carter
d5646c901e
Install from release instead of master
Install from release instead of master
2019-09-25 15:06:33 +02:00
Lucas Oldfield
4a59d0d615
Updated zfs-auto-snapshot.sh
Updated old snapshot removal to include the optional snapshot label
2019-09-07 14:56:30 +10:00
Jonathan Carter
ef7ae674f5
Merge pull request #98 from diablodale/missing-log-info
fix for verbose logging not working
2019-04-12 22:54:42 +02:00
Jonathan Carter
b0a5909335
Merge pull request #42 from FransUrbo/snapname_fix
Fix SNAPNAME and SNAPGLOB.
2019-04-12 22:53:29 +02:00
Jonathan Carter
3689b2c43d
Merge pull request #91 from schors/master
Fix recursive snapshots
2019-04-12 22:47:53 +02:00
Jonathan Carter
d27bbfa650
Merge pull request #96 from diablodale/uninstall
add uninstall - fix zfsonlinux/zfs-auto-snapshot#95
2019-04-12 22:47:29 +02:00
Jonathan Carter
897ca026e1
Merge pull request #59 from rkarlsba/patch-3
Added --min-size
2019-04-12 22:46:38 +02:00
Jonathan Carter
3e48c8956e
Merge pull request #100 from jsoref/spelling
spelling: construction
2019-04-12 22:35:17 +02:00
Josh Soref
3efc478828 spelling: construction 2018-11-25 20:32:28 -05:00
Dale Phurrough
c99de67c63
fix verbose logging
- corrects regression introduced
2018-10-15 18:20:13 +02:00
Dale Phurrough
4425d681f3
add uninstall - fix zfsonlinux/zfs-auto-snapshot#95
- intentionally does not remove directories
- intentionally does not force deletes
2018-10-13 19:50:50 +02:00
Emiel Wiedijk
6f6d1202cf
Support macOS with Homebrew gnu-getopt 2018-09-29 11:09:27 +02:00
Phil Kulin
6ee4553cf6 Fix jjj vs jj bug in recursive snapshot selection 2018-07-12 13:03:07 +03:00
Phil Kulin
6c7da10e24 Fix recursive snapshot 2018-07-11 17:32:57 +03:00
Jonathan Carter
3d9992b086 Undo PR#82 (fixes #86 and fixes #87) 2018-06-15 13:10:29 +02:00
Jonathan Carter
f145cf6e07 Revert PR85 2018-04-21 09:27:26 +02:00
Jonathan Carter
838b03b41f
Merge pull request #82 from attie/improve_list
Improve performance of listings
2018-04-17 13:34:47 +02:00
Jonathan Carter
e1268767b8
Merge pull request #85 from riyad/fix-recursive-snapshots-with-noauto-descendants
Fix recursive snapshots for datasets with noauto descendants
2018-04-17 13:33:38 +02:00
Riyad Preukschas
e93096c2d9 Fix recursive snapshots for datasets with noauto descendants
Fixes #80
2018-04-11 14:38:22 +02:00
Jonathan Carter
1ae1adc5f0
Merge pull request #79 from jbnance/man-page-perms
Set permissions on man page to 0644 when installing
2018-03-13 14:14:13 +02:00
Attie Grande
41eddc97cc only list entities that we are interested in 2018-01-18 17:22:30 +00:00
Jason Nance
2b7b694a95 Set permissions on man page to 0644 when installing 2017-12-27 15:34:39 -06:00
Jonathan Carter
277287f824 Further cron logic cleanups 2017-09-18 09:25:02 +02:00
Jonathan Carter
d49be6a2de Merge pull request #69 from mailinglists35/patch-4
make --quiet really quiet
2017-09-14 11:22:43 +02:00
Jonathan Carter
2e1f309131 Merge pull request #68 from lindhe/fix-broken-cron
Fix broken cron scripts
2017-07-11 13:44:13 +02:00
mailinglists35
1666623191 make --quiet really quiet
--quiet still prints the name of the datasets when print_log is called at lines 548/551
2017-07-06 13:15:56 +03:00
Andreas Lindhé
739972f18a Found a way to exec the process and yet have it work 2017-07-06 09:20:54 +02:00
Andreas Lindhé
8c45add2c0 Fix broken cron scripts
I found that none of the daily, hourly, weekly or monthly snapshots were
being taken. When I looked into it I found that the scripts didn't
execute properly, because of the newly introduced check (9c6f065).

I'm not versed enough with POSIX to understand if there was some clever
intention with using exec than just calling which by it self, but it
works without exec so I removed it.
2017-07-05 23:21:29 +02:00
Jonathan Carter
9c6f065589 Check whether we have zfs-auto-snapshot before running it 2017-06-06 11:06:16 +02:00
Jonathan Carter
62f5f7d920 Merge pull request #33 from aphor/master
zfs destroy will use -d for deferred destruction
2017-01-27 20:28:01 +02:00
Jonathan Carter
b74769894c Merge pull request #35 from bernhardschmidt/master
Fix frequent cronjob
2017-01-27 20:08:24 +02:00
Jonathan Carter
11130ba8d6 Merge pull request #43 from FransUrbo/prettify_SNAPSHOTS_OLD
"Prettify" long command line
2017-01-27 20:07:39 +02:00
rkarlsba
27413ac798 Added --min-size
Added an option to inhibit generation of empty (or very small) snapshots.
2017-01-16 00:59:13 +01:00
Turbo Fredriksson
c4ad5eeac5 Break up the huge line where SNAPSHOTS_OLD (if --fast was used) to make
it easier to read and follow.
2015-04-03 17:34:16 +02:00
Turbo Fredriksson
6e32b25d8f Fix SNAPNAME and SNAPGLOB.
* Currently the following command line:

    zfs-auto-snapshot.sh.orig --keep 7 --label daily --prefix '' --sep '-' \
      --event "daily-$(date --utc +"%Y%m%d.%H%M")" --recursive --verbose //

  will give the following result:

    zfs snapshot -o com.sun:auto-snapshot-desc='daily-20150403.0013' \
      -r 'share/.Bacula@-daily-2015-04-03-0013'

* If instead 'prefix=daily', this would be the result:

    zfs snapshot -o com.sun:auto-snapshot-desc='daily-20150403.0015' \
      -r 'share/.Bacula@daily-daily-2015-04-03-0016'

* If 'prefix=daily' and 'label=NULL':

    zfs snapshot -o com.sun:auto-snapshot-desc='daily-20150403.0017' \
      -r 'share@daily'

This because SNAPNAME is constructed wrongly. Instead, only separate
the 'prefix' from the 'label' with 'sep' if 'prefix' is actually set.
2015-04-03 02:12:16 +02:00
Bernhard Schmidt
b2e97c5fe0 use long options in frequent cronjob 2014-12-29 20:07:18 +01:00
Bernhard Schmidt
d3bdd2dc23 include default installation prefix in frequent cronjob 2014-12-29 20:05:26 +01:00
Jeremy McMillan
f2767ad43a zfs destroy will use -d for deferred destruction
I am working on a complimentary script that does log-shipping style replication to a backup volume for highly efficient incremental backups. This relies on "zfs send -R" and that the sets of snapshots existing on the source and backup destination overlap by at least one snapshot. I plan to use snapshot clones to place a "checkpoint" reservation on a snapshot that will be required for future backups.

In order to keep zfs-auto-snapshot from destroying a snapshot necessary for a future incremental backup replication stream, I will create an unmounted clone of that snapshot, and destroy any prior clones when the backup completes. 

Any snapshots destroyed by the zfs-auto-snapshot "zfs destroy -d" will be destroyed as the dependent clones are destroyed. Without the -d option, zfs-auto-snapshot would fail to destroy the old snapshot with a checkpoint clone, and it would persist until later snapshot jobs destroy it in subsequent runs. Since monthlies and weeklies are relatively infrequent, deferred destruction will reap the snapshots opportunistically as soon as the "checkpoint" clones are gone. Intermediate snapshots between the "checkpoint" reserved snapshots and the recent snapshots preserved by the zfs-auto-snapshot.sh will still be immediately destroyed.
2014-11-17 19:21:52 -06:00
Darik Horn
d5cb31aaae Install the cron.d part without the execute bit.
Resolve this lintian error:

	E: zfs-auto-snapshot: bad-permissions-for-etc-cron.d-script etc/cron.d/zfs-auto-snapshot 0755 != 0644
	W: zfs-auto-snapshot: executable-not-elf-or-script etc/cron.d/zfs-auto-snapshot

This should also resolve a related failure on Arch Linux.

Closes: zfsonlinux/zfs-auto-snapshot#4
Thanks: @bitloggerig
Thanks: @scottj97
2014-10-13 23:12:53 -05:00
Darik Horn
1ce72681bf Merge pull request #31 from virtualguy/patch-1
Update README
2014-10-13 20:41:01 -04:00
Darik Horn
a0df1ebcc1 Merge pull request #30 from mbaynton/remove-only
--destroy-only switch, --{pre,post} fixes
2014-10-13 20:39:40 -04:00
Darik Horn
0be4466869 Merge pull request #29 from mmalecki/pre-post
Add pre and post snapshot hooks
2014-10-13 20:37:12 -04:00
Darik Horn
9d2398ed8e Merge pull request #26 from borutmrak/master
Fix manpage path
2014-10-13 20:31:06 -04:00
virtualguy
bc1b65a66e Update README
Add some simple installation instructions
2014-08-18 21:38:32 +12:00
Mike Baynton
bfe4c911a8 Make --{pre,post}-snapshot optional, add --destroy-only, revise docs 2014-08-09 17:23:02 -05:00
Maciej Małecki
10f9b3e336 Document `--{pre,post}-snapshot 2014-08-07 02:08:29 +02:00
Maciej Małecki
c08f366c1c Abort if pre snapshot hook returns non-zero 2014-08-07 02:08:29 +02:00
Maciej Małecki
da5a8bd5b7 Add --{pre,post}-snapshot for pre and post creation hook 2014-08-07 02:08:23 +02:00
Borut Mrak
a1b89b6fef Makefile:
* Remove PREFIX from cron scripts - they should always end up in /etc.
  * Leave PREFIX for man page and program, and set it to /usr/local by default.
2014-04-23 09:31:30 +02:00
10 changed files with 228 additions and 199 deletions

9
CHANGELOG Normal file
View File

@ -0,0 +1,9 @@
[ 1.2.5 (Unreleased) ]
* Start a changelog
* Accept PR#94 from aimileus/macos
- Replace --utc longform option with -u for macos compatibility
* Accept PR#107 from ArakniD/master
- Add optional label for snap removals
-- Jonathan Carter 2019-09-25, 15:24 SAST

View File

@ -1,17 +1,28 @@
PREFIX := /usr/local
all: all:
install: install:
install -d $(DESTDIR)$(PREFIX)/etc/cron.d install -d $(DESTDIR)/etc/cron.d
install -d $(DESTDIR)$(PREFIX)/etc/cron.daily install -d $(DESTDIR)/etc/cron.daily
install -d $(DESTDIR)$(PREFIX)/etc/cron.hourly install -d $(DESTDIR)/etc/cron.hourly
install -d $(DESTDIR)$(PREFIX)/etc/cron.weekly install -d $(DESTDIR)/etc/cron.weekly
install -d $(DESTDIR)$(PREFIX)/etc/cron.monthly install -d $(DESTDIR)/etc/cron.monthly
install etc/zfs-auto-snapshot.cron.frequent $(DESTDIR)$(PREFIX)/etc/cron.d/zfs-auto-snapshot install -m 0644 etc/zfs-auto-snapshot.cron.frequent $(DESTDIR)/etc/cron.d/zfs-auto-snapshot
install etc/zfs-auto-snapshot.cron.hourly $(DESTDIR)$(PREFIX)/etc/cron.hourly/zfs-auto-snapshot install etc/zfs-auto-snapshot.cron.hourly $(DESTDIR)/etc/cron.hourly/zfs-auto-snapshot
install etc/zfs-auto-snapshot.cron.daily $(DESTDIR)$(PREFIX)/etc/cron.daily/zfs-auto-snapshot install etc/zfs-auto-snapshot.cron.daily $(DESTDIR)/etc/cron.daily/zfs-auto-snapshot
install etc/zfs-auto-snapshot.cron.weekly $(DESTDIR)$(PREFIX)/etc/cron.weekly/zfs-auto-snapshot install etc/zfs-auto-snapshot.cron.weekly $(DESTDIR)/etc/cron.weekly/zfs-auto-snapshot
install etc/zfs-auto-snapshot.cron.monthly $(DESTDIR)$(PREFIX)/etc/cron.monthly/zfs-auto-snapshot install etc/zfs-auto-snapshot.cron.monthly $(DESTDIR)/etc/cron.monthly/zfs-auto-snapshot
install -d $(DESTDIR)$(PREFIX)/share/man/man8 install -d $(DESTDIR)$(PREFIX)/share/man/man8
install src/zfs-auto-snapshot.8 $(DESTDIR)$(PREFIX)/share/man/man8/zfs-auto-snapshot.8 install -m 0644 src/zfs-auto-snapshot.8 $(DESTDIR)$(PREFIX)/share/man/man8/zfs-auto-snapshot.8
install -d $(DESTDIR)$(PREFIX)/sbin install -d $(DESTDIR)$(PREFIX)/sbin
install src/zfs-auto-snapshot.sh $(DESTDIR)$(PREFIX)/sbin/zfs-auto-snapshot install src/zfs-auto-snapshot.sh $(DESTDIR)$(PREFIX)/sbin/zfs-auto-snapshot
uninstall:
rm $(DESTDIR)/etc/cron.d/zfs-auto-snapshot
rm $(DESTDIR)/etc/cron.hourly/zfs-auto-snapshot
rm $(DESTDIR)/etc/cron.daily/zfs-auto-snapshot
rm $(DESTDIR)/etc/cron.weekly/zfs-auto-snapshot
rm $(DESTDIR)/etc/cron.monthly/zfs-auto-snapshot
rm $(DESTDIR)$(PREFIX)/share/man/man8/zfs-auto-snapshot.8
rm $(DESTDIR)$(PREFIX)/sbin/zfs-auto-snapshot

9
README
View File

@ -10,3 +10,12 @@ snapshots if it is installed.
This program is a posixly correct bourne shell script. It depends only on This program is a posixly correct bourne shell script. It depends only on
the zfs utilities and cron, and can run in the dash shell. the zfs utilities and cron, and can run in the dash shell.
Installation:
-------------
wget https://github.com/zfsonlinux/zfs-auto-snapshot/archive/upstream/1.2.4.tar.gz
tar -xzf 1.2.4.tar.gz
cd zfs-auto-snapshot-upstream-1.2.4
make install

View File

@ -1,2 +1,6 @@
#!/bin/sh #!/bin/sh
# Only call zfs-auto-snapshot if it's available
which zfs-auto-snapshot > /dev/null || exit 0
exec zfs-auto-snapshot --quiet --syslog --label=daily --keep=31 // exec zfs-auto-snapshot --quiet --syslog --label=daily --keep=31 //

View File

@ -1,3 +1,3 @@
PATH="/usr/bin:/bin:/usr/sbin:/sbin" PATH="/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
*/15 * * * * root zfs-auto-snapshot -q -g --label=frequent --keep=4 // */15 * * * * root which zfs-auto-snapshot > /dev/null || exit 0 ; zfs-auto-snapshot --quiet --syslog --label=frequent --keep=4 //

View File

@ -1,2 +1,6 @@
#!/bin/sh #!/bin/sh
# Only call zfs-auto-snapshot if it's available
which zfs-auto-snapshot > /dev/null || exit 0
exec zfs-auto-snapshot --quiet --syslog --label=hourly --keep=24 // exec zfs-auto-snapshot --quiet --syslog --label=hourly --keep=24 //

View File

@ -1,2 +1,6 @@
#!/bin/sh #!/bin/sh
# Only call zfs-auto-snapshot if it's available
which zfs-auto-snapshot > /dev/null || exit 0
exec zfs-auto-snapshot --quiet --syslog --label=monthly --keep=12 // exec zfs-auto-snapshot --quiet --syslog --label=monthly --keep=12 //

View File

@ -1,2 +1,6 @@
#!/bin/sh #!/bin/sh
# Only call zfs-auto-snapshot if it's available
which zfs-auto-snapshot > /dev/null || exit 0
exec zfs-auto-snapshot --quiet --syslog --label=weekly --keep=8 // exec zfs-auto-snapshot --quiet --syslog --label=weekly --keep=8 //

View File

@ -64,6 +64,27 @@ Snapshot named filesystem and all descendants.
\fB\-v\fR, \fB\-\-verbose\fR \fB\-v\fR, \fB\-\-verbose\fR
Print info messages. Print info messages.
.TP .TP
\fB\-\-pre-snapshot\fR=\fICOMMAND\fR
Command to run before each dataset is snapshotted.
It is passed the dataset and snapshot name. If it
returns non-zero, snapshotting this dataset is
aborted.
.TP
\fB\-\-post-snapshot\fR=\fICOMMAND\fR
Command to run after each dataset is snapshotted.
It is passed the dataset and snapshot name.
.TP
\fB\-\-destroy-only\fR
Do not create new snapshots, but do destroy older
snapshots. Has no effect unless used with \fB\-k\fR.
.IP
A non-obvious use may be construction of cron jobs or
scripts that run pre-snapshot command(s), then run
zfs-auto-snapshot (without \fB\-k\fR) to quickly
snapshot all datasets, then run post-snapshot
command(s) and clean up with zfs-auto-snapshot
\fB\-\-destroy-only\fR.
.TP
name name
Filesystem and volume names, or '//' for all ZFS datasets. Filesystem and volume names, or '//' for all ZFS datasets.
.SH SEE ALSO .SH SEE ALSO

331
src/zfs-auto-snapshot.sh Executable file → Normal file
View File

@ -39,6 +39,10 @@ opt_setauto=''
opt_syslog='' opt_syslog=''
opt_skip_scrub='' opt_skip_scrub=''
opt_verbose='' opt_verbose=''
opt_pre_snapshot=''
opt_post_snapshot=''
opt_do_snapshots=1
opt_min_size=0
# Global summary statistics. # Global summary statistics.
DESTRUCTION_COUNT='0' DESTRUCTION_COUNT='0'
@ -59,10 +63,6 @@ print_usage ()
-n, --dry-run Print actions without actually doing anything. -n, --dry-run Print actions without actually doing anything.
-s, --skip-scrub Do not snapshot filesystems in scrubbing pools. -s, --skip-scrub Do not snapshot filesystems in scrubbing pools.
-h, --help Print this usage message. -h, --help Print this usage message.
-H, --hanoi=INT Use the hanoi rotation scheme.
INT how frequently the hanoi rotation is being run.
It is a number followed by one of w, d, h, m, s for
weeks, days, hours, minutes or seconds.
-k, --keep=NUM Keep NUM recent snapshots and destroy older snapshots. -k, --keep=NUM Keep NUM recent snapshots and destroy older snapshots.
-l, --label=LAB LAB is usually 'hourly', 'daily', or 'monthly'. -l, --label=LAB LAB is usually 'hourly', 'daily', or 'monthly'.
-p, --prefix=PRE PRE is 'zfs-auto-snap' by default. -p, --prefix=PRE PRE is 'zfs-auto-snap' by default.
@ -73,6 +73,7 @@ print_usage ()
-g, --syslog Write messages into the system log. -g, --syslog Write messages into the system log.
-r, --recursive Snapshot named filesystem and all descendants. -r, --recursive Snapshot named filesystem and all descendants.
-v, --verbose Print info messages. -v, --verbose Print info messages.
--destroy-only Only destroy older snapshots, do not create new ones.
name Filesystem and volume names, or '//' for all ZFS datasets. name Filesystem and volume names, or '//' for all ZFS datasets.
" "
} }
@ -110,7 +111,7 @@ print_log () # level, message, ...
;; ;;
(inf*) (inf*)
# test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.info $* # test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.info $*
test -n "$opt_verbose" && echo $* test -z "$opt_quiet" && test -n "$opt_verbose" && echo $*
;; ;;
(deb*) (deb*)
# test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.debug $* # test -n "$opt_syslog" && logger -t "$opt_prefix" -p daemon.debug $*
@ -144,123 +145,6 @@ do_run () # [argv]
} }
do_rotate () # flags, oldglob, target
{
local FLAGS="$1"
local GLOB="$2"
local TARGET="$3"
local KEEP=''
# global DESTRUCTION_COUNT
# global WARNING_COUNT
# global SNAPSHOTS_OLD
# Retain at most $opt_keep number of old snapshots of this filesystem,
# including the one that was just recently created.
KEEP="$opt_keep"
# ASSERT: The old snapshot list is sorted by increasing age.
for jj in $SNAPSHOTS_OLD
do
# Check whether this is an old snapshot of the filesystem.
if [ -z "${jj#$TARGET@$GLOB}" ]
then
KEEP=$(( $KEEP - 1 ))
if [ "$KEEP" -le '0' ]
then
if do_run "zfs destroy $FLAGS '$jj'"
then
DESTRUCTION_COUNT=$(( $DESTRUCTION_COUNT + 1 ))
else
WARNING_COUNT=$(( $WARNING_COUNT + 1 ))
fi
fi
fi
done
}
compute_hanoi_level() # date
{
local DATE="$1"
local EPOCH_TIME=''
local HANOI_NUM=''
local HANOI_LEVEL='1'
# The h* is because on Solaris %H%M will have generated 12h34
EPOCH_TIME=$(date +%s --date="$(echo $DATE | sed 's/-\(..\)h*\(..\)$/ \1:\2/')")
HANOI_NUM=$(($EPOCH_TIME / $opt_hanoi));
while test "$HANOI_NUM" -ne "0"
do
case "${HANOI_NUM}" in
(*[13579])
break
;;
esac
HANOI_LEVEL=$(($HANOI_LEVEL + 1))
HANOI_NUM=$(($HANOI_NUM / 2))
done
echo $HANOI_LEVEL
}
do_hanoi () # flags, oldglob, target
{
local FLAGS="$1"
local GLOB="$2"
local TARGET="$3"
local KEEP=''
local HANOI_LEVEL='0'
local SNAP_DATE=''
local SNAP_LEVEL=''
local POSSIBLY_DESTROY=''
# global DESTRUCTION_COUNT
# global WARNING_COUNT
# global SNAPSHOTS_OLD
HANOI_LEVEL=$(compute_hanoi_level "$DATE")
# Retain at most $opt_keep number of old snapshots of this filesystem,
# including the one that was just recently created.
KEEP="$opt_keep"
# ASSERT: The old snapshot list is sorted by increasing age.
for jj in $SNAPSHOTS_OLD
do
# Check whether this is an old snapshot of the filesystem.
if [ -z "${jj#$TARGET@$GLOB}" ]
then
# If younger snapshot was stored for possible
# deletion, delete it.
if [ -n "$POSSIBLY_DESTROY" ]
then
if do_run "zfs destroy $FLAGS '$POSSIBLY_DESTROY'"
then
DESTRUCTION_COUNT=$(( $DESTRUCTION_COUNT + 1 ))
else
WARNING_COUNT=$(( $WARNING_COUNT + 1 ))
fi
POSSIBLY_DESTROY=''
fi
SNAP_DATE=$(echo $jj | sed 's/.*-\(....-..-..-..h*..\)$/\1/')
SNAP_LEVEL=$(compute_hanoi_level "$SNAP_DATE")
if test "$HANOI_LEVEL" -eq "$SNAP_LEVEL"
then
# By default the hanoi rotation scheme acts as
# though there are an infinite number of
# disks. So instead of immediately destroying
# this snapshot, remember it as possibly
# needing to be destroyed and only do so if an
# older snapshot is found for this set.
POSSIBLY_DESTROY="$jj"
fi
fi
done
}
do_snapshots () # properties, flags, snapname, oldglob, [targets...] do_snapshots () # properties, flags, snapname, oldglob, [targets...]
{ {
local PROPS="$1" local PROPS="$1"
@ -268,27 +152,71 @@ do_snapshots () # properties, flags, snapname, oldglob, [targets...]
local NAME="$3" local NAME="$3"
local GLOB="$4" local GLOB="$4"
local TARGETS="$5" local TARGETS="$5"
local KEEP=''
local RUNSNAP=1
# global DESTRUCTION_COUNT
# global SNAPSHOT_COUNT # global SNAPSHOT_COUNT
# global WARNING_COUNT # global WARNING_COUNT
# global SNAPSHOTS_OLD
for ii in $TARGETS for ii in $TARGETS
do do
if do_run "zfs snapshot $PROPS $FLAGS '$ii@$NAME'" # Check if size check is > 0
size_check_skip=0
if [ "$opt_min_size" -gt 0 ]
then
bytes_written=`zfs get -Hp -o value written $ii`
kb_written=$(( $bytes_written / 1024 ))
if [ "$kb_written" -lt "$opt_min_size" ]
then
size_check_skip=1
if [ $opt_verbose -gt 0 ]
then
echo "Skipping target $ii, only $kb_written kB written since last snap. opt_min_size is $opt_min_size"
fi
fi
fi
if [ -n "$opt_do_snapshots" -a "$size_check_skip" -eq 0 ]
then then
SNAPSHOT_COUNT=$(( $SNAPSHOT_COUNT + 1 )) if [ "$opt_pre_snapshot" != "" ]
else then
WARNING_COUNT=$(( $WARNING_COUNT + 1 )) do_run "$opt_pre_snapshot $ii $NAME" || RUNSNAP=0
continue fi
if [ $RUNSNAP -eq 1 ] && do_run "zfs snapshot $PROPS $FLAGS '$ii@$NAME'"
then
[ "$opt_post_snapshot" != "" ] && do_run "$opt_post_snapshot $ii $NAME"
SNAPSHOT_COUNT=$(( $SNAPSHOT_COUNT + 1 ))
else
WARNING_COUNT=$(( $WARNING_COUNT + 1 ))
continue
fi
fi fi
if test -z "$opt_hanoi" # Retain at most $opt_keep number of old snapshots of this filesystem,
then # including the one that was just recently created.
test -z "$opt_keep" && continue test -z "$opt_keep" && continue
do_rotate "$FLAGS" "$GLOB" "$ii" KEEP="$opt_keep"
else
do_hanoi "$FLAGS" "$GLOB" "$ii" # ASSERT: The old snapshot list is sorted by increasing age.
fi for jj in $SNAPSHOTS_OLD
do
# Check whether this is an old snapshot of the filesystem.
if [ -z "${jj#$ii@$GLOB}" ]
then
KEEP=$(( $KEEP - 1 ))
if [ "$KEEP" -le '0' ]
then
if do_run "zfs destroy -d $FLAGS '$jj'"
then
DESTRUCTION_COUNT=$(( $DESTRUCTION_COUNT + 1 ))
else
WARNING_COUNT=$(( $WARNING_COUNT + 1 ))
fi
fi
fi
done
done done
} }
@ -296,11 +224,19 @@ do_snapshots () # properties, flags, snapname, oldglob, [targets...]
# main () # main ()
# { # {
GETOPT=$(getopt \ if [ "$(uname)" = "Darwin" ]; then
GETOPT_BIN="$(brew --prefix gnu-getopt 2> /dev/null || echo /usr/local)/bin/getopt"
else
GETOPT_BIN="getopt"
fi
GETOPT=$($GETOPT_BIN \
--longoptions=default-exclude,dry-run,fast,skip-scrub,recursive \ --longoptions=default-exclude,dry-run,fast,skip-scrub,recursive \
--longoptions=event:,hanoi:,keep:,label:,prefix:,sep: \ --longoptions=event:,keep:,label:,prefix:,sep: \
--longoptions=debug,help,quiet,syslog,verbose \ --longoptions=debug,help,quiet,syslog,verbose \
--options=dnshH:e:l:k:p:rs:qgv \ --longoptions=pre-snapshot:,post-snapshot:,destroy-only \
--longoptions=min-size: \
--options=dnshe:l:k:p:rs:qgvm: \
-- "$@" ) \ -- "$@" ) \
|| exit 128 || exit 128
@ -346,29 +282,6 @@ do
print_usage print_usage
exit 0 exit 0
;; ;;
(-H|--hanoi)
HANOI_OPT="$2"
MULT="";
INT="";
case "$2" in
(*[0-9]s) MULT=1 ;;
(*[0-9]m) MULT=60 ;;
(*[0-9]h) MULT=3600 ;;
(*[0-9]d) MULT=86400 ;;
(*[0-9]w) MULT=604800 ;;
(*)
print_log error "Unrecognized interval $2 for the $1 parameter."
exit 139
;;
esac
INT=$(echo $2 | sed 's/.$//')
if ! test "$INT" -gt '0' 2>/dev/null
then
print_log error "The $2 parameter must be a positive integer."
fi
opt_hanoi=$(($INT * $MULT))
shift 2
;;
(-k|--keep) (-k|--keep)
if ! test "$2" -gt '0' 2>/dev/null if ! test "$2" -gt '0' 2>/dev/null
then then
@ -382,6 +295,10 @@ do
opt_label="$2" opt_label="$2"
shift 2 shift 2
;; ;;
(-m|--min-size)
opt_min_size="$2"
shift 2
;;
(-p|--prefix) (-p|--prefix)
opt_prefix="$2" opt_prefix="$2"
while test "${#opt_prefix}" -gt '0' while test "${#opt_prefix}" -gt '0'
@ -433,6 +350,18 @@ do
opt_verbose='1' opt_verbose='1'
shift 1 shift 1
;; ;;
(--pre-snapshot)
opt_pre_snapshot="$2"
shift 2
;;
(--post-snapshot)
opt_post_snapshot="$2"
shift 2
;;
(--destroy-only)
opt_do_snapshots=''
shift 1
;;
(--) (--)
shift 1 shift 1
break break
@ -459,11 +388,6 @@ then
exit 134 exit 134
fi fi
if test -n "$opt_hanoi" -a -z "$opt_label"
then
opt_label=hanoi
fi
# These are the only times that `zpool status` or `zfs list` are invoked, so # These are the only times that `zpool status` or `zfs list` are invoked, so
# this program for Linux has a much better runtime complexity than the similar # this program for Linux has a much better runtime complexity than the similar
# Solaris implementation. # Solaris implementation.
@ -471,16 +395,33 @@ fi
ZPOOL_STATUS=$(env LC_ALL=C zpool status 2>&1 ) \ ZPOOL_STATUS=$(env LC_ALL=C zpool status 2>&1 ) \
|| { print_log error "zpool status $?: $ZPOOL_STATUS"; exit 135; } || { print_log error "zpool status $?: $ZPOOL_STATUS"; exit 135; }
ZFS_LIST=$(env LC_ALL=C zfs list -H -t filesystem,volume -s name \ ZFS_LIST=$(env LC_ALL=C zfs list -H -t filesystem,volume -s name \
-o name,com.sun:auto-snapshot,com.sun:auto-snapshot:"$opt_label") \ -o name,com.sun:auto-snapshot,com.sun:auto-snapshot:"$opt_label") \
|| { print_log error "zfs list $?: $ZFS_LIST"; exit 136; } || { print_log error "zfs list $?: $ZFS_LIST"; exit 136; }
if [ -n "$opt_fast_zfs_list" ] if [ -n "$opt_fast_zfs_list" ]
then then
SNAPSHOTS_OLD=$(env LC_ALL=C zfs list -H -t snapshot -o name -s name|grep $opt_prefix |awk '{ print substr( $0, length($0) - 14, length($0) ) " " $0}' |sort -r -k1,1 -k2,2|awk '{ print substr( $0, 17, length($0) )}') \ # Check if a snapshot label is being used, in which case restrict the old
|| { print_log error "zfs list $?: $SNAPSHOTS_OLD"; exit 137; } # snapshot removal to only snapshots with the same label format
if [ -n "$opt_label" ]
then
SNAPSHOTS_OLD=$(env LC_ALL=C zfs list -H -t snapshot -o name -s name | \
grep "$opt_prefix"_"$opt_label" | \
awk '{ print substr( $0, length($0) - 14, length($0) ) " " $0}' | \
sort -r -k1,1 -k2,2 | \
awk '{ print substr( $0, 17, length($0) )}') \
|| { print_log error "zfs list $?: $SNAPSHOTS_OLD"; exit 137; }
else
SNAPSHOTS_OLD=$(env LC_ALL=C zfs list -H -t snapshot -o name -s name | \
grep $opt_prefix | \
awk '{ print substr( $0, length($0) - 14, length($0) ) " " $0}' | \
sort -r -k1,1 -k2,2 | \
awk '{ print substr( $0, 17, length($0) )}') \
|| { print_log error "zfs list $?: $SNAPSHOTS_OLD"; exit 137; }
fi
else else
SNAPSHOTS_OLD=$(env LC_ALL=C zfs list -H -t snapshot -S creation -o name) \ SNAPSHOTS_OLD=$(env LC_ALL=C zfs list -H -t snapshot -S creation -o name) \
|| { print_log error "zfs list $?: $SNAPSHOTS_OLD"; exit 137; } || { print_log error "zfs list $?: $SNAPSHOTS_OLD"; exit 137; }
fi fi
@ -540,11 +481,20 @@ do
# Just testing "$ii" != ${ii#$jj} would incorrectly match. # Just testing "$ii" != ${ii#$jj} would incorrectly match.
iii="$ii/" iii="$ii/"
# Exclude datasets that are not named on the command line.
# Exclude datasets
# * that are not named on the command line or
# * those whose prefix is not on the command line (if --recursive flag is set)
IN_ARGS='0' IN_ARGS='0'
for jj in "$@" for jj in "$@"
do do
# Ibid regarding iii.
jjj="$jj/"
if [ "$jj" = '//' -o "$jj" = "$ii" ] if [ "$jj" = '//' -o "$jj" = "$ii" ]
then
IN_ARGS=$(( $IN_ARGS + 1 ))
elif [ -n "$opt_recursive" -a "$iii" != "${iii#$jjj}" ]
then then
IN_ARGS=$(( $IN_ARGS + 1 )) IN_ARGS=$(( $IN_ARGS + 1 ))
fi fi
@ -628,30 +578,43 @@ do
TARGETS_RECURSIVE="${TARGETS_RECURSIVE:+$TARGETS_RECURSIVE }$ii" # nb: \t TARGETS_RECURSIVE="${TARGETS_RECURSIVE:+$TARGETS_RECURSIVE }$ii" # nb: \t
done done
# ISO style date; fifteen characters: YYYY-MM-DD-HHMM
# On Solaris %H%M expands to 12h34.
DATE=$(date --utc +%F-%H%M)
if test -n "$opt_hanoi" -a "$opt_event" = "-"
then
opt_event=hanoi-$HANOI_OPT-level-$(compute_hanoi_level $DATE)
fi
# Linux lacks SMF and the notion of an FMRI event, but always set this property # Linux lacks SMF and the notion of an FMRI event, but always set this property
# because the SUNW program does. The dash character is the default. # because the SUNW program does. The dash character is the default.
SNAPPROP="-o com.sun:auto-snapshot-desc='$opt_event'" SNAPPROP="-o com.sun:auto-snapshot-desc='$opt_event'"
# ISO style date; fifteen characters: YYYY-MM-DD-HHMM
# On Solaris %H%M expands to 12h34.
# We use the shortfirm -u here because --utc is not supported on macos.
DATE=$(date -u +%F-%H%M)
# The snapshot name after the @ symbol. # The snapshot name after the @ symbol.
SNAPNAME="$opt_prefix${opt_label:+$opt_sep$opt_label}-$DATE" SNAPNAME="${opt_prefix:+$opt_prefix$opt_sep}${opt_label:+$opt_label}-$DATE"
# The expression for matching old snapshots. -YYYY-MM-DD-HHMM # The expression for matching old snapshots. -YYYY-MM-DD-HHMM
SNAPGLOB="$opt_prefix${opt_label:+?$opt_label}????????????????" SNAPGLOB="${opt_prefix:+$opt_prefix$opt_sep}${opt_label:+$opt_label}-???????????????"
test -n "$TARGETS_REGULAR" \ if [ -n "$opt_do_snapshots" ]
&& print_log info "Doing regular snapshots of $TARGETS_REGULAR" then
test -n "$TARGETS_REGULAR" \
&& print_log info "Doing regular snapshots of $TARGETS_REGULAR"
test -n "$TARGETS_RECURSIVE" \ test -n "$TARGETS_RECURSIVE" \
&& print_log info "Doing recursive snapshots of $TARGETS_RECURSIVE" && print_log info "Doing recursive snapshots of $TARGETS_RECURSIVE"
if test -n "$opt_keep" && [ "$opt_keep" -ge "1" ]
then
print_log info "Destroying all but the newest $opt_keep snapshots of each dataset."
fi
elif test -n "$opt_keep" && [ "$opt_keep" -ge "1" ]
then
test -n "$TARGETS_REGULAR" \
&& print_log info "Destroying all but the newest $opt_keep snapshots of $TARGETS_REGULAR"
test -n "$TARGETS_RECURSIVE" \
&& print_log info "Recursively destroying all but the newest $opt_keep snapshots of $TARGETS_RECURSIVE"
else
print_log notice "Only destroying snapshots, but count of snapshots to preserve not given. Nothing to do."
fi
test -n "$opt_dry_run" \ test -n "$opt_dry_run" \
&& print_log info "Doing a dry run. Not running these commands..." && print_log info "Doing a dry run. Not running these commands..."