blob: 902df34e0f8cb3872cab9271984483a57759e9a1 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002/*
Eric Andersen596e5461999-10-07 08:30:23 +00003 * Mini mount implementation for busybox
4 *
Eric Andersenc4996011999-10-20 22:08:37 +00005 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00006 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Rob Landleydc0955b2006-03-14 18:16:25 +00007 * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
Eric Andersen596e5461999-10-07 08:30:23 +00008 *
Rob Landley7b363fd2005-12-20 17:18:01 +00009 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Erik Andersenb7cc49d2000-01-13 06:38:14 +000010 */
Eric Andersencc8ed391999-10-05 16:24:54 +000011
Rob Landley22d26fc2006-06-15 15:49:36 +000012/* Design notes: There is no spec for mount. Remind me to write one.
Rob Landleydc0955b2006-03-14 18:16:25 +000013
14 mount_main() calls singlemount() which calls mount_it_now().
Eric Andersen9601a1c2006-03-20 18:07:50 +000015
Rob Landleydc0955b2006-03-14 18:16:25 +000016 mount_main() can loop through /etc/fstab for mount -a
17 singlemount() can loop through /etc/filesystems for fstype detection.
18 mount_it_now() does the actual mount.
19*/
20
Eric Andersencc8ed391999-10-05 16:24:54 +000021#include <mntent.h>
Bernhard Reutner-Fischerf4701962008-01-27 12:50:12 +000022#include <syslog.h>
Denis Vlasenkode7684a2008-02-18 21:08:49 +000023#include "libbb.h"
Eric Andersenbd22ed82000-07-08 18:55:24 +000024
Denis Vlasenkode7684a2008-02-18 21:08:49 +000025/* For FEATURE_MOUNT_LABEL only */
26#include "volume_id.h"
27
28/* Needed for nfs support only */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +000029#include <sys/utsname.h>
30#undef TRUE
31#undef FALSE
32#include <rpc/rpc.h>
33#include <rpc/pmap_prot.h>
34#include <rpc/pmap_clnt.h>
35
Denis Vlasenko2535f122007-09-15 13:28:30 +000036#ifndef MS_SILENT
37#define MS_SILENT (1 << 15)
38#endif
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +000039/* Grab more as needed from util-linux's mount/mount_constants.h */
40#ifndef MS_DIRSYNC
41#define MS_DIRSYNC 128 /* Directory modifications are synchronous */
42#endif
43
Denis Vlasenko30a64cd2006-09-15 15:12:00 +000044
Denis Vlasenko908d6b72006-12-18 23:07:42 +000045#if defined(__dietlibc__)
46/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
47 * dietlibc-0.30 does not have implementation of getmntent_r() */
Denis Vlasenko63430ae2007-10-29 19:18:39 +000048static struct mntent *getmntent_r(FILE* stream, struct mntent* result, char* buffer, int bufsize)
Denis Vlasenko908d6b72006-12-18 23:07:42 +000049{
Denis Vlasenko908d6b72006-12-18 23:07:42 +000050 struct mntent* ment = getmntent(stream);
51 memcpy(result, ment, sizeof(struct mntent));
52 return result;
53}
54#endif
55
56
Rob Landleydc0955b2006-03-14 18:16:25 +000057// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +000058enum {
59 MOUNT_USERS = (1<<28)*ENABLE_DESKTOP,
60 MOUNT_NOAUTO = (1<<29),
61 MOUNT_SWAP = (1<<30),
62};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +000063
64
65#define OPTION_STR "o:t:rwanfvsi"
66enum {
67 OPT_o = (1 << 0),
68 OPT_t = (1 << 1),
69 OPT_r = (1 << 2),
70 OPT_w = (1 << 3),
71 OPT_a = (1 << 4),
72 OPT_n = (1 << 5),
73 OPT_f = (1 << 6),
74 OPT_v = (1 << 7),
75 OPT_s = (1 << 8),
76 OPT_i = (1 << 9),
77};
78
79#if ENABLE_FEATURE_MTAB_SUPPORT
80#define useMtab (!(option_mask32 & OPT_n))
81#else
82#define useMtab 0
83#endif
84
85#if ENABLE_FEATURE_MOUNT_FAKE
86#define fakeIt (option_mask32 & OPT_f)
87#else
88#define fakeIt 0
89#endif
90
91
Denis Vlasenko13c5a682006-10-16 22:39:51 +000092// TODO: more "user" flag compatibility.
93// "user" option (from mount manpage):
94// Only the user that mounted a filesystem can unmount it again.
95// If any user should be able to unmount, then use users instead of user
96// in the fstab line. The owner option is similar to the user option,
97// with the restriction that the user must be the owner of the special file.
98// This may be useful e.g. for /dev/fd if a login script makes
99// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000100
Rob Landleydc0955b2006-03-14 18:16:25 +0000101/* Standard mount options (from -o options or --options), with corresponding
102 * flags */
Eric Andersencc8ed391999-10-05 16:24:54 +0000103
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000104static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000105 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000106
Rob Landleye3781b72006-08-08 01:39:49 +0000107 USE_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000108 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000109 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000110
Rob Landleye3781b72006-08-08 01:39:49 +0000111 USE_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000112 /* "defaults" */ 0,
113 /* "quiet" 0 - do not filter out, vfat wants to see it */
114 /* "noauto" */ MOUNT_NOAUTO,
115 /* "sw" */ MOUNT_SWAP,
116 /* "swap" */ MOUNT_SWAP,
117 USE_DESKTOP(/* "user" */ MOUNT_USERS,)
118 USE_DESKTOP(/* "users" */ MOUNT_USERS,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000119 /* "_netdev" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000120 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000121
Rob Landleye3781b72006-08-08 01:39:49 +0000122 USE_FEATURE_MOUNT_FLAGS(
123 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000124 /* "nosuid" */ MS_NOSUID,
125 /* "suid" */ ~MS_NOSUID,
126 /* "dev" */ ~MS_NODEV,
127 /* "nodev" */ MS_NODEV,
128 /* "exec" */ ~MS_NOEXEC,
129 /* "noexec" */ MS_NOEXEC,
130 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000131 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000132 /* "async" */ ~MS_SYNCHRONOUS,
133 /* "atime" */ ~MS_NOATIME,
134 /* "noatime" */ MS_NOATIME,
135 /* "diratime" */ ~MS_NODIRATIME,
136 /* "nodiratime" */ MS_NODIRATIME,
137 /* "loud" */ ~MS_SILENT,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000138
Rob Landleye3781b72006-08-08 01:39:49 +0000139 // action flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000140 /* "bind" */ MS_BIND,
141 /* "move" */ MS_MOVE,
142 /* "shared" */ MS_SHARED,
143 /* "slave" */ MS_SLAVE,
144 /* "private" */ MS_PRIVATE,
145 /* "unbindable" */ MS_UNBINDABLE,
146 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
147 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
148 /* "rprivate" */ MS_SLAVE|MS_RECURSIVE,
149 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000150 )
151
152 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000153 /* "ro" */ MS_RDONLY, // vfs flag
154 /* "rw" */ ~MS_RDONLY, // vfs flag
155 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000156};
157
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000158static const char mount_option_str[] =
159 USE_FEATURE_MOUNT_LOOP(
160 "loop" "\0"
161 )
162 USE_FEATURE_MOUNT_FSTAB(
163 "defaults" "\0"
164 /* "quiet" "\0" - do not filter out, vfat wants to see it */
165 "noauto" "\0"
166 "sw" "\0"
167 "swap" "\0"
168 USE_DESKTOP("user" "\0")
169 USE_DESKTOP("users" "\0")
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000170 "_netdev" "\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000171 )
172 USE_FEATURE_MOUNT_FLAGS(
173 // vfs flags
174 "nosuid" "\0"
175 "suid" "\0"
176 "dev" "\0"
177 "nodev" "\0"
178 "exec" "\0"
179 "noexec" "\0"
180 "sync" "\0"
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000181 "dirsync" "\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000182 "async" "\0"
183 "atime" "\0"
184 "noatime" "\0"
185 "diratime" "\0"
186 "nodiratime" "\0"
187 "loud" "\0"
188
189 // action flags
190 "bind" "\0"
191 "move" "\0"
192 "shared" "\0"
193 "slave" "\0"
194 "private" "\0"
195 "unbindable" "\0"
196 "rshared" "\0"
197 "rslave" "\0"
198 "rprivate" "\0"
199 "runbindable" "\0"
200 )
201
202 // Always understood.
203 "ro" "\0" // vfs flag
204 "rw" "\0" // vfs flag
205 "remount" "\0" // action flag
206;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000207
Denis Vlasenkof732e962008-02-18 12:07:49 +0000208
209struct globals {
210#if ENABLE_FEATURE_MOUNT_NFS
211 smalluint nfs_mount_version;
212#endif
213#if ENABLE_FEATURE_MOUNT_VERBOSE
214 unsigned verbose;
215#endif
216 llist_t *fslist;
217 char getmntent_buf[sizeof(bb_common_bufsiz1) - 8*3];
218
219};
220#define G (*(struct globals*)&bb_common_bufsiz1)
221#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000222#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000223#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000224#else
225#define verbose 0
226#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000227#define fslist (G.fslist )
228#define getmntent_buf (G.getmntent_buf )
229
230
231#if ENABLE_FEATURE_MOUNT_VERBOSE
232static int verbose_mount(const char *source, const char *target,
233 const char *filesystemtype,
234 unsigned long mountflags, const void *data)
235{
236 int rc;
237
238 errno = 0;
239 rc = mount(source, target, filesystemtype, mountflags, data);
240 if (verbose >= 2)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000241 bb_perror_msg("would do mount('%s','%s','%s',0x%08lx,'%s'):%d"
242 + (sizeof("would do ")-1),
243 source, target, filesystemtype,
244 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000245 return rc;
246}
247#else
248#define verbose_mount(...) mount(__VA_ARGS__)
249#endif
250
Denis Vlasenko53ce7f02008-02-19 11:29:46 +0000251#if ENABLE_FEATURE_MOUNT_LABEL
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000252static int resolve_mount_spec(char **fsname)
253{
254 char *tmp = NULL;
255
256 if (!strncmp(*fsname, "UUID=", 5))
257 tmp = get_devname_from_uuid(*fsname + 5);
258 else if (!strncmp(*fsname, "LABEL=", 6))
259 tmp = get_devname_from_label(*fsname + 6);
260
261 if (tmp) {
262 *fsname = tmp;
263 return 1;
264 }
265 return 0;
266}
Denis Vlasenko53ce7f02008-02-19 11:29:46 +0000267#endif
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000268
Rob Landleydc0955b2006-03-14 18:16:25 +0000269/* Append mount options to string */
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000270static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000271{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000272 if (*oldopts && **oldopts) {
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000273 /* do not insert options which are already there */
274 while (newopts[0]) {
275 char *p;
276 int len = strlen(newopts);
277 p = strchr(newopts, ',');
278 if (p) len = p - newopts;
279 p = *oldopts;
280 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000281 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000282 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000283 goto skip;
284 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000285 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000286 p++;
287 }
288 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
289 free(*oldopts);
290 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000291 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000292 newopts += len;
293 while (newopts[0] == ',') newopts++;
294 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000295 } else {
296 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000297 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000298 }
299}
300
301/* Use the mount_options list to parse options into flags.
Denis Vlasenko00d7d6c2006-09-11 17:42:44 +0000302 * Also return list of unrecognized options if unrecognized!=NULL */
Denis Vlasenkob4133682008-02-18 13:05:38 +0000303static long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000304{
Denis Vlasenkob4133682008-02-18 13:05:38 +0000305 long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000306
Rob Landley6a6798b2005-08-10 20:35:54 +0000307 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000308 for (;;) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000309 int i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000310 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000311 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000312
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000313 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000314
Rob Landley6a6798b2005-08-10 20:35:54 +0000315 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000316 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000317 if (!strcasecmp(option_str, options)) {
318 long fl = mount_options[i];
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000319 if (fl < 0) flags &= fl;
Rob Landleydc0955b2006-03-14 18:16:25 +0000320 else flags |= fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000321 break;
322 }
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000323 option_str += strlen(option_str) + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000324 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000325 // If unrecognized not NULL, append unrecognized mount options */
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000326 if (unrecognized && i == ARRAY_SIZE(mount_options)) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000327 // Add it to strflags, to pass on to kernel
Rob Landleydc0955b2006-03-14 18:16:25 +0000328 i = *unrecognized ? strlen(*unrecognized) : 0;
329 *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000330
Rob Landley6a6798b2005-08-10 20:35:54 +0000331 // Comma separated if it's not the first one
Rob Landleydc0955b2006-03-14 18:16:25 +0000332 if (i) (*unrecognized)[i++] = ',';
333 strcpy((*unrecognized)+i, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000334 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000335
Denis Vlasenko2535f122007-09-15 13:28:30 +0000336 if (!comma)
337 break;
338 // Advance to next option
339 *comma = ',';
340 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000341 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000342
Rob Landleydc0955b2006-03-14 18:16:25 +0000343 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000344}
345
Rob Landleydc0955b2006-03-14 18:16:25 +0000346// Return a list of all block device backed filesystems
Matt Kraai12400822001-04-17 04:32:50 +0000347
Rob Landleydc0955b2006-03-14 18:16:25 +0000348static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000349{
Denis Vlasenko87468852007-04-13 23:22:00 +0000350 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000351 "/etc/filesystems",
352 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000353 };
354 char *fs, *buf;
Rob Landleydc0955b2006-03-14 18:16:25 +0000355 llist_t *list = 0;
356 int i;
357 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000358
Denis Vlasenko87468852007-04-13 23:22:00 +0000359 for (i = 0; i < 2; i++) {
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000360 f = fopen(filesystems[i], "r");
361 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000362
Denis Vlasenko2d5ca602006-10-12 22:43:20 +0000363 while ((buf = xmalloc_getline(f)) != 0) {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000364 if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))
365 continue;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000366 fs = skip_whitespace(buf);
Denis Vlasenko372686b2006-10-12 22:42:33 +0000367 if (*fs=='#' || *fs=='*' || !*fs) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000368
Denis Vlasenko372686b2006-10-12 22:42:33 +0000369 llist_add_to_end(&list, xstrdup(fs));
370 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000371 }
372 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
373 }
374
375 return list;
376}
377
Rob Landleydc0955b2006-03-14 18:16:25 +0000378#if ENABLE_FEATURE_CLEAN_UP
379static void delete_block_backed_filesystems(void)
380{
Rob Landleya6b5b602006-05-08 19:03:07 +0000381 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000382}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000383#else
384void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000385#endif
386
Rob Landleydc0955b2006-03-14 18:16:25 +0000387// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000388// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000389static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000390{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000391 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000392
Denis Vlasenkob4133682008-02-18 13:05:38 +0000393 if (fakeIt) {
394 if (verbose >= 2)
395 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
396 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
397 vfsflags, filteropts);
398 goto mtab;
399 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000400
Rob Landleydc0955b2006-03-14 18:16:25 +0000401 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000402 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000403 errno = 0;
404 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000405 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000406
407 // If mount failed, try
408 // helper program <mnt_type>
409 if (ENABLE_FEATURE_MOUNT_HELPERS && rc) {
410 char *args[6];
411 int errno_save = errno;
412 args[0] = mp->mnt_type;
413 rc = 1;
414 if (filteropts) {
415 args[rc++] = (char *)"-o";
416 args[rc++] = filteropts;
417 }
418 args[rc++] = mp->mnt_fsname;
419 args[rc++] = mp->mnt_dir;
420 args[rc] = NULL;
421 rc = wait4pid(spawn(args));
422 if (!rc)
423 break;
424 errno = errno_save;
425 }
426
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000427 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000428 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000429 if (!(vfsflags & MS_SILENT))
430 bb_error_msg("%s is write-protected, mounting read-only",
431 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000432 vfsflags |= MS_RDONLY;
433 }
434
Rob Landleydc0955b2006-03-14 18:16:25 +0000435 // Abort entirely if permission denied.
436
437 if (rc && errno == EPERM)
438 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
439
440 /* If the mount was successful, and we're maintaining an old-style
441 * mtab file by hand, add the new entry to it now. */
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000442 mtab:
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000443 if (useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000444 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000445 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000446 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000447 int i;
448
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000449 if (!mountTable) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000450 bb_error_msg("no %s", bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000451 goto ret;
452 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000453
454 // Add vfs string flags
455
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000456 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
457 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
458 append_mount_options(&(mp->mnt_opts), option_str);
459 option_str += strlen(option_str) + 1;
460 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000461
462 // Remove trailing / (if any) from directory we mounted on
463
Denis Vlasenko727ef942006-09-14 13:19:19 +0000464 i = strlen(mp->mnt_dir) - 1;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000465 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000466
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000467 // Convert to canonical pathnames as needed
Denis Vlasenko727ef942006-09-14 13:19:19 +0000468
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000469 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000470 fsname = 0;
Denis Vlasenko727ef942006-09-14 13:19:19 +0000471 if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000472 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000473 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000474 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000475 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000476
477 // Write and close.
478
Denis Vlasenko727ef942006-09-14 13:19:19 +0000479 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000480 endmntent(mountTable);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000481 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000482 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000483 free(fsname);
484 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000485 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000486 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000487 return rc;
488}
489
Denis Vlasenko25098f72006-09-14 15:46:33 +0000490#if ENABLE_FEATURE_MOUNT_NFS
491
492/*
493 * Linux NFS mount
494 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
495 *
496 * Licensed under GPLv2, see file LICENSE in this tarball for details.
497 *
498 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
499 * numbers to be specified on the command line.
500 *
501 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
502 * Omit the call to connect() for Linux version 1.3.11 or later.
503 *
504 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
505 * Implemented the "bg", "fg" and "retry" mount options for NFS.
506 *
507 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
508 * - added Native Language Support
509 *
510 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
511 * plus NFSv3 stuff.
512 */
513
Denis Vlasenko25098f72006-09-14 15:46:33 +0000514/* This is just a warning of a common mistake. Possibly this should be a
515 * uclibc faq entry rather than in busybox... */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000516#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000517#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
518#endif
519
520#define MOUNTPORT 635
521#define MNTPATHLEN 1024
522#define MNTNAMLEN 255
523#define FHSIZE 32
524#define FHSIZE3 64
525
526typedef char fhandle[FHSIZE];
527
528typedef struct {
529 unsigned int fhandle3_len;
530 char *fhandle3_val;
531} fhandle3;
532
533enum mountstat3 {
534 MNT_OK = 0,
535 MNT3ERR_PERM = 1,
536 MNT3ERR_NOENT = 2,
537 MNT3ERR_IO = 5,
538 MNT3ERR_ACCES = 13,
539 MNT3ERR_NOTDIR = 20,
540 MNT3ERR_INVAL = 22,
541 MNT3ERR_NAMETOOLONG = 63,
542 MNT3ERR_NOTSUPP = 10004,
543 MNT3ERR_SERVERFAULT = 10006,
544};
545typedef enum mountstat3 mountstat3;
546
547struct fhstatus {
548 unsigned int fhs_status;
549 union {
550 fhandle fhs_fhandle;
551 } fhstatus_u;
552};
553typedef struct fhstatus fhstatus;
554
555struct mountres3_ok {
556 fhandle3 fhandle;
557 struct {
558 unsigned int auth_flavours_len;
559 char *auth_flavours_val;
560 } auth_flavours;
561};
562typedef struct mountres3_ok mountres3_ok;
563
564struct mountres3 {
565 mountstat3 fhs_status;
566 union {
567 mountres3_ok mountinfo;
568 } mountres3_u;
569};
570typedef struct mountres3 mountres3;
571
572typedef char *dirpath;
573
574typedef char *name;
575
576typedef struct mountbody *mountlist;
577
578struct mountbody {
579 name ml_hostname;
580 dirpath ml_directory;
581 mountlist ml_next;
582};
583typedef struct mountbody mountbody;
584
585typedef struct groupnode *groups;
586
587struct groupnode {
588 name gr_name;
589 groups gr_next;
590};
591typedef struct groupnode groupnode;
592
593typedef struct exportnode *exports;
594
595struct exportnode {
596 dirpath ex_dir;
597 groups ex_groups;
598 exports ex_next;
599};
600typedef struct exportnode exportnode;
601
602struct ppathcnf {
603 int pc_link_max;
604 short pc_max_canon;
605 short pc_max_input;
606 short pc_name_max;
607 short pc_path_max;
608 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000609 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000610 char pc_xxx;
611 short pc_mask[2];
612};
613typedef struct ppathcnf ppathcnf;
614
615#define MOUNTPROG 100005
616#define MOUNTVERS 1
617
618#define MOUNTPROC_NULL 0
619#define MOUNTPROC_MNT 1
620#define MOUNTPROC_DUMP 2
621#define MOUNTPROC_UMNT 3
622#define MOUNTPROC_UMNTALL 4
623#define MOUNTPROC_EXPORT 5
624#define MOUNTPROC_EXPORTALL 6
625
626#define MOUNTVERS_POSIX 2
627
628#define MOUNTPROC_PATHCONF 7
629
630#define MOUNT_V3 3
631
632#define MOUNTPROC3_NULL 0
633#define MOUNTPROC3_MNT 1
634#define MOUNTPROC3_DUMP 2
635#define MOUNTPROC3_UMNT 3
636#define MOUNTPROC3_UMNTALL 4
637#define MOUNTPROC3_EXPORT 5
638
639enum {
640#ifndef NFS_FHSIZE
641 NFS_FHSIZE = 32,
642#endif
643#ifndef NFS_PORT
644 NFS_PORT = 2049
645#endif
646};
647
Denis Vlasenko25098f72006-09-14 15:46:33 +0000648/*
649 * We want to be able to compile mount on old kernels in such a way
650 * that the binary will work well on more recent kernels.
651 * Thus, if necessary we teach nfsmount.c the structure of new fields
652 * that will come later.
653 *
654 * Moreover, the new kernel includes conflict with glibc includes
655 * so it is easiest to ignore the kernel altogether (at compile time).
656 */
657
658struct nfs2_fh {
659 char data[32];
660};
661struct nfs3_fh {
662 unsigned short size;
663 unsigned char data[64];
664};
665
666struct nfs_mount_data {
667 int version; /* 1 */
668 int fd; /* 1 */
669 struct nfs2_fh old_root; /* 1 */
670 int flags; /* 1 */
671 int rsize; /* 1 */
672 int wsize; /* 1 */
673 int timeo; /* 1 */
674 int retrans; /* 1 */
675 int acregmin; /* 1 */
676 int acregmax; /* 1 */
677 int acdirmin; /* 1 */
678 int acdirmax; /* 1 */
679 struct sockaddr_in addr; /* 1 */
680 char hostname[256]; /* 1 */
681 int namlen; /* 2 */
682 unsigned int bsize; /* 3 */
683 struct nfs3_fh root; /* 4 */
684};
685
686/* bits in the flags field */
687enum {
688 NFS_MOUNT_SOFT = 0x0001, /* 1 */
689 NFS_MOUNT_INTR = 0x0002, /* 1 */
690 NFS_MOUNT_SECURE = 0x0004, /* 1 */
691 NFS_MOUNT_POSIX = 0x0008, /* 1 */
692 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
693 NFS_MOUNT_NOAC = 0x0020, /* 1 */
694 NFS_MOUNT_TCP = 0x0040, /* 2 */
695 NFS_MOUNT_VER3 = 0x0080, /* 3 */
696 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
697 NFS_MOUNT_NONLM = 0x0200 /* 3 */
698};
699
700
701/*
702 * We need to translate between nfs status return values and
703 * the local errno values which may not be the same.
704 *
705 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
706 * "after #include <errno.h> the symbol errno is reserved for any use,
707 * it cannot even be used as a struct tag or field name".
708 */
709
710#ifndef EDQUOT
711#define EDQUOT ENOSPC
712#endif
713
714// Convert each NFSERR_BLAH into EBLAH
715
716static const struct {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000717 short stat;
718 short errnum;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000719} nfs_errtbl[] = {
720 {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
721 {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
722 {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
723 {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
724};
725
726static char *nfs_strerror(int status)
727{
728 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000729
730 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
731 if (nfs_errtbl[i].stat == status)
732 return strerror(nfs_errtbl[i].errnum);
733 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000734 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000735}
736
737static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
738{
739 if (!xdr_opaque(xdrs, objp, FHSIZE))
740 return FALSE;
741 return TRUE;
742}
743
744static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
745{
746 if (!xdr_u_int(xdrs, &objp->fhs_status))
747 return FALSE;
748 switch (objp->fhs_status) {
749 case 0:
750 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
751 return FALSE;
752 break;
753 default:
754 break;
755 }
756 return TRUE;
757}
758
759static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
760{
761 if (!xdr_string(xdrs, objp, MNTPATHLEN))
762 return FALSE;
763 return TRUE;
764}
765
766static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
767{
768 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
769 return FALSE;
770 return TRUE;
771}
772
773static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
774{
775 if (!xdr_fhandle3(xdrs, &objp->fhandle))
776 return FALSE;
777 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
778 sizeof (int), (xdrproc_t) xdr_int))
779 return FALSE;
780 return TRUE;
781}
782
783static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
784{
785 if (!xdr_enum(xdrs, (enum_t *) objp))
786 return FALSE;
787 return TRUE;
788}
789
790static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
791{
792 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
793 return FALSE;
794 switch (objp->fhs_status) {
795 case MNT_OK:
796 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
797 return FALSE;
798 break;
799 default:
800 break;
801 }
802 return TRUE;
803}
804
805#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
806
Denis Vlasenko25098f72006-09-14 15:46:33 +0000807/*
808 * Unfortunately, the kernel prints annoying console messages
809 * in case of an unexpected nfs mount version (instead of
810 * just returning some error). Therefore we'll have to try
811 * and figure out what version the kernel expects.
812 *
813 * Variables:
814 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
815 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
816 * nfs_mount_version: version this source and running kernel can handle
817 */
818static void
819find_kernel_nfs_mount_version(void)
820{
Denis Vlasenkob9256052007-09-28 10:29:17 +0000821 int kernel_version;
822
823 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000824 return;
825
826 nfs_mount_version = 4; /* default */
827
828 kernel_version = get_linux_version_code();
829 if (kernel_version) {
830 if (kernel_version < KERNEL_VERSION(2,1,32))
831 nfs_mount_version = 1;
832 else if (kernel_version < KERNEL_VERSION(2,2,18) ||
833 (kernel_version >= KERNEL_VERSION(2,3,0) &&
834 kernel_version < KERNEL_VERSION(2,3,99)))
835 nfs_mount_version = 3;
836 /* else v4 since 2.3.99pre4 */
837 }
838}
839
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000840static void
Denis Vlasenkob9256052007-09-28 10:29:17 +0000841get_mountport(struct pmap *pm_mnt,
842 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +0000843 long unsigned prog,
844 long unsigned version,
845 long unsigned proto,
846 long unsigned port)
847{
848 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000849
850 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +0000851/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
852 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000853 pmap = pmap_getmaps(server_addr);
854
855 if (version > MAX_NFSPROT)
856 version = MAX_NFSPROT;
857 if (!prog)
858 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000859 pm_mnt->pm_prog = prog;
860 pm_mnt->pm_vers = version;
861 pm_mnt->pm_prot = proto;
862 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000863
Denis Vlasenko25098f72006-09-14 15:46:33 +0000864 while (pmap) {
865 if (pmap->pml_map.pm_prog != prog)
866 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000867 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000868 goto next;
869 if (version > 2 && pmap->pml_map.pm_vers != version)
870 goto next;
871 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
872 goto next;
873 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
Denis Vlasenkob9256052007-09-28 10:29:17 +0000874 (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
Denis Vlasenko25098f72006-09-14 15:46:33 +0000875 (port && pmap->pml_map.pm_port != port))
876 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000877 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
878 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +0000879 pmap = pmap->pml_next;
880 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000881 if (!pm_mnt->pm_vers)
882 pm_mnt->pm_vers = MOUNTVERS;
883 if (!pm_mnt->pm_port)
884 pm_mnt->pm_port = MOUNTPORT;
885 if (!pm_mnt->pm_prot)
886 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000887}
888
Denis Vlasenkof0000652007-09-04 18:30:26 +0000889#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +0000890static int daemonize(void)
891{
892 int fd;
893 int pid = fork();
894 if (pid < 0) /* error */
895 return -errno;
896 if (pid > 0) /* parent */
897 return 0;
898 /* child */
899 fd = xopen(bb_dev_null, O_RDWR);
900 dup2(fd, 0);
901 dup2(fd, 1);
902 dup2(fd, 2);
Denis Vlasenko9af7c9d2007-01-19 21:19:35 +0000903 while (fd > 2) close(fd--);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000904 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000905 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000906 logmode = LOGMODE_SYSLOG;
907 return 1;
908}
Denis Vlasenkof0000652007-09-04 18:30:26 +0000909#else
910static inline int daemonize(void) { return -ENOSYS; }
911#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000912
913// TODO
914static inline int we_saw_this_host_before(const char *hostname)
915{
916 return 0;
917}
918
919/* RPC strerror analogs are terminally idiotic:
920 * *mandatory* prefix and \n at end.
921 * This hopefully helps. Usage:
922 * error_msg_rpc(clnt_*error*(" ")) */
923static void error_msg_rpc(const char *msg)
924{
Denis Vlasenko23514fe2006-09-19 14:07:52 +0000925 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000926 while (msg[0] == ' ' || msg[0] == ':') msg++;
927 len = strlen(msg);
928 while (len && msg[len-1] == '\n') len--;
929 bb_error_msg("%.*s", len, msg);
930}
931
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +0000932// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000933static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000934{
935 CLIENT *mclient;
936 char *hostname;
937 char *pathname;
938 char *mounthost;
939 struct nfs_mount_data data;
940 char *opt;
941 struct hostent *hp;
942 struct sockaddr_in server_addr;
943 struct sockaddr_in mount_server_addr;
944 int msock, fsock;
945 union {
946 struct fhstatus nfsv2;
947 struct mountres3 nfsv3;
948 } status;
949 int daemonized;
950 char *s;
951 int port;
952 int mountport;
953 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000954#if BB_MMU
955 int bg = 0;
956#else
957 enum { bg = 0 };
958#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000959 int soft;
960 int intr;
961 int posix;
962 int nocto;
963 int noac;
964 int nolock;
965 int retry;
966 int tcp;
967 int mountprog;
968 int mountvers;
969 int nfsprog;
970 int nfsvers;
971 int retval;
972
973 find_kernel_nfs_mount_version();
974
975 daemonized = 0;
976 mounthost = NULL;
977 retval = ETIMEDOUT;
978 msock = fsock = -1;
979 mclient = NULL;
980
981 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
982
983 filteropts = xstrdup(filteropts); /* going to trash it later... */
984
985 hostname = xstrdup(mp->mnt_fsname);
986 /* mount_main() guarantees that ':' is there */
987 s = strchr(hostname, ':');
988 pathname = s + 1;
989 *s = '\0';
990 /* Ignore all but first hostname in replicated mounts
991 until they can be fully supported. (mack@sgi.com) */
992 s = strchr(hostname, ',');
993 if (s) {
994 *s = '\0';
995 bb_error_msg("warning: multiple hostnames not supported");
996 }
997
998 server_addr.sin_family = AF_INET;
999 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1000 hp = gethostbyname(hostname);
1001 if (hp == NULL) {
1002 bb_herror_msg("%s", hostname);
1003 goto fail;
1004 }
1005 if (hp->h_length > sizeof(struct in_addr)) {
1006 bb_error_msg("got bad hp->h_length");
1007 hp->h_length = sizeof(struct in_addr);
1008 }
1009 memcpy(&server_addr.sin_addr,
1010 hp->h_addr, hp->h_length);
1011 }
1012
1013 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1014
1015 /* add IP address to mtab options for use when unmounting */
1016
1017 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1018 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1019 } else {
1020 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1021 mp->mnt_opts[0] ? "," : "",
1022 inet_ntoa(server_addr.sin_addr));
1023 free(mp->mnt_opts);
1024 mp->mnt_opts = tmp;
1025 }
1026
1027 /* Set default options.
1028 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1029 * let the kernel decide.
1030 * timeo is filled in after we know whether it'll be TCP or UDP. */
1031 memset(&data, 0, sizeof(data));
1032 data.retrans = 3;
1033 data.acregmin = 3;
1034 data.acregmax = 60;
1035 data.acdirmin = 30;
1036 data.acdirmax = 60;
1037 data.namlen = NAME_MAX;
1038
Denis Vlasenko25098f72006-09-14 15:46:33 +00001039 soft = 0;
1040 intr = 0;
1041 posix = 0;
1042 nocto = 0;
1043 nolock = 0;
1044 noac = 0;
1045 retry = 10000; /* 10000 minutes ~ 1 week */
1046 tcp = 0;
1047
1048 mountprog = MOUNTPROG;
1049 mountvers = 0;
1050 port = 0;
1051 mountport = 0;
1052 nfsprog = 100003;
1053 nfsvers = 0;
1054
1055 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001056 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001057 char *opteq = strchr(opt, '=');
1058 if (opteq) {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001059 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001060 /* 0 */ "rsize\0"
1061 /* 1 */ "wsize\0"
1062 /* 2 */ "timeo\0"
1063 /* 3 */ "retrans\0"
1064 /* 4 */ "acregmin\0"
1065 /* 5 */ "acregmax\0"
1066 /* 6 */ "acdirmin\0"
1067 /* 7 */ "acdirmax\0"
1068 /* 8 */ "actimeo\0"
1069 /* 9 */ "retry\0"
1070 /* 10 */ "port\0"
1071 /* 11 */ "mountport\0"
1072 /* 12 */ "mounthost\0"
1073 /* 13 */ "mountprog\0"
1074 /* 14 */ "mountvers\0"
1075 /* 15 */ "nfsprog\0"
1076 /* 16 */ "nfsvers\0"
1077 /* 17 */ "vers\0"
1078 /* 18 */ "proto\0"
1079 /* 19 */ "namlen\0"
1080 /* 20 */ "addr\0";
Denis Vlasenko13858992006-10-08 12:49:22 +00001081 int val = xatoi_u(opteq + 1);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001082 *opteq = '\0';
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001083 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001084 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001085 data.rsize = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001086 break;
1087 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001088 data.wsize = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001089 break;
1090 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001091 data.timeo = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001092 break;
1093 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001094 data.retrans = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001095 break;
1096 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001097 data.acregmin = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001098 break;
1099 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001100 data.acregmax = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001101 break;
1102 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001103 data.acdirmin = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001104 break;
1105 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001106 data.acdirmax = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001107 break;
1108 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001109 data.acregmin = val;
1110 data.acregmax = val;
1111 data.acdirmin = val;
1112 data.acdirmax = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001113 break;
1114 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001115 retry = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001116 break;
1117 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001118 port = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001119 break;
1120 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001121 mountport = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001122 break;
1123 case 12: // "mounthost"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001124 mounthost = xstrndup(opteq+1,
Denis Vlasenko5af906e2006-11-05 18:05:09 +00001125 strcspn(opteq+1," \t\n\r,"));
Denis Vlasenko68f21872006-10-26 01:47:34 +00001126 break;
1127 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001128 mountprog = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001129 break;
1130 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001131 mountvers = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001132 break;
1133 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001134 nfsprog = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001135 break;
1136 case 16: // "nfsvers"
1137 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001138 nfsvers = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001139 break;
1140 case 18: // "proto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001141 if (!strncmp(opteq+1, "tcp", 3))
1142 tcp = 1;
1143 else if (!strncmp(opteq+1, "udp", 3))
1144 tcp = 0;
1145 else
1146 bb_error_msg("warning: unrecognized proto= option");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001147 break;
1148 case 19: // "namlen"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001149 if (nfs_mount_version >= 2)
1150 data.namlen = val;
1151 else
1152 bb_error_msg("warning: option namlen is not supported\n");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001153 break;
1154 case 20: // "addr" - ignore
1155 break;
1156 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001157 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1158 goto fail;
1159 }
1160 }
1161 else {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001162 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001163 "bg\0"
1164 "fg\0"
1165 "soft\0"
1166 "hard\0"
1167 "intr\0"
1168 "posix\0"
1169 "cto\0"
1170 "ac\0"
1171 "tcp\0"
1172 "udp\0"
1173 "lock\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001174 int val = 1;
1175 if (!strncmp(opt, "no", 2)) {
1176 val = 0;
1177 opt += 2;
1178 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001179 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001180 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001181#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001182 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001183#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001184 break;
1185 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001186#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001187 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001188#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001189 break;
1190 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001191 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001192 break;
1193 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001194 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001195 break;
1196 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001197 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001198 break;
1199 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001200 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001201 break;
1202 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001203 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001204 break;
1205 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001206 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001207 break;
1208 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001209 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001210 break;
1211 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001212 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001213 break;
1214 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001215 if (nfs_mount_version >= 3)
1216 nolock = !val;
1217 else
1218 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001219 break;
1220 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001221 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1222 goto fail;
1223 }
1224 }
1225 }
1226 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1227
1228 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1229 | (intr ? NFS_MOUNT_INTR : 0)
1230 | (posix ? NFS_MOUNT_POSIX : 0)
1231 | (nocto ? NFS_MOUNT_NOCTO : 0)
1232 | (noac ? NFS_MOUNT_NOAC : 0);
1233 if (nfs_mount_version >= 2)
1234 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1235 if (nfs_mount_version >= 3)
1236 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1237 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1238 bb_error_msg("NFSv%d not supported", nfsvers);
1239 goto fail;
1240 }
1241 if (nfsvers && !mountvers)
1242 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1243 if (nfsvers && nfsvers < mountvers) {
1244 mountvers = nfsvers;
1245 }
1246
1247 /* Adjust options if none specified */
1248 if (!data.timeo)
1249 data.timeo = tcp ? 70 : 7;
1250
Denis Vlasenko25098f72006-09-14 15:46:33 +00001251 data.version = nfs_mount_version;
1252
1253 if (vfsflags & MS_REMOUNT)
1254 goto do_mount;
1255
1256 /*
1257 * If the previous mount operation on the same host was
1258 * backgrounded, and the "bg" for this mount is also set,
1259 * give up immediately, to avoid the initial timeout.
1260 */
1261 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001262 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001263 if (daemonized <= 0) { /* parent or error */
1264 retval = -daemonized;
1265 goto ret;
1266 }
1267 }
1268
1269 /* create mount daemon client */
1270 /* See if the nfs host = mount host. */
1271 if (mounthost) {
1272 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1273 mount_server_addr.sin_family = AF_INET;
1274 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1275 } else {
1276 hp = gethostbyname(mounthost);
1277 if (hp == NULL) {
1278 bb_herror_msg("%s", mounthost);
1279 goto fail;
1280 } else {
1281 if (hp->h_length > sizeof(struct in_addr)) {
1282 bb_error_msg("got bad hp->h_length?");
1283 hp->h_length = sizeof(struct in_addr);
1284 }
1285 mount_server_addr.sin_family = AF_INET;
1286 memcpy(&mount_server_addr.sin_addr,
1287 hp->h_addr, hp->h_length);
1288 }
1289 }
1290 }
1291
1292 /*
1293 * The following loop implements the mount retries. When the mount
1294 * times out, and the "bg" option is set, we background ourself
1295 * and continue trying.
1296 *
1297 * The case where the mount point is not present and the "bg"
1298 * option is set, is treated as a timeout. This is done to
1299 * support nested mounts.
1300 *
1301 * The "retry" count specified by the user is the number of
1302 * minutes to retry before giving up.
1303 */
1304 {
1305 struct timeval total_timeout;
1306 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001307 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001308 time_t t;
1309 time_t prevt;
1310 time_t timeout;
1311
1312 retry_timeout.tv_sec = 3;
1313 retry_timeout.tv_usec = 0;
1314 total_timeout.tv_sec = 20;
1315 total_timeout.tv_usec = 0;
1316 timeout = time(NULL) + 60 * retry;
1317 prevt = 0;
1318 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001319 retry:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001320 /* be careful not to use too many CPU cycles */
1321 if (t - prevt < 30)
1322 sleep(30);
1323
Denis Vlasenkob9256052007-09-28 10:29:17 +00001324 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001325 mountprog,
1326 mountvers,
1327 proto,
1328 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001329 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001330
1331 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001332 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001333 msock = RPC_ANYSOCK;
1334
Denis Vlasenkob9256052007-09-28 10:29:17 +00001335 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001336 case IPPROTO_UDP:
1337 mclient = clntudp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001338 pm_mnt.pm_prog,
1339 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001340 retry_timeout,
1341 &msock);
1342 if (mclient)
1343 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001344 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001345 msock = RPC_ANYSOCK;
1346 case IPPROTO_TCP:
1347 mclient = clnttcp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001348 pm_mnt.pm_prog,
1349 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001350 &msock, 0, 0);
1351 break;
1352 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001353 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001354 }
1355 if (!mclient) {
1356 if (!daemonized && prevt == 0)
1357 error_msg_rpc(clnt_spcreateerror(" "));
1358 } else {
1359 enum clnt_stat clnt_stat;
1360 /* try to mount hostname:pathname */
1361 mclient->cl_auth = authunix_create_default();
1362
1363 /* make pointers in xdr_mountres3 NULL so
1364 * that xdr_array allocates memory for us
1365 */
1366 memset(&status, 0, sizeof(status));
1367
Denis Vlasenkob9256052007-09-28 10:29:17 +00001368 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001369 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1370 (xdrproc_t) xdr_dirpath,
1371 (caddr_t) &pathname,
1372 (xdrproc_t) xdr_mountres3,
1373 (caddr_t) &status,
1374 total_timeout);
1375 else
1376 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1377 (xdrproc_t) xdr_dirpath,
1378 (caddr_t) &pathname,
1379 (xdrproc_t) xdr_fhstatus,
1380 (caddr_t) &status,
1381 total_timeout);
1382
1383 if (clnt_stat == RPC_SUCCESS)
1384 goto prepare_kernel_data; /* we're done */
1385 if (errno != ECONNREFUSED) {
1386 error_msg_rpc(clnt_sperror(mclient, " "));
1387 goto fail; /* don't retry */
1388 }
1389 /* Connection refused */
1390 if (!daemonized && prevt == 0) /* print just once */
1391 error_msg_rpc(clnt_sperror(mclient, " "));
1392 auth_destroy(mclient->cl_auth);
1393 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001394 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001395 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001396 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001397 }
1398
1399 /* Timeout. We are going to retry... maybe */
1400
1401 if (!bg)
1402 goto fail;
1403 if (!daemonized) {
1404 daemonized = daemonize();
1405 if (daemonized <= 0) { /* parent or error */
1406 retval = -daemonized;
1407 goto ret;
1408 }
1409 }
1410 prevt = t;
1411 t = time(NULL);
1412 if (t >= timeout)
1413 /* TODO error message */
1414 goto fail;
1415
1416 goto retry;
1417 }
1418
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001419 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001420
1421 if (nfsvers == 2) {
1422 if (status.nfsv2.fhs_status != 0) {
1423 bb_error_msg("%s:%s failed, reason given by server: %s",
1424 hostname, pathname,
1425 nfs_strerror(status.nfsv2.fhs_status));
1426 goto fail;
1427 }
1428 memcpy(data.root.data,
1429 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1430 NFS_FHSIZE);
1431 data.root.size = NFS_FHSIZE;
1432 memcpy(data.old_root.data,
1433 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1434 NFS_FHSIZE);
1435 } else {
1436 fhandle3 *my_fhandle;
1437 if (status.nfsv3.fhs_status != 0) {
1438 bb_error_msg("%s:%s failed, reason given by server: %s",
1439 hostname, pathname,
1440 nfs_strerror(status.nfsv3.fhs_status));
1441 goto fail;
1442 }
1443 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1444 memset(data.old_root.data, 0, NFS_FHSIZE);
1445 memset(&data.root, 0, sizeof(data.root));
1446 data.root.size = my_fhandle->fhandle3_len;
1447 memcpy(data.root.data,
1448 (char *) my_fhandle->fhandle3_val,
1449 my_fhandle->fhandle3_len);
1450
1451 data.flags |= NFS_MOUNT_VER3;
1452 }
1453
1454 /* create nfs socket for kernel */
1455
1456 if (tcp) {
1457 if (nfs_mount_version < 3) {
1458 bb_error_msg("NFS over TCP is not supported");
1459 goto fail;
1460 }
1461 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1462 } else
1463 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1464 if (fsock < 0) {
1465 bb_perror_msg("nfs socket");
1466 goto fail;
1467 }
1468 if (bindresvport(fsock, 0) < 0) {
1469 bb_perror_msg("nfs bindresvport");
1470 goto fail;
1471 }
1472 if (port == 0) {
1473 server_addr.sin_port = PMAPPORT;
1474 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1475 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1476 if (port == 0)
1477 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001478 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001479 server_addr.sin_port = htons(port);
1480
1481 /* prepare data structure for kernel */
1482
1483 data.fd = fsock;
1484 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1485 strncpy(data.hostname, hostname, sizeof(data.hostname));
1486
1487 /* clean up */
1488
1489 auth_destroy(mclient->cl_auth);
1490 clnt_destroy(mclient);
1491 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001492 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001493
1494 if (bg) {
1495 /* We must wait until mount directory is available */
1496 struct stat statbuf;
1497 int delay = 1;
1498 while (stat(mp->mnt_dir, &statbuf) == -1) {
1499 if (!daemonized) {
1500 daemonized = daemonize();
1501 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001502 // FIXME: parent doesn't close fsock - ??!
Denis Vlasenko25098f72006-09-14 15:46:33 +00001503 retval = -daemonized;
1504 goto ret;
1505 }
1506 }
1507 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1508 delay *= 2;
1509 if (delay > 30)
1510 delay = 30;
1511 }
1512 }
1513
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001514 do_mount: /* perform actual mount */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001515
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001516 mp->mnt_type = (char*)"nfs";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001517 retval = mount_it_now(mp, vfsflags, (char*)&data);
1518 goto ret;
1519
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001520 fail: /* abort */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001521
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001522 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001523 if (mclient) {
1524 auth_destroy(mclient->cl_auth);
1525 clnt_destroy(mclient);
1526 }
1527 close(msock);
1528 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001529 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001530 close(fsock);
1531
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001532 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001533 free(hostname);
1534 free(mounthost);
1535 free(filteropts);
1536 return retval;
1537}
1538
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001539#else /* !ENABLE_FEATURE_MOUNT_NFS */
1540
1541/* Never called. Call should be optimized out. */
Denis Vlasenkob4133682008-02-18 13:05:38 +00001542int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001543
1544#endif /* !ENABLE_FEATURE_MOUNT_NFS */
1545
1546// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1547// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001548// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001549static int singlemount(struct mntent *mp, int ignore_busy)
1550{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001551 int rc = -1;
1552 long vfsflags;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001553 char *loopFile = 0, *filteropts = 0;
1554 llist_t *fl = 0;
1555 struct stat st;
1556
1557 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1558
1559 // Treat fstype "auto" as unspecified.
1560
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001561 if (mp->mnt_type && strcmp(mp->mnt_type,"auto") == 0)
1562 mp->mnt_type = 0;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001563
Denis Vlasenko2535f122007-09-15 13:28:30 +00001564 // Might this be a virtual filesystem?
1565
1566 if (ENABLE_FEATURE_MOUNT_HELPERS
Denis Vlasenkoc03e8722007-12-26 20:56:55 +00001567 && (strchr(mp->mnt_fsname, '#'))
Denis Vlasenko2535f122007-09-15 13:28:30 +00001568 ) {
1569 char *s, *p, *args[35];
1570 int n = 0;
1571 for (s = p = mp->mnt_fsname; *s && n < 35-3; ++s) {
1572 if (s[0] == '#' && s[1] != '#') {
1573 *s = '\0';
1574 args[n++] = p;
1575 p = s + 1;
1576 }
1577 }
1578 args[n++] = p;
1579 args[n++] = mp->mnt_dir;
1580 args[n] = NULL;
1581 rc = wait4pid(xspawn(args));
1582 goto report_error;
1583 }
1584
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001585 // Might this be an CIFS filesystem?
1586
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001587 if (ENABLE_FEATURE_MOUNT_CIFS
1588 && (!mp->mnt_type || strcmp(mp->mnt_type,"cifs") == 0)
1589 && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\')
1590 && mp->mnt_fsname[0]==mp->mnt_fsname[1]
1591 ) {
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001592 len_and_sockaddr *lsa;
1593 char *ip, *dotted;
1594 char *s;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001595
1596 rc = 1;
1597 // Replace '/' with '\' and verify that unc points to "//server/share".
1598
1599 for (s = mp->mnt_fsname; *s; ++s)
1600 if (*s == '/') *s = '\\';
1601
1602 // get server IP
1603
1604 s = strrchr(mp->mnt_fsname, '\\');
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001605 if (s <= mp->mnt_fsname+1) goto report_error;
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001606 *s = '\0';
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001607 lsa = host2sockaddr(mp->mnt_fsname+2, 0);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001608 *s = '\\';
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001609 if (!lsa) goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001610
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001611 // insert ip=... option into string flags.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001612
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001613 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001614 ip = xasprintf("ip=%s", dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001615 parse_mount_options(ip, &filteropts);
1616
1617 // compose new unc '\\server-ip\share'
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001618 // (s => slash after hostname)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001619
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001620 mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001621
1622 // lock is required
1623 vfsflags |= MS_MANDLOCK;
1624
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001625 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001626 rc = mount_it_now(mp, vfsflags, filteropts);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001627 if (ENABLE_FEATURE_CLEAN_UP) {
1628 free(mp->mnt_fsname);
1629 free(ip);
1630 free(dotted);
1631 free(lsa);
1632 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001633 goto report_error;
1634 }
1635
1636 // Might this be an NFS filesystem?
1637
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001638 if (ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001639 && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001640 && strchr(mp->mnt_fsname, ':') != NULL
1641 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001642 rc = nfsmount(mp, vfsflags, filteropts);
1643 goto report_error;
1644 }
1645
1646 // Look at the file. (Not found isn't a failure for remount, or for
1647 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001648 // (We use stat, not lstat, in order to allow
1649 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001650
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001651 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001652 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1653 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001654 // Do we need to allocate a loopback device for it?
1655
1656 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1657 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001658 mp->mnt_fsname = NULL; /* will receive malloced loop dev name */
1659 if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) {
1660 if (errno == EPERM || errno == EACCES)
1661 bb_error_msg(bb_msg_perm_denied_are_you_root);
1662 else
1663 bb_perror_msg("cannot setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00001664 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001665 }
1666
1667 // Autodetect bind mounts
1668
1669 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1670 vfsflags |= MS_BIND;
1671 }
1672
1673 /* If we know the fstype (or don't need to), jump straight
1674 * to the actual mount. */
1675
1676 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1677 rc = mount_it_now(mp, vfsflags, filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001678 else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001679 // Loop through filesystem types until mount succeeds
1680 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001681
1682 /* Initialize list of block backed filesystems. This has to be
1683 * done here so that during "mount -a", mounts after /proc shows up
1684 * can autodetect. */
1685
1686 if (!fslist) {
1687 fslist = get_block_backed_filesystems();
1688 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1689 atexit(delete_block_backed_filesystems);
1690 }
1691
1692 for (fl = fslist; fl; fl = fl->link) {
1693 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00001694 rc = mount_it_now(mp, vfsflags, filteropts);
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001695 if (!rc) break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001696 }
1697 }
1698
1699 // If mount failed, clean up loop file (if any).
1700
1701 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1702 del_loop(mp->mnt_fsname);
1703 if (ENABLE_FEATURE_CLEAN_UP) {
1704 free(loopFile);
1705 free(mp->mnt_fsname);
1706 }
1707 }
1708
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001709 report_error:
1710 if (ENABLE_FEATURE_CLEAN_UP)
1711 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001712
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00001713 if (errno == EBUSY && ignore_busy)
1714 return 0;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001715 if (rc < 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001716 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001717 return rc;
1718}
1719
1720// Parse options, if necessary parse fstab/mtab, and call singlemount for
1721// each directory to be mounted.
1722
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001723static const char must_be_root[] ALIGN1 = "you must be root";
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001724
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001725int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001726int mount_main(int argc, char **argv)
1727{
Denis Vlasenkoda3cec92006-09-24 01:01:01 +00001728 enum { OPT_ALL = 0x10 };
Denis Vlasenko9c99b622006-09-17 15:05:31 +00001729
1730 char *cmdopts = xstrdup(""), *fstype=0, *storage_path=0;
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001731 char *opt_o;
1732 const char *fstabname;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001733 FILE *fstab;
Denis Vlasenko9c99b622006-09-17 15:05:31 +00001734 int i, j, rc = 0;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001735 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001736 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001737 SKIP_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001738
Denis Vlasenkob4133682008-02-18 13:05:38 +00001739 USE_DESKTOP( int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00001740
Denis Vlasenkof732e962008-02-18 12:07:49 +00001741 // Parse long options, like --bind and --move. Note that -o option
1742 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001743
Denis Vlasenko9c99b622006-09-17 15:05:31 +00001744 for (i = j = 0; i < argc; i++) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001745 if (argv[i][0] == '-' && argv[i][1] == '-') {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001746 append_mount_options(&cmdopts, argv[i]+2);
Denis Vlasenko9c99b622006-09-17 15:05:31 +00001747 } else argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001748 }
Denis Vlasenkoda3cec92006-09-24 01:01:01 +00001749 argv[j] = 0;
Denis Vlasenko9c99b622006-09-17 15:05:31 +00001750 argc = j;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001751
1752 // Parse remaining options
1753
Denis Vlasenkof732e962008-02-18 12:07:49 +00001754#if ENABLE_FEATURE_MOUNT_VERBOSE
1755 opt_complementary = "vv"; // -v is a counter
1756#endif
1757 opt = getopt32(argv, OPTION_STR, &opt_o, &fstype
1758 USE_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00001759 if (opt & OPT_o) append_mount_options(&cmdopts, opt_o); // -o
1760 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1761 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001762 argv += optind;
1763 argc -= optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001764
1765 // Three or more non-option arguments? Die with a usage message.
1766
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001767 if (argc > 2) bb_show_usage();
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001768
1769 // If we have no arguments, show currently mounted filesystems
1770
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001771 if (!argc) {
Denis Vlasenko9c99b622006-09-17 15:05:31 +00001772 if (!(opt & OPT_ALL)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001773 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1774
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001775 if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001776
Denis Vlasenko2535f122007-09-15 13:28:30 +00001777 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
1778 sizeof(getmntent_buf)))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001779 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001780 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00001781 // util-linux 2.12a happily shows rootfs...
1782 //if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001783
1784 if (!fstype || !strcmp(mtpair->mnt_type, fstype))
1785 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1786 mtpair->mnt_dir, mtpair->mnt_type,
1787 mtpair->mnt_opts);
1788 }
1789 if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable);
1790 return EXIT_SUCCESS;
1791 }
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001792 } else storage_path = bb_simplify_path(argv[0]);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001793
1794 // When we have two arguments, the second is the directory and we can
1795 // skip looking at fstab entirely. We can always abspath() the directory
1796 // argument when we get it.
1797
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001798 if (argc == 2) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001799 if (nonroot)
1800 bb_error_msg_and_die(must_be_root);
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001801 mtpair->mnt_fsname = argv[0];
1802 mtpair->mnt_dir = argv[1];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001803 mtpair->mnt_type = fstype;
1804 mtpair->mnt_opts = cmdopts;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001805 if (ENABLE_FEATURE_MOUNT_LABEL) {
1806 resolve_mount_spec(&mtpair->mnt_fsname);
1807 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001808 rc = singlemount(mtpair, 0);
1809 goto clean_up;
1810 }
1811
Denis Vlasenkob4133682008-02-18 13:05:38 +00001812 i = parse_mount_options(cmdopts, 0); // FIXME: should be "long", not "int"
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001813 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
1814 bb_error_msg_and_die(must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00001815
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001816 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko546cd182006-10-02 18:52:49 +00001817
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001818 if (ENABLE_FEATURE_MOUNT_FLAGS
1819 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1820 ) {
Denis Vlasenkof732e962008-02-18 12:07:49 +00001821 rc = verbose_mount("", argv[0], "", i, "");
Denis Vlasenko0c97c9d2007-10-01 11:58:38 +00001822 if (rc) bb_simple_perror_msg_and_die(argv[0]);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001823 goto clean_up;
1824 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001825
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001826 // Open either fstab or mtab
1827
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001828 fstabname = "/etc/fstab";
1829 if (i & MS_REMOUNT) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001830 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001831 }
1832 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001833 if (!fstab)
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001834 bb_perror_msg_and_die("cannot read %s", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001835
1836 // Loop through entries until we find what we're looking for.
1837
Denis Vlasenko546cd182006-10-02 18:52:49 +00001838 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001839 for (;;) {
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001840 struct mntent *mtnext = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001841
1842 // Get next fstab entry
1843
Denis Vlasenko2535f122007-09-15 13:28:30 +00001844 if (!getmntent_r(fstab, mtcur, getmntent_buf
1845 + (mtcur==mtpair ? sizeof(getmntent_buf)/2 : 0),
1846 sizeof(getmntent_buf)/2))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001847 {
1848 // Were we looking for something specific?
1849
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001850 if (argc) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001851
1852 // If we didn't find anything, complain.
1853
1854 if (!mtnext->mnt_fsname)
1855 bb_error_msg_and_die("can't find %s in %s",
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001856 argv[0], fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001857
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001858 mtcur = mtnext;
1859 if (nonroot) {
1860 // fstab must have "users" or "user"
1861 if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))
1862 bb_error_msg_and_die(must_be_root);
1863 }
1864
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001865 // Mount the last thing we found.
1866
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001867 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001868 append_mount_options(&(mtcur->mnt_opts), cmdopts);
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001869 if (ENABLE_FEATURE_MOUNT_LABEL) {
1870 resolve_mount_spec(&mtpair->mnt_fsname);
1871 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001872 rc = singlemount(mtcur, 0);
1873 free(mtcur->mnt_opts);
1874 }
1875 goto clean_up;
1876 }
1877
1878 /* If we're trying to mount something specific and this isn't it,
1879 * skip it. Note we must match both the exact text in fstab (ala
1880 * "proc") or a full path from root */
1881
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001882 if (argc) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001883
1884 // Is this what we're looking for?
1885
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001886 if (strcmp(argv[0], mtcur->mnt_fsname) &&
1887 strcmp(storage_path, mtcur->mnt_fsname) &&
1888 strcmp(argv[0], mtcur->mnt_dir) &&
1889 strcmp(storage_path, mtcur->mnt_dir)) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001890
1891 // Remember this entry. Something later may have overmounted
1892 // it, and we want the _last_ match.
1893
1894 mtcur = mtnext;
1895
1896 // If we're mounting all.
1897
1898 } else {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001899 // Do we need to match a filesystem type?
Denis Vlasenkobf295dd2007-04-05 21:57:47 +00001900 if (fstype && match_fstype(mtcur, fstype)) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001901
1902 // Skip noauto and swap anyway.
1903
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001904 if (parse_mount_options(mtcur->mnt_opts, 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001905 & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;
1906
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001907 // No, mount -a won't mount anything,
1908 // even user mounts, for mere humans.
1909
1910 if (nonroot)
1911 bb_error_msg_and_die(must_be_root);
1912
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001913 // Mount this thing.
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001914 if (ENABLE_FEATURE_MOUNT_LABEL) {
1915 resolve_mount_spec(&mtpair->mnt_fsname);
1916 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001917
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001918 // NFS mounts want this to be xrealloc-able
1919 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001920 if (singlemount(mtcur, 1)) {
1921 /* Count number of failed mounts */
1922 rc++;
1923 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001924 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001925 }
1926 }
1927 if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab);
1928
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001929 clean_up:
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001930
1931 if (ENABLE_FEATURE_CLEAN_UP) {
1932 free(storage_path);
1933 free(cmdopts);
1934 }
1935
1936 return rc;
1937}