Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (7.4 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
REGLOOKUP=reglookup
32
CHNTPW=chntpw
33

    
34
CLEANUP=( )
35

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

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

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

    
51
get_base_distro() {
52
    local root_dir=$1
53

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

    
69
get_distro() {
70
    local root_dir=$1
71

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

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

    
104
    echo "$output"
105
}
106

    
107
get_partition_table_type() {
108
    local ptable="$1"
109

    
110
    local dev="$(sed -n 2p <<< "$ptable")"
111
    declare -a field
112
    IFS=':' read -ra field <<< "$dev"
113

    
114
    echo "${field[5]}"
115
}
116

    
117
get_partition_count() {
118
    local ptable="$1"
119

    
120
    expr $(echo "$ptable" | wc -l) - 2
121
}
122

    
123
get_last_partition() {
124
    local ptable="$1"
125

    
126
    echo "$ptable" | tail -1
127
}
128

    
129
is_extended_partition() {
130
    local dev="$1"
131
    local part_num="$2"
132

    
133
    id=$($SFDISK --print-id "$dev" "$part_num")
134
    if [ "$id" = "5" ]; then
135
        echo "yes"
136
    else
137
        echo "no"
138
    fi
139
}
140

    
141
get_extended_partition() {
142
    local ptable="$1"
143
    local dev="$(echo "$ptable" | sed -n 2p | cut -d':' -f1)"
144

    
145
    tail -n +3 <<< "$ptable" | while read line; do
146
        part_num=$(cut -d':' -f1 <<< "$line")
147
        if [ $(is_extended_partition "$dev" "$part_num") == "yes" ]; then
148
            echo "$line"
149
            return 0
150
        fi
151
    done
152
    echo ""
153
}
154

    
155
get_logical_partitions() {
156
    local ptable="$1"
157

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

    
165
    return 0
166
}
167

    
168
get_last_primary_partition() {
169
    local ptable="$1"
170
    local dev=$(echo "ptable" | sed -n 2p | cut -d':' -f1)
171

    
172
    for i in 4 3 2 1; do
173
        if output=$(grep "^$i:" <<< "$ptable"); then
174
            echo "$output"
175
            return 0
176
        fi
177
    done
178
    echo ""
179
}
180

    
181
create_partition() {
182
    local device=$1
183
    local part=$2
184
    local ptype=$3
185

    
186
    declare -a fields
187
    IFS=":;" read -ra fields <<< "$part"
188
    local id=${fields[0]}
189
    local start=${fields[1]}
190
    local end=${fields[2]}
191
    local size=${fields[3]}
192
    local fs=${fields[4]}
193
    local name=${fields[5]}
194
    local flags=${fields[6]//,/ }
195

    
196
    $PARTED -s -m $device mkpart "$ptype" $fs "$start" "$end"
197
    for flag in $flags; do
198
        $PARTED -s -m $device set "$id" "$flag" on
199
    done
200
}
201

    
202
enlarge_partition() {
203
    local device=$1
204
    local part=$2
205
    local ptype=$3
206

    
207
    local new_end=$(get_last_free_sector "$device")
208
    declare -a fields
209
    IFS=":;" read -ra fields <<< "$part"
210
    fields[2]="$new_end"
211

    
212
    local new_part=""
213
    for ((i = 0; i < ${#fields[*]}; i = i + 1)); do
214
        new_part="$new_part":"${fields[$i]}"
215
    done
216
    new_part=${new_part:1}
217

    
218
    # If this is an extended partition, removing it will also remove the
219
    # logical partitions it contains. We need to save them for later.
220
    if [ "$ptype" = "extended" ]; then
221
        local table="$(get_partition_table "$device")"
222
        local logical="$(get_logical_partitions "$table")"
223
    fi
224

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

    
229
    if [ "$ptype" = "extended" ]; then
230
        # Recreate logical partitions
231
        echo "$logical" | while read logical_part; do
232
            create_partition "$device" "$logical_part" "logical"
233
        done
234
    fi
235
}
236

    
237
get_last_free_sector() {
238
    local dev="$1"
239
    local last_line="$("$PARTED" -s -m "$dev" print free | tail -1)"
240
    local ptype="$(echo "$last_line" | cut -d: -f 5)"
241

    
242
    if [ "$ptype" = "free;" ]; then
243
        echo "$last_line" | cut -d: -f 3
244
    fi
245
}
246

    
247
cleanup() {
248
    # if something fails here, it shouldn't call cleanup again...
249
    trap - EXIT
250

    
251
    if [ ${#CLEANUP[*]} -gt 0 ]; then
252
        LAST_ELEMENT=$((${#CLEANUP[*]}-1))
253
        REVERSE_INDEXES=$(seq ${LAST_ELEMENT} -1 0)
254
        for i in $REVERSE_INDEXES; do
255
            # If something fails here, it's better to retry it for a few times
256
            # before we give up with an error. This is needed for kpartx when
257
            # dealing with ntfs partitions mounted through fuse. umount is not
258
            # synchronous and may return while the partition is still busy. A
259
            # premature attempt to delete partition mappings through kpartx on a
260
            # device that hosts previously mounted ntfs partition may fail with
261
            # a `device-mapper: remove ioctl failed: Device or resource busy'
262
            # error. A sensible workaround for this is to wait for a while and
263
            # then try again.
264
            local cmd=${CLEANUP[$i]}
265
            $cmd || for interval in 0.25 0.5 1 2 4; do
266
            echo "Command $cmd failed!"
267
            echo "I'll wait for $interval secs and will retry..."
268
            sleep $interval
269
            $cmd && break
270
        done
271
	if [ "$?" != "0" ]; then
272
            echo "Giving Up..."
273
            exit 1;
274
        fi
275
    done
276
  fi
277
}
278

    
279
check_if_excluded() {
280

    
281
    local exclude=SNF_IMAGE_PROPERTY_EXCLUDE_TASK_${PROGNAME:2}
282
    if [ -n "${!exclude}" ]; then
283
        warn "Task $PROGNAME was excluded and will not run."
284
        exit 0
285
    fi
286

    
287
    return 0
288
}
289

    
290
trap cleanup EXIT
291
set -o pipefail
292
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :