Statistics
| Branch: | Tag: | Revision:

root / snf-image-helper / common.sh @ 21be5a41

History | View | Annotate | Download (8.8 kB)

1 7e5d635b Nikos Skalkotos
# Copyright (C) 2011 GRNET S.A. 
2 7e5d635b Nikos Skalkotos
# Copyright (C) 2007, 2008, 2009 Google Inc.
3 54080484 Nikos Skalkotos
#
4 7e5d635b Nikos Skalkotos
# This program is free software; you can redistribute it and/or modify
5 7e5d635b Nikos Skalkotos
# it under the terms of the GNU General Public License as published by
6 7e5d635b Nikos Skalkotos
# the Free Software Foundation; either version 2 of the License, or
7 7e5d635b Nikos Skalkotos
# (at your option) any later version.
8 54080484 Nikos Skalkotos
#
9 7e5d635b Nikos Skalkotos
# This program is distributed in the hope that it will be useful, but
10 7e5d635b Nikos Skalkotos
# WITHOUT ANY WARRANTY; without even the implied warranty of
11 7e5d635b Nikos Skalkotos
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 7e5d635b Nikos Skalkotos
# General Public License for more details.
13 54080484 Nikos Skalkotos
#
14 7e5d635b Nikos Skalkotos
# You should have received a copy of the GNU General Public License
15 7e5d635b Nikos Skalkotos
# along with this program; if not, write to the Free Software
16 7e5d635b Nikos Skalkotos
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 7e5d635b Nikos Skalkotos
# 02110-1301, USA.
18 54080484 Nikos Skalkotos
19 7f6bd8e0 Nikos Skalkotos
RESULT=/dev/ttyS1
20 c349d1b3 Nikos Skalkotos
FLOPPY_DEV=/dev/fd0
21 f6e23601 Nikos Skalkotos
PROGNAME=$(basename $0)
22 54080484 Nikos Skalkotos
23 8cd155a3 Nikos Skalkotos
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
24 8cd155a3 Nikos Skalkotos
25 54080484 Nikos Skalkotos
# Programs
26 54080484 Nikos Skalkotos
XMLSTARLET=xmlstarlet
27 b97ada71 Nikos Skalkotos
TUNE2FS=tune2fs
28 c349d1b3 Nikos Skalkotos
RESIZE2FS=resize2fs
29 42f09a19 Nikos Skalkotos
PARTED=parted
30 b126203e Nikos Skalkotos
SFDISK=sfdisk
31 bc9d337a Nikos Skalkotos
MKSWAP=mkswap
32 bc9d337a Nikos Skalkotos
BLKID=blkid
33 8576747b Nikos Skalkotos
BLOCKDEV=blockdev
34 ec728294 Nikos Skalkotos
REGLOOKUP=reglookup
35 ec728294 Nikos Skalkotos
CHNTPW=chntpw
36 54080484 Nikos Skalkotos
37 54080484 Nikos Skalkotos
CLEANUP=( )
38 54080484 Nikos Skalkotos
39 bad5ca1f Nikos Skalkotos
add_cleanup() {
40 bad5ca1f Nikos Skalkotos
    local cmd=""
41 bad5ca1f Nikos Skalkotos
    for arg; do cmd+=$(printf "%q " "$arg"); done
42 bad5ca1f Nikos Skalkotos
    CLEANUP+=("$cmd")
43 bad5ca1f Nikos Skalkotos
}
44 bad5ca1f Nikos Skalkotos
45 54080484 Nikos Skalkotos
log_error() {
46 7f6bd8e0 Nikos Skalkotos
    echo "ERROR: $@" | tee $RESULT >&2
47 54080484 Nikos Skalkotos
    exit 1
48 54080484 Nikos Skalkotos
}
49 54080484 Nikos Skalkotos
50 f6e23601 Nikos Skalkotos
warn() {
51 f6e23601 Nikos Skalkotos
    echo "Warning: $@" >&2
52 f6e23601 Nikos Skalkotos
}
53 f6e23601 Nikos Skalkotos
54 54080484 Nikos Skalkotos
get_base_distro() {
55 54080484 Nikos Skalkotos
    local root_dir=$1
56 54080484 Nikos Skalkotos
57 54080484 Nikos Skalkotos
    if [ -e "$root_dir/etc/debian_version" ]; then
58 54080484 Nikos Skalkotos
        echo "debian"
59 54080484 Nikos Skalkotos
    elif [ -e "$root_dir/etc/redhat-release" ]; then
60 54080484 Nikos Skalkotos
        echo "redhat"
61 54080484 Nikos Skalkotos
    elif [ -e "$root_dir/etc/slackware-version" ]; then
62 54080484 Nikos Skalkotos
        echo "slackware"
63 b5294d61 Nikos Skalkotos
    elif [ -e "$root_dir/etc/SuSE-release" ]; then
64 54080484 Nikos Skalkotos
        echo "suse"
65 b5294d61 Nikos Skalkotos
    elif [ -e "$root_dir/etc/gentoo-release" ]; then
66 54080484 Nikos Skalkotos
        echo "gentoo"
67 2755bb06 Nikos Skalkotos
    else
68 2755bb06 Nikos Skalkotos
        warn "Unknown base distro."
69 54080484 Nikos Skalkotos
    fi
70 54080484 Nikos Skalkotos
}
71 54080484 Nikos Skalkotos
72 54080484 Nikos Skalkotos
get_distro() {
73 54080484 Nikos Skalkotos
    local root_dir=$1
74 54080484 Nikos Skalkotos
75 54080484 Nikos Skalkotos
    if [ -e "$root_dir/etc/debian_version" ]; then
76 54080484 Nikos Skalkotos
        distro="debian"
77 54080484 Nikos Skalkotos
        if [ -e ${root_dir}/etc/lsb-release ]; then
78 df8b2f85 Nikos Skalkotos
            ID=$(grep ^DISTRIB_ID= ${root_dir}/etc/lsb-release | cut -d= -f2)
79 54080484 Nikos Skalkotos
            if [ "x$ID" = "xUbuntu" ]; then
80 54080484 Nikos Skalkotos
                distro="ubuntu"
81 54080484 Nikos Skalkotos
            fi
82 54080484 Nikos Skalkotos
        fi
83 54080484 Nikos Skalkotos
        echo "$distro"
84 54080484 Nikos Skalkotos
    elif [ -e "$root_dir/etc/fedora-release" ]; then
85 54080484 Nikos Skalkotos
        echo "fedora"
86 a93a31ee Nikos Skalkotos
    elif [ -e "$root_dir/etc/centos-release" ]; then
87 54080484 Nikos Skalkotos
        echo "centos"
88 54080484 Nikos Skalkotos
    elif [ -e "$root_dir/etc/redhat-release" ]; then
89 54080484 Nikos Skalkotos
        echo "redhat"
90 54080484 Nikos Skalkotos
    elif [ -e "$root_dir/etc/slackware-version" ]; then
91 54080484 Nikos Skalkotos
        echo "slackware"
92 b5294d61 Nikos Skalkotos
    elif [ -e "$root_dir/etc/SuSE-release" ]; then
93 54080484 Nikos Skalkotos
        echo "suse"
94 b5294d61 Nikos Skalkotos
    elif [ -e "$root_dir/etc/gentoo-release" ]; then
95 54080484 Nikos Skalkotos
        echo "gentoo"
96 2755bb06 Nikos Skalkotos
    else
97 2755bb06 Nikos Skalkotos
        warn "Unknown distro."
98 54080484 Nikos Skalkotos
    fi
99 54080484 Nikos Skalkotos
}
100 54080484 Nikos Skalkotos
101 01da0f7d Nikos Skalkotos
102 01da0f7d Nikos Skalkotos
get_partition_table() {
103 01da0f7d Nikos Skalkotos
    local dev="$1"
104 8576747b Nikos Skalkotos
    # If the partition table is gpt then parted will raise an error if the
105 8576747b Nikos Skalkotos
    # secondary gpt is not it the end of the disk, and a warning that has to
106 8576747b Nikos Skalkotos
    # do with the "Last Usable LBA" entry in gpt.
107 8576747b Nikos Skalkotos
    if ! output="$("$PARTED" -s -m "$dev" unit s print | grep -E -v "^(Warning|Error): ")"; then
108 01da0f7d Nikos Skalkotos
        log_error "Unable to read partition table for device \`${dev}'"
109 01da0f7d Nikos Skalkotos
    fi
110 01da0f7d Nikos Skalkotos
111 b126203e Nikos Skalkotos
    echo "$output"
112 b126203e Nikos Skalkotos
}
113 b126203e Nikos Skalkotos
114 b126203e Nikos Skalkotos
get_partition_table_type() {
115 b126203e Nikos Skalkotos
    local ptable="$1"
116 b126203e Nikos Skalkotos
117 b126203e Nikos Skalkotos
    local dev="$(sed -n 2p <<< "$ptable")"
118 b126203e Nikos Skalkotos
    declare -a field
119 b126203e Nikos Skalkotos
    IFS=':' read -ra field <<< "$dev"
120 b126203e Nikos Skalkotos
121 b126203e Nikos Skalkotos
    echo "${field[5]}"
122 b126203e Nikos Skalkotos
}
123 b126203e Nikos Skalkotos
124 b126203e Nikos Skalkotos
get_partition_count() {
125 b126203e Nikos Skalkotos
    local ptable="$1"
126 b126203e Nikos Skalkotos
127 b126203e Nikos Skalkotos
    expr $(echo "$ptable" | wc -l) - 2
128 eb8e3364 Nikos Skalkotos
}
129 eb8e3364 Nikos Skalkotos
130 8576747b Nikos Skalkotos
get_partition_by_num() {
131 01da0f7d Nikos Skalkotos
    local ptable="$1"
132 01da0f7d Nikos Skalkotos
    local id="$2"
133 01da0f7d Nikos Skalkotos
134 01da0f7d Nikos Skalkotos
    grep "^$id:" <<< "$ptable"
135 01da0f7d Nikos Skalkotos
}
136 01da0f7d Nikos Skalkotos
137 42f09a19 Nikos Skalkotos
get_last_partition() {
138 b126203e Nikos Skalkotos
    local ptable="$1"
139 42f09a19 Nikos Skalkotos
140 b126203e Nikos Skalkotos
    echo "$ptable" | tail -1
141 42f09a19 Nikos Skalkotos
}
142 42f09a19 Nikos Skalkotos
143 b126203e Nikos Skalkotos
is_extended_partition() {
144 42f09a19 Nikos Skalkotos
    local dev="$1"
145 b126203e Nikos Skalkotos
    local part_num="$2"
146 42f09a19 Nikos Skalkotos
147 b126203e Nikos Skalkotos
    id=$($SFDISK --print-id "$dev" "$part_num")
148 b126203e Nikos Skalkotos
    if [ "$id" = "5" ]; then
149 b126203e Nikos Skalkotos
        echo "yes"
150 b126203e Nikos Skalkotos
    else
151 b126203e Nikos Skalkotos
        echo "no"
152 b126203e Nikos Skalkotos
    fi
153 42f09a19 Nikos Skalkotos
}
154 42f09a19 Nikos Skalkotos
155 b126203e Nikos Skalkotos
get_extended_partition() {
156 b126203e Nikos Skalkotos
    local ptable="$1"
157 b126203e Nikos Skalkotos
    local dev="$(echo "$ptable" | sed -n 2p | cut -d':' -f1)"
158 42f09a19 Nikos Skalkotos
159 b126203e Nikos Skalkotos
    tail -n +3 <<< "$ptable" | while read line; do
160 b126203e Nikos Skalkotos
        part_num=$(cut -d':' -f1 <<< "$line")
161 b126203e Nikos Skalkotos
        if [ $(is_extended_partition "$dev" "$part_num") == "yes" ]; then
162 b126203e Nikos Skalkotos
            echo "$line"
163 b126203e Nikos Skalkotos
            return 0
164 b126203e Nikos Skalkotos
        fi
165 b126203e Nikos Skalkotos
    done
166 b126203e Nikos Skalkotos
    echo ""
167 b126203e Nikos Skalkotos
}
168 b126203e Nikos Skalkotos
169 b126203e Nikos Skalkotos
get_logical_partitions() {
170 b126203e Nikos Skalkotos
    local ptable="$1"
171 b126203e Nikos Skalkotos
172 b126203e Nikos Skalkotos
    tail -n +3 <<< "$ptable" | while read line; do
173 b126203e Nikos Skalkotos
        part_num=$(cut -d':' -f1 <<< "$line")
174 b126203e Nikos Skalkotos
        if [ $part_num -ge 5 ]; then
175 b126203e Nikos Skalkotos
            echo "$line"
176 b126203e Nikos Skalkotos
        fi
177 b126203e Nikos Skalkotos
    done
178 b126203e Nikos Skalkotos
179 b126203e Nikos Skalkotos
    return 0
180 b126203e Nikos Skalkotos
}
181 b126203e Nikos Skalkotos
182 b126203e Nikos Skalkotos
get_last_primary_partition() {
183 b126203e Nikos Skalkotos
    local ptable="$1"
184 b126203e Nikos Skalkotos
    local dev=$(echo "ptable" | sed -n 2p | cut -d':' -f1)
185 b126203e Nikos Skalkotos
186 b126203e Nikos Skalkotos
    for i in 4 3 2 1; do
187 b126203e Nikos Skalkotos
        if output=$(grep "^$i:" <<< "$ptable"); then
188 b126203e Nikos Skalkotos
            echo "$output"
189 b126203e Nikos Skalkotos
            return 0
190 b126203e Nikos Skalkotos
        fi
191 b126203e Nikos Skalkotos
    done
192 b126203e Nikos Skalkotos
    echo ""
193 b126203e Nikos Skalkotos
}
194 b126203e Nikos Skalkotos
195 8576747b Nikos Skalkotos
get_partition_to_resize() {
196 8576747b Nikos Skalkotos
    local dev="$1"
197 8576747b Nikos Skalkotos
198 8576747b Nikos Skalkotos
    table=$(get_partition_table "$dev")
199 8576747b Nikos Skalkotos
200 8576747b Nikos Skalkotos
    if [ $(get_partition_count "$table") -eq 0 ]; then
201 8576747b Nikos Skalkotos
        return 0
202 8576747b Nikos Skalkotos
    fi
203 8576747b Nikos Skalkotos
204 8576747b Nikos Skalkotos
    table_type=$(get_partition_table_type "$table")
205 8576747b Nikos Skalkotos
    last_part=$(get_last_partition "$table")
206 8576747b Nikos Skalkotos
    last_part_num=$(cut -d: -f1 <<< "$last_part")
207 8576747b Nikos Skalkotos
208 8576747b Nikos Skalkotos
    if [ "$table_type" == "msdos" -a $last_part_num -gt 4 ]; then
209 8576747b Nikos Skalkotos
        extended=$(get_extended_partition "$table")
210 8576747b Nikos Skalkotos
        last_primary=$(get_last_primary_partition "$table")
211 8576747b Nikos Skalkotos
        ext_num=$(cut -d: -f1 <<< "$extended")
212 8576747b Nikos Skalkotos
        prim_num=$(cut -d: -f1 <<< "$last_primary")
213 8576747b Nikos Skalkotos
214 8576747b Nikos Skalkotos
        if [ "$ext_num" != "$last_prim_num" ]; then
215 8576747b Nikos Skalkotos
            echo "$last_prim_num"
216 8576747b Nikos Skalkotos
        else
217 8576747b Nikos Skalkotos
            echo "$last_part_num"
218 8576747b Nikos Skalkotos
        fi
219 8576747b Nikos Skalkotos
    else
220 8576747b Nikos Skalkotos
        echo "$last_part_num"
221 8576747b Nikos Skalkotos
    fi
222 8576747b Nikos Skalkotos
}
223 8576747b Nikos Skalkotos
224 b126203e Nikos Skalkotos
create_partition() {
225 01da0f7d Nikos Skalkotos
    local device="$1"
226 01da0f7d Nikos Skalkotos
    local part="$2"
227 01da0f7d Nikos Skalkotos
    local ptype="$3"
228 b126203e Nikos Skalkotos
229 b126203e Nikos Skalkotos
    declare -a fields
230 b126203e Nikos Skalkotos
    IFS=":;" read -ra fields <<< "$part"
231 01da0f7d Nikos Skalkotos
    local id="${fields[0]}"
232 01da0f7d Nikos Skalkotos
    local start="${fields[1]}"
233 01da0f7d Nikos Skalkotos
    local end="${fields[2]}"
234 01da0f7d Nikos Skalkotos
    local size="${fields[3]}"
235 01da0f7d Nikos Skalkotos
    local fs="${fields[4]}"
236 01da0f7d Nikos Skalkotos
    local name="${fields[5]}"
237 01da0f7d Nikos Skalkotos
    local flags="${fields[6]//,/ }"
238 01da0f7d Nikos Skalkotos
239 01da0f7d Nikos Skalkotos
    $PARTED -s -m -- $device mkpart "$ptype" $fs "$start" "$end"
240 b126203e Nikos Skalkotos
    for flag in $flags; do
241 b126203e Nikos Skalkotos
        $PARTED -s -m $device set "$id" "$flag" on
242 b126203e Nikos Skalkotos
    done
243 b126203e Nikos Skalkotos
}
244 b126203e Nikos Skalkotos
245 b126203e Nikos Skalkotos
enlarge_partition() {
246 01da0f7d Nikos Skalkotos
    local device="$1"
247 01da0f7d Nikos Skalkotos
    local part="$2"
248 01da0f7d Nikos Skalkotos
    local ptype="$3"
249 01da0f7d Nikos Skalkotos
    local new_end="$4"
250 01da0f7d Nikos Skalkotos
251 01da0f7d Nikos Skalkotos
    if [ -z "$new_end" ]; then
252 01da0f7d Nikos Skalkotos
        new_end=$(cut -d: -f 3 <<< "$(get_last_free_sector "$device")")
253 01da0f7d Nikos Skalkotos
    fi
254 b126203e Nikos Skalkotos
255 b126203e Nikos Skalkotos
    declare -a fields
256 b126203e Nikos Skalkotos
    IFS=":;" read -ra fields <<< "$part"
257 b126203e Nikos Skalkotos
    fields[2]="$new_end"
258 b126203e Nikos Skalkotos
259 b126203e Nikos Skalkotos
    local new_part=""
260 b126203e Nikos Skalkotos
    for ((i = 0; i < ${#fields[*]}; i = i + 1)); do
261 b126203e Nikos Skalkotos
        new_part="$new_part":"${fields[$i]}"
262 b126203e Nikos Skalkotos
    done
263 b126203e Nikos Skalkotos
    new_part=${new_part:1}
264 b126203e Nikos Skalkotos
265 b126203e Nikos Skalkotos
    # If this is an extended partition, removing it will also remove the
266 b126203e Nikos Skalkotos
    # logical partitions it contains. We need to save them for later.
267 b126203e Nikos Skalkotos
    if [ "$ptype" = "extended" ]; then
268 b126203e Nikos Skalkotos
        local table="$(get_partition_table "$device")"
269 b126203e Nikos Skalkotos
        local logical="$(get_logical_partitions "$table")"
270 b126203e Nikos Skalkotos
    fi
271 b126203e Nikos Skalkotos
272 b126203e Nikos Skalkotos
    id=${fields[0]}
273 b126203e Nikos Skalkotos
    $PARTED -s -m "$device" rm "$id"
274 b126203e Nikos Skalkotos
    create_partition "$device" "$new_part" "$ptype"
275 b126203e Nikos Skalkotos
276 b126203e Nikos Skalkotos
    if [ "$ptype" = "extended" ]; then
277 b126203e Nikos Skalkotos
        # Recreate logical partitions
278 b126203e Nikos Skalkotos
        echo "$logical" | while read logical_part; do
279 b126203e Nikos Skalkotos
            create_partition "$device" "$logical_part" "logical"
280 b126203e Nikos Skalkotos
        done
281 b126203e Nikos Skalkotos
    fi
282 42f09a19 Nikos Skalkotos
}
283 42f09a19 Nikos Skalkotos
284 42f09a19 Nikos Skalkotos
get_last_free_sector() {
285 42f09a19 Nikos Skalkotos
    local dev="$1"
286 01da0f7d Nikos Skalkotos
    local unit="$2"
287 01da0f7d Nikos Skalkotos
288 01da0f7d Nikos Skalkotos
    if [ -n "$unit" ]; then
289 01da0f7d Nikos Skalkotos
        unit="unit $unit"
290 01da0f7d Nikos Skalkotos
    fi
291 01da0f7d Nikos Skalkotos
292 01da0f7d Nikos Skalkotos
    local last_line="$("$PARTED" -s -m "$dev" "$unit" print free | tail -1)"
293 01da0f7d Nikos Skalkotos
    local ptype="$(cut -d: -f 5 <<< "$last_line")"
294 42f09a19 Nikos Skalkotos
295 b126203e Nikos Skalkotos
    if [ "$ptype" = "free;" ]; then
296 01da0f7d Nikos Skalkotos
        echo "$last_line"
297 42f09a19 Nikos Skalkotos
    fi
298 42f09a19 Nikos Skalkotos
}
299 42f09a19 Nikos Skalkotos
300 54080484 Nikos Skalkotos
cleanup() {
301 6a95db10 Vangelis Koukis
    # if something fails here, it shouldn't call cleanup again...
302 54080484 Nikos Skalkotos
    trap - EXIT
303 54080484 Nikos Skalkotos
304 54080484 Nikos Skalkotos
    if [ ${#CLEANUP[*]} -gt 0 ]; then
305 54080484 Nikos Skalkotos
        LAST_ELEMENT=$((${#CLEANUP[*]}-1))
306 54080484 Nikos Skalkotos
        REVERSE_INDEXES=$(seq ${LAST_ELEMENT} -1 0)
307 54080484 Nikos Skalkotos
        for i in $REVERSE_INDEXES; do
308 54080484 Nikos Skalkotos
            # If something fails here, it's better to retry it for a few times
309 54080484 Nikos Skalkotos
            # before we give up with an error. This is needed for kpartx when
310 54080484 Nikos Skalkotos
            # dealing with ntfs partitions mounted through fuse. umount is not
311 54080484 Nikos Skalkotos
            # synchronous and may return while the partition is still busy. A
312 01da0f7d Nikos Skalkotos
            # premature attempt to delete partition mappings through kpartx on
313 01da0f7d Nikos Skalkotos
            # a device that hosts previously mounted ntfs partition may fail
314 01da0f7d Nikos Skalkotos
            # with a `device-mapper: remove ioctl failed: Device or resource
315 01da0f7d Nikos Skalkotos
            # busy' error. A sensible workaround for this is to wait for a
316 01da0f7d Nikos Skalkotos
            # while and then try again.
317 54080484 Nikos Skalkotos
            local cmd=${CLEANUP[$i]}
318 54080484 Nikos Skalkotos
            $cmd || for interval in 0.25 0.5 1 2 4; do
319 54080484 Nikos Skalkotos
            echo "Command $cmd failed!"
320 54080484 Nikos Skalkotos
            echo "I'll wait for $interval secs and will retry..."
321 54080484 Nikos Skalkotos
            sleep $interval
322 54080484 Nikos Skalkotos
            $cmd && break
323 54080484 Nikos Skalkotos
        done
324 76009480 Nikos Skalkotos
	if [ "$?" != "0" ]; then
325 76009480 Nikos Skalkotos
            echo "Giving Up..."
326 76009480 Nikos Skalkotos
            exit 1;
327 76009480 Nikos Skalkotos
        fi
328 54080484 Nikos Skalkotos
    done
329 54080484 Nikos Skalkotos
  fi
330 54080484 Nikos Skalkotos
}
331 54080484 Nikos Skalkotos
332 e7cbe965 Nikos Skalkotos
check_if_excluded() {
333 f6e23601 Nikos Skalkotos
334 7ee2a43d Nikos Skalkotos
    local exclude=SNF_IMAGE_PROPERTY_EXCLUDE_TASK_${PROGNAME:2}
335 7ee2a43d Nikos Skalkotos
    if [ -n "${!exclude}" ]; then
336 e7cbe965 Nikos Skalkotos
        warn "Task $PROGNAME was excluded and will not run."
337 e7cbe965 Nikos Skalkotos
        exit 0
338 e7cbe965 Nikos Skalkotos
    fi
339 e7cbe965 Nikos Skalkotos
340 e7cbe965 Nikos Skalkotos
    return 0
341 e7cbe965 Nikos Skalkotos
}
342 e7cbe965 Nikos Skalkotos
343 de7269cd Nikos Skalkotos
trap cleanup EXIT
344 88262dba Nikos Skalkotos
set -o pipefail
345 01da0f7d Nikos Skalkotos
346 54080484 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :