60
60
static void drop_privs(void)
63
oldfsuid = setfsuid(getuid());
64
oldfsgid = setfsgid(getgid());
63
oldfsuid = setfsuid(getuid());
64
oldfsgid = setfsgid(getgid());
68
68
static void restore_privs(void)
76
76
#ifndef IGNORE_MTAB
77
77
static int add_mount(const char *source, const char *mnt, const char *type,
80
return fuse_mnt_add_mount(progname, source, mnt, type, opts);
80
return fuse_mnt_add_mount(progname, source, mnt, type, opts);
83
83
static int unmount_fuse(const char *mnt, int quiet, int lazy)
88
const char *user = NULL;
92
const char *mtab = _PATH_MOUNTED;
94
user = get_user_name();
98
fp = setmntent(mtab, "r");
100
fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
105
uidlen = sprintf(uidstr, "%u", getuid());
108
while ((entp = getmntent(fp)) != NULL) {
109
if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
110
(strcmp(entp->mnt_type, "fuse") == 0 ||
111
strcmp(entp->mnt_type, "fuseblk") == 0 ||
112
strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
113
strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
114
char *p = strstr(entp->mnt_opts, "user=");
115
if (p && (p == entp->mnt_opts || *(p-1) == ',') &&
116
strcmp(p + 5, user) == 0) {
120
/* /etc/mtab is a link pointing to /proc/mounts: */
121
else if ((p = strstr(entp->mnt_opts, "user_id=")) &&
122
(p == entp->mnt_opts || *(p-1) == ',') &&
123
strncmp(p + 8, uidstr, uidlen) == 0 &&
124
(*(p+8+uidlen) == ',' || *(p+8+uidlen) == '\0')) {
134
fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
140
return fuse_mnt_umount(progname, mnt, lazy);
88
const char *user = NULL;
92
const char *mtab = _PATH_MOUNTED;
94
user = get_user_name();
98
fp = setmntent(mtab, "r");
101
"%s: failed to open %s: %s\n", progname, mtab,
106
uidlen = sprintf(uidstr, "%u", getuid());
109
while ((entp = getmntent(fp)) != NULL) {
110
if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
111
(strcmp(entp->mnt_type, "fuse") == 0 ||
112
strcmp(entp->mnt_type, "fuseblk") == 0 ||
113
strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
114
strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
115
char *p = strstr(entp->mnt_opts, "user=");
117
(p == entp->mnt_opts || *(p-1) == ',') &&
118
strcmp(p + 5, user) == 0) {
122
/* /etc/mtab is a link pointing to
125
strstr(entp->mnt_opts, "user_id=")) &&
126
(p == entp->mnt_opts ||
128
strncmp(p + 8, uidstr, uidlen) == 0 &&
129
(*(p+8+uidlen) == ',' ||
130
*(p+8+uidlen) == '\0')) {
141
"%s: entry for %s not found in %s\n",
142
progname, mnt, mtab);
147
return fuse_mnt_umount(progname, mnt, lazy);
143
150
static int count_fuse_fs(void)
147
const char *mtab = _PATH_MOUNTED;
148
FILE *fp = setmntent(mtab, "r");
150
fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
154
while ((entp = getmntent(fp)) != NULL) {
155
if (strcmp(entp->mnt_type, "fuse") == 0 ||
156
strncmp(entp->mnt_type, "fuse.", 5) == 0)
154
const char *mtab = _PATH_MOUNTED;
155
FILE *fp = setmntent(mtab, "r");
157
fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
161
while ((entp = getmntent(fp)) != NULL) {
162
if (strcmp(entp->mnt_type, "fuse") == 0 ||
163
strncmp(entp->mnt_type, "fuse.", 5) == 0)
164
171
#else /* IGNORE_MTAB */
165
172
static int count_fuse_fs()
170
177
static int add_mount(const char *source, const char *mnt, const char *type,
180
187
static int unmount_fuse(const char *mnt, int quiet, int lazy)
182
return fuse_mnt_umount(progname, mnt, lazy);
189
return fuse_mnt_umount(progname, mnt, lazy);
184
191
#endif /* IGNORE_MTAB */
186
193
static void strip_line(char *line)
188
char *s = strchr(line, '#');
191
for (s = line + strlen(line) - 1; s >= line && isspace((unsigned char) *s); s--);
193
for (s = line; isspace((unsigned char) *s); s++);
195
memmove(line, s, strlen(s)+1);
195
char *s = strchr(line, '#');
198
for (s = line + strlen(line) - 1;
199
s >= line && isspace((unsigned char) *s); s--);
201
for (s = line; isspace((unsigned char) *s); s++);
203
memmove(line, s, strlen(s)+1);
198
206
static void parse_line(char *line, int linenum)
201
if (strcmp(line, "user_allow_other") == 0)
202
user_allow_other = 1;
203
else if (sscanf(line, "mount_max = %i", &tmp) == 1)
206
fprintf(stderr, "%s: unknown parameter in %s at line %i: '%s'\n",
207
progname, FUSE_CONF, linenum, line);
209
if (strcmp(line, "user_allow_other") == 0)
210
user_allow_other = 1;
211
else if (sscanf(line, "mount_max = %i", &tmp) == 1)
215
"%s: unknown parameter in %s at line %i: '%s'\n",
216
progname, FUSE_CONF, linenum, line);
210
219
static void read_conf(void)
212
FILE *fp = fopen(FUSE_CONF, "r");
217
while (fgets(line, sizeof(line), fp) != NULL) {
219
if (line[strlen(line)-1] == '\n') {
221
parse_line(line, linenum);
223
fprintf(stderr, "%s: reading %s: line %i too long\n",
224
progname, FUSE_CONF, linenum);
227
} else if(line[strlen(line)-1] == '\n')
233
} else if (errno != ENOENT) {
234
fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF,
221
FILE *fp = fopen(FUSE_CONF, "r");
226
while (fgets(line, sizeof(line), fp) != NULL) {
228
if (line[strlen(line)-1] == '\n') {
230
parse_line(line, linenum);
232
fprintf(stderr, "%s: reading %s: line %i too long\n",
233
progname, FUSE_CONF, linenum);
236
} else if(line[strlen(line)-1] == '\n')
242
} else if (errno != ENOENT) {
243
fprintf(stderr, "%s: failed to open %s: %s\n",
244
progname, FUSE_CONF, strerror(errno));
239
248
static int begins_with(const char *s, const char *beg)
241
if (strncmp(s, beg, strlen(beg)) == 0)
250
if (strncmp(s, beg, strlen(beg)) == 0)
247
256
struct mount_flags {
254
263
static struct mount_flags mount_flags[] = {
255
{"rw", MS_RDONLY, 0, 1},
256
{"ro", MS_RDONLY, 1, 1},
257
{"suid", MS_NOSUID, 0, 0},
258
{"nosuid", MS_NOSUID, 1, 1},
259
{"dev", MS_NODEV, 0, 0},
260
{"nodev", MS_NODEV, 1, 1},
261
{"exec", MS_NOEXEC, 0, 1},
262
{"noexec", MS_NOEXEC, 1, 1},
263
{"async", MS_SYNCHRONOUS, 0, 1},
264
{"sync", MS_SYNCHRONOUS, 1, 1},
265
{"atime", MS_NOATIME, 0, 1},
266
{"noatime", MS_NOATIME, 1, 1},
267
{"dirsync", MS_DIRSYNC, 1, 1},
264
{"rw", MS_RDONLY, 0, 1},
265
{"ro", MS_RDONLY, 1, 1},
266
{"suid", MS_NOSUID, 0, 0},
267
{"nosuid", MS_NOSUID, 1, 1},
268
{"dev", MS_NODEV, 0, 0},
269
{"nodev", MS_NODEV, 1, 1},
270
{"exec", MS_NOEXEC, 0, 1},
271
{"noexec", MS_NOEXEC, 1, 1},
272
{"async", MS_SYNCHRONOUS, 0, 1},
273
{"sync", MS_SYNCHRONOUS, 1, 1},
274
{"atime", MS_NOATIME, 0, 1},
275
{"noatime", MS_NOATIME, 1, 1},
276
{"dirsync", MS_DIRSYNC, 1, 1},
271
280
static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
275
for (i = 0; mount_flags[i].opt != NULL; i++) {
276
const char *opt = mount_flags[i].opt;
277
if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
278
*on = mount_flags[i].on;
279
*flag = mount_flags[i].flag;
280
if (!mount_flags[i].safe && getuid() != 0) {
282
fprintf(stderr, "%s: unsafe option %s ignored\n",
284
for (i = 0; mount_flags[i].opt != NULL; i++) {
285
const char *opt = mount_flags[i].opt;
286
if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
287
*on = mount_flags[i].on;
288
*flag = mount_flags[i].flag;
289
if (!mount_flags[i].safe && getuid() != 0) {
292
"%s: unsafe option %s ignored\n",
291
301
static int add_option(char **optsp, const char *opt, unsigned expand)
295
newopts = strdup(opt);
297
unsigned oldsize = strlen(*optsp);
298
unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
299
newopts = (char *) realloc(*optsp, newsize);
301
sprintf(newopts + oldsize, ",%s", opt);
303
if (newopts == NULL) {
304
fprintf(stderr, "%s: failed to allocate memory\n", progname);
305
newopts = strdup(opt);
307
unsigned oldsize = strlen(*optsp);
308
unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
309
newopts = (char *) realloc(*optsp, newsize);
311
sprintf(newopts + oldsize, ",%s", opt);
313
if (newopts == NULL) {
314
fprintf(stderr, "%s: failed to allocate memory\n", progname);
311
321
static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
316
if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
319
for (i = 0; mount_flags[i].opt != NULL; i++) {
320
if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
321
add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
325
if (add_option(mnt_optsp, opts, 0) == -1)
327
/* remove comma from end of opts*/
328
l = strlen(*mnt_optsp);
329
if ((*mnt_optsp)[l-1] == ',')
330
(*mnt_optsp)[l-1] = '\0';
332
const char *user = get_user_name();
336
if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
338
strcat(*mnt_optsp, user);
326
if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
329
for (i = 0; mount_flags[i].opt != NULL; i++) {
330
if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
331
add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
335
if (add_option(mnt_optsp, opts, 0) == -1)
337
/* remove comma from end of opts*/
338
l = strlen(*mnt_optsp);
339
if ((*mnt_optsp)[l-1] == ',')
340
(*mnt_optsp)[l-1] = '\0';
342
const char *user = get_user_name();
346
if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
348
strcat(*mnt_optsp, user);
343
353
static int opt_eq(const char *s, unsigned len, const char *opt)
345
if(strlen(opt) == len && strncmp(s, opt, len) == 0)
355
if(strlen(opt) == len && strncmp(s, opt, len) == 0)
351
361
static int get_string_opt(const char *s, unsigned len, const char *opt,
354
unsigned opt_len = strlen(opt);
358
*val = (char *) malloc(len - opt_len + 1);
360
fprintf(stderr, "%s: failed to allocate memory\n", progname);
364
memcpy(*val, s + opt_len, len - opt_len);
365
(*val)[len - opt_len] = '\0';
364
unsigned opt_len = strlen(opt);
368
*val = (char *) malloc(len - opt_len + 1);
370
fprintf(stderr, "%s: failed to allocate memory\n", progname);
374
memcpy(*val, s + opt_len, len - opt_len);
375
(*val)[len - opt_len] = '\0';
369
379
static int do_mount(const char *mnt, char **typep, mode_t rootmode,
370
int fd, const char *opts, const char *dev, char **sourcep,
371
char **mnt_optsp, off_t rootsize)
380
int fd, const char *opts, const char *dev, char **sourcep,
381
char **mnt_optsp, off_t rootsize)
374
int flags = MS_NOSUID | MS_NODEV;
376
char *mnt_opts = NULL;
380
char *subtype = NULL;
386
optbuf = (char *) malloc(strlen(opts) + 128);
388
fprintf(stderr, "%s: failed to allocate memory\n", progname);
392
for (s = opts, d = optbuf; *s;) {
394
const char *fsname_str = "fsname=";
395
const char *subtype_str = "subtype=";
396
for (len = 0; s[len] && s[len] != ','; len++);
397
if (begins_with(s, fsname_str)) {
398
if (!get_string_opt(s, len, fsname_str, &fsname))
400
} else if (begins_with(s, subtype_str)) {
401
if (!get_string_opt(s, len, subtype_str, &subtype))
403
} else if (opt_eq(s, len, "blkdev")) {
405
fprintf(stderr, "%s: option blkdev is privileged\n", progname);
409
} else if (opt_eq(s, len, "nonempty")) {
411
} else if (!begins_with(s, "fd=") &&
412
!begins_with(s, "rootmode=") &&
413
!begins_with(s, "user_id=") &&
414
!begins_with(s, "group_id=")) {
418
if (opt_eq(s, len, "large_read")) {
419
struct utsname utsname;
421
res = uname(&utsname);
423
sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 &&
424
(kmaj > 2 || (kmaj == 2 && kmin > 4))) {
425
fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
429
if (getuid() != 0 && !user_allow_other &&
430
(opt_eq(s, len, "allow_other") ||
431
opt_eq(s, len, "allow_root"))) {
432
fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
436
if (find_mount_flag(s, len, &on, &flag)) {
453
res = get_mnt_opts(flags, optbuf, &mnt_opts);
457
sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
458
fd, rootmode, getuid(), getgid());
461
fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1)
464
source = malloc((fsname ? strlen(fsname) : 0) +
465
(subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
467
type = malloc((subtype ? strlen(subtype) : 0) + 32);
468
if (!type || !source) {
469
fprintf(stderr, "%s: failed to allocate memory\n", progname);
474
sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
476
strcpy(type, blkdev ? "fuseblk" : "fuse");
479
strcpy(source, fsname);
481
strcpy(source, subtype ? subtype : dev);
483
res = mount(source, mnt, type, flags, optbuf);
484
if (res == -1 && errno == ENODEV && subtype) {
485
/* Probably missing subtype support */
486
strcpy(type, blkdev ? "fuseblk" : "fuse");
489
sprintf(source, "%s#%s", subtype, fsname);
491
strcpy(source, type);
494
res = mount(source, mnt, type, flags, optbuf);
496
if (res == -1 && errno == EINVAL) {
497
/* It could be an old version not supporting group_id */
498
sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid());
499
res = mount(source, mnt, type, flags, optbuf);
502
int errno_save = errno;
503
if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
504
fprintf(stderr, "%s: 'fuseblk' support missing\n", progname);
506
fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save));
511
*mnt_optsp = mnt_opts;
384
int flags = MS_NOSUID | MS_NODEV;
386
char *mnt_opts = NULL;
390
char *subtype = NULL;
396
optbuf = (char *) malloc(strlen(opts) + 128);
398
fprintf(stderr, "%s: failed to allocate memory\n", progname);
402
for (s = opts, d = optbuf; *s;) {
404
const char *fsname_str = "fsname=";
405
const char *subtype_str = "subtype=";
406
for (len = 0; s[len] && s[len] != ','; len++);
407
if (begins_with(s, fsname_str)) {
408
if (!get_string_opt(s, len, fsname_str, &fsname))
410
} else if (begins_with(s, subtype_str)) {
411
if (!get_string_opt(s, len, subtype_str, &subtype))
413
} else if (opt_eq(s, len, "blkdev")) {
416
"%s: option blkdev is privileged\n",
421
} else if (opt_eq(s, len, "nonempty")) {
423
} else if (!begins_with(s, "fd=") &&
424
!begins_with(s, "rootmode=") &&
425
!begins_with(s, "user_id=") &&
426
!begins_with(s, "group_id=")) {
430
if (opt_eq(s, len, "large_read")) {
431
struct utsname utsname;
433
res = uname(&utsname);
435
sscanf(utsname.release, "%u.%u",
436
&kmaj, &kmin) == 2 &&
437
(kmaj > 2 || (kmaj == 2 && kmin > 4))) {
438
fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
442
if (getuid() != 0 && !user_allow_other &&
443
(opt_eq(s, len, "allow_other") ||
444
opt_eq(s, len, "allow_root"))) {
445
fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
449
if (find_mount_flag(s, len, &on, &flag)) {
466
res = get_mnt_opts(flags, optbuf, &mnt_opts);
470
sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
471
fd, rootmode, getuid(), getgid());
474
fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1)
477
source = malloc((fsname ? strlen(fsname) : 0) +
478
(subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
480
type = malloc((subtype ? strlen(subtype) : 0) + 32);
481
if (!type || !source) {
482
fprintf(stderr, "%s: failed to allocate memory\n", progname);
487
sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
489
strcpy(type, blkdev ? "fuseblk" : "fuse");
492
strcpy(source, fsname);
494
strcpy(source, subtype ? subtype : dev);
496
res = mount(source, mnt, type, flags, optbuf);
497
if (res == -1 && errno == ENODEV && subtype) {
498
/* Probably missing subtype support */
499
strcpy(type, blkdev ? "fuseblk" : "fuse");
502
sprintf(source, "%s#%s", subtype, fsname);
504
strcpy(source, type);
507
res = mount(source, mnt, type, flags, optbuf);
509
if (res == -1 && errno == EINVAL) {
510
/* It could be an old version not supporting group_id */
511
sprintf(d, "fd=%i,rootmode=%o,user_id=%i",
512
fd, rootmode, getuid());
513
res = mount(source, mnt, type, flags, optbuf);
516
int errno_save = errno;
517
if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
518
fprintf(stderr, "%s: 'fuseblk' support missing\n",
521
fprintf(stderr, "%s: mount failed: %s\n", progname,
522
strerror(errno_save));
527
*mnt_optsp = mnt_opts;
527
543
static int check_version(const char *dev)
532
const char *version_file;
535
if (strcmp(dev, FUSE_DEV_OLD) != 0)
538
version_file = FUSE_VERSION_FILE_OLD;
539
vf = fopen(version_file, "r");
541
fprintf(stderr, "%s: kernel interface too old\n", progname);
544
res = fscanf(vf, "%i.%i", &majorver, &minorver);
547
fprintf(stderr, "%s: error reading %s\n", progname, version_file);
551
fprintf(stderr, "%s: kernel interface too old\n", progname);
548
const char *version_file;
551
if (strcmp(dev, FUSE_DEV_OLD) != 0)
554
version_file = FUSE_VERSION_FILE_OLD;
555
vf = fopen(version_file, "r");
557
fprintf(stderr, "%s: kernel interface too old\n", progname);
560
res = fscanf(vf, "%i.%i", &majorver, &minorver);
563
fprintf(stderr, "%s: error reading %s\n", progname,
568
fprintf(stderr, "%s: kernel interface too old\n", progname);
557
574
static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
561
const char *mnt = *mntp;
562
const char *origmnt = mnt;
564
res = lstat(mnt, stbuf);
566
fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
567
progname, mnt, strerror(errno));
571
/* No permission checking is done for root */
575
if (S_ISDIR(stbuf->st_mode)) {
576
*currdir_fd = open(".", O_RDONLY);
577
if (*currdir_fd == -1) {
578
fprintf(stderr, "%s: failed to open current directory: %s\n",
579
progname, strerror(errno));
584
fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n",
585
progname, strerror(errno));
589
res = lstat(mnt, stbuf);
591
fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
592
progname, origmnt, strerror(errno));
596
if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
597
fprintf(stderr, "%s: mountpoint %s not owned by user\n",
602
res = access(mnt, W_OK);
604
fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
608
} else if (S_ISREG(stbuf->st_mode)) {
609
static char procfile[256];
610
*mountpoint_fd = open(mnt, O_WRONLY);
611
if (*mountpoint_fd == -1) {
612
fprintf(stderr, "%s: failed to open %s: %s\n", progname, mnt,
616
res = fstat(*mountpoint_fd, stbuf);
618
fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
619
progname, mnt, strerror(errno));
622
if (!S_ISREG(stbuf->st_mode)) {
623
fprintf(stderr, "%s: mountpoint %s is no longer a regular file\n",
628
sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
632
"%s: mountpoint %s is not a directory or a regular file\n",
578
const char *mnt = *mntp;
579
const char *origmnt = mnt;
581
res = lstat(mnt, stbuf);
583
fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
584
progname, mnt, strerror(errno));
588
/* No permission checking is done for root */
592
if (S_ISDIR(stbuf->st_mode)) {
593
*currdir_fd = open(".", O_RDONLY);
594
if (*currdir_fd == -1) {
596
"%s: failed to open current directory: %s\n",
597
progname, strerror(errno));
603
"%s: failed to chdir to mountpoint: %s\n",
604
progname, strerror(errno));
608
res = lstat(mnt, stbuf);
611
"%s: failed to access mountpoint %s: %s\n",
612
progname, origmnt, strerror(errno));
616
if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
617
fprintf(stderr, "%s: mountpoint %s not owned by user\n",
622
res = access(mnt, W_OK);
624
fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
628
} else if (S_ISREG(stbuf->st_mode)) {
629
static char procfile[256];
630
*mountpoint_fd = open(mnt, O_WRONLY);
631
if (*mountpoint_fd == -1) {
632
fprintf(stderr, "%s: failed to open %s: %s\n",
633
progname, mnt, strerror(errno));
636
res = fstat(*mountpoint_fd, stbuf);
639
"%s: failed to access mountpoint %s: %s\n",
640
progname, mnt, strerror(errno));
643
if (!S_ISREG(stbuf->st_mode)) {
645
"%s: mountpoint %s is no longer a regular file\n",
650
sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
654
"%s: mountpoint %s is not a directory or a regular file\n",
641
663
static int try_open(const char *dev, char **devp, int silent)
643
int fd = open(dev, O_RDWR);
647
fprintf(stderr, "%s: failed to allocate memory\n", progname);
651
} else if (errno == ENODEV ||
652
errno == ENOENT) /* check for ENOENT too, for the udev case */
655
fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
665
int fd = open(dev, O_RDWR);
669
fprintf(stderr, "%s: failed to allocate memory\n",
674
} else if (errno == ENODEV ||
675
errno == ENOENT)/* check for ENOENT too, for the udev case */
678
fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
661
684
static int try_open_fuse_device(char **devp)
667
fd = try_open(FUSE_DEV_NEW, devp, 0);
673
fd = try_open(FUSE_DEV_OLD, devp, 1);
690
fd = try_open(FUSE_DEV_NEW, devp, 0);
696
fd = try_open(FUSE_DEV_OLD, devp, 1);
680
703
static int open_fuse_device(char **devp)
682
int fd = try_open_fuse_device(devp);
686
fprintf(stderr, "%s: fuse device not found, try 'modprobe fuse' first\n",
705
int fd = try_open_fuse_device(devp);
710
"%s: fuse device not found, try 'modprobe fuse' first\n",
693
717
static int mount_fuse(const char *mnt, const char *opts)
701
char *mnt_opts = NULL;
702
const char *real_mnt = mnt;
704
int mountpoint_fd = -1;
706
fd = open_fuse_device(&dev);
713
if (getuid() != 0 && mount_max != -1) {
714
int mount_count = count_fuse_fs();
715
if (mount_count >= mount_max) {
716
fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
722
res = check_version(dev);
724
res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd);
727
res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, fd, opts,
728
dev, &source, &mnt_opts, stbuf.st_size);
732
if (currdir_fd != -1) {
736
if (mountpoint_fd != -1)
737
close(mountpoint_fd);
744
if (geteuid() == 0) {
745
res = add_mount(source, mnt, type, mnt_opts);
747
umount2(mnt, 2); /* lazy umount */
725
char *mnt_opts = NULL;
726
const char *real_mnt = mnt;
728
int mountpoint_fd = -1;
730
fd = open_fuse_device(&dev);
737
if (getuid() != 0 && mount_max != -1) {
738
int mount_count = count_fuse_fs();
739
if (mount_count >= mount_max) {
740
fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
746
res = check_version(dev);
748
res = check_perm(&real_mnt, &stbuf, &currdir_fd,
752
res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
753
fd, opts, dev, &source, &mnt_opts,
758
if (currdir_fd != -1) {
762
if (mountpoint_fd != -1)
763
close(mountpoint_fd);
770
if (geteuid() == 0) {
771
res = add_mount(source, mnt, type, mnt_opts);
773
umount2(mnt, 2); /* lazy umount */
761
787
static int send_fd(int sock_fd, int fd)
765
struct cmsghdr *p_cmsg;
767
size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
791
struct cmsghdr *p_cmsg;
793
size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
771
msg.msg_control = cmsgbuf;
772
msg.msg_controllen = sizeof(cmsgbuf);
773
p_cmsg = CMSG_FIRSTHDR(&msg);
774
p_cmsg->cmsg_level = SOL_SOCKET;
775
p_cmsg->cmsg_type = SCM_RIGHTS;
776
p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
777
p_fds = (int *) CMSG_DATA(p_cmsg);
779
msg.msg_controllen = p_cmsg->cmsg_len;
785
/* "To pass file descriptors or credentials you need to send/read at
786
* least one byte" (man 7 unix) */
787
vec.iov_base = &sendchar;
788
vec.iov_len = sizeof(sendchar);
789
while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
791
perror("sending file descriptor");
797
msg.msg_control = cmsgbuf;
798
msg.msg_controllen = sizeof(cmsgbuf);
799
p_cmsg = CMSG_FIRSTHDR(&msg);
800
p_cmsg->cmsg_level = SOL_SOCKET;
801
p_cmsg->cmsg_type = SCM_RIGHTS;
802
p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
803
p_fds = (int *) CMSG_DATA(p_cmsg);
805
msg.msg_controllen = p_cmsg->cmsg_len;
811
/* "To pass file descriptors or credentials you need to send/read at
812
* least one byte" (man 7 unix) */
813
vec.iov_base = &sendchar;
814
vec.iov_len = sizeof(sendchar);
815
while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
817
perror("sending file descriptor");
797
823
static void usage(void)
800
"%s: [options] mountpoint\n"
803
" -V print version\n"
804
" -o opt[,opt...] mount options\n"
807
" -z lazy unmount\n",
826
"%s: [options] mountpoint\n"
829
" -V print version\n"
830
" -o opt[,opt...] mount options\n"
833
" -z lazy unmount\n",
812
838
static void show_version(void)
814
printf("fusermount version: %s\n", PACKAGE_VERSION);
840
printf("fusermount version: %s\n", PACKAGE_VERSION);
818
844
int main(int argc, char *argv[])
825
static int unmount = 0;
827
static int quiet = 0;
830
const char *opts = "";
832
static const struct option long_opts[] = {
833
{"unmount", no_argument, NULL, 'u'},
834
{"lazy", no_argument, NULL, 'z'},
835
{"quiet", no_argument, NULL, 'q'},
836
{"help", no_argument, NULL, 'h'},
837
{"version", no_argument, NULL, 'V'},
840
progname = strdup(argv[0]);
841
if (progname == NULL) {
842
fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
846
while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, NULL)) != -1) {
877
if (lazy && !unmount) {
878
fprintf(stderr, "%s: -z can only be used with -u\n", progname);
882
if (optind >= argc) {
883
fprintf(stderr, "%s: missing mountpoint argument\n", progname);
887
origmnt = argv[optind];
890
mnt = fuse_mnt_resolve_path(progname, origmnt);
898
res = unmount_fuse(mnt, quiet, lazy);
900
res = umount2(mnt, lazy ? 2 : 0);
901
if (res == -1 && !quiet)
902
fprintf(stderr, "%s: failed to unmount %s: %s\n", progname,
903
mnt, strerror(errno));
910
commfd = getenv(FUSE_COMMFD_ENV);
911
if (commfd == NULL) {
912
fprintf(stderr, "%s: old style mounting not supported\n", progname);
916
fd = mount_fuse(mnt, opts);
921
res = send_fd(cfd, fd);
851
static int unmount = 0;
853
static int quiet = 0;
856
const char *opts = "";
858
static const struct option long_opts[] = {
859
{"unmount", no_argument, NULL, 'u'},
860
{"lazy", no_argument, NULL, 'z'},
861
{"quiet", no_argument, NULL, 'q'},
862
{"help", no_argument, NULL, 'h'},
863
{"version", no_argument, NULL, 'V'},
866
progname = strdup(argv[0]);
867
if (progname == NULL) {
868
fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
872
while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
904
if (lazy && !unmount) {
905
fprintf(stderr, "%s: -z can only be used with -u\n", progname);
909
if (optind >= argc) {
910
fprintf(stderr, "%s: missing mountpoint argument\n", progname);
914
origmnt = argv[optind];
917
mnt = fuse_mnt_resolve_path(progname, origmnt);
925
res = unmount_fuse(mnt, quiet, lazy);
927
res = umount2(mnt, lazy ? 2 : 0);
928
if (res == -1 && !quiet)
930
"%s: failed to unmount %s: %s\n",
931
progname, mnt, strerror(errno));
938
commfd = getenv(FUSE_COMMFD_ENV);
939
if (commfd == NULL) {
940
fprintf(stderr, "%s: old style mounting not supported\n",
945
fd = mount_fuse(mnt, opts);
950
res = send_fd(cfd, fd);