~james-w/+junk/fuse-ubuntu-upstream

« back to all changes in this revision

Viewing changes to util/fusermount.c

  • Committer: James Westby
  • Date: 2008-05-16 12:59:17 UTC
  • Revision ID: jw+debian@jameswestby.net-20080516125917-tp1sifyaxglg2kjk
Tags: upstream-debian-2.7.2, upstream-ubuntu-2.7.2
Import upstream from fuse_2.7.2.orig.tar.gz

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
    FUSE: Filesystem in Userspace
3
 
    Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
 
2
  FUSE: Filesystem in Userspace
 
3
  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
4
4
 
5
 
    This program can be distributed under the terms of the GNU GPL.
6
 
    See the file COPYING.
 
5
  This program can be distributed under the terms of the GNU GPL.
 
6
  See the file COPYING.
7
7
*/
8
8
/* This program does the mounting and unmounting of FUSE filesystems */
9
9
 
27
27
#include <sys/socket.h>
28
28
#include <sys/utsname.h>
29
29
 
30
 
#define FUSE_COMMFD_ENV         "_FUSE_COMMFD"
 
30
#define FUSE_COMMFD_ENV         "_FUSE_COMMFD"
31
31
 
32
32
#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
33
33
#define FUSE_DEV_NEW "/dev/fuse"
45
45
 
46
46
static const char *get_user_name(void)
47
47
{
48
 
    struct passwd *pw = getpwuid(getuid());
49
 
    if (pw != NULL && pw->pw_name != NULL)
50
 
        return pw->pw_name;
51
 
    else {
52
 
        fprintf(stderr, "%s: could not determine username\n", progname);
53
 
        return NULL;
54
 
    }
 
48
        struct passwd *pw = getpwuid(getuid());
 
49
        if (pw != NULL && pw->pw_name != NULL)
 
50
                return pw->pw_name;
 
51
        else {
 
52
                fprintf(stderr, "%s: could not determine username\n", progname);
 
53
                return NULL;
 
54
        }
55
55
}
56
56
 
57
57
static uid_t oldfsuid;
59
59
 
60
60
static void drop_privs(void)
61
61
{
62
 
    if (getuid() != 0) {
63
 
        oldfsuid = setfsuid(getuid());
64
 
        oldfsgid = setfsgid(getgid());
65
 
    }
 
62
        if (getuid() != 0) {
 
63
                oldfsuid = setfsuid(getuid());
 
64
                oldfsgid = setfsgid(getgid());
 
65
        }
66
66
}
67
67
 
68
68
static void restore_privs(void)
69
69
{
70
 
    if (getuid() != 0) {
71
 
        setfsuid(oldfsuid);
72
 
        setfsgid(oldfsgid);
73
 
    }
 
70
        if (getuid() != 0) {
 
71
                setfsuid(oldfsuid);
 
72
                setfsgid(oldfsgid);
 
73
        }
74
74
}
75
75
 
76
76
#ifndef IGNORE_MTAB
77
77
static int add_mount(const char *source, const char *mnt, const char *type,
78
 
                     const char *opts)
 
78
                     const char *opts)
79
79
{
80
 
    return fuse_mnt_add_mount(progname, source, mnt, type, opts);
 
80
        return fuse_mnt_add_mount(progname, source, mnt, type, opts);
81
81
}
82
82
 
83
83
static int unmount_fuse(const char *mnt, int quiet, int lazy)
84
84
{
85
 
    if (getuid() != 0) {
86
 
        struct mntent *entp;
87
 
        FILE *fp;
88
 
        const char *user = NULL;
89
 
        char uidstr[32];
90
 
        unsigned uidlen = 0;
91
 
        int found;
92
 
        const char *mtab = _PATH_MOUNTED;
93
 
 
94
 
        user = get_user_name();
95
 
        if (user == NULL)
96
 
            return -1;
97
 
 
98
 
        fp = setmntent(mtab, "r");
99
 
        if (fp == NULL) {
100
 
            fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
101
 
                    strerror(errno));
102
 
            return -1;
103
 
        }
104
 
 
105
 
        uidlen = sprintf(uidstr, "%u", getuid());
106
 
 
107
 
        found = 0;
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) {
117
 
                    found = 1;
118
 
                    break;
119
 
                }
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')) {
125
 
                    found = 1;
126
 
                    break;
127
 
                }
128
 
            }
129
 
        }
130
 
        endmntent(fp);
131
 
 
132
 
        if (!found) {
133
 
            if (!quiet)
134
 
                fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
135
 
                        mnt, mtab);
136
 
            return -1;
137
 
        }
138
 
    }
139
 
 
140
 
    return fuse_mnt_umount(progname, mnt, lazy);
 
85
        if (getuid() != 0) {
 
86
                struct mntent *entp;
 
87
                FILE *fp;
 
88
                const char *user = NULL;
 
89
                char uidstr[32];
 
90
                unsigned uidlen = 0;
 
91
                int found;
 
92
                const char *mtab = _PATH_MOUNTED;
 
93
 
 
94
                user = get_user_name();
 
95
                if (user == NULL)
 
96
                        return -1;
 
97
 
 
98
                fp = setmntent(mtab, "r");
 
99
                if (fp == NULL) {
 
100
                        fprintf(stderr,
 
101
                                "%s: failed to open %s: %s\n", progname, mtab,
 
102
                                strerror(errno));
 
103
                        return -1;
 
104
                }
 
105
 
 
106
                uidlen = sprintf(uidstr, "%u", getuid());
 
107
 
 
108
                found = 0;
 
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=");
 
116
                                if (p &&
 
117
                                    (p == entp->mnt_opts || *(p-1) == ',') &&
 
118
                                    strcmp(p + 5, user) == 0) {
 
119
                                        found = 1;
 
120
                                        break;
 
121
                                }
 
122
                                /* /etc/mtab is a link pointing to
 
123
                                   /proc/mounts: */
 
124
                                else if ((p =
 
125
                                          strstr(entp->mnt_opts, "user_id=")) &&
 
126
                                         (p == entp->mnt_opts ||
 
127
                                          *(p-1) == ',') &&
 
128
                                         strncmp(p + 8, uidstr, uidlen) == 0 &&
 
129
                                         (*(p+8+uidlen) == ',' ||
 
130
                                          *(p+8+uidlen) == '\0')) {
 
131
                                        found = 1;
 
132
                                        break;
 
133
                                }
 
134
                        }
 
135
                }
 
136
                endmntent(fp);
 
