4 4
lauhub

Armbian in Read Only Mode

Recommended Posts

Hi,

 

I am currently working on a OLinuxIno A20 limeX system which works in read only mode.

 

I use the code I developped here: https://github.com/lauhub/debian-to-readonly

 

I have small problems with armbian evolutions, since it uses, creates and modifies some files in some directories that should not be modified according to this page.

 

Example of files :

 

  • /etc/init.d/armhwinfo (modifies permissions of /etc/logrotate.d/armhwinfo)
  • /sbin/fake-hwclock (creates /etc/fake-hwclock.data)
  • /etc/update-motd.d/40-updates
  • /usr/local/bin/armbianmonitor (modifies /etc/armbianmonitor/datasources/soctemp)

I can easily disable these files for my purposes, but I would be glad to help or discuss about how to integrate this "read only mode" into Armbian project.

 

Does it interest someone ?

 

Share this post


Link to post
Share on other sites

Better than read only is overlay file system aka "virtual read only". If you use recent kernel:

apt-get install overlayroot
echo 'overlayroot="tmpfs"' >> /etc/overlayroot.conf
reboot

After reboot you can't make any permanent changes unless you use it within:

overlayroot-chroot

Overlay is done (with current settings) to RAM which is very fast but small. You can have overlay on any other device ...

Share this post


Link to post
Share on other sites

Thank you for this lead. I had forgotten that solution.

 

Overlayfs was not OK for me two years ago, because of my needs of 3.4 kernel with NAND support. At that time, it was not as simple as you indicate (there were some patches, but it gave me some headaches). So I developed my own solution.

 

(it sounds like I re-invented the wheel ;) )

 

Do you know if there are consequences in term of speed, boot time, reliability, ram footprint (I will run a Java VM (or more on a 1Gb RAM machine)) ?

Share this post


Link to post
Share on other sites
Do you know if there are consequences in term of speed, boot time, reliability, ram footprint (I will run a Java VM (or more on a 1Gb RAM machine)) ?

 

If you can, rather use modern kernel but it works on our 3.4.x out of the box. I only made few tests but one of my friends is using this on several Cubietruck workstations with 3.4 and he just confirmed "yes it works perfectly".

Share this post


Link to post
Share on other sites

Hi again,

Sorry, but it seems that overlayroot package is not available for Debian (package is missing from both Jessie an Wheezy). Seems to be an Ubuntu only package.

 

As I am stuck (for now) to Debian, I have to use my solution.

Share this post


Link to post
Share on other sites

Sorry, but it seems that overlayroot package is not available for Debian (package is missing from both Jessie an Wheezy). Seems to be an Ubuntu only package.

 

As I am stuck (for now) to Debian, I have to use my solution.

This package doesn't have any OS specific dependencies, so you should be able to install Ubuntu package on Debian manually without any issues.

Share this post


Link to post
Share on other sites

Thank you for this info,

I will try it, hoping that the package version are not too old (initramfs-tools 0.109 under Wheezy, although 0.122 under Ubuntu Xenial).

 

I will try it with Trusty packages as soon as I have some time.

Share this post


Link to post
Share on other sites

Hi Lauhub,

Thank you for this info,

I will try it, hoping that the package version are not too old (initramfs-tools 0.109 under Wheezy, although 0.122 under Ubuntu Xenial).

 

I will try it with Trusty packages as soon as I have some time.

Do you have success in using overlayfs to make rootfs read only on Armbian?

 

I am using Lime2-eMMC and latest Armbian (5.21), U-Boot (2016.09) and Kernel (4.7.6) and need to make rootfs read only when installed on eMMC and have:

  • SSD for system and data and make the system to boot from both eMMC and SSD;
  • succeeded to use overlayfs for merging read only and read/write data staff easily.

Unfortunately, described by Igor way is not possible because overlayfs-root packet is not in Debian.

In my opinion it is not good idea to rely on other distribution packages.

 

Any way did you try suggested by Zador way to install it in Armbian?

 

I am interested in getting work done with Armbian customization features only.

On the other hand read only root fs is a very frequent use case in embedded systems.

 

@Igor,

Is it possible to add overlayfs-root packet (will not be a precedent) in Armbian?

 

Best regards

Chris

 

Share this post


Link to post
Share on other sites

Hi Igor,

I can add this package to our repo if it works on Debian?

http://packages.ubuntu.com/xenial/overlayroot

I have installed manually overlayroot and change its configuration as mentioned above.

Before installation I have to install cryptsetup and cryptsetup-bin dependencies and installation had no problem.

 

After adding 'overlayroot="tmpfs"' to /etc/overlayroot.conf and reboot I try to test it by creating of some file in the root home directory.

Unfortunately, after rebooting the created file was still there and command 'overlayroot-chroot' says:

ERROR: Unable to find an overlayroot filesystem

which means there is something wrong.

 

Where could be the problem?

 

EDIT: I have removed the line for rootfs from /etc/fstab file for ability to support boot from any device without changing any files.

At overlayroot installation initrd.img was rebuild with warnings because of rootfs line lack in /etc/fstab file.

cryptsetup: WARNING: could not determine root device from /etc/fstab

Could it be the reason of the problem?

 

EDIT2: I try to install and configure overlayroot with rootfs line added to /etc/fstab and the installation (rebuilding initrd.img) completed without errors and warnings. Unfortunately, the problem is still there.

 

Best regards

Chris

Share this post


Link to post
Share on other sites

None. I made quick investigation and haven't found a solution. Anyway, there are at least two ways to go from here - close examine of overlayroot scripts or DIY. You need an overlay modules, which is build in and few proper mounts, which you can find in driver documentation. This way is also userspace independent and must work. It's just a bit more rough way.

Share this post


Link to post
Share on other sites

Thanks Igor,

None. I made quick investigation and haven't found a solution. Anyway, there are at least two ways to go from here - close examine of overlayroot scripts or DIY. You need an overlay modules, which is build in and few proper mounts, which you can find in driver documentation. This way is also userspace independent and must work. It's just a bit more rough way.

I have already used overlayfs to merge both RO and RW staff in a single directory used by our application. It was very easy to setup and it is working perfect.

 

Unfortunately, overlaying the root fs is more troublesome that is why I prefer to rely on a working and reliable solution.

 

Is it possible to use btrfs or bindfs as alternative of overlayfs to make root fs read only?

 

Best regards

Chris

Share this post


Link to post
Share on other sites

Hi to All,

 

As Igor recommended I start looking into overlayroot package staff.

 

After a brief search I find that overlayroot is looking for overlayfs Kernel module which do not exists (trying with modeprobe).

In my experience the Kernel module is 'overlay' instead of 'overlayfs' and probably this is a problem.

 

On the other hand in overlayroot script '/usr/share/initramfs-tools/scripts/init-bottom/overlayroot' can be read:

# overlayroot_driver *could* be defined in one of the configs above
# but we're not documenting that.
overlayroot_driver=${overlayroot_driver:-overlayfs}

I try to put in /etc/overlayroot.config following line:

overlayroot_driver="overlay"

and add 'overlay' to /etc/modules abut without success in activating overlayroot.

 

May be it is related with initrd image usage for early preparation to mount of overlayed root.

By default it is not loaded because U-Boot searches for /boot/initramfs-linux.img file.

It is rising a question is there any special reason for the lack of the link to initrd.img-4.7.6-sunxi in /boot directory?

 

That why I make appropriate link:

cd /boot && ln -sf initrd.img-4.7.6-sunxi initramfs-linux.img

and reboot. After loading the initram disk following messages can be read:

Begin: Running /scripts/init-bottom ... Warning: overlayroot: debug is busted
Warning: overlayroot: configuring overlayroot with mode=tmpfs opts='' per /dev/mmcblk0p1/etc/overlayroot.conf
Failure: overlayroot: missing kernel module overlayfs
/scripts/init-bottom/plymouth: line 18: /bin/plymouth: not found

which shows that overlayroot is looking for overlayfs kernel module but it is missing. Even 'overlay' module is missing in initram disk image.

On the other hand it looks for overlayroot.conf file on /dev/mmcblk0p1/etc/ which may be a problem when booting from other device (eMMC, SSD etc.).

 

Did somebody have such a problem and find a proper solution?

 

Best regards

Chris

 

Share this post


Link to post
Share on other sites

Hi to All,

 

After findings that overlayroot initialization is invoked in initram disk I have tried to make use of it in Jessie build by running:

cd /boot && ln -sf initrd.img-4.7.6-sunxi initramfs-linux.img

and after rebooting following is printed:

## Flattened Device Tree blob at 43000000
   Booting using the fdt blob at 0x43000000
   Loading Ramdisk to 49b93000, end 49fff18f ... OK
   Loading Device Tree to 49b84000, end 49b92f95 ... OK

Starting kernel ...

Uncompressing Linux... done, booting the kernel.
Loading, please wait...
Begin: Loading essential drivers ... done.
Begin: Running /scripts/init-premount ... done.
Begin: Mounting root file system ... Begin: Running /scripts/local-top ... done.
Begin: Running /scripts/local-premount ... Scanning for Btrfs filesystems
done.
Begin: Will now check root file system ... fsck from util-linux 2.25.2
fsck: error 2 (No such file or directory) while executing fsck.ext4 for /dev/sda1
fsck exited with status code 8
done.
Warning: File system check failed but did not detect errors
mount: No such file or directory
done.
Target filesystem doesn't have requested /sbin/init.
Begin: Running /scripts/local-bottom ... done.
Begin: Running /scripts/init-bottom ... trap: EXIT: bad trap
Warning: overlayroot: debug is busted
mount: No such file or directory
done.
Could not copy file: No such file or directory
No init found. Try passing init= bootarg.
Rebooting automatically due to panic= boot argument

and the system continuously reboots itself. Trying the same on a build without overlayroot installed the situation is the almost the same:

## Flattened Device Tree blob at 43000000
   Booting using the fdt blob at 0x43000000
   Loading Ramdisk to 49c25000, end 49fff4cd ... OK
   Loading Device Tree to 49c16000, end 49c24f95 ... OK

Starting kernel ...

Uncompressing Linux... done, booting the kernel.
Loading, please wait...
Begin: Loading essential drivers ... done.
Begin: Running /scripts/init-premount ... done.
Begin: Mounting root file system ... Begin: Running /scripts/local-top ... done.
Begin: Running /scripts/local-premount ... Scanning for Btrfs filesystems
done.
Begin: Will now check root file system ... fsck from util-linux 2.25.2
[/sbin/fsck.ext4 (1) -- /dev/mmcblk1p1] fsck.ext4 -a -C0 /dev/mmcblk1p1
/dev/mmcblk1p1: clean, 64029/228928 files, 291923/895744 blocks
done.
mount: No such file or directory
done.
Target filesystem doesn't have requested /sbin/init.
Begin: Running /scripts/local-bottom ... done.
Begin: Running /scripts/init-bottom ... mount: No such file or directory
done.
Could not copy file: No such file or directory
No init found. Try passing init= bootarg.
Rebooting automatically due to panic= boot argument

In my opinion there is some problem in default initram disk staff causing system panic and reboot.

 

On the other hand one of the problems in overlayroot is trying to use not existing 'overlayfs' module instead of existing 'overlay' one.

 

Last one is very rough difference with Kernel module name which is unlikely to be simply bug.

 

Does somebody knows working solution using overlayroot?

 

Best egards

Chris

 

Share this post


Link to post
Share on other sites

Hi Chris,

I think I found at least a lead to that problem

 

There are some missing parts into the initramfs scripts / configuration problem in boot.cmd.

 

I experienced the same problem with a small difference

 

Investigation

 

To investigate the problem, I modified the /usr/share/initramfs-tools/init first line as follow (shell debug mode):

#!/bin/sh -x

To correct the problem, I did the following:

 

FIrst bug correction: creating the /root/dev mount point

 

I had to modify the script /usr/share/initramfs-tools/scripts/init-bottom/udev adding a line prior to the mount command:

#This line prevents the "mount: No such file or directory" error:
mkdir -p ${rootmnt}/dev

#The following mount call was leading to "mount: No such file or directory" error
#Creating the directory works better
# move the /dev tmpfs to the rootfs
mount -n -o move /dev ${rootmnt}/dev

Second bug: modification of boot.cmd

 

I changed my boot.cmd script. I replaced boot parameters PARTUUID=e8198e69-01 with the UUID value (root=UUID=abcdef-012345-abcdef-123456)

 

My script is (if I remember well) is close to the one you provided:

setenv verbosity 7
part uuid ${devtype} ${devnum}:${distro_bootpart} uuid

#Old line:
#setenv bootargs "console=${console} root="PARTUUID=${uuid}" rw rootwait nomodeset mac_addr=02:8f:06:c0:f4:31 loglevel=${verbosity} ${extended_bootargs}"

#New line
setenv bootargs "console=${console} root="UUID=6b742ea8-78e6-403f-8558-d57ec67755c4" rw rootwait nomodeset mac_addr=02:8f:06:c0:f4:31 loglevel=${verbosity} ${extended_bootargs}"

if load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} /boot/zImage; then
  if load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} /boot/dtb/${fdtfile}; then
    if load ${devtype} ${devnum}:${distro_bootpart} ${ramdisk_addr_r} /boot/initramfs-linux.img; then
      bootz ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};
    else
      bootz ${kernel_addr_r} - ${fdt_addr_r};
    fi;
  fi;
