firstboot: add support for union mounts
[openwrt.git] / package / base-files / files / sbin / firstboot
1 #!/bin/sh
2 . /etc/functions.sh
3
4 partname="rootfs_data"
5 mtdpart="$(find_mtd_part $partname)"
6
7 rom=$(awk '/squashfs/ {print $2}' /proc/mounts)
8 jffs=$(awk '/jffs2/ {print $2}' /proc/mounts)
9
10 dupe() { # <new_root> <old_root>
11         cd $1
12         echo -n "creating directories... "
13         {
14                 cd $2 
15                 find . -xdev -type d
16                 echo "./dev ./jffs ./mnt ./proc ./tmp"
17                 # xdev skips mounted directories
18                 cd $1 
19         } | xargs mkdir -p
20         echo "done"
21
22         echo -n "setting up symlinks... "
23         for file in $(cd $2; find . -xdev -type f;); do
24                 case "$file" in
25                 ./rom/note) ;; #nothing
26                 ./etc/config*|\
27                 ./usr/lib/opkg/info/*) cp -af $2/$file $file;;
28                 *) ln -sf /rom/${file#./*} $file;;
29                 esac
30         done
31         for file in $(cd $2; find . -xdev -type l;); do
32                 cp -af $2/${file#./*} $file
33         done
34         echo "done"
35 }
36
37 pivot() { # <new_root> <old_root>
38         mount -o move /proc $1/proc && \
39         pivot_root $1 $1$2 && {
40                 mount -o move $2/dev /dev
41                 mount -o move $2/tmp /tmp
42                 mount -o move $2/sys /sys 2>&-
43                 mount -o move $2/jffs /jffs 2>&-
44                 return 0
45         }
46 }
47
48 fopivot() { # <rw_root> <ro_root> <dupe?>
49         root=$1
50         {
51                 if grep -q mini_fo /proc/filesystems; then
52                         mount -t mini_fo -o base=/,sto=$1 "mini_fo:$1" /mnt 2>&- && root=/mnt
53                 else
54                         mount --bind / /mnt
55                         mount --bind -o union "$1" /mnt && root=/mnt 
56                 fi
57         } || {
58                 [ "$3" = "1" ] && {
59                 mount | grep "on $1 type" 2>&- 1>&- || mount -o bind $1 $1
60                 dupe $1 $rom
61                 }
62         }
63         pivot $root $2
64 }
65
66 ramoverlay() {
67         mkdir -p /tmp/root
68         mount -t tmpfs root /tmp/root
69         fopivot /tmp/root /rom 1
70 }
71
72 # invoked as an executable
73 [ "${0##*/}" = "firstboot" ] && {
74
75         [ -z "$mtdpart" ] && {
76                 echo "MTD partition not found."
77                 exit 1
78         }
79
80         [ -z "$rom" ] && {
81                 echo "You do not have a squashfs partition; aborting"
82                 echo "(firstboot cannot be run on jffs2 based firmwares)"
83                 exit 1
84         }
85
86         [ "$1" = "switch2jffs" ] && {
87                 if grep -q mini_fo /proc/filesystems; then
88                         mount "$mtdpart" /rom/jffs -t jffs2 || exit
89
90                         # try to avoid fs changing while copying
91                         mount -o remount,ro none / 2>&-
92
93                         # copy ramoverlay to jffs2
94                         echo -n "copying files ... "
95                         cp -a /tmp/root/* /rom/jffs 2>&-
96                         echo "done"
97
98                         # switch back to squashfs (temporarily)
99                         # and park the ramdisk ontop of /tmp/root
100                         pivot /rom /mnt
101                         mount -o move /mnt /tmp/root
102
103                         # /jffs is the overlay
104                         # /rom is the readonly
105                         fopivot /jffs /rom
106
107                         # try to get rid of /tmp/root
108                         # this will almost always fail
109                         umount /tmp/root 2>&-
110                 else
111                         # switch back to squashfs temporarily
112                         pivot /rom /mnt
113
114                         # get rid of the old overlay
115                         umount -l /mnt
116
117                         # another umount to get rid of the bind from /tmp/root
118                         umount -l /mnt
119
120                         # initialize jffs2
121                         mount "$mtdpart" /jffs -t jffs2 || exit
122
123                         # workaround to ensure that union can attach properly
124                         sync
125                         ls /jffs >/dev/null
126
127                         # switch to the new (empty) jffs2
128                         fopivot /jffs /rom 1
129
130                         # copy ramoverlay to jffs2, must be done after switching
131                         # to the new rootfs to avoid creating opaque directories
132                         echo -n "copying files ... "
133                         cp -a /tmp/root/* / >/dev/null 2>&1
134                         sync
135                         echo "done"
136
137                         umount -l /jffs
138                         umount -l /tmp/root
139                 fi
140
141                 exit 0
142         }
143
144         # script run manually
145         [ \! -z "$jffs" ] && {
146                 echo "firstboot has already been run"
147                 echo "jffs2 partition is mounted, only resetting files"
148                 grep mini_fo /proc/filesystems >&-
149                 [ $? != 0 ] && {
150                         dupe $jffs $rom
151                         exit 0
152                 } || { 
153                         rm -rf $jffs/* 2>&-
154                         mount -o remount $jffs / 2>&-
155                         exit 0
156                 }
157         }
158
159         mtd erase "$partname"
160         mount "$mtdpart" /jffs -t jffs2
161         fopivot /jffs /rom 1
162 }