lbu.in 15.8 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
# unpack archive on LBU_MEDIA to given dir
unpack_apkovl() {
	local f="$(hostname).apkovl.tar.gz"
	local dest="$1"
163
	local mnt="${LBU_BACKUPDIR:-/media/$LBU_MEDIA}"
164 165
	local count=0
	mkdir -p "$dest"
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

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

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:"
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"
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)"
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
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
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
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
}
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>]
385 386

Options:
Natanael Copa's avatar
Natanael Copa committed
387
  -d	Remove old apk overlay files.
388
  -e	Protect configuration with a password.
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
391 392 393
  -v	Verbose mode.

The following values for <media> is supported: floppy usb
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

404
The environment variables can also be set in $LBU_CONF
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"

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
423

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
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
459
	fi
460 461 462

	# create package
	if ! cmd_package "$outfile"; then
463
		restore_apkovl "$outfile"
Natanael Copa's avatar
Natanael Copa committed
464
		cleanup
465
		die "Problems creating archive. aborting"
466
	fi
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
485

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

	# move current to commited.
491
	vecho "Successfully saved apk overlay files"
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
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

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:"
531
		cat "$EXCLUDE_LIST"
532
	fi
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"}
550 551
	local mnt="${LBU_BACKUPDIR:-/media/$media}"
	[ -z "$media" ] && [ -z "$LBU_BACKUPDIR" ] && usage_listbackup
Natanael Copa's avatar
Natanael Copa committed
552

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
}

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]
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"}
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"
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
}

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

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";;
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";;
699 700 701 702
	*)			usage;;
esac

# parse common args
703
while getopts "adehlM:np:qrv" opt ; do
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
			;;
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"
			;;
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
736
exit $retcode