blob: 020b223dca5a9711495414b02a8d3bc45d0bc62f [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB.
7*/
8
9#include "mount_util.h"
10#include <stdio.h>
11#include <unistd.h>
12#include <stdlib.h>
13#include <string.h>
Dees_Troye34c1332013-02-06 19:13:00 +000014#include <signal.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050015#include <dirent.h>
16#include <errno.h>
17#include <fcntl.h>
18#include <limits.h>
Dees_Troye34c1332013-02-06 19:13:00 +000019#include <paths.h>
Matt Mower523a0592015-12-13 11:31:00 -060020#ifndef __NetBSD__
21#include <mntent.h>
22#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050023#include <sys/stat.h>
24#include <sys/wait.h>
25#include <sys/mount.h>
26#include <sys/param.h>
Matt Mower523a0592015-12-13 11:31:00 -060027#if defined(__ANDROID__)
28#include <paths.h>
29#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050030
Dees_Troye34c1332013-02-06 19:13:00 +000031#ifdef __NetBSD__
32#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
33#define mtab_needs_update(mnt) 0
Matt Mower523a0592015-12-13 11:31:00 -060034#elif defined(__ANDROID__)
35#define mtab_needs_update(mnt) 0
Dees_Troye34c1332013-02-06 19:13:00 +000036#else
bigbiff bigbiff9c754052013-01-09 09:09:08 -050037static int mtab_needs_update(const char *mnt)
38{
39 int res;
40 struct stat stbuf;
41
42 /* If mtab is within new mount, don't touch it */
43 if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
44 _PATH_MOUNTED[strlen(mnt)] == '/')
45 return 0;
46
47 /*
48 * Skip mtab update if /etc/mtab:
49 *
50 * - doesn't exist,
51 * - is a symlink,
52 * - is on a read-only filesystem.
53 */
54 res = lstat(_PATH_MOUNTED, &stbuf);
55 if (res == -1) {
56 if (errno == ENOENT)
57 return 0;
58 } else {
Dees_Troye34c1332013-02-06 19:13:00 +000059 uid_t ruid;
60 int err;
61
bigbiff bigbiff9c754052013-01-09 09:09:08 -050062 if (S_ISLNK(stbuf.st_mode))
63 return 0;
64
Dees_Troye34c1332013-02-06 19:13:00 +000065 ruid = getuid();
66 if (ruid != 0)
67 setreuid(0, -1);
68
bigbiff bigbiff9c754052013-01-09 09:09:08 -050069 res = access(_PATH_MOUNTED, W_OK);
Dees_Troye34c1332013-02-06 19:13:00 +000070 err = (res == -1) ? errno : 0;
71 if (ruid != 0)
72 setreuid(ruid, -1);
73
74 if (err == EROFS)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050075 return 0;
76 }
77
78 return 1;
79}
Dees_Troye34c1332013-02-06 19:13:00 +000080#endif /* __NetBSD__ */
bigbiff bigbiff9c754052013-01-09 09:09:08 -050081
82static int add_mount(const char *progname, const char *fsname,
83 const char *mnt, const char *type, const char *opts)
84{
85 int res;
86 int status;
87 sigset_t blockmask;
88 sigset_t oldmask;
89
90 sigemptyset(&blockmask);
91 sigaddset(&blockmask, SIGCHLD);
92 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
93 if (res == -1) {
94 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
95 return -1;
96 }
97
98 res = fork();
99 if (res == -1) {
100 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
101 goto out_restore;
102 }
103 if (res == 0) {
Matt Mower523a0592015-12-13 11:31:00 -0600104 char *env = NULL;
105
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500106 sigprocmask(SIG_SETMASK, &oldmask, NULL);
107 setuid(geteuid());
Matt Mower523a0592015-12-13 11:31:00 -0600108 execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
109 "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500110 fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
111 progname, strerror(errno));
112 exit(1);
113 }
114 res = waitpid(res, &status, 0);
115 if (res == -1)
116 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
117
118 if (status != 0)
119 res = -1;
120
121 out_restore:
122 sigprocmask(SIG_SETMASK, &oldmask, NULL);
123
124 return res;
125}
126
127int fuse_mnt_add_mount(const char *progname, const char *fsname,
128 const char *mnt, const char *type, const char *opts)
129{
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500130 if (!mtab_needs_update(mnt))
131 return 0;
132
Dees_Troye34c1332013-02-06 19:13:00 +0000133 return add_mount(progname, fsname, mnt, type, opts);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500134}
135
136static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
137{
138 int res;
139 int status;
140 sigset_t blockmask;
141 sigset_t oldmask;
142
143 sigemptyset(&blockmask);
144 sigaddset(&blockmask, SIGCHLD);
145 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
146 if (res == -1) {
147 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
148 return -1;
149 }
150
151 res = fork();
152 if (res == -1) {
153 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
154 goto out_restore;
155 }
156 if (res == 0) {
Matt Mower523a0592015-12-13 11:31:00 -0600157 char *env = NULL;
158
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500159 sigprocmask(SIG_SETMASK, &oldmask, NULL);
160 setuid(geteuid());
Matt Mower523a0592015-12-13 11:31:00 -0600161 if (lazy) {
162 execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
163 "-l", NULL, &env);
164 } else {
165 execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
166 NULL, &env);
167 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500168 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
169 progname, strerror(errno));
170 exit(1);
171 }
172 res = waitpid(res, &status, 0);
173 if (res == -1)
174 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
175
176 if (status != 0) {
177 res = -1;
178 }
179
180 out_restore:
181 sigprocmask(SIG_SETMASK, &oldmask, NULL);
182 return res;
183
184}
185
186int fuse_mnt_umount(const char *progname, const char *abs_mnt,
187 const char *rel_mnt, int lazy)
188{
189 int res;
190
191 if (!mtab_needs_update(abs_mnt)) {
192 res = umount2(rel_mnt, lazy ? 2 : 0);
193 if (res == -1)
194 fprintf(stderr, "%s: failed to unmount %s: %s\n",
195 progname, abs_mnt, strerror(errno));
196 return res;
197 }
198
199 return exec_umount(progname, rel_mnt, lazy);
200}
201
Dees_Troye34c1332013-02-06 19:13:00 +0000202static int remove_mount(const char *progname, const char *mnt)
203{
204 int res;
205 int status;
206 sigset_t blockmask;
207 sigset_t oldmask;
208
209 sigemptyset(&blockmask);
210 sigaddset(&blockmask, SIGCHLD);
211 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
212 if (res == -1) {
213 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
214 return -1;
215 }
216
217 res = fork();
218 if (res == -1) {
219 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
220 goto out_restore;
221 }
222 if (res == 0) {
Matt Mower523a0592015-12-13 11:31:00 -0600223 char *env = NULL;
224
Dees_Troye34c1332013-02-06 19:13:00 +0000225 sigprocmask(SIG_SETMASK, &oldmask, NULL);
226 setuid(geteuid());
Matt Mower523a0592015-12-13 11:31:00 -0600227 execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
228 "--fake", mnt, NULL, &env);
Dees_Troye34c1332013-02-06 19:13:00 +0000229 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
230 progname, strerror(errno));
231 exit(1);
232 }
233 res = waitpid(res, &status, 0);
234 if (res == -1)
235 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
236
237 if (status != 0)
238 res = -1;
239
240 out_restore:
241 sigprocmask(SIG_SETMASK, &oldmask, NULL);
242 return res;
243}
244
245int fuse_mnt_remove_mount(const char *progname, const char *mnt)
246{
247 if (!mtab_needs_update(mnt))
248 return 0;
249
250 return remove_mount(progname, mnt);
251}
252
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500253char *fuse_mnt_resolve_path(const char *progname, const char *orig)
254{
255 char buf[PATH_MAX];
256 char *copy;
257 char *dst;
258 char *end;
259 char *lastcomp;
260 const char *toresolv;
261
262 if (!orig[0]) {
263 fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
264 orig);
265 return NULL;
266 }
267
268 copy = strdup(orig);
269 if (copy == NULL) {
270 fprintf(stderr, "%s: failed to allocate memory\n", progname);
271 return NULL;
272 }
273
274 toresolv = copy;
275 lastcomp = NULL;
276 for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
277 if (end[0] != '/') {
278 char *tmp;
279 end[1] = '\0';
280 tmp = strrchr(copy, '/');
281 if (tmp == NULL) {
282 lastcomp = copy;
283 toresolv = ".";
284 } else {
285 lastcomp = tmp + 1;
286 if (tmp == copy)
287 toresolv = "/";
288 }
289 if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
290 lastcomp = NULL;
291 toresolv = copy;
292 }
293 else if (tmp)
294 tmp[0] = '\0';
295 }
296 if (realpath(toresolv, buf) == NULL) {
297 fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
298 strerror(errno));
299 free(copy);
300 return NULL;
301 }
302 if (lastcomp == NULL)
303 dst = strdup(buf);
304 else {
305 dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
306 if (dst) {
307 unsigned buflen = strlen(buf);
308 if (buflen && buf[buflen-1] == '/')
309 sprintf(dst, "%s%s", buf, lastcomp);
310 else
311 sprintf(dst, "%s/%s", buf, lastcomp);
312 }
313 }
314 free(copy);
315 if (dst == NULL)
316 fprintf(stderr, "%s: failed to allocate memory\n", progname);
317 return dst;
318}
319
320int fuse_mnt_check_empty(const char *progname, const char *mnt,
Matt Mower523a0592015-12-13 11:31:00 -0600321 mode_t rootmode, loff_t rootsize)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500322{
323 int isempty = 1;
324
325 if (S_ISDIR(rootmode)) {
326 struct dirent *ent;
327 DIR *dp = opendir(mnt);
328 if (dp == NULL) {
329 fprintf(stderr,
330 "%s: failed to open mountpoint for reading: %s\n",
331 progname, strerror(errno));
332 return -1;
333 }
334 while ((ent = readdir(dp)) != NULL) {
335 if (strcmp(ent->d_name, ".") != 0 &&
336 strcmp(ent->d_name, "..") != 0) {
337 isempty = 0;
338 break;
339 }
340 }
341 closedir(dp);
342 } else if (rootsize)
343 isempty = 0;
344
345 if (!isempty) {
346 fprintf(stderr, "%s: mountpoint is not empty\n", progname);
347 fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
348 return -1;
349 }
350 return 0;
351}
352
353int fuse_mnt_check_fuseblk(void)
354{
355 char buf[256];
356 FILE *f = fopen("/proc/filesystems", "r");
357 if (!f)
358 return 1;
359
360 while (fgets(buf, sizeof(buf), f))
361 if (strstr(buf, "fuseblk\n")) {
362 fclose(f);
363 return 1;
364 }
365
366 fclose(f);
367 return 0;
368}