Page 2 of 8

Re: Raspbian with Read-only Root

Posted: Fri Dec 09, 2016 3:17 pm
by TimG
ejolson wrote:A read-only root filesystem can prevent sdcard corruption when the Raspberry Pi suddenly loses power.
I've been wanting to try this for a while. A few days ago I got round to it, and it's been working very nicely.

Disc corruption with read-write Raspbian is sufficiently rare that I can't say definitively whether the read-only root is helpful. But it's worth a try in projects which encounter frequent power interruptions, and Ejolson's recipe made it easy to set-up.

So, many thanks to Ejolson!

PS. I modified the recipe slightly to account for 1st generation Pis and to make switching between read-only and read-write easier:

Code: Select all

if [ "$(uname -m)" = "armv7l" ]; then v=7; else v=; fi

cp /boot/config.txt{,.rw}
echo -e "\nkernel=kernel$v.img\ninitramfs initrd$v.img" | cat /boot/config.txt - > /boot/config.txt.ro
cp /boot/config.txt{.ro,}

cp /boot/cmdline.txt{,.rw}
echo -n "boot=overlay " | cat - /boot/cmdline.txt > /boot/cmdline.txt.ro
cp /boot/cmdline.txt{.ro,}

update-initramfs -c -k $(uname -r)
mv /boot/initrd.img-$(uname -r) /boot/initrd$v.img

Re: Raspbian with Read-only Root

Posted: Fri Dec 09, 2016 3:49 pm
by drmacro
I mentioned in another post, just so it's here:
drmacro wrote:
Well that looks great, especially since is is with jessie...but

in the second set of instructions "cp -rp local-bottom overlay-bottom", get a "no such file or directory" error.

Sorry, about that. Please try just skipping that step. Unless an important package is missing it should still work. Let me know if you have any further trouble, because read-only with overlayfs should be quite easy.

Re: Raspbian with Read-only Root

Posted: Fri Dec 09, 2016 3:56 pm
by drmacro
So I proceeded.

When editing local_mount_root(), I can see the part that is to be commented out. But the rest of the listing shown in this post is significantly different that the content of my overlay file. Are the differences to be added to my local_mount_root()? I'm guessing yes...but, I'd rather be sure.

Code: Select all

    # Mount root
    mkdir /upper /lower                <--------- is not in my local file
    if [ "${FSTYPE}" != "unknown" ]; then
        mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} /lower
    else
        mount ${roflag} ${ROOTFLAGS} ${ROOT} /lower
    fi
    modprobe overlay                                                                    <--------- is not in my local file
    mount -t tmpfs tmpfs /upper                                                    <--------- is not in my local file
    mkdir /upper/data /upper/work                                                <--------- is not in my local file
    mount -t overlay \                                                                      <--------- is not in my local file
        -olowerdir=/lower,upperdir=/upper/data,workdir=/upper/work \ <--------- is not in my local file
        overlay ${rootmnt}                                                                 <--------- is not in my local file

Re: Raspbian with Read-only Root

Posted: Fri Dec 09, 2016 5:23 pm
by drmacro
Ok, so I read those lines a few more times and decided that it was meant that they should be added, I did so.

After boot. dmesg shows: overlayfs: failed to resolve '/upper/data': -2

'mount' shows nothing read only.

:?

Re: Raspbian with Read-only Root

Posted: Fri Dec 09, 2016 6:03 pm
by drmacro
Went back and retraced my steps found a couple of things I missed in overlay. Fixed that and re-ran update-initramfs.

Now I see no errors, but mount still shows everything as rw. And, if I create something, say in /home/pi, it's there after re-boot.

:(
drmacro wrote:Ok, so I read those lines a few more times and decided that it was meant that they should be added, I did so.

After boot. dmesg shows: overlayfs: failed to resolve '/upper/data': -2

'mount' shows nothing read only.

:?

Re: Raspbian with Read-only Root

Posted: Fri Dec 09, 2016 7:58 pm
by drmacro
OK, after some experimentation it does appear root is read only now.

But, other than df showing filesystem for / being overlay, how would I know? (I know I can create something and re-boot to see if its still there...)

(PS: my apologies for all the chatter. :oops: )

Re: Raspbian with Read-only Root

Posted: Sat Dec 10, 2016 1:52 am
by ejolson
drmacro wrote:OK, after some experimentation it does appear root is read only now.

But, other than df showing filesystem for / being overlay, how would I know? (I know I can create something and re-boot to see if its still there...)

(PS: my apologies for all the chatter. :oops: )
Root being mounted on overlay is the giveaway. The fact that it is otherwise difficult to tell is exactly what solves the compatibility problems and why all the software continues to work without any additional fiddling. Glad everything worked out.

Re: Raspbian with Read-only Root

Posted: Mon Dec 12, 2016 5:20 am
by pumpkinpi
Just tried this on a car based media server I built for the kids. Works! I didn't want to have any risk of corruptions on this thing. Nice little tutorial.

Thanks!

PPi

Re: Raspbian with Read-only Root

Posted: Wed Dec 21, 2016 5:14 pm
by carljohanjensen
This instruction is doing exactly what I like. :-) Thanks.
One thing: i did not find the local-bottom file ?
And one question: is there a simple way to "write through" the ram layer. ? Just in case I'd like to make some changes to the protected boot disk.

