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
|
#!/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
#############################################################################
# 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
}
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 ls -alh | grep -v -E ' \.\.?$' | grep -v '^total')
[ -n "$OLD" ] && echo -- "Leftovers:" && echo -- "$OLD"
cd "$PRE" || true
}
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
}
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 ] && [ -d "/proc/$upid" ]; do
[ -n "$hdd" ] && has_hdd && 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
sleep 1
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"
# Get all partitions with given id (list of /dev/sdXX)
# Works for MBR/DOS by looking at the type (1 byte)
# and for GPT by looking for the label 'OpenSLX-ID$1'
# in case an id was given, or just at the UUID if some
# longer string was given
# The output will be a list of matching devices,
# sorted from largest to smallest
get_all_with_id () {
local ID dev exp
exp=
while [ $# -gt 0 ]; do
ID=$1
shift
[ -z "$ID" ] && continue
[ ${#ID} -eq 1 ] && ID="0?$ID" # passed '7' as argument -- look for 0x7 or 0x07
if [ ${#ID} -eq 2 ]; then
exp="$exp|ID_PART_ENTRY_(NAME=OpenSLX-ID|TYPE=0x)$ID"
else
exp="$exp|ID_PART_ENTRY_TYPE=$ID"
fi
done
exp=${exp:1}
#echo "Partition find is '$exp'" >&2
for dev in $(find /dev/ -type b); do
udevadm info --name="$dev" | grep -iqE "($exp)\$" && echo "$(blockdev --getsize64 "$dev") $dev"
done | sort -n -k1 -r | cut -d' ' -f2
}
# Check for standard swap partitions and make them available to the system
HAVE_SWAP=no
for PART_DEV in $(get_all_with_id "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
# We use special non assigned partition type (id44) for harddisk scratch
# space, thus no normal filesystem will be incidentally deleted or
# corrupted
HAVE_TEMP=no
for PART_DEV in $(get_all_with_id "44"); 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
# Put detected linux partitions (83) into /etc/fstab with "noauto"
for PART_DEV in $(get_all_with_id 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 $(get_all_with_id "45"); 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}')
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 $(get_all_with_id "46"); do
mkdir -p "/media/${PART_DEV#/dev/*}"
#mount -t auto ${PART_DEV} /mnt/media/${PART_DEV#/dev/*} \n\
#test -d /mnt/media/${PART_DEV#/dev/*}/home && \
# ln -sf /media/${PART_DEV#/dev/*} /var/home
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
# 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
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
exit 0
|