• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/fstools/libfstools/mount.c

  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