lbu.in 15.8 KB
Newer Older
Natanael Copa's avatar
Natanael Copa committed
1
2
3
#!/bin/sh

# lbu - utility to create local backups.
4
# Copyright (c) 2006-2010 Natanael Copa <ncopa@alpinelinux.org>
Natanael Copa's avatar
Natanael Copa committed
5
6
# May be distributed under GPL2

7
VERSION=@VERSION@
Natanael Copa's avatar
Natanael Copa committed
8
sysconfdir=@sysconfdir@
Natanael Copa's avatar
Natanael Copa committed
9

10
11
if [ ! -f ${libalpine:="./libalpine.sh"} ]; then
	libalpine=/usr/share/lbu/libalpine.sh
12
13
14
	if [ ! -f "$libalpine" ]; then
		libalpine=/lib/libalpine.sh
	fi
15
16
fi
. $libalpine || exit 1
Natanael Copa's avatar
Natanael Copa committed
17

Natanael Copa's avatar
Natanael Copa committed
18
19
EXCLUDE_LIST="$sysconfdir"/exclude
INCLUDE_LIST="$sysconfdir"/include
Natanael Copa's avatar
Natanael Copa committed
20

Natanael Copa's avatar
Natanael Copa committed
21
22
DEFAULT_CIPHER="aes-256-cbc"

Natanael Copa's avatar
Natanael Copa committed
23
LBU_CONF="$sysconfdir"/lbu.conf
24
25
26
LBU_PREPACKAGE="$sysconfdir"/pre-package.d
LBU_POSTPACKAGE="$sysconfdir"/post-package.d

Natanael Copa's avatar
Natanael Copa committed
27
28
if [ -f "$LBU_CONF" ]; then
	. "$LBU_CONF"
29
30
fi

Natanael Copa's avatar
Natanael Copa committed
31
32
UMOUNT_LIST=

Natanael Copa's avatar
Natanael Copa committed
33
34
35
36
37
38
39
40
usage() {
	echo "$PROGRAM $VERSION"
	echo "usage: $PROGRAM <subcommand> [options] [args]

Available subcommands:
  commit (ci)
  exclude (ex, delete)
  include (inc, add)
41
42
  list (ls)
  package (pkg)
Natanael Copa's avatar
Natanael Copa committed
43
  status (stat, st)
44
  list-backup (lb) 
Natanael Copa's avatar
Natanael Copa committed
45
  revert
Natanael Copa's avatar
Natanael Copa committed
46
47
48
49
50
51
52
53
54

Common options:
 -h	Show help for subcommand.
 -q	Quiet mode.
 -v	Verbose mode.
"
	exit 1
}

Natanael Copa's avatar
Natanael Copa committed
55
56
cleanup() {
	local i
57
58
59
	for i in $REMOUNT_RO_LIST; do
		mount -o remount,ro $i
	done
Natanael Copa's avatar
Natanael Copa committed
60
61
62
63
64
65
66
67
68
69
	for i in $UMOUNT_LIST; do
		umount $i
	done
}

exit_clean() {
	cleanup
	exit 1
}

70
71
72
73
74
# check if given dir is not a mounted mountpoint
is_unmounted() {
	awk "\$2 == \"$1\" {exit 1}" /proc/mounts
}

Natanael Copa's avatar
Natanael Copa committed
75
mount_once() {
76
77
78
79
80
81
82
	if is_unmounted "$1"; then
		mount $1 && UMOUNT_LIST="$1 $UMOUNT_LIST" || return 1
	fi
}

# check if given dir is read-only
is_ro() {
83
	local tmpfile=$(mktemp -p "$1" 2>/dev/null)
84
85
86
87
88
89
90
91
92
93
	[ -z "$tmpfile" ] && return 0
	rm -f "$tmpfile"
	return 1
}

mount_once_rw() {
	mount_once "$1" || return 1
	if is_ro "$1"; then
		REMOUNT_RO_LIST="$1 $REMOUNT_RO_LIST"
		mount -o remount,rw "$1"
Natanael Copa's avatar
Natanael Copa committed
94
95
96
	fi
}

