16881f68fSopenharmony_ci/* 26881f68fSopenharmony_ci FUSE: Filesystem in Userspace 36881f68fSopenharmony_ci Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 46881f68fSopenharmony_ci 56881f68fSopenharmony_ci Architecture-independent mounting code. 66881f68fSopenharmony_ci 76881f68fSopenharmony_ci This program can be distributed under the terms of the GNU LGPLv2. 86881f68fSopenharmony_ci See the file COPYING.LIB. 96881f68fSopenharmony_ci*/ 106881f68fSopenharmony_ci 116881f68fSopenharmony_ci#include "fuse_config.h" 126881f68fSopenharmony_ci#include "mount_util.h" 136881f68fSopenharmony_ci 146881f68fSopenharmony_ci#include <stdio.h> 156881f68fSopenharmony_ci#include <unistd.h> 166881f68fSopenharmony_ci#include <stdlib.h> 176881f68fSopenharmony_ci#include <string.h> 186881f68fSopenharmony_ci#include <signal.h> 196881f68fSopenharmony_ci#include <dirent.h> 206881f68fSopenharmony_ci#include <errno.h> 216881f68fSopenharmony_ci#include <fcntl.h> 226881f68fSopenharmony_ci#include <limits.h> 236881f68fSopenharmony_ci#include <paths.h> 246881f68fSopenharmony_ci#if !defined( __NetBSD__) && !defined(__FreeBSD__) && !defined(__DragonFly__) 256881f68fSopenharmony_ci#include <mntent.h> 266881f68fSopenharmony_ci#else 276881f68fSopenharmony_ci#define IGNORE_MTAB 286881f68fSopenharmony_ci#endif 296881f68fSopenharmony_ci#include <sys/stat.h> 306881f68fSopenharmony_ci#include <sys/wait.h> 316881f68fSopenharmony_ci 326881f68fSopenharmony_ci#include "fuse_mount_compat.h" 336881f68fSopenharmony_ci 346881f68fSopenharmony_ci#include <sys/param.h> 356881f68fSopenharmony_ci 366881f68fSopenharmony_ci#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 376881f68fSopenharmony_ci#define umount2(mnt, flags) unmount(mnt, ((flags) == 2) ? MNT_FORCE : 0) 386881f68fSopenharmony_ci#endif 396881f68fSopenharmony_ci 406881f68fSopenharmony_ci#ifdef IGNORE_MTAB 416881f68fSopenharmony_ci#define mtab_needs_update(mnt) 0 426881f68fSopenharmony_ci#else 436881f68fSopenharmony_cistatic int mtab_needs_update(const char *mnt) 446881f68fSopenharmony_ci{ 456881f68fSopenharmony_ci int res; 466881f68fSopenharmony_ci struct stat stbuf; 476881f68fSopenharmony_ci 486881f68fSopenharmony_ci /* If mtab is within new mount, don't touch it */ 496881f68fSopenharmony_ci if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && 506881f68fSopenharmony_ci _PATH_MOUNTED[strlen(mnt)] == '/') 516881f68fSopenharmony_ci return 0; 526881f68fSopenharmony_ci 536881f68fSopenharmony_ci /* 546881f68fSopenharmony_ci * Skip mtab update if /etc/mtab: 556881f68fSopenharmony_ci * 566881f68fSopenharmony_ci * - doesn't exist, 576881f68fSopenharmony_ci * - is a symlink, 586881f68fSopenharmony_ci * - is on a read-only filesystem. 596881f68fSopenharmony_ci */ 606881f68fSopenharmony_ci res = lstat(_PATH_MOUNTED, &stbuf); 616881f68fSopenharmony_ci if (res == -1) { 626881f68fSopenharmony_ci if (errno == ENOENT) 636881f68fSopenharmony_ci return 0; 646881f68fSopenharmony_ci } else { 656881f68fSopenharmony_ci uid_t ruid; 666881f68fSopenharmony_ci int err; 676881f68fSopenharmony_ci 686881f68fSopenharmony_ci if (S_ISLNK(stbuf.st_mode)) 696881f68fSopenharmony_ci return 0; 706881f68fSopenharmony_ci 716881f68fSopenharmony_ci ruid = getuid(); 726881f68fSopenharmony_ci if (ruid != 0) 736881f68fSopenharmony_ci setreuid(0, -1); 746881f68fSopenharmony_ci 756881f68fSopenharmony_ci res = access(_PATH_MOUNTED, W_OK); 766881f68fSopenharmony_ci err = (res == -1) ? errno : 0; 776881f68fSopenharmony_ci if (ruid != 0) 786881f68fSopenharmony_ci setreuid(ruid, -1); 796881f68fSopenharmony_ci 806881f68fSopenharmony_ci if (err == EROFS) 816881f68fSopenharmony_ci return 0; 826881f68fSopenharmony_ci } 836881f68fSopenharmony_ci 846881f68fSopenharmony_ci return 1; 856881f68fSopenharmony_ci} 866881f68fSopenharmony_ci#endif /* IGNORE_MTAB */ 876881f68fSopenharmony_ci 886881f68fSopenharmony_cistatic int add_mount(const char *progname, const char *fsname, 896881f68fSopenharmony_ci const char *mnt, const char *type, const char *opts) 906881f68fSopenharmony_ci{ 916881f68fSopenharmony_ci int res; 926881f68fSopenharmony_ci int status; 936881f68fSopenharmony_ci sigset_t blockmask; 946881f68fSopenharmony_ci sigset_t oldmask; 956881f68fSopenharmony_ci 966881f68fSopenharmony_ci sigemptyset(&blockmask); 976881f68fSopenharmony_ci sigaddset(&blockmask, SIGCHLD); 986881f68fSopenharmony_ci res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); 996881f68fSopenharmony_ci if (res == -1) { 1006881f68fSopenharmony_ci fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); 1016881f68fSopenharmony_ci return -1; 1026881f68fSopenharmony_ci } 1036881f68fSopenharmony_ci 1046881f68fSopenharmony_ci res = fork(); 1056881f68fSopenharmony_ci if (res == -1) { 1066881f68fSopenharmony_ci fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); 1076881f68fSopenharmony_ci goto out_restore; 1086881f68fSopenharmony_ci } 1096881f68fSopenharmony_ci if (res == 0) { 1106881f68fSopenharmony_ci char *env = NULL; 1116881f68fSopenharmony_ci 1126881f68fSopenharmony_ci sigprocmask(SIG_SETMASK, &oldmask, NULL); 1136881f68fSopenharmony_ci 1146881f68fSopenharmony_ci if(setuid(geteuid()) == -1) { 1156881f68fSopenharmony_ci fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno)); 1166881f68fSopenharmony_ci res = -1; 1176881f68fSopenharmony_ci goto out_restore; 1186881f68fSopenharmony_ci } 1196881f68fSopenharmony_ci 1206881f68fSopenharmony_ci execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i", 1216881f68fSopenharmony_ci "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env); 1226881f68fSopenharmony_ci fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", 1236881f68fSopenharmony_ci progname, strerror(errno)); 1246881f68fSopenharmony_ci exit(1); 1256881f68fSopenharmony_ci } 1266881f68fSopenharmony_ci res = waitpid(res, &status, 0); 1276881f68fSopenharmony_ci if (res == -1) 1286881f68fSopenharmony_ci fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); 1296881f68fSopenharmony_ci 1306881f68fSopenharmony_ci if (status != 0) 1316881f68fSopenharmony_ci res = -1; 1326881f68fSopenharmony_ci 1336881f68fSopenharmony_ci out_restore: 1346881f68fSopenharmony_ci sigprocmask(SIG_SETMASK, &oldmask, NULL); 1356881f68fSopenharmony_ci 1366881f68fSopenharmony_ci return res; 1376881f68fSopenharmony_ci} 1386881f68fSopenharmony_ci 1396881f68fSopenharmony_ciint fuse_mnt_add_mount(const char *progname, const char *fsname, 1406881f68fSopenharmony_ci const char *mnt, const char *type, const char *opts) 1416881f68fSopenharmony_ci{ 1426881f68fSopenharmony_ci if (!mtab_needs_update(mnt)) 1436881f68fSopenharmony_ci return 0; 1446881f68fSopenharmony_ci 1456881f68fSopenharmony_ci return add_mount(progname, fsname, mnt, type, opts); 1466881f68fSopenharmony_ci} 1476881f68fSopenharmony_ci 1486881f68fSopenharmony_cistatic int exec_umount(const char *progname, const char *rel_mnt, int lazy) 1496881f68fSopenharmony_ci{ 1506881f68fSopenharmony_ci int res; 1516881f68fSopenharmony_ci int status; 1526881f68fSopenharmony_ci sigset_t blockmask; 1536881f68fSopenharmony_ci sigset_t oldmask; 1546881f68fSopenharmony_ci 1556881f68fSopenharmony_ci sigemptyset(&blockmask); 1566881f68fSopenharmony_ci sigaddset(&blockmask, SIGCHLD); 1576881f68fSopenharmony_ci res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); 1586881f68fSopenharmony_ci if (res == -1) { 1596881f68fSopenharmony_ci fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); 1606881f68fSopenharmony_ci return -1; 1616881f68fSopenharmony_ci } 1626881f68fSopenharmony_ci 1636881f68fSopenharmony_ci res = fork(); 1646881f68fSopenharmony_ci if (res == -1) { 1656881f68fSopenharmony_ci fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); 1666881f68fSopenharmony_ci goto out_restore; 1676881f68fSopenharmony_ci } 1686881f68fSopenharmony_ci if (res == 0) { 1696881f68fSopenharmony_ci char *env = NULL; 1706881f68fSopenharmony_ci 1716881f68fSopenharmony_ci sigprocmask(SIG_SETMASK, &oldmask, NULL); 1726881f68fSopenharmony_ci 1736881f68fSopenharmony_ci if(setuid(geteuid()) == -1) { 1746881f68fSopenharmony_ci fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno)); 1756881f68fSopenharmony_ci res = -1; 1766881f68fSopenharmony_ci goto out_restore; 1776881f68fSopenharmony_ci } 1786881f68fSopenharmony_ci 1796881f68fSopenharmony_ci if (lazy) { 1806881f68fSopenharmony_ci execle("/bin/umount", "/bin/umount", "-i", rel_mnt, 1816881f68fSopenharmony_ci "-l", NULL, &env); 1826881f68fSopenharmony_ci } else { 1836881f68fSopenharmony_ci execle("/bin/umount", "/bin/umount", "-i", rel_mnt, 1846881f68fSopenharmony_ci NULL, &env); 1856881f68fSopenharmony_ci } 1866881f68fSopenharmony_ci fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", 1876881f68fSopenharmony_ci progname, strerror(errno)); 1886881f68fSopenharmony_ci exit(1); 1896881f68fSopenharmony_ci } 1906881f68fSopenharmony_ci res = waitpid(res, &status, 0); 1916881f68fSopenharmony_ci if (res == -1) 1926881f68fSopenharmony_ci fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); 1936881f68fSopenharmony_ci 1946881f68fSopenharmony_ci if (status != 0) { 1956881f68fSopenharmony_ci res = -1; 1966881f68fSopenharmony_ci } 1976881f68fSopenharmony_ci 1986881f68fSopenharmony_ci out_restore: 1996881f68fSopenharmony_ci sigprocmask(SIG_SETMASK, &oldmask, NULL); 2006881f68fSopenharmony_ci return res; 2016881f68fSopenharmony_ci 2026881f68fSopenharmony_ci} 2036881f68fSopenharmony_ci 2046881f68fSopenharmony_ciint fuse_mnt_umount(const char *progname, const char *abs_mnt, 2056881f68fSopenharmony_ci const char *rel_mnt, int lazy) 2066881f68fSopenharmony_ci{ 2076881f68fSopenharmony_ci int res; 2086881f68fSopenharmony_ci 2096881f68fSopenharmony_ci if (!mtab_needs_update(abs_mnt)) { 2106881f68fSopenharmony_ci res = umount2(rel_mnt, lazy ? 2 : 0); 2116881f68fSopenharmony_ci if (res == -1) 2126881f68fSopenharmony_ci fprintf(stderr, "%s: failed to unmount %s: %s\n", 2136881f68fSopenharmony_ci progname, abs_mnt, strerror(errno)); 2146881f68fSopenharmony_ci return res; 2156881f68fSopenharmony_ci } 2166881f68fSopenharmony_ci 2176881f68fSopenharmony_ci return exec_umount(progname, rel_mnt, lazy); 2186881f68fSopenharmony_ci} 2196881f68fSopenharmony_ci 2206881f68fSopenharmony_cistatic int remove_mount(const char *progname, const char *mnt) 2216881f68fSopenharmony_ci{ 2226881f68fSopenharmony_ci int res; 2236881f68fSopenharmony_ci int status; 2246881f68fSopenharmony_ci sigset_t blockmask; 2256881f68fSopenharmony_ci sigset_t oldmask; 2266881f68fSopenharmony_ci 2276881f68fSopenharmony_ci sigemptyset(&blockmask); 2286881f68fSopenharmony_ci sigaddset(&blockmask, SIGCHLD); 2296881f68fSopenharmony_ci res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask); 2306881f68fSopenharmony_ci if (res == -1) { 2316881f68fSopenharmony_ci fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno)); 2326881f68fSopenharmony_ci return -1; 2336881f68fSopenharmony_ci } 2346881f68fSopenharmony_ci 2356881f68fSopenharmony_ci res = fork(); 2366881f68fSopenharmony_ci if (res == -1) { 2376881f68fSopenharmony_ci fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); 2386881f68fSopenharmony_ci goto out_restore; 2396881f68fSopenharmony_ci } 2406881f68fSopenharmony_ci if (res == 0) { 2416881f68fSopenharmony_ci char *env = NULL; 2426881f68fSopenharmony_ci 2436881f68fSopenharmony_ci sigprocmask(SIG_SETMASK, &oldmask, NULL); 2446881f68fSopenharmony_ci 2456881f68fSopenharmony_ci if(setuid(geteuid()) == -1) { 2466881f68fSopenharmony_ci fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno)); 2476881f68fSopenharmony_ci res = -1; 2486881f68fSopenharmony_ci goto out_restore; 2496881f68fSopenharmony_ci } 2506881f68fSopenharmony_ci 2516881f68fSopenharmony_ci execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i", 2526881f68fSopenharmony_ci "--fake", mnt, NULL, &env); 2536881f68fSopenharmony_ci fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", 2546881f68fSopenharmony_ci progname, strerror(errno)); 2556881f68fSopenharmony_ci exit(1); 2566881f68fSopenharmony_ci } 2576881f68fSopenharmony_ci res = waitpid(res, &status, 0); 2586881f68fSopenharmony_ci if (res == -1) 2596881f68fSopenharmony_ci fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); 2606881f68fSopenharmony_ci 2616881f68fSopenharmony_ci if (status != 0) 2626881f68fSopenharmony_ci res = -1; 2636881f68fSopenharmony_ci 2646881f68fSopenharmony_ci out_restore: 2656881f68fSopenharmony_ci sigprocmask(SIG_SETMASK, &oldmask, NULL); 2666881f68fSopenharmony_ci return res; 2676881f68fSopenharmony_ci} 2686881f68fSopenharmony_ci 2696881f68fSopenharmony_ciint fuse_mnt_remove_mount(const char *progname, const char *mnt) 2706881f68fSopenharmony_ci{ 2716881f68fSopenharmony_ci if (!mtab_needs_update(mnt)) 2726881f68fSopenharmony_ci return 0; 2736881f68fSopenharmony_ci 2746881f68fSopenharmony_ci return remove_mount(progname, mnt); 2756881f68fSopenharmony_ci} 2766881f68fSopenharmony_ci 2776881f68fSopenharmony_cichar *fuse_mnt_resolve_path(const char *progname, const char *orig) 2786881f68fSopenharmony_ci{ 2796881f68fSopenharmony_ci char buf[PATH_MAX]; 2806881f68fSopenharmony_ci char *copy; 2816881f68fSopenharmony_ci char *dst; 2826881f68fSopenharmony_ci char *end; 2836881f68fSopenharmony_ci char *lastcomp; 2846881f68fSopenharmony_ci const char *toresolv; 2856881f68fSopenharmony_ci 2866881f68fSopenharmony_ci if (!orig[0]) { 2876881f68fSopenharmony_ci fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, 2886881f68fSopenharmony_ci orig); 2896881f68fSopenharmony_ci return NULL; 2906881f68fSopenharmony_ci } 2916881f68fSopenharmony_ci 2926881f68fSopenharmony_ci copy = strdup(orig); 2936881f68fSopenharmony_ci if (copy == NULL) { 2946881f68fSopenharmony_ci fprintf(stderr, "%s: failed to allocate memory\n", progname); 2956881f68fSopenharmony_ci return NULL; 2966881f68fSopenharmony_ci } 2976881f68fSopenharmony_ci 2986881f68fSopenharmony_ci toresolv = copy; 2996881f68fSopenharmony_ci lastcomp = NULL; 3006881f68fSopenharmony_ci for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); 3016881f68fSopenharmony_ci if (end[0] != '/') { 3026881f68fSopenharmony_ci char *tmp; 3036881f68fSopenharmony_ci end[1] = '\0'; 3046881f68fSopenharmony_ci tmp = strrchr(copy, '/'); 3056881f68fSopenharmony_ci if (tmp == NULL) { 3066881f68fSopenharmony_ci lastcomp = copy; 3076881f68fSopenharmony_ci toresolv = "."; 3086881f68fSopenharmony_ci } else { 3096881f68fSopenharmony_ci lastcomp = tmp + 1; 3106881f68fSopenharmony_ci if (tmp == copy) 3116881f68fSopenharmony_ci toresolv = "/"; 3126881f68fSopenharmony_ci } 3136881f68fSopenharmony_ci if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { 3146881f68fSopenharmony_ci lastcomp = NULL; 3156881f68fSopenharmony_ci toresolv = copy; 3166881f68fSopenharmony_ci } 3176881f68fSopenharmony_ci else if (tmp) 3186881f68fSopenharmony_ci tmp[0] = '\0'; 3196881f68fSopenharmony_ci } 3206881f68fSopenharmony_ci if (realpath(toresolv, buf) == NULL) { 3216881f68fSopenharmony_ci fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, 3226881f68fSopenharmony_ci strerror(errno)); 3236881f68fSopenharmony_ci free(copy); 3246881f68fSopenharmony_ci return NULL; 3256881f68fSopenharmony_ci } 3266881f68fSopenharmony_ci if (lastcomp == NULL) 3276881f68fSopenharmony_ci dst = strdup(buf); 3286881f68fSopenharmony_ci else { 3296881f68fSopenharmony_ci dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); 3306881f68fSopenharmony_ci if (dst) { 3316881f68fSopenharmony_ci unsigned buflen = strlen(buf); 3326881f68fSopenharmony_ci if (buflen && buf[buflen-1] == '/') 3336881f68fSopenharmony_ci sprintf(dst, "%s%s", buf, lastcomp); 3346881f68fSopenharmony_ci else 3356881f68fSopenharmony_ci sprintf(dst, "%s/%s", buf, lastcomp); 3366881f68fSopenharmony_ci } 3376881f68fSopenharmony_ci } 3386881f68fSopenharmony_ci free(copy); 3396881f68fSopenharmony_ci if (dst == NULL) 3406881f68fSopenharmony_ci fprintf(stderr, "%s: failed to allocate memory\n", progname); 3416881f68fSopenharmony_ci return dst; 3426881f68fSopenharmony_ci} 3436881f68fSopenharmony_ci 3446881f68fSopenharmony_ciint fuse_mnt_check_fuseblk(void) 3456881f68fSopenharmony_ci{ 3466881f68fSopenharmony_ci char buf[256]; 3476881f68fSopenharmony_ci FILE *f = fopen("/proc/filesystems", "r"); 3486881f68fSopenharmony_ci if (!f) 3496881f68fSopenharmony_ci return 1; 3506881f68fSopenharmony_ci 3516881f68fSopenharmony_ci while (fgets(buf, sizeof(buf), f)) 3526881f68fSopenharmony_ci if (strstr(buf, "fuseblk\n")) { 3536881f68fSopenharmony_ci fclose(f); 3546881f68fSopenharmony_ci return 1; 3556881f68fSopenharmony_ci } 3566881f68fSopenharmony_ci 3576881f68fSopenharmony_ci fclose(f); 3586881f68fSopenharmony_ci return 0; 3596881f68fSopenharmony_ci} 3606881f68fSopenharmony_ci 3616881f68fSopenharmony_ciint fuse_mnt_parse_fuse_fd(const char *mountpoint) 3626881f68fSopenharmony_ci{ 3636881f68fSopenharmony_ci int fd = -1; 3646881f68fSopenharmony_ci int len = 0; 3656881f68fSopenharmony_ci 3666881f68fSopenharmony_ci if (sscanf(mountpoint, "/dev/fd/%u%n", &fd, &len) == 1 && 3676881f68fSopenharmony_ci len == strlen(mountpoint)) { 3686881f68fSopenharmony_ci return fd; 3696881f68fSopenharmony_ci } 3706881f68fSopenharmony_ci 3716881f68fSopenharmony_ci return -1; 3726881f68fSopenharmony_ci} 373