137
 
 
138
                if (!found) {
 
139
                        if (!quiet)
 
140
                                fprintf(stderr,
 
141
                                        "%s: entry for %s not found in %s\n",
 
142
                                        progname, mnt, mtab);
 
143
                        return -1;
 
144
                }
 
145
        }
 
146
 
 
147
        return fuse_mnt_umount(progname, mnt, lazy);
141
148
}
142
149
 
143
150
static int count_fuse_fs(void)
144
151
{
145
 
    struct mntent *entp;
146
 
    int count = 0;
147
 
    const char *mtab = _PATH_MOUNTED;
148
 
    FILE *fp = setmntent(mtab, "r");
149
 
    if (fp == NULL) {
150
 
        fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
151
 
                strerror(errno));
152
 
        return -1;
153
 
    }
154
 
    while ((entp = getmntent(fp)) != NULL) {
155
 
        if (strcmp(entp->mnt_type, "fuse") == 0 ||
156
 
            strncmp(entp->mnt_type, "fuse.", 5) == 0)
157
 
            count ++;
158
 
    }
159
 
    endmntent(fp);
160
 
    return count;
 
152
        struct mntent *entp;
 
153
        int count = 0;
 
154
        const char *mtab = _PATH_MOUNTED;
 
155
        FILE *fp = setmntent(mtab, "r");
 
156
        if (fp == NULL) {
 
157
                fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
 
158
                        strerror(errno));
 
159
                return -1;
 
160
        }
 
161
        while ((entp = getmntent(fp)) != NULL) {
 
162
                if (strcmp(entp->mnt_type, "fuse") == 0 ||
 
163
                    strncmp(entp->mnt_type, "fuse.", 5) == 0)
 
164
                        count ++;
 
165
        }
 
166
        endmntent(fp);
 
167
        return count;
161
168
}
162
169
 
163
170
 
164
171
#else /* IGNORE_MTAB */
165
172
static int count_fuse_fs()
166
173
{
167
 
    return 0;
 
174
        return 0;
168
175
}
169
176
 
170
177
static int add_mount(const char *source, const char *mnt, const char *type,
171
 
                     const char *opts)
 
178
                     const char *opts)
172
179
{
173
 
    (void) source;
174
 
    (void) mnt;
175
 
    (void) type;
176
 
    (void) opts;
177
 
    return 0;
 
180
        (void) source;
 
181
        (void) mnt;
 
182
        (void) type;
 
183
        (void) opts;
 
184
        return 0;
178
185
}
179
186
 
180
187
static int unmount_fuse(const char *mnt, int quiet, int lazy)
181
188
{
182
 
    return fuse_mnt_umount(progname, mnt, lazy);
 
189
        return fuse_mnt_umount(progname, mnt, lazy);
183
190
}
184
191
#endif /* IGNORE_MTAB */
185
192
 
186
193
static void strip_line(char *line)
187
194
{
188
 
    char *s = strchr(line, '#');
189
 
    if (s != NULL)
190
 
        s[0] = '\0';
191
 
    for (s = line + strlen(line) - 1; s >= line && isspace((unsigned char) *s); s--);
192
 
    s[1] = '\0';
193
 
    for (s = line; isspace((unsigned char) *s); s++);
194
 
    if (s != line)
195
 
        memmove(line, s, strlen(s)+1);
 
195
        char *s = strchr(line, '#');
 
196
        if (s != NULL)
 
197
                s[0] = '\0';
 
198
        for (s = line + strlen(line) - 1;
 
199
             s >= line && isspace((unsigned char) *s); s--);
 
200
        s[1] = '\0';
 
201
        for (s = line; isspace((unsigned char) *s); s++);
 
202
        if (s != line)
 
203
                memmove(line, s, strlen(s)+1);
196
204
}
197
205
 
198
206
static void parse_line(char *line, int linenum)
199
207
{
200
 
    int tmp;
201
 
    if (strcmp(line, "user_allow_other") == 0)
202
 
        user_allow_other = 1;
203
 
    else if (sscanf(line, "mount_max = %i", &tmp) == 1)
204
 
        mount_max = tmp;
205
 
    else if(line[0])
206
 
        fprintf(stderr, "%s: unknown parameter in %s at line %i: '%s'\n",
207
 
                progname, FUSE_CONF, linenum, line);
 
208
        int tmp;
 
209
        if (strcmp(line, "user_allow_other") == 0)
 
210
                user_allow_other = 1;
 
211
        else if (sscanf(line, "mount_max = %i", &tmp) == 1)
 
212
                mount_max = tmp;
 
213
        else if(line[0])
 
214
                fprintf(stderr,
 
215
                        "%s: unknown parameter in %s at line %i: '%s'\n",
 
216
                        progname, FUSE_CONF, linenum, line);
208
217
}
209
218
 
210
219
static void read_conf(void)
211
220
{
212
 
    FILE *fp = fopen(FUSE_CONF, "r");
213
 
    if (fp != NULL) {
214
 
        int linenum = 1;
215
 
        char line[256];
216
 
        int isnewline = 1;
217
 
        while (fgets(line, sizeof(line), fp) != NULL) {
218
 
            if (isnewline) {
219
 
                if (line[strlen(line)-1] == '\n') {
220
 
                    strip_line(line);
221
 
                    parse_line(line, linenum);
222
 
                } else {
223
 
                    fprintf(stderr, "%s: reading %s: line %i too long\n",
224
 
                            progname, FUSE_CONF, linenum);
225
 
                    isnewline = 0;
226
 
                }
227
 
            } else if(line[strlen(line)-1] == '\n')
228
 
                isnewline = 1;
229
 
            if (isnewline)
230
 
                linenum ++;
231
 
        }
232
 
        fclose(fp);
233
 
    } else if (errno != ENOENT) {
234
 
        fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF,
235
 
                strerror(errno));
236
 
    }
 
221
        FILE *fp = fopen(FUSE_CONF, "r");
 
222
        if (fp != NULL) {
 
223
                int linenum = 1;
 
224
                char line[256];
 
225
                int isnewline = 1;
 
226
                while (fgets(line, sizeof(line), fp) != NULL) {
 
227
                        if (isnewline) {
 
228
                                if (line[strlen(line)-1] == '\n') {
 
229
                                        strip_line(line);
 
230
                                        parse_line(line, linenum);
 
231
                                } else {
 
232
                                        fprintf(stderr, "%s: reading %s: line %i too long\n",
 
233
                                                progname, FUSE_CONF, linenum);
 
234
                                        isnewline = 0;
 
235
                                }
 
236
                        } else if(line[strlen(line)-1] == '\n')
 
237
                                isnewline = 1;
 
238
                        if (isnewline)
 
239
                                linenum ++;
 
240
                }
 
241
                fclose(fp);
 
242
        } else if (errno != ENOENT) {
 
243
                fprintf(stderr, "%s: failed to open %s: %s\n",
 
244
                        progname, FUSE_CONF, strerror(errno));
 
245
        }
