common.sh.in 18 KB
Newer Older
Nikos Skalkotos's avatar
Nikos Skalkotos committed
1
# Copyright (C) 2011, 2012, 2013 GRNET S.A.
2
# Copyright (C) 2007, 2008, 2009 Google Inc.
Nikos Skalkotos's avatar
Nikos Skalkotos committed
3
#
4
5
6
7
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
Nikos Skalkotos's avatar
Nikos Skalkotos committed
8
#
9
10
11
12
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
Nikos Skalkotos's avatar
Nikos Skalkotos committed
13
#
14
15
16
17
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
Nikos Skalkotos's avatar
Nikos Skalkotos committed
18

19
PROGNAME=$(basename $0)
Nikos Skalkotos's avatar
Nikos Skalkotos committed
20

Nikos Skalkotos's avatar
Nikos Skalkotos committed
21
22
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin

Nikos Skalkotos's avatar
Nikos Skalkotos committed
23
24
# Programs
XMLSTARLET=xmlstarlet
25
TUNE2FS=tune2fs
Nikos Skalkotos's avatar
Nikos Skalkotos committed
26
RESIZE2FS=resize2fs
27
PARTED=parted
28
SFDISK=sfdisk
Nikos Skalkotos's avatar
Nikos Skalkotos committed
29
30
MKSWAP=mkswap
BLKID=blkid
31
BLOCKDEV=blockdev
32
33
REGLOOKUP=reglookup
CHNTPW=chntpw
34
SGDISK=sgdisk
Nikos Skalkotos's avatar
Nikos Skalkotos committed
35
GROWFS_UFS=growfs.ufs
36
DUMPFS_UFS=dumpfs.ufs
37
38
GROWFS_OPENBSD=growfs.openbsd
DUMPFS_OPENBSD=dumpfs.openbsd
39
DATE="date -u" # Time in UTC
40
EATMYDATA=eatmydata
41
MOUNT="mount -n"
Nikos Skalkotos's avatar
Nikos Skalkotos committed
42
43

CLEANUP=( )
44
45
ERRORS=( )
WARNINGS=( )
Nikos Skalkotos's avatar
Nikos Skalkotos committed
46

47
48
49
50
MSG_TYPE_TASK_START="TASK_START"
MSG_TYPE_TASK_END="TASK_END"

STDERR_LINE_SIZE=10
51

Nikos Skalkotos's avatar
Nikos Skalkotos committed
52
53
54
55
56
add_cleanup() {
    local cmd=""
    for arg; do cmd+=$(printf "%q " "$arg"); done
    CLEANUP+=("$cmd")
}
Dimitris Aragiorgis's avatar
Dimitris Aragiorgis committed
57

Nikos Skalkotos's avatar
Nikos Skalkotos committed
58
59
60
61
close_fd() {
    local fd=$1

    exec {fd}>&-
Dimitris Aragiorgis's avatar
Dimitris Aragiorgis committed
62
63
}

64
65
66
67
68
69
70
71
72
73
74
75
76
send_result_kvm() {
    echo "$@" > /dev/ttyS1
}

send_monitor_message_kvm() {
    echo "$@" > /dev/ttyS2
}

send_result_xen() {
    xenstore-write /local/domain/0/snf-image-helper/$DOMID "$*"
}

send_monitor_message_xen() {
77
    #Broadcast the message
78
    echo "$@" | socat "STDIO" "UDP-DATAGRAM:${BROADCAST}:${MONITOR_PORT},broadcast"
79
80
}

