summaryrefslogtreecommitdiff
path: root/libfuse-lite/mount_util.c (plain)
blob: 75a7ee63cfd4b50dcb4fb97aaaa41dbd88335acc
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
62 if (!mtab_needs_update(mnt))
63 return 0;
64
65 res = fork();
66 if (res == -1) {
67 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
68 return 0;
69 }
70 if (res == 0) {
71 char templ[] = "/tmp/fusermountXXXXXX";
72 char *tmp;
73
74 setuid(geteuid());
75
76 /*
77 * hide in a directory, where mount isn't able to resolve
78 * fsname as a valid path
79 */
80 tmp = mkdtemp(templ);
81 if (!tmp) {
82 fprintf(stderr, "%s: failed to create temporary directory\n",
83 progname);
84 exit(1);
85 }
86 if (chdir(tmp)) {
87 fprintf(stderr, "%s: failed to chdir to %s: %s\n",
88 progname, tmp, strerror(errno));
89 exit(1);
90 }
91 rmdir(tmp);
92 execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
93 fsname, mnt, NULL);
94 fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname,
95 strerror(errno));
96 exit(1);
97 }
98 return 0;
99}
100
101int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
102{
103 int res;
104 int status;
105
106 if (!mtab_needs_update(mnt)) {
107 res = umount2(mnt, lazy ? 2 : 0);
108 if (res == -1)
109 fprintf(stderr, "%s: failed to unmount %s: %s\n", progname,
110 mnt, strerror(errno));
111 return res;
112 }
113
114 res = fork();
115 if (res == -1) {
116 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
117 return -1;
118 }
119 if (res == 0) {
120 setuid(geteuid());
121 execl("/bin/umount", "/bin/umount", "-i", mnt, lazy ? "-l" : NULL,
122 NULL);
123 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname,
124 strerror(errno));
125 exit(1);
126 }
127 res = waitpid(res, &status, 0);
128 if (res == -1) {
129 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
130 return -1;
131 }
132 if (status != 0)
133 return -1;
134
135 return 0;
136}
137
138char *fuse_mnt_resolve_path(const char *progname, const char *orig)
139{
140 char buf[PATH_MAX];
141 char *copy;
142 char *dst;
143 char *end;
144 char *lastcomp;
145 const char *toresolv;
146
147 if (!orig[0]) {
148 fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
149 return NULL;
150 }
151
152 copy = strdup(orig);
153 if (copy == NULL) {
154 fprintf(stderr, "%s: failed to allocate memory\n", progname);
155 return NULL;
156 }
157
158 toresolv = copy;
159 lastcomp = NULL;
160 for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
161 if (end[0] != '/') {
162 char *tmp;
163 end[1] = '\0';
164 tmp = strrchr(copy, '/');
165 if (tmp == NULL) {
166 lastcomp = copy;
167 toresolv = ".";
168 } else {
169 lastcomp = tmp + 1;
170 if (tmp == copy)
171 toresolv = "/";
172 }
173 if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
174 lastcomp = NULL;
175 toresolv = copy;
176 }
177 else if (tmp)
178 tmp[0] = '\0';
179 }
180 if (realpath(toresolv, buf) == NULL) {
181 fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
182 strerror(errno));
183 free(copy);
184 return NULL;
185 }
186 if (lastcomp == NULL)
187 dst = strdup(buf);
188 else {
189 dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
190 if (dst) {
191 unsigned buflen = strlen(buf);
192 if (buflen && buf[buflen-1] == '/')
193 sprintf(dst, "%s%s", buf, lastcomp);
194 else
195 sprintf(dst, "%s/%s", buf, lastcomp);
196 }
197 }
198 free(copy);
199 if (dst == NULL)
200 fprintf(stderr, "%s: failed to allocate memory\n", progname);
201 return dst;
202}
203
204int fuse_mnt_check_fuseblk(void)
205{
206 char buf[256];
207 FILE *f = fopen("/proc/filesystems", "r");
208 if (!f)
209 return 1;
210
211 while (fgets(buf, sizeof(buf), f))
212 if (strstr(buf, "fuseblk\n")) {
213 fclose(f);
214 return 1;
215 }
216
217 fclose(f);
218 return 0;
219}
220