fi

if load ${devtype} ${devnum}:${distro_bootpart} 0x48000000 /boot/uImage; then
  if load ${devtype} ${devnum}:${distro_bootpart} 0x43000000 /boot/script.bin; then
    setenv bootm_boot_mode sec;
    bootm 0x48000000;
  fi;
fi
# Recompile with:
# mkimage -C none -A arm -T script -d boot.cmd boot.scr

This make my initramfs work.

 

Now, I have to make overlayfs work.

 

Conclusion

 

Two bugs, and two ways to correct the second one.

 

The second way:

 

I think it could be possible to retrieve UUID from PARTUUID in u-boot, but I don't know how to do this.

 

Another way could be to change the scripts/functions script (resolve_device function) by adding the PARTUUID parsing (line 327), and/or the scripts/local (function local_mount_root, line 152 adn 154, replacing "mount" with "mount -f ")

 

EDIT:

There is a bug about PARTUUID in Debian BTS: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=801154

 

Version 0.121 of initramfs-tools support PARTUUID

Share this post


Link to post
Share on other sites

Hi again,

 

I successfully made overlayroot work under Debian Jessie.

 

Ubuntu package

 

I installed overlayroot_0.27ubuntu1.2_all.deb package

wget http://fr.archive.ubuntu.com/ubuntu/pool/main/c/cloud-initramfs-tools/overlayroot_0.27ubuntu1.2_all.deb
dpkg -i overlayroot_0.27ubuntu1.2_all.deb

Correcting overlayfs module name

 

About the following error:

Failure: overlayroot: missing kernel module overlayfs

I had to modify the /usr/share/initramfs-tools/scripts/init-bottom/overlayroot file:

Here is a diff:

diff --suppress-common-lines -r -y ./usr/share/initramfs-tools/scripts/init-bottom/overlayroot /usr/share/initramfs-tools/scripts/init-bottom/overlayroot
VARIABLES="overlayroot overlayroot_cfgdisk"                   | VARIABLES="overlayroot overlayroot_cfgdisk overlayroot_driver
        overlayfs)                                            |         overlayfs|overlay)
                mount_type="overlayfs"                        |                 mount_type="overlay"
                mount_opts="${mount_opts} overlayroot ${ROOTM |                 mount_opts="${mount_opts} overlay ${ROOTMNT}"
mount --move "${ROOTMNT}" "${root_ro}" ||                     | mount -o move "${ROOTMNT}" "${root_ro}" ||
        mount --move ${root_ro} ${ROOTMNT}                    |         mount -o move ${root_ro} ${ROOTMNT}
mount --move ${root_ro} "${ROOTMNT}${root_ro}" ||             | mount -o move ${root_ro} "${ROOTMNT}${root_ro}" ||
mount --move "${root_rw}" "${ROOTMNT}${root_rw}" ||           | mount -o move "${root_rw}" "${ROOTMNT}${root_rw}" ||

As you can see, I added one variable to the VARIABLES list and made some changes to mount parameters.

 

Here is the complete file:

 

 

#!/bin/sh
#  Copyright, 2012 Dustin Kirkland <kirkland@ubuntu.com>
#  Copyright, 2012 Scott Moser <smoser@ubuntu.com>
#  Copyright, 2012 Axel Heider
#
#  Based on scripts from
#    Sebastian P.
#    Nicholas A. Schembri State College PA USA
#    Axel Heider
#    Dustin Kirkland
#    Scott Moser
#
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see
#    <http://www.gnu.org/licenses/>.

case "$1" in
    # no pre-reqs
    prereqs) echo ""; exit 0;;
esac

. /scripts/functions

PATH=/usr/sbin:/usr/bin:/sbin:/bin
MYTAG="overlayroot"

TEMP_D="${TMPDIR:-/tmp}/${0##*/}.configs"
VARIABLES="overlayroot overlayroot_cfgdisk overlayroot_driver"

# generic settings
# ${ROOT} and ${rootmnt} are predefined by caller of this script. Note that
# the root fs ${rootmnt} it mounted readonly on the initrams, which fits
# nicely for our purposes.
root_rw=/media/root-rw
root_ro=/media/root-ro
ROOTMNT=${rootmnt} # use global name to indicate created outside this
OVERLAYROOT_DEBUG=0

