How to add custom script to RPi0w image

<p>Hi Folks,
</p>
<p>I have a small custom script which I would like to add to default RPi0w image. In the past I've mounted the second partition from .img file on loopback and did my changes. However since today the file system seams to be changed from ext4 to squashfs and the same procedure does not work. I would appreciate any suggestion on how to mount/modify the image content.
</p>
<p>Here is the script I was using in the past to mount the second file system:
</p>
<p>part_id=2; INFILE=cloudhub-brcm2708-bcm2708-rpi-ext4-sdcard.img; MOUNTPT=mount_dir PARTITION=${part_id}; sudo mount "$INFILE" -o loop,offset=$[ `/sbin/sfdisk -d "$INFILE" | grep "start=" | head -n $PARTITION | tail -n1 | sed 's/.*start=[ ]*//' | sed 's/,.*//'` * 512 ] "$MOUNTPT"
</p>
<p>It boils down to the following command:<br />
$ sudo mount cloudhub-brcm2708-bcm2708-rpi-ext4-sdcard.img -o loop,offset=29360128 mount_dir/
</p>
<p>Now, if I run:<br />
$ sudo mount cloudhub-brcm2708-bcm2708-rpi-squashfs-factory.img mount_dir/ -t squashfs -o loop,offset=29360128
</p>
<p>I am getting the following error:
</p>
<p>mount: wrong fs type, bad option, bad superblock on /dev/loop1,<br />
missing codepage or helper program, or other error
</p>
<p> In some cases useful info is found in syslog - try<br />
dmesg | tail or so.
</p>
<p>I was also trying kpartx without success:
</p>
<p>$ sudo kpartx -a cloudhub-brcm2708-bcm2708-rpi-squashfs-factory.img<br />
device-mapper: resume ioctl on loop1p2 failed: Invalid argument<br />
create/reload failed on loop1p2
</p>
<p>My system is:<br />
$ lsb_release -a<br />
No LSB modules are available.<br />
Distributor ID: Ubuntu<br />
Description: Ubuntu 16.04.5 LTS<br />
Release: 16.04<br />
Codename: xenial
</p>
<p>$ uname -a<br />
Linux ubuntu1604 4.4.0-131-generic #157-Ubuntu SMP Thu Jul 12 15:51:36 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
</p>
<p>Thank you,<br />
Andrey.
</p>

#2

