block: support extroot and overlay mounts by device
[project/ubox.git] / mount_root.c
1 /*
2  * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
3  * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License version 2.1
7  * as published by the Free Software Foundation
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <getopt.h>
18 #include <syslog.h>
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <libgen.h>
24 #include <glob.h>
25 #include <dirent.h>
26
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/mount.h>
30 #include <sys/wait.h>
31
32 #include <asm/byteorder.h>
33
34 #include <mtd/mtd-user.h>
35
36 #define DEBUG(level, fmt, ...) do { \
37         if (debug >= level) \
38                 fprintf(stderr, "%s %s(%d): " fmt, argv0, __func__, __LINE__, ## __VA_ARGS__); \
39         } while (0)
40
41 #define LOG(fmt, ...) do { \
42                 syslog(LOG_INFO, fmt, ## __VA_ARGS__); \
43                 fprintf(stderr, "%s: "fmt, argv0, ## __VA_ARGS__); \
44         } while (0)
45
46 #define ERROR(fmt, ...) do { \
47                 syslog(LOG_ERR, fmt, ## __VA_ARGS__); \
48                 fprintf(stderr, "%s: "fmt, argv0, ## __VA_ARGS__); \
49         } while (0)
50
51 enum {
52         FS_NONE,
53         FS_JFFS2,
54         FS_DEADCODE,
55 };
56
57 static const char *argv0;
58
59 /* this is a raw syscall - man 2 pivot_root */
60 extern int pivot_root(const char *new_root, const char *put_old);
61
62 static int debug = 0;
63
64 static void foreachdir(const char *dir, int (*cb)(const char*))
65 {
66         char globdir[256];
67         glob_t gl;
68         int j;
69
70         if (dir[strlen(dir) - 1] == '/')
71                 snprintf(globdir, 256, "%s*", dir);
72         else
73                 snprintf(globdir, 256, "%s/*", dir);
74
75         if (!glob(globdir, GLOB_NOESCAPE | GLOB_MARK | GLOB_ONLYDIR, NULL, &gl))
76                 for (j = 0; j < gl.gl_pathc; j++)
77                         foreachdir(gl.gl_pathv[j], cb);
78
79         cb(dir);
80 }
81
82 static int find_overlay_mount(char *overlay)
83 {
84         FILE *fp = fopen("/proc/mounts", "r");
85         static char line[256];
86         int ret = -1;
87
88         if(!fp)
89                 return ret;
90
91         while (ret && fgets(line, sizeof(line), fp))
92                 if (!strncmp(line, overlay, strlen(overlay)))
93                         ret = 0;
94
95         fclose(fp);
96
97         return ret;
98 }
99
100 static char* find_mount(char *mp)
101 {
102         FILE *fp = fopen("/proc/mounts", "r");
103         static char line[256];
104         char *point = NULL;
105
106         if(!fp)
107                 return NULL;
108
109         while (fgets(line, sizeof(line), fp)) {
110                 char *s, *t = strstr(line, " ");
111
112                 if (!t) {
113                         fclose(fp);
114                         return NULL;
115                 }
116                 t++;
117                 s = strstr(t, " ");
118                 if (!s) {
119                         fclose(fp);
120                         return NULL;
121                 }
122                 *s = '\0';
123
124                 if (!strcmp(t, mp)) {
125                         fclose(fp);
126                         return t;
127                 }
128         }
129
130         fclose(fp);
131
132         return point;
133 }
134
135 static char* find_mount_point(char *block, char *fs)
136 {
137         FILE *fp = fopen("/proc/mounts", "r");
138         static char line[256];
139         int len = strlen(block);
140         char *point = NULL;
141
142         if(!fp)
143                 return NULL;
144
145         while (fgets(line, sizeof(line), fp)) {
146                 if (!strncmp(line, block, len)) {
147                         char *p = &line[len + 1];
148                         char *t = strstr(p, " ");
149
150                         if (!t) {
151                                 fclose(fp);
152                                 return NULL;
153                         }
154
155                         *t = '\0';
156                         t++;
157
158                         if (fs && strncmp(t, fs, strlen(fs))) {
159                                 fclose(fp);
160                                 ERROR("block is mounted with wrong fs\n");
161                                 return NULL;
162                         }
163                         point = p;
164                         break;
165                 }
166         }
167
168         fclose(fp);
169
170         return point;
171 }
172
173 static char* find_mtd_index(char *name)
174 {
175         FILE *fp = fopen("/proc/mtd", "r");
176         static char line[256];
177         char *index = NULL;
178
179         if(!fp)
180                 return index;
181
182         while (!index && fgets(line, sizeof(line), fp)) {
183                 if (strstr(line, name)) {
184                         char *eol = strstr(line, ":");
185
186                         if (!eol)
187                                 continue;
188
189                         *eol = '\0';
190                         index = &line[3];
191                         DEBUG(1, "found %s -> index:%s\n", name, index);
192                 }
193         }
194
195         fclose(fp);
196
197         return index;
198 }
199
200 static int find_mtd_block(char *name, char *part, int plen)
201 {
202         char *index = find_mtd_index(name);
203
204         if (!index)
205                 return -1;
206
207         snprintf(part, plen, "/dev/mtdblock%s", index);
208         DEBUG(1, "found %s -> %s\n", name, part);
209
210         return 0;
211 }
212
213 static int find_mtd_char(char *name, char *part, int plen)
214 {
215         char *index = find_mtd_index(name);
216
217         if (!index)
218                 return -1;
219
220         snprintf(part, plen, "/dev/mtd%s", index);
221         DEBUG(1, "found %s -> %s\n", name, part);
222
223         return 0;
224 }
225
226 static int mtd_unlock(char *mtd)
227 {
228         struct erase_info_user mtdlock;
229         struct mtd_info_user mtdinfo;
230         int fd = open(mtd, O_RDWR | O_SYNC);
231         int ret = -1;
232
233         DEBUG(1, "%s\n", mtd);
234
235         if (!fd) {
236                 ERROR("failed to open %s: %s\n", mtd, strerror(errno));
237                 return -1;
238         }
239
240         ret = ioctl(fd, MEMGETINFO, &mtdinfo);
241         if (ret) {
242                 ERROR("ioctl(%s, MEMGETINFO) failed: %s\n", mtd, strerror(errno));
243                 goto err_out;
244         }
245
246         mtdlock.start = 0;
247         mtdlock.length = mtdinfo.size;
248         ioctl(fd, MEMUNLOCK, &mtdlock);
249
250 err_out:
251         close(fd);
252
253         return ret;
254 }
255
256 static int mtd_mount_jffs2(void)
257 {
258         char rootfs_data[32];
259
260         if (mkdir("/tmp/overlay", 0755)) {
261                 ERROR("failed to mkdir /tmp/overlay: %s\n", strerror(errno));
262                 return -1;
263         }
264
265         if (find_mtd_block("rootfs_data", rootfs_data, sizeof(rootfs_data))) {
266                 ERROR("rootfs_data does not exist\n");
267                 return -1;
268         }
269
270         if (mount(rootfs_data, "/tmp/overlay", "jffs2", MS_NOATIME, NULL)) {
271                 ERROR("failed to mount -t jffs2 %s /tmp/overlay: %s\n", rootfs_data, strerror(errno));
272                 return -1;
273         }
274
275         find_mtd_char("rootfs_data", rootfs_data, sizeof(rootfs_data));
276
277         return mtd_unlock(rootfs_data);
278 }
279
280 static int jffs2_ready(char *mtd)
281 {
282         FILE *fp = fopen(mtd, "r");
283         __u32 deadc0de;
284         __u16 jffs2;
285         size_t sz;
286
287         if (!fp) {
288                 ERROR("reading %s failed\n", mtd);
289                 exit(-1);
290         }
291
292         sz = fread(&deadc0de, sizeof(deadc0de), 1, fp);
293         fclose(fp);
294
295         if (sz != 1) {
296                 ERROR("reading %s failed: %s\n", mtd, strerror(errno));
297                 exit(-1);
298         }
299
300         deadc0de = __be32_to_cpu(deadc0de);
301         jffs2 = __be16_to_cpu(deadc0de >> 16);
302
303         if (jffs2 == 0x1985) {
304                 LOG("jffs2 is ready\n");
305                 return FS_JFFS2;
306         }
307
308         if (deadc0de == 0xdeadc0de) {
309                 LOG("jffs2 is not ready - marker found\n");
310                 return FS_DEADCODE;
311         }
312
313         ERROR("No jffs2 marker was found\n");
314
315         return FS_NONE;
316 }
317
318 static int check_fs_exists(char *fs)
319 {
320         FILE *fp = fopen("/proc/filesystems", "r");
321         static char line[256];
322         int ret = -1;
323
324         DEBUG(2, "%s\n", fs);
325
326         if (!fp) {
327                 ERROR("opening /proc/filesystems failed: %s\n", strerror(errno));
328                 goto out;
329         }
330
331         while (ret && fgets(line, sizeof(line), fp))
332                 if (strstr(line, fs))
333                         ret = 0;
334
335         fclose(fp);
336
337 out:
338         return ret;
339 }
340
341 static int mount_move(char *oldroot, char *newroot, char *dir)
342 {
343 #ifndef MS_MOVE
344 #define MS_MOVE (1 << 13)
345 #endif
346         struct stat s;
347         char olddir[64];
348         char newdir[64];
349         int ret;
350
351         DEBUG(2, "%s %s %s\n", oldroot, newroot, dir);
352
353         snprintf(olddir, sizeof(olddir), "%s%s", oldroot, dir);
354         snprintf(newdir, sizeof(newdir), "%s%s", newroot, dir);
355
356         if (stat(olddir, &s) || !S_ISDIR(s.st_mode))
357                 return -1;
358
359         if (stat(newdir, &s) || !S_ISDIR(s.st_mode))
360                 return -1;
361
362         ret = mount(olddir, newdir, NULL, MS_NOATIME | MS_MOVE, NULL);
363
364         if (ret)
365                 DEBUG(1, "failed %s %s: %s\n", olddir, newdir, strerror(errno));
366
367         return ret;
368 }
369
370 static int pivot(char *new, char *old)
371 {
372         char pivotdir[64];
373         int ret;
374
375         DEBUG(2, "%s %s\n", new, old);
376
377         if (mount_move("", new, "/proc"))
378                 return -1;
379
380         snprintf(pivotdir, sizeof(pivotdir), "%s%s", new, old);
381
382         ret = pivot_root(new, pivotdir);
383
384         if (ret < 0) {
385                 ERROR("pivot_root failed %s %s: %s\n", new, pivotdir, strerror(errno));
386                 return -1;
387         }
388
389         mount_move(old, "", "/dev");
390         mount_move(old, "", "/tmp");
391         mount_move(old, "", "/sys");
392         mount_move(old, "", "/overlay");
393
394         return 0;
395 }
396
397 static int fopivot(char *rw_root, char *ro_root)
398 {
399         char overlay[64], lowerdir[64];
400
401         DEBUG(2, "%s %s\n", rw_root, ro_root);
402
403         if (check_fs_exists("overlay")) {
404                 ERROR("BUG: no suitable fs found\n");
405                 return -1;
406         }
407
408         snprintf(overlay, sizeof(overlay), "overlayfs:%s", rw_root);
409         snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s", rw_root);
410
411         if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, lowerdir)) {
412                 ERROR("mount failed: %s\n", strerror(errno));
413                 return -1;
414         }
415
416         return pivot("/mnt", ro_root);
417 }
418
419 static int ramoverlay(void)
420 {
421         DEBUG(2, "\n");
422
423         mkdir("/tmp/root", 0755);
424         mount("tmpfs", "/tmp/root", "tmpfs", MS_NOATIME, "mode=0755");
425
426         return fopivot("/tmp/root", "/rom");
427 }
428
429 static int switch2jffs(void)
430 {
431         char mtd[32];
432
433         if (!find_mtd_block("rootfs_patches", mtd, sizeof(mtd)))
434                 return 0;
435
436         if (find_mtd_block("rootfs_data", mtd, sizeof(mtd))) {
437                 ERROR("no rootfs_data was found\n");
438                 return -1;
439         }
440
441         if (mount(mtd, "/rom/overlay", "jffs2", MS_NOATIME, NULL)) {
442                 ERROR("failed - mount -t jffs2 %s /rom/overlay: %s\n", mtd, strerror(errno));
443                 return -1;
444         }
445
446         if (mount("none", "/", NULL, MS_NOATIME | MS_REMOUNT, 0)) {
447                 ERROR("failed - mount -o remount,ro none: %s\n", strerror(errno));
448                 return -1;
449         }
450
451         system("cp -a /tmp/root/* /rom/overlay");
452
453         if (pivot("/rom", "/mnt")) {
454                 ERROR("failed - pivot /rom /mnt: %s\n", strerror(errno));
455                 return -1;
456         }
457
458         if (mount_move("/mnt", "/tmp/root", "")) {
459                 ERROR("failed - mount -o move /mnt /tmp/root %s\n", strerror(errno));
460                 return -1;
461         }
462
463         return fopivot("/overlay", "/rom");
464 }
465
466 static int handle_whiteout(const char *dir)
467 {
468         struct stat s;
469         char link[256];
470         ssize_t sz;
471         struct dirent **namelist;
472         int n;
473
474         n = scandir(dir, &namelist, NULL, NULL);
475
476         if (n < 1)
477                 return -1;
478
479         while (n--) {
480                 char file[256];
481
482                 snprintf(file, sizeof(file), "%s%s", dir, namelist[n]->d_name);
483                 if (!lstat(file, &s) && S_ISLNK(s.st_mode)) {
484                         sz = readlink(file, link, sizeof(link) - 1);
485                         if (sz > 0) {
486                                 char *orig;
487
488                                 link[sz] = '\0';
489                                 orig = strstr(&file[1], "/");
490                                 if (orig && !strcmp(link, "(overlay-whiteout)")) {
491                                         DEBUG(1, "unlinking %s\n", orig);
492                                         unlink(orig);
493                                 }
494                         }
495                 }
496                 free(namelist[n]);
497         }
498         free(namelist);
499
500         return 0;
501 }
502
503 static int mtd_erase(const char *mtd)
504 {
505         int fd = open(mtd, O_RDWR | O_SYNC);
506         struct mtd_info_user i;
507         struct erase_info_user e;
508         int ret;
509
510         if (!fd) {
511                 ERROR("failed to open %s: %s\n", mtd, strerror(errno));
512                 return -1;
513         }
514
515         ret = ioctl(fd, MEMGETINFO, &i);
516         if (ret) {
517                 ERROR("ioctl(%s, MEMGETINFO) failed: %s\n", mtd, strerror(errno));
518                 return -1;
519         }
520
521         e.length = i.erasesize;
522         for (e.start = 0; e.start < i.size; e.start += i.erasesize) {
523                 ioctl(fd, MEMUNLOCK, &e);
524                 if(ioctl(fd, MEMERASE, &e))
525                         ERROR("Failed to erase block on %s at 0x%x\n", mtd, e.start);
526         }
527
528         close(fd);
529         return 0;
530 }
531
532 static int ask_user(int argc, char **argv)
533 {
534         if ((argc < 2) || strcmp(argv[1], "-y")) {
535                 LOG("This will erase all settings and remove any installed packages. Are you sure? [N/y]\n");
536                 if (getchar() != 'y')
537                         return -1;
538         }
539         return 0;
540
541 }
542
543 static int handle_rmdir(const char *dir)
544 {
545         struct stat s;
546         struct dirent **namelist;
547         int n;
548
549         n = scandir(dir, &namelist, NULL, NULL);
550
551         if (n < 1)
552                 return -1;
553
554         while (n--) {
555                 char file[256];
556
557                 snprintf(file, sizeof(file), "%s%s", dir, namelist[n]->d_name);
558                 if (!lstat(file, &s) && !S_ISDIR(s.st_mode)) {
559                         DEBUG(1, "unlinking %s\n", file);
560                         unlink(file);
561                 }
562                 free(namelist[n]);
563         }
564         free(namelist);
565
566         DEBUG(1, "rmdir %s\n", dir);
567         rmdir(dir);
568
569         return 0;
570 }
571
572 static int main_jffs2reset(int argc, char **argv)
573 {
574         char mtd[32];
575         char *mp;
576
577         if (ask_user(argc, argv))
578                 return -1;
579
580         if (check_fs_exists("overlay")) {
581                 ERROR("overlayfs not found\n");
582                 return -1;
583         }
584
585         if (find_mtd_block("rootfs_data", mtd, sizeof(mtd))) {
586                 ERROR("no rootfs_data was found\n");
587                 return -1;
588         }
589
590         mp = find_mount_point(mtd, "jffs2");
591         if (mp) {
592                 LOG("%s is mounted as %s, only erasing files\n", mtd, mp);
593                 foreachdir(mp, handle_rmdir);
594                 mount(mp, "/", NULL, MS_REMOUNT, 0);
595         } else {
596                 LOG("%s is not mounted, erasing it\n", mtd);
597                 find_mtd_char("rootfs_data", mtd, sizeof(mtd));
598                 mtd_erase(mtd);
599         }
600
601         return 0;
602 }
603
604 static int main_jffs2mark(int argc, char **argv)
605 {
606         FILE *fp;
607         __u32 deadc0de = __cpu_to_be32(0xdeadc0de);
608         char mtd[32];
609         size_t sz;
610
611         if (ask_user(argc, argv))
612                 return -1;
613
614         if (find_mtd_block("rootfs_data", mtd, sizeof(mtd))) {
615                 ERROR("no rootfs_data was found\n");
616                 return -1;
617         }
618
619         fp = fopen(mtd, "w");
620         LOG("%s - marking with deadc0de\n", mtd);
621         if (!fp) {
622                 ERROR("opening %s failed\n", mtd);
623                 return -1;
624         }
625
626         sz = fwrite(&deadc0de, sizeof(deadc0de), 1, fp);
627         fclose(fp);
628
629         if (sz != 1) {
630                 ERROR("writing %s failed: %s\n", mtd, strerror(errno));
631                 return -1;
632         }
633
634         return 0;
635  }
636 static int main_switch2jffs(int argc, char **argv)
637 {
638         char mtd[32];
639         char *mp;
640         int ret = -1;
641
642         if (find_overlay_mount("overlayfs:/tmp/root"))
643                 return -1;
644
645         if (check_fs_exists("overlay")) {
646                 ERROR("overlayfs not found\n");
647                 return ret;
648         }
649
650         find_mtd_block("rootfs_data", mtd, sizeof(mtd));
651         mp = find_mount_point(mtd, NULL);
652         if (mp) {
653                 LOG("rootfs_data:%s is already mounted as %s\n", mtd, mp);
654                 return -1;
655         }
656
657         if (find_mtd_char("rootfs_data", mtd, sizeof(mtd))) {
658                 ERROR("no rootfs_data was found\n");
659                 return ret;
660         }
661
662         switch (jffs2_ready(mtd)) {
663         case FS_NONE:
664                 ERROR("no jffs2 marker found\n");
665                 /* fall through */
666
667         case FS_DEADCODE:
668                 ret = switch2jffs();
669                 if (!ret) {
670                         DEBUG(1, "doing fo cleanup\n");
671                         umount2("/tmp/root", MNT_DETACH);
672                         foreachdir("/overlay/", handle_whiteout);
673                 }
674                 break;
675
676         case FS_JFFS2:
677                 ret = mtd_mount_jffs2();
678                 if (ret)
679                         break;
680                 if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) {
681                         ERROR("switching to jffs2 failed\n");
682                         ret = -1;
683                 }
684                 break;
685         }
686
687         return ret;
688 }
689
690 static int extroot(const char *prefix)
691 {
692         char block_path[32];
693         char kmod_loader[64];
694         struct stat s;
695         pid_t pid;
696
697         sprintf(block_path, "%s/sbin/block", prefix);
698
699         if (stat(block_path, &s))
700                 return -1;
701
702         sprintf(kmod_loader, "/sbin/kmodloader %s/etc/modules-boot.d/ %s", prefix, prefix);
703         system(kmod_loader);
704
705         pid = fork();
706         if (!pid) {
707                 mkdir("/tmp/extroot", 0755);
708                 execl(block_path, block_path, "extroot", NULL);
709                 exit(-1);
710         } else if (pid > 0) {
711                 int status;
712
713                 waitpid(pid, &status, 0);
714                 if (!WEXITSTATUS(status)) {
715                         if (find_mount("/tmp/extroot/mnt")) {
716                                 mount("/dev/root", "/", NULL, MS_NOATIME | MS_REMOUNT | MS_RDONLY, 0);
717
718                                 mkdir("/tmp/extroot/mnt/proc", 0755);
719                                 mkdir("/tmp/extroot/mnt/dev", 0755);
720                                 mkdir("/tmp/extroot/mnt/sys", 0755);
721                                 mkdir("/tmp/extroot/mnt/tmp", 0755);
722                                 mkdir("/tmp/extroot/mnt/rom", 0755);
723
724                                 if (mount_move("/tmp/extroot", "", "/mnt")) {
725                                         ERROR("moving pivotroot failed - continue normal boot\n");
726                                         umount("/tmp/extroot/mnt");
727                                 } else if (pivot("/mnt", "/rom")) {
728                                         ERROR("switching to pivotroot failed - continue normal boot\n");
729                                         umount("/mnt");
730                                 } else {
731                                         umount("/tmp/overlay");
732                                         rmdir("/tmp/overlay");
733                                         rmdir("/tmp/extroot/mnt");
734                                         rmdir("/tmp/extroot");
735                                         return 0;
736                                 }
737                         } else if (find_mount("/tmp/extroot/overlay")) {
738                                 if (mount_move("/tmp/extroot", "", "/overlay")) {
739                                         ERROR("moving extroot failed - continue normal boot\n");
740                                         umount("/tmp/extroot/overlay");
741                                 } else if (fopivot("/overlay", "/rom")) {
742                                         ERROR("switching to extroot failed - continue normal boot\n");
743                                         umount("/overlay");
744                                 } else {
745                                         umount("/tmp/overlay");
746                                         rmdir("/tmp/overlay");
747                                         rmdir("/tmp/extroot/overlay");
748                                         rmdir("/tmp/extroot");
749                                         return 0;
750                                 }
751                         }
752                 }
753         }
754         return -1;
755 }
756
757 int main(int argc, char **argv)
758 {
759         char *mp;
760         char mtd[32];
761
762         argv0 = basename(*argv);
763
764         if (!strcmp(basename(*argv), "jffs2mark"))
765                 return main_jffs2mark(argc, argv);
766
767         if (!strcmp(basename(*argv), "jffs2reset"))
768                 return main_jffs2reset(argc, argv);
769
770         if (!strcmp(basename(*argv), "switch2jffs"))
771                 return main_switch2jffs(argc, argv);
772
773         if (!getenv("PREINIT"))
774                 return -1;
775
776         if (!find_mtd_block("rootfs_patches", mtd, sizeof(mtd))) {
777                 ramoverlay();
778         } else if (find_mtd_char("rootfs_data", mtd, sizeof(mtd))) {
779                 if (!find_mtd_char("rootfs", mtd, sizeof(mtd)))
780                         mtd_unlock(mtd);
781                 LOG("mounting /dev/root\n");
782                 mount("/dev/root", "/", NULL, MS_NOATIME | MS_REMOUNT, 0);
783         } else {
784                 if (!extroot("")) {
785                         fprintf(stderr, "mount_root: switched to extroot\n");
786                         return 0;
787                 }
788
789                 switch (jffs2_ready(mtd)) {
790                 case FS_NONE:
791                 case FS_DEADCODE:
792                         return ramoverlay();
793
794                 case FS_JFFS2:
795                         find_mtd_block("rootfs_data", mtd, sizeof(mtd));
796                         mp = find_mount_point(mtd, NULL);
797                         if (mp) {
798                                 LOG("rootfs_data:%s is already mounted as %s\n", mtd, mp);
799                                 return -1;
800                         }
801
802                         mtd_mount_jffs2();
803
804                         if (!extroot("/tmp/overlay")) {
805                                 fprintf(stderr, "mount_root: switched to extroot\n");
806                                 return 0;
807                         }
808
809                         DEBUG(1, "switching to jffs2\n");
810                         if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) {
811                                 ERROR("switching to jffs2 failed - fallback to ramoverlay\n");
812                                 return ramoverlay();
813                         }
814                 }
815         }
816
817         return 0;
818 }