Statistics
| Branch: | Tag: | Revision:

root / snf-image-helper / common.sh @ bc9d337a

History | View | Annotate | Download (8 kB)

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

    
19
RESULT=/dev/ttyS1
20
FLOPPY_DEV=/dev/fd0
21
PROGNAME=$(basename $0)
22

    
23
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
24

    
25
# Programs
26
XMLSTARLET=xmlstarlet
27
TUNE2FS=tune2fs
28
RESIZE2FS=resize2fs
29
PARTED=parted
30
SFDISK=sfdisk
31
MKSWAP=mkswap
32
BLKID=blkid
33
REGLOOKUP=reglookup
34
CHNTPW=chntpw
35

    
36
CLEANUP=( )
37

    
38
add_cleanup() {
39
    local cmd=""
40
    for arg; do cmd+=$(printf "%q " "$arg"); done
41
    CLEANUP+=("$cmd")
42
}
43

    
44
log_error() {
45
    echo "ERROR: $@" | tee $RESULT >&2
46
    exit 1
47
}
48

    
49
warn() {
50
    echo "Warning: $@" >&2
51
}
52

    
53
get_base_distro() {
54
    local root_dir=$1
55

    
56
    if [ -e "$root_dir/etc/debian_version" ]; then
57
        echo "debian"
58
    elif [ -e "$root_dir/etc/redhat-release" ]; then
59
        echo "redhat"
60
    elif [ -e "$root_dir/etc/slackware-version" ]; then
61
        echo "slackware"
62
    elif [ -e "$root_dir/etc/SuSE-release" ]; then
63
        echo "suse"
64
    elif [ -e "$root_dir/etc/gentoo-release" ]; then
65
        echo "gentoo"
66
    else
67
        warn "Unknown base distro."
68
    fi
69
}
70

    
71
get_distro() {
72
    local root_dir=$1
73

    
74
    if [ -e "$root_dir/etc/debian_version" ]; then
75
        distro="debian"
76
        if [ -e ${root_dir}/etc/lsb-release ]; then
77
            ID=$(grep ^DISTRIB_ID= ${root_dir}/etc/lsb-release | cut -d= -f2)
78
            if [ "x$ID" = "xUbuntu" ]; then
79
                distro="ubuntu"
80
            fi
81
        fi
82
        echo "$distro"
83
    elif [ -e "$root_dir/etc/fedora-release" ]; then
84
        echo "fedora"
85
    elif [ -e "$root_dir/etc/centos-release" ]; then
86
        echo "centos"
87
    elif [ -e "$root_dir/etc/redhat-release" ]; then
88
        echo "redhat"
89
    elif [ -e "$root_dir/etc/slackware-version" ]; then
90
        echo "slackware"
91
    elif [ -e "$root_dir/etc/SuSE-release" ]; then
92
        echo "suse"
93
    elif [ -e "$root_dir/etc/gentoo-release" ]; then
94
        echo "gentoo"
95
    else
96
        warn "Unknown distro."
97
    fi
98
}
99

    
100
get_last_partition_id() {
101
    local dev="$1"
102
    if ! output="$("$PARTED" -s -m "$dev" print)"; then
103
        log_error "Unable to read partition table for device \`${dev}'"
104
    fi
105

    
106
    last_line=$(tail -1 <<< "$output")
107

    
108
    echo $(cut -d: -f1 <<< "$last_line")
109
}
110

    
111
get_partition_table() {
112
    local dev="$1"
113
    if ! output="$("$PARTED" -s -m "$dev" unit s print)"; then
114
        log_error "Unable to read partition table for device \`${dev}'"
115
    fi
116

    
117
    echo "$output"
118
}
119

    
120
get_partition_table_type() {
121
    local ptable="$1"
122

    
123
    local dev="$(sed -n 2p <<< "$ptable")"
124
    declare -a field
125
    IFS=':' read -ra field <<< "$dev"
126

    
127
    echo "${field[5]}"
128
}
129

    
130
get_partition_count() {
131
    local ptable="$1"
132

    
133
    expr $(echo "$ptable" | wc -l) - 2
134
}
135

    
136
get_partition_by_id() {
137
    local ptable="$1"
138
    local id="$2"
139

    
140
    grep "^$id:" <<< "$ptable"
141
}
142

    
143
get_last_partition() {
144
    local ptable="$1"
145

    
146
    echo "$ptable" | tail -1
147
}
148

    
149
is_extended_partition() {
150
    local dev="$1"
151
    local part_num="$2"
152

    
153
    id=$($SFDISK --print-id "$dev" "$part_num")
154
    if [ "$id" = "5" ]; then
155
        echo "yes"
156
    else
157
        echo "no"
158
    fi
159
}
160

    
161
get_extended_partition() {
162
    local ptable="$1"
163
    local dev="$(echo "$ptable" | sed -n 2p | cut -d':' -f1)"
164

    
165
    tail -n +3 <<< "$ptable" | while read line; do
166
        part_num=$(cut -d':' -f1 <<< "$line")
167
        if [ $(is_extended_partition "$dev" "$part_num") == "yes" ]; then
168
            echo "$line"
169
            return 0
170
        fi
171
    done
172
    echo ""
173
}
174

    
175
get_logical_partitions() {
176
    local ptable="$1"
177

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

    
185
    return 0
186
}
187

    
188
get_last_primary_partition() {
189
    local ptable="$1"
190
    local dev=$(echo "ptable" | sed -n 2p | cut -d':' -f1)
191

    
192
    for i in 4 3 2 1; do
193
        if output=$(grep "^$i:" <<< "$ptable"); then
194
            echo "$output"
195
            return 0
196
        fi
197
    done
198
    echo ""
199
}
200

    
201
create_partition() {
202
    local device="$1"
203
    local part="$2"
204
    local ptype="$3"
205

    
206
    declare -a fields
207
    IFS=":;" read -ra fields <<< "$part"
208
    local id="${fields[0]}"
209
    local start="${fields[1]}"
210
    local end="${fields[2]}"
211
    local size="${fields[3]}"
212
    local fs="${fields[4]}"
213
    local name="${fields[5]}"
214
    local flags="${fields[6]//,/ }"
215

    
216
    $PARTED -s -m -- $device mkpart "$ptype" $fs "$start" "$end"
217
    for flag in $flags; do
218
        $PARTED -s -m $device set "$id" "$flag" on
219
    done
220
}
221

    
222
enlarge_partition() {
223
    local device="$1"
224
    local part="$2"
225
    local ptype="$3"
226
    local new_end="$4"
227

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

    
232
    declare -a fields
233
    IFS=":;" read -ra fields <<< "$part"
234
    fields[2]="$new_end"
235

    
236
    local new_part=""
237
    for ((i = 0; i < ${#fields[*]}; i = i + 1)); do
238
        new_part="$new_part":"${fields[$i]}"
239
    done
240
    new_part=${new_part:1}
241

    
242
    # If this is an extended partition, removing it will also remove the
243
    # logical partitions it contains. We need to save them for later.
244
    if [ "$ptype" = "extended" ]; then
245
        local table="$(get_partition_table "$device")"
246
        local logical="$(get_logical_partitions "$table")"
247
    fi
248

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

    
253
    if [ "$ptype" = "extended" ]; then
254
        # Recreate logical partitions
255
        echo "$logical" | while read logical_part; do
256
            create_partition "$device" "$logical_part" "logical"
257
        done
258
    fi
259
}
260

    
261
get_last_free_sector() {
262
    local dev="$1"
263
    local unit="$2"
264

    
265
    if [ -n "$unit" ]; then
266
        unit="unit $unit"
267
    fi
268

    
269
    local last_line="$("$PARTED" -s -m "$dev" "$unit" print free | tail -1)"
270
    local ptype="$(cut -d: -f 5 <<< "$last_line")"
271

    
272
    if [ "$ptype" = "free;" ]; then
273
        echo "$last_line"
274
    fi
275
}
276

    
277
cleanup() {
278
    # if something fails here, it shouldn't call cleanup again...
279
    trap - EXIT
280

    
281
    if [ ${#CLEANUP[*]} -gt 0 ]; then
282
        LAST_ELEMENT=$((${#CLEANUP[*]}-1))
283
        REVERSE_INDEXES=$(seq ${LAST_ELEMENT} -1 0)
284
        for i in $REVERSE_INDEXES; do
285
            # If something fails here, it's better to retry it for a few times
286
            # before we give up with an error. This is needed for kpartx when
287
            # dealing with ntfs partitions mounted through fuse. umount is not
288
            # synchronous and may return while the partition is still busy. A
289
            # premature attempt to delete partition mappings through kpartx on
290
            # a device that hosts previously mounted ntfs partition may fail
291
            # with a `device-mapper: remove ioctl failed: Device or resource
292
            # busy' error. A sensible workaround for this is to wait for a
293
            # while and then try again.
294
            local cmd=${CLEANUP[$i]}
295
            $cmd || for interval in 0.25 0.5 1 2 4; do
296
            echo "Command $cmd failed!"
297
            echo "I'll wait for $interval secs and will retry..."
298
            sleep $interval
299
            $cmd && break
300
        done
301
	if [ "$?" != "0" ]; then
302
            echo "Giving Up..."
303
            exit 1;
304
        fi
305
    done
306
  fi
307
}
308

    
309
check_if_excluded() {
310

    
311
    local exclude=SNF_IMAGE_PROPERTY_EXCLUDE_TASK_${PROGNAME:2}
312
    if [ -n "${!exclude}" ]; then
313
        warn "Task $PROGNAME was excluded and will not run."
314
        exit 0
315
    fi
316

    
317
    return 0
318
}
319

    
320
trap cleanup EXIT
321
set -o pipefail
322

    
323
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :