diff --git a/docs/losetup.md b/docs/losetup.md new file mode 100644 index 000000000..ec24edce3 --- /dev/null +++ b/docs/losetup.md @@ -0,0 +1,27 @@ +# LinuxKit losetup + +Image to setup a loop device backed by a regular file in a [linuxkit](https://github.com/linuxkit/linuxkit)-generated image. The typical use case is to have a portable storage location which can be used to persist settings or other files. Can be combined with the `linuxkit/dm-crypt` package for protection. + +## Usage + +The setup is a one time step during boot: + +```yaml +onboot: + - name: losetup + image: linuxkit/losetup: + command: ["/usr/bin/loopy", "-c", "/var/test.img"] +``` + +The above will associate the file `/var/test.img` with `/dev/loop0` and will also create it if it's not present. + +The container by default bind-mounts `/var:/var` and `/dev:/dev`. Usually the loop-file will reside on external storage which should be typically mounted under `/var` hence the choice of the defaults. If the loop-file is located somewhere else and you need a different bind-mount for it then do not forget to explicitly bind-mount `/dev:/dev` as well or else `losetup` will fail. + +### Options + +|Option|Default|Required|Notes| +|---|---|---|---| +|`-c` or `--create`||No|Creates the file if not present. If `--create` is not specified and the file is missing then the loop setup will obviously fail.| +|`-s` or `--size`|10|No|If `--create` was specified and the file is not present then this sets the size in MiB of the created file. The file will be filled from `/dev/zero`.| +|`-d` or `--dev`|`/dev/loop0`|No|Loop device which should be associated with the file.| +|``||**Yes**|The file to use as backing storage.| diff --git a/pkg/losetup/Dockerfile b/pkg/losetup/Dockerfile new file mode 100644 index 000000000..99b922d20 --- /dev/null +++ b/pkg/losetup/Dockerfile @@ -0,0 +1,18 @@ +FROM linuxkit/alpine:3683c9a66cd4da40bd7d6c7da599b2dcd738b559 AS mirror +RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/ +RUN apk add --no-cache --initdb -p /out \ + alpine-baselayout \ + busybox + +# Remove apk residuals +RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache + +FROM scratch +ENTRYPOINT [] +WORKDIR / +COPY --from=mirror /out/ / + +COPY loopy.sh /usr/bin/loopy +RUN chmod +x /usr/bin/loopy + +CMD ["/usr/bin/loopy"] diff --git a/pkg/losetup/build.yml b/pkg/losetup/build.yml new file mode 100644 index 000000000..0f158a560 --- /dev/null +++ b/pkg/losetup/build.yml @@ -0,0 +1,7 @@ +image: losetup +config: + binds: + - /dev:/dev + - /var:/var + capabilities: + - CAP_SYS_ADMIN diff --git a/pkg/losetup/loopy.sh b/pkg/losetup/loopy.sh new file mode 100644 index 000000000..ff872e594 --- /dev/null +++ b/pkg/losetup/loopy.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +set -e + +help() +{ + echo "Usage: $0 [options] " + echo + echo "Options:" + echo " -c, --create Create if not present, default: false" + echo " -s, --size NUM Size of in MiB if it gets created, default: 10" + echo " -d, --dev DEVICE Use DEVICE as loop device, default: /dev/loop0" + echo +} + +create=false +size_mib=10 +loop_device="/dev/loop0" + +O=`getopt -l create,size:,dev:,help -- cs:d:h "$@"` || exit 1 +eval set -- "$O" +while true; do + case "$1" in + -c|--create) create=true; shift;; + -s|--size) size_mib=$2; shift 2;; + -d|--dev) loop_device=$2; shift 2;; + -h|--help) help; exit 0;; + --) shift; break;; + *) echo "Unknown option $1"; help; exit 1;; + esac +done + +if [ -z "$1" ]; then + echo "Missing argument " + help + exit 1 +fi + +container_file=$1 + +if [ ! -b "$loop_device" ]; then + echo "Loop device $loop_device doesn't exist! Did you forget to bind-mount '/dev'?" + exit 2 +fi + +if [ ! -f "$container_file" ]; then + if [ $create = true ]; then + echo "File $container_file not found, creating new one of size $size_mib MiB" + dd if="/dev/zero" of="$container_file" bs=1M count=$size_mib + else + echo "File $container_file not found. Please specify --create or ensure it's present." + exit 2 + fi +fi + +echo "Associating file $container_file with loop device $loop_device" +losetup "$loop_device" "$container_file" diff --git a/test/cases/040_packages/012_losetup/check.sh b/test/cases/040_packages/012_losetup/check.sh new file mode 100755 index 000000000..19741ecb4 --- /dev/null +++ b/test/cases/040_packages/012_losetup/check.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +function failed { + printf "losetup test suite FAILED\n" >&1 + exit 1 +} + +LOOPFILE=$(losetup /dev/loop0 2>/dev/null | cut -d' ' -f3) + +[ "$LOOPFILE" = "/var/test.img" ] || failed + +printf "losetup test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/012_losetup/test.sh b/test/cases/040_packages/012_losetup/test.sh new file mode 100644 index 000000000..5ff5860dc --- /dev/null +++ b/test/cases/040_packages/012_losetup/test.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# SUMMARY: Check that the losetup package works +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=losetup + +clean_up() { + rm -rf ${NAME}-* +} +trap clean_up EXIT + +# Test code goes here +linuxkit build -format kernel+initrd -name "${NAME}" test.yml +RESULT="$(linuxkit run $NAME)" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/012_losetup/test.yml b/test/cases/040_packages/012_losetup/test.yml new file mode 100644 index 000000000..4cad560fe --- /dev/null +++ b/test/cases/040_packages/012_losetup/test.yml @@ -0,0 +1,28 @@ +kernel: + image: linuxkit/kernel:4.14.88 + cmdline: "console=ttyS0 console=ttyAMA0" +init: + - linuxkit/init:c563953a2277eb73a89d89f70e4b6dcdcfebc2d1 + - linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe +onboot: + - name: losetup + image: linuxkit/losetup:aaceeea49ac519bc3b87da239436dd997d67b431 + command: ["/usr/bin/loopy", "-c", "/var/test.img"] + - name: test + image: alpine:3.8 + net: host + binds: + - /check.sh:/check.sh + - /dev:/dev + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:afe8f7dd0d47a7991c54519b0f09124cb8c4e300 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh +trust: + org: + - linuxkit + image: + - alpine:3.8