Nikos Skalkotos's avatar
Nikos Skalkotos committed
81
82
prepare_helper() {
	local cmdline item key val hypervisor domid
Dimitris Aragiorgis's avatar
Dimitris Aragiorgis committed
83

Nikos Skalkotos's avatar
Nikos Skalkotos committed
84
85
	read -a cmdline	 < /proc/cmdline
	for item in "${cmdline[@]}"; do
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
            key=$(cut -d= -f1 <<< "$item")
            val=$(cut -d= -f2 <<< "$item")
            if [ "$key" = "hypervisor" ]; then
                hypervisor="$val"
            fi
            if [ "$key" = "rules_dev" ]; then
                export RULES_DEV="$val"
            fi
            if [ "$key" = "helper_ip" ]; then
                export IP="$val"
                export NETWORK="$IP/24"
                export BROADCAST="${IP%.*}.255"
            fi
            if [ "$key" = "monitor_port" ]; then
                export MONITOR_PORT="$val"
            fi
Nikos Skalkotos's avatar
Nikos Skalkotos committed
102
103
104
105
	done

    case "$hypervisor" in
    kvm)
106
        HYPERVISOR=kvm
107
        ;;
Nikos Skalkotos's avatar
Nikos Skalkotos committed
108
    xen-hvm|xen-pvm)
109
110
111
112
113
114
115
116
        if [ -z "$IP" ]; then
            echo "ERROR: \`helper_ip' not defined or empty" >&2
            exit 1
        fi
        if [ -z "$MONITOR_PORT" ]; then
            echo "ERROR: \`monitor_port' not defined or empty" >&2
            exit 1
        fi
117
        $MOUNT -t xenfs xenfs /proc/xen
118
        ip addr add "$NETWORK" dev eth0
119
        ip link set eth0 up
120
        ip route add default dev eth0
121
122
        export DOMID=$(xenstore-read domid)
        HYPERVISOR=xen
Nikos Skalkotos's avatar
Nikos Skalkotos committed
123
124
125
126
        ;;
    *)
        echo "ERROR: Unknown hypervisor: \`$hypervisor'" >&2
        exit 1
127
128
        ;;
    esac
Dimitris Aragiorgis's avatar
Dimitris Aragiorgis committed
129

130
    export HYPERVISOR
131
132
}

133
report_error() {
134
    msg=""
135
136
    if [ ${#ERRORS[*]} -eq 0 ]; then
        # No error message. Print stderr
137
138
139
140
        local lines stderr
        stderr="$(tail --lines=${STDERR_LINE_SIZE} "$STDERR_FILE")"
        lines=$(wc -l <<< "$stderr")
        msg="STDERR:${lines}:$stderr"
141
142
    else
        for line in "${ERRORS[@]}"; do
143
            msg+="ERROR:$line"$'\n'
144
145
        done
    fi
146
147

    send_monitor_message_${HYPERVISOR} "$msg"
148
149
}

Nikos Skalkotos's avatar
Nikos Skalkotos committed
150
log_error() {
151
    ERRORS+=("$*")
152

153
    send_result_${HYPERVISOR} "ERROR: $@"
154
155
156
157

    # Use return instead of exit. The set -x options will terminate the script
    # but will also trigger ERR traps if defined.
    return 1
Nikos Skalkotos's avatar
Nikos Skalkotos committed
158
159
}

160
161
warn() {
    echo "Warning: $@" >&2
162
    send_monitor_message_${HYPERVISOR} "WARNING: $@"
163
164
}

165
report_task_start() {
166
    send_monitor_message_${HYPERVISOR} "$MSG_TYPE_TASK_START:${PROGNAME:2}"
167
168
}

169
report_task_end() {
170
    send_monitor_message_${HYPERVISOR} "$MSG_TYPE_TASK_END:${PROGNAME:2}"
171
172
}

173
system_poweroff() {
174
175
176
177
178
    while [ 1 ]; do
        # Credits to psomas@grnet.gr for this ...
        echo o > /proc/sysrq-trigger
        sleep 1
    done
179
180
}

Nikos Skalkotos's avatar
Nikos Skalkotos committed
181
182
183
184
185
186
187
188
189
get_base_distro() {
    local root_dir=$1

    if [ -e "$root_dir/etc/debian_version" ]; then
        echo "debian"
    elif [ -e "$root_dir/etc/redhat-release" ]; then
        echo "redhat"
    elif [ -e "$root_dir/etc/slackware-version" ]; then
        echo "slackware"
190
    elif [ -e "$root_dir/etc/SuSE-release" ]; then
Nikos Skalkotos's avatar
Nikos Skalkotos committed
191
        echo "suse"
192
    elif [ -e "$root_dir/etc/gentoo-release" ]; then
Nikos Skalkotos's avatar
Nikos Skalkotos committed
193
        echo "gentoo"
Nikos Skalkotos's avatar
Nikos Skalkotos committed
194
195
    elif [ -e "$root_dir/etc/arch-release" ]; then
        echo "arch"
Nikos Skalkotos's avatar
Nikos Skalkotos committed
196
197
    elif [ -e "$root_dir/etc/freebsd-update.conf" ]; then
        echo "freebsd"
198
    elif [ -e "$root_dir/etc/release" ]; then
199
        if grep -i netbsd "$root_dir/etc/release" &> /dev/null; then
200
201
202
203
            echo "netbsd"
        else
            warn "Unknown Unix flavor."
        fi
204
205
    elif [ -e "$root_dir/etc/motd" ]; then
        if grep -i ^openbsd <(head -1 "$root_dir/etc/motd") &> /dev/null; then
206
207
208
209
            echo "openbsd"
        else
            warn "Unknown Unix flavor"
        fi
210
211
    else
        warn "Unknown base distro."
Nikos Skalkotos's avatar
Nikos Skalkotos committed
212
213
214
215
    fi
}

get_distro() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
216
217
    local root_dir distro
    root_dir=$1
Nikos Skalkotos's avatar
Nikos Skalkotos committed
218
219
220
221

    if [ -e "$root_dir/etc/debian_version" ]; then
        distro="debian"
        if [ -e ${root_dir}/etc/lsb-release ]; then
222
            ID=$(grep ^DISTRIB_ID= ${root_dir}/etc/lsb-release | cut -d= -f2)
Nikos Skalkotos's avatar
Nikos Skalkotos committed
223
224
225
226
227
228
229
            if [ "x$ID" = "xUbuntu" ]; then
                distro="ubuntu"
            fi
        fi
        echo "$distro"
    elif [ -e "$root_dir/etc/fedora-release" ]; then
        echo "fedora"
Nikos Skalkotos's avatar
Nikos Skalkotos committed
230
    elif [ -e "$root_dir/etc/centos-release" ]; then
Nikos Skalkotos's avatar
Nikos Skalkotos committed
231
232
233
234
235
        echo "centos"
    elif [ -e "$root_dir/etc/redhat-release" ]; then
        echo "redhat"
    elif [ -e "$root_dir/etc/slackware-version" ]; then
        echo "slackware"
236
    elif [ -e "$root_dir/etc/SuSE-release" ]; then
Nikos Skalkotos's avatar
Nikos Skalkotos committed
237
        echo "suse"
238
    elif [ -e "$root_dir/etc/gentoo-release" ]; then
Nikos Skalkotos's avatar
Nikos Skalkotos committed
239
        echo "gentoo"
Nikos Skalkotos's avatar
Nikos Skalkotos committed
240
241
    elif [ -e "$root_dir/etc/arch-release" ]; then
        echo "arch"
Nikos Skalkotos's avatar
Nikos Skalkotos committed
242
243
    elif [ -e "$root_dir/etc/freebsd-update.conf" ]; then
        echo "freebsd"
244
245
246
247
248
249
    elif [ -e "$root_dir/etc/release" ]; then
        if grep -in netbsd "$root_dir/etc/release" &> /dev/null; then
            echo "netbsd"
        else
            warn "Unknown Unix flavor"
        fi
250
251
    elif [ -e "$root_dir/etc/motd" ]; then
        if grep -i ^openbsd <(head -1 "$root_dir/etc/motd") &> /dev/null; then
252
253
254
255
            echo "openbsd"
        else
            warn "Unknown Unix flavor"
        fi
256
257
    else
        warn "Unknown distro."
Nikos Skalkotos's avatar
Nikos Skalkotos committed
258
259
260
    fi
}

261
get_partition_table() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
262
263
    local dev output
    dev="$1"
264
265
266
267
    # If the partition table is gpt then parted will raise an error if the
    # secondary gpt is not it the end of the disk, and a warning that has to
    # do with the "Last Usable LBA" entry in gpt.
    if ! output="$("$PARTED" -s -m "$dev" unit s print | grep -E -v "^(Warning|Error): ")"; then
268
        log_error "Unable to read partition table for device \`${dev}'. The image seems corrupted."
269
270
    fi

271
272
273
274
    echo "$output"
}

get_partition_table_type() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
275
276
    local ptable dev field
    ptable="$1"
277

Nikos Skalkotos's avatar
Nikos Skalkotos committed
278
    dev="$(sed -n 2p <<< "$ptable")"
279
280
281
282
283
284
285
286
287
    IFS=':' read -ra field <<< "$dev"

    echo "${field[5]}"
}

get_partition_count() {
    local ptable="$1"

    expr $(echo "$ptable" | wc -l) - 2
288
289
}

290
get_partition_by_num() {
291
292
293
294
295
296
    local ptable="$1"
    local id="$2"

    grep "^$id:" <<< "$ptable"
}

297
get_last_partition() {
298
    local ptable="$1"
299

300
    echo "$ptable" | tail -1
301
302
}

303
is_extended_partition() {
304
    local dev="$1"
305
    local part_num="$2"
306

307
    id=$($SFDISK --force --print-id "$dev" "$part_num")
308
    if [ "$id" = "5" -o "$id" = "f" ]; then
309
310
311
312
        echo "yes"
    else
        echo "no"
    fi
313
314
}

315
get_extended_partition() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
316
317
318
    local ptable dev
    ptable="$1"
    dev="$(echo "$ptable" | sed -n 2p | cut -d':' -f1)"
319

320
321
322
323
324
325
326
327
328
329
330
    tail -n +3 <<< "$ptable" | while read line; do
        part_num=$(cut -d':' -f1 <<< "$line")
        if [ $(is_extended_partition "$dev" "$part_num") == "yes" ]; then
            echo "$line"
            return 0
        fi
    done
    echo ""
}

get_logical_partitions() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
331
332
    local ptable part_num
    ptable="$1"
333
334
335
336
337
338
339
340
341
342
343
344

    tail -n +3 <<< "$ptable" | while read line; do
        part_num=$(cut -d':' -f1 <<< "$line")
        if [ $part_num -ge 5 ]; then
            echo "$line"
        fi
    done

    return 0
}

get_last_primary_partition() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
345
346
347
    local ptable dev output
    ptable="$1"
    dev=$(echo "ptable" | sed -n 2p | cut -d':' -f1)
348
349
350
351
352
353
354
355
356
357

    for i in 4 3 2 1; do
        if output=$(grep "^$i:" <<< "$ptable"); then
            echo "$output"
            return 0
        fi
    done
    echo ""
}

358
get_partition_to_resize() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
359
360
361
    local dev table table_type last_part last_part_num extended last_primary \
        ext_num prim_num
    dev="$1"
362
363

    table=$(get_partition_table "$dev")
364
365
366
    if [ -z "$table" ]; then
        return 0
    fi
367
368
369
370
371
372
373
374
375
376
377
378
379

    if [ $(get_partition_count "$table") -eq 0 ]; then
        return 0
    fi

    table_type=$(get_partition_table_type "$table")
    last_part=$(get_last_partition "$table")
    last_part_num=$(cut -d: -f1 <<< "$last_part")

    if [ "$table_type" == "msdos" -a $last_part_num -gt 4 ]; then
        extended=$(get_extended_partition "$table")
        last_primary=$(get_last_primary_partition "$table")
        ext_num=$(cut -d: -f1 <<< "$extended")
