#!/bin/bash
# Note: running this scipt with bash is mandatory only becausee the -e option
# of read is not defined in POSIX.

# Name: absm or A Btrfs Snapshots Manager

# This script has been written from scratch and dedicated to the public
# domain by its author: Didier Spaier, Paris.

# Anyone is free to copy, modify, publish, use, sell, or distribute it
# for any purpose, commercial or non-commercial, and by any means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>

# This script provide an accessible to the blind and easy to use btrfs snapshots manager, mostly
# intended to allow booting and restoring a system in its previous state if can't boot or does not
# work as expected otherwise. The first boot entries are associated with a hot key bearing their
# number (most recent first) so users can just press this key to boot a wanted snapshot.

# Each snapshots bear as name its creation date, and all creations, deletions and restorations
# are logged.

# To know more, read or run the script. :-)

# TODO:
# Add a function that compare two subvolumes
# Manage snapshots of /home

# The directive below for https://www.shellcheck.net/wiki/SC1090 -- ShellCheck can't follow non-const...
# shellcheck source=/dev/null

# Last change: build the list of snapshots .snapshots/snsphots.cfg after each modification and in
# copy it in all snapshots and in the root subvolume.


#------ No edit should be necessary beyond this line ---------------------------------------------#

ROOT_SUBVOL="$(grep ' / ' /etc/fstab|sed 's;.*subvol=;;;s;,.*;;')"
# TODO: write another script to manage snapshots of /home (GRUB not involved then).
# The aim would be to recover a deleted file, or the previous state of a file,
# rather than restoring the subvolume.
#HOME_SUBVOL="$(findmnt -no source /home|sed "s@.*/@@;s@]@@")"
OS_NAME=$(grep "^NAME" /etc/os-release|cut -d"=" -f2)

# The boot entries for the snapshots should be updated after a creation, deletion or restoration.
# In this aim, disable Ctl+C while we are running.
trap "" INT

