18 |
mount_it_now() does the actual mount. |
mount_it_now() does the actual mount. |
19 |
*/ |
*/ |
20 |
|
|
|
#include "busybox.h" |
|
21 |
#include <mntent.h> |
#include <mntent.h> |
|
|
|
|
/* Needed for nfs support only... */ |
|
22 |
#include <syslog.h> |
#include <syslog.h> |
23 |
|
#include "libbb.h" |
24 |
|
|
25 |
|
#if ENABLE_FEATURE_MOUNT_LABEL |
26 |
|
#include "volume_id.h" |
27 |
|
#endif |
28 |
|
|
29 |
|
/* Needed for nfs support only */ |
30 |
#include <sys/utsname.h> |
#include <sys/utsname.h> |
31 |
#undef TRUE |
#undef TRUE |
32 |
#undef FALSE |
#undef FALSE |
34 |
#include <rpc/pmap_prot.h> |
#include <rpc/pmap_prot.h> |
35 |
#include <rpc/pmap_clnt.h> |
#include <rpc/pmap_clnt.h> |
36 |
|
|
37 |
|
#ifndef MS_SILENT |
38 |
|
#define MS_SILENT (1 << 15) |
39 |
|
#endif |
40 |
|
/* Grab more as needed from util-linux's mount/mount_constants.h */ |
41 |
|
#ifndef MS_DIRSYNC |
42 |
|
#define MS_DIRSYNC 128 /* Directory modifications are synchronous */ |
43 |
|
#endif |
44 |
|
|
45 |
|
|
46 |
#if defined(__dietlibc__) |
#if defined(__dietlibc__) |
47 |
/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi) |
/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi) |
48 |
* dietlibc-0.30 does not have implementation of getmntent_r() */ |
* dietlibc-0.30 does not have implementation of getmntent_r() */ |
49 |
/* OTOH: why we use getmntent_r instead of getmntent? TODO... */ |
static struct mntent *getmntent_r(FILE* stream, struct mntent* result, |
50 |
struct mntent *getmntent_r(FILE* stream, struct mntent* result, char* buffer, int bufsize) |
char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM) |
51 |
{ |
{ |
|
/* *** XXX FIXME WARNING: This hack is NOT thread safe. --Sampo */ |
|
52 |
struct mntent* ment = getmntent(stream); |
struct mntent* ment = getmntent(stream); |
53 |
memcpy(result, ment, sizeof(struct mntent)); |
return memcpy(result, ment, sizeof(*ment)); |
|
return result; |
|
54 |
} |
} |
55 |
#endif |
#endif |
56 |
|
|
57 |
|
|
58 |
// Not real flags, but we want to be able to check for this. |
// Not real flags, but we want to be able to check for this. |
59 |
enum { |
enum { |
60 |
MOUNT_USERS = (1<<28)*ENABLE_DESKTOP, |
MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP, |
61 |
MOUNT_NOAUTO = (1<<29), |
MOUNT_NOAUTO = (1 << 29), |
62 |
MOUNT_SWAP = (1<<30), |
MOUNT_SWAP = (1 << 30), |
63 |
}; |
}; |
64 |
|
|
65 |
|
|
66 |
|
#define OPTION_STR "o:t:rwanfvsi" |
67 |
|
enum { |
68 |
|
OPT_o = (1 << 0), |
69 |
|
OPT_t = (1 << 1), |
70 |
|
OPT_r = (1 << 2), |
71 |
|
OPT_w = (1 << 3), |
72 |
|
OPT_a = (1 << 4), |
73 |
|
OPT_n = (1 << 5), |
74 |
|
OPT_f = (1 << 6), |
75 |
|
OPT_v = (1 << 7), |
76 |
|
OPT_s = (1 << 8), |
77 |
|
OPT_i = (1 << 9), |
78 |
|
}; |
79 |
|
|
80 |
|
#if ENABLE_FEATURE_MTAB_SUPPORT |
81 |
|
#define useMtab (!(option_mask32 & OPT_n)) |
82 |
|
#else |
83 |
|
#define useMtab 0 |
84 |
|
#endif |
85 |
|
|
86 |
|
#if ENABLE_FEATURE_MOUNT_FAKE |
87 |
|
#define fakeIt (option_mask32 & OPT_f) |
88 |
|
#else |
89 |
|
#define fakeIt 0 |
90 |
|
#endif |
91 |
|
|
92 |
|
|
93 |
// TODO: more "user" flag compatibility. |
// TODO: more "user" flag compatibility. |
94 |
// "user" option (from mount manpage): |
// "user" option (from mount manpage): |
95 |
// Only the user that mounted a filesystem can unmount it again. |
// Only the user that mounted a filesystem can unmount it again. |
102 |
/* Standard mount options (from -o options or --options), with corresponding |
/* Standard mount options (from -o options or --options), with corresponding |
103 |
* flags */ |
* flags */ |
104 |
|
|
105 |
struct { |
static const int32_t mount_options[] = { |
|
char *name; |
|
|
long flags; |
|
|
} static mount_options[] = { |
|
106 |
// MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs. |
// MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs. |
107 |
|
|
108 |
USE_FEATURE_MOUNT_LOOP( |
USE_FEATURE_MOUNT_LOOP( |
109 |
{"loop", 0}, |
/* "loop" */ 0, |
110 |
) |
) |
111 |
|
|
112 |
USE_FEATURE_MOUNT_FSTAB( |
USE_FEATURE_MOUNT_FSTAB( |
113 |
{"defaults", 0}, |
/* "defaults" */ 0, |
114 |
/* {"quiet", 0}, - do not filter out, vfat wants to see it */ |
/* "quiet" 0 - do not filter out, vfat wants to see it */ |
115 |
{"noauto", MOUNT_NOAUTO}, |
/* "noauto" */ MOUNT_NOAUTO, |
116 |
{"swap", MOUNT_SWAP}, |
/* "sw" */ MOUNT_SWAP, |
117 |
USE_DESKTOP({"user", MOUNT_USERS},) |
/* "swap" */ MOUNT_SWAP, |
118 |
USE_DESKTOP({"users", MOUNT_USERS},) |
USE_DESKTOP(/* "user" */ MOUNT_USERS,) |
119 |
|
USE_DESKTOP(/* "users" */ MOUNT_USERS,) |
120 |
|
/* "_netdev" */ 0, |
121 |
) |
) |
122 |
|
|
123 |
USE_FEATURE_MOUNT_FLAGS( |
USE_FEATURE_MOUNT_FLAGS( |
124 |
// vfs flags |
// vfs flags |
125 |
{"nosuid", MS_NOSUID}, |
/* "nosuid" */ MS_NOSUID, |
126 |
{"suid", ~MS_NOSUID}, |
/* "suid" */ ~MS_NOSUID, |
127 |
{"dev", ~MS_NODEV}, |
/* "dev" */ ~MS_NODEV, |
128 |
{"nodev", MS_NODEV}, |
/* "nodev" */ MS_NODEV, |
129 |
{"exec", ~MS_NOEXEC}, |
/* "exec" */ ~MS_NOEXEC, |
130 |
{"noexec", MS_NOEXEC}, |
/* "noexec" */ MS_NOEXEC, |
131 |
{"sync", MS_SYNCHRONOUS}, |
/* "sync" */ MS_SYNCHRONOUS, |
132 |
{"async", ~MS_SYNCHRONOUS}, |
/* "dirsync" */ MS_DIRSYNC, |
133 |
{"atime", ~MS_NOATIME}, |
/* "async" */ ~MS_SYNCHRONOUS, |
134 |
{"noatime", MS_NOATIME}, |
/* "atime" */ ~MS_NOATIME, |
135 |
{"diratime", ~MS_NODIRATIME}, |
/* "noatime" */ MS_NOATIME, |
136 |
{"nodiratime", MS_NODIRATIME}, |
/* "diratime" */ ~MS_NODIRATIME, |
137 |
{"loud", ~MS_SILENT}, |
/* "nodiratime" */ MS_NODIRATIME, |
138 |
|
/* "mand" */ MS_MANDLOCK, |
139 |
|
/* "nomand" */ ~MS_MANDLOCK, |
140 |
|
/* "relatime" */ MS_RELATIME, |
141 |
|
/* "norelatime" */ ~MS_RELATIME, |
142 |
|
/* "loud" */ ~MS_SILENT, |
143 |
|
|
144 |
// action flags |
// action flags |
145 |
|
/* "bind" */ MS_BIND, |
146 |
|
/* "move" */ MS_MOVE, |
147 |
|
/* "shared" */ MS_SHARED, |
148 |
|
/* "slave" */ MS_SLAVE, |
149 |
|
/* "private" */ MS_PRIVATE, |
150 |
|
/* "unbindable" */ MS_UNBINDABLE, |
151 |
|
/* "rshared" */ MS_SHARED|MS_RECURSIVE, |
152 |
|
/* "rslave" */ MS_SLAVE|MS_RECURSIVE, |
153 |
|
/* "rprivate" */ MS_SLAVE|MS_RECURSIVE, |
154 |
|
/* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE, |
155 |
|
) |
156 |
|
|
157 |
|
// Always understood. |
158 |
|
/* "ro" */ MS_RDONLY, // vfs flag |
159 |
|
/* "rw" */ ~MS_RDONLY, // vfs flag |
160 |
|
/* "remount" */ MS_REMOUNT // action flag |
161 |
|
}; |
162 |
|
|
163 |
|
static const char mount_option_str[] = |
164 |
|
USE_FEATURE_MOUNT_LOOP( |
165 |
|
"loop" "\0" |
166 |
|
) |
167 |
|
USE_FEATURE_MOUNT_FSTAB( |
168 |
|
"defaults" "\0" |
169 |
|
/* "quiet" "\0" - do not filter out, vfat wants to see it */ |
170 |
|
"noauto" "\0" |
171 |
|
"sw" "\0" |
172 |
|
"swap" "\0" |
173 |
|
USE_DESKTOP("user" "\0") |
174 |
|
USE_DESKTOP("users" "\0") |
175 |
|
"_netdev" "\0" |
176 |
|
) |
177 |
|
USE_FEATURE_MOUNT_FLAGS( |
178 |
|
// vfs flags |
179 |
|
"nosuid" "\0" |
180 |
|
"suid" "\0" |
181 |
|
"dev" "\0" |
182 |
|
"nodev" "\0" |
183 |
|
"exec" "\0" |
184 |
|
"noexec" "\0" |
185 |
|
"sync" "\0" |
186 |
|
"dirsync" "\0" |
187 |
|
"async" "\0" |
188 |
|
"atime" "\0" |
189 |
|
"noatime" "\0" |
190 |
|
"diratime" "\0" |
191 |
|
"nodiratime" "\0" |
192 |
|
"mand" "\0" |
193 |
|
"nomand" "\0" |
194 |
|
"relatime" "\0" |
195 |
|
"norelatime" "\0" |
196 |
|
"loud" "\0" |
197 |
|
|
198 |
{"bind", MS_BIND}, |
// action flags |
199 |
{"move", MS_MOVE}, |
"bind" "\0" |
200 |
{"shared", MS_SHARED}, |
"move" "\0" |
201 |
{"slave", MS_SLAVE}, |
"shared" "\0" |
202 |
{"private", MS_PRIVATE}, |
"slave" "\0" |
203 |
{"unbindable", MS_UNBINDABLE}, |
"private" "\0" |
204 |
{"rshared", MS_SHARED|MS_RECURSIVE}, |
"unbindable" "\0" |
205 |
{"rslave", MS_SLAVE|MS_RECURSIVE}, |
"rshared" "\0" |
206 |
{"rprivate", MS_SLAVE|MS_RECURSIVE}, |
"rslave" "\0" |
207 |
{"runbindable", MS_UNBINDABLE|MS_RECURSIVE}, |
"rprivate" "\0" |
208 |
|
"runbindable" "\0" |
209 |
) |
) |
210 |
|
|
211 |
// Always understood. |
// Always understood. |
212 |
|
"ro" "\0" // vfs flag |
213 |
|
"rw" "\0" // vfs flag |
214 |
|
"remount" "\0" // action flag |
215 |
|
; |
216 |
|
|
217 |
|
|
218 |
|
struct globals { |
219 |
|
#if ENABLE_FEATURE_MOUNT_NFS |
220 |
|
smalluint nfs_mount_version; |
221 |
|
#endif |
222 |
|
#if ENABLE_FEATURE_MOUNT_VERBOSE |
223 |
|
unsigned verbose; |
224 |
|
#endif |
225 |
|
llist_t *fslist; |
226 |
|
char getmntent_buf[1]; |
227 |
|
|
|
{"ro", MS_RDONLY}, // vfs flag |
|
|
{"rw", ~MS_RDONLY}, // vfs flag |
|
|
{"remount", MS_REMOUNT}, // action flag |
|
228 |
}; |
}; |
229 |
|
enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) }; |
230 |
|
#define G (*(struct globals*)&bb_common_bufsiz1) |
231 |
|
#define nfs_mount_version (G.nfs_mount_version) |
232 |
|
#if ENABLE_FEATURE_MOUNT_VERBOSE |
233 |
|
#define verbose (G.verbose ) |
234 |
|
#else |
235 |
|
#define verbose 0 |
236 |
|
#endif |
237 |
|
#define fslist (G.fslist ) |
238 |
|
#define getmntent_buf (G.getmntent_buf ) |
239 |
|
|
240 |
#define VECTOR_SIZE(v) (sizeof(v) / sizeof((v)[0])) |
|
241 |
|
#if ENABLE_FEATURE_MOUNT_VERBOSE |
242 |
|
static int verbose_mount(const char *source, const char *target, |
243 |
|
const char *filesystemtype, |
244 |
|
unsigned long mountflags, const void *data) |
245 |
|
{ |
246 |
|
int rc; |
247 |
|
|
248 |
|
errno = 0; |
249 |
|
rc = mount(source, target, filesystemtype, mountflags, data); |
250 |
|
if (verbose >= 2) |
251 |
|
bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d", |
252 |
|
source, target, filesystemtype, |
253 |
|
mountflags, (char*)data, rc); |
254 |
|
return rc; |
255 |
|
} |
256 |
|
#else |
257 |
|
#define verbose_mount(...) mount(__VA_ARGS__) |
258 |
|
#endif |
259 |
|
|
260 |
|
static int resolve_mount_spec(char **fsname) |
261 |
|
{ |
262 |
|
char *tmp = NULL; |
263 |
|
|
264 |
|
#if ENABLE_FEATURE_MOUNT_LABEL |
265 |
|
if (!strncmp(*fsname, "UUID=", 5)) |
266 |
|
tmp = get_devname_from_uuid(*fsname + 5); |
267 |
|
else if (!strncmp(*fsname, "LABEL=", 6)) |
268 |
|
tmp = get_devname_from_label(*fsname + 6); |
269 |
|
#endif |
270 |
|
|
271 |
|
if (tmp) { |
272 |
|
*fsname = tmp; |
273 |
|
return 1; |
274 |
|
} |
275 |
|
return 0; |
276 |
|
} |
277 |
|
|
278 |
/* Append mount options to string */ |
/* Append mount options to string */ |
279 |
static void append_mount_options(char **oldopts, char *newopts) |
static void append_mount_options(char **oldopts, const char *newopts) |
280 |
{ |
{ |
281 |
if (*oldopts && **oldopts) { |
if (*oldopts && **oldopts) { |
282 |
/* do not insert options which are already there */ |
/* do not insert options which are already there */ |
288 |
p = *oldopts; |
p = *oldopts; |
289 |
while (1) { |
while (1) { |
290 |
if (!strncmp(p, newopts, len) |
if (!strncmp(p, newopts, len) |
291 |
&& (p[len]==',' || p[len]==0)) |
&& (p[len] == ',' || p[len] == '\0')) |
292 |
goto skip; |
goto skip; |
293 |
p = strchr(p,','); |
p = strchr(p,','); |
294 |
if(!p) break; |
if (!p) break; |
295 |
p++; |
p++; |
296 |
} |
} |
297 |
p = xasprintf("%s,%.*s", *oldopts, len, newopts); |
p = xasprintf("%s,%.*s", *oldopts, len, newopts); |
298 |
free(*oldopts); |
free(*oldopts); |
299 |
*oldopts = p; |
*oldopts = p; |
300 |
skip: |
skip: |
301 |
newopts += len; |
newopts += len; |
302 |
while (newopts[0] == ',') newopts++; |
while (newopts[0] == ',') newopts++; |
303 |
} |
} |
309 |
|
|
310 |
/* Use the mount_options list to parse options into flags. |
/* Use the mount_options list to parse options into flags. |
311 |
* Also return list of unrecognized options if unrecognized!=NULL */ |
* Also return list of unrecognized options if unrecognized!=NULL */ |
312 |
static int parse_mount_options(char *options, char **unrecognized) |
static long parse_mount_options(char *options, char **unrecognized) |
313 |
{ |
{ |
314 |
int flags = MS_SILENT; |
long flags = MS_SILENT; |
315 |
|
|
316 |
// Loop through options |
// Loop through options |
317 |
for (;;) { |
for (;;) { |
318 |
int i; |
unsigned i; |
319 |
char *comma = strchr(options, ','); |
char *comma = strchr(options, ','); |
320 |
|
const char *option_str = mount_option_str; |
321 |
|
|
322 |
if (comma) *comma = 0; |
if (comma) *comma = '\0'; |
323 |
|
|
324 |
|
/* FIXME: use hasmntopt() */ |
325 |
// Find this option in mount_options |
// Find this option in mount_options |
326 |
for (i = 0; i < VECTOR_SIZE(mount_options); i++) { |
for (i = 0; i < ARRAY_SIZE(mount_options); i++) { |
327 |
if (!strcasecmp(mount_options[i].name, options)) { |
if (!strcasecmp(option_str, options)) { |
328 |
long fl = mount_options[i].flags; |
long fl = mount_options[i]; |
329 |
if (fl < 0) flags &= fl; |
if (fl < 0) flags &= fl; |
330 |
else flags |= fl; |
else flags |= fl; |
331 |
break; |
break; |
332 |
} |
} |
333 |
|
option_str += strlen(option_str) + 1; |
334 |
} |
} |
335 |
// If unrecognized not NULL, append unrecognized mount options */ |
// If unrecognized not NULL, append unrecognized mount options */ |
336 |
if (unrecognized && i == VECTOR_SIZE(mount_options)) { |
if (unrecognized && i == ARRAY_SIZE(mount_options)) { |
337 |
// Add it to strflags, to pass on to kernel |
// Add it to strflags, to pass on to kernel |
338 |
i = *unrecognized ? strlen(*unrecognized) : 0; |
i = *unrecognized ? strlen(*unrecognized) : 0; |
339 |
*unrecognized = xrealloc(*unrecognized, i+strlen(options)+2); |
*unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2); |
340 |
|
|
341 |
// Comma separated if it's not the first one |
// Comma separated if it's not the first one |
342 |
if (i) (*unrecognized)[i++] = ','; |
if (i) (*unrecognized)[i++] = ','; |
343 |
strcpy((*unrecognized)+i, options); |
strcpy((*unrecognized)+i, options); |
344 |
} |
} |
345 |
|
|
346 |
// Advance to next option, or finish |
if (!comma) |
347 |
if (comma) { |
break; |
348 |
*comma = ','; |
// Advance to next option |
349 |
options = ++comma; |
*comma = ','; |
350 |
} else break; |
options = ++comma; |
351 |
} |
} |
352 |
|
|
353 |
return flags; |
return flags; |
357 |
|
|
358 |
static llist_t *get_block_backed_filesystems(void) |
static llist_t *get_block_backed_filesystems(void) |
359 |
{ |
{ |
360 |
static const char *const filesystems[] = { |
static const char filesystems[2][sizeof("/proc/filesystems")] = { |
361 |
"/etc/filesystems", |
"/etc/filesystems", |
362 |
"/proc/filesystems", |
"/proc/filesystems", |
|
0 |
|
363 |
}; |
}; |
364 |
char *fs, *buf; |
char *fs, *buf; |
365 |
llist_t *list = 0; |
llist_t *list = 0; |
366 |
int i; |
int i; |
367 |
FILE *f; |
FILE *f; |
368 |
|
|
369 |
for (i = 0; filesystems[i]; i++) { |
for (i = 0; i < 2; i++) { |
370 |
f = fopen(filesystems[i], "r"); |
f = fopen_for_read(filesystems[i]); |
371 |
if (!f) continue; |
if (!f) continue; |
372 |
|
|
373 |
while ((buf = xmalloc_getline(f)) != 0) { |
while ((buf = xmalloc_fgetline(f)) != NULL) { |
374 |
if (!strncmp(buf, "nodev", 5) && isspace(buf[5])) |
if (!strncmp(buf, "nodev", 5) && isspace(buf[5])) |
375 |
continue; |
continue; |
376 |
fs = skip_whitespace(buf); |
fs = skip_whitespace(buf); |
385 |
return list; |
return list; |
386 |
} |
} |
387 |
|
|
|
llist_t *fslist = 0; |
|
|
|
|
388 |
#if ENABLE_FEATURE_CLEAN_UP |
#if ENABLE_FEATURE_CLEAN_UP |
389 |
static void delete_block_backed_filesystems(void) |
static void delete_block_backed_filesystems(void) |
390 |
{ |
{ |
394 |
void delete_block_backed_filesystems(void); |
void delete_block_backed_filesystems(void); |
395 |
#endif |
#endif |
396 |
|
|
|
#if ENABLE_FEATURE_MTAB_SUPPORT |
|
|
static int useMtab = 1; |
|
|
static int fakeIt; |
|
|
#else |
|
|
#define useMtab 0 |
|
|
#define fakeIt 0 |
|
|
#endif |
|
|
|
|
397 |
// Perform actual mount of specific filesystem at specific location. |
// Perform actual mount of specific filesystem at specific location. |
398 |
// NB: mp->xxx fields may be trashed on exit |
// NB: mp->xxx fields may be trashed on exit |
399 |
static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts) |
static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts) |
400 |
{ |
{ |
401 |
int rc = 0; |
int rc = 0; |
402 |
|
|
403 |
if (fakeIt) goto mtab; |
if (fakeIt) { |
404 |
|
if (verbose >= 2) |
405 |
|
bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')", |
406 |
|
mp->mnt_fsname, mp->mnt_dir, mp->mnt_type, |
407 |
|
vfsflags, filteropts); |
408 |
|
goto mtab; |
409 |
|
} |
410 |
|
|
411 |
// Mount, with fallback to read-only if necessary. |
// Mount, with fallback to read-only if necessary. |
|
|
|
412 |
for (;;) { |
for (;;) { |
413 |
rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type, |
errno = 0; |
414 |
|
rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type, |
415 |
vfsflags, filteropts); |
vfsflags, filteropts); |
416 |
if (!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS)) |
|
417 |
|
// If mount failed, try |
418 |
|
// helper program mount.<mnt_type> |
419 |
|
if (ENABLE_FEATURE_MOUNT_HELPERS && rc) { |
420 |
|
char *args[6]; |
421 |
|
int errno_save = errno; |
422 |
|
args[0] = xasprintf("mount.%s", mp->mnt_type); |
423 |
|
rc = 1; |
424 |
|
if (filteropts) { |
425 |
|
args[rc++] = (char *)"-o"; |
426 |
|
args[rc++] = filteropts; |
427 |
|
} |
428 |
|
args[rc++] = mp->mnt_fsname; |
429 |
|
args[rc++] = mp->mnt_dir; |
430 |
|
args[rc] = NULL; |
431 |
|
rc = wait4pid(spawn(args)); |
432 |
|
free(args[0]); |
433 |
|
if (!rc) |
434 |
|
break; |
435 |
|
errno = errno_save; |
436 |
|
} |
437 |
|
|
438 |
|
if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS)) |
439 |
break; |
break; |
440 |
bb_error_msg("%s is write-protected, mounting read-only", |
if (!(vfsflags & MS_SILENT)) |
441 |
mp->mnt_fsname); |
bb_error_msg("%s is write-protected, mounting read-only", |
442 |
|
mp->mnt_fsname); |
443 |
vfsflags |= MS_RDONLY; |
vfsflags |= MS_RDONLY; |
444 |
} |
} |
445 |
|
|
451 |
/* If the mount was successful, and we're maintaining an old-style |
/* If the mount was successful, and we're maintaining an old-style |
452 |
* mtab file by hand, add the new entry to it now. */ |
* mtab file by hand, add the new entry to it now. */ |
453 |
mtab: |
mtab: |
454 |
if (ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc && !(vfsflags & MS_REMOUNT)) { |
if (useMtab && !rc && !(vfsflags & MS_REMOUNT)) { |
455 |
char *fsname; |
char *fsname; |
456 |
FILE *mountTable = setmntent(bb_path_mtab_file, "a+"); |
FILE *mountTable = setmntent(bb_path_mtab_file, "a+"); |
457 |
|
const char *option_str = mount_option_str; |
458 |
int i; |
int i; |
459 |
|
|
460 |
if (!mountTable) { |
if (!mountTable) { |
461 |
bb_error_msg("no %s",bb_path_mtab_file); |
bb_error_msg("no %s", bb_path_mtab_file); |
462 |
goto ret; |
goto ret; |
463 |
} |
} |
464 |
|
|
465 |
// Add vfs string flags |
// Add vfs string flags |
466 |
|
|
467 |
for (i=0; mount_options[i].flags != MS_REMOUNT; i++) |
for (i = 0; mount_options[i] != MS_REMOUNT; i++) { |
468 |
if (mount_options[i].flags > 0 && (mount_options[i].flags & vfsflags)) |
if (mount_options[i] > 0 && (mount_options[i] & vfsflags)) |
469 |
append_mount_options(&(mp->mnt_opts), mount_options[i].name); |
append_mount_options(&(mp->mnt_opts), option_str); |
470 |
|
option_str += strlen(option_str) + 1; |
471 |
|
} |
472 |
|
|
473 |
// Remove trailing / (if any) from directory we mounted on |
// Remove trailing / (if any) from directory we mounted on |
474 |
|
|
475 |
i = strlen(mp->mnt_dir) - 1; |
i = strlen(mp->mnt_dir) - 1; |
476 |
if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = 0; |
if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0'; |
477 |
|
|
478 |
// Convert to canonical pathnames as needed |
// Convert to canonical pathnames as needed |
479 |
|
|
481 |
fsname = 0; |
fsname = 0; |
482 |
if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */ |
if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */ |
483 |
mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname); |
mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname); |
484 |
mp->mnt_type = "bind"; |
mp->mnt_type = (char*)"bind"; |
485 |
} |
} |
486 |
mp->mnt_freq = mp->mnt_passno = 0; |
mp->mnt_freq = mp->mnt_passno = 0; |
487 |
|
|
515 |
* Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com> |
* Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com> |
516 |
* Implemented the "bg", "fg" and "retry" mount options for NFS. |
* Implemented the "bg", "fg" and "retry" mount options for NFS. |
517 |
* |
* |
518 |
* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> |
* 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org> |
519 |
* - added Native Language Support |
* - added Native Language Support |
520 |
* |
* |
521 |
* Modified by Olaf Kirch and Trond Myklebust for new NFS code, |
* Modified by Olaf Kirch and Trond Myklebust for new NFS code, |
705 |
NFS_MOUNT_TCP = 0x0040, /* 2 */ |
NFS_MOUNT_TCP = 0x0040, /* 2 */ |
706 |
NFS_MOUNT_VER3 = 0x0080, /* 3 */ |
NFS_MOUNT_VER3 = 0x0080, /* 3 */ |
707 |
NFS_MOUNT_KERBEROS = 0x0100, /* 3 */ |
NFS_MOUNT_KERBEROS = 0x0100, /* 3 */ |
708 |
NFS_MOUNT_NONLM = 0x0200 /* 3 */ |
NFS_MOUNT_NONLM = 0x0200, /* 3 */ |
709 |
|
NFS_MOUNT_NORDIRPLUS = 0x4000 |
710 |
}; |
}; |
711 |
|
|
712 |
|
|
726 |
// Convert each NFSERR_BLAH into EBLAH |
// Convert each NFSERR_BLAH into EBLAH |
727 |
|
|
728 |
static const struct { |
static const struct { |
729 |
int stat; |
short stat; |
730 |
int errnum; |
short errnum; |
731 |
} nfs_errtbl[] = { |
} nfs_errtbl[] = { |
732 |
{0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST}, |
{0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST}, |
733 |
{19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG}, |
{19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG}, |
738 |
static char *nfs_strerror(int status) |
static char *nfs_strerror(int status) |
739 |
{ |
{ |
740 |
int i; |
int i; |
|
static char buf[sizeof("unknown nfs status return value: ") + sizeof(int)*3]; |
|
741 |
|
|
742 |
for (i = 0; nfs_errtbl[i].stat != -1; i++) { |
for (i = 0; nfs_errtbl[i].stat != -1; i++) { |
743 |
if (nfs_errtbl[i].stat == status) |
if (nfs_errtbl[i].stat == status) |
744 |
return strerror(nfs_errtbl[i].errnum); |
return strerror(nfs_errtbl[i].errnum); |
745 |
} |
} |
746 |
sprintf(buf, "unknown nfs status return value: %d", status); |
return xasprintf("unknown nfs status return value: %d", status); |
|
return buf; |
|
747 |
} |
} |
748 |
|
|
749 |
static bool_t xdr_fhandle(XDR *xdrs, fhandle objp) |
static bool_t xdr_fhandle(XDR *xdrs, fhandle objp) |
817 |
#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) |
#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) |
818 |
|
|
819 |
/* |
/* |
|
* nfs_mount_version according to the sources seen at compile time. |
|
|
*/ |
|
|
static int nfs_mount_version; |
|
|
static int kernel_version; |
|
|
|
|
|
/* |
|
820 |
* Unfortunately, the kernel prints annoying console messages |
* Unfortunately, the kernel prints annoying console messages |
821 |
* in case of an unexpected nfs mount version (instead of |
* in case of an unexpected nfs mount version (instead of |
822 |
* just returning some error). Therefore we'll have to try |
* just returning some error). Therefore we'll have to try |
830 |
static void |
static void |
831 |
find_kernel_nfs_mount_version(void) |
find_kernel_nfs_mount_version(void) |
832 |
{ |
{ |
833 |
if (kernel_version) |
int kernel_version; |
834 |
|
|
835 |
|
if (nfs_mount_version) |
836 |
return; |
return; |
837 |
|
|
838 |
nfs_mount_version = 4; /* default */ |
nfs_mount_version = 4; /* default */ |
849 |
} |
} |
850 |
} |
} |
851 |
|
|
852 |
static struct pmap * |
static void |
853 |
get_mountport(struct sockaddr_in *server_addr, |
get_mountport(struct pmap *pm_mnt, |
854 |
|
struct sockaddr_in *server_addr, |
855 |
long unsigned prog, |
long unsigned prog, |
856 |
long unsigned version, |
long unsigned version, |
857 |
long unsigned proto, |
long unsigned proto, |
858 |
long unsigned port) |
long unsigned port) |
859 |
{ |
{ |
860 |
struct pmaplist *pmap; |
struct pmaplist *pmap; |
|
static struct pmap p = {0, 0, 0, 0}; |
|
861 |
|
|
862 |
server_addr->sin_port = PMAPPORT; |
server_addr->sin_port = PMAPPORT; |
863 |
|
/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *). |
864 |
|
* I understand it like "IPv6 for this is not 100% ready" */ |
865 |
pmap = pmap_getmaps(server_addr); |
pmap = pmap_getmaps(server_addr); |
866 |
|
|
867 |
if (version > MAX_NFSPROT) |
if (version > MAX_NFSPROT) |
868 |
version = MAX_NFSPROT; |
version = MAX_NFSPROT; |
869 |
if (!prog) |
if (!prog) |
870 |
prog = MOUNTPROG; |
prog = MOUNTPROG; |
871 |
p.pm_prog = prog; |
pm_mnt->pm_prog = prog; |
872 |
p.pm_vers = version; |
pm_mnt->pm_vers = version; |
873 |
p.pm_prot = proto; |
pm_mnt->pm_prot = proto; |
874 |
p.pm_port = port; |
pm_mnt->pm_port = port; |
875 |
|
|
876 |
while (pmap) { |
while (pmap) { |
877 |
if (pmap->pml_map.pm_prog != prog) |
if (pmap->pml_map.pm_prog != prog) |
878 |
goto next; |
goto next; |
879 |
if (!version && p.pm_vers > pmap->pml_map.pm_vers) |
if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers) |
880 |
goto next; |
goto next; |
881 |
if (version > 2 && pmap->pml_map.pm_vers != version) |
if (version > 2 && pmap->pml_map.pm_vers != version) |
882 |
goto next; |
goto next; |
883 |
if (version && version <= 2 && pmap->pml_map.pm_vers > 2) |
if (version && version <= 2 && pmap->pml_map.pm_vers > 2) |
884 |
goto next; |
goto next; |
885 |
if (pmap->pml_map.pm_vers > MAX_NFSPROT || |
if (pmap->pml_map.pm_vers > MAX_NFSPROT || |
886 |
(proto && p.pm_prot && pmap->pml_map.pm_prot != proto) || |
(proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) || |
887 |
(port && pmap->pml_map.pm_port != port)) |
(port && pmap->pml_map.pm_port != port)) |
888 |
goto next; |
goto next; |
889 |
memcpy(&p, &pmap->pml_map, sizeof(p)); |
memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt)); |
890 |
next: |
next: |
891 |
pmap = pmap->pml_next; |
pmap = pmap->pml_next; |
892 |
} |
} |
893 |
if (!p.pm_vers) |
if (!pm_mnt->pm_vers) |
894 |
p.pm_vers = MOUNTVERS; |
pm_mnt->pm_vers = MOUNTVERS; |
895 |
if (!p.pm_port) |
if (!pm_mnt->pm_port) |
896 |
p.pm_port = MOUNTPORT; |
pm_mnt->pm_port = MOUNTPORT; |
897 |
if (!p.pm_prot) |
if (!pm_mnt->pm_prot) |
898 |
p.pm_prot = IPPROTO_TCP; |
pm_mnt->pm_prot = IPPROTO_TCP; |
|
return &p; |
|
899 |
} |
} |
900 |
|
|
901 |
|
#if BB_MMU |
902 |
static int daemonize(void) |
static int daemonize(void) |
903 |
{ |
{ |
|
int fd; |
|
904 |
int pid = fork(); |
int pid = fork(); |
905 |
if (pid < 0) /* error */ |
if (pid < 0) /* error */ |
906 |
return -errno; |
return -errno; |
907 |
if (pid > 0) /* parent */ |
if (pid > 0) /* parent */ |
908 |
return 0; |
return 0; |
909 |
/* child */ |
/* child */ |
910 |
fd = xopen(bb_dev_null, O_RDWR); |
close(0); |
911 |
dup2(fd, 0); |
xopen(bb_dev_null, O_RDWR); |
912 |
dup2(fd, 1); |
xdup2(0, 1); |
913 |
dup2(fd, 2); |
xdup2(0, 2); |
|
while (fd > 2) close(fd--); |
|
914 |
setsid(); |
setsid(); |
915 |
openlog(applet_name, LOG_PID, LOG_DAEMON); |
openlog(applet_name, LOG_PID, LOG_DAEMON); |
916 |
logmode = LOGMODE_SYSLOG; |
logmode = LOGMODE_SYSLOG; |
917 |
return 1; |
return 1; |
918 |
} |
} |
919 |
|
#else |
920 |
|
static inline int daemonize(void) { return -ENOSYS; } |
921 |
|
#endif |
922 |
|
|
923 |
// TODO |
// TODO |
924 |
static inline int we_saw_this_host_before(const char *hostname) |
static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM) |
925 |
{ |
{ |
926 |
return 0; |
return 0; |
927 |
} |
} |
940 |
} |
} |
941 |
|
|
942 |
// NB: mp->xxx fields may be trashed on exit |
// NB: mp->xxx fields may be trashed on exit |
943 |
static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts) |
static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) |
944 |
{ |
{ |
945 |
CLIENT *mclient; |
CLIENT *mclient; |
946 |
char *hostname; |
char *hostname; |
961 |
int port; |
int port; |
962 |
int mountport; |
int mountport; |
963 |
int proto; |
int proto; |
964 |
int bg; |
#if BB_MMU |
965 |
int soft; |
smallint bg = 0; |
966 |
int intr; |
#else |
967 |
int posix; |
enum { bg = 0 }; |
968 |
int nocto; |
#endif |
|
int noac; |
|
|
int nolock; |
|
969 |
int retry; |
int retry; |
|
int tcp; |
|
970 |
int mountprog; |
int mountprog; |
971 |
int mountvers; |
int mountvers; |
972 |
int nfsprog; |
int nfsprog; |
973 |
int nfsvers; |
int nfsvers; |
974 |
int retval; |
int retval; |
975 |
|
/* these all are one-bit really. 4.3.1 likes this combination: */ |
976 |
|
smallint tcp; |
977 |
|
smallint soft; |
978 |
|
int intr; |
979 |
|
int posix; |
980 |
|
int nocto; |
981 |
|
int noac; |
982 |
|
int nordirplus; |
983 |
|
int nolock; |
984 |
|
|
985 |
find_kernel_nfs_mount_version(); |
find_kernel_nfs_mount_version(); |
986 |
|
|
1014 |
bb_herror_msg("%s", hostname); |
bb_herror_msg("%s", hostname); |
1015 |
goto fail; |
goto fail; |
1016 |
} |
} |
1017 |
if (hp->h_length > sizeof(struct in_addr)) { |
if ((size_t)hp->h_length > sizeof(struct in_addr)) { |
1018 |
bb_error_msg("got bad hp->h_length"); |
bb_error_msg("got bad hp->h_length"); |
1019 |
hp->h_length = sizeof(struct in_addr); |
hp->h_length = sizeof(struct in_addr); |
1020 |
} |
} |
1041 |
* let the kernel decide. |
* let the kernel decide. |
1042 |
* timeo is filled in after we know whether it'll be TCP or UDP. */ |
* timeo is filled in after we know whether it'll be TCP or UDP. */ |
1043 |
memset(&data, 0, sizeof(data)); |
memset(&data, 0, sizeof(data)); |
1044 |
data.retrans = 3; |
data.retrans = 3; |
1045 |
data.acregmin = 3; |
data.acregmin = 3; |
1046 |
data.acregmax = 60; |
data.acregmax = 60; |
1047 |
data.acdirmin = 30; |
data.acdirmin = 30; |
1048 |
data.acdirmax = 60; |
data.acdirmax = 60; |
1049 |
data.namlen = NAME_MAX; |
data.namlen = NAME_MAX; |
1050 |
|
|
|
bg = 0; |
|
1051 |
soft = 0; |
soft = 0; |
1052 |
intr = 0; |
intr = 0; |
1053 |
posix = 0; |
posix = 0; |
1054 |
nocto = 0; |
nocto = 0; |
1055 |
nolock = 0; |
nolock = 0; |
1056 |
noac = 0; |
noac = 0; |
1057 |
|
nordirplus = 0; |
1058 |
retry = 10000; /* 10000 minutes ~ 1 week */ |
retry = 10000; /* 10000 minutes ~ 1 week */ |
1059 |
tcp = 0; |
tcp = 0; |
1060 |
|
|
1066 |
nfsvers = 0; |
nfsvers = 0; |
1067 |
|
|
1068 |
/* parse options */ |
/* parse options */ |
1069 |
|
if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) { |
|
for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) { |
|
1070 |
char *opteq = strchr(opt, '='); |
char *opteq = strchr(opt, '='); |
1071 |
if (opteq) { |
if (opteq) { |
1072 |
const char *const options[] = { |
int val, idx; |
1073 |
/* 0 */ "rsize", |
static const char options[] ALIGN1 = |
1074 |
/* 1 */ "wsize", |
/* 0 */ "rsize\0" |
1075 |
/* 2 */ "timeo", |
/* 1 */ "wsize\0" |
1076 |
/* 3 */ "retrans", |
/* 2 */ "timeo\0" |
1077 |
/* 4 */ "acregmin", |
/* 3 */ "retrans\0" |
1078 |
/* 5 */ "acregmax", |
/* 4 */ "acregmin\0" |
1079 |
/* 6 */ "acdirmin", |
/* 5 */ "acregmax\0" |
1080 |
/* 7 */ "acdirmax", |
/* 6 */ "acdirmin\0" |
1081 |
/* 8 */ "actimeo", |
/* 7 */ "acdirmax\0" |
1082 |
/* 9 */ "retry", |
/* 8 */ "actimeo\0" |
1083 |
/* 10 */ "port", |
/* 9 */ "retry\0" |
1084 |
/* 11 */ "mountport", |
/* 10 */ "port\0" |
1085 |
/* 12 */ "mounthost", |
/* 11 */ "mountport\0" |
1086 |
/* 13 */ "mountprog", |
/* 12 */ "mounthost\0" |
1087 |
/* 14 */ "mountvers", |
/* 13 */ "mountprog\0" |
1088 |
/* 15 */ "nfsprog", |
/* 14 */ "mountvers\0" |
1089 |
/* 16 */ "nfsvers", |
/* 15 */ "nfsprog\0" |
1090 |
/* 17 */ "vers", |
/* 16 */ "nfsvers\0" |
1091 |
/* 18 */ "proto", |
/* 17 */ "vers\0" |
1092 |
/* 19 */ "namlen", |
/* 18 */ "proto\0" |
1093 |
/* 20 */ "addr", |
/* 19 */ "namlen\0" |
1094 |
NULL |
/* 20 */ "addr\0"; |
1095 |
}; |
|
1096 |
int val = xatoi_u(opteq + 1); |
*opteq++ = '\0'; |
1097 |
*opteq = '\0'; |
idx = index_in_strings(options, opt); |
1098 |
switch (index_in_str_array(options, opt)) { |
switch (idx) { |
1099 |
|
case 12: // "mounthost" |
1100 |
|
mounthost = xstrndup(opteq, |
1101 |
|
strcspn(opteq, " \t\n\r,")); |
1102 |
|
continue; |
1103 |
|
case 18: // "proto" |
1104 |
|
if (!strncmp(opteq, "tcp", 3)) |
1105 |
|
tcp = 1; |
1106 |
|
else if (!strncmp(opteq, "udp", 3)) |
1107 |
|
tcp = 0; |
1108 |
|
else |
1109 |
|
bb_error_msg("warning: unrecognized proto= option"); |
1110 |
|
continue; |
1111 |
|
case 20: // "addr" - ignore |
1112 |
|
continue; |
1113 |
|
} |
1114 |
|
|
1115 |
|
val = xatoi_u(opteq); |
1116 |
|
switch (idx) { |
1117 |
case 0: // "rsize" |
case 0: // "rsize" |
1118 |
data.rsize = val; |
data.rsize = val; |
1119 |
break; |
continue; |
1120 |
case 1: // "wsize" |
case 1: // "wsize" |
1121 |
data.wsize = val; |
data.wsize = val; |
1122 |
break; |
continue; |
1123 |
case 2: // "timeo" |
case 2: // "timeo" |
1124 |
data.timeo = val; |
data.timeo = val; |
1125 |
break; |
continue; |
1126 |
case 3: // "retrans" |
case 3: // "retrans" |
1127 |
data.retrans = val; |
data.retrans = val; |
1128 |
break; |
continue; |
1129 |
case 4: // "acregmin" |
case 4: // "acregmin" |
1130 |
data.acregmin = val; |
data.acregmin = val; |
1131 |
break; |
continue; |
1132 |
case 5: // "acregmax" |
case 5: // "acregmax" |
1133 |
data.acregmax = val; |
data.acregmax = val; |
1134 |
break; |
continue; |
1135 |
case 6: // "acdirmin" |
case 6: // "acdirmin" |
1136 |
data.acdirmin = val; |
data.acdirmin = val; |
1137 |
break; |
continue; |
1138 |
case 7: // "acdirmax" |
case 7: // "acdirmax" |
1139 |
data.acdirmax = val; |
data.acdirmax = val; |
1140 |
break; |
continue; |
1141 |
case 8: // "actimeo" |
case 8: // "actimeo" |
1142 |
data.acregmin = val; |
data.acregmin = val; |
1143 |
data.acregmax = val; |
data.acregmax = val; |
1144 |
data.acdirmin = val; |
data.acdirmin = val; |
1145 |
data.acdirmax = val; |
data.acdirmax = val; |
1146 |
break; |
continue; |
1147 |
case 9: // "retry" |
case 9: // "retry" |
1148 |
retry = val; |
retry = val; |
1149 |
break; |
continue; |
1150 |
case 10: // "port" |
case 10: // "port" |
1151 |
port = val; |
port = val; |
1152 |
break; |
continue; |
1153 |
case 11: // "mountport" |
case 11: // "mountport" |
1154 |
mountport = val; |
mountport = val; |
1155 |
break; |
continue; |
|
case 12: // "mounthost" |
|
|
mounthost = xstrndup(opteq+1, |
|
|
strcspn(opteq+1," \t\n\r,")); |
|
|
break; |
|
1156 |
case 13: // "mountprog" |
case 13: // "mountprog" |
1157 |
mountprog = val; |
mountprog = val; |
1158 |
break; |
continue; |
1159 |
case 14: // "mountvers" |
case 14: // "mountvers" |
1160 |
mountvers = val; |
mountvers = val; |
1161 |
break; |
continue; |
1162 |
case 15: // "nfsprog" |
case 15: // "nfsprog" |
1163 |
nfsprog = val; |
nfsprog = val; |
1164 |
break; |
continue; |
1165 |
case 16: // "nfsvers" |
case 16: // "nfsvers" |
1166 |
case 17: // "vers" |
case 17: // "vers" |
1167 |
nfsvers = val; |
nfsvers = val; |
1168 |
break; |
continue; |
|
case 18: // "proto" |
|
|
if (!strncmp(opteq+1, "tcp", 3)) |
|
|
tcp = 1; |
|
|
else if (!strncmp(opteq+1, "udp", 3)) |
|
|
tcp = 0; |
|
|
else |
|
|
bb_error_msg("warning: unrecognized proto= option"); |
|
|
break; |
|
1169 |
case 19: // "namlen" |
case 19: // "namlen" |
1170 |
if (nfs_mount_version >= 2) |
//if (nfs_mount_version >= 2) |
1171 |
data.namlen = val; |
data.namlen = val; |
1172 |
else |
//else |
1173 |
bb_error_msg("warning: option namlen is not supported\n"); |
// bb_error_msg("warning: option namlen is not supported\n"); |
1174 |
break; |
continue; |
|
case 20: // "addr" - ignore |
|
|
break; |
|
1175 |
default: |
default: |
1176 |
bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val); |
bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val); |
1177 |
goto fail; |
goto fail; |
1178 |
} |
} |
1179 |
} |
} |
1180 |
else { |
else { /* not of the form opt=val */ |
1181 |
const char *const options[] = { |
static const char options[] ALIGN1 = |
1182 |
"bg", |
"bg\0" |
1183 |
"fg", |
"fg\0" |
1184 |
"soft", |
"soft\0" |
1185 |
"hard", |
"hard\0" |
1186 |
"intr", |
"intr\0" |
1187 |
"posix", |
"posix\0" |
1188 |
"cto", |
"cto\0" |
1189 |
"ac", |
"ac\0" |
1190 |
"tcp", |
"tcp\0" |
1191 |
"udp", |
"udp\0" |
1192 |
"lock", |
"lock\0" |
1193 |
NULL |
"rdirplus\0"; |
|
}; |
|
1194 |
int val = 1; |
int val = 1; |
1195 |
if (!strncmp(opt, "no", 2)) { |
if (!strncmp(opt, "no", 2)) { |
1196 |
val = 0; |
val = 0; |
1197 |
opt += 2; |
opt += 2; |
1198 |
} |
} |
1199 |
switch (index_in_str_array(options, opt)) { |
switch (index_in_strings(options, opt)) { |
1200 |
case 0: // "bg" |
case 0: // "bg" |
1201 |
|
#if BB_MMU |
1202 |
bg = val; |
bg = val; |
1203 |
|
#endif |
1204 |
break; |
break; |
1205 |
case 1: // "fg" |
case 1: // "fg" |
1206 |
|
#if BB_MMU |
1207 |
bg = !val; |
bg = !val; |
1208 |
|
#endif |
1209 |
break; |
break; |
1210 |
case 2: // "soft" |
case 2: // "soft" |
1211 |
soft = val; |
soft = val; |
1237 |
else |
else |
1238 |
bb_error_msg("warning: option nolock is not supported"); |
bb_error_msg("warning: option nolock is not supported"); |
1239 |
break; |
break; |
1240 |
|
case 11: //rdirplus |
1241 |
|
nordirplus = !val; |
1242 |
|
break; |
1243 |
default: |
default: |
1244 |
bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt); |
bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt); |
1245 |
goto fail; |
goto fail; |
1252 |
| (intr ? NFS_MOUNT_INTR : 0) |
| (intr ? NFS_MOUNT_INTR : 0) |
1253 |
| (posix ? NFS_MOUNT_POSIX : 0) |
| (posix ? NFS_MOUNT_POSIX : 0) |
1254 |
| (nocto ? NFS_MOUNT_NOCTO : 0) |
| (nocto ? NFS_MOUNT_NOCTO : 0) |
1255 |
| (noac ? NFS_MOUNT_NOAC : 0); |
| (noac ? NFS_MOUNT_NOAC : 0) |
1256 |
|
| (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0); |
1257 |
if (nfs_mount_version >= 2) |
if (nfs_mount_version >= 2) |
1258 |
data.flags |= (tcp ? NFS_MOUNT_TCP : 0); |
data.flags |= (tcp ? NFS_MOUNT_TCP : 0); |
1259 |
if (nfs_mount_version >= 3) |
if (nfs_mount_version >= 3) |
1283 |
* give up immediately, to avoid the initial timeout. |
* give up immediately, to avoid the initial timeout. |
1284 |
*/ |
*/ |
1285 |
if (bg && we_saw_this_host_before(hostname)) { |
if (bg && we_saw_this_host_before(hostname)) { |
1286 |
daemonized = daemonize(); /* parent or error */ |
daemonized = daemonize(); |
1287 |
if (daemonized <= 0) { /* parent or error */ |
if (daemonized <= 0) { /* parent or error */ |
1288 |
retval = -daemonized; |
retval = -daemonized; |
1289 |
goto ret; |
goto ret; |
1301 |
if (hp == NULL) { |
if (hp == NULL) { |
1302 |
bb_herror_msg("%s", mounthost); |
bb_herror_msg("%s", mounthost); |
1303 |
goto fail; |
goto fail; |
|
} else { |
|
|
if (hp->h_length > sizeof(struct in_addr)) { |
|
|
bb_error_msg("got bad hp->h_length?"); |
|
|
hp->h_length = sizeof(struct in_addr); |
|
|
} |
|
|
mount_server_addr.sin_family = AF_INET; |
|
|
memcpy(&mount_server_addr.sin_addr, |
|
|
hp->h_addr, hp->h_length); |
|
1304 |
} |
} |
1305 |
|
if ((size_t)hp->h_length > sizeof(struct in_addr)) { |
1306 |
|
bb_error_msg("got bad hp->h_length"); |
1307 |
|
hp->h_length = sizeof(struct in_addr); |
1308 |
|
} |
1309 |
|
mount_server_addr.sin_family = AF_INET; |
1310 |
|
memcpy(&mount_server_addr.sin_addr, |
1311 |
|
hp->h_addr, hp->h_length); |
1312 |
} |
} |
1313 |
} |
} |
1314 |
|
|
1327 |
{ |
{ |
1328 |
struct timeval total_timeout; |
struct timeval total_timeout; |
1329 |
struct timeval retry_timeout; |
struct timeval retry_timeout; |
1330 |
struct pmap* pm_mnt; |
struct pmap pm_mnt; |
1331 |
time_t t; |
time_t t; |
1332 |
time_t prevt; |
time_t prevt; |
1333 |
time_t timeout; |
time_t timeout; |
1336 |
retry_timeout.tv_usec = 0; |
retry_timeout.tv_usec = 0; |
1337 |
total_timeout.tv_sec = 20; |
total_timeout.tv_sec = 20; |
1338 |
total_timeout.tv_usec = 0; |
total_timeout.tv_usec = 0; |
1339 |
|
//FIXME: use monotonic()? |
1340 |
timeout = time(NULL) + 60 * retry; |
timeout = time(NULL) + 60 * retry; |
1341 |
prevt = 0; |
prevt = 0; |
1342 |
t = 30; |
t = 30; |
1343 |
retry: |
retry: |
1344 |
/* be careful not to use too many CPU cycles */ |
/* be careful not to use too many CPU cycles */ |
1345 |
if (t - prevt < 30) |
if (t - prevt < 30) |
1346 |
sleep(30); |
sleep(30); |
1347 |
|
|
1348 |
pm_mnt = get_mountport(&mount_server_addr, |
get_mountport(&pm_mnt, &mount_server_addr, |
1349 |
mountprog, |
mountprog, |
1350 |
mountvers, |
mountvers, |
1351 |
proto, |
proto, |
1352 |
mountport); |
mountport); |
1353 |
nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; |
nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers; |
1354 |
|
|
1355 |
/* contact the mount daemon via TCP */ |
/* contact the mount daemon via TCP */ |
1356 |
mount_server_addr.sin_port = htons(pm_mnt->pm_port); |
mount_server_addr.sin_port = htons(pm_mnt.pm_port); |
1357 |
msock = RPC_ANYSOCK; |
msock = RPC_ANYSOCK; |
1358 |
|
|
1359 |
switch (pm_mnt->pm_prot) { |
switch (pm_mnt.pm_prot) { |
1360 |
case IPPROTO_UDP: |
case IPPROTO_UDP: |
1361 |
mclient = clntudp_create(&mount_server_addr, |
mclient = clntudp_create(&mount_server_addr, |
1362 |
pm_mnt->pm_prog, |
pm_mnt.pm_prog, |
1363 |
pm_mnt->pm_vers, |
pm_mnt.pm_vers, |
1364 |
retry_timeout, |
retry_timeout, |
1365 |
&msock); |
&msock); |
1366 |
if (mclient) |
if (mclient) |
1367 |
break; |
break; |
1368 |
mount_server_addr.sin_port = htons(pm_mnt->pm_port); |
mount_server_addr.sin_port = htons(pm_mnt.pm_port); |
1369 |
msock = RPC_ANYSOCK; |
msock = RPC_ANYSOCK; |
1370 |
case IPPROTO_TCP: |
case IPPROTO_TCP: |
1371 |
mclient = clnttcp_create(&mount_server_addr, |
mclient = clnttcp_create(&mount_server_addr, |
1372 |
pm_mnt->pm_prog, |
pm_mnt.pm_prog, |
1373 |
pm_mnt->pm_vers, |
pm_mnt.pm_vers, |
1374 |
&msock, 0, 0); |
&msock, 0, 0); |
1375 |
break; |
break; |
1376 |
default: |
default: |
1377 |
mclient = 0; |
mclient = NULL; |
1378 |
} |
} |
1379 |
if (!mclient) { |
if (!mclient) { |
1380 |
if (!daemonized && prevt == 0) |
if (!daemonized && prevt == 0) |
1389 |
*/ |
*/ |
1390 |
memset(&status, 0, sizeof(status)); |
memset(&status, 0, sizeof(status)); |
1391 |
|
|
1392 |
if (pm_mnt->pm_vers == 3) |
if (pm_mnt.pm_vers == 3) |
1393 |
clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, |
clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, |
1394 |
(xdrproc_t) xdr_dirpath, |
(xdrproc_t) xdr_dirpath, |
1395 |
(caddr_t) &pathname, |
(caddr_t) &pathname, |
1415 |
error_msg_rpc(clnt_sperror(mclient, " ")); |
error_msg_rpc(clnt_sperror(mclient, " ")); |
1416 |
auth_destroy(mclient->cl_auth); |
auth_destroy(mclient->cl_auth); |
1417 |
clnt_destroy(mclient); |
clnt_destroy(mclient); |
1418 |
mclient = 0; |
mclient = NULL; |
1419 |
close(msock); |
close(msock); |
1420 |
|
msock = -1; |
1421 |
} |
} |
1422 |
|
|
1423 |
/* Timeout. We are going to retry... maybe */ |
/* Timeout. We are going to retry... maybe */ |
1440 |
goto retry; |
goto retry; |
1441 |
} |
} |
1442 |
|
|
1443 |
prepare_kernel_data: |
prepare_kernel_data: |
1444 |
|
|
1445 |
if (nfsvers == 2) { |
if (nfsvers == 2) { |
1446 |
if (status.nfsv2.fhs_status != 0) { |
if (status.nfsv2.fhs_status != 0) { |
1513 |
auth_destroy(mclient->cl_auth); |
auth_destroy(mclient->cl_auth); |
1514 |
clnt_destroy(mclient); |
clnt_destroy(mclient); |
1515 |
close(msock); |
close(msock); |
1516 |
|
msock = -1; |
1517 |
|
|
1518 |
if (bg) { |
if (bg) { |
1519 |
/* We must wait until mount directory is available */ |
/* We must wait until mount directory is available */ |
1523 |
if (!daemonized) { |
if (!daemonized) { |
1524 |
daemonized = daemonize(); |
daemonized = daemonize(); |
1525 |
if (daemonized <= 0) { /* parent or error */ |
if (daemonized <= 0) { /* parent or error */ |
1526 |
|
// FIXME: parent doesn't close fsock - ??! |
1527 |
retval = -daemonized; |
retval = -daemonized; |
1528 |
goto ret; |
goto ret; |
1529 |
} |
} |
1535 |
} |
} |
1536 |
} |
} |
1537 |
|
|
1538 |
do_mount: /* perform actual mount */ |
do_mount: /* perform actual mount */ |
1539 |
|
|
1540 |
mp->mnt_type = "nfs"; |
mp->mnt_type = (char*)"nfs"; |
1541 |
retval = mount_it_now(mp, vfsflags, (char*)&data); |
retval = mount_it_now(mp, vfsflags, (char*)&data); |
1542 |
goto ret; |
goto ret; |
1543 |
|
|
1544 |
fail: /* abort */ |
fail: /* abort */ |
1545 |
|
|
1546 |
if (msock != -1) { |
if (msock >= 0) { |
1547 |
if (mclient) { |
if (mclient) { |
1548 |
auth_destroy(mclient->cl_auth); |
auth_destroy(mclient->cl_auth); |
1549 |
clnt_destroy(mclient); |
clnt_destroy(mclient); |
1550 |
} |
} |
1551 |
close(msock); |
close(msock); |
1552 |
} |
} |
1553 |
if (fsock != -1) |
if (fsock >= 0) |
1554 |
close(fsock); |
close(fsock); |
1555 |
|
|
1556 |
ret: |
ret: |
1557 |
free(hostname); |
free(hostname); |
1558 |
free(mounthost); |
free(mounthost); |
1559 |
free(filteropts); |
free(filteropts); |
1563 |
#else /* !ENABLE_FEATURE_MOUNT_NFS */ |
#else /* !ENABLE_FEATURE_MOUNT_NFS */ |
1564 |
|
|
1565 |
/* Never called. Call should be optimized out. */ |
/* Never called. Call should be optimized out. */ |
1566 |
int nfsmount(struct mntent *mp, int vfsflags, char *filteropts); |
int nfsmount(struct mntent *mp, long vfsflags, char *filteropts); |
1567 |
|
|
1568 |
#endif /* !ENABLE_FEATURE_MOUNT_NFS */ |
#endif /* !ENABLE_FEATURE_MOUNT_NFS */ |
1569 |
|
|
1572 |
// NB: mp->xxx fields may be trashed on exit |
// NB: mp->xxx fields may be trashed on exit |
1573 |
static int singlemount(struct mntent *mp, int ignore_busy) |
static int singlemount(struct mntent *mp, int ignore_busy) |
1574 |
{ |
{ |
1575 |
int rc = -1, vfsflags; |
int rc = -1; |
1576 |
|
long vfsflags; |
1577 |
char *loopFile = 0, *filteropts = 0; |
char *loopFile = 0, *filteropts = 0; |
1578 |
llist_t *fl = 0; |
llist_t *fl = 0; |
1579 |
struct stat st; |
struct stat st; |
1582 |
|
|
1583 |
// Treat fstype "auto" as unspecified. |
// Treat fstype "auto" as unspecified. |
1584 |
|
|
1585 |
if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0; |
if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0) |
1586 |
|
mp->mnt_type = NULL; |
1587 |
|
|
1588 |
|
// Might this be a virtual filesystem? |
1589 |
|
|
1590 |
|
if (ENABLE_FEATURE_MOUNT_HELPERS |
1591 |
|
&& (strchr(mp->mnt_fsname, '#')) |
1592 |
|
) { |
1593 |
|
char *s, *p, *args[35]; |
1594 |
|
int n = 0; |
1595 |
|
// FIXME: does it allow execution of arbitrary commands?! |
1596 |
|
// What args[0] can end up with? |
1597 |
|
for (s = p = mp->mnt_fsname; *s && n < 35-3; ++s) { |
1598 |
|
if (s[0] == '#' && s[1] != '#') { |
1599 |
|
*s = '\0'; |
1600 |
|
args[n++] = p; |
1601 |
|
p = s + 1; |
1602 |
|
} |
1603 |
|
} |
1604 |
|
args[n++] = p; |
1605 |
|
args[n++] = mp->mnt_dir; |
1606 |
|
args[n] = NULL; |
1607 |
|
rc = wait4pid(xspawn(args)); |
1608 |
|
goto report_error; |
1609 |
|
} |
1610 |
|
|
1611 |
// Might this be an CIFS filesystem? |
// Might this be an CIFS filesystem? |
1612 |
|
|
1613 |
if (ENABLE_FEATURE_MOUNT_CIFS && |
if (ENABLE_FEATURE_MOUNT_CIFS |
1614 |
(!mp->mnt_type || !strcmp(mp->mnt_type,"cifs")) && |
&& (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0) |
1615 |
(mp->mnt_fsname[0]==mp->mnt_fsname[1] && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\'))) |
&& (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\') |
1616 |
{ |
&& mp->mnt_fsname[0] == mp->mnt_fsname[1] |
1617 |
struct hostent *he; |
) { |
1618 |
char ip[32], *s; |
len_and_sockaddr *lsa; |
1619 |
|
char *ip, *dotted; |
1620 |
|
char *s; |
1621 |
|
|
1622 |
rc = 1; |
rc = 1; |
1623 |
// Replace '/' with '\' and verify that unc points to "//server/share". |
// Replace '/' with '\' and verify that unc points to "//server/share". |
1628 |
// get server IP |
// get server IP |
1629 |
|
|
1630 |
s = strrchr(mp->mnt_fsname, '\\'); |
s = strrchr(mp->mnt_fsname, '\\'); |
1631 |
if (s == mp->mnt_fsname+1) goto report_error; |
if (s <= mp->mnt_fsname+1) goto report_error; |
1632 |
*s = 0; |
*s = '\0'; |
1633 |
he = gethostbyname(mp->mnt_fsname+2); |
lsa = host2sockaddr(mp->mnt_fsname+2, 0); |
1634 |
*s = '\\'; |
*s = '\\'; |
1635 |
if (!he) goto report_error; |
if (!lsa) goto report_error; |
1636 |
|
|
1637 |
// Insert ip=... option into string flags. (NOTE: Add IPv6 support.) |
// insert ip=... option into string flags. |
1638 |
|
|
1639 |
sprintf(ip, "ip=%d.%d.%d.%d", he->h_addr[0], he->h_addr[1], |
dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); |
1640 |
he->h_addr[2], he->h_addr[3]); |
ip = xasprintf("ip=%s", dotted); |
1641 |
parse_mount_options(ip, &filteropts); |
parse_mount_options(ip, &filteropts); |
1642 |
|
|
1643 |
// compose new unc '\\server-ip\share' |
// compose new unc '\\server-ip\share' |
1644 |
|
// (s => slash after hostname) |
1645 |
|
|
1646 |
mp->mnt_fsname = xasprintf("\\\\%s%s", ip+3, |
mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s); |
|
strchr(mp->mnt_fsname+2,'\\')); |
|
1647 |
|
|
1648 |
// lock is required |
// lock is required |
1649 |
vfsflags |= MS_MANDLOCK; |
vfsflags |= MS_MANDLOCK; |
1650 |
|
|
1651 |
mp->mnt_type = "cifs"; |
mp->mnt_type = (char*)"cifs"; |
1652 |
rc = mount_it_now(mp, vfsflags, filteropts); |
rc = mount_it_now(mp, vfsflags, filteropts); |
1653 |
if (ENABLE_FEATURE_CLEAN_UP) free(mp->mnt_fsname); |
if (ENABLE_FEATURE_CLEAN_UP) { |
1654 |
|
free(mp->mnt_fsname); |
1655 |
|
free(ip); |
1656 |
|
free(dotted); |
1657 |
|
free(lsa); |
1658 |
|
} |
1659 |
goto report_error; |
goto report_error; |
1660 |
} |
} |
1661 |
|
|
1662 |
// Might this be an NFS filesystem? |
// Might this be an NFS filesystem? |
1663 |
|
|
1664 |
if (ENABLE_FEATURE_MOUNT_NFS && |
if (ENABLE_FEATURE_MOUNT_NFS |
1665 |
(!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) && |
&& (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs")) |
1666 |
strchr(mp->mnt_fsname, ':') != NULL) |
&& strchr(mp->mnt_fsname, ':') != NULL |
1667 |
{ |
) { |
1668 |
rc = nfsmount(mp, vfsflags, filteropts); |
rc = nfsmount(mp, vfsflags, filteropts); |
1669 |
goto report_error; |
goto report_error; |
1670 |
} |
} |
1671 |
|
|
1672 |
// Look at the file. (Not found isn't a failure for remount, or for |
// Look at the file. (Not found isn't a failure for remount, or for |
1673 |
// a synthetic filesystem like proc or sysfs.) |
// a synthetic filesystem like proc or sysfs.) |
1674 |
|
// (We use stat, not lstat, in order to allow |
1675 |
|
// mount symlink_to_file_or_blkdev dir) |
1676 |
|
|
1677 |
if (!lstat(mp->mnt_fsname, &st) && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) |
if (!stat(mp->mnt_fsname, &st) |
1678 |
{ |
&& !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)) |
1679 |
|
) { |
1680 |
// Do we need to allocate a loopback device for it? |
// Do we need to allocate a loopback device for it? |
1681 |
|
|
1682 |
if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { |
if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { |
1683 |
loopFile = bb_simplify_path(mp->mnt_fsname); |
loopFile = bb_simplify_path(mp->mnt_fsname); |
1684 |
mp->mnt_fsname = 0; |
mp->mnt_fsname = NULL; /* will receive malloced loop dev name */ |
1685 |
switch (set_loop(&(mp->mnt_fsname), loopFile, 0)) { |
if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) { |
1686 |
case 0: |
if (errno == EPERM || errno == EACCES) |
1687 |
case 1: |
bb_error_msg(bb_msg_perm_denied_are_you_root); |
1688 |
break; |
else |
1689 |
default: |
bb_perror_msg("cannot setup loop device"); |
|
bb_error_msg( errno == EPERM || errno == EACCES |
|
|
? bb_msg_perm_denied_are_you_root |
|
|
: "cannot setup loop device"); |
|
1690 |
return errno; |
return errno; |
1691 |
} |
} |
1692 |
|
|
1701 |
|
|
1702 |
if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) |
if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) |
1703 |
rc = mount_it_now(mp, vfsflags, filteropts); |
rc = mount_it_now(mp, vfsflags, filteropts); |
|
|
|
|
// Loop through filesystem types until mount succeeds or we run out |
|
|
|
|
1704 |
else { |
else { |
1705 |
|
// Loop through filesystem types until mount succeeds |
1706 |
|
// or we run out |
1707 |
|
|
1708 |
/* Initialize list of block backed filesystems. This has to be |
/* Initialize list of block backed filesystems. This has to be |
1709 |
* done here so that during "mount -a", mounts after /proc shows up |
* done here so that during "mount -a", mounts after /proc shows up |
1732 |
} |
} |
1733 |
} |
} |
1734 |
|
|
1735 |
report_error: |
report_error: |
1736 |
if (ENABLE_FEATURE_CLEAN_UP) free(filteropts); |
if (ENABLE_FEATURE_CLEAN_UP) |
1737 |
|
free(filteropts); |
1738 |
|
|
1739 |
if (rc && errno == EBUSY && ignore_busy) rc = 0; |
if (errno == EBUSY && ignore_busy) |
1740 |
|
return 0; |
1741 |
if (rc < 0) |
if (rc < 0) |
1742 |
/* perror here sometimes says "mounting ... on ... failed: Success" */ |
bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); |
|
bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); |
|
|
|
|
1743 |
return rc; |
return rc; |
1744 |
} |
} |
1745 |
|
|
1746 |
// Parse options, if necessary parse fstab/mtab, and call singlemount for |
// Parse options, if necessary parse fstab/mtab, and call singlemount for |
1747 |
// each directory to be mounted. |
// each directory to be mounted. |
1748 |
|
|
1749 |
const char must_be_root[] = "you must be root"; |
static const char must_be_root[] ALIGN1 = "you must be root"; |
1750 |
|
|
1751 |
int mount_main(int argc, char **argv) |
int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1752 |
|
int mount_main(int argc UNUSED_PARAM, char **argv) |
1753 |
{ |
{ |
1754 |
enum { OPT_ALL = 0x10 }; |
char *cmdopts = xstrdup(""); |
1755 |
|
char *fstype = NULL; |
1756 |
char *cmdopts = xstrdup(""), *fstype=0, *storage_path=0; |
char *storage_path; |
1757 |
char *opt_o; |
llist_t *lst_o = NULL; |
1758 |
const char *fstabname; |
const char *fstabname; |
1759 |
FILE *fstab; |
FILE *fstab; |
1760 |
int i, j, rc = 0; |
int i, j, rc = 0; |
1761 |
unsigned opt; |
unsigned opt; |
1762 |
struct mntent mtpair[2], *mtcur = mtpair; |
struct mntent mtpair[2], *mtcur = mtpair; |
1763 |
SKIP_DESKTOP(const int nonroot = 0;) |
SKIP_DESKTOP(const int nonroot = 0;) |
|
USE_DESKTOP( int nonroot = (getuid() != 0);) |
|
1764 |
|
|
1765 |
/* parse long options, like --bind and --move. Note that -o option |
USE_DESKTOP(int nonroot = ) sanitize_env_if_suid(); |
|
* and --option are synonymous. Yes, this means --remount,rw works. */ |
|
1766 |
|
|
1767 |
for (i = j = 0; i < argc; i++) { |
// Parse long options, like --bind and --move. Note that -o option |
1768 |
if (argv[i][0] == '-' && argv[i][1] == '-') { |
// and --option are synonymous. Yes, this means --remount,rw works. |
1769 |
append_mount_options(&cmdopts, argv[i]+2); |
for (i = j = 1; argv[i]; i++) { |
1770 |
} else argv[j++] = argv[i]; |
if (argv[i][0] == '-' && argv[i][1] == '-') |
1771 |
|
append_mount_options(&cmdopts, argv[i] + 2); |
1772 |
|
else |
1773 |
|
argv[j++] = argv[i]; |
1774 |
} |
} |
1775 |
argv[j] = 0; |
argv[j] = NULL; |
|
argc = j; |
|
1776 |
|
|
1777 |
// Parse remaining options |
// Parse remaining options |
1778 |
|
// Max 2 params; -v is a counter |
1779 |
opt = getopt32(argc, argv, "o:t:rwanfvs", &opt_o, &fstype); |
opt_complementary = "?2o::" USE_FEATURE_MOUNT_VERBOSE(":vv"); |
1780 |
if (opt & 0x1) append_mount_options(&cmdopts, opt_o); // -o |
opt = getopt32(argv, OPTION_STR, &lst_o, &fstype |
1781 |
//if (opt & 0x2) // -t |
USE_FEATURE_MOUNT_VERBOSE(, &verbose)); |
1782 |
if (opt & 0x4) append_mount_options(&cmdopts, "ro"); // -r |
while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o |
1783 |
if (opt & 0x8) append_mount_options(&cmdopts, "rw"); // -w |
if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r |
1784 |
//if (opt & 0x10) // -a |
if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w |
|
if (opt & 0x20) USE_FEATURE_MTAB_SUPPORT(useMtab = 0); // -n |
|
|
if (opt & 0x40) USE_FEATURE_MTAB_SUPPORT(fakeIt = 1); // -f |
|
|
//if (opt & 0x80) // -v: verbose (ignore) |
|
|
//if (opt & 0x100) // -s: sloppy (ignore) |
|
1785 |
argv += optind; |
argv += optind; |
|
argc -= optind; |
|
|
|
|
|
// Three or more non-option arguments? Die with a usage message. |
|
|
|
|
|
if (argc > 2) bb_show_usage(); |
|
1786 |
|
|
1787 |
// If we have no arguments, show currently mounted filesystems |
// If we have no arguments, show currently mounted filesystems |
1788 |
|
if (!argv[0]) { |
1789 |
if (!argc) { |
if (!(opt & OPT_a)) { |
|
if (!(opt & OPT_ALL)) { |
|
1790 |
FILE *mountTable = setmntent(bb_path_mtab_file, "r"); |
FILE *mountTable = setmntent(bb_path_mtab_file, "r"); |
1791 |
|
|
1792 |
if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file); |
if (!mountTable) |
1793 |
|
bb_error_msg_and_die("no %s", bb_path_mtab_file); |
1794 |
|
|
1795 |
while (getmntent_r(mountTable, mtpair, bb_common_bufsiz1, |
while (getmntent_r(mountTable, &mtpair[0], getmntent_buf, |
1796 |
sizeof(bb_common_bufsiz1))) |
GETMNTENT_BUFSIZE)) |
1797 |
{ |
{ |
1798 |
// Don't show rootfs. FIXME: why?? |
// Don't show rootfs. FIXME: why?? |
1799 |
// util-linux 2.12a happily shows rootfs... |
// util-linux 2.12a happily shows rootfs... |
1804 |
mtpair->mnt_dir, mtpair->mnt_type, |
mtpair->mnt_dir, mtpair->mnt_type, |
1805 |
mtpair->mnt_opts); |
mtpair->mnt_opts); |
1806 |
} |
} |
1807 |
if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable); |
if (ENABLE_FEATURE_CLEAN_UP) |
1808 |
|
endmntent(mountTable); |
1809 |
return EXIT_SUCCESS; |
return EXIT_SUCCESS; |
1810 |
} |
} |
1811 |
} else storage_path = bb_simplify_path(argv[0]); |
storage_path = NULL; |
1812 |
|
} else { |
1813 |
// When we have two arguments, the second is the directory and we can |
// When we have two arguments, the second is the directory and we can |
1814 |
// skip looking at fstab entirely. We can always abspath() the directory |
// skip looking at fstab entirely. We can always abspath() the directory |
1815 |
// argument when we get it. |
// argument when we get it. |
1816 |
|
if (argv[1]) { |
1817 |
if (argc == 2) { |
if (nonroot) |
1818 |
if (nonroot) |
bb_error_msg_and_die(must_be_root); |
1819 |
bb_error_msg_and_die(must_be_root); |
mtpair->mnt_fsname = argv[0]; |
1820 |
mtpair->mnt_fsname = argv[0]; |
mtpair->mnt_dir = argv[1]; |
1821 |
mtpair->mnt_dir = argv[1]; |
mtpair->mnt_type = fstype; |
1822 |
mtpair->mnt_type = fstype; |
mtpair->mnt_opts = cmdopts; |
1823 |
mtpair->mnt_opts = cmdopts; |
if (ENABLE_FEATURE_MOUNT_LABEL) { |
1824 |
rc = singlemount(mtpair, 0); |
resolve_mount_spec(&mtpair->mnt_fsname); |
1825 |
goto clean_up; |
} |
1826 |
|
rc = singlemount(mtpair, 0); |
1827 |
|
return rc; |
1828 |
|
} |
1829 |
|
storage_path = bb_simplify_path(argv[0]); // malloced |
1830 |
} |
} |
1831 |
|
|
1832 |
i = parse_mount_options(cmdopts, 0); |
// Past this point, we are handling either "mount -a [opts]" |
1833 |
|
// or "mount [opts] single_param" |
1834 |
|
|
1835 |
|
i = parse_mount_options(cmdopts, 0); // FIXME: should be "long", not "int" |
1836 |
if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags |
if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags |
1837 |
bb_error_msg_and_die(must_be_root); |
bb_error_msg_and_die(must_be_root); |
1838 |
|
|
1839 |
// If we have a shared subtree flag, don't worry about fstab or mtab. |
// If we have a shared subtree flag, don't worry about fstab or mtab. |
1840 |
|
if (ENABLE_FEATURE_MOUNT_FLAGS |
1841 |
if (ENABLE_FEATURE_MOUNT_FLAGS && |
&& (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) |
1842 |
(i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))) |
) { |
1843 |
{ |
rc = verbose_mount(/*source:*/ "", /*target:*/ argv[0], |
1844 |
rc = mount("", argv[0], "", i, ""); |
/*type:*/ "", /*flags:*/ i, /*data:*/ ""); |
1845 |
if (rc) bb_perror_msg_and_die("%s", argv[0]); |
if (rc) |
1846 |
goto clean_up; |
bb_simple_perror_msg_and_die(argv[0]); |
1847 |
|
return rc; |
1848 |
} |
} |
1849 |
|
|
1850 |
// Open either fstab or mtab |
// Open either fstab or mtab |
|
|
|
1851 |
fstabname = "/etc/fstab"; |
fstabname = "/etc/fstab"; |
1852 |
if (i & MS_REMOUNT) { |
if (i & MS_REMOUNT) { |
1853 |
|
// WARNING. I am not sure this matches util-linux's |
1854 |
|
// behavior. It's possible util-linux does not |
1855 |
|
// take -o opts from mtab (takes only mount source). |
1856 |
fstabname = bb_path_mtab_file; |
fstabname = bb_path_mtab_file; |
1857 |
} |
} |
1858 |
fstab = setmntent(fstabname, "r"); |
fstab = setmntent(fstabname, "r"); |
1859 |
if (!fstab) |
if (!fstab) |
1860 |
bb_perror_msg_and_die("cannot read %s", fstabname); |
bb_perror_msg_and_die("cannot read %s", fstabname); |
1861 |
|
|
1862 |
// Loop through entries until we find what we're looking for. |
// Loop through entries until we find what we're looking for |
|
|
|
1863 |
memset(mtpair, 0, sizeof(mtpair)); |
memset(mtpair, 0, sizeof(mtpair)); |
1864 |
for (;;) { |
for (;;) { |
1865 |
struct mntent *mtnext = (mtcur==mtpair ? mtpair+1 : mtpair); |
struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair); |
1866 |
|
|
1867 |
// Get next fstab entry |
// Get next fstab entry |
1868 |
|
if (!getmntent_r(fstab, mtcur, getmntent_buf |
1869 |
if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1 |
+ (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0), |
1870 |
+ (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0), |
GETMNTENT_BUFSIZE/2) |
1871 |
sizeof(bb_common_bufsiz1)/2)) |
) { // End of fstab/mtab is reached |
1872 |
{ |
mtcur = mtother; // the thing we found last time |
1873 |
// Were we looking for something specific? |
break; |
|
|
|
|
if (argc) { |
|
|
|
|
|
// If we didn't find anything, complain. |
|
|
|
|
|
if (!mtnext->mnt_fsname) |
|
|
bb_error_msg_and_die("can't find %s in %s", |
|
|
argv[0], fstabname); |
|
|
|
|
|
mtcur = mtnext; |
|
|
if (nonroot) { |
|
|
// fstab must have "users" or "user" |
|
|
if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS)) |
|
|
bb_error_msg_and_die(must_be_root); |
|
|
} |
|
|
|
|
|
// Mount the last thing we found. |
|
|
|
|
|
mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); |
|
|
append_mount_options(&(mtcur->mnt_opts), cmdopts); |
|
|
rc = singlemount(mtcur, 0); |
|
|
free(mtcur->mnt_opts); |
|
|
} |
|
|
goto clean_up; |
|
1874 |
} |
} |
1875 |
|
|
1876 |
/* If we're trying to mount something specific and this isn't it, |
// If we're trying to mount something specific and this isn't it, |
1877 |
* skip it. Note we must match both the exact text in fstab (ala |
// skip it. Note we must match the exact text in fstab (ala |
1878 |
* "proc") or a full path from root */ |
// "proc") or a full path from root |
1879 |
|
if (argv[0]) { |
|
if (argc) { |
|
1880 |
|
|
1881 |
// Is this what we're looking for? |
// Is this what we're looking for? |
|
|
|
1882 |
if (strcmp(argv[0], mtcur->mnt_fsname) && |
if (strcmp(argv[0], mtcur->mnt_fsname) && |
1883 |
strcmp(storage_path, mtcur->mnt_fsname) && |
strcmp(storage_path, mtcur->mnt_fsname) && |
1884 |
strcmp(argv[0], mtcur->mnt_dir) && |
strcmp(argv[0], mtcur->mnt_dir) && |
1885 |
strcmp(storage_path, mtcur->mnt_dir)) continue; |
strcmp(storage_path, mtcur->mnt_dir)) continue; |
1886 |
|
|
1887 |
// Remember this entry. Something later may have overmounted |
// Remember this entry. Something later may have |
1888 |
// it, and we want the _last_ match. |
// overmounted it, and we want the _last_ match. |
1889 |
|
mtcur = mtother; |
|
mtcur = mtnext; |
|
|
|
|
|
// If we're mounting all. |
|
1890 |
|
|
1891 |
|
// If we're mounting all |
1892 |
} else { |
} else { |
1893 |
// Do we need to match a filesystem type? |
// Do we need to match a filesystem type? |
1894 |
// TODO: support "-t type1,type2"; "-t notype1,type2" |
if (fstype && match_fstype(mtcur, fstype)) |
1895 |
|
continue; |
|
if (fstype && strcmp(mtcur->mnt_type, fstype)) continue; |
|
1896 |
|
|
1897 |
// Skip noauto and swap anyway. |
// Skip noauto and swap anyway. |
1898 |
|
if (parse_mount_options(mtcur->mnt_opts, 0) & (MOUNT_NOAUTO | MOUNT_SWAP)) |
1899 |
if (parse_mount_options(mtcur->mnt_opts, 0) |
continue; |
|
& (MOUNT_NOAUTO | MOUNT_SWAP)) continue; |
|
1900 |
|
|
1901 |
// No, mount -a won't mount anything, |
// No, mount -a won't mount anything, |
1902 |
// even user mounts, for mere humans. |
// even user mounts, for mere humans |
|
|
|
1903 |
if (nonroot) |
if (nonroot) |
1904 |
bb_error_msg_and_die(must_be_root); |
bb_error_msg_and_die(must_be_root); |
1905 |
|
|
1906 |
// Mount this thing. |
// Mount this thing |
1907 |
|
if (ENABLE_FEATURE_MOUNT_LABEL) |
1908 |
|
resolve_mount_spec(&mtpair->mnt_fsname); |
1909 |
|
|
1910 |
// NFS mounts want this to be xrealloc-able |
// NFS mounts want this to be xrealloc-able |
1911 |
mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); |
mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); |
1912 |
if (singlemount(mtcur, 1)) { |
if (singlemount(mtcur, 1)) { |
1913 |
/* Count number of failed mounts */ |
// Count number of failed mounts |
1914 |
rc++; |
rc++; |
1915 |
} |
} |
1916 |
free(mtcur->mnt_opts); |
free(mtcur->mnt_opts); |
1917 |
} |
} |
1918 |
} |
} |
|
if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab); |
|
1919 |
|
|
1920 |
clean_up: |
// End of fstab/mtab is reached. |
1921 |
|
// Were we looking for something specific? |
1922 |
|
if (argv[0]) { |
1923 |
|
// If we didn't find anything, complain |
1924 |
|
if (!mtcur->mnt_fsname) |
1925 |
|
bb_error_msg_and_die("can't find %s in %s", |
1926 |
|
argv[0], fstabname); |
1927 |
|
if (nonroot) { |
1928 |
|
// fstab must have "users" or "user" |
1929 |
|
if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS)) |
1930 |
|
bb_error_msg_and_die(must_be_root); |
1931 |
|
} |
1932 |
|
|
1933 |
|
// Mount the last thing we found |
1934 |
|
mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); |
1935 |
|
append_mount_options(&(mtcur->mnt_opts), cmdopts); |
1936 |
|
if (ENABLE_FEATURE_MOUNT_LABEL) { |
1937 |
|
resolve_mount_spec(&mtpair->mnt_fsname); |
1938 |
|
} |
1939 |
|
rc = singlemount(mtcur, 0); |
1940 |
|
if (ENABLE_FEATURE_CLEAN_UP) |
1941 |
|
free(mtcur->mnt_opts); |
1942 |
|
} |
1943 |
|
|
1944 |
|
if (ENABLE_FEATURE_CLEAN_UP) |
1945 |
|
endmntent(fstab); |
1946 |
if (ENABLE_FEATURE_CLEAN_UP) { |
if (ENABLE_FEATURE_CLEAN_UP) { |
1947 |
free(storage_path); |
free(storage_path); |
1948 |
free(cmdopts); |
free(cmdopts); |
1949 |
} |
} |
|
|
|
1950 |
return rc; |
return rc; |
1951 |
} |
} |