~ecryptfs/ecryptfs/trunk

« back to all changes in this revision

Viewing changes to tests/lib/etl_funcs.sh

  • Committer: Dustin Kirkland
  • Date: 2009-02-13 15:57:24 UTC
  • Revision ID: kirkland@canonical.com-20090213155724-1q3qz2o0cbyimu9x
debian/ubuntu packaging

Initial checkin of the Debian/Ubuntu packaging

Signed-off-by: Dustin Kirkland <kirkland@canonical.com>

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/bin/bash
2
 
#
3
 
# etl_funcs.sh: eCryptfs test library (etl) helper functions
4
 
# Author: Tyler Hicks <tyhicks@canonical.com>
5
 
#
6
 
# Copyright (C) 2012 Canonical Ltd.
7
 
#
8
 
# This program is free software; you can redistribute it and/or
9
 
# modify it under the terms of the GNU General Public License
10
 
# as published by the Free Software Foundation version 2
11
 
# of the License.
12
 
#
13
 
# This program is distributed in the hope that it will be useful,
14
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
# GNU General Public License for more details.
17
 
#
18
 
# You should have received a copy of the GNU General Public License
19
 
# along with this program; if not, write to the Free Software
20
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21
 
 
22
 
etl=$(dirname $BASH_SOURCE[0])
23
 
 
24
 
default_fekek_pass="foo"
25
 
default_fekek_salt_hex="0011223344556677"
26
 
 
27
 
default_fnek_pass="$default_fekek_pass"
28
 
default_fnek_salt_hex="9988776655443322"
29
 
 
30
 
default_lfs="ext4"
31
 
default_lmount_opts="rw,relatime"
32
 
default_ext2_opts="user_xattr,acl"
33
 
default_ext3_opts="user_xattr,acl,commit=600,barrier=1,data=ordered"
34
 
default_btrfs_opts="nodatacow"
35
 
default_mount_opts="rw,relatime,ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_sig=\${ETL_FEKEK_SIG}"
36
 
default_fne_mount_opts="${default_mount_opts},ecryptfs_fnek_sig=\${ETL_FNEK_SIG}"
37
 
 
38
 
 
39
 
#
40
 
# etl_add_fekek_passphrase [PASS] [SALT_HEX]
41
 
#
42
 
# Adds a passphrase-based file encryption key to the kernel keyring. A default
43
 
# PASS and SALT_HEX will be used if they are not specified. The key signature
44
 
# is exported into ETL_FEKEK_SIG upon success.
45
 
#
46
 
# Only call this directly if your test needs to add a specific fekek.
47
 
#
48
 
etl_add_fekek_passphrase()
49
 
{
50
 
        if [ -z "$1" ]; then
51
 
                pass=$default_fekek_pass
52
 
        else
53
 
                pass=$1
54
 
        fi
55
 
        if [ -z "$2" ]; then
56
 
                salt_hex=$default_fekek_salt_hex
57
 
        else
58
 
                salt_hex=$2
59
 
        fi
60
 
 
61
 
        sig=$(${etl}/etl-add-passphrase-key-to-keyring $pass $salt_hex)
62
 
        if [ $? -ne 0 ]; then
63
 
                return 1
64
 
        fi
65
 
 
66
 
        export ETL_FEKEK_SIG=$sig
67
 
        return 0
68
 
}
69
 
 
70
 
#
71
 
# etl_add_fnek_passphrase [PASS] [SALT_HEX]
72
 
#
73
 
# Adds a passphrase-based filename encryption key to the kernel keyring. A
74
 
# default PASS and SALT_HEX will be used if they are not specified. The key
75
 
# signature is exported into ETL_FNEK_SIG upon success.
76
 
#
77
 
# Only call this directly if your test needs to add a specific fnek.
78
 
#
79
 
etl_add_fnek_passphrase()
80
 
