1/* 2 FUSE: Filesystem in Userspace 3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 4 5 This program can be distributed under the terms of the GNU LGPLv2. 6 See the file COPYING.LIB. 7*/ 8 9#include "config.h" 10#include "mount_util.h" 11#include <stdio.h> 12#include <unistd.h> 13#include <stdlib.h> 14#include <string.h> 15#include <dirent.h> 16#include <errno.h> 17#include <limits.h> 18#include <mntent.h> 19#include <sys/stat.h> 20#include <sys/wait.h> 21#include <sys/mount.h> 22#include <sys/param.h> 23 24static int mtab_needs_update(const char *mnt) 25{ 26 int res; 27 struct stat stbuf; 28 29 /* If mtab is within new mount, don't touch it */ 30 if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && 31 _PATH_MOUNTED[strlen(mnt)] == '/') 32 return 0; 33 34 /* 35 * Skip mtab update if /etc/mtab: 36 * 37 * - doesn't exist, 38 * - is a symlink, 39 * - is on a read-only filesystem. 40 */ 41 res = lstat(_PATH_MOUNTED, &stbuf); 42 if (res == -1) { 43 if (errno == ENOENT) 44 return 0; 45 } else { 46 if (S_ISLNK(stbuf.st_mode)) 47 return 0; 48 49 res = access(_PATH_MOUNTED, W_OK); 50 if (res == -1 && errno == EROFS) 51 return 0; 52 } 53 54 return 1; 55} 56 57int fuse_mnt_add_mount(const char *progname, const char *fsname, 58 const char *mnt, const char *type, const char *opts) 59{ 60 int res; 61 int status; 62 63 if (!mtab_needs_update(mnt)) 64 return 0; 65 66 res = fork(); 67 if (res == -1) { 68 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); 69 return -1; 70 } 71 if (res == 0) { 72 char templ[] = "/tmp/fusermountXXXXXX"; 73 char *tmp; 74 75 setuid(geteuid()); 76 77 /* 78 * hide in a directory, where mount isn't able to resolve 79 * fsname as a valid path 80 */ 81 tmp = mkdtemp(templ); 82 if (!tmp) { 83 fprintf(stderr, "%s: failed to create temporary directory\n", 84 progname); 85 exit(1); 86 } 87 if (chdir(tmp)) { 88 fprintf(stderr, "%s: failed to chdir to %s: %s\n", 89 progname, tmp, strerror(errno)); 90 exit(1); 91 } 92 rmdir(tmp); 93 execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts, 94 fsname, mnt, NULL); 95 fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname, 96 strerror(errno)); 97 exit(1); 98 } 99 res = waitpid(res, &status, 0); 100 if (res == -1) { 101 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); 102 return -1; 103 } 104 if (status != 0) 105 return -1; 106 107 return 0; 108} 109 110int fuse_mnt_umount(const char *progname, const char *mnt, int lazy) 111{ 112 int res; 113 int status; 114 115 if (!mtab_needs_update(mnt)) { 116 res = umount2(mnt, lazy ? 2 : 0); 117 if (res == -1) 118 fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, 119 mnt, strerror(errno)); 120 return res; 121 } 122 123 res = fork(); 124 if (res == -1) { 125 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); 126 return -1; 127 } 128 if (res == 0) { 129 setuid(geteuid()); 130 execl("/bin/umount", "/bin/umount", "-i", mnt, lazy ? "-l" : NULL, 131 NULL); 132 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname, 133 strerror(errno)); 134 exit(1); 135 } 136 res = waitpid(res, &status, 0); 137 if (res == -1) { 138 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); 139 return -1; 140 } 141 if (status != 0) 142 return -1; 143 144 return 0; 145} 146 147char *fuse_mnt_resolve_path(const char *progname, const char *orig) 148{ 149 char buf[PATH_MAX]; 150 char *copy; 151 char *dst; 152 char *end; 153 char *lastcomp; 154 const char *toresolv; 155 156 if (!orig[0]) { 157 fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig); 158 return NULL; 159 } 160 161 copy = strdup(orig); 162 if (copy == NULL) { 163 fprintf(stderr, "%s: failed to allocate memory\n", progname); 164 return NULL; 165 } 166 167 toresolv = copy; 168 lastcomp = NULL; 169 for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); 170 if (end[0] != '/') { 171 char *tmp; 172 end[1] = '\0'; 173 tmp = strrchr(copy, '/'); 174 if (tmp == NULL) { 175 lastcomp = copy; 176 toresolv = "."; 177 } else { 178 lastcomp = tmp + 1; 179 if (tmp == copy) 180 toresolv = "/"; 181 } 182 if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { 183 lastcomp = NULL; 184 toresolv = copy; 185 } 186 else if (tmp) 187 tmp[0] = '\0'; 188 } 189 if (realpath(toresolv, buf) == NULL) { 190 fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, 191 strerror(errno)); 192 free(copy); 193 return NULL; 194 } 195 if (lastcomp == NULL) 196 dst = strdup(buf); 197 else { 198 dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); 199 if (dst) { 200 unsigned buflen = strlen(buf); 201 if (buflen && buf[buflen-1] == '/') 202 sprintf(dst, "%s%s", buf, lastcomp); 203 else 204 sprintf(dst, "%s/%s", buf, lastcomp); 205 } 206 } 207 free(copy); 208 if (dst == NULL) 209 fprintf(stderr, "%s: failed to allocate memory\n", progname); 210 return dst; 211} 212 213int fuse_mnt_check_fuseblk(void) 214{ 215 char buf[256]; 216 FILE *f = fopen("/proc/filesystems", "r"); 217 if (!f) 218 return 1; 219 220 while (fgets(buf, sizeof(buf), f)) 221 if (strstr(buf, "fuseblk\n")) { 222 fclose(f); 223 return 1; 224 } 225 226 fclose(f); 227 return 0; 228} 229