libfuse: remove "-D_FILE_OFFSET_BITS=64" from fuse.pc
[fuse.git] / lib / mount_util.c
blob4415aa18d9d13648d5e436e633b75cc9fca5f85d
1 /*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB.
7 */
9 #include "config.h"
10 #include "mount_util.h"
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <signal.h>
16 #include <dirent.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <limits.h>
20 #ifndef __NetBSD__
21 #include <mntent.h>
22 #endif
23 #include <sys/stat.h>
24 #include <sys/wait.h>
25 #include <sys/mount.h>
26 #include <sys/param.h>
28 #ifdef __NetBSD__
29 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
30 #define mtab_needs_update(mnt) 0
31 #else
32 static int mtab_needs_update(const char *mnt)
34 int res;
35 struct stat stbuf;
37 /* If mtab is within new mount, don't touch it */
38 if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
39 _PATH_MOUNTED[strlen(mnt)] == '/')
40 return 0;
43 * Skip mtab update if /etc/mtab:
45 * - doesn't exist,
46 * - is a symlink,
47 * - is on a read-only filesystem.
49 res = lstat(_PATH_MOUNTED, &stbuf);
50 if (res == -1) {
51 if (errno == ENOENT)
52 return 0;
53 } else {
54 uid_t ruid;
55 int err;
57 if (S_ISLNK(stbuf.st_mode))
58 return 0;
60 ruid = getuid();
61 if (ruid != 0)
62 setreuid(0, -1);
64 res = access(_PATH_MOUNTED, W_OK);
65 err = (res == -1) ? errno : 0;
66 if (ruid != 0)
67 setreuid(ruid, -1);
69 if (err == EROFS)
70 return 0;
73 return 1;
75 #endif /* __NetBSD__ */
77 static int add_mount(const char *progname, const char *fsname,
78 const char *mnt, const char *type, const char *opts)
80 int res;
81 int status;
82 sigset_t blockmask;
83 sigset_t oldmask;
85 sigemptyset(&blockmask);
86 sigaddset(&blockmask, SIGCHLD);
87 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
88 if (res == -1) {
89 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
90 return -1;
93 res = fork();
94 if (res == -1) {
95 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
96 goto out_restore;
98 if (res == 0) {
99 sigprocmask(SIG_SETMASK, &oldmask, NULL);
100 setuid(geteuid());
101 execl("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
102 "-f", "-t", type, "-o", opts, fsname, mnt, NULL);
103 fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
104 progname, strerror(errno));
105 exit(1);
107 res = waitpid(res, &status, 0);
108 if (res == -1)
109 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
111 if (status != 0)
112 res = -1;
114 out_restore:
115 sigprocmask(SIG_SETMASK, &oldmask, NULL);
117 return res;
120 int fuse_mnt_add_mount(const char *progname, const char *fsname,
121 const char *mnt, const char *type, const char *opts)
123 if (!mtab_needs_update(mnt))
124 return 0;
126 return add_mount(progname, fsname, mnt, type, opts);
129 static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
131 int res;
132 int status;
133 sigset_t blockmask;
134 sigset_t oldmask;
136 sigemptyset(&blockmask);
137 sigaddset(&blockmask, SIGCHLD);
138 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
139 if (res == -1) {
140 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
141 return -1;
144 res = fork();
145 if (res == -1) {
146 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
147 goto out_restore;
149 if (res == 0) {
150 sigprocmask(SIG_SETMASK, &oldmask, NULL);
151 setuid(geteuid());
152 execl("/bin/umount", "/bin/umount", "-i", rel_mnt,
153 lazy ? "-l" : NULL, NULL);
154 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
155 progname, strerror(errno));
156 exit(1);
158 res = waitpid(res, &status, 0);
159 if (res == -1)
160 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
162 if (status != 0) {
163 res = -1;
166 out_restore:
167 sigprocmask(SIG_SETMASK, &oldmask, NULL);
168 return res;
172 int fuse_mnt_umount(const char *progname, const char *abs_mnt,
173 const char *rel_mnt, int lazy)
175 int res;
177 if (!mtab_needs_update(abs_mnt)) {
178 res = umount2(rel_mnt, lazy ? 2 : 0);
179 if (res == -1)
180 fprintf(stderr, "%s: failed to unmount %s: %s\n",
181 progname, abs_mnt, strerror(errno));
182 return res;
185 return exec_umount(progname, rel_mnt, lazy);
188 static int remove_mount(const char *progname, const char *mnt)
190 int res;
191 int status;
192 sigset_t blockmask;
193 sigset_t oldmask;
195 sigemptyset(&blockmask);
196 sigaddset(&blockmask, SIGCHLD);
197 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
198 if (res == -1) {
199 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
200 return -1;
203 res = fork();
204 if (res == -1) {
205 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
206 goto out_restore;
208 if (res == 0) {
209 sigprocmask(SIG_SETMASK, &oldmask, NULL);
210 setuid(geteuid());
211 execl("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
212 "--fake", mnt, NULL);
213 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
214 progname, strerror(errno));
215 exit(1);
217 res = waitpid(res, &status, 0);
218 if (res == -1)
219 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
221 if (status != 0)
222 res = -1;
224 out_restore:
225 sigprocmask(SIG_SETMASK, &oldmask, NULL);
226 return res;
229 int fuse_mnt_remove_mount(const char *progname, const char *mnt)
231 if (!mtab_needs_update(mnt))
232 return 0;
234 return remove_mount(progname, mnt);
237 char *fuse_mnt_resolve_path(const char *progname, const char *orig)
239 char buf[PATH_MAX];
240 char *copy;
241 char *dst;
242 char *end;
243 char *lastcomp;
244 const char *toresolv;
246 if (!orig[0]) {
247 fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
248 orig);
249 return NULL;
252 copy = strdup(orig);
253 if (copy == NULL) {
254 fprintf(stderr, "%s: failed to allocate memory\n", progname);
255 return NULL;
258 toresolv = copy;
259 lastcomp = NULL;
260 for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
261 if (end[0] != '/') {
262 char *tmp;
263 end[1] = '\0';
264 tmp = strrchr(copy, '/');
265 if (tmp == NULL) {
266 lastcomp = copy;
267 toresolv = ".";
268 } else {
269 lastcomp = tmp + 1;
270 if (tmp == copy)
271 toresolv = "/";
273 if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
274 lastcomp = NULL;
275 toresolv = copy;
277 else if (tmp)
278 tmp[0] = '\0';
280 if (realpath(toresolv, buf) == NULL) {
281 fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
282 strerror(errno));
283 free(copy);
284 return NULL;
286 if (lastcomp == NULL)
287 dst = strdup(buf);
288 else {
289 dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
290 if (dst) {
291 unsigned buflen = strlen(buf);
292 if (buflen && buf[buflen-1] == '/')
293 sprintf(dst, "%s%s", buf, lastcomp);
294 else
295 sprintf(dst, "%s/%s", buf, lastcomp);
298 free(copy);
299 if (dst == NULL)
300 fprintf(stderr, "%s: failed to allocate memory\n", progname);
301 return dst;
304 int fuse_mnt_check_empty(const char *progname, const char *mnt,
305 mode_t rootmode, off_t rootsize)
307 int isempty = 1;
309 if (S_ISDIR(rootmode)) {
310 struct dirent *ent;
311 DIR *dp = opendir(mnt);
312 if (dp == NULL) {
313 fprintf(stderr,
314 "%s: failed to open mountpoint for reading: %s\n",
315 progname, strerror(errno));
316 return -1;
318 while ((ent = readdir(dp)) != NULL) {
319 if (strcmp(ent->d_name, ".") != 0 &&
320 strcmp(ent->d_name, "..") != 0) {
321 isempty = 0;
322 break;
325 closedir(dp);
326 } else if (rootsize)
327 isempty = 0;
329 if (!isempty) {
330 fprintf(stderr, "%s: mountpoint is not empty\n", progname);
331 fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
332 return -1;
334 return 0;
337 int fuse_mnt_check_fuseblk(void)
339 char buf[256];
340 FILE *f = fopen("/proc/filesystems", "r");
341 if (!f)
342 return 1;
344 while (fgets(buf, sizeof(buf), f))
345 if (strstr(buf, "fuseblk\n")) {
346 fclose(f);
347 return 1;
350 fclose(f);
351 return 0;