⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fusermount.c

📁 UNIX/LINUX下面的用户文件系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    FUSE: Filesystem in Userspace    Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>    This program can be distributed under the terms of the GNU GPL.    See the file COPYING.*//* This program does the mounting and unmounting of FUSE filesystems *//* * NOTE: This program should be part of (or be called from) /bin/mount * * Unless that is done, operations on /etc/mtab are not under lock, and so * data in this file may be lost. (I will _not_ reimplement that locking, * and anyway that should be done in libc, if possible.  But probably it * isn't). */#include <config.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <getopt.h>#include <errno.h>#include <fcntl.h>#include <pwd.h>#include <mntent.h>#include <dirent.h>#include <sys/param.h>#include <sys/wait.h>#include <sys/stat.h>#include <sys/mount.h>#include <sys/fsuid.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/utsname.h>#include <sys/sysmacros.h>#define FUSE_COMMFD_ENV         "_FUSE_COMMFD"#define FUSE_DEV_OLD "/proc/fs/fuse/dev"#define FUSE_DEV_NEW "/dev/fuse"#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"#define FUSE_CONF "/etc/fuse.conf"#ifndef MS_DIRSYNC#define MS_DIRSYNC 128#endifstatic const char *progname;static int user_allow_other = 0;static int mount_max = 1000;static const char *get_user_name(void){    struct passwd *pw = getpwuid(getuid());    if (pw != NULL && pw->pw_name != NULL)        return pw->pw_name;    else {        fprintf(stderr, "%s: could not determine username\n", progname);        return NULL;    }}static uid_t oldfsuid;static gid_t oldfsgid;static void drop_privs(void){    if (getuid() != 0) {        oldfsuid = setfsuid(getuid());        oldfsgid = setfsgid(getgid());    }}static void restore_privs(void){    if (getuid() != 0) {        setfsuid(oldfsuid);        setfsgid(oldfsgid);    }}static int do_unmount(const char *mnt, int quiet, int lazy){    int res = umount2(mnt, lazy ? 2 : 0);    if (res == -1) {        if (!quiet)            fprintf(stderr, "%s: failed to unmount %s: %s\n",                    progname, mnt, strerror(errno));    }    return res;}#ifndef IGNORE_MTAB/* use a lock file so that multiple fusermount processes don't try and   modify the mtab file at once! */static int lock_mtab(void){    const char *mtab_lock = _PATH_MOUNTED ".fuselock";    int mtablock;    int res;    mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);    if (mtablock >= 0) {        res = lockf(mtablock, F_LOCK, 0);        if (res < 0)            fprintf(stderr, "%s: error getting lock", progname);    } else        fprintf(stderr, "%s: unable to open fuse lock file\n", progname);    return mtablock;}static void unlock_mtab(int mtablock){    if (mtablock >= 0) {	lockf(mtablock, F_ULOCK, 0);	close(mtablock);    }}/* Glibc addmntent() doesn't encode '\n', misencodes '\t' as '\n'   (version 2.3.2), and encodes '\\' differently as mount(8).  So   let's not allow those characters, they are not all that usual in   filenames. */static int check_name(const char *name){    char *s;    for (s = "\n\t\\"; *s; s++) {        if (strchr(name, *s)) {            fprintf(stderr, "%s: illegal character 0x%02x in mount entry\n",                    progname, *s);            return -1;        }    }    return 0;}static int add_mount(const char *fsname, const char *mnt, const char *type,                     const char *opts){    int res;    const char *mtab = _PATH_MOUNTED;    struct mntent ent;    FILE *fp;    if (check_name(fsname) == -1 || check_name(mnt) == -1 ||        check_name(type) == -1 || check_name(opts) == -1)        return -1;    fp = setmntent(mtab, "a");    if (fp == NULL) {	fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,		strerror(errno));	return -1;    }    ent.mnt_fsname = (char *) fsname;    ent.mnt_dir = (char *) mnt;    ent.mnt_type = (char *) type;    ent.mnt_opts = (char *) opts;    ent.mnt_freq = 0;    ent.mnt_passno = 0;    res = addmntent(fp, &ent);    if (res != 0) {        fprintf(stderr, "%s: failed to add entry to %s: %s\n", progname,                mtab, strerror(errno));        return -1;    }    endmntent(fp);    return 0;}static int unmount_rename(const char *mtab, const char *mtab_new){    int res;    struct stat sbuf;    if (stat(mtab, &sbuf) == 0)        chown(mtab_new, sbuf.st_uid, sbuf.st_gid);    res = rename(mtab_new, mtab);    if (res == -1) {        fprintf(stderr, "%s: failed to rename %s to %s: %s\n", progname,                mtab_new, mtab, strerror(errno));        return -1;    }    return 0;}static int unmount_fuse(const char *mnt, int quiet, int lazy){    int res;    struct mntent *entp;    FILE *fp;    FILE *newfp = NULL;    const char *user = NULL;    char uidstr[32];    unsigned uidlen = 0;    int found;    int issymlink = 0;    struct stat stbuf;    const char *mtab = _PATH_MOUNTED;    const char *mtab_new = _PATH_MOUNTED "~fuse~";    if (lstat(mtab, &stbuf) != -1 && S_ISLNK(stbuf.st_mode))        issymlink = 1;    fp = setmntent(mtab, "r");    if (fp == NULL) {	fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,		strerror(errno));	return -1;    }    if (!issymlink) {        newfp = setmntent(mtab_new, "w");        if (newfp == NULL) {            fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab_new,                    strerror(errno));            endmntent(fp);            return -1;        }    }    if (getuid() != 0) {        user = get_user_name();        if (user == NULL)            goto err_endmntent;        uidlen = sprintf(uidstr, "%u", getuid());    }    found = 0;    while ((entp = getmntent(fp)) != NULL) {        int removed = 0;        if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&           strcmp(entp->mnt_type, "fuse") == 0) {            if (user == NULL)                removed = 1;            else {                char *p = strstr(entp->mnt_opts, "user=");                if (p && (p == entp->mnt_opts || *(p-1) == ',') &&                    strcmp(p + 5, user) == 0)                    removed = 1;                /* /etc/mtab is a link pointing to /proc/mounts: */                else if ((p = strstr(entp->mnt_opts, "user_id=")) &&                         (p == entp->mnt_opts || *(p-1) == ',') &&                         strncmp(p + 8, uidstr, uidlen) == 0 &&                         (*(p+8+uidlen) == ',' || *(p+8+uidlen) == '\0'))                    removed = 1;            }        }        if (removed)            found = 1;        else if (!issymlink) {            res = addmntent(newfp, entp);            if (res != 0) {                fprintf(stderr, "%s: failed to add entry to %s: %s\n",                        progname, mtab_new, strerror(errno));            }        }    }    endmntent(fp);    if (!issymlink)        endmntent(newfp);    if (!found) {        if (!quiet)            fprintf(stderr, "%s: entry for %s not found in %s\n", progname,                    mnt, mtab);        goto err;    }    drop_privs();    res = do_unmount(mnt, quiet, lazy);    restore_privs();    if (res == -1)        goto err;    if (!issymlink) {        res = unmount_rename(mtab, mtab_new);        if (res == -1)            goto err;    }    return 0; err_endmntent:    if (!issymlink)        endmntent(newfp);    endmntent(fp); err:    if (!issymlink)        unlink(mtab_new);    return -1;}static int count_fuse_fs(void){    struct mntent *entp;    int count = 0;    const char *mtab = _PATH_MOUNTED;    FILE *fp = setmntent(mtab, "r");    if (fp == NULL) {        fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,                strerror(errno));        return -1;    }    while ((entp = getmntent(fp)) != NULL) {        if (strcmp(entp->mnt_type, "fuse") == 0)            count ++;    }    endmntent(fp);    return count;}#else /* IGNORE_MTAB */static int lock_mtab(){    return 0;}static void unlock_mtab(int mtablock){    (void) mtablock;}static int count_fuse_fs(){    return 0;}static int add_mount(const char *fsname, const char *mnt, const char *type,                     const char *opts){    (void) fsname;    (void) mnt;    (void) type;    (void) opts;    return 0;}static int unmount_fuse(const char *mnt, int quiet, int lazy){    return do_unmount(mnt, quiet, lazy);}#endif /* IGNORE_MTAB */static void strip_line(char *line){    char *s = strchr(line, '#');    if (s != NULL)        s[0] = '\0';    for (s = line + strlen(line) - 1; s >= line && isspace((unsigned char) *s); s--);    s[1] = '\0';    for (s = line; isspace((unsigned char) *s); s++);    if (s != line)        memmove(line, s, strlen(s)+1);}static void parse_line(char *line, int linenum){    int tmp;    if (strcmp(line, "user_allow_other") == 0)        user_allow_other = 1;    else if (sscanf(line, "mount_max = %i", &tmp) == 1)        mount_max = tmp;    else if(line[0])        fprintf(stderr, "%s: unknown parameter in %s at line %i: '%s'\n",                progname, FUSE_CONF, linenum, line);}static void read_conf(void){    FILE *fp = fopen(FUSE_CONF, "r");    if (fp != NULL) {        int linenum = 1;        char line[256];        int isnewline = 1;        while (fgets(line, sizeof(line), fp) != NULL) {            if (isnewline) {                if (line[strlen(line)-1] == '\n') {                    strip_line(line);                    parse_line(line, linenum);                } else {                    fprintf(stderr, "%s: reading %s: line %i too long\n",                            progname, FUSE_CONF, linenum);                    isnewline = 0;                }            } else if(line[strlen(line)-1] == '\n')                isnewline = 1;            if (isnewline)                linenum ++;        }        fclose(fp);    } else if (errno != ENOENT) {        fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF,                strerror(errno));    }}static int begins_with(const char *s, const char *beg){    if (strncmp(s, beg, strlen(beg)) == 0)        return 1;    else        return 0;}struct mount_flags {    const char *opt;    unsigned long flag;    int on;    int safe;};static struct mount_flags mount_flags[] = {    {"rw",      MS_RDONLY,      0, 1},    {"ro",      MS_RDONLY,      1, 1},    {"suid",    MS_NOSUID,      0, 0},    {"nosuid",  MS_NOSUID,      1, 1},    {"dev",     MS_NODEV,       0, 0},    {"nodev",   MS_NODEV,       1, 1},    {"exec",    MS_NOEXEC,      0, 1},    {"noexec",  MS_NOEXEC,      1, 1},    {"async",   MS_SYNCHRONOUS, 0, 1},    {"sync",    MS_SYNCHRONOUS, 1, 1},    {"atime",   MS_NOATIME,     0, 1},    {"noatime", MS_NOATIME,     1, 1},    {"dirsync", MS_DIRSYNC,     1, 1},    {NULL,      0,              0, 0}};static int find_mount_flag(const char *s, unsigned len, int *on, int *flag){    int i;    for (i = 0; mount_flags[i].opt != NULL; i++) {        const char *opt = mount_flags[i].opt;        if (strlen(opt) == len && strncmp(opt, s, len) == 0) {            *on = mount_flags[i].on;            *flag = mount_flags[i].flag;            if (!mount_flags[i].safe && getuid() != 0) {                *flag = 0;                fprintf(stderr, "%s: unsafe option %s ignored\n",                        progname, opt);            }            return 1;        }    }    return 0;}static int add_option(char **optsp, const char *opt, unsigned expand){    char *newopts;    if (*optsp == NULL)        newopts = strdup(opt);    else {        unsigned oldsize = strlen(*optsp);        unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;        newopts = (char *) realloc(*optsp, newsize);        if (newopts)            sprintf(newopts + oldsize, ",%s", opt);    }    if (newopts == NULL) {        fprintf(stderr, "%s: failed to allocate memory\n", progname);        return -1;    }    *optsp = newopts;    return 0;}static int get_mnt_opts(int flags, char *opts, char **mnt_optsp){    int i;    int l;    if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)        return -1;    for (i = 0; mount_flags[i].opt != NULL; i++) {        if (mount_flags[i].on && (flags & mount_flags[i].flag) &&            add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)            return -1;    }    if (add_option(mnt_optsp, opts, 0) == -1)        return -1;    /* remove comma from end of opts*/    l = strlen(*mnt_optsp);    if ((*mnt_optsp)[l-1] == ',')        (*mnt_optsp)[l-1] = '\0';    if (getuid() != 0) {        const char *user = get_user_name();        if (user == NULL)            return -1;        if (add_option(mnt_optsp, "user=", strlen(user)) == -1)            return -1;        strcat(*mnt_optsp, user);    }    return 0;}static int opt_eq(const char *s, unsigned len, const char *opt){    if(strlen(opt) == len && strncmp(s, opt, len) == 0)        return 1;    else        return 0;}static int check_mountpoint_empty(const char *mnt, mode_t rootmode,                                  off_t rootsize){    int isempty = 1;    if (S_ISDIR(rootmode)) {        struct dirent *ent;        DIR *dp = opendir(mnt);        if (dp == NULL) {            fprintf(stderr, "%s: failed to mountpoint for reading: %s\n",                    progname, strerror(errno));            return -1;        }        while ((ent = readdir(dp)) != NULL) {            if (strcmp(ent->d_name, ".") != 0 &&                strcmp(ent->d_name, "..") != 0) {                isempty = 0;                break;            }        }        closedir(dp);    } else if (rootsize)        isempty = 0;    if (!isempty) {        fprintf(stderr, "%s: mountpoint is not empty\n", progname);        fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);        return -1;    }    return 0;}static int do_mount(const char *mnt, const char *type, mode_t rootmode,                    int fd, const char *opts, const char *dev, char **fsnamep,                    char **mnt_optsp, off_t rootsize){    int res;    int flags = MS_NOSUID | MS_NODEV;    char *optbuf;    char *mnt_opts = NULL;    const char *s;    char *d;    char *fsname = NULL;    int check_empty = 1;    optbuf = (char *) malloc(strlen(opts) + 128);    if (!optbuf) {        fprintf(stderr, "%s: failed to allocate memory\n", progname);        return -1;    }    for (s = opts, d = optbuf; *s;) {        unsigned len;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -