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.
9 #include "mount_util.h"
24 #include <sys/mount.h>
25 #include <sys/param.h>
28 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
29 #define mtab_needs_update(mnt) 0
31 static int mtab_needs_update(const char *mnt
)
36 /* If mtab is within new mount, don't touch it */
37 if (strncmp(mnt
, _PATH_MOUNTED
, strlen(mnt
)) == 0 &&
38 _PATH_MOUNTED
[strlen(mnt
)] == '/')
42 * Skip mtab update if /etc/mtab:
46 * - is on a read-only filesystem.
48 res
= lstat(_PATH_MOUNTED
, &stbuf
);
56 if (S_ISLNK(stbuf
.st_mode
))
63 res
= access(_PATH_MOUNTED
, W_OK
);
64 err
= (res
== -1) ? errno
: 0;
74 #endif /* __NetBSD__ */
76 static int add_mount(const char *progname
, const char *fsname
,
77 const char *mnt
, const char *type
, const char *opts
)
84 sigemptyset(&blockmask
);
85 sigaddset(&blockmask
, SIGCHLD
);
86 res
= sigprocmask(SIG_BLOCK
, &blockmask
, &oldmask
);
88 fprintf(stderr
, "%s: sigprocmask: %s\n", progname
, strerror(errno
));
94 fprintf(stderr
, "%s: fork: %s\n", progname
, strerror(errno
));
98 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
100 execl("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
101 "-f", "-t", type
, "-o", opts
, fsname
, mnt
, NULL
);
102 fprintf(stderr
, "%s: failed to execute /bin/mount: %s\n",
103 progname
, strerror(errno
));
106 res
= waitpid(res
, &status
, 0);
108 fprintf(stderr
, "%s: waitpid: %s\n", progname
, strerror(errno
));
114 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
119 int fuse_mnt_add_mount(const char *progname
, const char *fsname
,
120 const char *mnt
, const char *type
, const char *opts
)
122 if (!mtab_needs_update(mnt
))
125 return add_mount(progname
, fsname
, mnt
, type
, opts
);
128 static int exec_umount(const char *progname
, const char *rel_mnt
, int lazy
)
135 sigemptyset(&blockmask
);
136 sigaddset(&blockmask
, SIGCHLD
);
137 res
= sigprocmask(SIG_BLOCK
, &blockmask
, &oldmask
);
139 fprintf(stderr
, "%s: sigprocmask: %s\n", progname
, strerror(errno
));
145 fprintf(stderr
, "%s: fork: %s\n", progname
, strerror(errno
));
149 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
151 execl("/bin/umount", "/bin/umount", "-i", rel_mnt
,
152 lazy
? "-l" : NULL
, NULL
);
153 fprintf(stderr
, "%s: failed to execute /bin/umount: %s\n",
154 progname
, strerror(errno
));
157 res
= waitpid(res
, &status
, 0);
159 fprintf(stderr
, "%s: waitpid: %s\n", progname
, strerror(errno
));
166 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
171 int fuse_mnt_umount(const char *progname
, const char *abs_mnt
,
172 const char *rel_mnt
, int lazy
)
176 if (!mtab_needs_update(abs_mnt
)) {
177 res
= umount2(rel_mnt
, lazy
? 2 : 0);
179 fprintf(stderr
, "%s: failed to unmount %s: %s\n",
180 progname
, abs_mnt
, strerror(errno
));
184 return exec_umount(progname
, rel_mnt
, lazy
);
187 static int remove_mount(const char *progname
, const char *mnt
)
194 sigemptyset(&blockmask
);
195 sigaddset(&blockmask
, SIGCHLD
);
196 res
= sigprocmask(SIG_BLOCK
, &blockmask
, &oldmask
);
198 fprintf(stderr
, "%s: sigprocmask: %s\n", progname
, strerror(errno
));
204 fprintf(stderr
, "%s: fork: %s\n", progname
, strerror(errno
));
208 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
210 execl("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
211 "--fake", mnt
, NULL
);
212 fprintf(stderr
, "%s: failed to execute /bin/umount: %s\n",
213 progname
, strerror(errno
));
216 res
= waitpid(res
, &status
, 0);
218 fprintf(stderr
, "%s: waitpid: %s\n", progname
, strerror(errno
));
224 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
228 int fuse_mnt_remove_mount(const char *progname
, const char *mnt
)
230 if (!mtab_needs_update(mnt
))
233 return remove_mount(progname
, mnt
);
236 char *fuse_mnt_resolve_path(const char *progname
, const char *orig
)
243 const char *toresolv
;
246 fprintf(stderr
, "%s: invalid mountpoint '%s'\n", progname
,
253 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
259 for (end
= copy
+ strlen(copy
) - 1; end
> copy
&& *end
== '/'; end
--);
263 tmp
= strrchr(copy
, '/');
272 if (strcmp(lastcomp
, ".") == 0 || strcmp(lastcomp
, "..") == 0) {
279 if (realpath(toresolv
, buf
) == NULL
) {
280 fprintf(stderr
, "%s: bad mount point %s: %s\n", progname
, orig
,
285 if (lastcomp
== NULL
)
288 dst
= (char *) malloc(strlen(buf
) + 1 + strlen(lastcomp
) + 1);
290 unsigned buflen
= strlen(buf
);
291 if (buflen
&& buf
[buflen
-1] == '/')
292 sprintf(dst
, "%s%s", buf
, lastcomp
);
294 sprintf(dst
, "%s/%s", buf
, lastcomp
);
299 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
303 int fuse_mnt_check_empty(const char *progname
, const char *mnt
,
304 mode_t rootmode
, off_t rootsize
)
308 if (S_ISDIR(rootmode
)) {
310 DIR *dp
= opendir(mnt
);
313 "%s: failed to open mountpoint for reading: %s\n",
314 progname
, strerror(errno
));
317 while ((ent
= readdir(dp
)) != NULL
) {
318 if (strcmp(ent
->d_name
, ".") != 0 &&
319 strcmp(ent
->d_name
, "..") != 0) {
329 fprintf(stderr
, "%s: mountpoint is not empty\n", progname
);
330 fprintf(stderr
, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname
);
336 int fuse_mnt_check_fuseblk(void)
339 FILE *f
= fopen("/proc/filesystems", "r");
343 while (fgets(buf
, sizeof(buf
), f
))
344 if (strstr(buf
, "fuseblk\n")) {