{
81
 
        if [ -z "$1" ]; then
82
 
                pass=$default_fnek_pass
83
 
        else
84
 
                pass=$1
85
 
        fi
86
 
        if [ -z "$2" ]; then
87
 
                salt_hex=$default_fnek_salt_hex
88
 
        else
89
 
                salt_hex=$2
90
 
        fi
91
 
 
92
 
        sig=$(${etl}/etl-add-passphrase-key-to-keyring $pass $salt_hex)
93
 
        if [ $? -ne 0 ]; then
94
 
                return 1
95
 
        fi
96
 
 
97
 
        export ETL_FNEK_SIG=$sig
98
 
        return 0
99
 
}
100
 
 
101
 
#
102
 
# etl_add_keys
103
 
#
104
 
# Adds a fekek and, if appropriate, a fnek to the kernel keyring using the
105
 
# default values defined above. Most test cases requiring a generic mount will
106
 
# use this rather than the lower level functions that this calls.
107
 
#
108
 
# Set ETL_TEST_FNE to true if you want filename encryption enabled (it is best
109
 
# to lest the test harness handle that). ETL_FEKEK_SIG and, if appropriate,
110
 
# ETL_FNEK_SIG will contain the key signatures upon success.
111
 
#
112
 
etl_add_keys()
113
 
{
114
 
        # TODO: This should support non-passphrase based keys, too
115
 
 
116
 
        etl_add_fekek_passphrase
117
 
        if [ $? -ne 0 ]; then
118
 
                return 1
119
 
        fi
120
 
 
121
 
        if $ETL_TEST_FNE ; then
122
 
                etl_add_fnek_passphrase
123
 
                return $?
124
 
        fi
125
 
 
126
 
        return 0
127
 
}
128
 
 
129
 
#
130
 
# etl_unlink_key_sig SIGNATURE
131
 
#
132
 
# Unlinks the key corresponding to the specified signature.
133
 
#
134
 
etl_unlink_key_sig()
135
 
{
136
 
        if [ -z "$1" ]; then
137
 
                return 1
138
 
        fi
139
 
 
140
 
        show_line=$(keyctl list @u | grep -s $1)
141
 
        if [ $? -ne 0 ]; then
142
 
                return 1
143
 
        fi
144
 
 
145
 
        key=$(printf $show_line | awk -F ':' '{ print $1 }')
146
 
        keyctl unlink $key &>/dev/null
147
 
}
148
 
 
149
 
#
150
 
# etl_unlink_fekek
151
 
#
152
 
# Unlinks the key corresponding to the value of ETL_FEKEK_SIG. Unsets
153
 
# that variable upon success.
154
 
#
155
 
etl_unlink_fekek()
156
 
{
157
 
        if [ -z "$ETL_FEKEK_SIG" ]; then
158
 
               return 1
159
 
        fi
160
 
 
161
 
        etl_unlink_key_sig $ETL_FEKEK_SIG
162
 
        if [ $? -ne 0 ]; then
163
 
                return 1
164
 
        fi
165
 
 
166
 
        unset ETL_FEKEK_SIG
167
 
}
168
 
 
169
 
#
170
 
# etl_unlink_fnek
171
 
#
172
 
# Unlinks the key corresponding to the value of ETL_FNEK_SIG. Unsets
173
 
# that variable upon success.
174
 
#
175
 
etl_unlink_fnek()
176
 
{
177
 
        if [ -z "$ETL_FNEK_SIG" ]; then
178
 
                return 1
179
 
        fi
180
 
 
181
 
        etl_unlink_key_sig $ETL_FNEK_SIG
182
 
        if [ $? -ne 0 ]; then
183
 
                return 1
184
 
        fi
185
 
 
186
 
        unset ETL_FNEK_SIG
187
 
}
188
 
 
189
 
#
190
 
# etl_unlink_keys
191
 
#
192
 
# Unlinks the fekek and, if appropriate, the fnek from the kernel keyring. See
193
 
# the functions called by etl_unlink_keys() for more information.
194
 
#
195
 
# Most test cases requiring a generic mount will use this rather than the lower
196
 
# level functions that this calls.
197
 
#
198
 