237
246
}
238
247
 
239
248
static int begins_with(const char *s, const char *beg)
240
249
{
241
 
    if (strncmp(s, beg, strlen(beg)) == 0)
242
 
        return 1;
243
 
    else
244
 
        return 0;
 
250
        if (strncmp(s, beg, strlen(beg)) == 0)
 
251
                return 1;
 
252
        else
 
253
                return 0;
245
254
}
246
255
 
247
256
struct mount_flags {
248
 
    const char *opt;
249
 
    unsigned long flag;
250
 
    int on;
251
 
    int safe;
 
257
        const char *opt;
 
258
        unsigned long flag;
 
259
        int on;
 
260
        int safe;
252
261
};
253
262
 
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},
268
 
    {NULL,      0,              0, 0}
 
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},
 
277
        {NULL,      0,              0, 0}
269
278
};
270
279
 
271
280
static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
272
281
{
273
 
    int i;
 
282
        int i;
274
283
 
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) {
281
 
                *flag = 0;
282
 
                fprintf(stderr, "%s: unsafe option %s ignored\n",
283
 
                        progname, opt);
284
 
            }
285
 
            return 1;
286
 
        }
287
 
    }
288
 
    return 0;
 
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) {
 
290
                                *flag = 0;
 
291
                                fprintf(stderr,
 
292
                                        "%s: unsafe option %s ignored\n",
 
293
                                        progname, opt);
 
294
                        }
 
295
                        return 1;
 
296
                }
 
297
        }
 
298
        return 0;
289
299
}
290
300
 
291
301
static int add_option(char **optsp, const char *opt, unsigned expand)
292
302
{
293
 
    char *newopts;
294
 
    if (*optsp == NULL)
295
 
        newopts = strdup(opt);
296
 
    else {
297
 
        unsigned oldsize = strlen(*optsp);
298
 
        unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
299
 
        newopts = (char *) realloc(*optsp, newsize);
300
 
        if (newopts)
301
 
            sprintf(newopts + oldsize, ",%s", opt);
302
 
    }
303
 
    if (newopts == NULL) {
304
 
        fprintf(stderr, "%s: failed to allocate memory\n", progname);
305
 
        return -1;
306
 
    }
307
 
    *optsp = newopts;
308
 
    return 0;
 
303
        char *newopts;
 
304
        if (*optsp == NULL)
 
305
                newopts = strdup(opt);
 
306
        else {
 
307
                unsigned oldsize = strlen(*optsp);
 
308
                unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
 
309
                newopts = (char *) realloc(*optsp, newsize);
 
310
                if (newopts)
 
311
                        sprintf(newopts + oldsize, ",%s", opt);
 
312
        }
 
313
        if (newopts == NULL) {
 
314
                fprintf(stderr, "%s: failed to allocate memory\n", progname);
 
315
                return -1;
 
316
        }
 
317
        *optsp = newopts;
 
318
        return 0;
309
319
}
310
320
 
311
321
static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
312
322
{
313
 
    int i;
314
 
    int l;
315
 
 
316
 
    if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
317
 
        return -1;
318
 
 
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)
322
 
            return -1;
323
 
    }
324
 
 
325
 
    if (add_option(mnt_optsp, opts, 0) == -1)
326
 
        return -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';
331
 
    if (getuid() != 0) {
332
 
        const char *user = get_user_name();
333
 
        if (user == NULL)
334
 
            return -1;
335
 
 
336
 
        if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
337
 
            return -1;
338
 
        strcat(*mnt_optsp, user);
339
 
    }
340
 
    return 0;
 
323
        int i;
 
324
        int l;
 
325
 
 
326
        if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
 
327
                return -1;
 
328
 
 
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)
 
332
                        return -1;
 
333
        }
 
334
 
 
335
        if (add_option(mnt_optsp, opts, 0) == -1)
 
336
                return -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';
 
341
        if (getuid() != 0) {
 
342
                const char *user = get_user_name();
 
343
                if (user == NULL)
 
344
                        return -1;
 
345
 
 
346
                if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
 
347
                        return -1;
 
348
                strcat(*mnt_optsp, user);
 
349
        }
 
350
        return 0;
341
351
}
342
352
 
343
353
static int opt_eq(const char *s, unsigned len, const char *opt)
344
354
{
345
 
    if(strlen(opt) == len && strncmp(s, opt, len) == 0)
346
 
        return 1;
347
 
    else
348
 
        return 0;
 
355
        if(strlen(opt) == len && strncmp(s, opt, len) == 0)
 
356
                return 1;
 
357
        else
 
358
                return 0;
349
359
}
350
360
 
351
361
static int get_string_opt(const char *s, unsigned len, const char *opt,
352
 
                          char **val)
 
362
                          char **val)
353
363
{
354
 
    unsigned opt_len = strlen(opt);
355
 
 
356
 
    if (*val)
357
 
        free(*val);
358
 
    *val = (char *) malloc(len - opt_len + 1);
359
 
    if (!*val) {
360
 
        fprintf(stderr, "%s: failed to allocate memory\n", progname);
361
 
        return 0;
362
 
    }
363
 
 
364
 
    memcpy(*val, s + opt_len, len - opt_len);
365
 
    (*val)[len - opt_len] = '\0';
366
 
    return 1;
 
364
        unsigned opt_len = strlen(opt);
 
365
 
 
366
        if (*val)
 
367
                free(*val);
 
368
        *val = (char *) malloc(len - opt_len + 1);
 
369
        if (!*val) {
 
370
                fprintf(stderr, "%s: failed to allocate memory\n", progname);
 
371
                return 0;
 
372
        }
 
373
 
 
374
        memcpy(*val, s + opt_len, len - opt_len);
 
375
        (*val)[len - opt_len] = '\0';
 
376
        return 1;
367
377
}
368
378
 
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)
372
382
{
373
 
    int res;
374
 
    int flags = MS_NOSUID | MS_NODEV;
375
 
    char *optbuf;
376
 
    char *mnt_opts = NULL;
377
 
    const char *s;
378
 
    char *d;
379
 
    char *fsname = NULL;
380
 
    char *subtype = NULL;
381
 
    char *source = NULL;
382
 
    char *type = NULL;
383
 
    int check_empty = 1;
384
 
    int blkdev = 0;
385
 
 
386
 
    optbuf = (char *) malloc(strlen(opts) + 128);
387
 
    if (!optbuf) {
388
 
        fprintf(stderr, "%s: failed to allocate memory\n", progname);
389
 
        return -1;
390
 
    }
391
 
 
392
 
    for (s = opts, d = optbuf; *s;) {
393
 
        unsigned len;
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))
399
 
                goto err;
