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