etl_unlink_keys()
199
 
{
200
 
        etl_unlink_fekek
201
 
        if [ $? -ne 0 ]; then
202
 
                return 1
203
 
        fi
204
 
 
205
 
        if $ETL_TEST_FNE ; then
206
 
                etl_unlink_fnek
207
 
                return $?
208
 
        fi
209
 
 
210
 
        return 0
211
 
}
212
 
 
213
 
#
214
 
# etl_create_disk DISK_SIZE [DIR_PATH]
215
 
#
216
 
# Creates a disk image for testing. This disk image will be formatted and ready
217
 
# for mounting as the lower filesystem.
218
 
#
219
 
# DISK_SIZE must be specified in 1K block sizes. DIR_PATH can be specified so
220
 
# that the image file is stored somewhere other than the /tmp/ directory.
221
 
#
222
 
etl_create_disk()
223
 
{
224
 
        if [ -z "$1" ]; then
225
 
                return 1
226
 
        fi
227
 
        if [ -z "$2" ]; then
228
 
                dir_path="/tmp"
229
 
        else
230
 
                dir_path="$2"
231
 
        fi
232
 
        if [ -z "$ETL_LFS" ]; then
233
 
                lfs=$default_lfs
234
 
        else
235
 
                lfs=$ETL_LFS
236
 
        fi
237
 
 
238
 
        img=$(mktemp -q /${dir_path}/etl-img-XXXXXXXXXX)
239
 
        if [ $? -ne 0 ]; then
240
 
                return 1
241
 
        fi
242
 
 
243
 
        dd if=/dev/zero of=$img bs=1024 count=$1 &>/dev/null
244
 
        if [ $? -ne 0 ]; then
245
 
                rm $img &>/dev/null
246
 
                return 1
247
 
        fi
248
 
 
249
 
        case $lfs in
250
 
        ext2|ext3|ext4)
251
 
                mkfs_force='-F'
252
 
                ;;
253
 
        xfs)
254
 
                mkfs_force='-f'
255
 
                ;;
256
 
        *)
257
 
                mkfs_force=''
258
 
                ;;
259
 
        esac
260
 
 
261
 
        mkfs -t $lfs $mkfs_force $img &>/dev/null
262
 
        if [ $? -ne 0 ]; then
263
 
                rm $img &>/dev/null
264
 
                return 1
265
 
        fi
266
 
 
267
 
        export ETL_DISK=$img
268
 
        export ETL_LMOUNT_SRC=$img
269
 
        export ETL_LFS=$lfs
270
 
}
271
 
 
272
 
#
273
 
# etl_remove_disk
274
 
#
275
 
# Removes any lower test disk created by etl_create_disk().
276
 
#
277
 
etl_remove_disk()
278
 
{
279
 
        if [ -z "$ETL_DISK" ] || [ ! -f "$ETL_DISK" ]; then
280
 
                return 1
281
 
        fi
282
 
        if grep -q $ETL_DISK /proc/mounts; then
283
 
                return 1
284
 
        fi
285
 
 
286
 
        rm -f $ETL_DISK &>/dev/null
287
 
        unset ETL_DISK
288
 
}
289
 
 
290
 
#
291
 
# etl_load_ecryptfs
292
 
#
293
 
# Ensures that the eCryptfs kernel code is either loaded, if a module, or
294
 
# compiled in.
295
 
#
296
 
# If your test only needs an eCryptfs mount, don't call this function. The mount
297
 
# process will autoload the module for you. If you need access to something like
298
 
# /dev/ecryptfs, but don't need an eCryptfs mount, this function is for you.
299
 
#
300
 
etl_load_ecryptfs()
301
 
{
302
 
        if ! grep -q ecryptfs /proc/filesystems; then
303
 
                modprobe ecryptfs
304
 
                return $?
305
 
        fi
306
 
 
307
 
        return 0
308
 
}
309
 
 
310
 
#
311
 
# etl_construct_lmount_opts
312
 
#
313
 
# Construct the lower filesystem mount options. If mount options are already
314
 
