1 /* 2 * Copyright (C) 2014 John Crispin <blogic@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2.1 6 * as published by the Free Software Foundation 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <sys/types.h> 15 #include <sys/stat.h> 16 #include <sys/mount.h> 17 #include <sys/wait.h> 18 19 #include <errno.h> 20 #include <stdio.h> 21 #include <unistd.h> 22 #include <string.h> 23 24 #include "libfstools.h" 25 26 /* this is a raw syscall - man 2 pivot_root */ 27 extern int pivot_root(const char *new_root, const char *put_old); 28 29 /** 30 * mount_move - move mounted point to the new location 31 * 32 * @oldroot: directory that is current location of mount point 33 * @newroot: new directory for the mount point 34 */ 35 int 36 mount_move(const char *oldroot, const char *newroot, const char *dir) 37 { 38 #ifndef MS_MOVE 39 #define MS_MOVE (1 << 13) 40 #endif 41 struct stat s; 42 char olddir[64]; 43 char newdir[64]; 44 int ret; 45 46 snprintf(olddir, sizeof(olddir), "%s%s", oldroot, dir); 47 snprintf(newdir, sizeof(newdir), "%s%s", newroot, dir); 48 49 if (stat(olddir, &s) || !S_ISDIR(s.st_mode)) 50 return -1; 51 52 if (stat(newdir, &s) || !S_ISDIR(s.st_mode)) 53 return -1; 54 55 ret = mount(olddir, newdir, NULL, MS_NOATIME | MS_MOVE, NULL); 56 57 /* if (ret) 58 ULOG_ERR("failed %s %s: %m\n", olddir, newdir);*/ 59 60 return ret; 61 } 62 63 int 64 pivot(char *new, char *old) 65 { 66 char pivotdir[64]; 67 int ret; 68 69 if (mount_move("", new, "/proc")) 70 return -1; 71 72 snprintf(pivotdir, sizeof(pivotdir), "%s%s", new, old); 73 74 ret = pivot_root(new, pivotdir); 75 76 if (ret < 0) { 77 ULOG_ERR("pivot_root failed %s %s: %m\n", new, pivotdir); 78 return -1; 79 } 80 81 mount_move(old, "", "/dev"); 82 mount_move(old, "", "/tmp"); 83 mount_move(old, "", "/sys"); 84 mount_move(old, "", "/overlay"); 85 86 return 0; 87 } 88 89 void 90 selinux_restorecon(char *overlaydir) 91 { 92 struct stat s; 93 pid_t restorecon_pid; 94 int status; 95 96 /* on non-SELinux system we don't have /sbin/restorecon, return */ 97 if (stat("/sbin/restorecon", &s)) 98 return; 99 100 restorecon_pid = fork(); 101 if (!restorecon_pid) 102 exit(execl("/sbin/restorecon", "restorecon", overlaydir, (char *) NULL)); 103 else if (restorecon_pid > 0) 104 waitpid(restorecon_pid, &status, 0); 105 } 106 107 /** 108 * fopivot - switch to overlay using passed dir as upper one 109 * 110 * @rw_root: writable directory that will be used as upper dir 111 * @ro_root: directory where old root will be put 112 */ 113 int 114 fopivot(char *rw_root, char *ro_root) 115 { 116 char overlay[64], mount_options[64], upperdir[64], workdir[64], upgrade[64], upgrade_dest[64]; 117 struct stat st; 118 119 if (find_filesystem("overlay")) { 120 ULOG_ERR("BUG: no suitable fs found\n"); 121 return -1; 122 } 123 124 snprintf(overlay, sizeof(overlay), "overlayfs:%s", rw_root); 125 snprintf(upperdir, sizeof(upperdir), "%s/upper", rw_root); 126 snprintf(workdir, sizeof(workdir), "%s/work", rw_root); 127 snprintf(upgrade, sizeof(upgrade), "%s/sysupgrade.tgz", rw_root); 128 snprintf(upgrade_dest, sizeof(upgrade_dest), "%s/sysupgrade.tgz", upperdir); 129 snprintf(mount_options, sizeof(mount_options), "lowerdir=/,upperdir=%s,workdir=%s", 130 upperdir, workdir); 131 132 /* 133 * Initialize SELinux security label on newly created overlay 134 * filesystem where /upper doesn't yet exist 135 */ 136 if (stat(upperdir, &st)) 137 selinux_restorecon(rw_root); 138 139 /* 140 * Overlay FS v23 and later requires both a upper and 141 * a work directory, both on the same filesystem, but 142 * not part of the same subtree. 143 * We can't really deal with these constraints without 144 * creating two new subdirectories in /overlay. 145 */ 146 if (mkdir(upperdir, 0755) == -1 && errno != EEXIST) 147 return -1; 148 149 if (mkdir(workdir, 0755) == -1 && errno != EEXIST) 150 return -1; 151 152 if (stat(upgrade, &st) == 0) 153 rename(upgrade, upgrade_dest); 154 155 if (mount(overlay, "/mnt", "overlay", MS_NOATIME, mount_options)) { 156 ULOG_ERR("mount failed: %m, options %s\n", mount_options); 157 return -1; 158 } 159 160 return pivot("/mnt", ro_root); 161 } 162 163 /** 164 * ramoverlay - use RAM to store filesystem changes on top of RO root 165 */ 166 int 167 ramoverlay(void) 168 { 169 mkdir("/tmp/root", 0755); 170 mount("tmpfs", "/tmp/root", "tmpfs", MS_NOATIME, "mode=0755"); 171 172 return fopivot("/tmp/root", "/rom"); 173 } 174
This page was automatically generated by LXR 0.3.1. • OpenWrt