<p>I found the way to add a custom script to the distributed image. However, I am pretty sure that this is not a clean way to do it. Nevertheless, here is the detailed description of what I have made. The hope is that someone who understands it better then I will provide comments and corrections.
</p>
<p>1. My goal was to add custom script to /etc/init.d and make sure that it will not be deleted after factory reset.
</p>
<p>2. I've made the assumption, that I need to modify squashfs inside .img file to achieve this goal.
</p>
<p>3. Where is the squashfs in the image? Use sfdisk and binwalk to find it.
</p>
<p>$ /sbin/sfdisk -d cloudhub-brcm2708-bcm2708-rpi-squashfs-factory.img<br />
label: dos<br />
label-id: 0x5452574f<br />
device: cloudhub-brcm2708-bcm2708-rpi-squashfs-factory.img<br />
unit: sectors
</p>
<p>cloudhub-brcm2708-bcm2708-rpi-squashfs-factory.img1 : start= 8192, size= 40960, type=c, bootable<br />
cloudhub-brcm2708-bcm2708-rpi-squashfs-factory.img2 : start= 57344, size= 524288, type=83
</p>
<p>$ binwalk cloudhub-brcm2708-bcm2708-rpi-squashfs-factory.img | grep -i squash<br />
29360128 0x1C00000 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 2706070 bytes, 553 inodes, blocksize: 262144 bytes, created: 2018-08-06 20:48:42
</p>
<p>So both tools reported the same byte offset 29360128 (=57344 * 512) . Here my first idea was to simply mount it using mount command with offset option. But as mentioned in my original post, it does not work.
</p>
<p>4. Extract everything from offset 29360128 in separate file and try to unsquashfs it.
</p>
<p>$ dd if=cloudhub-brcm2708-bcm2708-rpi-squashfs-factory.img of=root.squash skip=57344
</p>
<p>57344 because dd skips not bytes but ibs-sized blocks and default ibs size is 512. So now we have root.squash file.
</p>
<p>Cut out the head part of the image. It will be merged with modified squashfs part later<br />
$ dd if=cloudhub-brcm2708-bcm2708-rpi-squashfs-factory.img of=part1.bin bs=29360128 count=1
</p>
<p>$ sudo unsquashfs -d ttt/ root.squash<br />
Parallel unsquashfs: Using 8 processors<br />
489 inodes (496 blocks) to write
</p>
<p>[===============================|] 496/496 100%
</p>
<p>created 299 files<br />
created 64 directories<br />
created 189 symlinks<br />
created 1 devices<br />
created 0 fifos
</p>
<p>It extracts content of squashfs to ttt directory
</p>
<p>5. Make desired customizations. In my case I've add the script file and modified /etc/rc.local to execute it on startup.
</p>
<p>6. Squash modified directory.
</p>
<p>$ sudo mksquashfs ttt root2.squash -comp xz<br />
Parallel mksquashfs: Using 8 processors<br />
Creating 4.0 filesystem on root2.squash, block size 131072.<br />
[=================================================/] 322/322 100%
</p>
<p>Exportable Squashfs 4.0 filesystem, xz compressed, data block size 131072<br />
compressed data, compressed metadata, compressed fragments, compressed xattrs<br />
duplicates are removed<br />
Filesystem size 2733.29 Kbytes (2.67 Mbytes)<br />
44.35% of uncompressed filesystem size (6162.56 Kbytes)<br />
Inode table size 4178 bytes (4.08 Kbytes)<br />
22.15% of uncompressed inode table size (18859 bytes)<br />
Directory table size 5404 bytes (5.28 Kbytes)<br />
53.28% of uncompressed directory table size (10142 bytes)<br />
Number of duplicate files found 1<br />
Number of inodes 554<br />
Number of files 300<br />
Number of fragments 24<br />
Number of symbolic links 189<br />
Number of device nodes 1<br />
Number of fifo nodes 0<br />
Number of socket nodes 0<br />
Number of directories 64<br />
Number of ids (unique uids + gids) 1<br />
Number of uids 1<br />
root (0)<br />
Number of gids 1<br />
root (0)
</p>
<p>Now there is root2.squash with customizations inside
</p>
<p>7. Now we have part1.bin and root2.squash files which need to be merged together to produce new flashable image
</p>
<p>$ cat part1.bin root2.squash > newimage.img
</p>
<p>That's it.
</p>
<p>I did not performed extensive testing yet, but first impression - it works. However, somehow I am pretty sure that there are bunch of options (for example for mksquashfs) which I am missing. Or maybe the whole approach is wrong. Any feedback is highly appreciated.
</p>
<p>Best regards,<br />
Andrey.</p>

#3

Yes i switched to squashfs so that "firstboot" can be run to reset all settings back to their defaults. Previuosly this was not possible on ext4. If you bring pin 40 high for 2 seconds (i.e connect pin 1 to pin40 for 2 seconds) then firstboot will run and the device will reset. Some customers needed a way to reset the settings without reflashing.

Also i now included the opkg utility in all cloudhub builds. So ideally you would create an ipk file with your changes then just run opkg on the cloudhub via ssh and it would install. Thats how its meant to work.

#4

<p>I am completely understand your motivation for switching to squashfs. Actually, I am one of these customers who were asking for factory reset ;-) . Your suggestion to use opkg will definitely work but is not very practical if many devices should be manufactured. It is way more easy to include required customization in the image and avoid additional installation step. Also, it is not quite clear for me what will happens after factory reset. I assume that installed packages will gone and we can not ask our customers to log in with ssh and run opkg to complete recovering. Most of our users are far away from IT staff :-) .
</p>
<p>Do you have any comments regarding image modification process described above? My concern is that something is not quite correct, i.e. some kind of jffs alignments, missing required mksquashfs flags or whatever else I am missing which can cause unstable behavior later by customers. That is why i would really appreciate your thoughts about presented approach.</p>

#5

Unfortunatly my squashfs knowledge is limited. So im not sure...