blob: 6e63a01fc2ac06477bfcd07072373143752e3982 [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 {
Denis Vlasenkoa4522c52008-03-17 08:46:43 +000059 MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
60 MOUNT_NOAUTO = (1 << 29),
61 MOUNT_SWAP = (1 << 30),
Denis Vlasenko13c5a682006-10-16 22:39:51 +000062};
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 Vlasenkoa4522c52008-03-17 08:46:43 +0000241 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000242 source, target, filesystemtype,
243 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000244 return rc;
245}
246#else
247#define verbose_mount(...) mount(__VA_ARGS__)
248#endif
249
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000250static int resolve_mount_spec(char **fsname)
251{
252 char *tmp = NULL;
253
254 if (!strncmp(*fsname, "UUID=", 5))
255 tmp = get_devname_from_uuid(*fsname + 5);
256 else if (!strncmp(*fsname, "LABEL=", 6))
257 tmp = get_devname_from_label(*fsname + 6);
258
259 if (tmp) {
260 *fsname = tmp;
261 return 1;
262 }
263 return 0;
264}
265
Rob Landleydc0955b2006-03-14 18:16:25 +0000266/* Append mount options to string */
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000267static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000268{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000269 if (*oldopts && **oldopts) {
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000270 /* do not insert options which are already there */
271 while (newopts[0]) {
272 char *p;
273 int len = strlen(newopts);
274 p = strchr(newopts, ',');
275 if (p) len = p - newopts;
276 p = *oldopts;
277 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000278 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000279 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000280 goto skip;
281 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000282 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000283 p++;
284 }
285 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
286 free(*oldopts);
287 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000288 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000289 newopts += len;
290 while (newopts[0] == ',') newopts++;
291 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000292 } else {
293 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000294 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000295 }
296}
297
298/* Use the mount_options list to parse options into flags.
Denis Vlasenko00d7d6c2006-09-11 17:42:44 +0000299 * Also return list of unrecognized options if unrecognized!=NULL */
Denis Vlasenkob4133682008-02-18 13:05:38 +0000300static long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000301{
Denis Vlasenkob4133682008-02-18 13:05:38 +0000302 long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000303
Rob Landley6a6798b2005-08-10 20:35:54 +0000304 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000305 for (;;) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000306 int i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000307 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000308 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000309
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000310 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000311
Rob Landley6a6798b2005-08-10 20:35:54 +0000312 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000313 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000314 if (!strcasecmp(option_str, options)) {
315 long fl = mount_options[i];
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000316 if (fl < 0) flags &= fl;
Rob Landleydc0955b2006-03-14 18:16:25 +0000317 else flags |= fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000318 break;
319 }
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000320 option_str += strlen(option_str) + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000321 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000322 // If unrecognized not NULL, append unrecognized mount options */
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000323 if (unrecognized && i == ARRAY_SIZE(mount_options)) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000324 // Add it to strflags, to pass on to kernel
Rob Landleydc0955b2006-03-14 18:16:25 +0000325 i = *unrecognized ? strlen(*unrecognized) : 0;
326 *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000327
Rob Landley6a6798b2005-08-10 20:35:54 +0000328 // Comma separated if it's not the first one
Rob Landleydc0955b2006-03-14 18:16:25 +0000329 if (i) (*unrecognized)[i++] = ',';
330 strcpy((*unrecognized)+i, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000331 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000332
Denis Vlasenko2535f122007-09-15 13:28:30 +0000333 if (!comma)
334 break;
335 // Advance to next option
336 *comma = ',';
337 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000338 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000339
Rob Landleydc0955b2006-03-14 18:16:25 +0000340 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000341}
342
Rob Landleydc0955b2006-03-14 18:16:25 +0000343// Return a list of all block device backed filesystems
Matt Kraai12400822001-04-17 04:32:50 +0000344
Rob Landleydc0955b2006-03-14 18:16:25 +0000345static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000346{
Denis Vlasenko87468852007-04-13 23:22:00 +0000347 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000348 "/etc/filesystems",
349 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000350 };
351 char *fs, *buf;
Rob Landleydc0955b2006-03-14 18:16:25 +0000352 llist_t *list = 0;
353 int i;
354 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000355
Denis Vlasenko87468852007-04-13 23:22:00 +0000356 for (i = 0; i < 2; i++) {
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000357 f = fopen(filesystems[i], "r");
358 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000359
Denis Vlasenko2d5ca602006-10-12 22:43:20 +0000360 while ((buf = xmalloc_getline(f)) != 0) {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000361 if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))
362 continue;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000363 fs = skip_whitespace(buf);
Denis Vlasenko372686b2006-10-12 22:42:33 +0000364 if (*fs=='#' || *fs=='*' || !*fs) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000365
Denis Vlasenko372686b2006-10-12 22:42:33 +0000366 llist_add_to_end(&list, xstrdup(fs));
367 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000368 }
369 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
370 }
371
372 return list;
373}
374
Rob Landleydc0955b2006-03-14 18:16:25 +0000375#if ENABLE_FEATURE_CLEAN_UP
376static void delete_block_backed_filesystems(void)
377{
Rob Landleya6b5b602006-05-08 19:03:07 +0000378 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000379}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000380#else
381void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000382#endif
383
Rob Landleydc0955b2006-03-14 18:16:25 +0000384// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000385// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000386static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000387{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000388 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000389
Denis Vlasenkob4133682008-02-18 13:05:38 +0000390 if (fakeIt) {
391 if (verbose >= 2)
392 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
393 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
394 vfsflags, filteropts);
395 goto mtab;
396 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000397
Rob Landleydc0955b2006-03-14 18:16:25 +0000398 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000399 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000400 errno = 0;
401 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000402 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000403
404 // If mount failed, try
405 // helper program <mnt_type>
406 if (ENABLE_FEATURE_MOUNT_HELPERS && rc) {
407 char *args[6];
408 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000409 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000410 rc = 1;
411 if (filteropts) {
412 args[rc++] = (char *)"-o";
413 args[rc++] = filteropts;
414 }
415 args[rc++] = mp->mnt_fsname;
416 args[rc++] = mp->mnt_dir;
417 args[rc] = NULL;
418 rc = wait4pid(spawn(args));
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000419 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000420 if (!rc)
421 break;
422 errno = errno_save;
423 }
424
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000425 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000426 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000427 if (!(vfsflags & MS_SILENT))
428 bb_error_msg("%s is write-protected, mounting read-only",
429 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000430 vfsflags |= MS_RDONLY;
431 }
432
Rob Landleydc0955b2006-03-14 18:16:25 +0000433 // Abort entirely if permission denied.
434
435 if (rc && errno == EPERM)
436 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
437
438 /* If the mount was successful, and we're maintaining an old-style
439 * mtab file by hand, add the new entry to it now. */
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000440 mtab:
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000441 if (useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000442 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000443 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000444 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000445 int i;
446
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000447 if (!mountTable) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000448 bb_error_msg("no %s", bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000449 goto ret;
450 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000451
452 // Add vfs string flags
453
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000454 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
455 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
456 append_mount_options(&(mp->mnt_opts), option_str);
457 option_str += strlen(option_str) + 1;
458 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000459
460 // Remove trailing / (if any) from directory we mounted on
461
Denis Vlasenko727ef942006-09-14 13:19:19 +0000462 i = strlen(mp->mnt_dir) - 1;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000463 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000464
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000465 // Convert to canonical pathnames as needed
Denis Vlasenko727ef942006-09-14 13:19:19 +0000466
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000467 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000468 fsname = 0;
Denis Vlasenko727ef942006-09-14 13:19:19 +0000469 if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000470 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000471 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000472 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000473 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000474
475 // Write and close.
476
Denis Vlasenko727ef942006-09-14 13:19:19 +0000477 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000478 endmntent(mountTable);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000479 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000480 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000481 free(fsname);
482 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000483 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000484 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000485 return rc;
486}
487
Denis Vlasenko25098f72006-09-14 15:46:33 +0000488#if ENABLE_FEATURE_MOUNT_NFS
489
490/*
491 * Linux NFS mount
492 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
493 *
494 * Licensed under GPLv2, see file LICENSE in this tarball for details.
495 *
496 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
497 * numbers to be specified on the command line.
498 *
499 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
500 * Omit the call to connect() for Linux version 1.3.11 or later.
501 *
502 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
503 * Implemented the "bg", "fg" and "retry" mount options for NFS.
504 *
505 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
506 * - added Native Language Support
507 *
508 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
509 * plus NFSv3 stuff.
510 */
511
Denis Vlasenko25098f72006-09-14 15:46:33 +0000512/* This is just a warning of a common mistake. Possibly this should be a
513 * uclibc faq entry rather than in busybox... */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000514#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000515#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
516#endif
517
518#define MOUNTPORT 635
519#define MNTPATHLEN 1024
520#define MNTNAMLEN 255
521#define FHSIZE 32
522#define FHSIZE3 64
523
524typedef char fhandle[FHSIZE];
525
526typedef struct {
527 unsigned int fhandle3_len;
528 char *fhandle3_val;
529} fhandle3;
530
531enum mountstat3 {
532 MNT_OK = 0,
533 MNT3ERR_PERM = 1,
534 MNT3ERR_NOENT = 2,
535 MNT3ERR_IO = 5,
536 MNT3ERR_ACCES = 13,
537 MNT3ERR_NOTDIR = 20,
538 MNT3ERR_INVAL = 22,
539 MNT3ERR_NAMETOOLONG = 63,
540 MNT3ERR_NOTSUPP = 10004,
541 MNT3ERR_SERVERFAULT = 10006,
542};
543typedef enum mountstat3 mountstat3;
544
545struct fhstatus {
546 unsigned int fhs_status;
547 union {
548 fhandle fhs_fhandle;
549 } fhstatus_u;
550};
551typedef struct fhstatus fhstatus;
552
553struct mountres3_ok {
554 fhandle3 fhandle;
555 struct {
556 unsigned int auth_flavours_len;
557 char *auth_flavours_val;
558 } auth_flavours;
559};
560typedef struct mountres3_ok mountres3_ok;
561
562struct mountres3 {
563 mountstat3 fhs_status;
564 union {
565 mountres3_ok mountinfo;
566 } mountres3_u;
567};
568typedef struct mountres3 mountres3;
569
570typedef char *dirpath;
571
572typedef char *name;
573
574typedef struct mountbody *mountlist;
575
576struct mountbody {
577 name ml_hostname;
578 dirpath ml_directory;
579 mountlist ml_next;
580};
581typedef struct mountbody mountbody;
582
583typedef struct groupnode *groups;
584
585struct groupnode {
586 name gr_name;
587 groups gr_next;
588};
589typedef struct groupnode groupnode;
590
591typedef struct exportnode *exports;
592
593struct exportnode {
594 dirpath ex_dir;
595 groups ex_groups;
596 exports ex_next;
597};
598typedef struct exportnode exportnode;
599
600struct ppathcnf {
601 int pc_link_max;
602 short pc_max_canon;
603 short pc_max_input;
604 short pc_name_max;
605 short pc_path_max;
606 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000607 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000608 char pc_xxx;
609 short pc_mask[2];
610};
611typedef struct ppathcnf ppathcnf;
612
613#define MOUNTPROG 100005
614#define MOUNTVERS 1
615
616#define MOUNTPROC_NULL 0
617#define MOUNTPROC_MNT 1
618#define MOUNTPROC_DUMP 2
619#define MOUNTPROC_UMNT 3
620#define MOUNTPROC_UMNTALL 4
621#define MOUNTPROC_EXPORT 5
622#define MOUNTPROC_EXPORTALL 6
623
624#define MOUNTVERS_POSIX 2
625
626#define MOUNTPROC_PATHCONF 7
627
628#define MOUNT_V3 3
629
630#define MOUNTPROC3_NULL 0
631#define MOUNTPROC3_MNT 1
632#define MOUNTPROC3_DUMP 2
633#define MOUNTPROC3_UMNT 3
634#define MOUNTPROC3_UMNTALL 4
635#define MOUNTPROC3_EXPORT 5
636
637enum {
638#ifndef NFS_FHSIZE
639 NFS_FHSIZE = 32,
640#endif
641#ifndef NFS_PORT
642 NFS_PORT = 2049
643#endif
644};
645
Denis Vlasenko25098f72006-09-14 15:46:33 +0000646/*
647 * We want to be able to compile mount on old kernels in such a way
648 * that the binary will work well on more recent kernels.
649 * Thus, if necessary we teach nfsmount.c the structure of new fields
650 * that will come later.
651 *
652 * Moreover, the new kernel includes conflict with glibc includes
653 * so it is easiest to ignore the kernel altogether (at compile time).
654 */
655
656struct nfs2_fh {
657 char data[32];
658};
659struct nfs3_fh {
660 unsigned short size;
661 unsigned char data[64];
662};
663
664struct nfs_mount_data {
665 int version; /* 1 */
666 int fd; /* 1 */
667 struct nfs2_fh old_root; /* 1 */
668 int flags; /* 1 */
669 int rsize; /* 1 */
670 int wsize; /* 1 */
671 int timeo; /* 1 */
672 int retrans; /* 1 */
673 int acregmin; /* 1 */
674 int acregmax; /* 1 */
675 int acdirmin; /* 1 */
676 int acdirmax; /* 1 */
677 struct sockaddr_in addr; /* 1 */
678 char hostname[256]; /* 1 */
679 int namlen; /* 2 */
680 unsigned int bsize; /* 3 */
681 struct nfs3_fh root; /* 4 */
682};
683
684/* bits in the flags field */
685enum {
686 NFS_MOUNT_SOFT = 0x0001, /* 1 */
687 NFS_MOUNT_INTR = 0x0002, /* 1 */
688 NFS_MOUNT_SECURE = 0x0004, /* 1 */
689 NFS_MOUNT_POSIX = 0x0008, /* 1 */
690 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
691 NFS_MOUNT_NOAC = 0x0020, /* 1 */
692 NFS_MOUNT_TCP = 0x0040, /* 2 */
693 NFS_MOUNT_VER3 = 0x0080, /* 3 */
694 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
695 NFS_MOUNT_NONLM = 0x0200 /* 3 */
696};
697
698
699/*
700 * We need to translate between nfs status return values and
701 * the local errno values which may not be the same.
702 *
703 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
704 * "after #include <errno.h> the symbol errno is reserved for any use,
705 * it cannot even be used as a struct tag or field name".
706 */
707
708#ifndef EDQUOT
709#define EDQUOT ENOSPC
710#endif
711
712// Convert each NFSERR_BLAH into EBLAH
713
714static const struct {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000715 short stat;
716 short errnum;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000717} nfs_errtbl[] = {
718 {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
719 {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
720 {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
721 {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
722};
723
724static char *nfs_strerror(int status)
725{
726 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000727
728 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
729 if (nfs_errtbl[i].stat == status)
730 return strerror(nfs_errtbl[i].errnum);
731 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000732 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000733}
734
735static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
736{
737 if (!xdr_opaque(xdrs, objp, FHSIZE))
738 return FALSE;
739 return TRUE;
740}
741
742static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
743{
744 if (!xdr_u_int(xdrs, &objp->fhs_status))
745 return FALSE;
746 switch (objp->fhs_status) {
747 case 0:
748 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
749 return FALSE;
750 break;
751 default:
752 break;
753 }
754 return TRUE;
755}
756
757static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
758{
759 if (!xdr_string(xdrs, objp, MNTPATHLEN))
760 return FALSE;
761 return TRUE;
762}
763
764static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
765{
766 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
767 return FALSE;
768 return TRUE;
769}
770
771static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
772{
773 if (!xdr_fhandle3(xdrs, &objp->fhandle))
774 return FALSE;
775 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
776 sizeof (int), (xdrproc_t) xdr_int))
777 return FALSE;
778 return TRUE;
779}
780
781static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
782{
783 if (!xdr_enum(xdrs, (enum_t *) objp))
784 return FALSE;
785 return TRUE;
786}
787
788static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
789{
790 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
791 return FALSE;
792 switch (objp->fhs_status) {
793 case MNT_OK:
794 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
795 return FALSE;
796 break;
797 default:
798 break;
799 }
800 return TRUE;
801}
802
803#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
804
Denis Vlasenko25098f72006-09-14 15:46:33 +0000805/*
806 * Unfortunately, the kernel prints annoying console messages
807 * in case of an unexpected nfs mount version (instead of
808 * just returning some error). Therefore we'll have to try
809 * and figure out what version the kernel expects.
810 *
811 * Variables:
812 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
813 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
814 * nfs_mount_version: version this source and running kernel can handle
815 */
816static void
817find_kernel_nfs_mount_version(void)
818{
Denis Vlasenkob9256052007-09-28 10:29:17 +0000819 int kernel_version;
820
821 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000822 return;
823
824 nfs_mount_version = 4; /* default */
825
826 kernel_version = get_linux_version_code();
827 if (kernel_version) {
828 if (kernel_version < KERNEL_VERSION(2,1,32))
829 nfs_mount_version = 1;
830 else if (kernel_version < KERNEL_VERSION(2,2,18) ||
831 (kernel_version >= KERNEL_VERSION(2,3,0) &&
832 kernel_version < KERNEL_VERSION(2,3,99)))
833 nfs_mount_version = 3;
834 /* else v4 since 2.3.99pre4 */
835 }
836}
837
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000838static void
Denis Vlasenkob9256052007-09-28 10:29:17 +0000839get_mountport(struct pmap *pm_mnt,
840 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +0000841 long unsigned prog,
842 long unsigned version,
843 long unsigned proto,
844 long unsigned port)
845{
846 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000847
848 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +0000849/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
850 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000851 pmap = pmap_getmaps(server_addr);
852
853 if (version > MAX_NFSPROT)
854 version = MAX_NFSPROT;
855 if (!prog)
856 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000857 pm_mnt->pm_prog = prog;
858 pm_mnt->pm_vers = version;
859 pm_mnt->pm_prot = proto;
860 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000861
Denis Vlasenko25098f72006-09-14 15:46:33 +0000862 while (pmap) {
863 if (pmap->pml_map.pm_prog != prog)
864 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000865 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000866 goto next;
867 if (version > 2 && pmap->pml_map.pm_vers != version)
868 goto next;
869 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
870 goto next;
871 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
Denis Vlasenkob9256052007-09-28 10:29:17 +0000872 (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
Denis Vlasenko25098f72006-09-14 15:46:33 +0000873 (port && pmap->pml_map.pm_port != port))
874 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000875 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
876 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +0000877 pmap = pmap->pml_next;
878 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000879 if (!pm_mnt->pm_vers)
880 pm_mnt->pm_vers = MOUNTVERS;
881 if (!pm_mnt->pm_port)
882 pm_mnt->pm_port = MOUNTPORT;
883 if (!pm_mnt->pm_prot)
884 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000885}
886
Denis Vlasenkof0000652007-09-04 18:30:26 +0000887#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +0000888static int daemonize(void)
889{
890 int fd;
891 int pid = fork();
892 if (pid < 0) /* error */
893 return -errno;
894 if (pid > 0) /* parent */
895 return 0;
896 /* child */
897 fd = xopen(bb_dev_null, O_RDWR);
898 dup2(fd, 0);
899 dup2(fd, 1);
900 dup2(fd, 2);
Denis Vlasenko9af7c9d2007-01-19 21:19:35 +0000901 while (fd > 2) close(fd--);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000902 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000903 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000904 logmode = LOGMODE_SYSLOG;
905 return 1;
906}
Denis Vlasenkof0000652007-09-04 18:30:26 +0000907#else
908static inline int daemonize(void) { return -ENOSYS; }
909#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000910
911// TODO
Denis Vlasenko68404f12008-03-17 09:00:54 +0000912static inline int we_saw_this_host_before(const char *hostname ATTRIBUTE_UNUSED)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000913{
914 return 0;
915}
916
917/* RPC strerror analogs are terminally idiotic:
918 * *mandatory* prefix and \n at end.
919 * This hopefully helps. Usage:
920 * error_msg_rpc(clnt_*error*(" ")) */
921static void error_msg_rpc(const char *msg)
922{
Denis Vlasenko23514fe2006-09-19 14:07:52 +0000923 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000924 while (msg[0] == ' ' || msg[0] == ':') msg++;
925 len = strlen(msg);
926 while (len && msg[len-1] == '\n') len--;
927 bb_error_msg("%.*s", len, msg);
928}
929
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +0000930// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000931static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000932{
933 CLIENT *mclient;
934 char *hostname;
935 char *pathname;
936 char *mounthost;
937 struct nfs_mount_data data;
938 char *opt;
939 struct hostent *hp;
940 struct sockaddr_in server_addr;
941 struct sockaddr_in mount_server_addr;
942 int msock, fsock;
943 union {
944 struct fhstatus nfsv2;
945 struct mountres3 nfsv3;
946 } status;
947 int daemonized;
948 char *s;
949 int port;
950 int mountport;
951 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000952#if BB_MMU
953 int bg = 0;
954#else
955 enum { bg = 0 };
956#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000957 int soft;
958 int intr;
959 int posix;
960 int nocto;
961 int noac;
962 int nolock;
963 int retry;
964 int tcp;
965 int mountprog;
966 int mountvers;
967 int nfsprog;
968 int nfsvers;
969 int retval;
970
971 find_kernel_nfs_mount_version();
972
973 daemonized = 0;
974 mounthost = NULL;
975 retval = ETIMEDOUT;
976 msock = fsock = -1;
977 mclient = NULL;
978
979 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
980
981 filteropts = xstrdup(filteropts); /* going to trash it later... */
982
983 hostname = xstrdup(mp->mnt_fsname);
984 /* mount_main() guarantees that ':' is there */
985 s = strchr(hostname, ':');
986 pathname = s + 1;
987 *s = '\0';
988 /* Ignore all but first hostname in replicated mounts
989 until they can be fully supported. (mack@sgi.com) */
990 s = strchr(hostname, ',');
991 if (s) {
992 *s = '\0';
993 bb_error_msg("warning: multiple hostnames not supported");
994 }
995
996 server_addr.sin_family = AF_INET;
997 if (!inet_aton(hostname, &server_addr.sin_addr)) {
998 hp = gethostbyname(hostname);
999 if (hp == NULL) {
1000 bb_herror_msg("%s", hostname);
1001 goto fail;
1002 }
1003 if (hp->h_length > sizeof(struct in_addr)) {
1004 bb_error_msg("got bad hp->h_length");
1005 hp->h_length = sizeof(struct in_addr);
1006 }
1007 memcpy(&server_addr.sin_addr,
1008 hp->h_addr, hp->h_length);
1009 }
1010
1011 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1012
1013 /* add IP address to mtab options for use when unmounting */
1014
1015 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1016 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1017 } else {
1018 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1019 mp->mnt_opts[0] ? "," : "",
1020 inet_ntoa(server_addr.sin_addr));
1021 free(mp->mnt_opts);
1022 mp->mnt_opts = tmp;
1023 }
1024
1025 /* Set default options.
1026 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1027 * let the kernel decide.
1028 * timeo is filled in after we know whether it'll be TCP or UDP. */
1029 memset(&data, 0, sizeof(data));
1030 data.retrans = 3;
1031 data.acregmin = 3;
1032 data.acregmax = 60;
1033 data.acdirmin = 30;
1034 data.acdirmax = 60;
1035 data.namlen = NAME_MAX;
1036
Denis Vlasenko25098f72006-09-14 15:46:33 +00001037 soft = 0;
1038 intr = 0;
1039 posix = 0;
1040 nocto = 0;
1041 nolock = 0;
1042 noac = 0;
1043 retry = 10000; /* 10000 minutes ~ 1 week */
1044 tcp = 0;
1045
1046 mountprog = MOUNTPROG;
1047 mountvers = 0;
1048 port = 0;
1049 mountport = 0;
1050 nfsprog = 100003;
1051 nfsvers = 0;
1052
1053 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001054 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001055 char *opteq = strchr(opt, '=');
1056 if (opteq) {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001057 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001058 /* 0 */ "rsize\0"
1059 /* 1 */ "wsize\0"
1060 /* 2 */ "timeo\0"
1061 /* 3 */ "retrans\0"
1062 /* 4 */ "acregmin\0"
1063 /* 5 */ "acregmax\0"
1064 /* 6 */ "acdirmin\0"
1065 /* 7 */ "acdirmax\0"
1066 /* 8 */ "actimeo\0"
1067 /* 9 */ "retry\0"
1068 /* 10 */ "port\0"
1069 /* 11 */ "mountport\0"
1070 /* 12 */ "mounthost\0"
1071 /* 13 */ "mountprog\0"
1072 /* 14 */ "mountvers\0"
1073 /* 15 */ "nfsprog\0"
1074 /* 16 */ "nfsvers\0"
1075 /* 17 */ "vers\0"
1076 /* 18 */ "proto\0"
1077 /* 19 */ "namlen\0"
1078 /* 20 */ "addr\0";
Denis Vlasenko13858992006-10-08 12:49:22 +00001079 int val = xatoi_u(opteq + 1);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001080 *opteq = '\0';
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001081 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001082 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001083 data.rsize = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001084 break;
1085 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001086 data.wsize = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001087 break;
1088 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001089 data.timeo = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001090 break;
1091 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001092 data.retrans = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001093 break;
1094 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001095 data.acregmin = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001096 break;
1097 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001098 data.acregmax = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001099 break;
1100 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001101 data.acdirmin = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001102 break;
1103 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001104 data.acdirmax = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001105 break;
1106 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001107 data.acregmin = val;
1108 data.acregmax = val;
1109 data.acdirmin = val;
1110 data.acdirmax = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001111 break;
1112 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001113 retry = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001114 break;
1115 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001116 port = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001117 break;
1118 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001119 mountport = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001120 break;
1121 case 12: // "mounthost"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001122 mounthost = xstrndup(opteq+1,
Denis Vlasenko5af906e2006-11-05 18:05:09 +00001123 strcspn(opteq+1," \t\n\r,"));
Denis Vlasenko68f21872006-10-26 01:47:34 +00001124 break;
1125 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001126 mountprog = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001127 break;
1128 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001129 mountvers = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001130 break;
1131 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001132 nfsprog = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001133 break;
1134 case 16: // "nfsvers"
1135 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001136 nfsvers = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001137 break;
1138 case 18: // "proto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001139 if (!strncmp(opteq+1, "tcp", 3))
1140 tcp = 1;
1141 else if (!strncmp(opteq+1, "udp", 3))
1142 tcp = 0;
1143 else
1144 bb_error_msg("warning: unrecognized proto= option");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001145 break;
1146 case 19: // "namlen"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001147 if (nfs_mount_version >= 2)
1148 data.namlen = val;
1149 else
1150 bb_error_msg("warning: option namlen is not supported\n");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001151 break;
1152 case 20: // "addr" - ignore
1153 break;
1154 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001155 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1156 goto fail;
1157 }
1158 }
1159 else {
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001160 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001161 "bg\0"
1162 "fg\0"
1163 "soft\0"
1164 "hard\0"
1165 "intr\0"
1166 "posix\0"
1167 "cto\0"
1168 "ac\0"
1169 "tcp\0"
1170 "udp\0"
1171 "lock\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001172 int val = 1;
1173 if (!strncmp(opt, "no", 2)) {
1174 val = 0;
1175 opt += 2;
1176 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001177 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001178 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001179#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001180 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001181#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001182 break;
1183 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001184#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001185 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001186#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001187 break;
1188 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001189 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001190 break;
1191 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001192 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001193 break;
1194 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001195 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001196 break;
1197 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001198 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001199 break;
1200 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001201 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001202 break;
1203 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001204 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001205 break;
1206 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001207 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001208 break;
1209 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001210 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001211 break;
1212 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001213 if (nfs_mount_version >= 3)
1214 nolock = !val;
1215 else
1216 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001217 break;
1218 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001219 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1220 goto fail;
1221 }
1222 }
1223 }
1224 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1225
1226 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1227 | (intr ? NFS_MOUNT_INTR : 0)
1228 | (posix ? NFS_MOUNT_POSIX : 0)
1229 | (nocto ? NFS_MOUNT_NOCTO : 0)
1230 | (noac ? NFS_MOUNT_NOAC : 0);
1231 if (nfs_mount_version >= 2)
1232 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1233 if (nfs_mount_version >= 3)
1234 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1235 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1236 bb_error_msg("NFSv%d not supported", nfsvers);
1237 goto fail;
1238 }
1239 if (nfsvers && !mountvers)
1240 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1241 if (nfsvers && nfsvers < mountvers) {
1242 mountvers = nfsvers;
1243 }
1244
1245 /* Adjust options if none specified */
1246 if (!data.timeo)
1247 data.timeo = tcp ? 70 : 7;
1248
Denis Vlasenko25098f72006-09-14 15:46:33 +00001249 data.version = nfs_mount_version;
1250
1251 if (vfsflags & MS_REMOUNT)
1252 goto do_mount;
1253
1254 /*
1255 * If the previous mount operation on the same host was
1256 * backgrounded, and the "bg" for this mount is also set,
1257 * give up immediately, to avoid the initial timeout.
1258 */
1259 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001260 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001261 if (daemonized <= 0) { /* parent or error */
1262 retval = -daemonized;
1263 goto ret;
1264 }
1265 }
1266
1267 /* create mount daemon client */
1268 /* See if the nfs host = mount host. */
1269 if (mounthost) {
1270 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1271 mount_server_addr.sin_family = AF_INET;
1272 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1273 } else {
1274 hp = gethostbyname(mounthost);
1275 if (hp == NULL) {
1276 bb_herror_msg("%s", mounthost);
1277 goto fail;
1278 } else {
1279 if (hp->h_length > sizeof(struct in_addr)) {
1280 bb_error_msg("got bad hp->h_length?");
1281 hp->h_length = sizeof(struct in_addr);
1282 }
1283 mount_server_addr.sin_family = AF_INET;
1284 memcpy(&mount_server_addr.sin_addr,
1285 hp->h_addr, hp->h_length);
1286 }
1287 }
1288 }
1289
1290 /*
1291 * The following loop implements the mount retries. When the mount
1292 * times out, and the "bg" option is set, we background ourself
1293 * and continue trying.
1294 *
1295 * The case where the mount point is not present and the "bg"
1296 * option is set, is treated as a timeout. This is done to
1297 * support nested mounts.
1298 *
1299 * The "retry" count specified by the user is the number of
1300 * minutes to retry before giving up.
1301 */
1302 {
1303 struct timeval total_timeout;
1304 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001305 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001306 time_t t;
1307 time_t prevt;
1308 time_t timeout;
1309
1310 retry_timeout.tv_sec = 3;
1311 retry_timeout.tv_usec = 0;
1312 total_timeout.tv_sec = 20;
1313 total_timeout.tv_usec = 0;
1314 timeout = time(NULL) + 60 * retry;
1315 prevt = 0;
1316 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001317 retry:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001318 /* be careful not to use too many CPU cycles */
1319 if (t - prevt < 30)
1320 sleep(30);
1321
Denis Vlasenkob9256052007-09-28 10:29:17 +00001322 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001323 mountprog,
1324 mountvers,
1325 proto,
1326 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001327 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001328
1329 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001330 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001331 msock = RPC_ANYSOCK;
1332
Denis Vlasenkob9256052007-09-28 10:29:17 +00001333 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001334 case IPPROTO_UDP:
1335 mclient = clntudp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001336 pm_mnt.pm_prog,
1337 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001338 retry_timeout,
1339 &msock);
1340 if (mclient)
1341 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001342 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001343 msock = RPC_ANYSOCK;
1344 case IPPROTO_TCP:
1345 mclient = clnttcp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001346 pm_mnt.pm_prog,
1347 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001348 &msock, 0, 0);
1349 break;
1350 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001351 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001352 }
1353 if (!mclient) {
1354 if (!daemonized && prevt == 0)
1355 error_msg_rpc(clnt_spcreateerror(" "));
1356 } else {
1357 enum clnt_stat clnt_stat;
1358 /* try to mount hostname:pathname */
1359 mclient->cl_auth = authunix_create_default();
1360
1361 /* make pointers in xdr_mountres3 NULL so
1362 * that xdr_array allocates memory for us
1363 */
1364 memset(&status, 0, sizeof(status));
1365
Denis Vlasenkob9256052007-09-28 10:29:17 +00001366 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001367 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1368 (xdrproc_t) xdr_dirpath,
1369 (caddr_t) &pathname,
1370 (xdrproc_t) xdr_mountres3,
1371 (caddr_t) &status,
1372 total_timeout);
1373 else
1374 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1375 (xdrproc_t) xdr_dirpath,
1376 (caddr_t) &pathname,
1377 (xdrproc_t) xdr_fhstatus,
1378 (caddr_t) &status,
1379 total_timeout);
1380
1381 if (clnt_stat == RPC_SUCCESS)
1382 goto prepare_kernel_data; /* we're done */
1383 if (errno != ECONNREFUSED) {
1384 error_msg_rpc(clnt_sperror(mclient, " "));
1385 goto fail; /* don't retry */
1386 }
1387 /* Connection refused */
1388 if (!daemonized && prevt == 0) /* print just once */
1389 error_msg_rpc(clnt_sperror(mclient, " "));
1390 auth_destroy(mclient->cl_auth);
1391 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001392 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001393 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001394 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001395 }
1396
1397 /* Timeout. We are going to retry... maybe */
1398
1399 if (!bg)
1400 goto fail;
1401 if (!daemonized) {
1402 daemonized = daemonize();
1403 if (daemonized <= 0) { /* parent or error */
1404 retval = -daemonized;
1405 goto ret;
1406 }
1407 }
1408 prevt = t;
1409 t = time(NULL);
1410 if (t >= timeout)
1411 /* TODO error message */
1412 goto fail;
1413
1414 goto retry;
1415 }
1416
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001417 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001418
1419 if (nfsvers == 2) {
1420 if (status.nfsv2.fhs_status != 0) {
1421 bb_error_msg("%s:%s failed, reason given by server: %s",
1422 hostname, pathname,
1423 nfs_strerror(status.nfsv2.fhs_status));
1424 goto fail;
1425 }
1426 memcpy(data.root.data,
1427 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1428 NFS_FHSIZE);
1429 data.root.size = NFS_FHSIZE;
1430 memcpy(data.old_root.data,
1431 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1432 NFS_FHSIZE);
1433 } else {
1434 fhandle3 *my_fhandle;
1435 if (status.nfsv3.fhs_status != 0) {
1436 bb_error_msg("%s:%s failed, reason given by server: %s",
1437 hostname, pathname,
1438 nfs_strerror(status.nfsv3.fhs_status));
1439 goto fail;
1440 }
1441 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1442 memset(data.old_root.data, 0, NFS_FHSIZE);
1443 memset(&data.root, 0, sizeof(data.root));
1444 data.root.size = my_fhandle->fhandle3_len;
1445 memcpy(data.root.data,
1446 (char *) my_fhandle->fhandle3_val,
1447 my_fhandle->fhandle3_len);
1448
1449 data.flags |= NFS_MOUNT_VER3;
1450 }
1451
1452 /* create nfs socket for kernel */
1453
1454 if (tcp) {
1455 if (nfs_mount_version < 3) {
1456 bb_error_msg("NFS over TCP is not supported");
1457 goto fail;
1458 }
1459 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1460 } else
1461 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1462 if (fsock < 0) {
1463 bb_perror_msg("nfs socket");
1464 goto fail;
1465 }
1466 if (bindresvport(fsock, 0) < 0) {
1467 bb_perror_msg("nfs bindresvport");
1468 goto fail;
1469 }
1470 if (port == 0) {
1471 server_addr.sin_port = PMAPPORT;
1472 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1473 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1474 if (port == 0)
1475 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001476 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001477 server_addr.sin_port = htons(port);
1478
1479 /* prepare data structure for kernel */
1480
1481 data.fd = fsock;
1482 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1483 strncpy(data.hostname, hostname, sizeof(data.hostname));
1484
1485 /* clean up */
1486
1487 auth_destroy(mclient->cl_auth);
1488 clnt_destroy(mclient);
1489 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001490 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001491
1492 if (bg) {
1493 /* We must wait until mount directory is available */
1494 struct stat statbuf;
1495 int delay = 1;
1496 while (stat(mp->mnt_dir, &statbuf) == -1) {
1497 if (!daemonized) {
1498 daemonized = daemonize();
1499 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001500 // FIXME: parent doesn't close fsock - ??!
Denis Vlasenko25098f72006-09-14 15:46:33 +00001501 retval = -daemonized;
1502 goto ret;
1503 }
1504 }
1505 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1506 delay *= 2;
1507 if (delay > 30)
1508 delay = 30;
1509 }
1510 }
1511
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001512 do_mount: /* perform actual mount */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001513
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001514 mp->mnt_type = (char*)"nfs";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001515 retval = mount_it_now(mp, vfsflags, (char*)&data);
1516 goto ret;
1517
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001518 fail: /* abort */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001519
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001520 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001521 if (mclient) {
1522 auth_destroy(mclient->cl_auth);
1523 clnt_destroy(mclient);
1524 }
1525 close(msock);
1526 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001527 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001528 close(fsock);
1529
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001530 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001531 free(hostname);
1532 free(mounthost);
1533 free(filteropts);
1534 return retval;
1535}
1536
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001537#else /* !ENABLE_FEATURE_MOUNT_NFS */
1538
1539/* Never called. Call should be optimized out. */
Denis Vlasenkob4133682008-02-18 13:05:38 +00001540int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001541
1542#endif /* !ENABLE_FEATURE_MOUNT_NFS */
1543
1544// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1545// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001546// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001547static int singlemount(struct mntent *mp, int ignore_busy)
1548{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001549 int rc = -1;
1550 long vfsflags;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001551 char *loopFile = 0, *filteropts = 0;
1552 llist_t *fl = 0;
1553 struct stat st;
1554
1555 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1556
1557 // Treat fstype "auto" as unspecified.
1558
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001559 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1560 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001561
Denis Vlasenko2535f122007-09-15 13:28:30 +00001562 // Might this be a virtual filesystem?
1563
1564 if (ENABLE_FEATURE_MOUNT_HELPERS
Denis Vlasenkoc03e8722007-12-26 20:56:55 +00001565 && (strchr(mp->mnt_fsname, '#'))
Denis Vlasenko2535f122007-09-15 13:28:30 +00001566 ) {
1567 char *s, *p, *args[35];
1568 int n = 0;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001569// FIXME: does it allow execution of arbitrary commands?!
1570// What args[0] can end up with?
Denis Vlasenko2535f122007-09-15 13:28:30 +00001571 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
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001588 && (!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]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001591 ) {
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 Vlasenkoa4522c52008-03-17 08:46:43 +00001728 char *cmdopts = xstrdup("");
1729 char *fstype = NULL;
1730 char *storage_path = NULL;
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 Vlasenkoa4522c52008-03-17 08:46:43 +00001749 argv[j] = NULL;
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 Vlasenko397de612008-03-17 08:55:44 +00001772 if (!(opt & OPT_a)) {
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 Vlasenkoa4522c52008-03-17 08:46:43 +00001900 if (fstype && match_fstype(mtcur, fstype))
1901 continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001902
1903 // Skip noauto and swap anyway.
1904
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001905 if (parse_mount_options(mtcur->mnt_opts, 0) & (MOUNT_NOAUTO | MOUNT_SWAP))
1906 continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001907
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001908 // No, mount -a won't mount anything,
1909 // even user mounts, for mere humans.
1910
1911 if (nonroot)
1912 bb_error_msg_and_die(must_be_root);
1913
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001914 // Mount this thing.
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001915 if (ENABLE_FEATURE_MOUNT_LABEL)
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001916 resolve_mount_spec(&mtpair->mnt_fsname);
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}