summaryrefslogblamecommitdiffstats
path: root/core/modules/disk-partitions/data/opt/openslx/scripts/systemd-setup_partitions
blob: 641ae372d576fa3f656ac38bb5b1100356cf6097 (plain) (tree)










































































































































































                                                                                                                                                                                 
                                                                                      
















                                                                                                                 
                                                                                                                                                                          
























































                                                                                                                                                                                            
                                               























                                                                                                                     
#!/bin/bash
# Arrays etc and $(( )) with big numbers
# -----------------------------------------------------------------------------
#
# Copyright (c) 2018 bwLehrpool-Projektteam
#
# This program/file is free software distributed under the GPL version 2.
# See https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
#
# If you have any feedback please consult https://bwlehrpool.de and
# send your feedback to bwlehrpool@hs-offenburg.de.
#
# General information about bwLehrpool can be found at https://bwlehrpool.de
#
# -----------------------------------------------------------------------------
#
# Local hard disk autodetection script for OpenSLX linux stateless clients,
# detecting swap and special partitions

#############################################################################

. /opt/openslx/bin/slx-tools

# Mount point for persistent scratch partition (type 45)
MOUNT_POINT_45="/opt/openslx/persistent"
PARTITION_FILE="/run/openslx/partitions"
readonly MOUNT_POINT_45 PARTITION_FILE
mkdir -p "/run/openslx"

declare -a TMPFILES
gettmp () {
	local vn file
	for vn in "$@"; do
		file=$(mktemp -p /run/openslx) # since we fiddle around with /tmp in this script
		declare -g "${vn}=${file}"
		TMPFILES+=("$file")
	done
}
delalltmp () {
	rm -f -- "${TMPFILES[@]}"
}
trap delalltmp EXIT

# get_mount_options <fstype> <varname>
get_mount_options () {
	case "$1" in
		ext2)
			declare -ag "${2}=(-o nocheck)"
			;;
		ext4)
			declare -ag "${2}=(-o 'errors=remount-ro,data=ordered,relatime,quota')"
			;;
		*)
			declare -ag "${2}=()"
	esac
}

# General formatter for the /tmp partition on a local harddisk
format_disk () {
	declare -ag MOUNT_OPTIONS_SET_BY_FORMAT_DISK=() # Global var!
	local target="$1"
	local fslist="xfs jfs ext3 ext2 ext4"
	local fs
	declare -a fopt
	[ $# -ge 2 ] && fslist="$2"
	for fs in $fslist ; do
		if grep -q "\\b${fs}\\b" "/proc/filesystems"; then
			# Filesystem already supported by running kernel
			:
		elif modprobe "${fs}"; then
			# Filesystem module could be loaded and should be supported now
			:
		else
			# Not supported, try next one
			continue
		fi
		if which "mkfs.$fs" ; then
			case "$fs" in
			reiserfs)
				fopt=("-f")
				;;
			xfs)
				fopt=("-f" "-K")
				;;
			ext2|ext3)
				fopt=("-F")
				;;
			ext4)
				fopt=(-F -b 4096 -O "extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize,quota" -E "nodiscard,quotatype=usrquota:prjquota" -I 256)
				;;
			jfs)
				fopt=()
				;;
			*)
				fopt=()
				;;
			esac
			get_mount_options "$fs" MOUNT_OPTIONS_SET_BY_FORMAT_DISK
			"mkfs.$fs" "${fopt[@]}" "${target}" && return 0 # Success!
		fi
	done
	return 1
}

wait_for_udev () {
	local upid ctr hdd
	hdd=
	if [ "x$1" = "x--hdd" ]; then
		hdd=true
		shift
	fi
	ctr=$(( "$1" * 10 ))
	if ! [ "$ctr" -gt 0 ]; then # Negation to catch NaN
		ctr=1
	fi
	udevadm trigger &
	usleep 20000 # 20ms
	udevadm settle &> /dev/null & # --timeout doesn't work reliably, sometimes the process just hangs
	upid=$!
	while [ "$ctr" -gt 0 ]; do
		[ -n "$hdd" ] && has_hdd && break
		[ -z "$hdd" ] && ! [ -d "/proc/$upid" ] && break
		usleep 100000 # 100ms
		ctr=$(( ctr - 1 ))
	done
	if [ -d "/proc/$upid" ]; then
		kill -9 "$upid" &> /dev/null &
	fi
}

has_hdd () {
	[ -n "$( ls -U -1 /dev/disk/by-path/ )" ]
}

wait_for_udev 2

if ! has_hdd; then
	wait_for_udev --hdd 4
fi

shopt -s extglob
for disk in /dev/disk/by-path/!(*-part*|*-usb-*); do
	[ -L "$disk" ] || continue
	fdisk -l "$( readlink -f "$disk" )"
done > "$PARTITION_FILE"
shopt -u extglob
if ! [ -s "$PARTITION_FILE" ]; then
	echo "none" > "$PARTITION_FILE"
fi
echo "Partitions:"
cat "$PARTITION_FILE"

# Check for standard swap partitions and make them available to the system
HAVE_SWAP=no
for PART_DEV in $(dev_find_partitions "82" "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f"); do
	if swapon "$PART_DEV" -p 10; then
		HAVE_SWAP=yes # low priority, in case we have zram swap, prefer that)
		echo -e "$PART_DEV\tswap\t\tswap\t\tdefaults\t 0 0" >> "/etc/fstab"
	fi
done

# Put detected linux partitions (83) into /etc/fstab with "noauto"
for PART_DEV in $(dev_find_partitions "83"); do
	mkdir -p "/media/${PART_DEV#/dev/*}"
	echo -e "${PART_DEV}\t/media/${PART_DEV#/dev/*}\tauto\t\tnoauto,noexec\t 0 0" >> "/etc/fstab"
done

# special partition 45 (persistent scratch) to $MOUNT_POINT_45
HAVE_PARTITION_45=no
get_mount_options "ext4" mopts
# try all the ID45 partitions until one succeeds, from large to small
for PART_DEV in $(dev_find_partitions "45" "87f86132-ff94-4987-b250-454545454545"); do
	mkdir -p "$MOUNT_POINT_45"
	# Let's see if this is an ext4 partition and if so, whether it has the proper size
	# Any fixing should happen first
	gettmp "logfile"
	COUNT=0
	while true; do
		[ "$COUNT" -ge 4 ] && break
		let COUNT++
		fsck.ext4 -y "$PART_DEV" &> "$logfile"
		RET=$?
		if [ "$(( RET & 7 ))" = 4 ]; then
			slxlog "partition-45-fsck" "Error fixing file system errors on ID45 partition" "$logfile"
			break
		fi
		[ "$(( RET & 3 ))" != 1 ] && break
	done
	# awk script to take block count and block size from dumpe2fs output and multiply them to get byte size
	fs_size=$(dumpe2fs -h "$PART_DEV" | awk -F: 'BEGIN{a=0;b=0}{if ($1 == "Block count") a=$2; if($1 == "Block size") b=$2;}END{ if (a>0 && b>0) print a" * "b}' | bc)
	echo "$PART_DEV has ext4 fs of size $fs_size"
	if [ -n "$fs_size" ] && [ "$fs_size" -gt 1000000 ]; then
		# It's ext4, see if partition size was changed offline
		dev_size=$(blockdev --getsize64 "$PART_DEV")
		echo "$PART_DEV has actual size of $dev_size"
		if [ -n "$dev_size" ] && [ "$dev_size" -gt 1000000 ]; then
			# somewhat sane, see what to do
			dev_mb=$(( dev_size / 1024 / 1024 ))
			fs_mb=$(( fs_size / 1024 / 1024 ))
			echo "Dev: $dev_mb, fs: $fs_mb"
			if [ "$(( fs_mb + 100 ))" -lt "$dev_mb" ]; then
				# dev size plus 100MB is still smaller than reported fs size -- resize fs
				gettmp "logfile"
				fsck.ext4 -f -y "$PART_DEV" &> "$logfile"
				if resize2fs "$PART_DEV" &>> "$logfile"; then
					slxlog "partition-45-resize-ok" "Resized partition $PART_DEV from $fs_mb MiB to $dev_mb MiB" "$logfile"
				else
					slxlog "partition-45-resize-fail" "Could not enlarge file system size of $PART_DEV from $fs_mb MiB to $dev_mb MiB" "$logfile"
					dd if=/dev/zero of="$PART_DEV" bs=1M count=1 &>/dev/null
				fi
			elif [ "$dev_size" -lt "$fs_size" ]; then
				# partition is smaller than expected by fs -- killall
				slxlog "partition-45-shrink" "$PART_DEV has ext4 file system which is $fs_mb MiB, but partition size is only $dev_mb MiB. Will wipe partition to be safe..."
				dd if=/dev/zero of="$PART_DEV" bs=1M count=1 &>/dev/null
			fi
		fi
	fi
	# try to mount
	if ! mount -v -t ext4 "${mopts[@]}" "${PART_DEV}" "$MOUNT_POINT_45"; then
		# failed, try to format
		gettmp "logfile"
		if ! format_disk "$PART_DEV" "ext4" &> "$logfile"; then
			slxlog "partition-45-format" "Cannot format $PART_DEV with ext4" "$logfile"
			continue
		fi
		gettmp "logfile"
		if ! mount -v -t ext4 "${mopts[@]}" "${PART_DEV}" "$MOUNT_POINT_45" &> "$logfile"; then
			slxlog "partition-45-newmount" "Cannot mount $PART_DEV with ext4 right after formatting" "$logfile"
			continue
		fi
	fi
	# Mount success -- clean up lost+found
	find "${MOUNT_POINT_45}/slx_lost+found" -mindepth 1 -maxdepth 1 -mtime +90 -type d -exec rm -rf -- {} \;
	if [ -d "${MOUNT_POINT_45}/lost+found" ]; then
		touch "${MOUNT_POINT_45}/lost+found"
		mkdir -p "${MOUNT_POINT_45}/slx_lost+found"
		mv -f -- "${MOUNT_POINT_45}/lost+found" "${MOUNT_POINT_45}/slx_lost+found/$(date +%s)_$$-$RANDOM"
	fi
	chmod 0700 "${MOUNT_POINT_45}/slx_lost+found"
	chown 0:0 "${MOUNT_POINT_45}/slx_lost+found"
	# fstab entry
	echo -e "${PART_DEV}\t${MOUNT_POINT_45}\tauto\t\tnoauto\t\t 0 0" >> "/etc/fstab"
	HAVE_PARTITION_45=yes
	break # success, done
done

# and 46 to /media/devXX
for PART_DEV in $(dev_find_partitions "46"); do
	mkdir -p "/media/${PART_DEV#/dev/*}"
	echo -e "${PART_DEV}\t/media/${PART_DEV#/dev/*}\tauto\t\tnoauto\t\t 0 0" >> "/etc/fstab"
done

# finally, prepare the data subdir on persistent part
if [ "$HAVE_PARTITION_45" = "yes" ]; then
	mkdir -p "$MOUNT_POINT_45/data"
	chown root:root "$MOUNT_POINT_45" "$MOUNT_POINT_45/data"
	chmod a+rwxt "$MOUNT_POINT_45/data"
elif [ -d "$MOUNT_POINT_45" ]; then
	rm -f -- "$MOUNT_POINT_45"
fi

mount -a

if [ "$HAVE_SWAP" = "no" ]; then
	TOTAL_RAM=$(grep ^MemTotal /proc/meminfo | awk '{print $2}')
	if [ -n "$TOTAL_RAM" ] && [ "$TOTAL_RAM" -lt "3000000" ]; then
		slxlog "partition-swap" "Have no (formatted) swap partition, using zram swap only!" "$PARTITION_FILE"
	fi
fi

exit 0