# set, nothing is done. Otherwise, the default mount options for the lower
315
 
# filesystem are set.
316
 
#
317
 
# If you need specific options, you should probably construct them yourself and
318
 
# simply export them as ETL_LMOUNT_OPTS. This function is mostly a helper for
319
 
# other etl functions.
320
 
#
321
 
etl_construct_lmount_opts()
322
 
{
323
 
        if [ -n "$ETL_LMOUNT_OPTS" ]; then
324
 
                return 0
325
 
        fi
326
 
        if [ -z "$ETL_LFS" ]; then
327
 
                export ETL_LFS=$default_lfs
328
 
        fi
329
 
 
330
 
        # TODO: Add support for more filesystems
331
 
        case $ETL_LFS in
332
 
        ext2)
333
 
                lmount_opts=${default_lmount_opts},${default_ext2_opts}
334
 
                ;;
335
 
        ext3|ext4)
336
 
                lmount_opts=${default_lmount_opts},${default_ext3_opts}
337
 
                ;;
338
 
        btrfs)
339
 
                lmount_opts=${default_lmount_opts},${default_btrfs_opts}
340
 
                ;;
341
 
        *)
342
 
                lmount_opts=$default_lmount_opts
343
 
                ;;
344
 
        esac
345
 
 
346
 
        if [ -f "$ETL_LMOUNT_SRC" ]; then
347
 
                lmount_opts="${lmount_opts},loop"
348
 
        fi
349
 
 
350
 
        export ETL_LMOUNT_OPTS=$lmount_opts
351
 
        return 0
352
 
}
353
 
 
354
 
#
355
 
# etl_lmount
356
 
#
357
 
# Mounts the lower filesystem based upon the various env variables.
358
 
#
359
 
etl_lmount()
360
 
{
361
 
        if [ -z "$ETL_LMOUNT_SRC" ] || [ -z "$ETL_LMOUNT_DST" ]; then
362
 
                return 1
363
 
        fi
364
 
        if ! etl_construct_lmount_opts; then
365
 
                return 1
366
 
        fi
367
 
 
368
 
        mount -t "$ETL_LFS" -o "$ETL_LMOUNT_OPTS" \
369
 
                "$ETL_LMOUNT_SRC" "$ETL_LMOUNT_DST" &>/dev/null
370
 
}
371
 
 
372
 
#
373
 
# etl_lumount
374
 
#
375
 
# Unmounts the lower filesystem.
376
 
#
377
 
etl_lumount()
378
 
{
379
 
        if [ -z "$ETL_LMOUNT_SRC" ]; then
380
 
                return 1
381
 
        fi
382
 
 
383
 
        sync
384
 
        umount "$ETL_LMOUNT_DST" &>/dev/null
385
 
}
386
 
 
387
 
#
388
 
# etl_lmax_filesize
389
 
#
390
 
# Estimate on largest file that one can
391
 
# create in the lower filesystem.
392
 
#
393
 
etl_lmax_filesize()
394
 
{
395
 
        blks=$(df --total $ETL_LMOUNT_DST | tail -1 | awk '{print $4}')
396
 
 
397
 
        case $ETL_LFS in
398
 
        btrfs)
399
 
                # btrfs is a pain, since there is a big difference between the
400
 
                # amount of free space it reports and the maximum size of a file
401
 
                # one can produce before filling up the partition, especially
402
 
                # with small partitions. So instead we divide by 4 to ensure
403
 
                # we have more than enough free space. 
404
 
                #
405
 
                blks=$((blks / 4))
406
 
                ;;
407
 
        xfs)
408
 
                # xfs misbehaves on small file systems when we truncate, according to
409
 
                # david@fromorbit.com:
410
 
                #
411
 
                # "The space is considered "busy" and won't be reused until the
412
 
                # truncate transaction hits the log and the space is free on disk. See
413
 
                # xfs_busy_extent.c
414
 
                # 
415
 
                # Basically, testing XFS performance on tiny filesystems is going to