400
 
        } else if (begins_with(s, subtype_str)) {
401
 
            if (!get_string_opt(s, len, subtype_str, &subtype))
402
 
                goto err;
403
 
        } else if (opt_eq(s, len, "blkdev")) {
404
 
            if (getuid() != 0) {
405
 
                fprintf(stderr, "%s: option blkdev is privileged\n", progname);
406
 
                goto err;
407
 
            }
408
 
            blkdev = 1;
409
 
        } else if (opt_eq(s, len, "nonempty")) {
410
 
            check_empty = 0;
411
 
        } else if (!begins_with(s, "fd=") &&
412
 
                   !begins_with(s, "rootmode=") &&
413
 
                   !begins_with(s, "user_id=") &&
414
 
                   !begins_with(s, "group_id=")) {
415
 
            int on;
416
 
            int flag;
417
 
            int skip_option = 0;
418
 
            if (opt_eq(s, len, "large_read")) {
419
 
                struct utsname utsname;
420
 
                unsigned kmaj, kmin;
421
 
                res = uname(&utsname);
422
 
                if (res == 0 &&
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);
426
 
                    skip_option = 1;
427
 
                }
428
 
            }
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);
433
 
                goto err;
434
 
            }
435
 
            if (!skip_option) {
436
 
                if (find_mount_flag(s, len, &on, &flag)) {
437
 
                    if (on)
438
 
                        flags |= flag;
439
 
                    else
440
 
                        flags  &= ~flag;
441
 
                } else {
442
 
                    memcpy(d, s, len);
443
 
                    d += len;
444
 
                    *d++ = ',';
445
 
                }
446
 
            }
447
 
        }
448
 
        s += len;
449
 
        if (*s)
450
 
            s++;
451
 
    }
452
 
    *d = '\0';
453
 
    res = get_mnt_opts(flags, optbuf, &mnt_opts);
454
 
    if (res == -1)
455
 
        goto err;
456
 
 
457
 
    sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
458
 
            fd, rootmode, getuid(), getgid());
459
 
 
460
 
    if (check_empty &&
461
 
        fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1)
462
 
        goto err;
463
 
 
464
 
    source = malloc((fsname ? strlen(fsname) : 0) +
465
 
                    (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
466
 
 
467
 
    type = malloc((subtype ? strlen(subtype) : 0) + 32);
468
 
    if (!type || !source) {
469
 
        fprintf(stderr, "%s: failed to allocate memory\n", progname);
470
 
        goto err;
471
 
    }
472
 
 
473
 
    if (subtype)
474
 
        sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
475
 
    else
476
 
        strcpy(type, blkdev ? "fuseblk" : "fuse");
477
 
 
478
 
    if (fsname)
479
 
        strcpy(source, fsname);
480
 
    else
481
 
        strcpy(source, subtype ? subtype : dev);
482
 
 
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");
487
 
        if (fsname) {
488
 
            if (!blkdev)
489
 
                sprintf(source, "%s#%s", subtype, fsname);
490
 
        } else {
491
 
            strcpy(source, type);
492
 
        }
493
 
 
494
 
        res = mount(source, mnt, type, flags, optbuf);
495
 
    }
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);
500
 
    }
501
 
    if (res == -1) {
502
 
        int errno_save = errno;
503
 
        if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
504
 
            fprintf(stderr, "%s: 'fuseblk' support missing\n", progname);
505
 
        else
506
 
            fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save));
507
 
        goto err;
508
 
    } else {
509
 
        *sourcep = source;
510
 
        *typep = type;
511
 
        *mnt_optsp = mnt_opts;
512
 
    }
513
 
    free(optbuf);
514
 
 
515
 
    return res;
516
 
 
517
 
 err:
518
 
    free(fsname);
519
 
    free(subtype);
520
 
    free(source);
521
 
    free(type);
522
 
    free(mnt_opts);
523
 
    free(optbuf);
524
 
    return -1;
 
383
        int res;
 
384
        int flags = MS_NOSUID | MS_NODEV;
 
385
        char *optbuf;
 
386
        char *mnt_opts = NULL;
 
387
        const char *s;
 
388
        char *d;
 
389
        char *fsname = NULL;
 
390
        char *subtype = NULL;
 
391
        char *source = NULL;
 
392
        char *type = NULL;
 
393
        int check_empty = 1;
 
394
        int blkdev = 0;
 
395
 
 
396
        optbuf = (char *) malloc(strlen(opts) + 128);
 
397
        if (!optbuf) {
 
398
                fprintf(stderr, "%s: failed to allocate memory\n", progname);
 
399
                return -1;
 
400
        }
 
401
 
 
402
        for (s = opts, d = optbuf; *s;) {
 
403
                unsigned len;
 
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))
 
409
                                goto err;
 
410
                } else if (begins_with(s, subtype_str)) {
 
411
                        if (!get_string_opt(s, len, subtype_str, &subtype))
 
412
                                goto err;
 
413
                } else if (opt_eq(s, len, "blkdev")) {
 
414
                        if (getuid() != 0) {
 
415
                                fprintf(stderr,
 
416
                                        "%s: option blkdev is privileged\n",
 
417
                                        progname);
 
418
                                goto err;
 
419
                        }
 
420
                        blkdev = 1;
 
421
                } else if (opt_eq(s, len, "nonempty")) {
 
422
                        check_empty = 0;
 
423
                } else if (!begins_with(s, "fd=") &&
 
424
                           !begins_with(s, "rootmode=") &&
 
425
                           !begins_with(s, "user_id=") &&
 
426
                           !begins_with(s, "group_id=")) {
 
427
                        int on;
 
428
                        int flag;
 
429
                        int skip_option = 0;
 
430
                        if (opt_eq(s, len, "large_read")) {
 
431
                                struct utsname utsname;
 
432
                                unsigned kmaj, kmin;
 
433
                                res = uname(&utsname);
 
434
                                if (res == 0 &&
 
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);
 
439
                                        skip_option = 1;
 
440
                                }
 
441
                        }
 
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);
 
446
                                goto err;
 
447
                        }
 
