3
# etl_funcs.sh: eCryptfs test library (etl) helper functions
4
# Author: Tyler Hicks <tyhicks@canonical.com>
6
# Copyright (C) 2012 Canonical Ltd.
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
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.
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
22
etl=$(dirname $BASH_SOURCE[0])
24
default_fekek_pass="foo"
25
default_fekek_salt_hex="0011223344556677"
27
default_fnek_pass="$default_fekek_pass"
28
default_fnek_salt_hex="9988776655443322"
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}"
40
# etl_add_fekek_passphrase [PASS] [SALT_HEX]
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.
46
# Only call this directly if your test needs to add a specific fekek.
48
etl_add_fekek_passphrase()
51
pass=$default_fekek_pass
56
salt_hex=$default_fekek_salt_hex
61
sig=$(${etl}/etl-add-passphrase-key-to-keyring $pass $salt_hex)
66
export ETL_FEKEK_SIG=$sig
71
# etl_add_fnek_passphrase [PASS] [SALT_HEX]
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.
77
# Only call this directly if your test needs to add a specific fnek.
79
etl_add_fnek_passphrase()
82
pass=$default_fnek_pass
87
salt_hex=$default_fnek_salt_hex
92
sig=$(${etl}/etl-add-passphrase-key-to-keyring $pass $salt_hex)
97
export ETL_FNEK_SIG=$sig
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.
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.
114
# TODO: This should support non-passphrase based keys, too
116
etl_add_fekek_passphrase
117
if [ $? -ne 0 ]; then
121
if $ETL_TEST_FNE ; then
122
etl_add_fnek_passphrase
130
# etl_unlink_key_sig SIGNATURE
132
# Unlinks the key corresponding to the specified signature.
140
show_line=$(keyctl list @u | grep -s $1)
141
if [ $? -ne 0 ]; then
145
key=$(printf $show_line | awk -F ':' '{ print $1 }')
146
keyctl unlink $key &>/dev/null
152
# Unlinks the key corresponding to the value of ETL_FEKEK_SIG. Unsets
153
# that variable upon success.
157
if [ -z "$ETL_FEKEK_SIG" ]; then
161
etl_unlink_key_sig $ETL_FEKEK_SIG
162
if [ $? -ne 0 ]; then
172
# Unlinks the key corresponding to the value of ETL_FNEK_SIG. Unsets
173
# that variable upon success.
177
if [ -z "$ETL_FNEK_SIG" ]; then
181
etl_unlink_key_sig $ETL_FNEK_SIG
182
if [ $? -ne 0 ]; then
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.
195
# Most test cases requiring a generic mount will use this rather than the lower
196
# level functions that this calls.
201
if [ $? -ne 0 ]; then
205
if $ETL_TEST_FNE ; then
214
# etl_create_disk DISK_SIZE [DIR_PATH]
216
# Creates a disk image for testing. This disk image will be formatted and ready
217
# for mounting as the lower filesystem.
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.
232
if [ -z "$ETL_LFS" ]; then
238
img=$(mktemp -q /${dir_path}/etl-img-XXXXXXXXXX)
239
if [ $? -ne 0 ]; then
243
dd if=/dev/zero of=$img bs=1024 count=$1 &>/dev/null
244
if [ $? -ne 0 ]; then
261
mkfs -t $lfs $mkfs_force $img &>/dev/null
262
if [ $? -ne 0 ]; then
268
export ETL_LMOUNT_SRC=$img
275
# Removes any lower test disk created by etl_create_disk().
279
if [ -z "$ETL_DISK" ] || [ ! -f "$ETL_DISK" ]; then
282
if grep -q $ETL_DISK /proc/mounts; then
286
rm -f $ETL_DISK &>/dev/null
293
# Ensures that the eCryptfs kernel code is either loaded, if a module, or
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.
302
if ! grep -q ecryptfs /proc/filesystems; then
311
# etl_construct_lmount_opts
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.
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.
321
etl_construct_lmount_opts()
323
if [ -n "$ETL_LMOUNT_OPTS" ]; then
326
if [ -z "$ETL_LFS" ]; then
327
export ETL_LFS=$default_lfs
330
# TODO: Add support for more filesystems
333
lmount_opts=${default_lmount_opts},${default_ext2_opts}
336
lmount_opts=${default_lmount_opts},${default_ext3_opts}
339
lmount_opts=${default_lmount_opts},${default_btrfs_opts}
342
lmount_opts=$default_lmount_opts
346
if [ -f "$ETL_LMOUNT_SRC" ]; then
347
lmount_opts="${lmount_opts},loop"
350
export ETL_LMOUNT_OPTS=$lmount_opts
357
# Mounts the lower filesystem based upon the various env variables.
361
if [ -z "$ETL_LMOUNT_SRC" ] || [ -z "$ETL_LMOUNT_DST" ]; then
364
if ! etl_construct_lmount_opts; then
368
mount -t "$ETL_LFS" -o "$ETL_LMOUNT_OPTS" \
369
"$ETL_LMOUNT_SRC" "$ETL_LMOUNT_DST" &>/dev/null
375
# Unmounts the lower filesystem.
379
if [ -z "$ETL_LMOUNT_SRC" ]; then
384
umount "$ETL_LMOUNT_DST" &>/dev/null
390
# Estimate on largest file that one can
391
# create in the lower filesystem.
395
blks=$(df --total $ETL_LMOUNT_DST | tail -1 | awk '{print $4}')
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.
408
# xfs misbehaves on small file systems when we truncate, according to
409
# david@fromorbit.com:
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
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.
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...."
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
432
if [ $blks -lt 5000000 ]; then
440
# for other file systems we take off ~5% for some slop
443
blks=$((blks - $slop))
450
_etl_init_mount_opts()
452
if [ -z "$ETL_MOUNT_OPTS" ]; then
453
opts=$default_mount_opts
455
if [ -n "$ETL_FNEK_SIG" ]; then
456
opts="$default_fne_mount_opts"
459
if [ -n "$ETL_APPENDED_MOUNT_OPTS" ]; then
460
opts="${opts},${ETL_APPENDED_MOUNT_OPTS}"
463
export ETL_MOUNT_OPTS=$(eval "echo $opts")
467
etl_is_mount_opt_set()
475
if [[ ! $ETL_MOUNT_OPTS =~ (^|,)$1($|,) ]]; then
485
# Performs an eCryptfs mount, bypassing the eCryptfs mount helper.
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.
493
if [ -z "$ETL_MOUNT_SRC" ] || [ -z "$ETL_MOUNT_DST" ]; then
499
mount -it ecryptfs -o "$ETL_MOUNT_OPTS" \
500
"$ETL_MOUNT_SRC" "$ETL_MOUNT_DST"
506
# Unmounts the eCryptfs mount point specified by ETL_MOUNT_DST. Note that the
507
# eCryptfs umount helper will not be called.
511
if [ -z "$ETL_MOUNT_DST" ]; then
515
if ! grep -q $ETL_MOUNT_DST /proc/mounts; then
520
umount -i "$ETL_MOUNT_DST" &>/dev/null
526
# Unmounts the eCryptfs mount point specified by ETL_MOUNT_DST. Note that the
527
# eCryptfs umount helper will be called.
531
if [ -z "$ETL_MOUNT_DST" ]; then
535
if ! grep -q $ETL_MOUNT_DST /proc/mounts; then
540
umount "$ETL_MOUNT_DST" &>/dev/null
544
# etl_create_test_dir
546
# Creates a directory for carrying out tests inside of the eCryptfs mount point
549
# Upon success, the newly created directory's name is echoed to stdout.
551
etl_create_test_dir()
555
if [ -z "$ETL_MOUNT_DST" ] && [ -z "$1" ]; then
560
parent=$ETL_MOUNT_DST
564
test_basename=$(basename $0)
565
test_dir=$(mktemp -qd ${parent}/etl-${test_basename}-XXXXXXXXXX)
566
if [ $? -ne 0 ]; then
575
# etl_remove_test_dir TEST_DIR
577
# Removes the specified test directory.
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.
582
etl_remove_test_dir()
586
elif [ ! -d "$1" ]; then
588
elif [ "$1" = "/" ]; then
592
rm -rf $1 &>/dev/null
596
# etl_find_lower_path UPPER_PATH [LOWER_MOUNT]
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.
603
# Upon success, the lower path is echoed to stdout and zero is returned.
605
etl_find_lower_path()
607
lmount=$ETL_LMOUNT_DST
611
if [ -z "lmount" ]; then
615
inum=$(stat --printf=%i $1)
616
if [ $? -ne 0 ]; then
620
lower_path=$(find $lmount -inum $inum -print -quit 2>/dev/null)
621
if [ $? -ne 0 ] || [ -z "$lower_path" ]; then