Re: Raspbian with Read-only Root

Posted: Wed Dec 21, 2016 7:08 pm
by ejolson
carljohanjensen wrote:This instruction is doing exactly what I like. :-) Thanks.
One thing: i did not find the local-bottom file ?
And one question: is there a simple way to "write through" the ram layer. ? Just in case I'd like to make some changes to the protected boot disk.
The local-bottom stuff is not necessary, especially if it doesn't exist. For write access to the root filesystem simply revert the changes to /boot/config.txt and /boot/cmdline.txt and then reboot.

Re: Raspbian with Read-only Root

Posted: Wed Jan 04, 2017 10:56 pm
by art_gl
Thanks for the topic, this is exactly what I was looking for!

It is enough to remove boot=overlay from /boot/cmdline.txt to make system writable again.
FYI: this one-liner pretty-prints read/write statistics for memory card since the system was booted up:

Code: Select all

cat /sys/block/mmcblk0/stat | awk '{printf "Uptime read: %.3fMiB (%.1f%% I/Os merged) written: %.3f MiB (%.1f%% I/Os merged)\n", $3*512/1048576, $2/$1*100, $7*512/1048576, $6/$5*100}'

Re: Raspbian with Read-only Root

Posted: Mon Jan 30, 2017 2:36 pm
by spock
how hard would it be to write a bash or python script that makes the necessary changes to all the files? would this be worth trying or do you think that there are many issues that could arise?

Re: Raspbian with Read-only Root

Posted: Mon Jan 30, 2017 4:23 pm
by ejolson
spock wrote:how hard would it be to write a bash or python script that makes the necessary changes to all the files? would this be worth trying or do you think that there are many issues that could arise?
I suspect it would be pretty easy to automate. The difficulty of automating simple tasks with scripts is that the system as a whole becomes more complicated and difficult for the average person (who didn't write the script) to understand.

The Debian Live project consists of a set of scripts to build read-only root filesystems for live DVDs. In my opinion, after having used them, these scripts are too complicated to be helpful. For example, those scripts insist on building an entirely new OS image in a chroot environment, which can take an hour or more. Although Raspbian is also a Debian system, my post shows that accomplishing the same thing for the Pi can be done in a few minutes entirely by hand.

If you would like to create a Python script to automate the steps described in my original post, then by all means do so. It would be great if you included comments in the script explaining why each step is done and how things are supposed to work. It might be reasonable to cite this thread for further reference. A separate document describing how to use the script and the theory behind its operation would also be nice.

Thanks for the comments. If you write a script, I would be happy if you posted it here or a link to it.

Re: Raspbian with Read-only Root

Posted: Tue Jan 31, 2017 1:32 pm
by spock
i am going to give it a try but don't know yet when i will find the time. :)
i will try to keep the script as simple as possible.

Re: Raspbian with Read-only Root

Posted: Thu Feb 02, 2017 5:52 pm
by spock
here is the first version of my script. it seems to work but didn't have time to test it thorougly yet.

use at your own risk! :)

i would be happy about any suggestions for improvements. would there be a better way to patch the files? it's the first time i tried to do something like that. the script also needs more error checking at some places...