448
                        if (!skip_option) {
 
449
                                if (find_mount_flag(s, len, &on, &flag)) {
 
450
                                        if (on)
 
451
                                                flags |= flag;
 
452
                                        else
 
453
                                                flags  &= ~flag;
 
454
                                } else {
 
455
                                        memcpy(d, s, len);
 
456
                                        d += len;
 
457
                                        *d++ = ',';
 
458
                                }
 
459
                        }
 
460
                }
 
461
                s += len;
 
462
                if (*s)
 
463
                        s++;
 
464
        }
 
465
        *d = '\0';
 
466
        res = get_mnt_opts(flags, optbuf, &mnt_opts);
 
467
        if (res == -1)
 
468
                goto err;
 
469
 
 
470
        sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
 
471
                fd, rootmode, getuid(), getgid());
 
472
 
 
473
        if (check_empty &&
 
474
            fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1)
 
475
                goto err;
 
476
 
 
477
        source = malloc((fsname ? strlen(fsname) : 0) +
 
478
                        (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
 
479
 
 
480
        type = malloc((subtype ? strlen(subtype) : 0) + 32);
 
481
        if (!type || !source) {
 
482
                fprintf(stderr, "%s: failed to allocate memory\n", progname);
 
483
                goto err;
 
484
        }
 
485
 
 
486
        if (subtype)
 
487
                sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
 
488
        else
 
489
                strcpy(type, blkdev ? "fuseblk" : "fuse");
 
490
 
 
491
        if (fsname)
 
492
                strcpy(source, fsname);
 
493
        else
 
494
                strcpy(source, subtype ? subtype : dev);
 
495
 
 
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");
 
500
                if (fsname) {
 
501
                        if (!blkdev)
 
502
                                sprintf(source, "%s#%s", subtype, fsname);
 
503
                } else {
 
504
                        strcpy(source, type);
 
505
                }
 
506
 
 
507
                res = mount(source, mnt, type, flags, optbuf);
 
508
        }
 
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);
 
514
        }
 
515
        if (res == -1) {
 
516
                int errno_save = errno;
 
517
                if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
 
518
                        fprintf(stderr, "%s: 'fuseblk' support missing\n",
 
519
                                progname);
 
520
                else
 
521
                        fprintf(stderr, "%s: mount failed: %s\n", progname,
 
522
                                strerror(errno_save));
 
523
                goto err;
 
524
        } else {
 
525
                *sourcep = source;
 
526
                *typep = type;
 
527
                *mnt_optsp = mnt_opts;
 
528
        }
 
529
        free(optbuf);
 
530
 
 
531
        return res;
 
532
 
 
533
err:
 
534
        free(fsname);
 
535
        free(subtype);
 
536
        free(source);
 
537
        free(type);
 
538
        free(mnt_opts);
 
539
        free(optbuf);
 
540
        return -1;
525
541
}
526
542
 
527
543
static int check_version(const char *dev)
528
544
{
529
 
    int res;
530
 
    int majorver;
531
 
    int minorver;
532
 
    const char *version_file;
533
 
    FILE *vf;
534
 
 
535
 
    if (strcmp(dev, FUSE_DEV_OLD) != 0)
536
 
        return 0;
537
 
 
538
 
    version_file = FUSE_VERSION_FILE_OLD;
539
 
    vf = fopen(version_file, "r");
540
 
    if (vf == NULL) {
541
 
        fprintf(stderr, "%s: kernel interface too old\n", progname);
542
 
        return -1;
543
 
    }
544
 
    res = fscanf(vf, "%i.%i", &majorver, &minorver);
545
 
    fclose(vf);
546
 
    if (res != 2) {
547
 
        fprintf(stderr, "%s: error reading %s\n", progname, version_file);
548
 
        return -1;
549
 
    }
550
 
     if (majorver < 3) {
551
 
        fprintf(stderr, "%s: kernel interface too old\n", progname);
552
 
        return -1;
553
 
    }
554
 
    return 0;
 
545
        int res;
 
546
        int majorver;
 
547
        int minorver;
 
548
        const char *version_file;
 
549
        FILE *vf;
 
550
 
 
551
        if (strcmp(dev, FUSE_DEV_OLD) != 0)
 
552
                return 0;
 
553
 
 
554
        version_file = FUSE_VERSION_FILE_OLD;
 
555
        vf = fopen(version_file, "r");
 
556
        if (vf == NULL) {
 
557
                fprintf(stderr, "%s: kernel interface too old\n", progname);
 
558
                return -1;
 
559
        }
 
560
        res = fscanf(vf, "%i.%i", &majorver, &minorver);
 
561
        fclose(vf);
 
562
        if (res != 2) {
 
563
                fprintf(stderr, "%s: error reading %s\n", progname,
 
564
                        version_file);
 
565
                return -1;
 
566
        }
 
567
        if (majorver < 3) {
 
568
                fprintf(stderr, "%s: kernel interface too old\n", progname);
 
569
                return -1;
 
570
        }
 
571
        return 0;
555
572
}
556
573
 
557
574
static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
558
 
                      int *mountpoint_fd)
 
575
                      int *mountpoint_fd)
559
576
{
560
 
    int res;
561
 
    const char *mnt = *mntp;
562
 
    const char *origmnt = mnt;
563
 
 
564
 
    res = lstat(mnt, stbuf);
565
 
    if (res == -1) {
566
 
        fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
567
 
                progname, mnt, strerror(errno));
568
 
        return -1;
569
 
    }
570
 
 
571
 
    /* No permission checking is done for root */
572
 
    if (getuid() == 0)
573
 
        return 0;
574
 
 
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));
580
 
            return -1;
581
 
        }
582
 
        res = chdir(mnt);
583
 
        if (res == -1) {
584
 
            fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n",
585
 
                    progname, strerror(errno));
586
 
            return -1;
587
 
        }
588
 
        mnt = *mntp = ".";
589
 
        res = lstat(mnt, stbuf);
590
 
        if (res == -1) {
591
 
            fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
592
 
                    progname, origmnt, strerror(errno));
593
 
            return -1;
594
 
        }
595
 
 
596
 
        if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
597
 
            fprintf(stderr, "%s: mountpoint %s not owned by user\n",
598
 
                    progname, origmnt);
599
 
            return -1;
600
 
        }
601
 
 
602
 
        res = access(mnt, W_OK);
603
 
        if (res == -1) {
604
 
            fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
605
 
                    progname, origmnt);
606
 
            return -1;
607
 
        }
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,
613
 
                    strerror(errno));
614
 
            return -1;
615
 
        }
616
 
        res = fstat(*mountpoint_fd, stbuf);
617
 
        if (res == -1) {
618
 
            fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
619
 
                    progname, mnt, strerror(errno));
620
 
            return -1;
621
 
        }
622
 
        if (!S_ISREG(stbuf->st_mode)) {
623
 
            fprintf(stderr, "%s: mountpoint %s is no longer a regular file\n",
624
 
                    progname, mnt);
625
 
            return -1;
626
 
        }
627
 
 
628
 
        sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
629
 
        *mntp = procfile;
630
 
    } else {
631
 
        fprintf(stderr,
632
 
                "%s: mountpoint %s is not a directory or a regular file\n",
633
 
                progname, mnt);
634
 
        return -1;
635
 
    }
636
 
 
637
 
 
638
 
    return 0;
 
577
        int res;
 
578
        const char *mnt = *mntp;
 
579
        const char *origmnt = mnt;
 
580
 
 
581
        res = lstat(mnt, stbuf);
 
582
        if (res == -1) {
 
583
                fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
 
584
                        progname, mnt, strerror(errno));
 
585
                return -1;
 
586
        }
 
587
 
 
588
        /* No permission checking is done for root */
 
589
        if (getuid() == 0)
 
590
                return 0;
 
591
 
 
592
        if (S_ISDIR(stbuf->st_mode)) {
 
593
                *currdir_fd = open(".", O_RDONLY);
 
594
                if (*currdir_fd == -1) {
 
595
                        fprintf(stderr,
 
596
                                "%s: failed to open current directory: %s\n",
 
597
                                progname, strerror(errno));
 
598
                        return -1;
 
599
                }
 
600
                res = chdir(mnt);
 
601
                if (res == -1) {
 
602
                        fprintf(stderr,
 
603
                                "%s: failed to chdir to mountpoint: %s\n",
 
604
                                progname, strerror(errno));
 
605
                        return -1;
 
606
                }
 
607
                mnt = *mntp = ".";
 
608
                res = lstat(mnt, stbuf);
 
609
                if (res == -1) {
 
610
                        fprintf(stderr,
 
611
                                "%s: failed to access mountpoint %s: %s\n",
 
612
                                progname, origmnt, strerror(errno));
 
613
                        return -1;
 
614
                }
 
615
 
 
616
                if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
 
617
                        fprintf(stderr, "%s: mountpoint %s not owned by user\n",
 
618
                                progname, origmnt);
 
619
                        return -1;
 
620
                }
 
621
 
 
622
                res = access(mnt, W_OK);
 
623
                if (res == -1) {
 
624
                        fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
 
625
                                progname, origmnt);
 
626
                        return -1;
 
627
                }
 
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));
 
634
                        return -1;
 
635
                }
 
636
                res = fstat(*mountpoint_fd, stbuf);
 
637
                if (res == -1) {
 
638
                        fprintf(stderr,
 
639
                                "%s: failed to access mountpoint %s: %s\n",
 
640
                                progname, mnt, strerror(errno));
 
641
                        return -1;
 
642
                }
 
643
                if (!S_ISREG(stbuf->st_mode)) {
 
644
                        fprintf(stderr,
 
645
                                "%s: mountpoint %s is no longer a regular file\n",
 
646
                                progname, mnt);
 
647
                        return -1;
 
648
                }
 
649
 
 
650
                sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
 
651
                *mntp = procfile;
 
652
        } else {
 
653
                fprintf(stderr,
 
654
                        "%s: mountpoint %s is not a directory or a regular file\n",
 
655
                        progname, mnt);
 
656
                return -1;
 
657
        }
 
658
 
 
659
 
 
660
        return 0;
639
661
}
640
662
 
641
663
static int try_open(const char *dev, char **devp, int silent)
642
664
{
643
 
    int fd = open(dev, O_RDWR);
644
 
    if (fd != -1) {
645
 
        *devp = strdup(dev);
646
 
        if (*devp == NULL) {
647
 
            fprintf(stderr, "%s: failed to allocate memory\n", progname);
648
 
            close(fd);
649
 
            fd = -1;
650
 
        }
651
 
    } else if (errno == ENODEV ||
652
 
               errno == ENOENT) /* check for ENOENT too, for the udev case */
653
 
        return -2;
654
 
    else if (!silent) {
655
 
        fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
656
 
                strerror(errno));
657
 
    }
658
 
    return fd;
 
665
        int fd = open(dev, O_RDWR);
 
666
        if (fd != -1) {
 
667
                *devp = strdup(dev);
 
668
                if (*devp == NULL) {
 
669
                        fprintf(stderr, "%s: failed to allocate memory\n",
 
670
                                progname);
 
671
                        close(fd);
 
672
                        fd = -1;
 
673
                }
 
674
        } else if (errno == ENODEV ||
 
675
                   errno == ENOENT)/* check for ENOENT too, for the udev case */
 
676
                return -2;
 
677
        else if (!silent) {
 
678
                fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
 
679
                        strerror(errno));
 
680
        }
 
681
        return fd;
659
682
}
660
683
 
661
684
static int try_open_fuse_device(char **devp)
662
685
{
663
 
    int fd;
664
 
    int err;
665
 
 
666
 
    drop_privs();
667
 
    fd = try_open(FUSE_DEV_NEW, devp, 0);
668
 
    restore_privs();
669
 
    if (fd >= 0)
670
 
        return fd;
671
 
 
672
 
    err = fd;
673
 
    fd = try_open(FUSE_DEV_OLD, devp, 1);
674
 
    if (fd >= 0)
675
 
        return fd;
676
 
 
677
 
    return err;
 
686
        int fd;
 
687
        int err;
 
688
 
 
689
        drop_privs();
 
690
        fd = try_open(FUSE_DEV_NEW, devp, 0);
 
691
        restore_privs();
 
692
        if (fd >= 0)
 
693
                return fd;
 
694
 
 
695
        err = fd;
 
696
        fd = try_open(FUSE_DEV_OLD, devp, 1);
 
697
        if (fd >= 0)
 
698
                return fd;
 
699
 
 
700
        return err;
678
701
}
679
702
 
680
703
static int open_fuse_device(char **devp)
681
704
{
682
 
    int fd = try_open_fuse_device(devp);
683
 
    if (fd >= -1)
684
 
        return fd;
685
 
 
686
 
    fprintf(stderr, "%s: fuse device not found, try 'modprobe fuse' first\n",
687
 
            progname);
688
 
 
689
 
    return -1;
 
705
        int fd = try_open_fuse_device(devp);
 
706
        if (fd >= -1)
 
707
                return fd;
 
708
 
 
709
        fprintf(stderr,
 
710
                "%s: fuse device not found, try 'modprobe fuse' first\n",
 
711
                progname);
 
712
 
 
713
        return -1;
690
714
}
691
715
 