#
# Auxiliary functions
#
to_lower() {
	echo "$1"|tr '[:upper:]' '[:lower:]'
}
log() {
	printf %b "$(date "+%Y-%m-%d:%Hh%Mm%Ss") ${1}\n" >> "$LOGFILE"
}
#
# Initialization
#
check_specs() {
	[ "$(id -u)" -ne 0 ] && echo "Please run this program as root or using sudo." && exit
	MISSING=/run/$(date +%s)
	while true; do
		unset GRUB
		if command -v grub-install 1>/dev/null ; then
			GRUB=grub
		elif command -v grub2-install 1>/dev/null ; then
			GRUB=grub2
		else
			echo "grub is missing." >> "$MISSING" && break
		fi
		[ ! -f /boot/"$GRUB"/grub.cfg  ] && echo "You need to generate /boot/$GRUB/grub.cfg first." >> "$MISSING"
		if ! findmnt / -no FSTYPE|grep -q btrfs; then
			echo "The root partition does not contain a btrfs file system." >> "$MISSING" && break
		fi
		if ! findmnt /|grep -q "subvol="; then
			echo "The root partition is not mounted as a subvolume" >> "$MISSING" && break
		fi
		! command -v btrfs 1>/dev/null && echo "btrfs-progs is missing." >> "$MISSING" && break
		break
	done
	if [ -s "$MISSING" ]; then
		echo "This script can't be used for this reason:"
		cat "$MISSING"
		printf "Press Enter to quit "
		read -r
		rm -f "$MISSING"
		trap - INT
		exit	
	fi
	# w3m is a very accessible to the blind browser and pager.
	# We use it if available to allow navigating in an output, else use less is available,
	# else just display it with cat.
	HAVE_W3M=$(command -v w3m)
	HAVE_LESS=$(command -v less)
}
set_paths() {
	# All snapshots taken will be stored in "$MOUNTPOINT"/.snapshots, named $(date +%Y-%m-%d:%Hh%Mm%Ss) and
	# the associated metadata (used to build a boot entry for each) stored in a file bearing the
	# same name in "$MOUNTPOINT"/.snapshots/ $(date +%Y-%m-%d:%Hh%Mm%Ss)/var/lib/snapshot_metadata.
	# "$MOUNTPOINT"/.snapshots is created on top of the volume and created if need be.
	MOUNTPOINT=/run/$(date +%s)
	mkdir "$MOUNTPOINT"
	ROOTDEV=$(df --output=source,target|grep /$|cut -d" " -f1)
	mount "$ROOTDEV" "$MOUNTPOINT" -o subvolid=0
	LOGFILE="$MOUNTPOINT"/.snapshots/log
	mkdir -p "$MOUNTPOINT"/.snapshots
	chmod 750 "$MOUNTPOINT"/.snapshots
}
write_grub_hook() {
	# The content of the file 80_snapshots will be appended by grub-mkconfig to
	# /boot/"$GRUB"/grub.cfg thus the GRUB menu will include a boot entry for each created snapshot
	# listed in /boot/"$GRUB"/snapshots.cfg, written by the function write_snapshots_cfg.
if [ ! -f /etc/grub.d/80_snapshots ]; then
	cat<<-'eof'>/etc/grub.d/80_snapshots
	cat<<EOF
	 if [ -f  \${config_directory}/snapshots.cfg ]; then
	    source \${config_directory}/snapshots.cfg
	elif [ -z "\${config_directory}" -a -f  \$prefix/snapshots.cfg ]; then
	    source \$prefix/snapshots.cfg
	fi
	EOF
	eof
	chmod 755 /etc/grub.d/80_snapshots
fi
! grep -q snapshots.cfg  /boot/$GRUB/grub.cfg && echo "You need to regenerate /boot/$GRUB/grub.cfg before using this program." && closing
}
write_features() {
	cat <<-EOF> "$MOUNTPOINT/features"
	PRESENTATION
	
	This script allows you to take snapshots of the root subvolume of a system
	mounted as /, allowing ou to boot off one of them from the GRUB boot menu,
	and also to rollback the system restoring one of them.

	It requires that the / and /home directories be mounted as btrfs subvolumes.
	Currently it takes snapshots of / as a whole, excluding /home.
	
	The snapshots can be taken on demand by running the script on the command 
	line, or by another script that runs it to take snapshots upon events such as
	after boot or before a package update, or periodically through a cron job.

	WARNING
	As the snapshots are stored in the same file system as the root subvolume, this
	script does not protect against a hardware failure. This is not a backup tool!
	For that you could use btrbk, that can make incremental backups of / and /home
	using btrfs features.
	
	FEATURES
	When run without argument, this command starts by performing some checks, then
	if successful greets the user in a menu of items that allow to:
	. Create a snapshot.
	. Delete a snapshot.
	. Rollback the system to a previous state, recorded in a snapshot.
	. List the existing snapshots.
	. Display the GRUB boot menu including the snapshots, as it will appear at
	  the next boot. Note: in some cases the menu displayed may be different from
	  the one that will appear at next boot.
	. Display this file.
	. Show how to use snapshots and manage rollbacks.
	. View the log of creations, deletions and restorations of snapshots.
	
	The menu is contextual: it does not offer to delete, list or restore snapshots
	if none exist. When running from a snapshot it will only allows to display
	the GRUB boot menu or restore that snapshot.
	
	All snapshot creations, deletions and recoveries are logged.
	
	The "absm c" command creates a new snapshot unattended, usually from a script.
	If the SHORTDESC variable is set, its value is displayed in the entry for
	this snapshot in the GRUB boot menu. If the LONGDESC variable is set, it will
	be displayed in the log.
	
	A new snapshot is taken just before a rollback to enable it to be rolled back.
	This is optional if the snapshot being rolled back is running.

	LINKS
	https://btrfs.readthedocs.io/en/latest/
	https://digint.ch/btrbk/
	EOF
}
write_rollbacks() {
	cat <<-EOF> "$MOUNTPOINT/rollbacks"
	HOW-TO USE SNAPSHOTS AND MANAGE ROLLBACKS

	You can use snapshots to collect files or directories from one of them to
	replace those that have been accidentally deleted or corrupted, or to rollback
	the system to a previous, if this is the only or easiest way to repair it.

	Restoring a snapshot triggers a global rollback of the system, excluding /home,
	including files that should kept up to date, such as databases or web servers.

	For this reason, immediately after a rollback it may also be necessary to
	replace files wityh up to date ones stored in the snapshot taken just before
	the rollback, especially if the restored snapshot was old. Alternatively you
	can exclude from the snapshots directories containing files that should 
	be kept up to date, provided that they are part of the core system.
	
	SELECTIVELY REPLACING FILES OR DIRECTORIES WITH CURRENT ONES

	This can be done at any time, even immediately after a rollback.
	
	If done after a rollback we recommend that you perform the rollback,
	then immediately reboot so that the system be in a clean state,
	and only then perform the necessary replacements.
	
	You will need to identify the new snapshot taken just before the rollback,
	in this case the most recent one, from which you will copy files or
	directories into the running system as required.

	To do this, simply run this script and choose "list the snapshots."
	Example of output below:
	
	List of the snapshots in your Slint system:
	snapshot 1 [2024-05-14:22h10m10s] (before restoring from 2024-05-08:21h20m15s)
	snapshot 2 [2024-05-13:21h26m27s] (with extra and testing)
	snapshot 3 [2024-05-08:21h42m12s] (with extra but not testing)
	
	Snapshot 1, dated 2024-05-14:22h10, is the most recent.
	
	To access it, first mount the root partition (/dev/sda3 in the example
	below) at the top level of the btrfs volume, like this (as root):
	root[~]# mount /dev/sda3 /mnt

	The snapshots are stored  in the /mnt/.snapshots directory, named
	by their date, so the path to the snapshot 1 is:
	/mnt/.snapshots/2024-05-14:22h10m10s
	
	You can view a file in it, e.g. /etc/fstab, by typing:
	cat /mnt/.snapshots/2024-05-14:22h10m10s/etc/fstab
	and compare with the older version you have restored typing:
	cat /etc/fstab
	
	Then you can either edit the file in the running system or copy the one
	from the snapshot into the running system.
	
	You can also copy entire directories. For example to fastly copy the entire
	/var directory, as root you can type:
	mv /var /var.bak
	cp -a --reflink=always /mnt/.snapshots/2024-05-14:22h10m10s/var  /
	# Now, check the content of /var.  if OK type:
	rm -r /var.bak

	EXCLUDE DIRECTORIES FROM THE SNAPSHOTS
	
	WARNING: Be careful not to exclude directories which are part of the core
	system, or should stay in sync. For example the installed package log 
	stored in /var/lib/pkgtools in Slackware, should not be excluded as this
	would break the package management system. 
	
	Let's assume that you to want to exclude the /opt directory from snapshots. 
	directory /opt. If you have not already done so log as root, then type:
	root[~]# mount /dev/sda3 /mnt

	NOTE: The mount command options may need to be adjusted to suit your system
	or distribution. Looking at the mount options of / in /etc/fsab an give you
	an idea. Also, excluding the /opt directory could make it out of sync with
	the packages management system so take this is as an example.
	
	Then, still as root create a subvolume for /opt:
	btrfs subvol create /mnt/@opt
	
	Copy all the contentd of /opt to this subvolume:
	cp -a --reflink=always /opt/* /mnt/@opt

	Backup /opt, just in case.
	mv /opt /opt.bak
	mkdir /opt
	
	Now mount /opt as a subvolume. For example:
	mount /dev/sda3 /opt -o subvol=@opt,compress=zstd,discard=async,noatime

	Check carefully the content of /opt. If and if it is OK type:
	rm -r opt.bak

	To have /opt mounted on every boot, as now needed, append this line to
	/etc/fstab:
	UUID=<uuid of /> /opt brfs subvol=@opt,compress=zstd,discard=async,noatime 0 0
	
	Rememeber to do this before a reboot!
	Then on every boot, /opt will be mounted as subvolume, separate from /.
	
	Note: The UUID of / (actually, its filesystem) is the output of:
	findmnt -no uuid /
	EOF
}
	
rollbacks() {
	clear
	if [ "$HAVE_W3M" ]; then
		echo >> "$MOUNTPOINT/rollbacks" 
		echo "Press q to go back to the menu." >> "$MOUNTPOINT/rollbacks"
		w3m -o confirm_qq=false "$MOUNTPOINT/rollbacks"
	elif [ "$HAVE_LESS" ]; then
		echo >> "$MOUNTPOINT/rollbacks" 
		echo "Press q to go back to the menu." >> "$MOUNTPOINT/rollbacks"
		less "$MOUNTPOINT/rollbacks"
	else
		cat "$MOUNTPOINT/rollbacks"
		printf "Press Enter to go back to the menu "
		read -r ANSWER
	fi
	clear
}
#
# Other functions
#
features() {
	clear
	if [ "$HAVE_W3M" ]; then
		echo >> "$MOUNTPOINT/features" 
		echo "Press q to go back to the menu." >> "$MOUNTPOINT/features"
		w3m -o confirm_qq=false "$MOUNTPOINT/features"
	elif [ "$HAVE_LESS" ]; then
		echo >> "$MOUNTPOINT/features" 
		echo "Press q to go back to the menu." >> "$MOUNTPOINT/features"
		less "$MOUNTPOINT/features"
	else
		cat "$MOUNTPOINT/features"
		printf "Press Enter to go back to the menu "
		read -r ANSWER
	fi
	clear
}
write_snapshots_cfg() {
	# This function is called as soon as the script is started, even if no action is taken and
	# also when the user quits, to make sure the boot entries displayed in the GRUB menu stay in
	# sync with the "on demand" snapshots it manages.
	# For each snapshot written by this script we write a boot entry in /boot/"$GRUB"/snapshots.cfg
	# including the values of the variables set sourcing this file.
	# Preserve the values of SNAP_NAME and SNAP_SHORT_DESC from the caller
	SNAP_NUMBER=0
	btrfs sub list -s "$MOUNTPOINT" |grep "[.]snapshots"|sed "s;.* .snapshots/;;"|sort -r > "$MOUNTPOINT/snapshots_list"
	if [ ! -s "$MOUNTPOINT/snapshots_list" ]; then
		rm -f "$MOUNTPOINT/$ROOT_SUBVOL/boot/grub/snapshots.cfg"
		return
	fi
	rm -f "$MOUNTPOINT/snapshots.cfg"
	while read -r i; do
		unset INITRAMFS
		[ -f "$MOUNTPOINT"/.snapshots/"$i"/var/lib/snapshot_metadata ] \
		&& . "$MOUNTPOINT"/.snapshots/"$i"/var/lib/snapshot_metadata
		SNAP_NAME="$i"
		SNAP_NUMBER=$((SNAP_NUMBER + 1))
		if [ "$INITRAMFS" ]; then
			# If the patch to the kernel in /proc/cmdline includes a prefix after "linux" and
			# before / we need to include it also in the path to the initramfs, as we assume that
			# they live in the same directory. This can happen for instance is /boot is in its own
			# partition with an ext4 file system, as in Fedora 37.
			INITRD_PREFIX="/.snapshots/$SNAP_NAME/boot"
			KERNEL_PREFIX="$(echo "$CMDLINE"|cut -d/ -f1)"
			[ "$KERNEL_PREFIX" ] && INITRD_PREFIX="$KERNEL_PREFIX"
			cat<<-eof>>"$MOUNTPOINT/snapshots.cfg"
			menuentry 'snapshot $SNAP_NUMBER [$SNAP_NAME] ($SNAP_SHORT_DESC)' --hotkey=$SNAP_NUMBER {
				insmod part_gpt
				insmod part_msdos
				insmod btrfs
				insmod all_video
				echo 'Loading kernel: $KVER ...'
				linux $CMDLINE
				echo 'Loading initramfs: $INITRAMFS ...'
				initrd $INITRD_PREFIX/$INITRAMFS
			}
			eof
		else
			cat<<-eof>>"$MOUNTPOINT/snapshots.cfg"
			menuentry 'snapshot $SNAP_NUMBER [$SNAP_NAME] ($SNAP_SHORT_DESC)' --hotkey=$SNAP_NUMBER {
				insmod part_gpt
				insmod part_msdos
				insmod btrfs
				insmod all_video
				echo 'Loading kernel: $KVER ...'
				linux $CMDLINE
			}
			eof
		fi
	done < "$MOUNTPOINT/snapshots_list"
	while read -r i; do
		cp "$MOUNTPOINT/snapshots.cfg" "$MOUNTPOINT/.snapshots/$i/boot/grub/"
	done < "$MOUNTPOINT/snapshots_list"
	cp "$MOUNTPOINT/snapshots.cfg" "$MOUNTPOINT/$ROOT_SUBVOL/boot/grub/"
}
display_grub_menu() {
	# We write in list_boot_entries the description of each boot entry listed in
	# /boot/$GRUB/grub.cfg and case occurring /boot/$GRUB/snapshots.cfg. We append a text
	# indicating how to reach a given boot entry.
	# The file $list_boot_entries, is then displayed (in w3m, used as a pager, if available).
	clear
	rm -f "$MOUNTPOINT/listbootentries"
	sed -n "{
		/submenu/,/^}$/ {
		/^[[:space:]]*submenu /s%[[:space:]]*[^']*'\([^']*\)'.*%\1%p
		/^[[:space:]]*\menuentry /s%[^']*'\([^']*\)'.*%  \1%p
		}
		/^[[:space:]]*\menuentry /s%[^']*'\([^']*\)'.*%\1%p
	}" /boot/grub/grub.cfg >> "$MOUNTPOINT/listbootentries"
	for i in $(find /boot/grub/* -prune -name "*.cfg"|grep -v grub.cfg); do
		sed -n "/^[[:space:]]*\menuentry /s%[^']*'\([^']*\)'.*%\1%p" "$i" >> "$MOUNTPOINT/listbootentries"
	done
	if grep -q snapshot "$MOUNTPOINT/listbootentries"; then
		SNAP="
To boot directly a snapshot, you can just press the key bearing its number,
if it is lower than 10.
The snapshot number 1 is the most recent.
"
	fi
	echo "
After booting, the boot menu will be displayed as above.

To navigate in the menu you will use the down and up arrow keys,
then press Enter to use the selected boot entry.
To display the boot entries inside a submenu, select it then press Enter.
$SNAP" >> "$MOUNTPOINT/listbootentries"
	if [ "$HAVE_W3M" ]; then
		qecho "Press q to go back to the menu." >> "$MOUNTPOINT/listbootentries"
		w3m -o confirm_qq=false "$MOUNTPOINT/listbootentries"
	elif [ "$HAVE_LESS" ]; then
		echo "Press q to go back to the menu." >> "$MOUNTPOINT/listbootentries"
		less "$MOUNTPOINT/listbootentries"
	else
		cat "$MOUNTPOINT/listbootentries"
		echo
		printf "Press Enter to go back to the menu "
		read -r ANSWER
	fi
	rm -f "$MOUNTPOINT/listbootentries"
	menu
}
view_the_log() {
	if [ "$HAVE_W3M" ]; then
		echo >> "$LOGFILE"
		echo "Press q to go back to the menu." >> "$LOGFILE"
		w3m -o confirm_qq=false "$LOGFILE"
		sed  '/^$/d;$d' "$LOGFILE" > bof
		mv bof "$LOGFILE"
	elif [ "$HAVE_LESS" ]; then
		echo >> "$LOGFILE"
		echo "Press q to go back to the menu." >> "$LOGFILE"
		less "$LOGFILE"
		sed  '/^$/d;$d' "$LOGFILE" > bof
		mv bof "$LOGFILE"
	else
		cat "$LOGFILE"
		echo
		printf "Press Enter to go back to the menu "
		read -r ANSWER
	fi
	menu
}
create_snapshot() {
	NB_SNAP=0
	NB_SNAP=$(find "$MOUNTPOINT"/.snapshots -type d -maxdepth 1 -mindepth 1|wc -l)
	SNAPSHOTS="snapshots"
	[ "$NB_SNAP" -eq 1  ] && SNAPSHOTS="snapshot"
	if [ "$NB_SNAP" -ge 1  ]; then
		echo "You have already created the $SNAPSHOTS listed below:"
		display_snapshots
		echo
		printf "Type yes to create one more snapshot or Enter to go back to the menu: "
		read -r ANSWER
		[ ! "$(to_lower "$ANSWER")" = "yes" ] && menu
	fi
	KERNEL="$(sed "s|[^=]*=||;s|[ ].*||;s|.*/||" /proc/cmdline)"
	KERNEL_FOUND=$(find /boot -name "$KERNEL")
	if [ ! "$KERNEL_FOUND" ]; then
		echo "The running kernel was not found in /boot."
		echo "thus we can not create a snapshot using it."
		printf "Press Enter to go back to the menu "
		read -r ANSWER
		menu
	fi
	SNAP_NAME="$(date +%Y-%m-%d:%Hh%Mm%Ss)"
	NEW_SNAP_SHORT_DESC="on demand"
	echo "By default the snapshot will be labeled \"on demand\" but you may type"
	echo "a description instead (it should have between 5 and 40 characters)."
	while true; do
		printf "Description [on demand]: "
		read -r -e ANSWER
		[ ! "$ANSWER" ] && break
		FORBIDDEN=$(printf %s "$ANSWER"|grep -e "[]'([)*]" -e '"')
		DESC_LENGTH="$(printf %s "$ANSWER"|wc -c)"
		if [ "$DESC_LENGTH" -gt 40 ]; then
			echo "The description should have at most 40 characters, make it $((DESC_LENGTH -40)) shorter."
		elif [ "$DESC_LENGTH" -lt 5 ]; then
			echo "The description should have at least 5 characters."
		elif [ "$FORBIDDEN" ]; then
			echo "The characters  [ ] ' \" ( ) are not allowed."
		else
			NEW_SNAP_SHORT_DESC="$ANSWER"
			break
		fi
	done
	btrfs subvolume snapshot "$MOUNTPOINT/$ROOT_SUBVOL" "$MOUNTPOINT"/.snapshots/"$SNAP_NAME" 1>/dev/null
	RES="$?"
	if [ "$RES" -ne 0 ]; then
		echo "snapshot creation failed"
		printf "Press Enter to go back to the menu "
		read -r ANSWER
		menu
	fi
	# We generate the metadata that will be used to include a boot entry for this snapshot in
	# /boot/grub/snapshots.cfg. They will be recorded in
	# "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
	mkdir -p "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib
	KVER=$(uname -r)
	unset INITRAMFS
	# We first try to find an initramfs whose name matches that of the kernel
	KERNEL="$(sed "s|[^=]*=||;s|[ ].*||;s|.*/||" /proc/cmdline)"
	KERNEL_VERSION="$(echo "$KERNEL"|cut -d- -f 2-)"
	ALL_INITRAMFS=$(find /boot/ -name "initr*${KERNEL_VERSION}*" -type f)
	CMDLINE="$(sed "
		s|[^=]*=||
		s|.*/boot|/.snapshots/$SNAP_NAME/boot|
		s|subvol=[[:graph:]]*|subvol=.snapshots/$SNAP_NAME|" /proc/cmdline)"
	[ "$ALL_INITRAMFS" ] && INITRAMFS="$(echo "$ALL_INITRAMFS"|sed "s|.*/||"|head -n 1)"
	# If no initramfs whose name includes the kernel version, try initrd.gz and initrd.img
	[ ! "$INITRAMFS" ] && [ -f /boot/initrd.gz ] && INITRAMFS=/boot/initrd.gz
	[ ! "$INITRAMFS" ] && [ -f /boot/initrd.img ] && INITRAMFS=/boot/initrd.img
	# Still not found? Try a match with uname -r
	if [ ! "$INITRAMFS" ]; then
		ALL_INITRAMFS=$(find /boot/ -name "initr*" -type f|grep "$KVER")
		[ "$ALL_INITRAMFS" ] && INITRAMFS=$(echo "$ALL_INITRAMFS"|head -n 1)
	fi
	if [ "$INITRAMFS" ]; then
		echo "SNAP_SHORT_DESC=\"$NEW_SNAP_SHORT_DESC\" KVER=\"$KVER\" CMDLINE=\"$CMDLINE\" INITRAMFS=\"$INITRAMFS\"" \
	> "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
	else
		echo "SNAP_SHORT_DESC=\"$NEW_SNAP_SHORT_DESC\" KVER=\"$KVER\" CMDLINE=\"$CMDLINE\"" \
	> "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
	fi
	[ "$LONGDESC" ] && echo "LONGDESC=\"$LONGDESC\"" >> "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
	log "$SNAP_NAME ($NEW_SNAP_SHORT_DESC) created"
	echo "A snapshot has been created as \"$NEW_SNAP_SHORT_DESC\""
	printf "Press Enter to go back to the menu "
	read -r ANSWER
	menu
}
create_snapshot_unattended() {
	KERNEL="$(sed "s|[^=]*=||;s|[ ].*||;s|.*/||" /proc/cmdline)"
	KERNEL_FOUND=$(find /boot -name "$KERNEL")
	if [ ! "$KERNEL_FOUND" ]; then
			log "Creation of a snapshot failed. Reason: running kernel not found in /boot."
	fi
	SNAP_NAME="$(date +%Y-%m-%d:%Hh%Mm%Ss)"
	SNAP_SHORT_DESC="on demand"
	btrfs subvolume snapshot "$MOUNTPOINT/$ROOT_SUBVOL" "$MOUNTPOINT"/.snapshots/"$SNAP_NAME" 1>/dev/null
	RES="$?"
	if [ "$RES" -ne 0 ]; then
		log "Making a snapshot of the root subvolume $MOUNTPOINT/$ROOT_SUBVOL failed."
		exit
	else
		[ "$SHORTDESC" ] && SNAP_SHORT_DESC="$SHORTDESC"
		# We generate the metadata that will be used to include a boot entry for this snapshot in
		# /boot/grub/snapshots.cfg. They will be recorded in
		# "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
		mkdir -p "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib
		KVER=$(uname -r)
		unset INITRAMFS
		# We first try to find an initramfs whose name matches that of the kernel
		KERNEL="$(sed "s|[^=]*=||;s|[ ].*||;s|.*/||" /proc/cmdline)"
		KERNEL_VERSION="$(echo "$KERNEL"|cut -d- -f 2-)"
		ALL_INITRAMFS=$(find /boot/ -name "initr*${KERNEL_VERSION}*" -type f)
		CMDLINE="$(sed "
			s|[^=]*=||
			s|.*/boot|/.snapshots/$SNAP_NAME/boot|
			s|subvol=[[:graph:]]*|subvol=.snapshots/$SNAP_NAME|" /proc/cmdline)"
		[ "$ALL_INITRAMFS" ] && INITRAMFS="$(echo "$ALL_INITRAMFS"|sed "s|.*/||"|head -n 1)"
		# If no initramfs whose name includes the kernel version, try initrd.gz and initrd.img
		[ ! "$INITRAMFS" ] && [ -f /boot/initrd.gz ] && INITRAMFS=/boot/initrd.gz
		[ ! "$INITRAMFS" ] && [ -f /boot/initrd.img ] && INITRAMFS=/boot/initrd.img
		# Still not found? Try a match with uname -r
		if [ ! "$INITRAMFS" ]; then
			ALL_INITRAMFS=$(find /boot/ -name "initr*" -type f|grep "$KVER")
			[ "$ALL_INITRAMFS" ] && INITRAMFS=$(echo "$ALL_INITRAMFS"|head -n 1)
		fi
		if [ "$INITRAMFS" ]; then
			echo "SNAP_SHORT_DESC=\"$SNAP_SHORT_DESC\" KVER=\"$KVER\" CMDLINE=\"$CMDLINE\" INITRAMFS=\"$INITRAMFS\"" \
		> "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
		else
			echo "SNAP_SHORT_DESC=\"$SNAP_SHORT_DESC\" KVER=\"$KVER\" CMDLINE=\"$CMDLINE\"" \
		> "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
		fi
		if [ "$LONGDESC" ]; then
			echo "LONGDESC=\"$LONGDESC\"" >> "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
			log "$SNAP_NAME ($SNAP_SHORT_DESC\n$LONGDESC) created."
		else
			log "$SNAP_NAME ($SNAP_SHORT_DESC) created"
		fi
		closing
	fi
}
display_snapshots() {
	SNAP_NUM=0
	btrfs sub list -s "$MOUNTPOINT" |grep "[.]snapshots"|sed "s;.* .snapshots/;;"|sort -r > "$MOUNTPOINT/list_of_snapshots"
	while read -r i; do
		if [ -f "$MOUNTPOINT"/.snapshots/"$i"/var/lib/snapshot_metadata ]; then 
			. "$MOUNTPOINT"/.snapshots/"$i"/var/lib/snapshot_metadata
			SNAP_NAME="$i"
			SNAP_NUM=$((SNAP_NUM + 1))
			echo snapshot "$SNAP_NUM" ["$SNAP_NAME"] \("$SNAP_SHORT_DESC"\)
		else
			echo "WARNING: no metadata written by absm for the snapshot $MOUNTPOINT/.snapshots/$i"
		fi
	done < "$MOUNTPOINT/list_of_snapshots"
	unset SNAP_SHORT_DESC
	rm -f "$MOUNTPOINT/list_of_snapshots"
}
numbered_snapshots() {
	SNAP_NUM=0
	btrfs sub list -s "$MOUNTPOINT" |grep "[.]snapshots"|sed "s;.* .snapshots/;;"|sort -r > "$MOUNTPOINT/list_of_snapshots"
	while read -r i; do
		SNAP_NUM=$((SNAP_NUM + 1))
		if [ -f "$MOUNTPOINT/.snapshots/$i/var/lib/snapshot_metadata" ]; then
			. "$MOUNTPOINT/.snapshots/$i/var/lib/snapshot_metadata"
			SNAP_NAME="$i"
			if [ "$SNAP_SHORT_DESC" ]; then
				echo "$SNAP_NUM|$SNAP_NAME|$SNAP_SHORT_DESC"
			fi
		else 
			echo "$SNAP_NUM|$SNAP_NAME|(description not available)"
		fi
	done < "$MOUNTPOINT/list_of_snapshots" > "$MOUNTPOINT/numberedsnapshots"
}
list_snapshots() {
	clear
	echo "List of the snapshots in your $OS_NAME system:" > "$MOUNTPOINT/listsnapshots"
	display_snapshots >> "$MOUNTPOINT/listsnapshots"
	echo >> "$MOUNTPOINT/listsnapshots"
	if [ "$HAVE_W3M" ]; then
		echo "Press q to go back to the menu." >> "$MOUNTPOINT/listsnapshots"
		w3m -o confirm_qq=false "$MOUNTPOINT/listsnapshots"
	elif [ "$HAVE_LESS" ]; then
		echo "Press q to go back to the menu." >> "$MOUNTPOINT/listsnapshots"
		less "$MOUNTPOINT/listsnapshots"
	else
		cat "$MOUNTPOINT/listsnapshots"
		printf "Press Enter to go back to the menu "
		read -r ANSWER
	fi
	rm -f "$MOUNTPOINT/listsnapshots"
	menu
}
delete_snapshot() {
	# We allow to delete several snapshots in a row, one at a time, but not all in one shot.
	# get a list of basenames of snapshots in $MOUNTPOINT/.sna^shots 
	numbered_snapshots
	echo "List of the snapshots in your $OS_NAME system:"
	display_snapshots
	while true; do
		echo
		printf "Number of the snapshot to delete, or Enter to go back to the menu: "
		read -r NUMBER
		if [ ! "$NUMBER" ]; then
			rm "$MOUNTPOINT/numberedsnapshots"
			menu
		fi
		echo "$NUMBER"|grep -q '[^0123456789]' && echo "$NUMBER is not a number." && continue
		# Find the name of snapshot numbered $NUMBER
		SNAP_NAME=$(sed -n "/^$NUMBER|/s@[^|]*|\([^|]*\).*@\1@p" "$MOUNTPOINT/numberedsnapshots")
		SNAP_SHORT_DESC=$(sed -n "/^$NUMBER|/s@.*|@@p" "$MOUNTPOINT/numberedsnapshots")
		[ ! "$SNAP_NAME" ] && echo "There is no snapshot number $NUMBER." && continue
		break
	done
	while true; do
		echo
		echo Delete the snapshot "$NUMBER" ["$SNAP_NAME"] \("$SNAP_SHORT_DESC"\)?
		printf "Type YES in capital letters to confirm, or no to go back to the menu: "
		read -r ANSWER
		unset FAILURE
		case "$ANSWER" in
			YES) btrfs subvolume delete -C "$MOUNTPOINT"/.snapshots/"$SNAP_NAME" 1>/dev/null
				RET=$?
				break;;
			no) rm "$MOUNTPOINT/numberedsnapshots"
				menu;;
			*) :
		esac
	done
	if [ "$RET" -eq 0 ]; then
		echo
		echo "snapshot $SNAP_NAME deleted."
		rm "$MOUNTPOINT/numberedsnapshots"
		log "$SNAP_NAME deleted."
		printf "Press Enter to go back to the menu "
		read -r
		menu
	else
		echo "The snapshot $SNAP_NAME could not be deleted."
		log "$SNAP_NAME not deleted."
		printf "To try again to delete a snapshot type yes, else just press Enter: "
		read -r ANSWER
		[ "$(to_lower "$ANSWER")" = "yes" ] && delete_snapshot
		menu
	fi
}
restore_any_snapshot() {
	clear
	numbered_snapshots >"$MOUNTPOINT/numberedsnapshots"
	echo "List of the snapshots in your $OS_NAME system:"
	display_snapshots
	while true; do
		echo
		printf "Number of the snapshot to restore, or Enter to go back to the menu: "
		read -r NUMBER
		[ ! "$NUMBER" ] && rm "$MOUNTPOINT/numberedsnapshots" && menu
		echo "$NUMBER"|grep -q '[^0123456789]' && echo "$NUMBER is not a number." && continue
		# Find the name of snapshot numbered $NUMBER
		SNAP_NAME=$(sed -n "/^$NUMBER|/s@[^|]*|\([^|]*\).*@\1@p" "$MOUNTPOINT/numberedsnapshots")
		SNAP_SHORT_DESC=$(sed -n "/^$NUMBER|/s@.*|@@p" "$MOUNTPOINT/numberedsnapshots")
		[ ! "$SNAP_NAME" ] && echo "There is no snapshot number $NUMBER." && continue
		break
	done
	while true; do
		echo
		echo "Restore the snapshot $NUMBER [$SNAP_NAME] ($SNAP_SHORT_DESC)?"
		printf "Type yes to confirm, or no to go back to the menu: "
		read -r ANSWER
		unset FAILURE
		[ ! "$(to_lower "$ANSWER")" = "yes" ] && menu 
		SNAP_SHORT_DESC="before restoration of \"$SNAP_NAME\""
		echo
		echo "Before restoration a new snapshot will be created to allow a"
		echo "rollback to the current state of the system, labeled by default:"
		echo "    Before restoring from \"$SNAP_NAME\""
		echo "Press Enter to accept this description or type another one,"
		echo "between 5 and 40 characters long."
		while true; do
			printf "Description (or NO): "
			read -r -e ANSWER
			[ "$ANSWER" = "NO" ] && break
			[ ! "$ANSWER" ] && break
			FORBIDDEN=$(printf %s "$ANSWER"|grep -e "[]'([)*]" -e '"')
			DESC_LENGTH="$(printf %s "$ANSWER"|wc -c)"
			if [ "$DESC_LENGTH" -gt 40 ]; then
				echo "The description should have at most 40 characters, make it $((DESC_LENGTH -40)) shorter."
			elif [ "$(printf %s "$ANSWER"|wc -c)" -lt 5 ]; then
				echo "The description should have at least 5 characters."
			elif [ "$FORBIDDEN" ]; then
				echo "The characters  [ ] ' \" ( ) are not allowed."
			else
				SNAP_SHORT_DESC="$ANSWER"
				break
			fi
		done	
		# We create a new snapshot
		NEW_SNAP_NAME="$(date +%Y-%m-%d:%Hh%Mm%Ss)"
		mv "$MOUNTPOINT/$ROOT_SUBVOL" "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"
		# Write its metadata.
		mkdir -p "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"/var/lib
		KVER=$(uname -r)
		unset INITRAMFS
		# We first try to find an initramfs whose name matches that of the kernel
		KERNEL="$(sed "s|[^=]*=||;s|[ ].*||;s|.*/||" /proc/cmdline)"
		KERNEL_VERSION="$(echo "$KERNEL"|cut -d- -f 2-)"
		ALL_INITRAMFS=$(find /boot/ -name "initr*${KERNEL_VERSION}*" -type f)
		CMDLINE="$(sed "
			s|[^=]*=||
			s|.*/boot|/.snapshots/$NEW_SNAP_NAME/boot|
			s|subvol=[[:graph:]]*|subvol=.snapshots/$NEW_SNAP_NAME|" /proc/cmdline)"
		[ "$ALL_INITRAMFS" ] && INITRAMFS="$(echo "$ALL_INITRAMFS"|sed "s|.*/||"|head -n 1)"
		# If no initramfs whose name includes the kernel version,try initrd.gz and initrd.img
		[ ! "$INITRAMFS" ] && [ -f /boot/initrd.gz ] && INITRAMFS=/boot/initrd.gz
		[ ! "$INITRAMFS" ] && [ -f /boot/initrd.img ] && INITRAMFS=/boot/initrd.img
		# Still not found? Try a match with uname -r
		if [ ! "$INITRAMFS" ]; then
			ALL_INITRAMFS=$(find /boot/ -name "initr*" -type f|grep "$KVER")
			[ "$ALL_INITRAMFS" ] && INITRAMFS=$(echo "$ALL_INITRAMFS"|head -n 1)
		fi
		if [ "$INITRAMFS" ]; then
			echo "SNAP_SHORT_DESC=\"$SNAP_SHORT_DESC\" KVER=\"$KVER\" CMDLINE=\"$CMDLINE\" INITRAMFS=\"$INITRAMFS\"" \
		> "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"/var/lib/snapshot_metadata
		else
			echo "$SNAP_SHORT_DESC=\"$SNAP_SHORT_DESC\" KVER=\"$KVER\" CMDLINE=\"$CMDLINE\"" \
		> "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"/var/lib/snapshot_metadata
		fi
		[ "$LONGDESC" ] && echo "LONGDESC=\"$LONGDESC\"" >> "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"/var/lib/snapshot_metadata
		# Restore the snapshot
		rm -f "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
		mv "$MOUNTPOINT"/.snapshots/"$SNAP_NAME" "$MOUNTPOINT/$ROOT_SUBVOL"
		echo "The snapshot .snapshots/$SNAP_NAME has been restored."
		echo "We recommend that you reboot now and in any case do not create,"
		echo  "delete or restore a snapshot before rebooting."
		log "$SNAP_NAME restored."
		touch /run/restored_snapshot
		closing
	done
}
restore_me() {
	SNAP_NAME="$RUNNING_SNAPSHOT"
	. /var/lib/snapshot_metadata
	echo "Restore the running snapshot dated ${SNAP_NAME} (${SNAP_SHORT_DESC})?"
	printf "To confirm type yes, else press Enter: "
	read -r ANSWER
	unset FAILURE
	[ ! "$(to_lower "$ANSWER")" = "yes" ] && menu
	SNAP_SHORT_DESC="before restoration of \"$SNAP_NAME\""
	echo
	echo "Before restoration a new snapshot can be taken to allow a"
	echo "rollback to the current state of the system, labeled by default:"
	echo "    Before restoring from \"$SNAP_NAME\""
	echo "Press Enter to accept this description or type another description,"  
	echo "between 5 and 40 characters long. But if you don't want to take"
	echo "a new snapshot type NO in capital letters."
	while true; do
		printf "Description (or NO): "
		read -r -e ANSWER
		[ "$ANSWER" = "NO" ] && SNAP_SHORT_DESC="$ANSWER" && break
		[ ! "$ANSWER" ] && break
		FORBIDDEN=$(printf %s "$ANSWER"|grep -e "[]'([)*]" -e '"')
		DESC_LENGTH="$(printf %s "$ANSWER"|wc -c)"
		if [ "$DESC_LENGTH" -gt 40 ]; then
			echo "The description should have at most 40 characters, make it $((DESC_LENGTH -40)) shorter."
		elif [ "$(printf %s "$ANSWER"|wc -c)" -lt 5 ]; then
			echo "The description should have at least 5 characters."
		elif [ "$FORBIDDEN" ]; then
			echo "The characters  [ ] ' \" ( ) are not allowed."
		else
			SNAP_SHORT_DESC="$ANSWER"
			break
		fi
	done	
	# We create a new snapshot
	NEW_SNAP_NAME="$(date +%Y-%m-%d:%Hh%Mm%Ss)"
	mv "$MOUNTPOINT/$ROOT_SUBVOL" "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"
	# Let's write its metadata if we will keep it
		if [ ! "$ANSWER" = "NO" ]; then
		mkdir -p "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"/var/lib
		KVER=$(uname -r)
		unset INITRAMFS
		# We first try to find an initramfs whose name matches that of the kernel
		KERNEL="$(sed "s|[^=]*=||;s|[ ].*||;s|.*/||" /proc/cmdline)"
		KERNEL_VERSION="$(echo "$KERNEL"|cut -d- -f 2-)"
		ALL_INITRAMFS=$(find /boot/ -name "initr*${KERNEL_VERSION}*" -type f)
		CMDLINE="$(sed "
			s|[^=]*=||
			s|.*/boot|/.snapshots/$NEW_SNAP_NAME/boot|
			s|subvol=[[:graph:]]*|subvol=.snapshots/$NEW_SNAP_NAME|" /proc/cmdline)"
		[ "$ALL_INITRAMFS" ] && INITRAMFS="$(echo "$ALL_INITRAMFS"|sed "s|.*/||"|head -n 1)"
		# If no initramfs whose name includes the kernel version,try initrd.gz and initrd.img
		[ ! "$INITRAMFS" ] && [ -f /boot/initrd.gz ] && INITRAMFS=/boot/initrd.gz
		[ ! "$INITRAMFS" ] && [ -f /boot/initrd.img ] && INITRAMFS=/boot/initrd.img
		# Still not found? Try a match with uname -r
		if [ ! "$INITRAMFS" ]; then
			ALL_INITRAMFS=$(find /boot/ -name "initr*" -type f|grep "$KVER")
			[ "$ALL_INITRAMFS" ] && INITRAMFS=$(echo "$ALL_INITRAMFS"|head -n 1)
		fi
		if [ "$INITRAMFS" ]; then
			echo "SNAP_SHORT_DESC=\"$SNAP_SHORT_DESC\" KVER=\"$KVER\" CMDLINE=\"$CMDLINE\" INITRAMFS=\"$INITRAMFS\"" \
		> "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"/var/lib/snapshot_metadata
		else
			echo "$SNAP_SHORT_DESC=\"$SNAP_SHORT_DESC\" KVER=\"$KVER\" CMDLINE=\"$CMDLINE\"" \
		> "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"/var/lib/snapshot_metadata
		fi
		[ "$LONGDESC" ] && echo "LONGDESC=\"$LONGDESC\"" >> "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME"/var/lib/snapshot_metadata
	fi
	# Restore the running snapshot	
	rm -f "$MOUNTPOINT"/.snapshots/"$SNAP_NAME"/var/lib/snapshot_metadata
	mv "$MOUNTPOINT"/.snapshots/"$SNAP_NAME" "$MOUNTPOINT/$ROOT_SUBVOL"
	echo "The snapshot .snapshots/$SNAP_NAME has been restored."
	echo "We recommend that you reboot now and in any case do not create,"
	echo  "delete or restore a snapshot before rebooting."
	log "$SNAP_NAME restored."
	touch /run/restored_snapshot
	# Remove the new snapshot if user does not want it. 
	[ "$ANSWER" = "NO" ] && btrfs subvolume delete -C "$MOUNTPOINT"/.snapshots/"$NEW_SNAP_NAME" 1>/dev/null
	closing
}
closing() {
	write_snapshots_cfg
	(cd "$MOUNTPOINT" || exit
	rm -f features rollbacks snapshots.cfg snapshots_list numberedsnapshots
	)
	umount "$MOUNTPOINT"
	rmdir "$MOUNTPOINT"
	#  listsnapshots
	#  list_of_snapshots
	trap - INT
	exit
}
menu() {
	clear
	# From a snapshot we do not allow to create or delete a snapshot, or to restore another
	# snashot than the one in use.
	IS_SNAP=$(grep -s .snapshots /proc/cmdline)
	[ "$IS_SNAP" ] && RUNNING_SNAPSHOT=$(sed "s|.*subvol=.snapshots/||;s|[ ].*||" /proc/cmdline)
	# After having restored a snapshot we do not allow to create or delete or restore a
	# until after a reboot. We write an indicator in /run for that, so it will vanish
	# after a reboot.
	unset RESTORED
	unset SNAPS
	[ -f /run/restored_snapshot ] && RESTORED="yes"
	write_snapshots_cfg
	[ -s "$MOUNTPOINT/snapshots_list" ] && SNAPS="yes"
	echo "Welcome to the absm snapshots manager."
	while true; do
		echo "To choose an action, press one of the letters indicated below then Enter:"
		[ ! "$IS_SNAP" ] && [ ! "$RESTORED" ] && echo "C: Create a snapshot."
		[ ! "$IS_SNAP" ] && [ ! "$RESTORED" ] && [ "$SNAPS" ] && echo "D: Delete a snapshot."
		echo "P: Presentation and features."
		echo "G: Display GRUB's boot menu as it will appear at next boot."
		echo "H: How-to use snapshots and manage rollbacks."
		[ $SNAPS ] && echo "L: List the snapshots."
		[ ! "$IS_SNAP" ] && [ ! "$RESTORED" ] && [ "$SNAPS" ] && echo "R: Restore a snapshot."
		[ "$IS_SNAP" ] && [ ! "$RESTORED" ] && echo "R: Restore the snapshot in use."
		echo "V: View the log of creation, deletion and restoration of snapshots."
		printf "Your choice (or just press Enter to quit): "
		read -r ANSWER
		case $(to_lower "$ANSWER") in
			l) if [ $SNAPS ]; then list_snapshots; else menu; fi;;
			c) if [ ! "$IS_SNAP" ] && [ ! "$RESTORED" ]; then create_snapshot; else menu; fi;;
			d) if [ ! "$IS_SNAP" ] && [ ! "$RESTORED" ] && [ "$SNAPS" ]; then delete_snapshot; else menu; fi;;
			p) features;;
			g) display_grub_menu;;
			h) rollbacks;;
			r) if [ ! "$RESTORED" ] && [ "$SNAPS" ]; then
				if  [ ! "$IS_SNAP" ]; then
					restore_any_snapshot; menu
				else
					restore_me; menu
				fi
			fi;;
			v) view_the_log;;
			*) clear; closing
		esac
	done
}
# Main
arg1="$1"
unset RESTORED
[ -f /run/restored_snapshot ] && RESTORED="yes"
case "$arg1" in
"")
	check_specs
	set_paths
	write_grub_hook
	write_features
	write_rollbacks
	menu;;
c|C)
	check_specs
	set_paths
	write_grub_hook
	create_snapshot_unattended
	echo "done"
	closing;;
esac