Code: Select all

    #!/usr/bin/env python3
    """ror.py - Read-Only Root

    This script automates the steps described by ejolson in this thread:
    https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=161416

    Usage:
        sudo ./ror.py create
            Initializes and enables read-only root file system.
        sudo ./ror.py disable
            Disables read-only root file system.
        sudo ./ror.py enable
            Enables read-only root file system.
        sudo ./ror.py destroy
            Cleans up all changes made by the script (read-only root must be disabled!).
    """



    import sys
    import os
    import shutil
    import subprocess



    def edit(filename, old, new):
        with open(filename, "r") as f: data = f.read()
        for i in zip(old, new):
            data = data.replace(i[0], i[1])
        with open(filename, "w") as f: f.write(data)
    def append(filename, s):
        with open(filename, "a") as f: f.write(s)
    def prepend(filename, s):
        with open(filename, "r") as f: data = f.read()
        with open(filename, "w") as f: f.write(s + data)



    def create():
       
        print("setting up read only root...")
       
        shutil.copyfile("/usr/share/initramfs-tools/hook-functions", "/usr/share/initramfs-tools/hook-functions._ror_backup_")
        shutil.copyfile("/boot/config.txt", "/boot/config.txt._ror_backup_")
        shutil.copyfile("/boot/cmdline.txt", "/boot/cmdline.txt._ror_backup_")
        print("backup created!")
       
        old = ['modules="$modules ehci-pci ehci-orion ehci-hcd ohci-hcd ohci-pci uhci-hcd usbhid"']
        new = ['modules="$modules ehci-pci ehci-orion ehci-hcd ohci-hcd ohci-pci uhci-hcd usbhid overlay"']
        edit("/usr/share/initramfs-tools/hook-functions", old, new)
        print("hook-functions edited!")
       
        shutil.copyfile("/usr/share/initramfs-tools/scripts/local", "/usr/share/initramfs-tools/scripts/overlay")
        shutil.copytree("/usr/share/initramfs-tools/scripts/local-premount", "/usr/share/initramfs-tools/scripts/overlay-premount")
        shutil.copytree("/usr/share/initramfs-tools/scripts/local-bottom", "/usr/share/initramfs-tools/scripts/overlay-bottom")
        print("overlay created!")
       
        old = [
            'ROOT=$(resolve_device "$ROOT")\n\n\tif [ "${readonly}" = "y" ]; then\n\t\troflag=-r\n\telse\n\t\troflag=-w\n\tfi',
            '# Mount root\n\tif [ "${FSTYPE}" != "unknown" ]; then\n\t\tmount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt}\n\telse\n\t\tmount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt}\n\tfi'
            ]
        new = [
            'ROOT=$(resolve_device "$ROOT")\n\n\t#if [ "${readonly}" = "y" ]; then\n\t\troflag=-r\n\t#else\n\t#\troflag=-w\n\t#fi',
            '# Mount root\n\tmkdir /upper /lower\n\tif [ "${FSTYPE}" != "unknown" ]; then\n\t\tmount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} /lower\n\telse\n\t\tmount ${roflag} ${ROOTFLAGS} ${ROOT} /lower\n\tfi\n\tmodprobe overlay\n\tmount -t tmpfs tmpfs /upper\n\tmkdir /upper/data /upper/work\n\tmount -t overlay -olowerdir=/lower,upperdir=/upper/data,workdir=/upper/work overlay ${rootmnt}'
            ]
        edit("/usr/share/initramfs-tools/scripts/overlay", old, new)
        print("overlay edited!")
       
        # todo: support BCM27835!
       
        release = os.uname().release
        subprocess.call(["update-initramfs", "-c", "-k", release])
        shutil.move("/boot/initrd.img-" + release, "/boot/initrd7.img")
        print("initramfs created!")
       
        append("/boot/config.txt", "\n\n\nkernel=kernel7.img\ninitramfs initrd7.img\n")
        print("config.txt edited!")
       
        prepend("/boot/cmdline.txt", "boot=overlay ")
        print("cmdline.txt edited!")
       
        print("done! please reboot!")



    def disable():
        shutil.move("/boot/config.txt._ror_backup_", "/boot/config.txt")
        shutil.move("/boot/cmdline.txt._ror_backup_", "/boot/cmdline.txt")
        print("root will be writeable after the next reboot!")



    def enable():
        if os.path.exists("/boot/config.txt._ror_backup_") and os.path.exists("/boot/cmdline.txt._ror_backup_"):
            print("already enabled!")
            return
        shutil.copyfile("/boot/config.txt", "/boot/config.txt._ror_backup_")
        shutil.copyfile("/boot/cmdline.txt", "/boot/cmdline.txt._ror_backup_")
        append("/boot/config.txt", "\n\n\nkernel=kernel7.img\ninitramfs initrd7.img\n")
        prepend("/boot/cmdline.txt", "boot=overlay ")
        print("root will be read-only after the next reboot!")



    def destroy():
       
        print("cleaning up...")
       
        shutil.move("/usr/share/initramfs-tools/hook-functions._ror_backup_", "/usr/share/initramfs-tools/hook-functions")
       
        os.remove("/usr/share/initramfs-tools/scripts/overlay")
        shutil.rmtree("/usr/share/initramfs-tools/scripts/overlay-premount")
        shutil.rmtree("/usr/share/initramfs-tools/scripts/overlay-bottom")
       
        os.remove("/boot/initrd7.img")

        print("done!")



    if __name__ == "__main__":
       
        if sys.argv[1] == "enable": enable()
        elif sys.argv[1] == "disable": disable()
        elif sys.argv[1] == "destroy": destroy()
        elif sys.argv[1] == "create": create()

Re: Raspbian with Read-only Root

