libfstools: add "const" to char pointer arguments in mount_move()
[project/fstools.git] / 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
18 #include <errno.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <string.h>
22
23 #include "libfstools.h"
24
25 /* this is a raw syscall - man 2 pivot_root */
26 extern int pivot_root(const char *new_root, const char *put_old);
27
28 /**
29 * mount_move - move mounted point to the new location
30 *
31 * @oldroot: directory that is current location of mount point
32 * @newroot: new directory for the mount point
33 */
34 int
35 mount_move(const char *oldroot, const char *newroot, const char *dir)
36 {
37 #ifndef MS_MOVE
38 #define MS_MOVE (1 << 13)
39 #endif
40 struct stat s;
41 char olddir[64];
42 char newdir[64];
43 int ret;
44
45 snprintf(olddir, sizeof(olddir), "%s%s", oldroot, dir);
46 snprintf(newdir, sizeof(newdir), "%s%s", newroot, dir);
47
48 if (stat(olddir, &s) || !S_ISDIR(s.st_mode))
49 return -1;
50
51 if (stat(newdir, &s) || !S_ISDIR(s.st_mode))
52 return -1;
53
54 ret = mount(olddir, newdir, NULL, MS_NOATIME | MS_MOVE, NULL);
55
56 /* if (ret)
57 ULOG_ERR("failed %s %s: %s\n", olddir, newdir, strerror(errno));*/
58
59 return ret;
60 }
61
62 int
63 pivot(char *new, char *old)
64 {
65 char pivotdir[64];
66 int ret;
67
68 if (mount_move("", new, "/proc"))
69 return -1;
70
71 snprintf(pivotdir, sizeof(pivotdir), "%s%s", new, old);
72
73 ret = pivot_root(new, pivotdir);
74
75 if (ret < 0) {
76 ULOG_ERR("pivot_root failed %s %s: %s\n", new, pivotdir, strerror(errno));
77 return -1;
78 }
79
80 mount_move(old, "", "/dev");
81 mount_move(old, "", "/tmp");
82 mount_move(old, "", "/sys");
83 mount_move(old, "", "/overlay");
84
85 return 0;
86 }
87
88 /**
89 * fopivot - switch to overlay using passed dir as upper one
90 *
91 * @rw_root: writable directory that will be used as upper dir
92 * @ro_root: directory where old root will be put
93 */
94 int
95 fopivot(char *rw_root, char *ro_root)
96 {
97 char overlay[64], mount_options[64];
98
99 if (find_filesystem("overlay")) {
100 ULOG_ERR("BUG: no suitable fs found\n");
101 return -1;
102 }
103
104 snprintf(overlay, sizeof(overlay), "overlayfs:%s", rw_root);
105
106 /*
107 * First, try to mount without a workdir, for overlayfs v22 and before.
108 * If it fails, it means that we are probably using a v23 and
109 * later versions that require a workdir
110 */
111 snprintf(mount_options, sizeof(mount_options), "lowerdir=/,upperdir=%s", rw_root);
112 if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, mount_options)) {
113 char upperdir[64], workdir[64], upgrade[64], upgrade_dest[64];
114 struct stat st;
115
116 snprintf(upperdir, sizeof(upperdir), "%s/upper", rw_root);
117 snprintf(workdir, sizeof(workdir), "%s/work", rw_root);
118 snprintf(upgrade, sizeof(upgrade), "%s/sysupgrade.tgz", rw_root);
119 snprintf(upgrade_dest, sizeof(upgrade_dest), "%s/sysupgrade.tgz", upperdir);
120 snprintf(mount_options, sizeof(mount_options), "lowerdir=/,upperdir=%s,workdir=%s",
121 upperdir, workdir);
122
123 /*
124 * Overlay FS v23 and later requires both a upper and
125 * a work directory, both on the same filesystem, but
126 * not part of the same subtree.
127 * We can't really deal with these constraints without
128 * creating two new subdirectories in /overlay.
129 */
130 mkdir(upperdir, 0755);
131 mkdir(workdir, 0755);
132
133 if (stat(upgrade, &st) == 0)
134 rename(upgrade, upgrade_dest);
135
136 /* Mainlined overlayfs has been renamed to "overlay", try that first */
137 if (mount(overlay, "/mnt", "overlay", MS_NOATIME, mount_options)) {
138 if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, mount_options)) {
139 ULOG_ERR("mount failed: %s, options %s\n",
140 strerror(errno), mount_options);
141 return -1;
142 }
143 }
144 }
145
146 return pivot("/mnt", ro_root);
147 }
148
149 /**
150 * ramoverlay - use RAM to store filesystem changes on top of RO root
151 */
152 int
153 ramoverlay(void)
154 {
155 mkdir("/tmp/root", 0755);
156 mount("tmpfs", "/tmp/root", "tmpfs", MS_NOATIME, "mode=0755");
157
158 return fopivot("/tmp/root", "/rom");
159 }