692
716
 
693
717
static int mount_fuse(const char *mnt, const char *opts)
694
718
{
695
 
    int res;
696
 
    int fd;
697
 
    char *dev;
698
 
    struct stat stbuf;
699
 
    char *type = NULL;
700
 
    char *source = NULL;
701
 
    char *mnt_opts = NULL;
702
 
    const char *real_mnt = mnt;
703
 
    int currdir_fd = -1;
704
 
    int mountpoint_fd = -1;
705
 
 
706
 
    fd = open_fuse_device(&dev);
707
 
    if (fd == -1)
708
 
        return -1;
709
 
 
710
 
    drop_privs();
711
 
    read_conf();
712
 
 
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);
717
 
            close(fd);
718
 
            return -1;
719
 
        }
720
 
    }
721
 
 
722
 
    res = check_version(dev);
723
 
    if (res != -1) {
724
 
        res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd);
725
 
        restore_privs();
726
 
        if (res != -1)
727
 
            res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, fd, opts,
728
 
                           dev, &source, &mnt_opts, stbuf.st_size);
729
 
    } else
730
 
        restore_privs();
731
 
 
732
 
    if (currdir_fd != -1) {
733
 
        fchdir(currdir_fd);
734
 
        close(currdir_fd);
735
 
    }
736
 
    if (mountpoint_fd != -1)
737
 
        close(mountpoint_fd);
738
 
 
739
 
    if (res == -1) {
740
 
        close(fd);
741
 
        return -1;
742
 
    }
743
 
 
744
 
    if (geteuid() == 0) {
745
 
        res = add_mount(source, mnt, type, mnt_opts);
746
 
        if (res == -1) {
747
 
            umount2(mnt, 2); /* lazy umount */
748
 
            close(fd);
749
 
            return -1;
750
 
        }
751
 
    }
752
 
 
753
 
    free(source);
754
 
    free(type);
755
 
    free(mnt_opts);
756
 
    free(dev);
757
 
 
758
 
    return fd;
 
719
        int res;
 
720
        int fd;
 
721
        char *dev;
 
722
        struct stat stbuf;
 
723
        char *type = NULL;
 
724
        char *source = NULL;
 
725
        char *mnt_opts = NULL;
 
726
        const char *real_mnt = mnt;
 
727
        int currdir_fd = -1;
 
728
        int mountpoint_fd = -1;
 
729
 
 
730
        fd = open_fuse_device(&dev);
 
731
        if (fd == -1)
 
732
                return -1;
 
733
 
 
734
        drop_privs();
 
735
        read_conf();
 
736
 
 
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);
 
741
                        close(fd);
 
742
                        return -1;
 
743
                }
 
744
        }
 
745
 
 
746
        res = check_version(dev);
 
747
        if (res != -1) {
 
748
                res = check_perm(&real_mnt, &stbuf, &currdir_fd,
 
749
                                 &mountpoint_fd);
 
750
                restore_privs();
 
751
                if (res != -1)
 
752
                        res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
 
753
                                       fd, opts, dev, &source, &mnt_opts,
 
754
                                       stbuf.st_size);
 
755
        } else
 
756
                restore_privs();
 
757
 
 
758
        if (currdir_fd != -1) {
 
759
                fchdir(currdir_fd);
 
760
                close(currdir_fd);
 
761
        }
 
762
        if (mountpoint_fd != -1)
 
763
                close(mountpoint_fd);
 
764
 
 
765
        if (res == -1) {
 
766
                close(fd);
 
767
                return -1;
 
768
        }
 
769
 
 
770
        if (geteuid() == 0) {
 
771
                res = add_mount(source, mnt, type, mnt_opts);
 
772
                if (res == -1) {
 
773
                        umount2(mnt, 2); /* lazy umount */
 
774
                        close(fd);
 
775
                        return -1;
 
776
                }
 
777
        }
 
778
 
 
779
        free(source);
 
780
        free(type);
 
781
        free(mnt_opts);
 
782
        free(dev);
 
783
 
 
784
        return fd;
759
785
}
760
786
 
761
787
static int send_fd(int sock_fd, int fd)
762
788
{
763
 
    int retval;
764
 
    struct msghdr msg;
765
 
    struct cmsghdr *p_cmsg;
766
 
    struct iovec vec;
767
 
    size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
768
 
    int *p_fds;
769
 
    char sendchar = 0;
 
789
        int retval;
 
790
        struct msghdr msg;
 
791
        struct cmsghdr *p_cmsg;
 
792
        struct iovec vec;
 
793
        size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
 
794
        int *p_fds;
 
795
        char sendchar = 0;
770
796
 
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);
778
 
    *p_fds = fd;
779
 
    msg.msg_controllen = p_cmsg->cmsg_len;
780
 
    msg.msg_name = NULL;
781
 
    msg.msg_namelen = 0;
782
 
    msg.msg_iov = &vec;
783
 
    msg.msg_iovlen = 1;
784
 
    msg.msg_flags = 0;
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);
790
 
    if (retval != 1) {
791
 
        perror("sending file descriptor");
792
 
        return -1;
793
 
    }
794
 
    return 0;
 
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);
 
804
        *p_fds = fd;
 
805
        msg.msg_controllen = p_cmsg->cmsg_len;
 
806
        msg.msg_name = NULL;
 
807
        msg.msg_namelen = 0;
 
808
        msg.msg_iov = &vec;
 
809
        msg.msg_iovlen = 1;
 
810
        msg.msg_flags = 0;
 
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);
 
816
        if (retval != 1) {
 
817
                perror("sending file descriptor");
 
818
                return -1;
 
819
        }
 
820
        return 0;
795
821
}
796
822
 
797
823
static void usage(void)
798
824
{
799
 
    fprintf(stderr,
800
 
            "%s: [options] mountpoint\n"
801
 
            "Options:\n"
802
 
            " -h                print help\n"
803
 
            " -V                print version\n"
804
 
            " -o opt[,opt...]   mount options\n"
805
 
            " -u                unmount\n"
806
 
            " -q                quiet\n"
807
 
            " -z                lazy unmount\n",
808
 
            progname);
809
 
    exit(1);
 
825
        fprintf(stderr,
 
826
                "%s: [options] mountpoint\n"
 
827
                "Options:\n"
 
828
                " -h                print help\n"
 
829
                " -V                print version\n"
 
830
                " -o opt[,opt...]   mount options\n"
 
831
                " -u                unmount\n"
 
832
                " -q                quiet\n"
 
833
                " -z                lazy unmount\n",
 
834
                progname);
 
835
        exit(1);
810
836
}
811
837
 
