blob: 56ed85a4e08990e7694296584c5663bdcc71a948 [file] [log] [blame]
Miklos Szeredi8e10b742007-04-25 15:52:39 +00001/*
Miklos Szeredicdb8b792007-12-12 14:25:40 +00002 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi8e10b742007-04-25 15:52:39 +00004
Nikolaus Rathd968b4d2016-10-02 21:20:44 -07005 Architecture-independent mounting code.
6
Miklos Szeredicdb8b792007-12-12 14:25:40 +00007 This program can be distributed under the terms of the GNU LGPLv2.
8 See the file COPYING.LIB.
Miklos Szeredi8e10b742007-04-25 15:52:39 +00009*/
10
Miklos Szeredie6e7a242013-07-24 17:09:26 +020011#include "config.h"
Miklos Szeredi8e10b742007-04-25 15:52:39 +000012#include "mount_util.h"
13#include <stdio.h>
14#include <unistd.h>
15#include <stdlib.h>
16#include <string.h>
Miklos Szeredi64222fb2010-08-27 17:16:54 +020017#include <signal.h>
Miklos Szeredi8e10b742007-04-25 15:52:39 +000018#include <dirent.h>
19#include <errno.h>
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +000020#include <fcntl.h>
Miklos Szeredi8e10b742007-04-25 15:52:39 +000021#include <limits.h>
Daniel Thau78bc1102013-08-26 11:57:16 +020022#include <paths.h>
Miklos Szeredi64222fb2010-08-27 17:16:54 +020023#ifndef __NetBSD__
Miklos Szeredi7f571e32007-07-25 09:36:52 +000024#include <mntent.h>
Miklos Szeredi64222fb2010-08-27 17:16:54 +020025#endif
Miklos Szeredi8e10b742007-04-25 15:52:39 +000026#include <sys/stat.h>
27#include <sys/wait.h>
Miklos Szeredi0b47f6b2007-11-12 13:57:12 +000028#include <sys/mount.h>
Miklos Szeredi74579f92008-06-10 18:34:11 +000029#include <sys/param.h>
Miklos Szeredi8e10b742007-04-25 15:52:39 +000030
Miklos Szeredi64222fb2010-08-27 17:16:54 +020031#ifdef __NetBSD__
32#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
Nikolaus Rathac25c152016-12-23 18:47:01 -080033#endif
34
35#ifdef IGNORE_MTAB
Miklos Szeredi64222fb2010-08-27 17:16:54 +020036#define mtab_needs_update(mnt) 0
37#else
Miklos Szeredi0042f8c2007-08-08 18:22:01 +000038static int mtab_needs_update(const char *mnt)
Miklos Szeredi7f571e32007-07-25 09:36:52 +000039{
Miklos Szeredi5f28cd12008-07-10 19:35:21 +000040 int res;
Miklos Szeredicdb8b792007-12-12 14:25:40 +000041 struct stat stbuf;
Miklos Szeredi7f571e32007-07-25 09:36:52 +000042
Miklos Szeredicdb8b792007-12-12 14:25:40 +000043 /* If mtab is within new mount, don't touch it */
44 if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
45 _PATH_MOUNTED[strlen(mnt)] == '/')
46 return 0;
Miklos Szeredi0042f8c2007-08-08 18:22:01 +000047
Miklos Szeredi5f28cd12008-07-10 19:35:21 +000048 /*
49 * Skip mtab update if /etc/mtab:
50 *
51 * - doesn't exist,
52 * - is a symlink,
53 * - is on a read-only filesystem.
54 */
55 res = lstat(_PATH_MOUNTED, &stbuf);
56 if (res == -1) {
57 if (errno == ENOENT)
58 return 0;
59 } else {
Miklos Szeredibd99f9c2010-11-08 15:35:35 +010060 uid_t ruid;
61 int err;
62
Miklos Szeredi5f28cd12008-07-10 19:35:21 +000063 if (S_ISLNK(stbuf.st_mode))
64 return 0;
65
Miklos Szeredibd99f9c2010-11-08 15:35:35 +010066 ruid = getuid();
67 if (ruid != 0)
68 setreuid(0, -1);
69
Miklos Szeredi5f28cd12008-07-10 19:35:21 +000070 res = access(_PATH_MOUNTED, W_OK);
Miklos Szeredibd99f9c2010-11-08 15:35:35 +010071 err = (res == -1) ? errno : 0;
72 if (ruid != 0)
73 setreuid(ruid, -1);
74
75 if (err == EROFS)
Miklos Szeredi5f28cd12008-07-10 19:35:21 +000076 return 0;
77 }
Miklos Szeredi0042f8c2007-08-08 18:22:01 +000078
Miklos Szeredicdb8b792007-12-12 14:25:40 +000079 return 1;
Miklos Szeredi7f571e32007-07-25 09:36:52 +000080}
Nikolaus Rathac25c152016-12-23 18:47:01 -080081#endif /* IGNORE_MTAB */
Miklos Szeredi7f571e32007-07-25 09:36:52 +000082
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +000083static int add_mount(const char *progname, const char *fsname,
84 const char *mnt, const char *type, const char *opts)
Miklos Szerediccd1fa62007-04-27 18:08:15 +000085{
Miklos Szeredicdb8b792007-12-12 14:25:40 +000086 int res;
87 int status;
Miklos Szeredi66756772008-02-08 10:45:06 +000088 sigset_t blockmask;
89 sigset_t oldmask;
Miklos Szerediccd1fa62007-04-27 18:08:15 +000090
Miklos Szeredi66756772008-02-08 10:45:06 +000091 sigemptyset(&blockmask);
92 sigaddset(&blockmask, SIGCHLD);
93 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
94 if (res == -1) {
95 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
96 return -1;
97 }
98
Miklos Szeredicdb8b792007-12-12 14:25:40 +000099 res = fork();
100 if (res == -1) {
101 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
Miklos Szeredi66756772008-02-08 10:45:06 +0000102 goto out_restore;
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000103 }
104 if (res == 0) {
Miklos Szeredicfe13b72015-05-22 10:58:43 +0200105 char *env = NULL;
106
Miklos Szeredi66756772008-02-08 10:45:06 +0000107 sigprocmask(SIG_SETMASK, &oldmask, NULL);
Alex Richman1bec2c12016-07-21 16:17:40 +0100108
109 if(setuid(geteuid()) == -1) {
110 fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
111 res = -1;
112 goto out_restore;
113 }
114
Miklos Szeredicfe13b72015-05-22 10:58:43 +0200115 execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
116 "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +0000117 fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
118 progname, strerror(errno));
119 exit(1);
120 }
121 res = waitpid(res, &status, 0);
122 if (res == -1)
123 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
124
125 if (status != 0)
126 res = -1;
127
128 out_restore:
129 sigprocmask(SIG_SETMASK, &oldmask, NULL);
130
131 return res;
132}
133
134int fuse_mnt_add_mount(const char *progname, const char *fsname,
135 const char *mnt, const char *type, const char *opts)
136{
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +0000137 if (!mtab_needs_update(mnt))
138 return 0;
139
Miklos Szeredicbd3a2a2011-01-31 16:22:41 +0100140 return add_mount(progname, fsname, mnt, type, opts);
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +0000141}
142
Miklos Szeredi8b3a0c72010-01-26 18:20:13 +0000143static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +0000144{
145 int res;
146 int status;
147 sigset_t blockmask;
148 sigset_t oldmask;
149
150 sigemptyset(&blockmask);
151 sigaddset(&blockmask, SIGCHLD);
152 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
153 if (res == -1) {
154 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
155 return -1;
156 }
157
158 res = fork();
159 if (res == -1) {
160 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
161 goto out_restore;
162 }
163 if (res == 0) {
Miklos Szeredicfe13b72015-05-22 10:58:43 +0200164 char *env = NULL;
165
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +0000166 sigprocmask(SIG_SETMASK, &oldmask, NULL);
Alex Richman1bec2c12016-07-21 16:17:40 +0100167
168 if(setuid(geteuid()) == -1) {
169 fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
170 res = -1;
171 goto out_restore;
172 }
173
Miklos Szeredicfe13b72015-05-22 10:58:43 +0200174 if (lazy) {
175 execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
176 "-l", NULL, &env);
177 } else {
178 execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
179 NULL, &env);
180 }
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000181 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
182 progname, strerror(errno));
183 exit(1);
184 }
185 res = waitpid(res, &status, 0);
Miklos Szeredi66756772008-02-08 10:45:06 +0000186 if (res == -1)
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000187 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
Miklos Szerediccd1fa62007-04-27 18:08:15 +0000188
Miklos Szeredi8b3a0c72010-01-26 18:20:13 +0000189 if (status != 0) {
Miklos Szeredi66756772008-02-08 10:45:06 +0000190 res = -1;
Miklos Szeredi8b3a0c72010-01-26 18:20:13 +0000191 }
Miklos Szeredi66756772008-02-08 10:45:06 +0000192
193 out_restore:
194 sigprocmask(SIG_SETMASK, &oldmask, NULL);
195 return res;
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +0000196
197}
198
Miklos Szeredi8b3a0c72010-01-26 18:20:13 +0000199int fuse_mnt_umount(const char *progname, const char *abs_mnt,
200 const char *rel_mnt, int lazy)
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +0000201{
202 int res;
203
Miklos Szeredi8b3a0c72010-01-26 18:20:13 +0000204 if (!mtab_needs_update(abs_mnt)) {
205 res = umount2(rel_mnt, lazy ? 2 : 0);
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +0000206 if (res == -1)
207 fprintf(stderr, "%s: failed to unmount %s: %s\n",
Miklos Szeredi8b3a0c72010-01-26 18:20:13 +0000208 progname, abs_mnt, strerror(errno));
Miklos Szeredi4c3d9b12009-12-23 12:51:40 +0000209 return res;
210 }
211
Miklos Szeredi8b3a0c72010-01-26 18:20:13 +0000212 return exec_umount(progname, rel_mnt, lazy);
Miklos Szerediccd1fa62007-04-27 18:08:15 +0000213}
214
Miklos Szeredieba22692010-11-08 16:00:16 +0100215static int remove_mount(const char *progname, const char *mnt)
216{
217 int res;
218 int status;
219 sigset_t blockmask;
220 sigset_t oldmask;
221
222 sigemptyset(&blockmask);
223 sigaddset(&blockmask, SIGCHLD);
224 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
225 if (res == -1) {
226 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
227 return -1;
228 }
229
230 res = fork();
231 if (res == -1) {
232 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
233 goto out_restore;
234 }
235 if (res == 0) {
Miklos Szeredicfe13b72015-05-22 10:58:43 +0200236 char *env = NULL;
237
Miklos Szeredieba22692010-11-08 16:00:16 +0100238 sigprocmask(SIG_SETMASK, &oldmask, NULL);
Alex Richman1bec2c12016-07-21 16:17:40 +0100239
240 if(setuid(geteuid()) == -1) {
241 fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
242 res = -1;
243 goto out_restore;
244 }
245
Miklos Szeredicfe13b72015-05-22 10:58:43 +0200246 execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
247 "--fake", mnt, NULL, &env);
Miklos Szeredieba22692010-11-08 16:00:16 +0100248 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
249 progname, strerror(errno));
250 exit(1);
251 }
252 res = waitpid(res, &status, 0);
253 if (res == -1)
254 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
255
256 if (status != 0)
257 res = -1;
258
259 out_restore:
260 sigprocmask(SIG_SETMASK, &oldmask, NULL);
261 return res;
262}
263
264int fuse_mnt_remove_mount(const char *progname, const char *mnt)
265{
266 if (!mtab_needs_update(mnt))
267 return 0;
268
269 return remove_mount(progname, mnt);
270}
271
Miklos Szeredi8e10b742007-04-25 15:52:39 +0000272char *fuse_mnt_resolve_path(const char *progname, const char *orig)
273{
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000274 char buf[PATH_MAX];
275 char *copy;
276 char *dst;
277 char *end;
278 char *lastcomp;
279 const char *toresolv;
Miklos Szeredi8e10b742007-04-25 15:52:39 +0000280
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000281 if (!orig[0]) {
282 fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
283 orig);
284 return NULL;
285 }
Miklos Szeredi8e10b742007-04-25 15:52:39 +0000286
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000287 copy = strdup(orig);
288 if (copy == NULL) {
289 fprintf(stderr, "%s: failed to allocate memory\n", progname);
290 return NULL;
291 }
Miklos Szeredi8e10b742007-04-25 15:52:39 +0000292
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000293 toresolv = copy;
294 lastcomp = NULL;
295 for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
296 if (end[0] != '/') {
297 char *tmp;
298 end[1] = '\0';
299 tmp = strrchr(copy, '/');
300 if (tmp == NULL) {
301 lastcomp = copy;
302 toresolv = ".";
303 } else {
304 lastcomp = tmp + 1;
305 if (tmp == copy)
306 toresolv = "/";
307 }
308 if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
309 lastcomp = NULL;
310 toresolv = copy;
311 }
312 else if (tmp)
313 tmp[0] = '\0';
314 }
315 if (realpath(toresolv, buf) == NULL) {
316 fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
317 strerror(errno));
318 free(copy);
319 return NULL;
320 }
321 if (lastcomp == NULL)
322 dst = strdup(buf);
323 else {
324 dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
325 if (dst) {
326 unsigned buflen = strlen(buf);
327 if (buflen && buf[buflen-1] == '/')
328 sprintf(dst, "%s%s", buf, lastcomp);
329 else
330 sprintf(dst, "%s/%s", buf, lastcomp);
331 }
332 }
333 free(copy);
334 if (dst == NULL)
335 fprintf(stderr, "%s: failed to allocate memory\n", progname);
336 return dst;
Miklos Szeredi8e10b742007-04-25 15:52:39 +0000337}
338
Miklos Szeredi62c24a82007-06-20 21:37:58 +0000339int fuse_mnt_check_fuseblk(void)
340{
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000341 char buf[256];
342 FILE *f = fopen("/proc/filesystems", "r");
343 if (!f)
344 return 1;
Miklos Szeredi62c24a82007-06-20 21:37:58 +0000345
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000346 while (fgets(buf, sizeof(buf), f))
347 if (strstr(buf, "fuseblk\n")) {
348 fclose(f);
349 return 1;
350 }
Miklos Szeredi62c24a82007-06-20 21:37:58 +0000351
Miklos Szeredicdb8b792007-12-12 14:25:40 +0000352 fclose(f);
353 return 0;
Miklos Szeredi62c24a82007-06-20 21:37:58 +0000354}