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.
10 #include "mount_util.h"
25 #include <sys/mount.h>
26 #include <sys/param.h>
29 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
30 #define mtab_needs_update(mnt) 0
32 static int mtab_needs_update(const char *mnt
)
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
)] == '/')
43 * Skip mtab update if /etc/mtab:
47 * - is on a read-only filesystem.
49 res
= lstat(_PATH_MOUNTED
, &stbuf
);
57 if (S_ISLNK(stbuf
.st_mode
))
64 res
= access(_PATH_MOUNTED
, W_OK
);
65 err
= (res
== -1) ? errno
: 0;
75 #endif /* __NetBSD__ */
77 static int add_mount(const char *progname
, const char *fsname
,
78 const char *mnt
, const char *type
, const char *opts
)
85 sigemptyset(&blockmask
);
86 sigaddset(&blockmask
, SIGCHLD
);
87 res
= sigprocmask(SIG_BLOCK
, &blockmask
, &oldmask
);
89 fprintf(stderr
, "%s: sigprocmask: %s\n", progname
, strerror(errno
));
95 fprintf(stderr
, "%s: fork: %s\n", progname
, strerror(errno
));
99 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
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
));
107 res
= waitpid(res
, &status
, 0);
109 fprintf(stderr
, "%s: waitpid: %s\n", progname
, strerror(errno
));
115 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
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
))
126 return add_mount(progname
, fsname
, mnt
, type
, opts
);
129 static int exec_umount(const char *progname
, const char *rel_mnt
, int lazy
)
136 sigemptyset(&blockmask
);
137 sigaddset(&blockmask
, SIGCHLD
);
138 res
= sigprocmask(SIG_BLOCK
, &blockmask
, &oldmask
);
140 fprintf(stderr
, "%s: sigprocmask: %s\n", progname
, strerror(errno
));
146 fprintf(stderr
, "%s: fork: %s\n", progname
, strerror(errno
));
150 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
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
));
158 res
= waitpid(res
, &status
, 0);
160 fprintf(stderr
, "%s: waitpid: %s\n", progname
, strerror(errno
));
167 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
172 int fuse_mnt_umount(const char *progname
, const char *abs_mnt
,
173 const char *rel_mnt
, int lazy
)
177 if (!mtab_needs_update(abs_mnt
)) {
178 res
= umount2(rel_mnt
, lazy
? 2 : 0);
180 fprintf(stderr
, "%s: failed to unmount %s: %s\n",
181 progname
, abs_mnt
, strerror(errno
));
185 return exec_umount(progname
, rel_mnt
, lazy
);
188 static int remove_mount(const char *progname
, const char *mnt
)
195 sigemptyset(&blockmask
);
196 sigaddset(&blockmask
, SIGCHLD
);
197 res
= sigprocmask(SIG_BLOCK
, &blockmask
, &oldmask
);
199 fprintf(stderr
, "%s: sigprocmask: %s\n", progname
, strerror(errno
));
205 fprintf(stderr
, "%s: fork: %s\n", progname
, strerror(errno
));
209 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
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
));
217 res
= waitpid(res
, &status
, 0);
219 fprintf(stderr
, "%s: waitpid: %s\n", progname
, strerror(errno
));
225 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
229 int fuse_mnt_remove_mount(const char *progname
, const char *mnt
)
231 if (!mtab_needs_update(mnt
))
234 return remove_mount(progname
, mnt
);
237 char *fuse_mnt_resolve_path(const char *progname
, const char *orig
)
244 const char *toresolv
;
247 fprintf(stderr
, "%s: invalid mountpoint '%s'\n", progname
,
254 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
260 for (end
= copy
+ strlen(copy
) - 1; end
> copy
&& *end
== '/'; end
--);
264 tmp
= strrchr(copy
, '/');
273 if (strcmp(lastcomp
, ".") == 0 || strcmp(lastcomp
, "..") == 0) {
280 if (realpath(toresolv
, buf
) == NULL
) {
281 fprintf(stderr
, "%s: bad mount point %s: %s\n", progname
, orig
,
286 if (lastcomp
== NULL
)
289 dst
= (char *) malloc(strlen(buf
) + 1 + strlen(lastcomp
) + 1);
291 unsigned buflen
= strlen(buf
);
292 if (buflen
&& buf
[buflen
-1] == '/')
293 sprintf(dst
, "%s%s", buf
, lastcomp
);
295 sprintf(dst
, "%s/%s", buf
, lastcomp
);
300 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
304 int fuse_mnt_check_empty(const char *progname
, const char *mnt
,
305 mode_t rootmode
, off_t rootsize
)
309 if (S_ISDIR(rootmode
)) {
311 DIR *dp
= opendir(mnt
);
314 "%s: failed to open mountpoint for reading: %s\n",
315 progname
, strerror(errno
));
318 while ((ent
= readdir(dp
)) != NULL
) {
319 if (strcmp(ent
->d_name
, ".") != 0 &&
320 strcmp(ent
->d_name
, "..") != 0) {
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
);
337 int fuse_mnt_check_fuseblk(void)
340 FILE *f
= fopen("/proc/filesystems", "r");
344 while (fgets(buf
, sizeof(buf
), f
))
345 if (strstr(buf
, "fuseblk\n")) {