812
838
static void show_version(void)
813
839
{
814
 
    printf("fusermount version: %s\n", PACKAGE_VERSION);
815
 
    exit(0);
 
840
        printf("fusermount version: %s\n", PACKAGE_VERSION);
 
841
        exit(0);
816
842
}
817
843
 
818
844
int main(int argc, char *argv[])
819
845
{
820
 
    int ch;
821
 
    int fd;
822
 
    int res;
823
 
    char *origmnt;
824
 
    char *mnt;
825
 
    static int unmount = 0;
826
 
    static int lazy = 0;
827
 
    static int quiet = 0;
828
 
    char *commfd;
829
 
    int cfd;
830
 
    const char *opts = "";
831
 
 
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'},
838
 
        {0, 0, 0, 0}};
839
 
 
840
 
    progname = strdup(argv[0]);
841
 
    if (progname == NULL) {
842
 
        fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
843
 
        exit(1);
844
 
    }
845
 
 
846
 
    while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, NULL)) != -1) {
847
 
        switch (ch) {
848
 
        case 'h':
849
 
            usage();
850
 
            break;
851
 
 
852
 
        case 'V':
853
 
            show_version();
854
 
            break;
855
 
 
856
 
        case 'o':
857
 
            opts = optarg;
858
 
            break;
859
 
 
860
 
        case 'u':
861
 
            unmount = 1;
862
 
            break;
863
 
 
864
 
        case 'z':
865
 
            lazy = 1;
866
 
            break;
867
 
 
868
 
        case 'q':
869
 
            quiet = 1;
870
 
            break;
871
 
 
872
 
        default:
873
 
            exit(1);
874
 
        }
875
 
    }
876
 
 
877
 
    if (lazy && !unmount) {
878
 
        fprintf(stderr, "%s: -z can only be used with -u\n", progname);
879
 
        exit(1);
880
 
    }
881
 
 
882
 
    if (optind >= argc) {
883
 
        fprintf(stderr, "%s: missing mountpoint argument\n", progname);
884
 
        exit(1);
885
 
    }
886
 
 
887
 
    origmnt = argv[optind];
888
 
 
889
 
    drop_privs();
890
 
    mnt = fuse_mnt_resolve_path(progname, origmnt);
891
 
    restore_privs();
892
 
    if (mnt == NULL)
893
 
        exit(1);
894
 
 
895
 
    umask(033);
896
 
    if (unmount) {
897
 
        if (geteuid() == 0)
898
 
            res = unmount_fuse(mnt, quiet, lazy);
899
 
        else {
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));
904
 
        }
905
 
        if (res == -1)
906
 
            exit(1);
907
 
        return 0;
908
 
    }
909
 
 
910
 
    commfd = getenv(FUSE_COMMFD_ENV);
911
 
    if (commfd == NULL) {
912
 
        fprintf(stderr, "%s: old style mounting not supported\n", progname);
913
 
        exit(1);
914
 
    }
915
 
 
916
 
    fd = mount_fuse(mnt, opts);
917
 
    if (fd == -1)
918
 
        exit(1);
919
 
 
920
 
    cfd = atoi(commfd);
921
 
    res = send_fd(cfd, fd);
922
 
    if (res == -1)
923
 
        exit(1);
924
 
 
925
 
    return 0;
 
846
        int ch;
 
847
        int fd;
 
848
        int res;
 
849
        char *origmnt;
 
850
        char *mnt;
 
851
        static int unmount = 0;
 
852
        static int lazy = 0;
 
853
        static int quiet = 0;
 
854
        char *commfd;
 
855
        int cfd;
 
856
        const char *opts = "";
 
857
 
 
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'},
 
864
                {0, 0, 0, 0}};
 
865
 
 
866
        progname = strdup(argv[0]);
 
867
        if (progname == NULL) {
 
868
                fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
 
869
                exit(1);
 
870
        }
 
871
 
 
872
        while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
 
873
                                 NULL)) != -1) {
 
874
                switch (ch) {
 
875
                case 'h':
 
876
                        usage();
 
877
                        break;
 
878
 
 
879
                case 'V':
 
880
                        show_version();
 
881
                        break;
 
882
 
 
883
                case 'o':
 
884
                        opts = optarg;
 
885
                        break;
 
886
 
 
887
                case 'u':
 
888
                        unmount = 1;
 
889
                        break;
 
890
 
 
891
                case 'z':
 
892
                        lazy = 1;
 
893
                        break;
 
894
 
 
895
                case 'q':
 
896
                        quiet = 1;
 
897
                        break;
 
898
 
 
899
                default:
 
900
                        exit(1);
 
901
                }
 
902
        }
 
903
 
 
904
        if (lazy && !unmount) {
 
905
                fprintf(stderr, "%s: -z can only be used with -u\n", progname);
 
906
                exit(1);
 
907
        }
 
908
 
 
909
        if (optind >= argc) {
 
910
                fprintf(stderr, "%s: missing mountpoint argument\n", progname);
 
911
                exit(1);
 
912
        }
 
913
 
 
914
        origmnt = argv[optind];
 
915
 
 
916
        drop_privs();
 
917
        mnt = fuse_mnt_resolve_path(progname, origmnt);
 
918
        restore_privs();
 
919
        if (mnt == NULL)
 
920
                exit(1);
 
921
 
 
922
        umask(033);
 
923
        if (unmount) {
 
924
                if (geteuid() == 0)
 
925
                        res = unmount_fuse(mnt, quiet, lazy);
 
926
                else {
 
927
                        res = umount2(mnt, lazy ? 2 : 0);
 
928
                        if (res == -1 && !quiet)
 
929
                                fprintf(stderr,
 
930
                                        "%s: failed to unmount %s: %s\n",
 
931
                                        progname, mnt, strerror(errno));
 
932
                }
 
933
                if (res == -1)
 
934
                        exit(1);
 
935
                return 0;
 
936
        }
 
937
 
 
938
        commfd = getenv(FUSE_COMMFD_ENV);
 
939
        if (commfd == NULL) {
 
940
                fprintf(stderr, "%s: old style mounting not supported\n",
 
941
                        progname);
 
942
                exit(1);
 
943
        }
 
944
 
 
945
        fd = mount_fuse(mnt, opts);
 
946
        if (fd == -1)
 
947
                exit(1);
 
948
 
 
949
        cfd = atoi(commfd);
 
950
        res = send_fd(cfd, fd);
 
951
        if (res == -1)
 
952
                exit(1);
 
953
 
 
954
        return 0;
926
955
}