Posted: Thu Feb 02, 2017 6:16 pm
by epoch1970
Just in case.
I've spotted a recent post that solves the same problem via an init script. viewtopic.php?f=66&t=173063
Haven't tried it.

Re: Raspbian with Read-only Root

Posted: Thu Feb 02, 2017 6:22 pm
by ejolson
spock wrote:here is the first version of my script.
I like it. Thanks for spending the time working on this.

The comments, usage and code seem straightforward. It would nice to include a "help" feature that would explain the usage if an unrecognized command is entered. You might want to check /etc/apt/sources.list to make sure the device is running the correct version of Raspbian before patching. I like how you coded your own patching algorithm. The standard Unix commands diff and patch do something similar.

Re: Raspbian with Read-only Root

Posted: Thu Feb 02, 2017 7:11 pm
by spock
@epoch1970:
interesting! thanks for posting the link. has anyone tried it?

@ejolson:
thanks for your feedback! :) next time i find some time working on it i will go through your suggestions.

what do you think about the other script epoch1970 posted?

Re: Raspbian with Read-only Root

Posted: Fri Feb 03, 2017 2:16 am
by ejolson
spock wrote:what do you think about the other script epoch1970 posted?
That script seems based on the same idea: pivot root to an overlayfs. The advantage of the script is simplicity by avoiding the initramfs, and I prefer simplicity. The disadvantage would be not having the educational opportunity to learn how an initramfs works. I suspect either way will protect the sdcard equally well.

Most x86 distributions use an initramfs, so that is why I did things the way I did. In particular, my instructions can readily be modified to work for standard Ubuntu, Mint and Debian. Note that historically, x86 systems used an initramfs because there were so many different kinds of disk drivers that it was impractical to include all of them built into the kernel. As there are fewer kinds of Pi computers, an initramfs is generally not used in Raspbian.

Re: Raspbian with Read-only Root

Posted: Fri Feb 03, 2017 10:55 am
by spock
i roughly understand how this overlayfs idea works but how could i best learn about the details? what is this upper and lower thing for example? :)

how did you learn about all of this? is this your job?

Re: Raspbian with Read-only Root

Posted: Sat Feb 04, 2017 5:40 pm
by ejolson
spock wrote:i roughly understand how this overlayfs idea works but how could i best learn about the details? what is this upper and lower thing for example?
The Linux kernel contains documentation on unionfs. I also ran across some bug discussions in online forums.
spock wrote:how did you learn about all of this? is this your job?
I teach mathematics and how to use computers to solve mathematics problems. I've been interested in computers since childhood. As a teacher, one of the primary things I find important is learning. As a result I've accumulated a bit of computer knowledge over the years.

This appears to be post 1000 for me on the forum. As that was my limit, I will now take a break from the forum for some time. I still owe someone a reply about Bluetooth, so 1000 may turn out to be a soft limit. In closing I would like to thank all the people here for interesting discussion and even making me laugh a few times. All the best.

Re: Raspbian with Read-only Root

Posted: Thu Mar 16, 2017 7:40 pm
by vandiwa
This works great, and I love the simplicity of it compared to another approach I tried where root was mounted read-only. The problem I have is that I need to be able to occassionaly write to the actual root file system changing things like wpa_supplicant.conf. Is there a way to revert to the rw file system that doesn't involve a reboot? If not, I have some workarounds involving temp copying to /boot, changing cmdline.txt and rebooting, then realizing I'm in that situation, copy the files I need to root, change cmdline.txt back again and reboot, but that seems a little convoluted.

*Update - even though it's a little convoluted, I did get it to work by making use of a service that writes a flag file to /boot and then reboots with cmdline.txt modified. The next time it boots, is sees the flag, makes the changes in the rw file system, removes the flag file and reboots again, so there are two boots required to change the config, but it's working.

Re: Raspbian with Read-only Root

Posted: Sun Mar 26, 2017 9:44 pm
by LGarber
ejolson and spock rock! I just spent the last 5 hours playing around with psuter's solution viewtopic.php?f=66&t=173063 because it sounded so slick. But on my NOOBS RPi 3, I couldn't get it to work. Then I went back to spock's script and in 10 minutes I was up and running. Spent half of that time trying to confirm that it indeed worked. THANK YOU!!!
....Larry

Re: Raspbian with Read-only Root

Posted: Mon Mar 27, 2017 5:33 pm
by spock
for me the script doesn't work anymore with the newest raspbian. the directory local-bottom doesn't exist anymore. does anyone know why?

Re: Raspbian with Read-only Root

Posted: Mon Mar 27, 2017 6:29 pm
by kusti8
spock wrote:for me the script doesn't work anymore with the newest raspbian. the directory local-bottom doesn't exist anymore. does anyone know why?
Didn't exist for me also, but it still worked.