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"
26 #include <sys/mount.h>
27 #include <sys/param.h>
30 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
31 #define mtab_needs_update(mnt) 0
33 static int mtab_needs_update(const char *mnt
)
38 /* If mtab is within new mount, don't touch it */
39 if (strncmp(mnt
, _PATH_MOUNTED
, strlen(mnt
)) == 0 &&
40 _PATH_MOUNTED
[strlen(mnt
)] == '/')
44 * Skip mtab update if /etc/mtab:
48 * - is on a read-only filesystem.
50 res
= lstat(_PATH_MOUNTED
, &stbuf
);
58 if (S_ISLNK(stbuf
.st_mode
))
65 res
= access(_PATH_MOUNTED
, W_OK
);
66 err
= (res
== -1) ? errno
: 0;
76 #endif /* __NetBSD__ */
78 static int add_mount(const char *progname
, const char *fsname
,
79 const char *mnt
, const char *type
, const char *opts
)
86 sigemptyset(&blockmask
);
87 sigaddset(&blockmask
, SIGCHLD
);
88 res
= sigprocmask(SIG_BLOCK
, &blockmask
, &oldmask
);
90 fprintf(stderr
, "%s: sigprocmask: %s\n", progname
, strerror(errno
));
96 fprintf(stderr
, "%s: fork: %s\n", progname
, strerror(errno
));
102 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
104 execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
105 "-f", "-t", type
, "-o", opts
, fsname
, mnt
, NULL
, &env
);
106 fprintf(stderr
, "%s: failed to execute /bin/mount: %s\n",
107 progname
, strerror(errno
));
110 res
= waitpid(res
, &status
, 0);
112 fprintf(stderr
, "%s: waitpid: %s\n", progname
, strerror(errno
));
118 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
123 int fuse_mnt_add_mount(const char *progname
, const char *fsname
,
124 const char *mnt
, const char *type
, const char *opts
)
126 if (!mtab_needs_update(mnt
))
129 return add_mount(progname
, fsname
, mnt
, type
, opts
);
132 static int exec_umount(const char *progname
, const char *rel_mnt
, int lazy
)
139 sigemptyset(&blockmask
);
140 sigaddset(&blockmask
, SIGCHLD
);
141 res
= sigprocmask(SIG_BLOCK
, &blockmask
, &oldmask
);
143 fprintf(stderr
, "%s: sigprocmask: %s\n", progname
, strerror(errno
));
149 fprintf(stderr
, "%s: fork: %s\n", progname
, strerror(errno
));
155 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
158 execle("/bin/umount", "/bin/umount", "-i", rel_mnt
,
161 execle("/bin/umount", "/bin/umount", "-i", rel_mnt
,
164 fprintf(stderr
, "%s: failed to execute /bin/umount: %s\n",
165 progname
, strerror(errno
));
168 res
= waitpid(res
, &status
, 0);
170 fprintf(stderr
, "%s: waitpid: %s\n", progname
, strerror(errno
));
177 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
182 int fuse_mnt_umount(const char *progname
, const char *abs_mnt
,
183 const char *rel_mnt
, int lazy
)
187 if (!mtab_needs_update(abs_mnt
)) {
188 res
= umount2(rel_mnt
, lazy
? 2 : 0);
190 fprintf(stderr
, "%s: failed to unmount %s: %s\n",
191 progname
, abs_mnt
, strerror(errno
));
195 return exec_umount(progname
, rel_mnt
, lazy
);
198 static int remove_mount(const char *progname
, const char *mnt
)
205 sigemptyset(&blockmask
);
206 sigaddset(&blockmask
, SIGCHLD
);
207 res
= sigprocmask(SIG_BLOCK
, &blockmask
, &oldmask
);
209 fprintf(stderr
, "%s: sigprocmask: %s\n", progname
, strerror(errno
));
215 fprintf(stderr
, "%s: fork: %s\n", progname
, strerror(errno
));
221 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
223 execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
224 "--fake", mnt
, NULL
, &env
);
225 fprintf(stderr
, "%s: failed to execute /bin/umount: %s\n",
226 progname
, strerror(errno
));
229 res
= waitpid(res
, &status
, 0);
231 fprintf(stderr
, "%s: waitpid: %s\n", progname
, strerror(errno
));
237 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
241 int fuse_mnt_remove_mount(const char *progname
, const char *mnt
)
243 if (!mtab_needs_update(mnt
))
246 return remove_mount(progname
, mnt
);
249 char *fuse_mnt_resolve_path(const char *progname
, const char *orig
)
256 const char *toresolv
;
259 fprintf(stderr
, "%s: invalid mountpoint '%s'\n", progname
,
266 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
272 for (end
= copy
+ strlen(copy
) - 1; end
> copy
&& *end
== '/'; end
--);
276 tmp
= strrchr(copy
, '/');
285 if (strcmp(lastcomp
, ".") == 0 || strcmp(lastcomp
, "..") == 0) {
292 if (realpath(toresolv
, buf
) == NULL
) {
293 fprintf(stderr
, "%s: bad mount point %s: %s\n", progname
, orig
,
298 if (lastcomp
== NULL
)
301 dst
= (char *) malloc(strlen(buf
) + 1 + strlen(lastcomp
) + 1);
303 unsigned buflen
= strlen(buf
);
304 if (buflen
&& buf
[buflen
-1] == '/')
305 sprintf(dst
, "%s%s", buf
, lastcomp
);
307 sprintf(dst
, "%s/%s", buf
, lastcomp
);
312 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
316 int fuse_mnt_check_empty(const char *progname
, const char *mnt
,
317 mode_t rootmode
, off_t rootsize
)
321 if (S_ISDIR(rootmode
)) {
323 DIR *dp
= opendir(mnt
);
326 "%s: failed to open mountpoint for reading: %s\n",
327 progname
, strerror(errno
));
330 while ((ent
= readdir(dp
)) != NULL
) {
331 if (strcmp(ent
->d_name
, ".") != 0 &&
332 strcmp(ent
->d_name
, "..") != 0) {
342 fprintf(stderr
, "%s: mountpoint is not empty\n", progname
);
343 fprintf(stderr
, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname
);
349 int fuse_mnt_check_fuseblk(void)
352 FILE *f
= fopen("/proc/filesystems", "r");
356 while (fgets(buf
, sizeof(buf
), f
))
357 if (strstr(buf
, "fuseblk\n")) {