--- sbin/transactional-update.in
+++ sbin/transactional-update.in	2018/06/05 12:09:21
@@ -34,6 +34,8 @@
 DO_DUP=0
 DO_ROLLBACK=0
 DO_SELF_UPDATE=1
+DO_REGISTRATION=0
+REGISTRATION_ARGS=""
 ROLLBACK_SNAPSHOT=0
 REBOOT_AFTERWARDS=0
 REBOOT_METHOD="auto"
@@ -63,20 +65,31 @@
     . ${CONFFILE}
 fi
 
+# Log stderr to log file
+exec 4>&2 2> >(tee -a "${LOGFILE}")
+
 self_update() {
     if [ ${DO_SELF_UPDATE} == 0 ]; then
 	return
     fi
 
-    echo "Checking for newer version."
-    if zypper info transactional-update | grep -q '^Status *: out-of-date'; then
-	echo "New version found - updating..."
-	export TA_UPDATE_TMPFILE="`mktemp -d /tmp/transactional-update.XXXXXXXXXX`"
+    log_info "Checking for newer version."
+    if zypper --non-interactive info transactional-update | grep -q '^Status *: out-of-date'; then
+	log_info "New version found - updating..."
+	TA_UPDATE_TMPFILE="`mktemp -d /tmp/transactional-update.XXXXXXXXXX`"
+	if [ $? -ne 0 ]; then
+	    log_error "ERROR: Couldn't create temporary directory for self-update."
+	    quit 1
+	fi
+	export TA_UPDATE_TMPFILE
 	cd "${TA_UPDATE_TMPFILE}"
-	zypper --pkg-cache-dir "${TA_UPDATE_TMPFILE}" download transactional-update
-	find . -name transactional-update*.rpm -exec rpm2cpio {} \; | cpio -idmv >/dev/null
-	rm -f "${LOCKFILE}"
-	exec "${TA_UPDATE_TMPFILE}/usr/sbin/transactional-update" $@
+	zypper --non-interactive --pkg-cache-dir "${TA_UPDATE_TMPFILE}" download transactional-update
+	find . -name transactional-update*.rpm -exec rpm2cpio {} \; | cpio -idmv 2>/dev/null
+	if [ $? -ne 0 ]; then
+	    log_error "ERROR: Couldn't extract the update."
+	    quit 1
+	fi
+	exec "${TA_UPDATE_TMPFILE}/usr/sbin/transactional-update" "$@"
     fi
 }
 
@@ -85,6 +98,7 @@
     echo "       transactional-update [--no-selfupdate] [cleanup][up|dup|patch|initrd][kdump][reboot]"
     echo "       transactional-update [--no-selfupdate] [cleanup] [reboot] pkg install|remove|update PKG1..PKGN"
     echo "       transactional-update [--no-selfupdate] migration"
+    echo "       transactional-update [--no-selfupdate] register -p <product> [-r <registration code>]"
     echo "       transactional-update rollback [number]"
     exit $1
 }
@@ -406,6 +420,24 @@
 	    DO_SELF_UPDATE=0
 	    shift
 	    ;;
+	register)
+	    DO_REGISTRATION=1
+	    shift
+
+	    # Collect arguments for Registration
+	    if [ $# -eq 0 ]; then
+		usage 1
+	    fi
+
+	    while [ 1 ]; do
+		if [ $# -eq 0 ]; then
+		    break;
+		else
+		    REGISTRATION_ARGS="${REGISTRATION_ARGS} $1";
+		    shift
+		fi
+	    done
+	    ;;
 	-h|--help)
 	    usage 0
 	    ;;
@@ -424,16 +456,17 @@
     usage 1;
 fi
 
+# Check if this is a self-updated transactional-update; if it isn't lock and
+# check for update
 if [ -z "${TA_UPDATE_TMPFILE}" ]; then
-  self_update "${ORIG_ARGS[@]}"
-else
-  trap 'rm -rf "${TA_UPDATE_TMPFILE}" && unset TA_UPDATE_TMPFILE' EXIT
-fi
-
-bashlock "/var/run/transactional-update.pid"
-if [ $? -ne 0 ]; then
-  echo "Couldn't get lock, is another instance already running?"
-  exit 1;
+    bashlock "/var/run/transactional-update.pid"
+    if [ $? -ne 0 ]; then
+	echo "Couldn't get lock, is another instance already running?"
+	exit 1
+    fi
+    self_update "${ORIG_ARGS[@]}"
+else # Set exit handler to clean up artifacts of the self-update
+    trap 'rm -f "$LOCKFILE" && rm -rf "${TA_UPDATE_TMPFILE}" && unset TA_UPDATE_TMPFILE' EXIT
 fi
 
 # Load old state file
@@ -468,7 +501,7 @@
     fi
 fi
 
-if [ ${ZYPPER_AUTO_IMPORT_KEYS} -eq 1 ]; then
+if [ -n "${ZYPPER_ARG}" -a ${ZYPPER_AUTO_IMPORT_KEYS} -eq 1 ]; then
     ZYPPER_ARG="--gpg-auto-import-keys ${ZYPPER_ARG}"
 fi
 
@@ -484,7 +517,7 @@
 	NEED_REBOOT_WARNING=0
     fi
 
-    echo "Rollback to snapshot ${ROLLBACK_SNAPSHOT}..."
+    log_info "Rollback to snapshot ${ROLLBACK_SNAPSHOT}..."
 
     if [ ${RO_ROOT} == "true" ]; then
 	BTRFS_ID=`btrfs subvolume list / |grep /.snapshots/${ROLLBACK_SNAPSHOT}/snapshot | awk '{print $2}'`
@@ -581,10 +614,20 @@
 
 if [ -n "${ZYPPER_ARG}" -o ${REWRITE_GRUB_CFG} -eq 1 \
     -o ${REWRITE_INITRD} -eq 1 -o ${REBUILD_KDUMP_INITRD} -eq 1 \
-    -o ${RUN_SHELL} -eq 1 -o ${REWRITE_BOOTLOADER} -eq 1 ]; then
+    -o ${RUN_SHELL} -eq 1 -o ${REWRITE_BOOTLOADER} -eq 1 \
+    -o ${DO_REGISTRATION} -eq 1 ]; then
 