Natanael Copa's avatar
Natanael Copa committed
97
98
99
# create backupfile
backup_apkovl() {
	local outfile="$1"
100
	local d=$( date -u -r "$outfile" "+%Y%m%d%H%M%S" )
Natanael Copa's avatar
Natanael Copa committed
101
102
103
104
	local backup=$(echo "$outfile" | sed "s/\.apkovl\.tar\.gz/.$d.tar.gz/")
	vecho "Creating backup $backup"
	if [ -z "$DRYRUN" ]; then
		mv "$outfile" "$backup"
Natanael Copa's avatar
Natanael Copa committed
105
		APKOVL_BACKUP="$backup"
Natanael Copa's avatar
Natanael Copa committed
106
107
108
	fi
}

Natanael Copa's avatar
Natanael Copa committed
109
110
111
112
113
114
115
116
restore_apkovl() {
	local outfile="$1"
	if [ -n "$DRYRUN" ] || [ -z "$APKOVL_BACKUP" ]; then
		return 0
	fi
	mv "$APKOVL_BACKUP" "$outfile"
}

Natanael Copa's avatar
Natanael Copa committed
117
# verify we have openssl if we want to encrypt
118
119
120
check_openssl() {
	[ -z "$ENCRYPTION" ] && return 0
	OPENSSL=$(which openssl 2>/dev/null) || die "openssl was not found"
Natanael Copa's avatar
Natanael Copa committed
121

122
123
124
	$OPENSSL list-cipher-commands | grep "^$ENCRYPTION$" > /dev/null \
		|| die "Cipher $ENCRYPTION is not supported"
}
Natanael Copa's avatar
Natanael Copa committed
125
126
127
128
129
130
131
132
133

