1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
|
#!/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 support@bwlehrpool.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
#############################################################################
# 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"
. /opt/openslx/config
. /opt/openslx/bin/slx-tools
dev_find_partitions &> /dev/null # Preload function
logfile=
HAVE_TEMP=
HAVE_SWAP=
# Check what to do. Currently triggered by:
# setup-partitions.service (Mini and Maxi, for swap, linux, persistent)
# setup-temp.service (Mini only, for ID44 /tmp)
while (( $# > 0 )); do
case "$1" in
--tmp) DO_TMP=1 ;;
--persistent) DO_PERSISTENT=1 ;;
--swap) DO_SWAP=1 ;;
--linux) DO_LINUX=1 ;;
*) echo "Unknown option '$1'" >&2 ;;
esac
shift
done
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
}
# cd to /tmp, mount new /tmp, mv * from cwd (=old temp) to /tmp (=new temp)
# If cd to /tmp fails, call the fallback function below
mount_temp () {
local PRE=$(pwd)
if ! cd /tmp; then
mount_temp_fallback "$@"
return $?
fi
mount "$@" /tmp || return 1
chmod a+rwxt /tmp
# Move stuff from working directory, which is old /tmp, to new /tmp just mounted
mv ./* ./.[!.]* ./..?* /tmp/ 2> /dev/null
local OLD=$(LANG=C.UTF-8 ls -alh | grep -v -E ' \.\.?$' | grep -v '^total')
[ -n "$OLD" ] && echo -- "Leftovers:" && echo -- "$OLD"
cd "$PRE" || true
}
# Fallback: Make new temporary /tmp, move everything there, mount new /tmp
# then move everything back.
mount_temp_fallback () {
mkdir -p /tmptmp
mv /tmp/* /tmp/.* /tmptmp/ 2> /dev/null
mount "$@" /tmp || return 1
chmod a+rwxt /tmp
mv /tmptmp/* /tmptmp/.* /tmp/
rmdir /tmptmp
return 0
}
# call with --hdd <secs>: Wait for max. <secs> seconds until an HDD appears
# call with <secs>: Wait for max. <secs> seconds until udevadm settile finishes
wait_for_udev () {
local upid ctr hdd
hdd=
if [ "$1" = "--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/ )" ]
}
if ! [ -s "/run/openslx/dmsetup.state" ]; then
# If above file exists we should've waited for HDDs to appear in stage 3 already,
# so don't just wait for udev for two+ seconds for no reason.
wait_for_udev 2
if ! has_hdd; then
wait_for_udev --hdd 4
fi
fi
declare -A known=
shopt -s extglob
for disk in /dev/disk/by-path/!(*-part*|*-usb-*); do
disk="$( readlink -f "$disk" )"
[ -b "$disk" ] || continue
[ -z "${known["$disk"]}" ] || continue
known["$disk"]=1
fdisk -l "$disk"
done > "$PARTITION_FILE"
shopt -u extglob
if ! [ -s "$PARTITION_FILE" ]; then
echo "none" > "$PARTITION_FILE"
fi
echo "Partitions:"
cat "$PARTITION_FILE"
linux_pid=
if [ -n "$DO_LINUX" ]; then
# Put detected linux partitions (83) into /etc/fstab with "noauto"
echo "Adding existing linux partitions to fstab"
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 &
linux_pid=$!
fi
if [ -n "$DO_SWAP" ]; then
# Check for standard swap partitions and make them available to the system
echo "Enabling existing swap partitions"
HAVE_SWAP=no
for PART_DEV in $(dev_find_partitions --rw "82" "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f"); do
if swapon -p 10 "$PART_DEV"; 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
if [ -b "/dev/mapper/slx-swap" ] && mkswap "/dev/mapper/slx-swap" \
&& swapon -p 10 "/dev/mapper/slx-swap"; then
echo "Added slx-swap in ID44"
HAVE_SWAP=yes # finally, success
fi
fi
if [ -n "$DO_TMP" ]; then
# We use special non assigned partition type (id44) for harddisk scratch
# space, thus no normal filesystem will be incidentally deleted or
# corrupted
echo "Mounting ID44 temp partitions"
HAVE_TEMP=no
for PART_DEV in $(dev_find_partitions --rw "44" "87f86132-ff94-4987-b250-444444444444"); do
# check for supported filesystem and formatter
if format_disk "$PART_DEV"; then
mount_temp "${MOUNT_OPTIONS_SET_BY_FORMAT_DISK[@]}" "$PART_DEV" || continue
echo -e "${PART_DEV}\t/tmp\t\tauto\t\tnoexec\t 0 0" >> "/etc/fstab"
HAVE_TEMP=yes
break
else
echo "formatting failed for some reason"
fi # Made this non-forking, systemd should handle it - 2013-05-28
done
fi
if [ -n "$DO_PERSISTENT" ]; then
# special partition 45 (persistent scratch) to $MOUNT_POINT_45
echo "Mounting ID45 persistent partitions"
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 --rw "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 (( COUNT++ < 4 )); do
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 (bc because awk suxx)
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 > 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 > 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) < 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 < 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
# 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
fi # /persistent
# finally, prepare the data subdir on persistent part
if [ "$HAVE_PARTITION_45" = "yes" ]; then
echo "Fixing permissions on ID45 partition"
mkdir -p "$MOUNT_POINT_45/data"
chown 0:0 "${MOUNT_POINT_45}" "${MOUNT_POINT_45}/slx_lost+found" "${MOUNT_POINT_45}/data"
chmod 0700 "${MOUNT_POINT_45}/slx_lost+found"
chmod 0755 "${MOUNT_POINT_45}"
chmod a+rwxt "$MOUNT_POINT_45/data"
elif [ -d "$MOUNT_POINT_45" ]; then
rm -f -- "$MOUNT_POINT_45"
fi
[ -n "$linux_pid" ] && wait "$linux_pid"
mount -a
# HAVE_* will be empty if the according cmdline option was not passed.
# Make tmpfs if nothing could be mounted for /tmp
# 2016-10-12: Use a sane size of 66% which should be generous enough and prevent the machine from
# just crashing if RAM is too full. We previously hugely oversized since vmware wants at least as
# much free space as the VMs RAM; however, this requirement can be disabled with a vmx setting,
# which we're now doing.
if [ "$HAVE_TEMP" = "no" ]; then
# If --tmp wasn't requested HAVE_TEMP will be empty, so we don't end up here...
mount_temp -t tmpfs -o size=66% none
slxlog "partition-temp" "Running /tmp on tmpfs only!" "$PARTITION_FILE"
fi
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
[ -n "$SLX_SPLASH" ] && splashtool --icon "/opt/openslx/icons/active/??-hdd.ppm"
exit 0
|