-    # Check if there are updates at all.
-    if [ -n "${ZYPPER_ARG}" -a -n "${ZYPPER_NONINTERACTIVE}" ]; then
+    # If the current snapshot and the default snapshot differ
+    # there have been changes that we are now discarding.
+    if [ "${DEFAULT_SNAPSHOT_ID}" -ne "${CURRENT_SNAPSHOT_ID}" ]; then
+       log_info "WARNING: Default snapshot differs from current snapshot."
+       log_info "WARNING: Any changes within the previous snapshot will be discarded!"
+    fi
+
+    # Check if there are updates at all. Don't check if we do
+    # a registration, as this can change the zypper result.
+    if [ -n "${ZYPPER_ARG}" -a -n "${ZYPPER_NONINTERACTIVE}" \
+         -a ${DO_REGISTRATION} -eq 0 ]; then
 	if [ $DO_DUP -eq 1 ]; then
 	    "${SELF_PATH}"/transactional-update-helper disable-optical
 	fi
@@ -687,8 +730,7 @@
 
     # Check which directories in /boot/grub2 need to be mounted,
     # otherwise grub2 will not boot after a version update.
-    DIR_TO_MOUNT="${DIR_TO_MOUNT} $(awk '$2 ~ /\/boot\/grub2\// { print $2 }' /proc/mounts)"
-
+    DIR_TO_MOUNT="${DIR_TO_MOUNT} $(awk '$2 ~ /^\/boot\/grub2\// { print $2 }' /proc/mounts)"
 
     # Mount everything we need:
     mount -t proc none ${SNAPSHOT_DIR}/proc
@@ -759,6 +801,10 @@
 	fi
     done
 
+    if [ ${DO_REGISTRATION} -eq 1 ]; then
+	SUSEConnect --root ${MOUNT_DIR}  ${REGISTRATION_ARGS}
+    fi
+
     if [ -n "${ZYPPER_ARG}" ]; then
 
 	calc_user_group_sha256sum
@@ -794,8 +840,14 @@
 	    if [ $? -ne 0 ]; then
 		check_registration_on_next_reboot
 	    fi
+	    # Rebuild grub.cfg if /etc/os-release changes, could change grub
+	    # menu output, too.
+	    cmp -s /etc/os-release ${MOUNT_DIR}/etc/os-release
+	    if [ $? -ne 0 ]; then
+	        REWRITE_GRUB_CFG=1
+	    fi
 	else
-	    log_error "ERROR: zypper ${ZYPPER_ARG} on ${MOUNT_DIR} failed!"
+	    log_error "ERROR: zypper ${ZYPPER_ARG} on ${MOUNT_DIR} failed with exit code ${RETVAL}!"
 	    EXITCODE=1
 	fi
     fi
@@ -836,7 +888,7 @@
 
     if [ ${RUN_SHELL} -eq 1 ]; then
 	echo "Opening chroot in snapshot ${SNAPSHOT_ID}, continue with 'exit'"
-	env PS1="transactional update # " chroot ${MOUNT_DIR} bash
+	env PS1="transactional update # " chroot ${MOUNT_DIR} bash 2>&4
     fi
 
     # Unset variable
@@ -880,8 +932,8 @@
 
     # Somersault:
     if [ $EXITCODE -eq 0 ]; then
-	BTRFS_ID=`btrfs subvolume list / |grep ${SNAPSHOT_DIR} | awk '{print $2}'`
-	if [ -z $BTRFS_ID ]; then
+	BTRFS_ID=`btrfs subvolume list / |grep ${SNAPSHOT_DIR}$ | awk '{print $2}'`
+	if [ -z "$BTRFS_ID" ]; then
 	    log_error "ERROR: couldn't determine btrfs subvolume ID"
 	    EXITCODE=1
 	else
