lbu.in 15.2 KB
Newer Older
1 2 3
#!/bin/sh

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

7
VERSION=@VERSION@
Natanael Copa's avatar
Natanael Copa committed
8
sysconfdir=@sysconfdir@
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
17

Natanael Copa's avatar
Natanael Copa committed
18 19
EXCLUDE_LIST="$sysconfdir"/exclude
INCLUDE_LIST="$sysconfdir"/include
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=

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)
43
  status (stat, st)
44
  list-backup (lb) 
Natanael Copa's avatar
Natanael Copa committed
45
  revert
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"
105
		APKOVL_BACKUP="$backup"
Natanael Copa's avatar
Natanael Copa committed
106 107 108
	fi
}

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"
121

122 123 124
	$OPENSSL list-cipher-commands | grep "^$ENCRYPTION$" > /dev/null \
		|| die "Cipher $ENCRYPTION is not supported"
}
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."
135
		else
136
			vecho "Adding $filename to $list."
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."
153 154 155 156 157 158
		grep -v "^$filename$" "$tmp" > "$list"
		rm "$tmp"
		shift
	done
}

159 160 161 162 163 164 165 166
# unpack archive on LBU_MEDIA to given dir
unpack_apkovl() {
	local f="$(hostname).apkovl.tar.gz"
	local dest="$1"
	local mnt="/media/$LBU_MEDIA"
	local count=0
	mkdir -p "$dest"
	mount_once "$mnt"
167 168 169
	if [ -n "$ENCRYPTION" ]; then
		f="$f.$ENCRYPTION"
	fi	
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
	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"
}		
186

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

usage: $PROGRAM include|inc|add [-rv] <file> ...
       $PROGRAM include|inc|add [-v] -l
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210

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
211

212 213 214 215 216 217 218 219 220 221 222
	[ $# -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
223
		vecho "Include files:"
224 225 226 227
		cat "$INCLUDE_LIST"
	fi
}

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
#
# 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.

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

252 253 254 255 256 257 258 259 260 261 262
_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'
}

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

	check_openssl
Natanael Copa's avatar
Natanael Copa committed
271
	init_tmpdir tmpdir
272

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

277
	[ -n "$ENCRYPTION" ] && suff="$suff.$ENCRYPTION"
278 279 280

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

Natanael Copa's avatar
Natanael Copa committed
286 287
	tmppkg="$tmpdir/$(basename $pkg)"

288
	cd "${ROOT:-/}"
289
	# remove old package.list
290
	if [ -f etc/lbu/packages.list ] && [ -f var/lib/apk/world ]; then
291 292 293 294
		echo "Note: Removing /etc/lbu/packages.list."
		echo "      /var/lib/apk/world will be used."
		rm -f etc/lbu/packages.list
	fi
295 296 297
	# create tar archive
	[ -f "$EXCLUDE_LIST" ] && excl="-X $EXCLUDE_LIST"
	[ -f "$INCLUDE_LIST" ] && incl="-T $INCLUDE_LIST"
Natanael Copa's avatar
Natanael Copa committed
298 299 300 301
	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.
302
		_gen_filelist_0 | xargs -0 tar  $excl $incl -c -v > /dev/null
Natanael Copa's avatar
Natanael Copa committed
303
		rc=$?
Natanael Copa's avatar
Natanael Copa committed
304 305 306
	fi
	if [ $rc -eq 0 ]; then
		if [ -z "$ENCRYPTION" ]; then
307 308
			_gen_filelist_0 | xargs -0 tar $excl $incl -c \
				| gzip -c  >"$tmppkg"
Natanael Copa's avatar
Natanael Copa committed
309
			rc=$?
Natanael Copa's avatar
Natanael Copa committed
310
		else
Natanael Copa's avatar
Natanael Copa committed
311 312
			set -- enc "-$ENCRYPTION" -salt
			[ -n "$PASSWORD" ] && set -- "$@" -pass pass:"$PASSWORD"
313 314
			_gen_filelist_0 | xargs -0 tar $excl $incl -c \
				| gzip -c \
Natanael Copa's avatar
Natanael Copa committed
315 316
				| $OPENSSL "$@" > "$tmppkg"
			rc=$?
317
		fi
318
	fi
Natanael Copa's avatar
Natanael Copa committed
319
	cd "$owd"
Natanael Copa's avatar
Natanael Copa committed
320

Natanael Copa's avatar
Natanael Copa committed
321
	# actually commit unless dryrun mode
Natanael Copa's avatar
Natanael Copa committed
322
	if [ $rc -eq 0 ]; then
323 324 325
		if [ -z "$DRYRUN" ]; then
			if [ "x$pkg" = "x-" ]; then
				cat "$tmppkg"
326 327
			elif [ -b "$pkg" ] || [ -c "$pkg" ]; then
				cat "$tmppkg" > "$pkg"
328
			else
329 330 331 332 333 334 335
				if cp "$tmppkg" "$pkg.new"; then
					mv "$pkg.new" "$pkg"
					rc=$?
				else
					rm -f "$pkg.new"
					rc=1
				fi
336 337
			fi
		fi
338
		[ $rc -eq 0 ] && vecho "Created $pkg"
Natanael Copa's avatar
Natanael Copa committed
339
	fi
340
	if [ -d "$LBU_POSTPACKAGE" ]; then
341
		run-parts "$LBU_POSTPACKAGE" >&2
342
	fi
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
	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"
360
	DRYRUN="-n"
361
	ENCRYPTION=
362 363
	cmd_package /dev/null
}
364 365 366 367 368 369

#
# lbu_commit - commit config files to writeable media
#
usage_commit() {
	echo "$PROGRAM $VERSION
370 371 372
Create a backup of config to writeable media.

usage: $PROGRAM commit|ci [-nv] [<media>]
373 374

Options:
Natanael Copa's avatar
Natanael Copa committed
375
  -d	Remove old apk overlay files.
376
  -e	Protect configuration with a password.
377
  -n	Don't commit, just show what would have been commited.
Natanael Copa's avatar
Natanael Copa committed
378
  -p <password>	Give encryption password on the command-line
379 380 381 382
  -v	Verbose mode.

The following values for <media> is supported: floppy usb
If <media> is not specified, the environment variable LBU_MEDIA will be used.
Natanael Copa's avatar
Natanael Copa committed
383

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

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

391
The environment variables can also be set in $LBU_CONF
392 393 394 395 396
"
	exit 1
}

cmd_commit() {
397
	local media mnt statuslist tmplist
398 399 400 401
	local incl excl outfile ovls lines

	check_openssl

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

405
	# find what media to use
Natanael Copa's avatar
Natanael Copa committed
406
	media="${1:-$LBU_MEDIA}"
407 408
	[ -z "$media" ] && usage_commit

409
	# mount media unles its already mounted
410
	mnt=/media/$media
Natanael Copa's avatar
Natanael Copa committed
411
	[ -d "$mnt" ] || usage
412
	mount_once_rw "$mnt" || die "failed to mount $mnt"
413

Natanael Copa's avatar
Natanael Copa committed
414 415 416 417 418 419 420
	# find the outfile
	outfile="$mnt/$(hostname).apkovl.tar.gz"
	if [ -n "$ENCRYPTION" ]; then
		outfile="$outfile.$ENCRYPTION"
	fi

	# remove old config files
421
	if [ -n "$DELETEOLDCONFIGS" ] ; then
Natanael Copa's avatar
Natanael Copa committed
422 423 424 425
		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
426
				echo "$rmfiles"
Natanael Copa's avatar
Natanael Copa committed
427
				echo "" >&2
428
			fi
Natanael Copa's avatar
Natanael Copa committed
429
			[ -z "$DRYRUN" ] && rm "$mnt/"*.apkovl.tar.gz*
430 431
		fi
	else
Natanael Copa's avatar
Natanael Copa committed
432
       		lines=$(ls -1 "$mnt"/*.apkovl.tar.gz* 2>/dev/null)
Natanael Copa's avatar
Natanael Copa committed
433
		if [ "$lines" = "$outfile" ]; then
Natanael Copa's avatar
Natanael Copa committed
434
			backup_apkovl "$outfile"
Natanael Copa's avatar
Natanael Copa committed
435
		elif [ -n "$lines" ]; then
436
	               	# More then one apkovl, this is a security concern
Natanael Copa's avatar
Natanael Copa committed
437
			cleanup
Natanael Copa's avatar
Natanael Copa committed
438 439 440 441
			eecho "The following apkovl file(s) were found:"
			eecho "$lines"
			eecho ""
	               	die "Please use -d to replace."
442
		fi
443
	fi
444 445 446

	# create package
	if ! cmd_package "$outfile"; then
447
		restore_apkovl "$outfile"
Natanael Copa's avatar
Natanael Copa committed
448
		cleanup
449
		die "Problems creating archive. aborting"
450
	fi
451

452 453
	# delete old backups if needed
	# poor mans 'head -n -N' done with awk.
454
	ls "$mnt"/$(hostname).[0-9][0-9][0-9][0-9]*[0-9].tar.gz 2>/dev/null \
455 456 457 458 459 460 461
		| 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
462
	# remove obsolete file. some older version of alpine needs this
463
	# to be able to upgrade
464 465
	if [ -z "$DRYRUN" ] && [ -f $mnt/packages.list ]; then
		echo "Note: Removing packages.list from $(basename $mnt)."
466
		echo "      /var/lib/apk/world will be used."
467 468
		rm -f $mnt/packages.list
	fi
469

Natanael Copa's avatar
Natanael Copa committed
470
	# make sure data is written
471
	sync
Natanael Copa's avatar
Natanael Copa committed
472
	[ "$media" = "floppy" ] && sleep 1
473 474

	# move current to commited.
475
	vecho "Successfully saved apk overlay files"
476 477 478 479 480 481 482
}

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

usage_exclude() {
	echo "$PROGRAM $VERSION
Natanael Copa's avatar
Natanael Copa committed
483
Add filename(s) to exclude list ($sysconfdir/exclude)
484 485 486

usage: $PROGRAM exclude|ex|delete [-rv] <file> ...
       $PROGRAM exclude|ex|delete [-v] -l
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501

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
502

503 504 505 506 507 508 509 510 511 512 513
	[ $# -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
514
		vecho "Exclude files:"
515
		cat "$EXCLUDE_LIST"
516
	fi
517 518
}

Natanael Copa's avatar
Natanael Copa committed
519
#---------------------------------------------------------------------------
520
# lbu_listbackup - Show old commits
521
usage_listbackup() {
Natanael Copa's avatar
Natanael Copa committed
522 523 524 525
	cat <<EOF
$PROGRAM $VERSION
Show old commits.

526
usage: $PROGRAM list-backup [<media>]
Natanael Copa's avatar
Natanael Copa committed
527 528 529 530 531

EOF
	exit 1
}

532
cmd_listbackup() {
Natanael Copa's avatar
Natanael Copa committed
533 534
	local media=${1:-"$LBU_MEDIA"}
	local mnt="/media/$media"
Natanael Copa's avatar
Natanael Copa committed
535
	[ -z "$media" ] && usage_listbackup
Natanael Copa's avatar
Natanael Copa committed
536 537 538 539 540 541 542 543

	mount_once "$mnt" || die "failed to mount $mnt"
	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
544 545 546 547 548 549
	cat <<EOF
$PROGRAM $VERSION
Revert to older commit.

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

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

Natanael Copa's avatar
Natanael Copa committed
552
EOF
Natanael Copa's avatar
Natanael Copa committed
553 554 555 556
}

cmd_revert() {
	local media=${2:-"$LBU_MEDIA"}
Natanael Copa's avatar
Natanael Copa committed
557 558 559 560 561 562
	[ -z "$media" ] && usage_revert
	local mnt="/media/$media"
	local revertto="$mnt/$1"
	local current="$mnt/$(hostname).apkovl.tar.gz"

	if [ -n "$ENCRYPTION" ]; then
563
		current="$current.$ENCRYPTION"
Natanael Copa's avatar
Natanael Copa committed
564
	fi
565
	mount_once_rw "$mnt" || die "failed to mount $mnt"
Natanael Copa's avatar
Natanael Copa committed
566
	[ -f "$revertto" ] || die "file not found: $revertto"
567
	backup_apkovl "$current"
Natanael Copa's avatar
Natanael Copa committed
568
	vecho "Reverting to $1"
569
	[ -z "$DRYRUN" ] && mv "$revertto" "$current"
Natanael Copa's avatar
Natanael Copa committed
570 571
}

572 573 574 575 576 577
#---------------------------------------------------------------------------
# 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.

578
usage: $PROGRAM status|st [-av]
579 580 581 582 583 584 585 586

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

587 588 589 590 591
cmd_status() {
	if [ -n "$USE_DEFAULT" ]; then
		apk audit --backup
		return 0
	fi
592 593 594 595
	LBU_MEDIA=${1:-"$LBU_MEDIA"}
	[ -z "$LBU_MEDIA" ] && usage_status
	local tmp
	init_tmpdir tmp
596
	mkdir -p "$tmp/a" "$tmp/b"
597 598 599 600

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

601
	# generate new apkovl and extract to tmpdir/b
602 603
	local save_encryption="$ENCRYPTION"
	ENCRYPTION=
604
	cmd_package - | tar -C "$tmp/b" -zx
605
	ENCRYPTION="$save_encryption"
606

607
	# show files that exists in a but not in b as deleted
608 609 610
	local f
	( cd "$tmp"/a && find ) | while read f; do
		f=${f#./}
611 612 613 614 615
		local b="$tmp/b/$f"
		if [ "$f" = "." ] || [ -e "$b" ] || [ -L "$b" ]; then
			continue
		fi
		echo "D $f"
616 617
	done
	
618
	# compare files in b with files in a
619 620 621 622 623
	( cd "$tmp"/b && find ) | while read f; do
		f=${f#./}
		[ "$f" = "." ] && continue
		local a="$tmp/a/$f"
		local b="$tmp/b/$f"
624
		if [ ! -e "$a" ] && [ ! -L "$a" ]; then
625
			echo "A $f"
626 627
		elif [ -f "$a" ] && [ -f "$b" ] && [ "$b" -nt "$a" ] \
		     && ! cmp -s "$a" "$b"; then
628 629 630
			echo "U $f"
		fi
	done
631 632
}

633

634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
#-----------------------------------------------------------
# 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"}
	[ -z "$LBU_MEDIA" ] && usage_diff
	local tmp
	init_tmpdir tmp
	mkdir -p "$tmpdir/a" "$tmp/b"
	unpack_apkovl "$tmp/a"
652
	ENCRYPTION=
653 654 655 656 657
	cmd_package - | tar -C "$tmp/b" -zx
	cd "$tmp" && diff -ruN a b 
}
	

658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674

#-----------------------------------------------------------
# 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";;
675 676
	list|ls)		SUBCMD="list";;
	package|pkg)		SUBCMD="package";;
677
	status|stat|st)		SUBCMD="status";;
678
	list-backup|lb)		SUBCMD="listbackup";;
Natanael Copa's avatar
Natanael Copa committed
679
	revert)			SUBCMD="revert";;
680
	diff)			SUBCMD="diff";;
681 682 683 684
	*)			usage;;
esac

# parse common args
685
while getopts "adehlM:np:qrv" opt ; do
686 687 688 689
	case "$opt" in
		a) 	[ $SUBCMD = status ] || usage_$SUBCMD
			USE_DEFAULT="-a"
			;;
690 691
		d)	DELETEOLDCONFIGS="yes"
			;;
692
		e)	[ -z "$ENCRYPTION" ] && ENCRYPTION="$DEFAULT_CIPHER"
693
			;;
694 695 696 697 698 699 700
		h) 	usage_$SUBCMD
			;;
		l)	LIST="-l"
			;;
		n) 	[ $SUBCMD = commit ] || usage_$SUBCMD
			DRYRUN="-n"
			;;
701 702
		p)	PASSWORD="$OPTARG"
			;;
703 704 705 706 707 708 709 710 711
		q)	QUIET="$QUIET -q"
			;;
		r)	REMOVE="-r"
			;;
		v) 	VERBOSE="$VERBOSE -v"
			;;
	esac
done
shift `expr $OPTIND - 1`
712

Natanael Copa's avatar
Natanael Copa committed
713
trap exit_clean SIGINT SIGTERM
714
cmd_$SUBCMD "$@"
Natanael Copa's avatar
Natanael Copa committed
715 716 717
retcode=$?

cleanup
718
exit $retcode