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
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
|
#!/bin/sh
. /usr/share/debconf/confmodule
# Translate device from /proc/mdstat (mdX) to device node
md_devnode() {
local num=$(echo $1 | sed -e "s/^md//")
# Also handle the case where the first does not exist
if [ -b /dev/md/$num ]; then
echo /dev/md/$num
elif [ -b /dev/md$num ]; then
echo /dev/md$num
else
return 1
fi
}
md_get_level() {
echo $(mdadm -Q --detail $1 | grep "Raid Level" | sed "s/.*: //")
}
md_get_devices() {
DEVICES=""
for DEVICE in $(grep ^md /proc/mdstat | \
sed -e 's/^\(md.*\) : .*/\1/'); do
MDDEV=$(md_devnode $DEVICE) || return 1
TYPE=$(md_get_level $MDDEV)
DEVICES="${DEVICES:+$DEVICES, }${DEVICE}_$TYPE"
done
}
md_delete_verify() {
DEVICE=$(echo "$1" | sed -e "s/^\(md.*\)_.*/\1/")
DEVICES=$(grep "^$DEVICE[ :]" /proc/mdstat | \
sed -e "s/^.*active \(.*\)/\1/; s/raid[0-9]* //")
MDDEV=$(md_devnode $DEVICE) || return 1
TYPE=$(md_get_level $MDDEV)
db_set mdcfg/deleteverify false
db_subst mdcfg/deleteverify DEVICE "/dev/$DEVICE"
db_subst mdcfg/deleteverify TYPE "$TYPE"
db_subst mdcfg/deleteverify DEVICES "$DEVICES"
db_input critical mdcfg/deleteverify
db_go
db_get mdcfg/deleteverify
case $RET in
true)
# Stop the MD device and zero the superblock
# of all the component devices
DEVICES=$(mdadm -Q --detail $MDDEV | \
grep -E "^[[:space:]]*[0-9].*(active|spare)" | \
sed -e 's/.* //')
logger -t mdcfg "Removing $MDDEV ($DEVICES)"
log-output -t mdcfg mdadm --stop $MDDEV || return 1
for DEV in "$DEVICES"; do
log-output -t mdcfg \
mdadm --zero-superblock --force $DEV || return 1
done
;;
esac
return 0
}
md_delete() {
md_get_devices
if [ -z "$DEVICES" ]; then
db_set mdcfg/delete_no_md false
db_input high mdcfg/delete_no_md
db_go
return
fi
db_set mdcfg/deletemenu false
db_subst mdcfg/deletemenu DEVICES "$DEVICES"
db_input critical mdcfg/deletemenu
db_go
db_get mdcfg/deletemenu
case $RET in
md*)
if ! md_delete_verify $RET; then
db_input critical mdcfg/deletefailed
db_go
fi
;;
esac
}
md_createmain() {
db_set mdcfg/createmain false
db_input critical mdcfg/createmain
db_go
if [ $? -ne 30 ]; then
db_get mdcfg/createmain
if [ "$RET" = Cancel ]; then
return
fi
RAID_SEL="$RET"
if ! get_partitions; then
return
fi
case "$RAID_SEL" in
RAID10|RAID6|RAID5|RAID1)
md_create_array "$RAID_SEL" ;;
RAID0)
md_create_raid0 ;;
*)
return 1 ;;
esac
fi
}
# This will set PARTITIONS and NUM_PART global variables
get_partitions() {
PARTITIONS=""
# Get a list of RAID partitions. This only works if there is no
# filesystem on the partitions, which is fine by us.
RAW_PARTITIONS=$(/usr/lib/partconf/find-partitions --ignore-fstype 2>/dev/null | \
grep "[[:space:]]RAID[[:space:]]" | cut -f1)
# Convert it into a proper list form for a select question
# (comma separated)
NUM_PART=0
for i in $RAW_PARTITIONS; do
DEV=$(echo $i | sed -e "s/\/dev\///")
REALDEV=$(mapdevfs "$i")
MAPPEDDEV=$(echo "$REALDEV" | sed -e "s/\/dev\///")
if grep -Eq "($DEV|$MAPPEDDEV)" /proc/mdstat; then
continue
fi
PARTITIONS="${PARTITIONS:+$PARTITIONS, }$REALDEV"
NUM_PART=$(($NUM_PART + 1))
done
if [ -z "$PARTITIONS" ]; then
db_input critical mdcfg/noparts
db_go
return 1
fi
return 0
}
prune_partitions() {
CHOSEN="$1"
OLDIFS="$IFS"
IFS=,
NEW_PARTITIONS=""
for i in $PARTITIONS; do
found=0
for j in $CHOSEN; do
if [ "$i" = "$j" ]; then
found=1
fi
done
if [ $found -eq 0 ]; then
NEW_PARTITIONS="${NEW_PARTITIONS:+$NEW_PARTITIONS,}$i"
fi
done
IFS=$OLDIFS
PARTITIONS=$NEW_PARTITIONS
}
md_create_raid0() {
db_subst mdcfg/raid0devs PARTITIONS "$PARTITIONS"
db_set mdcfg/raid0devs ""
db_input critical mdcfg/raid0devs
db_go
if [ $? -eq 30 ]; then return; fi
db_get mdcfg/raid0devs
SELECTED=0
for i in $RET; do
let SELECTED++
done
prune_partitions "$RET"
MD_NUM=$(grep ^md /proc/mdstat | \
sed -e 's/^md\(.*\) : active .*/\1/' | sort | tail -n1)
if [ -z "$MD_NUM" ]; then
MD_NUM=0
else
let MD_NUM++
fi
logger -t mdcfg "Number of devices in the RAID0 array md$MD_NUM: $SELECTED"
RAID_DEVICES="$(echo $RET | sed -e 's/,//g')"
log-output -t mdcfg \
mdadm --create /dev/md$MD_NUM --auto=yes --force -R -l raid0 \
-n $SELECTED $RAID_DEVICES
}
md_create_array(){
OK=0
case "$1" in
RAID1)
MIN_SIZE=2 ;;
RAID5)
MIN_SIZE=3 ;;
RAID6)
MIN_SIZE=4 ;;
RAID10)
MIN_SIZE=2 ;;
*)
return ;;
esac
LEVEL=${1#RAID}
for i in devcount devs sparecount sparedevs; do
db_subst mdcfg/raid$i LEVEL "$LEVEL"
done
db_subst mdcfg/raiddevcount MINIMUM "$MIN_SIZE"
db_set mdcfg/raiddevcount "$MIN_SIZE"
# Get the count of active devices
while [ $OK -eq 0 ]; do
db_input critical mdcfg/raiddevcount
db_go
if [ $? -eq 30 ]; then
return
fi
# Figure out, if the user entered a number
db_get mdcfg/raiddevcount
RET=$(echo $RET | sed -e "s/[[:space:]]//g")
if [ "$RET" ]; then
let "OK=${RET}>0 && ${RET}<99"
fi
done
db_set mdcfg/raidsparecount "0"
OK=0
# Same procedure as above, but get the number of spare partitions
# this time.
# TODO: Make a general function for this kind of stuff
while [ $OK -eq 0 ]; do
db_input critical mdcfg/raidsparecount
db_go
if [ $? -eq 30 ]; then
return
fi
db_get mdcfg/raidsparecount
RET=$(echo $RET | sed -e "s/[[:space:]]//g")
if [ "$RET" ]; then
let "OK=${RET}>=0 && ${RET}<99"
fi
done
db_get mdcfg/raiddevcount
DEV_COUNT="$RET"
if [ $LEVEL -ne 1 ]; then
if [ $DEV_COUNT -lt $MIN_SIZE ]; then
DEV_COUNT=$MIN_SIZE # Minimum number for the selected RAID level
fi
fi
db_get mdcfg/raidsparecount
SPARE_COUNT="$RET"
REQUIRED=$(($DEV_COUNT + $SPARE_COUNT))
if [ $LEVEL -ne 1 ]; then
if [ $REQUIRED -gt $NUM_PART ]; then
db_subst mdcfg/notenoughparts NUM_PART "$NUM_PART"
db_subst mdcfg/notenoughparts REQUIRED "$REQUIRED"
db_input critical mdcfg/notenoughparts
db_go mdcfg/notenoughparts
return
fi
fi
db_set mdcfg/raiddevs ""
SELECTED=0
# Loop until the correct number of active devices has been selected for RAID 5, 6, and 10
# Loop until at least one device has been selected for RAID 1
until ([ $LEVEL -ne 1 ] && [ $SELECTED -eq $DEV_COUNT ]) || \
([ $LEVEL -eq 1 ] && [ $SELECTED -gt 0 ] && [ $SELECTED -le $DEV_COUNT ]); do
db_subst mdcfg/raiddevs COUNT "$DEV_COUNT"
db_subst mdcfg/raiddevs PARTITIONS "$PARTITIONS"
db_input critical mdcfg/raiddevs
db_go
if [ $? -eq 30 ]; then
return
fi
db_get mdcfg/raiddevs
SELECTED=0
for i in $RET; do
DEVICE=$(echo $i | sed -e "s/,//")
let SELECTED++
done
done
MISSING_DEVICES=""
if [ $LEVEL -eq 1 ]; then
# Add "missing" for as many devices as weren't selected
while [ $SELECTED -lt $DEV_COUNT ]; do
MISSING_DEVICES="$MISSING_DEVICES missing"
let SELECTED++
done
fi
# Remove partitions selected in raiddevs from the PARTITION list
db_get mdcfg/raiddevs
prune_partitions "$RET"
db_set mdcfg/raidsparedevs ""
SELECTED=0
if [ $SPARE_COUNT -gt 0 ] && [ -n "$PARTITIONS" ]; then
FIRST=1
# Loop until the correct number of devices has been selected.
# That means any number less than or equal to the spare count.
while [ $SELECTED -gt $SPARE_COUNT ] || [ $FIRST -eq 1 ]; do
FIRST=0
db_subst mdcfg/raidsparedevs COUNT "$SPARE_COUNT"
db_subst mdcfg/raidsparedevs PARTITIONS "$PARTITIONS"
db_input critical mdcfg/raidsparedevs
db_go
if [ $? -eq 30 ]; then
return
fi
db_get mdcfg/raidsparedevs
SELECTED=0
for i in $RET; do
DEVICE=$(echo $i | sed -e "s/,//")
let SELECTED++
done
done
fi
LAYOUT=""
if [ $LEVEL -eq 10 ]; then
OK=0
db_set mdcfg/raid10layout "n2"
while [ $OK -eq 0 ]; do
db_input low mdcfg/raid10layout
db_go
if [ $? -eq 30 ]; then return; fi
db_get mdcfg/raid10layout
if echo $RET | grep -Eq "^[nfo][0-9]{1,2}$" && \
[ $(echo $RET | sed s/.//) -le $DEV_COUNT ]; then
OK=1
fi
done
LAYOUT="--layout=$RET"
fi
# The number of spares the user has selected
NAMED_SPARES=$SELECTED
db_get mdcfg/raiddevs
RAID_DEVICES=$(echo $RET | sed -e "s/,//g")
db_get mdcfg/raidsparedevs
SPARE_DEVICES=$(echo $RET | sed -e "s/,//g")
MISSING_SPARES=""
COUNT=$NAMED_SPARES
while [ $COUNT -lt $SPARE_COUNT ]; do
MISSING_SPARES="$MISSING_SPARES missing"
let COUNT++
done
# Find the next available md-number
MD_NUM=$(grep ^md /proc/mdstat | \
sed -e 's/^md\(.*\) : active .*/\1/' | sort | tail -n1)
if [ -z "$MD_NUM" ]; then
MD_NUM=0
else
let MD_NUM++
fi
logger -t mdcfg "Selected spare count: $NAMED_SPARES"
logger -t mdcfg "Raid devices count: $DEV_COUNT"
logger -t mdcfg "Spare devices count: $SPARE_COUNT"
log-output -t mdcfg \
mdadm --create /dev/md$MD_NUM --auto=yes --force -R -l raid${LEVEL} $LAYOUT \
-n $DEV_COUNT -x $SPARE_COUNT $RAID_DEVICES \
$MISSING_DEVICES $SPARE_DEVICES $MISSING_SPARES
}
md_mainmenu() {
while true; do
db_set mdcfg/mainmenu false
db_input critical mdcfg/mainmenu
db_go
if [ $? -eq 30 ]; then
exit 30
fi
db_get mdcfg/mainmenu
case $RET in
"Create MD device")
md_createmain ;;
"Delete MD device")
md_delete ;;
"Finish")
break ;;
esac
done
}
### Main of script ###
# Load the modules and scan for MD devices if needed
if ! [ -e /proc/mdstat ] || ! [ -d /dev/md ]; then
# Try to load the necesarry modules.
depmod -a >/dev/null 2>&1
modprobe md-mod >/dev/null 2>&1
# Make sure that we have md-support
if [ ! -e /proc/mdstat ]; then
db_set mdcfg/nomd false
db_input high mdcfg/nomd
db_go
exit 0
fi
# Try to detect MD devices, and start them
# mdadm will fail if /dev/md does not already exist
mkdir -p /dev/md
log-output -t mdcfg --pass-stdout \
mdadm --examine --scan --config=partitions >/tmp/mdadm.conf
log-output -t mdcfg \
mdadm --assemble --scan --run \
--config=/tmp/mdadm.conf --auto=yes
fi
# Force mdadm to be installed on the target system
apt-install mdadm
# We want the "go back" button
#db_capb backup
md_mainmenu
exit 0
|