380
        last_prim_num=$(cut -d: -f1 <<< "$last_primary")
381
382
383
384
385
386
387
388
389
390
391

        if [ "$ext_num" != "$last_prim_num" ]; then
            echo "$last_prim_num"
        else
            echo "$last_part_num"
        fi
    else
        echo "$last_part_num"
    fi
}

392
create_partition() {
393
394
395
    local device="$1"
    local part="$2"
    local ptype="$3"
396

Nikos Skalkotos's avatar
Nikos Skalkotos committed
397
    local fields=()
398
    IFS=":;" read -ra fields <<< "$part"
399
400
401
402
403
404
405
406
    local id="${fields[0]}"
    local start="${fields[1]}"
    local end="${fields[2]}"
    local size="${fields[3]}"
    local fs="${fields[4]}"
    local name="${fields[5]}"
    local flags="${fields[6]//,/ }"

407
408
409
410
411
412
413
414
415
416
417
    if [ "$ptype" = "primary" -o "$ptype" = "logical" -o "$ptype" = "extended" ]; then
        $PARTED -s -m -- $device mkpart "$ptype" $fs "$start" "$end"
        for flag in $flags; do
            $PARTED -s -m $device set "$id" "$flag" on
        done
    else
        # For gpt
        start=${start:0:${#start}-1} # remove the s at the end
        end=${end:0:${#end}-1} # remove the s at the end
        $SGDISK -n "$id":"$start":"$end" -t "$id":"$ptype" "$device"
    fi
418
419
420
}

enlarge_partition() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
421
422
423
424
425
    local device part ptype new_end fields new_part table logical id
    device="$1"
    part="$2"
    ptype="$3"
    new_end="$4"
426
427
428
429

    if [ -z "$new_end" ]; then
        new_end=$(cut -d: -f 3 <<< "$(get_last_free_sector "$device")")
    fi
430

Nikos Skalkotos's avatar
Nikos Skalkotos committed
431
    fields=()
432
433
434
    IFS=":;" read -ra fields <<< "$part"
    fields[2]="$new_end"

Nikos Skalkotos's avatar
Nikos Skalkotos committed
435
    new_part=""
436
437
438
439
440
441
442
443
    for ((i = 0; i < ${#fields[*]}; i = i + 1)); do
        new_part="$new_part":"${fields[$i]}"
    done
    new_part=${new_part:1}

    # If this is an extended partition, removing it will also remove the
    # logical partitions it contains. We need to save them for later.
    if [ "$ptype" = "extended" ]; then
Nikos Skalkotos's avatar
Nikos Skalkotos committed
444
445
        table="$(get_partition_table "$device")"
        logical="$(get_logical_partitions "$table")"
446
447
448
449
450
451
452
453
454
455
456
457
    fi

    id=${fields[0]}
    $PARTED -s -m "$device" rm "$id"
    create_partition "$device" "$new_part" "$ptype"

    if [ "$ptype" = "extended" ]; then
        # Recreate logical partitions
        echo "$logical" | while read logical_part; do
            create_partition "$device" "$logical_part" "logical"
        done
    fi
458
459
460
}

get_last_free_sector() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
461
462
463
    local dev unit last_line ptype
    dev="$1"
    unit="$2"
464
465
466
467
468

    if [ -n "$unit" ]; then
        unit="unit $unit"
    fi

Nikos Skalkotos's avatar
Nikos Skalkotos committed
469
470
    last_line="$($PARTED -s -m "$dev" "$unit" print free | tail -1)"
    ptype="$(cut -d: -f 5 <<< "$last_line")"
471

472
    if [ "$ptype" = "free;" ]; then
473
        echo "$last_line"
474
475
476
    fi
}

477
get_unattend() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
478
479
    local target exists
    target="$1"
480
481
482
483
484
485
486
487
488
489

    # Workaround to search for $target/Unattend.xml in an case insensitive way.
    exists=$(find "$target"/ -maxdepth 1 -iname unattend.xml)
    if [ $(wc -l <<< "$exists") -gt 1 ]; then
        log_error "Found multiple Unattend.xml files in the image:" $exists
    fi

    echo "$exists"
}

Nikos Skalkotos's avatar
Nikos Skalkotos committed
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
disklabel2linux() {
    local partition i p
    partition="$1"

    i=4
    # Partition 'c' traditionally used to describe the entire disk is not
    # mapped to /dev/sda7 by the kernel
    for p in a b {d..p}; do
        let i++
        if [ "$p" = "$partition" ]; then
           echo "$i"
           return 0
        fi
    done

    log_error "Invalid BSD partition label: \`$partition'"
}

mount_all() {
    local osfamily target fs device fstab entry duid opts types num
    osfamily="$1"
    device="$2"
    target="$3"

    case "$osfamily" in
    linux)
        fs="ext[234]|msdos|vfat|ntfs"
        ;;
    freebsd)
        fs="ufs|msdosfs|ntfs"
        ;;
    openbsd)
        fs="ffs|msdos|ntfs|ext2fs"
        ;;
    netbsd)
        fs="ffs|ufs|msdos|ext2fs|ntfs"
        ;;
    *)
        log_error "Unsupported osfamily: \`$osfamily'"
        ;;
    esac

    fstab="$(grep -v ^\# "${target}/etc/fstab" | awk "{ if (match(\$3, \"$fs\")) { print \$2,\$1,\$3 } }" | sort -bd)"
    # <mpoint> <device> <fs>
    while read -ra entry; do
        # Skip root. It is already mounted
        if [ "${entry[0]}" = "/" ]; then
            continue
        fi

        opts="rw"
        types="auto"

        if [ "$osfamily" = linux ]; then
            # Linux persistent block device naming
            if [[ ${entry[1]} =~ ^(LABEL|UUID)= ]]; then
                entry[1]=$(findfs "${entry[1]}")
            else
                log_error "fstab contains non-persistent block device names"
            fi
        else
            if [[ "$osfamily" =~ ^(open|net)bsd$ ]]; then
                # OpenBSD DUIDs device naming
                if [[ "${entry[1]}" =~ ^[a-f0-9]{16}\.[a-p]$ ]]; then
                    duid="$(@scriptsdir@/disklabel.py --print-duid "$device")"

                    if [[ ! "${entry[1]}" =~ ^$duid ]]; then
                        warn "fstab refers to unknown DUID: \`$duid'"
                        continue
                    fi
                fi
                num="$(disklabel2linux "${entry[1]: -1}")"
                if [ "${entry[2]}" = ffs -o "$entry[2]" = ufs ]; then
                    types="ufs"
                    opts="ufstype=44bsd,rw"
                fi
            else # FreeBSD
                # We do not support FreeBSD labels for now
                if [[ "${entry[1]}" =~ ^/dev/(ufs|label)/ ]]; then
                    log_error "fstab contains FreeBSD labels. We currently don't support them"
                fi
                num="${entry[1]: -1}"
                if [ "${entry[2]}" = ufs ]; then
                    types="ufs"
                    opts="ufstype=ufs2,rw"
                fi
            fi
            entry[1]="${device}${num}"
        fi

        $MOUNT -t "$types" -o "$opts" "${entry[1]}" "${target}${entry[0]}"
        # In many cases when you try to mount a UFS file system read-write, the
        # mount command returns SUCCESS and a message like this gets printed:
        #
        #   mount: warning: <target> seems to be mounted read-only.
        #
        # remounting does the trick
        if [ "$types" = ufs ]; then
            $MOUNT -o remount,rw "${entry[1]}"
        fi

    done <<< "$fstab"
}

594
595
596
597
598
599
600
601
602
603
604
605
umount_all() {
    local target mpoints
    target="$1"

    # Unmount file systems mounted under directory `target'
    mpoints="$({ awk "{ if (match(\$2, \"^$target\")) { print \$2 } }" < /proc/mounts; } | sort -rbd | uniq)"

    for mpoint in $mpoints; do
        umount $mpoint
    done
}

606
607
608
609
get_ufstype() {
    local device ufs

    device="$1"
610
    ufs="$($DUMPFS_UFS "$device" | head -1 | awk -F "[()]" '{ for (i=2; i<NF; i+=2) print $i }')"
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625

    case "$ufs" in
        UFS1)
            echo 44bsd
            ;;
        UFS2)
            echo ufs2
            ;;
        *)
            log_error "Unsupported UFS type: \`$ufs' in device $device"
            echo ""
            ;;
    esac
}

Nikos Skalkotos's avatar
Nikos Skalkotos committed
626
cleanup() {
627
    # if something fails here, it shouldn't call cleanup again...
Nikos Skalkotos's avatar
Nikos Skalkotos committed
628
629
630
631
632
633
634
635
636
637
    trap - EXIT

    if [ ${#CLEANUP[*]} -gt 0 ]; then
        LAST_ELEMENT=$((${#CLEANUP[*]}-1))
        REVERSE_INDEXES=$(seq ${LAST_ELEMENT} -1 0)
        for i in $REVERSE_INDEXES; do
            # If something fails here, it's better to retry it for a few times
            # before we give up with an error. This is needed for kpartx when
            # dealing with ntfs partitions mounted through fuse. umount is not
            # synchronous and may return while the partition is still busy. A
638
639
640
641
642
            # premature attempt to delete partition mappings through kpartx on
            # a device that hosts previously mounted ntfs partition may fail
            # with a `device-mapper: remove ioctl failed: Device or resource
            # busy' error. A sensible workaround for this is to wait for a
            # while and then try again.
Nikos Skalkotos's avatar
Nikos Skalkotos committed
643
644
645
646
647
648
649
            local cmd=${CLEANUP[$i]}
            $cmd || for interval in 0.25 0.5 1 2 4; do
            echo "Command $cmd failed!"
            echo "I'll wait for $interval secs and will retry..."
            sleep $interval
            $cmd && break
        done
650
651
652
653
	if [ "$?" != "0" ]; then
            echo "Giving Up..."
            exit 1;
        fi
Nikos Skalkotos's avatar
Nikos Skalkotos committed
654
655
656
657
    done
  fi
}

658
task_cleanup() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
659
    local rc=$?
660
661

    if [ $rc -eq 0 ]; then
662
       report_task_end
663
664
665
666
667
668
669
    else
       report_error
    fi

    cleanup
}

670
check_if_excluded() {
Nikos Skalkotos's avatar
Nikos Skalkotos committed
671
672
673
    local name exclude
    name="$(tr [a-z] [A-Z] <<< ${PROGNAME:2})"
    exclude="SNF_IMAGE_PROPERTY_EXCLUDE_TASK_${name}"
674
    if [ -n "${!exclude}" ]; then
675
        warn "Task ${PROGNAME:2} was excluded and will not run."
676
677
678
679
680
681
        exit 0
    fi

    return 0
}

682
return_success() {
683
    send_result_${HYPERVISOR} "SUCCESS"
684
685
}

686
trap cleanup EXIT
687
set -o pipefail
688

689
690
691
692
STDERR_FILE=$(mktemp)
add_cleanup rm -f "$STDERR_FILE"
exec 2> >(tee -a "$STDERR_FILE" >&2)

Nikos Skalkotos's avatar
Nikos Skalkotos committed
693
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :