#!/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 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