# list_add(char *listfile, char* file...)
list_add() {
	local list="$1"
	shift
	mkdir -p `dirname "$list"`
	while [ $# -gt 0 ] ; do
		filename=`echo "$1" | sed 's:^/\+::'`
		if grep "^$filename$" "$list" >/dev/null 2>&1 ; then
134
			vecho "$filename is already in $list."
Natanael Copa's avatar
Natanael Copa committed
135
		else
136
			vecho "Adding $filename to $list."
Natanael Copa's avatar
Natanael Copa committed
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
			echo "$filename" >> "$list"
		fi
		shift
	done
}

# list_delete(char *listfile, char *file...)
list_delete() {
	local list="$1"
	local tmp="$list.old"
	shift
	[ -f "$list" ] || return 1
	while [ $# -gt 0 ] ; do
		filename=`echo "$1" | sed 's:^/\+::'`
		mv "$list" "$tmp"
152
		vecho "Removing $filename from list."
Natanael Copa's avatar
Natanael Copa committed
153
154
155
156
157
158
		grep -v "^$filename$" "$tmp" > "$list"
		rm "$tmp"
		shift
	done
}

159
160
161
162
# unpack archive on LBU_MEDIA to given dir
unpack_apkovl() {
	local f="$(hostname).apkovl.tar.gz"
	local dest="$1"
Natanael Copa's avatar
Natanael Copa committed
163
	local mnt="${LBU_BACKUPDIR:-/media/$LBU_MEDIA}"
164
165
	local count=0
	mkdir -p "$dest"
Natanael Copa's avatar
Natanael Copa committed
166
167
168
	if [ -n "$LBU_MEDIA" ]; then
		mount_once "$mnt"
	fi
169
170
171
	if [ -n "$ENCRYPTION" ]; then
		f="$f.$ENCRYPTION"
	fi	
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
	if [ ! -f "$mnt/$f" ]; then
		return 1
	fi
	if [ -z "$ENCRYPTION" ]; then
		tar -C "$dest" -zxf "$mnt/$f"
		return
	fi
	check_openssl
        while [ $count -lt 3 ]; do
		$OPENSSL enc -d -$ENCRYPTION -in "$mnt/$f" | tar \
			-C "$dest" -zx 2>/dev/null && return 0
		count=$(( $count + 1 ))
	done
	cleanup
	die "Failed to unpack $mnt/$f"
}		
188

Natanael Copa's avatar
Natanael Copa committed
189
190
191
192
193
#
# lbu_include - add/remove files to include list
#
usage_include() {
	echo "$PROGRAM $VERSION
Natanael Copa's avatar
Natanael Copa committed
194
Add filename(s) to include list ($sysconfdir/include)
195
196
197

usage: $PROGRAM include|inc|add [-rv] <file> ...
       $PROGRAM include|inc|add [-v] -l
Natanael Copa's avatar
Natanael Copa committed
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212

Options:
  -l	List contents of include list.
  -r	Remove specified file(s) from include list instead of adding.
  -v	Verbose mode.
"
	exit 1
}

cmd_include() {
	if [ "$LIST" ] ; then
		[ $# -gt 0 ] && usage_include
		show_include
		return
	fi
213

Natanael Copa's avatar
Natanael Copa committed
214
215
216
217
218
219
220
221
222
223
224
	[ $# -lt 1 ] && usage_include
	if [ "$REMOVE" ] ; then
		list_delete "$INCLUDE_LIST" "$@"
	else
		list_add "$INCLUDE_LIST" "$@"
		list_delete "$EXCLUDE_LIST" "$@"
	fi
}

show_include() {
	if [ -f "$INCLUDE_LIST" ] ; then
225
		vecho "Include files:"
Natanael Copa's avatar
Natanael Copa committed
226
227
228
229
		cat "$INCLUDE_LIST"
	fi
}

230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#
# lbu_package - create a package
#
usage_package() {
	echo "$PROGRAM $VERSION
Create backup package.

usage: $PROGRAM package|pkg -v [<dirname>|<filename>]

Options:
  -v	Verbose mode.

If <dirname> is a directory, a package named <hostname>.apkovl.tar.gz will
be created in the specified directory.

If <filename> is specified, and is not a direcotry, a package with the
specified name willbe created.

248
If <dirname> nor <filename> is not specified, a package named
249
250
251
252
253
<hostname>.apkovl.tar.gz will be created in current work directory.
"
	exit 1
}

254
255
256
257
258
259
260
261
262
263
264
_gen_filelist() {
	apk audit --backup -q
	if [ -f var/lib/apk/world ]; then
		echo var/lib/apk/world
	fi
}

_gen_filelist_0() {
	_gen_filelist | tr '\n' '\0'
}

265
266
267
268
cmd_package() {
	local pkg="$1"
	local rc=0
	local owd="$PWD"
269
	local suff="apkovl.tar.gz"
Natanael Copa's avatar
Natanael Copa committed
270
	local tmpdir tmppkg tmpexclude tmpinclude
271
272

	check_openssl
Natanael Copa's avatar
Natanael Copa committed
273
	init_tmpdir tmpdir
274

275
	if [ -d "$LBU_PREPACKAGE" ]; then
276
		run-parts "$LBU_PREPACKAGE" >&2 || return 1
277
278
	fi

279
	[ -n "$ENCRYPTION" ] && suff="$suff.$ENCRYPTION"
280
281
282

	# find filename
	if [ -d "$pkg" ] ; then
283
		pkg="$pkg/$(hostname).$suff"
284
	elif [ -z "$pkg" ]; then
285
		pkg="$PWD/$(hostname).$suff"
286
287
	fi

Natanael Copa's avatar
Natanael Copa committed
288
	tmppkg="$tmpdir/$(basename $pkg)"
Natanael Copa's avatar
Natanael Copa committed
289
290
	tmpexclude="$tmpdir"/exclude
	tmpinclude="$tmpdir"/include
Natanael Copa's avatar
Natanael Copa committed
291

292
	cd "${ROOT:-/}"
293
	# remove old package.list
294
	if [ -f etc/lbu/packages.list ] && [ -f var/lib/apk/world ]; then
295
296
297
298
		echo "Note: Removing /etc/lbu/packages.list."
		echo "      /var/lib/apk/world will be used."
		rm -f etc/lbu/packages.list
	fi
299
	# create tar archive
Natanael Copa's avatar
Natanael Copa committed
300
301
302
303
304
305
306
307
308
309
	if [ -f "$EXCLUDE_LIST" ]; then
		# strip empty lines and lines with only whitespace
		sed -e '/^[[:space:]]*$/d' "$EXCLUDE_LIST" > $tmpexclude
		excl="-X $tmpexclude"
	fi
	if [ -f "$INCLUDE_LIST" ]; then
		# strip empty lines and lines with only whitespace
		sed -e '/^[[:space:]]*$/d' "$INCLUDE_LIST" > $tmpinclude
		incl="-T $tmpinclude"
	fi
Natanael Copa's avatar
Natanael Copa committed
310
311
312
313
	if [ -n "$VERBOSE" ]; then
		echo "Archiving the following files:" >&2
		# we dont want to mess the tar output with the
		# password prompt. Lets get the tar output first.
314
		_gen_filelist_0 | xargs -0 tar  $excl $incl -c -v > /dev/null
Natanael Copa's avatar
Natanael Copa committed
315
		rc=$?
Natanael Copa's avatar
Natanael Copa committed
316
317
318
	fi
	if [ $rc -eq 0 ]; then
		if [ -z "$ENCRYPTION" ]; then
319
320
			_gen_filelist_0 | xargs -0 tar $excl $incl -c \
				| gzip -c  >"$tmppkg"
Natanael Copa's avatar
Natanael Copa committed
321
			rc=$?
Natanael Copa's avatar
Natanael Copa committed
322
		else
Natanael Copa's avatar
Natanael Copa committed
323
324
			set -- enc "-$ENCRYPTION" -salt
			[ -n "$PASSWORD" ] && set -- "$@" -pass pass:"$PASSWORD"
325
326
			_gen_filelist_0 | xargs -0 tar $excl $incl -c \
				| gzip -c \
Natanael Copa's avatar
Natanael Copa committed
327
328
				| $OPENSSL "$@" > "$tmppkg"
			rc=$?
329
		fi
330
	fi
Natanael Copa's avatar
Natanael Copa committed
331
	cd "$owd"
Natanael Copa's avatar
Natanael Copa committed
332

Natanael Copa's avatar
Natanael Copa committed
333
	# actually commit unless dryrun mode
Natanael Copa's avatar
Natanael Copa committed
334
	if [ $rc -eq 0 ]; then
335
336
337
		if [ -z "$DRYRUN" ]; then
			if [ "x$pkg" = "x-" ]; then
				cat "$tmppkg"
338
339
			elif [ -b "$pkg" ] || [ -c "$pkg" ]; then
				cat "$tmppkg" > "$pkg"
340
			else
Natanael Copa's avatar
Natanael Copa committed
341
342
343
344
345
346
347
				if cp "$tmppkg" "$pkg.new"; then
					mv "$pkg.new" "$pkg"
					rc=$?
				else
					rm -f "$pkg.new"
					rc=1
				fi
348
349
			fi
		fi
Natanael Copa's avatar
Natanael Copa committed
350
		[ $rc -eq 0 ] && vecho "Created $pkg"
Natanael Copa's avatar
Natanael Copa committed
351
	fi
352
	if [ -d "$LBU_POSTPACKAGE" ]; then
353
		run-parts "$LBU_POSTPACKAGE" >&2
354
	fi
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
	return $rc
}

#
# lbu list - list files that would go to archive
#
usage_list() {
	echo "$PROGRAM $VERSION
Lists files that would go to tar package. Same as: 'lbu package -v /dev/null'

usage: $PROGRAM list|ls
"
	exit 1
}

cmd_list() {
	VERBOSE="-v"
372
	DRYRUN="-n"
373
	ENCRYPTION=
374
375
	cmd_package /dev/null
}
Natanael Copa's avatar
Natanael Copa committed
376
377
378
379
380
381

#
# lbu_commit - commit config files to writeable media
#
usage_commit() {
	echo "$PROGRAM $VERSION
382
383
384
Create a backup of config to writeable media.

usage: $PROGRAM commit|ci [-nv] [<media>]
Natanael Copa's avatar
Natanael Copa committed
385
386

Options:
Natanael Copa's avatar
Natanael Copa committed
387
  -d	Remove old apk overlay files.
388
  -e	Protect configuration with a password.
Natanael Copa's avatar
Natanael Copa committed
389
  -n	Don't commit, just show what would have been commited.
Natanael Copa's avatar
Natanael Copa committed
390
  -p <password>	Give encryption password on the command-line
Natanael Copa's avatar
Natanael Copa committed
391
392
393
  -v	Verbose mode.

The following values for <media> is supported: floppy usb
Natanael Copa's avatar
Natanael Copa committed
394
395
If <media> is not specified, the environment variable LBU_BACKUPDIR or
LBU_MEDIA will be used. If LBU_BACKUPDIR is set, nothing will be mounted.
Natanael Copa's avatar
Natanael Copa committed
396

397
Password protection will use $DEFAULT_CIPHER encryption. Other ciphers can be
Natanael Copa's avatar
Natanael Copa committed
398
399
400
used by setting the DEFAULT_CIPHER or ENCRYPTION environment variables.
For possible ciphers, try: openssl -v

Natanael Copa's avatar
Natanael Copa committed
401
402
The password used to encrypt the file, can either be specified with the -p
option or using the PASSWORD environment variable.
403

Jeremy Thomerson's avatar
Jeremy Thomerson committed
404
The environment variables can also be set in $LBU_CONF
Natanael Copa's avatar
Natanael Copa committed
405
406
407
408
409
"
	exit 1
}

cmd_commit() {
410
	local media mnt statuslist tmplist
411
412
413
414
	local incl excl outfile ovls lines

	check_openssl

Natanael Copa's avatar
Natanael Copa committed
415
416
417
	# turn on verbose mode if dryrun
	[ -n "$DRYRUN" ] && VERBOSE="-v"

Natanael Copa's avatar
Natanael Copa committed
418
419
420
421
422
	mnt="$LBU_BACKUPDIR"
	if [ -z "$mnt" ]; then
		# find what media to use
		media="${1:-$LBU_MEDIA}"
		[ -z "$media" ] && usage_commit
Natanael Copa's avatar
Natanael Copa committed
423

Natanael Copa's avatar
Natanael Copa committed
424
425
426
427
428
		# mount media unles its already mounted
		mnt=/media/$media
		[ -d "$mnt" ] || usage
		mount_once_rw "$mnt" || die "failed to mount $mnt"
	fi
Natanael Copa's avatar
Natanael Copa committed
429

Natanael Copa's avatar
Natanael Copa committed
430
431
432
433
434
435
436
	# find the outfile
	outfile="$mnt/$(hostname).apkovl.tar.gz"
	if [ -n "$ENCRYPTION" ]; then
		outfile="$outfile.$ENCRYPTION"
	fi

	# remove old config files
437
	if [ -n "$DELETEOLDCONFIGS" ] ; then
Natanael Copa's avatar
Natanael Copa committed
438
439
440
441
		local rmfiles=$(ls "$mnt/"*.apkovl.tar.gz* 2>/dev/null)
		if [ -n "$rmfiles" ] ; then
			if [ -n "$VERBOSE" ]; then
				echo "Removing old apk overlay files:" >&2
442
				echo "$rmfiles"
Natanael Copa's avatar
Natanael Copa committed
443
				echo "" >&2
444
			fi
Natanael Copa's avatar
Natanael Copa committed
445
			[ -z "$DRYRUN" ] && rm "$mnt/"*.apkovl.tar.gz*
446
447
		fi
	else
Natanael Copa's avatar
Natanael Copa committed
448
       		lines=$(ls -1 "$mnt"/*.apkovl.tar.gz* 2>/dev/null)
Natanael Copa's avatar
Natanael Copa committed
449
		if [ "$lines" = "$outfile" ]; then
Natanael Copa's avatar
Natanael Copa committed
450
			backup_apkovl "$outfile"
Natanael Copa's avatar
Natanael Copa committed
451
		elif [ -n "$lines" ]; then
452
	               	# More then one apkovl, this is a security concern
Natanael Copa's avatar
Natanael Copa committed
453
			cleanup
Natanael Copa's avatar
Natanael Copa committed
454
455
456
457
			eecho "The following apkovl file(s) were found:"
			eecho "$lines"
			eecho ""
	               	die "Please use -d to replace."
458
		fi
Natanael Copa's avatar
Natanael Copa committed
459
	fi
460
461
462

	# create package
	if ! cmd_package "$outfile"; then
Natanael Copa's avatar
Natanael Copa committed
463
		restore_apkovl "$outfile"
Natanael Copa's avatar
Natanael Copa committed
464
		cleanup
Natanael Copa's avatar
Natanael Copa committed
465
		die "Problems creating archive. aborting"
466
	fi
Natanael Copa's avatar
Natanael Copa committed
467

468
469
	# delete old backups if needed
	# poor mans 'head -n -N' done with awk.
470
	ls "$mnt"/$(hostname).[0-9][0-9][0-9][0-9]*[0-9].tar.gz 2>/dev/null \
471
472
473
474
475
476
477
		| awk '{ a[++i] = $0; } END { 
			print a[0]; 
			while (i-- > '"${BACKUP_LIMIT:-0}"') { 
				print a[++j] 
			}
		}' | xargs rm 2>/dev/null

Natanael Copa's avatar
Natanael Copa committed
478
	# remove obsolete file. some older version of alpine needs this
479
	# to be able to upgrade
480
481
	if [ -z "$DRYRUN" ] && [ -f $mnt/packages.list ]; then
		echo "Note: Removing packages.list from $(basename $mnt)."
482
		echo "      /var/lib/apk/world will be used."
483
484
		rm -f $mnt/packages.list
	fi
Natanael Copa's avatar
Natanael Copa committed
485

Natanael Copa's avatar
Natanael Copa committed
486
	# make sure data is written
Natanael Copa's avatar
Natanael Copa committed
487
	sync
Natanael Copa's avatar
Natanael Copa committed
488
	[ "$media" = "floppy" ] && sleep 1
Natanael Copa's avatar
Natanael Copa committed
489
490

	# move current to commited.
491
	vecho "Successfully saved apk overlay files"
Natanael Copa's avatar
Natanael Copa committed
492
493
494
495
496
497
498
}

#---------------------------------------------------------------------------
# lbu_exclude - add remove file(s) from exclude list

usage_exclude() {
	echo "$PROGRAM $VERSION
Natanael Copa's avatar
Natanael Copa committed
499
Add filename(s) to exclude list ($sysconfdir/exclude)
500
501
502

usage: $PROGRAM exclude|ex|delete [-rv] <file> ...
       $PROGRAM exclude|ex|delete [-v] -l
Natanael Copa's avatar
Natanael Copa committed
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517

Options:
  -l	List contents of exclude list.
  -r	Remove specified file(s) from exclude list instead of adding.
  -v	Verbose mode.
"
	exit 1
}

cmd_exclude() {
	if [ "$LIST" ] ; then
		[ $# -gt 0 ] && usage_exclude
		show_exclude
		return
	fi
518

Natanael Copa's avatar
Natanael Copa committed
519
520
521
522
523
524
525
526
527
528
529
	[ $# -lt 1 ] && usage_exclude
	if [ "$REMOVE" ] ; then
		list_delete "$EXCLUDE_LIST" "$@"
	else
		list_delete "$INCLUDE_LIST" "$@"
		list_add "$EXCLUDE_LIST" "$@"
	fi
}

show_exclude() {
	if [ -f "$EXCLUDE_LIST" ] ; then
530
		vecho "Exclude files:"
Natanael Copa's avatar
Natanael Copa committed
531
		cat "$EXCLUDE_LIST"
532
	fi
Natanael Copa's avatar
Natanael Copa committed
533
534
}

Natanael Copa's avatar
Natanael Copa committed
535
#---------------------------------------------------------------------------
536
# lbu_listbackup - Show old commits
537
usage_listbackup() {
Natanael Copa's avatar
Natanael Copa committed
538
539
540
541
	cat <<EOF
$PROGRAM $VERSION
Show old commits.

542
usage: $PROGRAM list-backup [<media>]
Natanael Copa's avatar
Natanael Copa committed
543
544
545
546
547

EOF
	exit 1
}

548
cmd_listbackup() {
Natanael Copa's avatar
Natanael Copa committed
549
	local media=${1:-"$LBU_MEDIA"}
Natanael Copa's avatar
Natanael Copa committed
550
551
	local mnt="${LBU_BACKUPDIR:-/media/$media}"
	[ -z "$media" ] && [ -z "$LBU_BACKUPDIR" ] && usage_listbackup
Natanael Copa's avatar
Natanael Copa committed
552

Natanael Copa's avatar
Natanael Copa committed
553
554
555
	if [ -n "$media" ]; then
		mount_once "$mnt" || die "failed to mount $mnt"
	fi
Natanael Copa's avatar
Natanael Copa committed
556
557
558
559
560
561
	ls -1 "$mnt"/*.[0-9][0-9]*[0-9][0-9].tar.gz* 2>/dev/null | sed 's:.*/::'
}

#---------------------------------------------------------------------------
# lbu_revert - revert to old config
usage_revert() {
Natanael Copa's avatar
Natanael Copa committed
562
563
564
565
566
567
	cat <<EOF
$PROGRAM $VERSION
Revert to older commit.

usage: $PROGRAM revert <REVISION> [<media>]

Natanael Copa's avatar
Natanael Copa committed
568
The revision should be one of the files listed by 'lbu list-backup'.
Natanael Copa's avatar
Natanael Copa committed
569

Natanael Copa's avatar
Natanael Copa committed
570
EOF
Natanael Copa's avatar
Natanael Copa committed
571
572
573
574
}

cmd_revert() {
	local media=${2:-"$LBU_MEDIA"}
Natanael Copa's avatar
Natanael Copa committed
575
576
577
578
579
580
	[ -z "$media" ] && usage_revert
	local mnt="/media/$media"
	local revertto="$mnt/$1"
	local current="$mnt/$(hostname).apkovl.tar.gz"

	if [ -n "$ENCRYPTION" ]; then
581
		current="$current.$ENCRYPTION"
Natanael Copa's avatar
Natanael Copa committed
582
	fi
583
	mount_once_rw "$mnt" || die "failed to mount $mnt"
Natanael Copa's avatar
Natanael Copa committed
584
	[ -f "$revertto" ] || die "file not found: $revertto"
585
	backup_apkovl "$current"
Natanael Copa's avatar
Natanael Copa committed
586
	vecho "Reverting to $1"
587
	[ -z "$DRYRUN" ] && mv "$revertto" "$current"
Natanael Copa's avatar
Natanael Copa committed
588
589
}

Natanael Copa's avatar
Natanael Copa committed
590
591
592
593
594
595
#---------------------------------------------------------------------------
# lbu_status - check what files have been changed since last save
usage_status() {
	echo "$PROGRAM $VERSION
Check what files have been changed since last commit.

596
usage: $PROGRAM status|st [-av]
Natanael Copa's avatar
Natanael Copa committed
597
598
599
600
601
602
603
604

Options:
  -a	Compare all files, not just since last commit.
  -v	Also show include and exclude lists.
"
	exit 1
}

605
606
607
608
609
cmd_status() {
	if [ -n "$USE_DEFAULT" ]; then
		apk audit --backup
		return 0
	fi
610
	LBU_MEDIA=${1:-"$LBU_MEDIA"}
Natanael Copa's avatar
Natanael Copa committed
611
	[ -z "$LBU_MEDIA" ] && [ -z "$LBU_BACKUPDIR" ] && usage_status
612
613
	local tmp
	init_tmpdir tmp
614
	mkdir -p "$tmp/a" "$tmp/b"
615
616
617
618

	# unpack last commited apkovl to tmpdir/a
	unpack_apkovl "$tmp/a"

619
	# generate new apkovl and extract to tmpdir/b
620
621
	local save_encryption="$ENCRYPTION"
	ENCRYPTION=
622
	cmd_package - | tar -C "$tmp/b" -zx
623
	ENCRYPTION="$save_encryption"
624

625
	# show files that exists in a but not in b as deleted
626
627
628
	local f
	( cd "$tmp"/a && find ) | while read f; do
		f=${f#./}
629
630
631
632
633
		local b="$tmp/b/$f"
		if [ "$f" = "." ] || [ -e "$b" ] || [ -L "$b" ]; then
			continue
		fi
		echo "D $f"
634
635
	done
	
636
	# compare files in b with files in a
637
638
639
640
641
	( cd "$tmp"/b && find ) | while read f; do
		f=${f#./}
		[ "$f" = "." ] && continue
		local a="$tmp/a/$f"
		local b="$tmp/b/$f"
642
		if [ ! -e "$a" ] && [ ! -L "$a" ]; then
643
			echo "A $f"
Natanael Copa's avatar
Natanael Copa committed
644
645
		elif [ -f "$a" ] && [ -f "$b" ] && [ "$b" -nt "$a" ] \
		     && ! cmp -s "$a" "$b"; then
646
647
648
			echo "U $f"
		fi
	done
649
650
}

Natanael Copa's avatar
Natanael Copa committed
651

652
653
654
655
656
657
658
659
660
661
662
663
664
#-----------------------------------------------------------
# lbu_diff - run a diff against last commit
usage_diff() {
	echo "$PROGRAM $VERSION
Run a diff against last commit

usage: $PROGRAM diff [<media>]
"
	exit 1
}

cmd_diff() {
	LBU_MEDIA=${1:-"$LBU_MEDIA"}
Natanael Copa's avatar
Natanael Copa committed
665
	[ -z "$LBU_MEDIA" ] && [ -z "$LBU_BACKUPDIR" ] && usage_diff
666
667
668
669
	local tmp
	init_tmpdir tmp
	mkdir -p "$tmpdir/a" "$tmp/b"
	unpack_apkovl "$tmp/a"
670
	ENCRYPTION=
671
672
673
674
675
	cmd_package - | tar -C "$tmp/b" -zx
	cd "$tmp" && diff -ruN a b 
}
	

Natanael Copa's avatar
Natanael Copa committed
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692

#-----------------------------------------------------------
# Main

cmd=`echo "$PROGRAM" | cut -s -d_ -f2`
PROGRAM=`echo "$PROGRAM" | cut -d_ -f1`
if [ -z "$cmd" ] ; then
	cmd="$1"
	[ -z "$cmd" ] && usage
	shift
fi

# check for valid sub command
case "$cmd" in
	include|inc|add)	SUBCMD="include";;
	commit|ci)		SUBCMD="commit";;
	exclude|ex|delete)	SUBCMD="exclude";;
693
694
	list|ls)		SUBCMD="list";;
	package|pkg)		SUBCMD="package";;
Natanael Copa's avatar
Natanael Copa committed
695
	status|stat|st)		SUBCMD="status";;
696
	list-backup|lb)		SUBCMD="listbackup";;
Natanael Copa's avatar
Natanael Copa committed
697
	revert)			SUBCMD="revert";;
698
	diff)			SUBCMD="diff";;
Natanael Copa's avatar
Natanael Copa committed
699
700
701
702
	*)			usage;;
esac

# parse common args
703
while getopts "adehlM:np:qrv" opt ; do
Natanael Copa's avatar
Natanael Copa committed
704
705
706
707
	case "$opt" in
		a) 	[ $SUBCMD = status ] || usage_$SUBCMD
			USE_DEFAULT="-a"
			;;
708
709
		d)	DELETEOLDCONFIGS="yes"
			;;
710
		e)	[ -z "$ENCRYPTION" ] && ENCRYPTION="$DEFAULT_CIPHER"
711
			;;
Natanael Copa's avatar
Natanael Copa committed
712
713
714
715
716
717
718
		h) 	usage_$SUBCMD
			;;
		l)	LIST="-l"
			;;
		n) 	[ $SUBCMD = commit ] || usage_$SUBCMD
			DRYRUN="-n"
			;;
719
720
		p)	PASSWORD="$OPTARG"
			;;
Natanael Copa's avatar
Natanael Copa committed
721
722
723
724
725
726
727
728
729
		q)	QUIET="$QUIET -q"
			;;
		r)	REMOVE="-r"
			;;
		v) 	VERBOSE="$VERBOSE -v"
			;;
	esac
done
shift `expr $OPTIND - 1`
730

Natanael Copa's avatar
Natanael Copa committed
731
trap exit_clean SIGINT SIGTERM
732
cmd_$SUBCMD "$@"
Natanael Copa's avatar
Natanael Copa committed
733
734
735
retcode=$?

cleanup
Natanael Copa's avatar
Natanael Copa committed
736
exit $retcode