log() {
    "log_${1}_msg" "$MYTAG: $2";
    _debug "[$1]:" "$2"
}
log_fail() { log failure "$*"; }
log_success() { log success "$*"; }
log_warn() { log warning "$*"; }
fail() {
    [ $# -eq 0 ] || log_fail "$@";
    exit 0; # why do we exit success?
}
cleanup() {
    [ -d "${TEMP_D}" ] && rm -Rf "${TEMP_D}"
}
debug() {
    _debug "$@"
    [ "${OVERLAYROOT_DEBUG:-0}" = "0" ] && return
    echo "$MYTAG:" "$@"
}
_debug() {
    if [ "${DEBUG_BUSTED:-0}" = "0" ]; then
        { echo "$@" >> "/dev/.initramfs/${MYTAG}.log"; } 2>/dev/null ||
            { DEBUG_BUSTED=1; log_warn "debug is busted"; }
    fi
}
safe_string() {
    local prev="$1" allowed="$2" cur=""
    [ -n "$prev" ] || return 1
    while cur="${prev#[${allowed}]}"; do
        [ -z "$cur" ] && return 0
        [ "$cur" = "$prev" ] && break
        prev="$cur"
    done
    return 1
}

parse_string() {
    # parse a key/value string like:
    # name=mapper,pass=foo,fstype=ext4,mkfs=1
    # set variables under namespace 'ns'.
    #  _RET_name=mapper
    #  _RET_pass=foo
    #  _RET_fstype=ext4
    # set _RET to the list of variables found
    local input="${1}" delim="${2:-,}" ns="${3:-_RET_}"
    local oifs="$IFS" tok="" keys="" key="" val=""

    set -f; IFS="$delim"; set -- $input; IFS="$oifs"; set +f;
    _RET=""
    for tok in "$@"; do
        key="${tok%%=*}"
        val="${tok#${key}}"
        val=${val#=}
        safe_string "$key" "0-9a-zA-Z_" ||
            { debug "$key not a safe variable name"; return 1; }
        eval "${ns}${key}"='${val}' || return 1
        keys="${keys} ${ns}${key}"
    done
    _RET=${keys# }
    return
}
get_varval() { eval _RET='${'$1'}'; }
write_kernel_cmdline_cfg() {
    local cfg="$1" desc="${2:-kernel cmdline}"
    local cmdline="" var=""
    read cmdline < /proc/cmdline || return 1
    : > "${cfg}" || return
    set -f
    {
    echo "desc='${desc}'"
    for tok in $cmdline; do
        for var in $VARIABLES; do
            if [ "$tok" = "$var" ]; then
                log_warn "kernel param without value '${tok}'";
                continue;
            elif [ "${tok}" = "${var}=" ]; then
                echo "${var}=''";
            elif [ "${tok#${var}=}" != "${tok}" ]; then
                echo "${var}='${tok#${var}=}'"
            fi
        done
    done
    } >> "$cfg"
    set +f
}

wait_for_dev() {
    local dev="$1" timeout="${2:-0}"
    [ -b "$dev" ] && return 0
    [ "$timeout" = "0" ] && return 1
    # wait-for-root writes fstype to stdout, redirect to null
    wait-for-root "$dev" "$timeout" >/dev/null
}
crypto_setup() {
    local fstype="ext4" pass="" mapname="secure" mkfs="1" dev=""
    local timeout=0
    local entropy_sources="/proc/sys/kernel/random/boot_id /proc/sys/kernel/random/uuid /dev/urandom"
    local seed=
    # Seed the psuedo random number generator with available seeds
    for seed in "/.random-seed" "${ROOTMNT}/var/lib/urandom/random-seed"; do
        [ -f "${seed}" ] && cat "${seed}" > /dev/urandom ||
            { debug "missing rng seed [${seed}]"; }
    done
    # this does necessary crypto setup and sets _RET
    # to the appropriate block device (ie /dev/mapper/secure)

    # mkfs (default is 1):
    #  0: never create filesystem
    #  1: if pass is given and mount fails, create a new one
    #     if no pass given, create new
    #  2: if pass is given and mount fails, fail
    #     if no pass given, create new
    local options="$1"
    parse_string "${options}" ||
        { log_fail "failed parsing '${options}'"; return 1; }

    fstype=${_RET_fstype:-${fstype}}
    pass=${_RET_pass:-${pass}}
    mapname=${_RET_mapname:-${mapname}}
    mkfs=${_RET_mkfs:-${mkfs}}
    dev=${_RET_dev:-${dev}}
    timeout=${_RET_timeout:-${timeout}}

    [ -n "$dev" ] ||
        { log_fail "dev= argument not provided in '${options}'"; return 1; }

    short2dev "$dev" ||
        { log_fail "failed to convert $dev to a device"; return 1; }
    dev="${_RET}"

    debug "fstype=${fstype} pass=${pass} mapname=${mapname}"
    debug "mkfs=${mkfs} dev=${dev} timeout=${timeout}"

    wait_for_dev "$dev" "$timeout" || {
        log_fail "crypt dev device $dev does not exist after ${timeout}s";
        return 1;
    }

    if [ -n "$pass" ]; then
        printf "%s" "$pass" |
            cryptsetup luksOpen "$dev" "$mapname" --key-file -
        if [ $? -eq 0 ]; then
            local tdev="/dev/mapper/$mapname"
            log_warn "reusing existing luks device at $dev"
            wait_for_dev "$tdev" 20 ||
                { log_fail "$tdev did not appear"; return 1; }
            _RET_DEVICE="/dev/mapper/$mapname"
            return 0
        fi
        if [ "$mkfs" != "1" ]; then
            log_fail "luksOpen failed on $dev with mkfs=$mkfs";
            return 1;
        fi
        log_warn "re-opening $dev failed with mkfs=$mkfs will create new"
    else
        [ "$mkfs" = "0" ] &&
            { log_fail "mkfs=0, but no password provided"; return 1; }
        entropy_sources="$entropy_sources $dev"
        local pass_file=$(mktemp /dev/.initramfs/${MYTAG}.XXXXXX) ||
            { log_fail "failed creation of password file"; return 1; }
        stat -L /dev/* /proc/* /sys/* >${pass_file} 2>&1 ||
            { log_warn "could not seed with stat entropy [$entropy_sources]"; }
        head -c 4096 $entropy_sources >> ${pass_file} ||
            { log_fail "failed reading entropy [$entropy_sources]"; return 1; }
        pass=$(sha512sum ${pass_file}) ||
            { log_fail "failed generation of password"; return 1; }
        pass=${pass%% *}
        printf "%s" "${pass}" > ${pass_file}
    fi

    log_warn "setting up new luks device at $dev"
    # clear backing device
    wipefs -a "$dev" ||
        { log_fail "failed to wipe $dev"; return 1; }
    printf "%s" "$pass" | cryptsetup luksFormat "$dev" --key-file - ||
        { log_fail "luksFormat $dev failed"; return 1; }
    printf "%s" "$pass" |
        cryptsetup luksOpen "$dev" "$mapname" --key-file - ||
        { log_fail "luksOpen $dev failed"; return 1; }
    mke2fs -t "${fstype}" "/dev/mapper/${mapname}" || {
        log_fail "failed to mkfs -t $fstype on map $mapname";
        return 1;
    }

    _RET_DEVICE="/dev/mapper/$mapname"
    return 0
}

dev_setup() {
    local options="$1" dev="" timeout=0 path="/"
    # options supported:
    #    dev=device,timeout=X,path=/
    parse_string "${options}" ||
        { log_fail "failed parsing '${options}'"; return 1; }

    dev=${_RET_dev:-${dev}}
    timeout=${_RET_timeout:-${timeout}}

    [ -n "$dev" ] ||
        { log_fail "dev= argument not provided in '${options}'"; return 1; }

    short2dev "$dev" ||
        { log_fail "failed to convert $dev to a device"; return 1; }
    dev="${_RET}"

    debug "dev=${dev} timeout=${timeout}"

    wait_for_dev "$dev" "$timeout"
    _RET_DEVICE="$dev"
}

overlayrootify_fstab() {
    # overlayrootify_fstab(input, root_ro, root_rw, dir_prefix, recurse, swap)
    # read input fstab file, write an overlayroot version to stdout
    # also returns (_RET) a list of directories that will need to be made
    local input="$1" root_ro="${2:-/media/root-ro}"
    local root_rw="${3:-/media/root-rw}" dir_prefix="${4:-/}"
    local recurse=${5:-1} swap=${6:-0}
    local hash="#" oline="" ospec="" upper="" dirs="" copy_opts=""
    local vfstypes=" proc sys tmpfs dev udev "
    local spec file vfstype opts pass freq line ro_line
    
    dir_prefix="${dir_prefix#/}"

    [ -f "$input" ] || return 1
    while read spec file vfstype opts pass freq; do
        line="$spec $file $vfstype $opts $pass $freq"
        case ",$opts," in
            *,ro,*) ro_opts="$opts";;
            *) ro_opts="ro,${opts}";;
        esac
        ro_line="$spec ${root_ro}$file $vfstype ${ro_opts} $pass $freq"
        if [ "${spec#${hash}}" != "$spec" ] ||
           [ -z "$freq" ]; then
            # line has a comment in first field, or not 6 fields
            echo "$line"
        elif [ "${vfstypes# *${vfstype} }" != "${vfstypes}" ]; then
            # this is a virtual filesystem, just let it through
            echo "${line}"
        elif [ "$vfstype" = "swap" ]; then
            if [ "$swap" = "0" ]; then
                # comment out swap lines
                echo "#overlayroot:swap=${swap}#${line}"
            elif [ "${spec#/}" != "${spec}" ] &&
                 [ "${spec#/dev/}" = "${spec}" ]; then
                # comment out swap files (spec starts with / and not in /dev)
                echo "#overlayroot:swapfile#${line}"
            else
                echo "${line}"
            fi
        else
            ospec="${root_ro}${file}"
            copy_opts=""
            [ "${opts#*nobootwait*}" != "${opts}" ] &&
                copy_opts=",nobootwait"
            upper="${root_rw%/}/${dir_prefix%/}${file%/}"
            oline="${ospec} ${file} overlayfs "
            oline="${oline}lowerdir=${root_ro}${file},"
            oline="${oline}upperdir=${upper}${copy_opts} $pass $freq"

            if [ "$recurse" != "0" ]; then
                echo "$ro_line"
                echo "$oline"
                dirs="${dirs} ${upper}"
            else
                echo "$line"
                [ "$file" = "/" ] && dirs="${dirs} ${upper}"
            fi
        fi
    done < "$input"
    _RET=${dirs# }
}

short2dev() {
    # turn 'LABEL=' or 'UUID=' into a device path
    # also support /dev/* and 'vdb' or 'xvda'
    local input="$1" oifs="$IFS" dev newdev s
    case "$input" in
        LABEL=*)
            dev="${input#LABEL=}"
            case "${dev}" in
                */*) dev="$(echo "${dev}" | sed 's,/,\\x2f,g')";;
            esac
            dev="/dev/disk/by-label/${dev}"
            ;;
        UUID=*) dev="/dev/disk/by-uuid/${input#UUID=}" ;;
        /dev/*) dev="${input}";;
        *) dev="/dev/${input}";;
    esac
    _RET=$dev
}

get_cfg() {
    # get_cfg(device, file, cfg, timeout=0)
    # copy the file $cfg off $device to $file, waiting $timeout for
    # $device to appear
    local dev="$1" file="$2" cfg="${3:-overlayroot.conf}" timeout="${4:-0}"
    local cfgdev="" success=0 didmnt=false mp="" pre="get_cfg($dev):"
    [ -z "$dev" ] && return 1

    if [ "$timeout" != "0" ]; then
        wait_for_dev "$dev" "$timeout" ||
            { debug "$pre did not appear in $timeout"; return 1; }
    else
        udevadm settle
    fi

    short2dev "$dev" && cfgdev="$_RET" && [ -b "$cfgdev" ] ||
        { debug "$pre not present"; return 1; }

    if mp="${TEMP_D}/mp" && mkdir "$mp" &&
        mount -o ro "$cfgdev" "$mp"; then
        if [ -f "$mp/$cfg" ]; then
            cp "$mp/$cfg" "$file" && success=1 ||
                debug "$pre copy failed"
        else
            debug "$pre '$file' file not found"
        fi
        umount "$mp"
    else
        debug "$pre mount failed"
    fi
    [ -d "$mp" ] || rmdir "$mp"
    [ $success -eq 1 ] || return 1
    _RET="$dev/$cfg"
}

parse_cfg() {
    # parse_cfg($file,$desc,$vars)
    # this reasonably safely sources the "config" file $file
    # and then declares the variables listed to stdout
    #
    # known issues:
    # * sourced file could re-define 'echo'
    # * just fails if a value has a ' in it
    [ -f "$1" ] || return 0
    tick="'" sh -c '
        __tick=$tick
        __file=$1; __desc=$2;
        __unset__="__unset__"
        shift 2
        __vars="$*"
        readonly __tick __file __desc __vars
        . "${__file}"
        if [ $? -ne 0 ]; then
            echo "failed source \"${__file}\" ($__desc)" 1>&2
            return 1
        fi
        set -e
        echo "desc=${__tick}${__desc}${__tick}"
        for var in ${__vars}; do
            eval val=\${${var}-${__unset__}} ||
                { echo "eval of $var failed"; exit 1; }
            [ "${val#*${__tick}}" = "${val}" ] || {
                echo "variable \"$var\" had single tick in it. fail";
                exit 1;
            }
            [ "${val}" = "${__unset__}" ] ||
                echo "$var=${__tick}${val}${__tick}"
        done
    ' -- "$@"
}

readcfgd() {
    local cfg_d="$1"
    # this kind of stinks, each VARIABLE goes into global scope
    local or="" or_cfgdisk=""
    _RET_desc_oroot=""
    _RET_desc_cfgdisk=""
    set +f
    for f in "${cfg_d}"/*; do
        . "$f" || fail "failed reading $f"
        [ "$or" != "${overlayroot}" ] &&
            _RET_desc_oroot="$desc"
        [ "${or_cfgdisk}" != "${overlayroot_cfgdisk}" ] &&
            _RET_desc_cfgdisk="$desc"
        or=${overlayroot}
        or_cfgdisk=${overlayroot_cfgdisk}
    done
    set -f
}

fix_upstart_overlayfs() {
    # inotify events on an overlayfs underlay do not propogate through
    # a newly created overlay.  This causes job creation and deletion issues
    # for upstart, which uses inotify on /etc/init. So ensure that the overlay
    # explicitly has a /etc/init (LP: #1213925)
    local root="$1"
    local initctl="$root/sbin/initctl"
    local eifile="/etc/init/.overlayfs-upstart-helper"

    [ -e "$initctl" -o -L "$initctl" ] || return 0
    [ -d "$root/etc/init" ] || return 0
    echo "#upstart needs help for overlayfs (LP: #1213925)." \
        > "$root/$eifile" ||
        { log_fail "failed to write $root/$eifile"; return 1; }
    debug "created $eifile under $root (LP: #1213925)"
}

cfgd="${TEMP_D}/configs"
mkdir -p "${cfgd}" || fail "failed to create tempdir"
trap cleanup EXIT

# collect the different config locations into a file
# write individual config files in $cfgd that contain
{
echo "desc='builtin'"
echo "overlayroot=''"
echo "overlayroot_cfgdisk='disabled'"
} > "$cfgd/00-builtin"

write_kernel_cmdline_cfg "${cfgd}/90-kernel" ||
    fail "failed to read kernel command line!"

parse_cfg "/conf/conf.d/overlayroot" "initramfs config" \
    "$VARIABLES" > "${cfgd}/10-initramfs" ||
    fail "failed parsing initramfs config"

parse_cfg "${ROOTMNT}/etc/overlayroot.conf" "$ROOT/etc/overlayroot.conf" \
    "$VARIABLES" > "${cfgd}/20-root-config" ||
    fail "failed parsing root config"

parse_cfg "${ROOTMNT}/etc/overlayroot.local.conf" \
    "$ROOT/etc/overlayroot.local.conf" \
    "$VARIABLES" > "${cfgd}/30-root-local-config" ||
    fail "failed parsing root config"

# now read the trusted configs, to see if overlayroot_cfgdisk is set
readcfgd "$cfgd" ||
    fail "reading configs failed"
used_desc="${_RET_desc_oroot}"

[ -n "${_RET_desc_cfgdisk}" ] &&
    debug "${_RET_desc_cfgdisk} set cfgdisk='${overlayroot_cfgdisk}'"

# if one of the trusted configs above gave us set the overlayroot_cfgdisk
# variable, then look for such a device and read a config from it.
cfgdisk=0
if [ "${overlayroot_cfgdisk:-disabled}" != "disabled" ] &&
    get_cfg "${overlayroot_cfgdisk}" "${TEMP_D}/cfgdisk"; then
    desc=${_RET}
    parse_cfg "${TEMP_D}/cfgdisk" "${desc}" "$VARIABLES" \
        > "${cfgd}/80-cfgdisk" ||
        fail "reading config from ${desc} failed"
    used_desc="${_RET_desc_oroot}"

    # now read the parsed configs again.
    readcfgd "$cfgd" ||
        fail "reading configs failed"

    [ -n "${_RET_desc_cfgdisk}" ] &&
        debug "${_RET_desc_cfgdisk} set cfgdisk=${overlayroot_cfgdisk}"
    [ -n "${_RET_desc_oroot}" ] &&
        debug "${_RET_desc_oroot} set overlayroot=${overlayroot}"
fi

opts=""
cfgmsg="${used_desc:+ (per ${used_desc})}"
case "${overlayroot:-disabled}" in
    tmpfs|tmpfs:*)
        mode="tmpfs"
        opts="${overlayroot#tmpfs}";
        opts=${opts#:}
        ;;
    /dev/*|device:*)
        case "$overlayroot" in
            /dev/*) opts="dev=${overlayroot}";;
            *) opts="${overlayroot#device:}";;
        esac
        dev_setup "${opts}" ||
            fail "failed setup overlay for ${overlayroot} [$opts]${cfgmsg}"
        mode="device"
        device="$_RET_DEVICE"
        ;;
    crypt:*)
        mode="crypt"
        opts=${overlayroot#crypt:}
        crypto_setup "${opts}" ||
            fail "failed setup crypt for ${overlayroot}${cfgmsg}"
        device="$_RET_DEVICE"
        ;;
    disabled)
        debug "overlayroot disabled${cfgmsg}"
        exit 0;;
    *)
        fail "invalid value for overlayroot: ${overlayroot}${cfgmsg}"
        exit 0;;
esac

parse_string "$opts" "," _RET_common_
swap=${_RET_common_swap:-0}
recurse=${_RET_common_recurse:-1}
OVERLAYROOT_DEBUG=${_RET_common_debug:-${OVERLAYROOT_DEBUG}}
dir_prefix=${_RET_common_dir:-"/overlay"}

debug "swap=$swap recurse=$recurse debug=$OVERLAYROOT_DEBUG dir=$dir_prefix"
debug "device=$device mode=$mode"

[ "$swap" = "0" -o "$swap" = "1" ] ||
    fail "invalid setting for swap: $swap. must be '0' or '1'"
[ "$recurse" = "0" -o "$recurse" = "1" ] ||
    fail "invalid setting for recurse: $recurse. must be '0' or '1'"

log_warn "configuring overlayroot with mode=$mode opts='$opts' per $used_desc"

# overlayroot_driver *could* be defined in one of the configs above
# but we're not documenting that.
overlayroot_driver=${overlayroot_driver:-overlayfs}

# settings based on overlayroot_driver
workdir=""
case "${overlayroot_driver}" in
    overlayfs|overlay)
        mount_type="overlay"
        mount_opts="-o lowerdir=${root_ro},upperdir=${root_rw}/${dir_prefix}"
        # 3.18+ require 'workdir=' option.
        case "$(uname -r)" in
            2*|3.1[01234567]*|3.[0-9].*) :;;
            *)
                workdir="${dir_prefix%/}-workdir"
                mount_opts="${mount_opts},workdir=${root_rw}/${workdir}";;
        esac
        mount_opts="${mount_opts} overlay ${ROOTMNT}"
        ;;
    aufs)
        mount_type="aufs"
        mount_opts="-o dirs=${root_rw}/${dir_prefix}:${root_ro}=ro aufs-root ${ROOTMNT}"
        ;;
    *)
        log_fail "invalid overlayroot driver: ${overlayroot_driver}"
        panic "$MYTAG"
        ;;
esac

# check if kernel module exists
modprobe -qb "${overlayroot_driver}" ||
    fail "missing kernel module ${overlayroot_driver}"

# make the mount point on the init root fs ${root_rw}
mkdir -p "${root_rw}" ||
    fail "failed to create ${root_rw}"

# make the mount point on the init root fs ${root_ro}
mkdir -p "${root_ro}" ||
    fail "failed to create ${root_ro}"

# mount the backing device to $root_rw
if [ "$mode" = "tmpfs" ]; then
    # mount a tmpfs using the device name tmpfs-root
    mount -t tmpfs tmpfs-root "${root_rw}" ||
        fail "failed to create tmpfs"
else
    # dev or crypto
    mount "$device" "${root_rw}" ||
        fail "failed mount backing device $device"
fi

mkdir -p "${root_rw}/${dir_prefix}" ||
    fail "failed to create ${dir_prefix} on ${device}"

[ -z "$workdir" ] || mkdir -p "$root_rw/${workdir}" ||
    fail "failed to create workdir '$workdir' on ${device}"

# root is mounted on ${ROOTMNT}, move it to ${ROOT_RO}.
mount -o move "${ROOTMNT}" "${root_ro}" ||
    fail "failed to move root away from ${ROOTMNT} to ${root_ro}"

# there is nothing left at ${ROOTMNT} now. So for any error we get we should
# either do recovery to restore ${ROOTMNT} for drop to a initramfs shell using
# "panic". Otherwise the boot process is very likely to fail with even more
# errors and leave the system in a wired state.

# mount virtual fs ${ROOTMNT} with rw-fs ${root_rw} on top or ro-fs ${root_ro}.
debug mount -t "$mount_type" $mount_opts
mount -t "$mount_type" $mount_opts
if [ $? -ne 0 ]; then
    log_fail "failed to create new ro/rw layered ${ROOTMNT}"
    log_fail "mount command was: mount -t $mount_type $mount_opts"
    # do recovery and try resoring the mount for ${ROOTMNT}
    mount -o move ${root_ro} ${ROOTMNT}
    if [ $? -ne 0 ]; then
        # thats bad, drop to shell to let the user try fixing this
        log_fail "RECOVERY_ERROR: failed to move $root_ro back to ${ROOTMNT}"
        panic "$MYTAG"
    fi
    exit 0
fi

# now the real root fs is on ${root_ro} of the init file system, our
# layered root fs is set up at ${ROOTMNT}. So we can write anywhere in
# {ROOTMNT} and the changes will end up in ${root_rw} while ${root_ro} it
# not touched. However ${root_ro} and ${root_rw} are on the initramfs root
# fs, which will be removed an replaced by ${ROOTMNT}. Thus we must move
# ${root_ro} and ${root_rw} to the rootfs visible later, ie.
# ${ROOTMNT}${root_ro} and ${ROOTMNT}${root_ro}.  Since the layered ro/rw
# is already up, these changes also end up on ${root_rw} while ${root_ro}
# is not touched.

# move mount from ${root_ro} to ${ROOTMNT}${root_ro}
mkdir -p "${ROOTMNT}/${root_ro}"
mount -o move ${root_ro} "${ROOTMNT}${root_ro}" ||
    fail "failed to move ${root_ro} to ${ROOTMNT}${root_ro}"

# move mount from ${root_rw} to ${ROOTMNT}${root_rw}
[ -d ${ROOTMNT}${root_rw} ] || mkdir -p ${ROOTMNT}${root_rw}
mount -o move "${root_rw}" "${ROOTMNT}${root_rw}" ||
    fail "failed to move ${root_rw} to ${ROOTMNT}${root_rw}"

# technically, everything is set up nicely now. Since ${ROOTMNT} had beend
# mounted read-only on the initfamfs already, ${ROOTMNT}${root_ro} is it,
# too.  Now we init process could run - but unfortunately, we may have to
# prepare some more things here.
# Basically, there are two ways to deal with the read-only root fs. If the
# system is made aware of this, things can be simplified a lot.  If it is
# not, things need to be done to our best knowledge.
#
# So we assume here, the system does not really know about our read-only
# root fs.
#
# Let's deal with /etc/fstab first. It usually contains an entry for the
# root fs, which is no longer valid now. We have to remove it and add our
# new ${root_ro} entry.
# Remember we are still on the initramfs root fs here, so we have to work
# on ${ROOTMNT}/etc/fstab. The original fstab is
# ${ROOTMNT}${root_ro}/etc/fstab.
cat <<EOF >${ROOTMNT}/etc/fstab
#
#  This fstab is in an overlayfs.  The real one can be found at
#  ${root_ro}/etc/fstab
#  The original entry for '/' and other mounts have been updated to be placed
#  under $root_ro.
#  To permanently modify this (or any other file), you should change-root into
#  a writable view of the underlying filesystem using:
#      sudo overlayroot-chroot
#
EOF

[ $? -eq 0 ] || log_fail "failed to modify /etc/fstab (step 1)"
overlayrootify_fstab ""${ROOTMNT}${root_ro}/etc/fstab"" "$root_ro" \
    "$root_rw" "$dir_prefix" "$recurse" "$swap" >> "${ROOTMNT}/etc/fstab" ||
    log_fail "failed to modify /etc/fstab (step 2)"

# we have to make the directories in ${root_rw} because if they do not
# exist, then the 'upper=' argument to overlayfs will fail.
for d in ${_RET}; do
    mkdir -p "${ROOTMNT}/$d"
done

if [ "${overlayroot_driver}" = "overlayfs" ]; then
    fix_upstart_overlayfs "$ROOTMNT" ||
        log_fail "failed to fix upstart for overlayfs"
fi

# if / is supposed to be mounted read-only (cmdline with 'ro')
# then mount our overlayfs as read-only just to be more normal
read cmdline < /proc/cmdline
cmdline=" $cmdline "
if [ "${cmdline#* ro }" != "$cmdline" ]; then
    mount -o remount,ro "$ROOTMNT" ||
        log_fail "failed to remount overlayroot read-only"
    debug "mounted $ROOTMNT read-only per kernel cmdline"
fi

msg="configured root with '$overlayroot' using ${overlayroot_driver} per"
msg="$msg ${used_desc}"
log_success "$msg"

exit 0
# vi: ts=4 noexpandtab


 

 

I modified the /usr/share/initramfs-tools/hooks/overlayroot:

diff --suppress-common-lines -r -y ./usr/share/initramfs-tools/hooks/overlayroot /usr/share/initramfs-tools/hooks/overlayroot
manual_add_modules overlayfs                                  | manual_add_modules overlay

Configuration

 

I added a file named /etc/overlayroot.local.conf (instead of modifying /etc/overlayroot.conf):

overlayroot_cfgdisk="disabled"
overlayroot="tmpfs"
overlayroot_driver="overlay"

Chrooting to R/W

 

Last but not least, I had to modify the overlayroot-chroot executable

diff --suppress-common-lines -r -y ./usr/sbin/overlayroot-chroot /usr/sbin/overlayroot-chroot
        overlay=$(grep -m1 "^overlayroot / overlayfs " /proc/ |         overlay=$(grep -m1 "^overlay / overlay " /proc/mounts

 

 

#!/bin/sh
#
#    overlayroot-chroot - chroot wrapper script for overlayroot
#    Copyright © 2012 Dustin Kirkland
#
#    Authors: Dustin Kirkland
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, version 3 of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

set -e
set -f # disable path expansion
REMOUNTS=""

error() {
    printf "ERROR: $@\n" 1>&2
}
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }

info() {
    printf "INFO: $@\n" 1>&2
}

get_lowerdir() {
    #overlay=$(grep -m1 "^overlayroot / overlayfs " /proc/mounts) || overlay=
    overlay=$(grep -m1 "^overlay / overlay " /proc/mounts) || overlay=
    if [ -n "${overlay}" ]; then
        lowerdir=${overlay##*lowerdir=}
        lowerdir=${lowerdir%%,*}
        if mountpoint "${lowerdir}" >/dev/null; then
            _RET="${lowerdir}"
        else
            fail "Unable to find the overlayroot lowerdir"
        fi
    else
        fail "Unable to find an overlayroot filesystem"
    fi
}

clean_exit() {
    local mounts="$1" rc=0 d="" lowerdir="" mp=""
    for d in ${mounts}; do
        if mountpoint ${d} >/dev/null; then
            umount ${d} || rc=1
        fi
    done
    for mp in $REMOUNTS; do
        mount -o remount,ro "${mp}" ||
            error "Note that [${mp}] is still mounted read/write"
    done
    [ "$2" = "return" ] && return ${rc} || exit ${rc}
}

# Try to find the overlayroot filesystem
get_lowerdir
lowerdir=${_RET}

recurse_mps=$(awk '$1 ~ /^\/dev\// && $2 ~ starts { print $2 }' \
    starts="^$lowerdir/" /proc/mounts)

mounts=
for d in proc run sys; do
    if ! mountpoint "${lowerdir}/${d}" >/dev/null; then
        mount -o bind "/${d}" "${lowerdir}/${d}" || fail "Unable to bind /${d}"
        mounts="$mounts $lowerdir/$d"
        trap "clean_exit \"${mounts}\" || true" EXIT HUP INT QUIT TERM   
    fi
done

# Remount with read/write
for mp in "$lowerdir" $recurse_mps; do
    mount -o remount,rw "${mp}" &&
        REMOUNTS="$mp $REMOUNTS" ||
        fail "Unable to remount [$mp] writable"
done
info "Chrooting into [${lowerdir}]"
chroot ${lowerdir} "$@"

# Clean up mounts on exit
clean_exit "${mounts}" "return"
trap "" EXIT HUP INT QUIT TERM

# vi: ts=4 noexpandtab
 

 

 

 

Fast-forward

 

I attached an archive with the modifications.

 

Using

tar zxvf overlayroot-debian-lauhub.tar.gz -C / 

after package installation should do the trick

overlayroot-debian.tar.gz

Share this post


Link to post
Share on other sites

Hi Lauhub,


I successfully made overlayroot work under Debian Jessie.

 

Ubuntu package

 

I installed overlayroot_0.27ubuntu1.2_all.deb package

Why did you base your solution on Debian Jessie and Ubuntu overlayroot package while it is available in Xenial?

As I have noted here the problem is probably the same in both cases.

 

Any way I will try your modification a.s.a.p.

 

Best regards

Chris

Share this post


Link to post
Share on other sites

Hi,

Why did you base your solution on Debian Jessie and Ubuntu overlayroot package while it is available in Xenial?
 

 

Because all the work I have already done on my current project is based on Jessie

Share this post


Link to post
Share on other sites

you can use unionfs-fuse, available on debian, that do the same stuff. I'm using it right now on several boards. You have to search on google how to conf it, but basically you need to unite the static and read-only /etc and /var with a temporary rw /etc /var that is mounted as tempfs file system. unionfs do that for you if you configure /usr/local/bin/mount_unionfs with

 

 

echo '[ -z "$1" ] && exit 1 || DIR=$1' > /usr/local/bin/mount_unionfs
echo 'ROOT_MOUNT=$(grep -v "^#" /etc/fstab | awk '"'"'$2=="/" {print substr($4,1,2)}'"'"')' >> /usr/local/bin/mount_unionfs
echo 'if [ "$ROOT_MOUNT" != "ro" ]; then' >> /usr/local/bin/mount_unionfs
echo '/bin/mount --bind ${DIR}_org ${DIR}' >> /usr/local/bin/mount_unionfs
echo 'else' >> /usr/local/bin/mount_unionfs
echo '/bin/mount -t tmpfs ramdisk ${DIR}_rw' >> /usr/local/bin/mount_unionfs
echo '/usr/bin/unionfs-fuse -o cow,allow_other,suid,dev,nonempty ${DIR}_rw=RW:${DIR}_org=RO ${DIR}' >> /usr/local/bin/mount_unionfs
echo 'fi' >> /usr/local/bin/mount_unionfs

chmod +x /usr/local/bin/mount_unionfs

 

 

and then switch to ro the partitions and add on fstab

 

 

mount_unionfs /etc fuse defaults 0 0

mount_unionfs /var fuse defaults 0 0

 

 

before it you need to create those 2 direcories and copy the static /etc and /var on them, you can do that by:

 

cp -al /etc /etc_org
mv /var /var_org
mkdir /etc_rw
mkdir /var /var_rw

 

Share this post


Link to post
Share on other sites

Thanks for your suggestion Dottgonzo,

you can use unionfs-fuse, available on debian, that do the same stuff. I'm using it right now on several boards...

I tried it and succeeded out-of-the-box following your description also applied for RPi.

 

Of course there was a small obstacle because in my use case rootfs options are transferred from uboot to kernel via its command line but it can be solved by a small change in mount_unionfs script.

 

Fortunately, simplicity and long life time (9+ years) of the project are more important for me at the moment than possible speed lost.

 

The only question for now is can we rely on Debian support to continue?

 

Best regards

Chris

Share this post


Link to post
Share on other sites

Does this work? How is it done? Is there any guide for dummies?
Ubuntu xenial is not valid for me for missing php5 and something else, but if it works overlayroot. I really liked how it works.
In debian jessie with kernel 4.8.4 it works but I want to freeze the system. I just need to make overlayroot work.

PD: On behalf of google, sorry for the translation.

Share this post


Link to post
Share on other sites

@lauhub

 

I am facing SD card corruption problem on power off (https://forum.armbian.com/index.php/topic/3427-armbian-sd-card-image-gets-corrupted-when-power-off-without-proper-shutdown/.

 

I am following your steps to make my rootfs read only with overlayfs  debian jessie/orange pi zero.  However I am not able to make it readonly. If I save any file and reboot file is present. There are some differences from your setup so looking forward to your help comment.

 

Your scripts in the attachment is expected to be applied on overlayroot_0.27ubuntu1.2_all.deb however this package is replaced with overlayroot_0.27ubuntu1.3_all.deb and it has some changes so not able to apply your changes directly. 

 

If you have a copy of overlayroot_0.27ubuntu1.2_all.deb can you please provide it Or if you have any suggestion to make it work on overlayroot_0.27ubuntu1.3_all.deb please let me know.

 

Based on diffs you provided I made changes, while I do not see any error, I am not able to make it readonly.

 

Thanks 

Share this post


Link to post
Share on other sites

Solusion for overlayroot in Armbian Jessie:

 

1) install overlayroot_0.27ubuntu1.4_all.deb

dpkg -i overlayroot_0.27ubuntu1.4_all.deb

 

2) add following lines to /usr/share/initramfs-tools/hooks/overlayroot file:

 

copy_exec /bin/grep /bin
copy_exec /usr/bin/stat /bin
copy_exec /bin/echo /bin

 

This will load missing tools required by /usr/share/initramfs-tools/scripts/init-bottom/overlayroot script.

 

3) replace all "mount --move" with "mount -o move" in /usr/share/initramfs-tools/scripts/init-bottom/overlayroot file.

 

4) update-initramfs -u

 

:-)

overlayroot_0.27ubuntu1.4_all.deb

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
4 4