416
 
                # show false behaviours. XFS is optimised for large filesystems and
417
 
                # will typically shows low space artifacts on small filesystems,
418
 
                # especially when you are doing things like filling most of the free
419
 
                # filesystem space with 1 file.
420
 
                # 
421
 
                # e.g.  1GB free on at 100TB filesystem will throttle behaviours (say
422
 
                # speculative preallocation) much more effectively because itis within
423
 
                # 1% of ENOSPC. That same 1GB free on a 1GB filesystem won't throttle
424
 
                # preallocation at all, and so that one file when it reaches a little
425
 
                # over 500MB will try to preallocate half the remaining space in the
426
 
                # filesystem because the filesystem is only 50% full...."
427
 
                #
428
 
                # So lets limit ourselves generously by using just 33% for 'small'
429
 
                # xfs file systems to leave plenty of slop and 50% for larger xfs
430
 
                # file systems.
431
 
                #
432
 
                if [ $blks -lt 5000000 ]; then
433
 
                        blks=$((blks / 3))
434
 
                else
435
 
                        blks=$((blks / 2))
436
 
                fi
437
 
                ;;
438
 
        *)
439
 
                #
440
 
                # for other file systems we take off ~5% for some slop
441
 
                #
442
 
                slop=$((blks / 20))
443
 
                blks=$((blks - $slop))
444
 
                ;;
445
 
        esac
446
 
 
447
 
        echo $blks
448
 
}
449
 
 
450
 
_etl_init_mount_opts()
451
 
{
452
 
        if [ -z "$ETL_MOUNT_OPTS" ]; then
453
 
                opts=$default_mount_opts
454
 
 
455
 
                if [ -n "$ETL_FNEK_SIG" ]; then
456
 
                        opts="$default_fne_mount_opts"
457
 
                fi
458
 
 
459
 
                if [ -n "$ETL_APPENDED_MOUNT_OPTS" ]; then
460
 
                        opts="${opts},${ETL_APPENDED_MOUNT_OPTS}"
461
 
                fi
462
 
 
463
 
                export ETL_MOUNT_OPTS=$(eval "echo $opts")
464
 
        fi
465
 
}
466
 
 
467
 
etl_is_mount_opt_set()
468
 
{
469
 
        if [ -z "$1" ]; then
470
 
                return 1
471
 
        fi
472
 
 
473
 
        _etl_init_mount_opts
474
 
 
475
 
        if [[ ! $ETL_MOUNT_OPTS =~ (^|,)$1($|,) ]]; then
476
 
                return 1
477
 
        fi
478
 
 
479
 
        return 0
480
 
}
481
 
 
482
 
#
483
 
# etl_mount_i
484
 
#
485
 
# Performs an eCryptfs mount, bypassing the eCryptfs mount helper.
486
 
#
487
 
# If you're fine with the default eCryptfs mount options, or have constructed
488
 
# your own mount options, and have already added the appropriate keys to the
489
 
# kernel keyring, this is the easiest way to do an eCryptfs mount.
490
 
#
491
 
etl_mount_i()
492
 
{
493
 
        if [ -z "$ETL_MOUNT_SRC" ] || [ -z "$ETL_MOUNT_DST" ]; then
494
 
                return 1
495
 
        fi
496
 
 
497
 
        _etl_init_mount_opts
498
 
 
499
 
        mount -it ecryptfs -o "$ETL_MOUNT_OPTS" \
500
 
                "$ETL_MOUNT_SRC" "$ETL_MOUNT_DST"
501
 
}
502
 
 
503
 
#
504
 
# etl_umount_i
505
 
#
506
 
# Unmounts the eCryptfs mount point specified by ETL_MOUNT_DST. Note that the
507
 
# eCryptfs umount helper will not be called.
508
 
#
509
 
etl_umount_i()
510
 
{
511
 
        if [ -z "$ETL_MOUNT_DST" ]; then
512
 
                return 1
513
 
        fi
514
 
 
515
 
        if ! grep -q $ETL_MOUNT_DST /proc/mounts; then
516
 
                return 1
517
 
        fi
518
 
 
519
 
        sync
520
 
        umount -i "$ETL_MOUNT_DST" &>/dev/null
521
 
}
522
 
 
523
 
#
524
 
# etl_umount
525
 
#
526
 
# Unmounts the eCryptfs mount point specified by ETL_MOUNT_DST. Note that the
527
 
# eCryptfs umount helper will be called.
528
 
#
529
 
etl_umount()
530
 
{
531
 
        if [ -z "$ETL_MOUNT_DST" ]; then
532
 
                return 1
533
 
        fi
534
 
 
535
 
        if ! grep -q $ETL_MOUNT_DST /proc/mounts; then
536
 
                return 1
537
 
        fi
538
 
 
539
 
        sync
540
 
        umount "$ETL_MOUNT_DST" &>/dev/null
541
 
}
542
 
 
543
 
#
544
 
# etl_create_test_dir
545
 
#
546
 
# Creates a directory for carrying out tests inside of the eCryptfs mount point
547
 
# (ETL_MOUNT_DST).
548
 
#
549
 
# Upon success, the newly created directory's name is echoed to stdout.
550
 
#
551
 
etl_create_test_dir()
552
 
{
553
 
        parent=
554
 
 
555
 
        if [ -z "$ETL_MOUNT_DST" ] && [ -z "$1" ]; then
556
 
                return 1
557
 
        fi
558
 
 
559
 
        if [ -z "$1" ]; then
560
 
                parent=$ETL_MOUNT_DST
561
 
        else
562
 
                parent=$1
563
 
        fi
564
 
        test_basename=$(basename $0)
565
 
        test_dir=$(mktemp -qd ${parent}/etl-${test_basename}-XXXXXXXXXX)
566
 
        if [ $? -ne 0 ]; then
567
 
                return 1;
568
 
        fi
569
 
 
570
 
        echo $test_dir
571
 
        return 0
572
 
}
573
 
 
574
 
#
575
 
# etl_remove_test_dir TEST_DIR
576
 
#
577
 
# Removes the specified test directory.
578
 
#
579
 
# For now, it is nothing much more than a wrapper around rm -rf, but it may
580
 
# gain more functionality and/or safety checks in the future, so please use it.
581
 
#
582
 
etl_remove_test_dir()
583
 
{
584
 
        if [ -z "$1" ]; then
585
 
                return 0
586
 
        elif [ ! -d "$1" ]; then
587
 
                return 1
588
 
        elif [ "$1" = "/" ]; then
589
 
                return 1
590
 
        fi
591
 
 
592
 
        rm -rf $1 &>/dev/null
593
 
}
594
 
 
595
 
#
596
 
# etl_find_lower_path UPPER_PATH [LOWER_MOUNT]
597
 
#
598
 
# Given a path to an eCryptfs inode, finds a path to the lower inode. Searches
599
 
# for the lower inode in $ETL_LMOUNT_DST, unless LOWER_MOUNT is specified. Be
600
 
# careful using this with an inode with multiple hard links, as only one lower
601
 
# path will be returned.
602
 
#
603
 
# Upon success, the lower path is echoed to stdout and zero is returned.
604
 
#
605
 
etl_find_lower_path()
606
 
{
607
 
        lmount=$ETL_LMOUNT_DST
608
 
        if [ -n "$2" ]; then
609
 
                lmount=$2
610
 
        fi
611
 
        if [ -z "lmount" ]; then
612
 
                return 1
613
 
        fi
614
 
 
615
 
        inum=$(stat --printf=%i $1)
616
 
        if [ $? -ne 0 ]; then
617
 
                return 1
618
 
        fi
619
 
 
620
 
        lower_path=$(find $lmount -inum $inum -print -quit 2>/dev/null)
621
 
        if [ $? -ne 0 ] || [ -z "$lower_path" ]; then
622
 
                return 1
623
 
        fi
624
 
 
625
 
        echo $lower_path
626
 
        return 0
627
 
}