@@ -34,6 +34,11 @@ opt_keep=''
3434opt_label=' '
3535opt_prefix=' zfs-auto-snap'
3636opt_recursive=' '
37+ opt_send_type=' '
38+ opt_send_host=' '
39+ opt_recv_pool=' '
40+ opt_send_opts=' '
41+ opt_recv_opts=' '
3742opt_sep=' _'
3843opt_setauto=' '
3944opt_syslog=' '
@@ -50,6 +55,7 @@ WARNING_COUNT='0'
5055
5156# Other global variables.
5257SNAPSHOTS_OLD=' '
58+ SNAPS_DONE=' '
5359
5460
5561print_usage ()
@@ -66,8 +72,10 @@ print_usage ()
6672 -l, --label=LAB LAB is usually 'hourly', 'daily', or 'monthly'.
6773 -p, --prefix=PRE PRE is 'zfs-auto-snap' by default.
6874 -q, --quiet Suppress warnings and notices at the console.
69- --send-full=F Send zfs full backup. Unimplemented.
70- --send-incr=F Send zfs incremental backup. Unimplemented.
75+ --send-full=F Send zfs full backup.
76+ --send-incr=F Send zfs incremental backup.
77+ --send-opts=F Option(s) passed to 'zfs send'.
78+ --recv-opts=F Option(s) passed to 'zfs receive'.
7179 --sep=CHAR Use CHAR to separate date stamps in snapshot names.
7280 -g, --syslog Write messages into the system log.
7381 -r, --recursive Snapshot named filesystem and all descendants.
@@ -144,6 +152,64 @@ do_run () # [argv]
144152}
145153
146154
155+ find_last_snap () # dset, GLOB
156+ {
157+ local snap=" $1 "
158+ local GLOB=" $2 "
159+
160+ local dset=" ${snap%@* } "
161+ local last_snap
162+ local jj
163+
164+ # STEP 1: Go through ALL snapshots that exist, look for exact
165+ # match on dataset/volume (with snapshot matching 'GLOB').
166+ for jj in $SNAPSHOTS_OLD
167+ do
168+ # Check whether this is an old snapshot of the filesystem.
169+ if [ -z " ${jj# $dset @ $GLOB } " ]; then
170+ # We want the FIRST one (which is the last in time
171+ # before the one we just created in do_snapshot()).
172+ # Also, here we just need the snapshot name.
173+ last_snap=" ${jj#*@ } "
174+ break
175+ fi
176+ done
177+
178+ # NOTE: If we don't have any previous snapshots (for example, we've
179+ # just created the first one) we can end up with last_snap=''
180+ # here.
181+ # If we're called with '--send-incr' we have to options:
182+ # 1: We change from incremental to full.
183+ # 2: We accept that the user have said INCR, and stick with
184+ # it.
185+ if [ " $opt_send_type " = " incr" -a -z " $last_snap " ]; then
186+ if [ -n " $opt_verbose " ]; then
187+ echo > /dev/stderr " WARNING: No previous snapshots exist but we where called"
188+ echo > /dev/stderr " with --send-incr. Can not continue."
189+ echo > /dev/stderr " Please rerun with --send-full."
190+ fi
191+ return 1
192+ fi
193+
194+ if [ -n " $opt_recursive " -a -n " $last_snap " ]; then
195+ # STEP 2: Again, go through ALL snapshots that exists, but this
196+ # time only look for the snapshots that 'starts with'
197+ # the dataset/volume in question AND 'ends with'
198+ # the exact snapshot name/date in step 2.
199+ for jj in $SNAPSHOTS_OLD
200+ do
201+ if echo " $jj " | grep -qE " ^$dset .*@$last_snap " ; then
202+ echo $jj
203+ fi
204+ done
205+ else
206+ echo " $snap "
207+ fi
208+
209+ return 0
210+ }
211+
212+
147213do_snapshots () # properties, flags, snapname, oldglob, [targets...]
148214{
149215 local PROPS=" $1 "
@@ -170,6 +236,8 @@ do_snapshots () # properties, flags, snapname, oldglob, [targets...]
170236 if [ $RUNSNAP -eq 1 ] && do_run " zfs snapshot $PROPS $FLAGS '$ii @$NAME '"
171237 then
172238 [ " $opt_post_snapshot " != " " ] && do_run " $opt_post_snapshot $ii $NAME "
239+ [ -n " $opt_send_host " ] && SNAPS_DONE=" $SNAPS_DONE
240+ $ii @$NAME "
173241 SNAPSHOT_COUNT=$(( $SNAPSHOT_COUNT + 1 ))
174242 else
175243 WARNING_COUNT=$(( $WARNING_COUNT + 1 ))
@@ -203,6 +271,34 @@ do_snapshots () # properties, flags, snapname, oldglob, [targets...]
203271 done
204272}
205273
274+ do_send () # snapname, oldglob
275+ {
276+ local NAME=" $1 "
277+ local GLOB=" $2 "
278+ local remote=" ssh $opt_send_host zfs receive $opt_recv_opts $opt_recv_pool "
279+ local ii
280+ local jj
281+
282+ # STEP 1: Go throug all snapshots we've created
283+ for ii in $SNAPS_DONE
284+ do
285+ opts=' '
286+ SNAPS_SEND=' '
287+
288+ # STEP 2: Find the last snapshot
289+ SNAPS_SEND=$( find_last_snap " $ii " " $GLOB " )
290+
291+ # STEP 3: Go through all snapshots that is to be transfered and send them.
292+ for jj in $SNAPS_SEND
293+ do
294+ if [ " $opt_send_type " = " incr" ]; then
295+ do_run " zfs send $opt_send_opts -i $jj $ii | $remote "
296+ else
297+ do_run " zfs send $opt_send_opts -R $jj | $remote "
298+ fi
299+ done
300+ done
301+ }
206302
207303# main ()
208304# {
@@ -212,6 +308,7 @@ GETOPT=$(getopt \
212308 --longoptions=event:,keep:,label:,prefix:,sep: \
213309 --longoptions=debug,help,quiet,syslog,verbose \
214310 --longoptions=pre-snapshot:,post-snapshot:,destroy-only \
311+ --longoptions=send-full:,send-incr:,send-opts:,recv-opts: \
215312 --options=dnshe:l:k:p:rs:qgv \
216313 -- " $@ " ) \
217314 || exit 128
296393 opt_recursive=' 1'
297394 shift 1
298395 ;;
396+ (--send-full)
397+ opt_send_type=' full'
398+
399+ opt_send_host=$( echo " $2 " | sed ' s,:.*,,' )
400+ opt_recv_pool=$( echo " $2 " | sed ' s,.*:,,' )
401+
402+ opt_send_opts=" $opt_send_opts -R"
403+ shift 2
404+ ;;
405+ (--send-incr)
406+ opt_send_type=' incr'
407+
408+ opt_send_host=$( echo " $2 " | sed ' s,:.*,,' )
409+ opt_recv_pool=$( echo " $2 " | sed ' s,.*:,,' )
410+ shift 2
411+ ;;
412+ (--send-opts)
413+ opt_send_opts=" $2 "
414+ shift 2
415+ ;;
416+ (--recv-opts)
417+ opt_recv_opts=" $2 "
418+ shift 2
419+ ;;
299420 (--sep)
300421 case " $2 " in
301422 ([[:alnum:]_.:\ -])
@@ -567,6 +688,8 @@ test -n "$opt_dry_run" \
567688do_snapshots " $SNAPPROP " " " " $SNAPNAME " " $SNAPGLOB " " $TARGETS_REGULAR "
568689do_snapshots " $SNAPPROP " " -r" " $SNAPNAME " " $SNAPGLOB " " $TARGETS_RECURSIVE "
569690
691+ do_send " $SNAPNAME " " $SNAPGLOB "
692+
570693print_log notice " @$SNAPNAME ," \
571694 " $SNAPSHOT_COUNT created," \
572695 " $DESTRUCTION_COUNT destroyed," \
0 commit comments