blob: 4cc1d4bee9a505271a5002b5dce7865a359913bc [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 Vlasenko6aa76962008-03-18 01:44:52 +000025#if ENABLE_FEATURE_MOUNT_LABEL
Denis Vlasenkode7684a2008-02-18 21:08:49 +000026#include "volume_id.h"
Denis Vlasenko6aa76962008-03-18 01:44:52 +000027#endif
Denis Vlasenkode7684a2008-02-18 21:08:49 +000028
29/* Needed for nfs support only */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +000030#include <sys/utsname.h>
31#undef TRUE
32#undef FALSE
33#include <rpc/rpc.h>
34#include <rpc/pmap_prot.h>
35#include <rpc/pmap_clnt.h>
36
Denis Vlasenko2535f122007-09-15 13:28:30 +000037#ifndef MS_SILENT
38#define MS_SILENT (1 << 15)
39#endif
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +000040/* Grab more as needed from util-linux's mount/mount_constants.h */
41#ifndef MS_DIRSYNC
42#define MS_DIRSYNC 128 /* Directory modifications are synchronous */
43#endif
44
Denis Vlasenko30a64cd2006-09-15 15:12:00 +000045
Denis Vlasenko908d6b72006-12-18 23:07:42 +000046#if defined(__dietlibc__)
47/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
48 * dietlibc-0.30 does not have implementation of getmntent_r() */
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +000049static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000050 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
Denis Vlasenko908d6b72006-12-18 23:07:42 +000051{
Denis Vlasenko908d6b72006-12-18 23:07:42 +000052 struct mntent* ment = getmntent(stream);
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +000053 return memcpy(result, ment, sizeof(*ment));
Denis Vlasenko908d6b72006-12-18 23:07:42 +000054}
55#endif
56
57
Rob Landleydc0955b2006-03-14 18:16:25 +000058// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +000059enum {
Denis Vlasenkoa4522c52008-03-17 08:46:43 +000060 MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
61 MOUNT_NOAUTO = (1 << 29),
62 MOUNT_SWAP = (1 << 30),
Denis Vlasenko13c5a682006-10-16 22:39:51 +000063};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +000064
65
66#define OPTION_STR "o:t:rwanfvsi"
67enum {
68 OPT_o = (1 << 0),
69 OPT_t = (1 << 1),
70 OPT_r = (1 << 2),
71 OPT_w = (1 << 3),
72 OPT_a = (1 << 4),
73 OPT_n = (1 << 5),
74 OPT_f = (1 << 6),
75 OPT_v = (1 << 7),
76 OPT_s = (1 << 8),
77 OPT_i = (1 << 9),
78};
79
80#if ENABLE_FEATURE_MTAB_SUPPORT
81#define useMtab (!(option_mask32 & OPT_n))
82#else
83#define useMtab 0
84#endif
85
86#if ENABLE_FEATURE_MOUNT_FAKE
87#define fakeIt (option_mask32 & OPT_f)
88#else
89#define fakeIt 0
90#endif
91
92
Denis Vlasenko13c5a682006-10-16 22:39:51 +000093// TODO: more "user" flag compatibility.
94// "user" option (from mount manpage):
95// Only the user that mounted a filesystem can unmount it again.
96// If any user should be able to unmount, then use users instead of user
97// in the fstab line. The owner option is similar to the user option,
98// with the restriction that the user must be the owner of the special file.
99// This may be useful e.g. for /dev/fd if a login script makes
100// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000101
Rob Landleydc0955b2006-03-14 18:16:25 +0000102/* Standard mount options (from -o options or --options), with corresponding
103 * flags */
Eric Andersencc8ed391999-10-05 16:24:54 +0000104
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000105static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000106 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000107
Rob Landleye3781b72006-08-08 01:39:49 +0000108 USE_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000109 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000110 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000111
Rob Landleye3781b72006-08-08 01:39:49 +0000112 USE_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000113 /* "defaults" */ 0,
114 /* "quiet" 0 - do not filter out, vfat wants to see it */
115 /* "noauto" */ MOUNT_NOAUTO,
116 /* "sw" */ MOUNT_SWAP,
117 /* "swap" */ MOUNT_SWAP,
118 USE_DESKTOP(/* "user" */ MOUNT_USERS,)
119 USE_DESKTOP(/* "users" */ MOUNT_USERS,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000120 /* "_netdev" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000121 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000122
Rob Landleye3781b72006-08-08 01:39:49 +0000123 USE_FEATURE_MOUNT_FLAGS(
124 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000125 /* "nosuid" */ MS_NOSUID,
126 /* "suid" */ ~MS_NOSUID,
127 /* "dev" */ ~MS_NODEV,
128 /* "nodev" */ MS_NODEV,
129 /* "exec" */ ~MS_NOEXEC,
130 /* "noexec" */ MS_NOEXEC,
131 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000132 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000133 /* "async" */ ~MS_SYNCHRONOUS,
134 /* "atime" */ ~MS_NOATIME,
135 /* "noatime" */ MS_NOATIME,
136 /* "diratime" */ ~MS_NODIRATIME,
137 /* "nodiratime" */ MS_NODIRATIME,
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000138 /* "mand" */ MS_MANDLOCK,
139 /* "nomand" */ ~MS_MANDLOCK,
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000140 /* "relatime" */ MS_RELATIME,
141 /* "norelatime" */ ~MS_RELATIME,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000142 /* "loud" */ ~MS_SILENT,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000143
Rob Landleye3781b72006-08-08 01:39:49 +0000144 // action flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000145 /* "bind" */ MS_BIND,
146 /* "move" */ MS_MOVE,
147 /* "shared" */ MS_SHARED,
148 /* "slave" */ MS_SLAVE,
149 /* "private" */ MS_PRIVATE,
150 /* "unbindable" */ MS_UNBINDABLE,
151 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
152 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
153 /* "rprivate" */ MS_SLAVE|MS_RECURSIVE,
154 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000155 )
156
157 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000158 /* "ro" */ MS_RDONLY, // vfs flag
159 /* "rw" */ ~MS_RDONLY, // vfs flag
160 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000161};
162
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000163static const char mount_option_str[] =
164 USE_FEATURE_MOUNT_LOOP(
165 "loop" "\0"
166 )
167 USE_FEATURE_MOUNT_FSTAB(
168 "defaults" "\0"
169 /* "quiet" "\0" - do not filter out, vfat wants to see it */
170 "noauto" "\0"
171 "sw" "\0"
172 "swap" "\0"
173 USE_DESKTOP("user" "\0")
174 USE_DESKTOP("users" "\0")
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000175 "_netdev" "\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000176 )
177 USE_FEATURE_MOUNT_FLAGS(
178 // vfs flags
179 "nosuid" "\0"
180 "suid" "\0"
181 "dev" "\0"
182 "nodev" "\0"
183 "exec" "\0"
184 "noexec" "\0"
185 "sync" "\0"
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000186 "dirsync" "\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000187 "async" "\0"
188 "atime" "\0"
189 "noatime" "\0"
190 "diratime" "\0"
191 "nodiratime" "\0"
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000192 "mand" "\0"
193 "nomand" "\0"
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000194 "relatime" "\0"
195 "norelatime" "\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000196 "loud" "\0"
197
198 // action flags
199 "bind" "\0"
200 "move" "\0"
201 "shared" "\0"
202 "slave" "\0"
203 "private" "\0"
204 "unbindable" "\0"
205 "rshared" "\0"
206 "rslave" "\0"
207 "rprivate" "\0"
208 "runbindable" "\0"
209 )
210
211 // Always understood.
212 "ro" "\0" // vfs flag
213 "rw" "\0" // vfs flag
214 "remount" "\0" // action flag
215;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000216
Denis Vlasenkof732e962008-02-18 12:07:49 +0000217
218struct globals {
219#if ENABLE_FEATURE_MOUNT_NFS
220 smalluint nfs_mount_version;
221#endif
222#if ENABLE_FEATURE_MOUNT_VERBOSE
223 unsigned verbose;
224#endif
225 llist_t *fslist;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000226 char getmntent_buf[1];
Denis Vlasenkof732e962008-02-18 12:07:49 +0000227
228};
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000229enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
Denis Vlasenkof732e962008-02-18 12:07:49 +0000230#define G (*(struct globals*)&bb_common_bufsiz1)
231#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000232#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000233#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000234#else
235#define verbose 0
236#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000237#define fslist (G.fslist )
238#define getmntent_buf (G.getmntent_buf )
239
240
241#if ENABLE_FEATURE_MOUNT_VERBOSE
242static int verbose_mount(const char *source, const char *target,
243 const char *filesystemtype,
244 unsigned long mountflags, const void *data)
245{
246 int rc;
247
248 errno = 0;
249 rc = mount(source, target, filesystemtype, mountflags, data);
250 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000251 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000252 source, target, filesystemtype,
253 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000254 return rc;
255}
256#else
257#define verbose_mount(...) mount(__VA_ARGS__)
258#endif
259
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000260static int resolve_mount_spec(char **fsname)
261{
262 char *tmp = NULL;
263
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000264#if ENABLE_FEATURE_MOUNT_LABEL
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000265 if (!strncmp(*fsname, "UUID=", 5))
266 tmp = get_devname_from_uuid(*fsname + 5);
267 else if (!strncmp(*fsname, "LABEL=", 6))
268 tmp = get_devname_from_label(*fsname + 6);
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000269#endif
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000270
271 if (tmp) {
272 *fsname = tmp;
273 return 1;
274 }
275 return 0;
276}
277
Rob Landleydc0955b2006-03-14 18:16:25 +0000278/* Append mount options to string */
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000279static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000280{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000281 if (*oldopts && **oldopts) {
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000282 /* do not insert options which are already there */
283 while (newopts[0]) {
284 char *p;
285 int len = strlen(newopts);
286 p = strchr(newopts, ',');
287 if (p) len = p - newopts;
288 p = *oldopts;
289 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000290 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000291 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000292 goto skip;
293 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000294 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000295 p++;
296 }
297 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
298 free(*oldopts);
299 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000300 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000301 newopts += len;
302 while (newopts[0] == ',') newopts++;
303 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000304 } else {
305 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000306 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000307 }
308}
309
310/* Use the mount_options list to parse options into flags.
Denis Vlasenko00d7d6c2006-09-11 17:42:44 +0000311 * Also return list of unrecognized options if unrecognized!=NULL */
Denis Vlasenkob4133682008-02-18 13:05:38 +0000312static long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000313{
Denis Vlasenkob4133682008-02-18 13:05:38 +0000314 long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000315
Rob Landley6a6798b2005-08-10 20:35:54 +0000316 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000317 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000318 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000319 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000320 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000321
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000322 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000323
Bernhard Reutner-Fischerf9a07842008-05-30 10:44:37 +0000324/* FIXME: use hasmntopt() */
Rob Landley6a6798b2005-08-10 20:35:54 +0000325 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000326 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000327 if (!strcasecmp(option_str, options)) {
328 long fl = mount_options[i];
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000329 if (fl < 0) flags &= fl;
Rob Landleydc0955b2006-03-14 18:16:25 +0000330 else flags |= fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000331 break;
332 }
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000333 option_str += strlen(option_str) + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000334 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000335 // If unrecognized not NULL, append unrecognized mount options */
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000336 if (unrecognized && i == ARRAY_SIZE(mount_options)) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000337 // Add it to strflags, to pass on to kernel
Rob Landleydc0955b2006-03-14 18:16:25 +0000338 i = *unrecognized ? strlen(*unrecognized) : 0;
Denis Vlasenkodeeed592008-07-08 05:14:36 +0000339 *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000340
Rob Landley6a6798b2005-08-10 20:35:54 +0000341 // Comma separated if it's not the first one
Rob Landleydc0955b2006-03-14 18:16:25 +0000342 if (i) (*unrecognized)[i++] = ',';
343 strcpy((*unrecognized)+i, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000344 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000345
Denis Vlasenko2535f122007-09-15 13:28:30 +0000346 if (!comma)
347 break;
348 // Advance to next option
349 *comma = ',';
350 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000351 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000352
Rob Landleydc0955b2006-03-14 18:16:25 +0000353 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000354}
355
Rob Landleydc0955b2006-03-14 18:16:25 +0000356// Return a list of all block device backed filesystems
Matt Kraai12400822001-04-17 04:32:50 +0000357
Rob Landleydc0955b2006-03-14 18:16:25 +0000358static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000359{
Denis Vlasenko87468852007-04-13 23:22:00 +0000360 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000361 "/etc/filesystems",
362 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000363 };
364 char *fs, *buf;
Rob Landleydc0955b2006-03-14 18:16:25 +0000365 llist_t *list = 0;
366 int i;
367 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000368
Denis Vlasenko87468852007-04-13 23:22:00 +0000369 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000370 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000371 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000372
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000373 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000374 if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))
375 continue;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000376 fs = skip_whitespace(buf);
Denis Vlasenko372686b2006-10-12 22:42:33 +0000377 if (*fs=='#' || *fs=='*' || !*fs) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000378
Denis Vlasenko372686b2006-10-12 22:42:33 +0000379 llist_add_to_end(&list, xstrdup(fs));
380 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000381 }
382 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
383 }
384
385 return list;
386}
387
Rob Landleydc0955b2006-03-14 18:16:25 +0000388#if ENABLE_FEATURE_CLEAN_UP
389static void delete_block_backed_filesystems(void)
390{
Rob Landleya6b5b602006-05-08 19:03:07 +0000391 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000392}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000393#else
394void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000395#endif
396
Rob Landleydc0955b2006-03-14 18:16:25 +0000397// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000398// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000399static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000400{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000401 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000402
Denis Vlasenkob4133682008-02-18 13:05:38 +0000403 if (fakeIt) {
404 if (verbose >= 2)
405 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
406 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
407 vfsflags, filteropts);
408 goto mtab;
409 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000410
Rob Landleydc0955b2006-03-14 18:16:25 +0000411 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000412 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000413 errno = 0;
414 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000415 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000416
417 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000418 // helper program mount.<mnt_type>
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000419 if (ENABLE_FEATURE_MOUNT_HELPERS && rc) {
420 char *args[6];
421 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000422 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000423 rc = 1;
424 if (filteropts) {
425 args[rc++] = (char *)"-o";
426 args[rc++] = filteropts;
427 }
428 args[rc++] = mp->mnt_fsname;
429 args[rc++] = mp->mnt_dir;
430 args[rc] = NULL;
431 rc = wait4pid(spawn(args));
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000432 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000433 if (!rc)
434 break;
435 errno = errno_save;
436 }
437
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000438 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000439 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000440 if (!(vfsflags & MS_SILENT))
441 bb_error_msg("%s is write-protected, mounting read-only",
442 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000443 vfsflags |= MS_RDONLY;
444 }
445
Rob Landleydc0955b2006-03-14 18:16:25 +0000446 // Abort entirely if permission denied.
447
448 if (rc && errno == EPERM)
449 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
450
451 /* If the mount was successful, and we're maintaining an old-style
452 * mtab file by hand, add the new entry to it now. */
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000453 mtab:
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000454 if (useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000455 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000456 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000457 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000458 int i;
459
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000460 if (!mountTable) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000461 bb_error_msg("no %s", bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000462 goto ret;
463 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000464
465 // Add vfs string flags
466
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000467 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
468 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
469 append_mount_options(&(mp->mnt_opts), option_str);
470 option_str += strlen(option_str) + 1;
471 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000472
473 // Remove trailing / (if any) from directory we mounted on
474
Denis Vlasenko727ef942006-09-14 13:19:19 +0000475 i = strlen(mp->mnt_dir) - 1;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000476 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000477
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000478 // Convert to canonical pathnames as needed
Denis Vlasenko727ef942006-09-14 13:19:19 +0000479
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000480 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000481 fsname = 0;
Denis Vlasenko727ef942006-09-14 13:19:19 +0000482 if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000483 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000484 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000485 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000486 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000487
488 // Write and close.
489
Denis Vlasenko727ef942006-09-14 13:19:19 +0000490 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000491 endmntent(mountTable);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000492 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000493 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000494 free(fsname);
495 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000496 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000497 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000498 return rc;
499}
500
Denis Vlasenko25098f72006-09-14 15:46:33 +0000501#if ENABLE_FEATURE_MOUNT_NFS
502
503/*
504 * Linux NFS mount
505 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
506 *
507 * Licensed under GPLv2, see file LICENSE in this tarball for details.
508 *
509 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
510 * numbers to be specified on the command line.
511 *
512 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
513 * Omit the call to connect() for Linux version 1.3.11 or later.
514 *
515 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
516 * Implemented the "bg", "fg" and "retry" mount options for NFS.
517 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000518 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000519 * - added Native Language Support
520 *
521 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
522 * plus NFSv3 stuff.
523 */
524
Denis Vlasenko25098f72006-09-14 15:46:33 +0000525/* This is just a warning of a common mistake. Possibly this should be a
526 * uclibc faq entry rather than in busybox... */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000527#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000528#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
529#endif
530
531#define MOUNTPORT 635
532#define MNTPATHLEN 1024
533#define MNTNAMLEN 255
534#define FHSIZE 32
535#define FHSIZE3 64
536
537typedef char fhandle[FHSIZE];
538
539typedef struct {
540 unsigned int fhandle3_len;
541 char *fhandle3_val;
542} fhandle3;
543
544enum mountstat3 {
545 MNT_OK = 0,
546 MNT3ERR_PERM = 1,
547 MNT3ERR_NOENT = 2,
548 MNT3ERR_IO = 5,
549 MNT3ERR_ACCES = 13,
550 MNT3ERR_NOTDIR = 20,
551 MNT3ERR_INVAL = 22,
552 MNT3ERR_NAMETOOLONG = 63,
553 MNT3ERR_NOTSUPP = 10004,
554 MNT3ERR_SERVERFAULT = 10006,
555};
556typedef enum mountstat3 mountstat3;
557
558struct fhstatus {
559 unsigned int fhs_status;
560 union {
561 fhandle fhs_fhandle;
562 } fhstatus_u;
563};
564typedef struct fhstatus fhstatus;
565
566struct mountres3_ok {
567 fhandle3 fhandle;
568 struct {
569 unsigned int auth_flavours_len;
570 char *auth_flavours_val;
571 } auth_flavours;
572};
573typedef struct mountres3_ok mountres3_ok;
574
575struct mountres3 {
576 mountstat3 fhs_status;
577 union {
578 mountres3_ok mountinfo;
579 } mountres3_u;
580};
581typedef struct mountres3 mountres3;
582
583typedef char *dirpath;
584
585typedef char *name;
586
587typedef struct mountbody *mountlist;
588
589struct mountbody {
590 name ml_hostname;
591 dirpath ml_directory;
592 mountlist ml_next;
593};
594typedef struct mountbody mountbody;
595
596typedef struct groupnode *groups;
597
598struct groupnode {
599 name gr_name;
600 groups gr_next;
601};
602typedef struct groupnode groupnode;
603
604typedef struct exportnode *exports;
605
606struct exportnode {
607 dirpath ex_dir;
608 groups ex_groups;
609 exports ex_next;
610};
611typedef struct exportnode exportnode;
612
613struct ppathcnf {
614 int pc_link_max;
615 short pc_max_canon;
616 short pc_max_input;
617 short pc_name_max;
618 short pc_path_max;
619 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000620 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000621 char pc_xxx;
622 short pc_mask[2];
623};
624typedef struct ppathcnf ppathcnf;
625
626#define MOUNTPROG 100005
627#define MOUNTVERS 1
628
629#define MOUNTPROC_NULL 0
630#define MOUNTPROC_MNT 1
631#define MOUNTPROC_DUMP 2
632#define MOUNTPROC_UMNT 3
633#define MOUNTPROC_UMNTALL 4
634#define MOUNTPROC_EXPORT 5
635#define MOUNTPROC_EXPORTALL 6
636
637#define MOUNTVERS_POSIX 2
638
639#define MOUNTPROC_PATHCONF 7
640
641#define MOUNT_V3 3
642
643#define MOUNTPROC3_NULL 0
644#define MOUNTPROC3_MNT 1
645#define MOUNTPROC3_DUMP 2
646#define MOUNTPROC3_UMNT 3
647#define MOUNTPROC3_UMNTALL 4
648#define MOUNTPROC3_EXPORT 5
649
650enum {
651#ifndef NFS_FHSIZE
652 NFS_FHSIZE = 32,
653#endif
654#ifndef NFS_PORT
655 NFS_PORT = 2049
656#endif
657};
658
Denis Vlasenko25098f72006-09-14 15:46:33 +0000659/*
660 * We want to be able to compile mount on old kernels in such a way
661 * that the binary will work well on more recent kernels.
662 * Thus, if necessary we teach nfsmount.c the structure of new fields
663 * that will come later.
664 *
665 * Moreover, the new kernel includes conflict with glibc includes
666 * so it is easiest to ignore the kernel altogether (at compile time).
667 */
668
669struct nfs2_fh {
670 char data[32];
671};
672struct nfs3_fh {
673 unsigned short size;
674 unsigned char data[64];
675};
676
677struct nfs_mount_data {
678 int version; /* 1 */
679 int fd; /* 1 */
680 struct nfs2_fh old_root; /* 1 */
681 int flags; /* 1 */
682 int rsize; /* 1 */
683 int wsize; /* 1 */
684 int timeo; /* 1 */
685 int retrans; /* 1 */
686 int acregmin; /* 1 */
687 int acregmax; /* 1 */
688 int acdirmin; /* 1 */
689 int acdirmax; /* 1 */
690 struct sockaddr_in addr; /* 1 */
691 char hostname[256]; /* 1 */
692 int namlen; /* 2 */
693 unsigned int bsize; /* 3 */
694 struct nfs3_fh root; /* 4 */
695};
696
697/* bits in the flags field */
698enum {
699 NFS_MOUNT_SOFT = 0x0001, /* 1 */
700 NFS_MOUNT_INTR = 0x0002, /* 1 */
701 NFS_MOUNT_SECURE = 0x0004, /* 1 */
702 NFS_MOUNT_POSIX = 0x0008, /* 1 */
703 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
704 NFS_MOUNT_NOAC = 0x0020, /* 1 */
705 NFS_MOUNT_TCP = 0x0040, /* 2 */
706 NFS_MOUNT_VER3 = 0x0080, /* 3 */
707 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000708 NFS_MOUNT_NONLM = 0x0200, /* 3 */
709 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +0000710};
711
712
713/*
714 * We need to translate between nfs status return values and
715 * the local errno values which may not be the same.
716 *
717 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
718 * "after #include <errno.h> the symbol errno is reserved for any use,
719 * it cannot even be used as a struct tag or field name".
720 */
721
722#ifndef EDQUOT
723#define EDQUOT ENOSPC
724#endif
725
726// Convert each NFSERR_BLAH into EBLAH
727
728static const struct {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000729 short stat;
730 short errnum;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000731} nfs_errtbl[] = {
732 {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
733 {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
734 {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
735 {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
736};
737
738static char *nfs_strerror(int status)
739{
740 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000741
742 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
743 if (nfs_errtbl[i].stat == status)
744 return strerror(nfs_errtbl[i].errnum);
745 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000746 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000747}
748
749static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
750{
751 if (!xdr_opaque(xdrs, objp, FHSIZE))
752 return FALSE;
753 return TRUE;
754}
755
756static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
757{
758 if (!xdr_u_int(xdrs, &objp->fhs_status))
759 return FALSE;
760 switch (objp->fhs_status) {
761 case 0:
762 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
763 return FALSE;
764 break;
765 default:
766 break;
767 }
768 return TRUE;
769}
770
771static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
772{
773 if (!xdr_string(xdrs, objp, MNTPATHLEN))
774 return FALSE;
775 return TRUE;
776}
777
778static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
779{
780 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
781 return FALSE;
782 return TRUE;
783}
784
785static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
786{
787 if (!xdr_fhandle3(xdrs, &objp->fhandle))
788 return FALSE;
789 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
790 sizeof (int), (xdrproc_t) xdr_int))
791 return FALSE;
792 return TRUE;
793}
794
795static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
796{
797 if (!xdr_enum(xdrs, (enum_t *) objp))
798 return FALSE;
799 return TRUE;
800}
801
802static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
803{
804 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
805 return FALSE;
806 switch (objp->fhs_status) {
807 case MNT_OK:
808 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
809 return FALSE;
810 break;
811 default:
812 break;
813 }
814 return TRUE;
815}
816
817#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
818
Denis Vlasenko25098f72006-09-14 15:46:33 +0000819/*
820 * Unfortunately, the kernel prints annoying console messages
821 * in case of an unexpected nfs mount version (instead of
822 * just returning some error). Therefore we'll have to try
823 * and figure out what version the kernel expects.
824 *
825 * Variables:
826 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
827 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
828 * nfs_mount_version: version this source and running kernel can handle
829 */
830static void
831find_kernel_nfs_mount_version(void)
832{
Denis Vlasenkob9256052007-09-28 10:29:17 +0000833 int kernel_version;
834
835 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000836 return;
837
838 nfs_mount_version = 4; /* default */
839
840 kernel_version = get_linux_version_code();
841 if (kernel_version) {
842 if (kernel_version < KERNEL_VERSION(2,1,32))
843 nfs_mount_version = 1;
844 else if (kernel_version < KERNEL_VERSION(2,2,18) ||
845 (kernel_version >= KERNEL_VERSION(2,3,0) &&
846 kernel_version < KERNEL_VERSION(2,3,99)))
847 nfs_mount_version = 3;
848 /* else v4 since 2.3.99pre4 */
849 }
850}
851
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000852static void
Denis Vlasenkob9256052007-09-28 10:29:17 +0000853get_mountport(struct pmap *pm_mnt,
854 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +0000855 long unsigned prog,
856 long unsigned version,
857 long unsigned proto,
858 long unsigned port)
859{
860 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000861
862 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +0000863/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
864 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000865 pmap = pmap_getmaps(server_addr);
866
867 if (version > MAX_NFSPROT)
868 version = MAX_NFSPROT;
869 if (!prog)
870 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000871 pm_mnt->pm_prog = prog;
872 pm_mnt->pm_vers = version;
873 pm_mnt->pm_prot = proto;
874 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000875
Denis Vlasenko25098f72006-09-14 15:46:33 +0000876 while (pmap) {
877 if (pmap->pml_map.pm_prog != prog)
878 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000879 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000880 goto next;
881 if (version > 2 && pmap->pml_map.pm_vers != version)
882 goto next;
883 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
884 goto next;
885 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
Denis Vlasenkob9256052007-09-28 10:29:17 +0000886 (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
Denis Vlasenko25098f72006-09-14 15:46:33 +0000887 (port && pmap->pml_map.pm_port != port))
888 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000889 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
890 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +0000891 pmap = pmap->pml_next;
892 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000893 if (!pm_mnt->pm_vers)
894 pm_mnt->pm_vers = MOUNTVERS;
895 if (!pm_mnt->pm_port)
896 pm_mnt->pm_port = MOUNTPORT;
897 if (!pm_mnt->pm_prot)
898 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000899}
900
Denis Vlasenkof0000652007-09-04 18:30:26 +0000901#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +0000902static int daemonize(void)
903{
Denis Vlasenko25098f72006-09-14 15:46:33 +0000904 int pid = fork();
905 if (pid < 0) /* error */
906 return -errno;
907 if (pid > 0) /* parent */
908 return 0;
909 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000910 close(0);
911 xopen(bb_dev_null, O_RDWR);
912 xdup2(0, 1);
913 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000914 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000915 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000916 logmode = LOGMODE_SYSLOG;
917 return 1;
918}
Denis Vlasenkof0000652007-09-04 18:30:26 +0000919#else
920static inline int daemonize(void) { return -ENOSYS; }
921#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000922
923// TODO
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000924static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000925{
926 return 0;
927}
928
929/* RPC strerror analogs are terminally idiotic:
930 * *mandatory* prefix and \n at end.
931 * This hopefully helps. Usage:
932 * error_msg_rpc(clnt_*error*(" ")) */
933static void error_msg_rpc(const char *msg)
934{
Denis Vlasenko23514fe2006-09-19 14:07:52 +0000935 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000936 while (msg[0] == ' ' || msg[0] == ':') msg++;
937 len = strlen(msg);
938 while (len && msg[len-1] == '\n') len--;
939 bb_error_msg("%.*s", len, msg);
940}
941
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +0000942// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000943static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000944{
945 CLIENT *mclient;
946 char *hostname;
947 char *pathname;
948 char *mounthost;
949 struct nfs_mount_data data;
950 char *opt;
951 struct hostent *hp;
952 struct sockaddr_in server_addr;
953 struct sockaddr_in mount_server_addr;
954 int msock, fsock;
955 union {
956 struct fhstatus nfsv2;
957 struct mountres3 nfsv3;
958 } status;
959 int daemonized;
960 char *s;
961 int port;
962 int mountport;
963 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000964#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000965 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000966#else
967 enum { bg = 0 };
968#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000969 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000970 int mountprog;
971 int mountvers;
972 int nfsprog;
973 int nfsvers;
974 int retval;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000975 /* these all are one-bit really. 4.3.1 likes this combination: */
976 smallint tcp;
977 smallint soft;
978 int intr;
979 int posix;
980 int nocto;
981 int noac;
982 int nordirplus;
983 int nolock;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000984
985 find_kernel_nfs_mount_version();
986
987 daemonized = 0;
988 mounthost = NULL;
989 retval = ETIMEDOUT;
990 msock = fsock = -1;
991 mclient = NULL;
992
993 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
994
995 filteropts = xstrdup(filteropts); /* going to trash it later... */
996
997 hostname = xstrdup(mp->mnt_fsname);
998 /* mount_main() guarantees that ':' is there */
999 s = strchr(hostname, ':');
1000 pathname = s + 1;
1001 *s = '\0';
1002 /* Ignore all but first hostname in replicated mounts
1003 until they can be fully supported. (mack@sgi.com) */
1004 s = strchr(hostname, ',');
1005 if (s) {
1006 *s = '\0';
1007 bb_error_msg("warning: multiple hostnames not supported");
1008 }
1009
1010 server_addr.sin_family = AF_INET;
1011 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1012 hp = gethostbyname(hostname);
1013 if (hp == NULL) {
1014 bb_herror_msg("%s", hostname);
1015 goto fail;
1016 }
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001017 if ((size_t)hp->h_length > sizeof(struct in_addr)) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001018 bb_error_msg("got bad hp->h_length");
1019 hp->h_length = sizeof(struct in_addr);
1020 }
1021 memcpy(&server_addr.sin_addr,
1022 hp->h_addr, hp->h_length);
1023 }
1024
1025 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1026
1027 /* add IP address to mtab options for use when unmounting */
1028
1029 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1030 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1031 } else {
1032 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1033 mp->mnt_opts[0] ? "," : "",
1034 inet_ntoa(server_addr.sin_addr));
1035 free(mp->mnt_opts);
1036 mp->mnt_opts = tmp;
1037 }
1038
1039 /* Set default options.
1040 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1041 * let the kernel decide.
1042 * timeo is filled in after we know whether it'll be TCP or UDP. */
1043 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001044 data.retrans = 3;
1045 data.acregmin = 3;
1046 data.acregmax = 60;
1047 data.acdirmin = 30;
1048 data.acdirmax = 60;
1049 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001050
Denis Vlasenko25098f72006-09-14 15:46:33 +00001051 soft = 0;
1052 intr = 0;
1053 posix = 0;
1054 nocto = 0;
1055 nolock = 0;
1056 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001057 nordirplus = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001058 retry = 10000; /* 10000 minutes ~ 1 week */
1059 tcp = 0;
1060
1061 mountprog = MOUNTPROG;
1062 mountvers = 0;
1063 port = 0;
1064 mountport = 0;
1065 nfsprog = 100003;
1066 nfsvers = 0;
1067
1068 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001069 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001070 char *opteq = strchr(opt, '=');
1071 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001072 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001073 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001074 /* 0 */ "rsize\0"
1075 /* 1 */ "wsize\0"
1076 /* 2 */ "timeo\0"
1077 /* 3 */ "retrans\0"
1078 /* 4 */ "acregmin\0"
1079 /* 5 */ "acregmax\0"
1080 /* 6 */ "acdirmin\0"
1081 /* 7 */ "acdirmax\0"
1082 /* 8 */ "actimeo\0"
1083 /* 9 */ "retry\0"
1084 /* 10 */ "port\0"
1085 /* 11 */ "mountport\0"
1086 /* 12 */ "mounthost\0"
1087 /* 13 */ "mountprog\0"
1088 /* 14 */ "mountvers\0"
1089 /* 15 */ "nfsprog\0"
1090 /* 16 */ "nfsvers\0"
1091 /* 17 */ "vers\0"
1092 /* 18 */ "proto\0"
1093 /* 19 */ "namlen\0"
1094 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001095
1096 *opteq++ = '\0';
1097 idx = index_in_strings(options, opt);
1098 switch (idx) {
1099 case 12: // "mounthost"
1100 mounthost = xstrndup(opteq,
1101 strcspn(opteq, " \t\n\r,"));
1102 continue;
1103 case 18: // "proto"
1104 if (!strncmp(opteq, "tcp", 3))
1105 tcp = 1;
1106 else if (!strncmp(opteq, "udp", 3))
1107 tcp = 0;
1108 else
1109 bb_error_msg("warning: unrecognized proto= option");
1110 continue;
1111 case 20: // "addr" - ignore
1112 continue;
1113 }
1114
1115 val = xatoi_u(opteq);
1116 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001117 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001118 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001119 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001120 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001121 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001122 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001123 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001124 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001125 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001126 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001127 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001128 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001129 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001130 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001131 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001132 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001133 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001134 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001135 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001136 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001137 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001138 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001139 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001140 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001141 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001142 data.acregmin = val;
1143 data.acregmax = val;
1144 data.acdirmin = val;
1145 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001146 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001147 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001148 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001149 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001150 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001151 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001152 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001153 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001154 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001155 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001156 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001157 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001158 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001159 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001160 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001161 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001162 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001163 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001164 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001165 case 16: // "nfsvers"
1166 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001167 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001168 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001169 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001170 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001171 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001172 //else
1173 // bb_error_msg("warning: option namlen is not supported\n");
1174 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001175 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001176 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1177 goto fail;
1178 }
1179 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001180 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001181 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001182 "bg\0"
1183 "fg\0"
1184 "soft\0"
1185 "hard\0"
1186 "intr\0"
1187 "posix\0"
1188 "cto\0"
1189 "ac\0"
1190 "tcp\0"
1191 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001192 "lock\0"
1193 "rdirplus\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001194 int val = 1;
1195 if (!strncmp(opt, "no", 2)) {
1196 val = 0;
1197 opt += 2;
1198 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001199 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001200 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001201#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001202 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001203#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001204 break;
1205 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001206#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001207 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001208#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001209 break;
1210 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001211 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001212 break;
1213 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001214 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001215 break;
1216 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001217 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001218 break;
1219 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001220 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001221 break;
1222 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001223 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001224 break;
1225 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001226 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001227 break;
1228 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001229 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001230 break;
1231 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001232 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001233 break;
1234 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001235 if (nfs_mount_version >= 3)
1236 nolock = !val;
1237 else
1238 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001239 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001240 case 11: //rdirplus
1241 nordirplus = !val;
1242 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001243 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001244 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1245 goto fail;
1246 }
1247 }
1248 }
1249 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1250
1251 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1252 | (intr ? NFS_MOUNT_INTR : 0)
1253 | (posix ? NFS_MOUNT_POSIX : 0)
1254 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001255 | (noac ? NFS_MOUNT_NOAC : 0)
1256 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001257 if (nfs_mount_version >= 2)
1258 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1259 if (nfs_mount_version >= 3)
1260 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1261 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1262 bb_error_msg("NFSv%d not supported", nfsvers);
1263 goto fail;
1264 }
1265 if (nfsvers && !mountvers)
1266 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1267 if (nfsvers && nfsvers < mountvers) {
1268 mountvers = nfsvers;
1269 }
1270
1271 /* Adjust options if none specified */
1272 if (!data.timeo)
1273 data.timeo = tcp ? 70 : 7;
1274
Denis Vlasenko25098f72006-09-14 15:46:33 +00001275 data.version = nfs_mount_version;
1276
1277 if (vfsflags & MS_REMOUNT)
1278 goto do_mount;
1279
1280 /*
1281 * If the previous mount operation on the same host was
1282 * backgrounded, and the "bg" for this mount is also set,
1283 * give up immediately, to avoid the initial timeout.
1284 */
1285 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001286 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001287 if (daemonized <= 0) { /* parent or error */
1288 retval = -daemonized;
1289 goto ret;
1290 }
1291 }
1292
1293 /* create mount daemon client */
1294 /* See if the nfs host = mount host. */
1295 if (mounthost) {
1296 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1297 mount_server_addr.sin_family = AF_INET;
1298 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1299 } else {
1300 hp = gethostbyname(mounthost);
1301 if (hp == NULL) {
1302 bb_herror_msg("%s", mounthost);
1303 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001304 }
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001305 if ((size_t)hp->h_length > sizeof(struct in_addr)) {
1306 bb_error_msg("got bad hp->h_length");
1307 hp->h_length = sizeof(struct in_addr);
1308 }
1309 mount_server_addr.sin_family = AF_INET;
1310 memcpy(&mount_server_addr.sin_addr,
1311 hp->h_addr, hp->h_length);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001312 }
1313 }
1314
1315 /*
1316 * The following loop implements the mount retries. When the mount
1317 * times out, and the "bg" option is set, we background ourself
1318 * and continue trying.
1319 *
1320 * The case where the mount point is not present and the "bg"
1321 * option is set, is treated as a timeout. This is done to
1322 * support nested mounts.
1323 *
1324 * The "retry" count specified by the user is the number of
1325 * minutes to retry before giving up.
1326 */
1327 {
1328 struct timeval total_timeout;
1329 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001330 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001331 time_t t;
1332 time_t prevt;
1333 time_t timeout;
1334
1335 retry_timeout.tv_sec = 3;
1336 retry_timeout.tv_usec = 0;
1337 total_timeout.tv_sec = 20;
1338 total_timeout.tv_usec = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001339//FIXME: use monotonic()?
Denis Vlasenko25098f72006-09-14 15:46:33 +00001340 timeout = time(NULL) + 60 * retry;
1341 prevt = 0;
1342 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001343 retry:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001344 /* be careful not to use too many CPU cycles */
1345 if (t - prevt < 30)
1346 sleep(30);
1347
Denis Vlasenkob9256052007-09-28 10:29:17 +00001348 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001349 mountprog,
1350 mountvers,
1351 proto,
1352 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001353 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001354
1355 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001356 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001357 msock = RPC_ANYSOCK;
1358
Denis Vlasenkob9256052007-09-28 10:29:17 +00001359 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001360 case IPPROTO_UDP:
1361 mclient = clntudp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001362 pm_mnt.pm_prog,
1363 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001364 retry_timeout,
1365 &msock);
1366 if (mclient)
1367 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001368 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001369 msock = RPC_ANYSOCK;
1370 case IPPROTO_TCP:
1371 mclient = clnttcp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001372 pm_mnt.pm_prog,
1373 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001374 &msock, 0, 0);
1375 break;
1376 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001377 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001378 }
1379 if (!mclient) {
1380 if (!daemonized && prevt == 0)
1381 error_msg_rpc(clnt_spcreateerror(" "));
1382 } else {
1383 enum clnt_stat clnt_stat;
1384 /* try to mount hostname:pathname */
1385 mclient->cl_auth = authunix_create_default();
1386
1387 /* make pointers in xdr_mountres3 NULL so
1388 * that xdr_array allocates memory for us
1389 */
1390 memset(&status, 0, sizeof(status));
1391
Denis Vlasenkob9256052007-09-28 10:29:17 +00001392 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001393 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1394 (xdrproc_t) xdr_dirpath,
1395 (caddr_t) &pathname,
1396 (xdrproc_t) xdr_mountres3,
1397 (caddr_t) &status,
1398 total_timeout);
1399 else
1400 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1401 (xdrproc_t) xdr_dirpath,
1402 (caddr_t) &pathname,
1403 (xdrproc_t) xdr_fhstatus,
1404 (caddr_t) &status,
1405 total_timeout);
1406
1407 if (clnt_stat == RPC_SUCCESS)
1408 goto prepare_kernel_data; /* we're done */
1409 if (errno != ECONNREFUSED) {
1410 error_msg_rpc(clnt_sperror(mclient, " "));
1411 goto fail; /* don't retry */
1412 }
1413 /* Connection refused */
1414 if (!daemonized && prevt == 0) /* print just once */
1415 error_msg_rpc(clnt_sperror(mclient, " "));
1416 auth_destroy(mclient->cl_auth);
1417 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001418 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001419 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001420 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001421 }
1422
1423 /* Timeout. We are going to retry... maybe */
1424
1425 if (!bg)
1426 goto fail;
1427 if (!daemonized) {
1428 daemonized = daemonize();
1429 if (daemonized <= 0) { /* parent or error */
1430 retval = -daemonized;
1431 goto ret;
1432 }
1433 }
1434 prevt = t;
1435 t = time(NULL);
1436 if (t >= timeout)
1437 /* TODO error message */
1438 goto fail;
1439
1440 goto retry;
1441 }
1442
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001443 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001444
1445 if (nfsvers == 2) {
1446 if (status.nfsv2.fhs_status != 0) {
1447 bb_error_msg("%s:%s failed, reason given by server: %s",
1448 hostname, pathname,
1449 nfs_strerror(status.nfsv2.fhs_status));
1450 goto fail;
1451 }
1452 memcpy(data.root.data,
1453 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1454 NFS_FHSIZE);
1455 data.root.size = NFS_FHSIZE;
1456 memcpy(data.old_root.data,
1457 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1458 NFS_FHSIZE);
1459 } else {
1460 fhandle3 *my_fhandle;
1461 if (status.nfsv3.fhs_status != 0) {
1462 bb_error_msg("%s:%s failed, reason given by server: %s",
1463 hostname, pathname,
1464 nfs_strerror(status.nfsv3.fhs_status));
1465 goto fail;
1466 }
1467 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1468 memset(data.old_root.data, 0, NFS_FHSIZE);
1469 memset(&data.root, 0, sizeof(data.root));
1470 data.root.size = my_fhandle->fhandle3_len;
1471 memcpy(data.root.data,
1472 (char *) my_fhandle->fhandle3_val,
1473 my_fhandle->fhandle3_len);
1474
1475 data.flags |= NFS_MOUNT_VER3;
1476 }
1477
1478 /* create nfs socket for kernel */
1479
1480 if (tcp) {
1481 if (nfs_mount_version < 3) {
1482 bb_error_msg("NFS over TCP is not supported");
1483 goto fail;
1484 }
1485 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1486 } else
1487 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1488 if (fsock < 0) {
1489 bb_perror_msg("nfs socket");
1490 goto fail;
1491 }
1492 if (bindresvport(fsock, 0) < 0) {
1493 bb_perror_msg("nfs bindresvport");
1494 goto fail;
1495 }
1496 if (port == 0) {
1497 server_addr.sin_port = PMAPPORT;
1498 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1499 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1500 if (port == 0)
1501 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001502 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001503 server_addr.sin_port = htons(port);
1504
1505 /* prepare data structure for kernel */
1506
1507 data.fd = fsock;
1508 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1509 strncpy(data.hostname, hostname, sizeof(data.hostname));
1510
1511 /* clean up */
1512
1513 auth_destroy(mclient->cl_auth);
1514 clnt_destroy(mclient);
1515 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001516 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001517
1518 if (bg) {
1519 /* We must wait until mount directory is available */
1520 struct stat statbuf;
1521 int delay = 1;
1522 while (stat(mp->mnt_dir, &statbuf) == -1) {
1523 if (!daemonized) {
1524 daemonized = daemonize();
1525 if (daemonized <= 0) { /* parent or error */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001526// FIXME: parent doesn't close fsock - ??!
Denis Vlasenko25098f72006-09-14 15:46:33 +00001527 retval = -daemonized;
1528 goto ret;
1529 }
1530 }
1531 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1532 delay *= 2;
1533 if (delay > 30)
1534 delay = 30;
1535 }
1536 }
1537
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001538 do_mount: /* perform actual mount */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001539
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001540 mp->mnt_type = (char*)"nfs";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001541 retval = mount_it_now(mp, vfsflags, (char*)&data);
1542 goto ret;
1543
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001544 fail: /* abort */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001545
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001546 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001547 if (mclient) {
1548 auth_destroy(mclient->cl_auth);
1549 clnt_destroy(mclient);
1550 }
1551 close(msock);
1552 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001553 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001554 close(fsock);
1555
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001556 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001557 free(hostname);
1558 free(mounthost);
1559 free(filteropts);
1560 return retval;
1561}
1562
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001563#else /* !ENABLE_FEATURE_MOUNT_NFS */
1564
1565/* Never called. Call should be optimized out. */
Denis Vlasenkob4133682008-02-18 13:05:38 +00001566int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001567
1568#endif /* !ENABLE_FEATURE_MOUNT_NFS */
1569
1570// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1571// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001572// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001573static int singlemount(struct mntent *mp, int ignore_busy)
1574{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001575 int rc = -1;
1576 long vfsflags;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001577 char *loopFile = 0, *filteropts = 0;
1578 llist_t *fl = 0;
1579 struct stat st;
1580
1581 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1582
1583 // Treat fstype "auto" as unspecified.
1584
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001585 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1586 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001587
Denis Vlasenko2535f122007-09-15 13:28:30 +00001588 // Might this be a virtual filesystem?
1589
1590 if (ENABLE_FEATURE_MOUNT_HELPERS
Denis Vlasenkoc03e8722007-12-26 20:56:55 +00001591 && (strchr(mp->mnt_fsname, '#'))
Denis Vlasenko2535f122007-09-15 13:28:30 +00001592 ) {
1593 char *s, *p, *args[35];
1594 int n = 0;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001595// FIXME: does it allow execution of arbitrary commands?!
1596// What args[0] can end up with?
Denis Vlasenko2535f122007-09-15 13:28:30 +00001597 for (s = p = mp->mnt_fsname; *s && n < 35-3; ++s) {
1598 if (s[0] == '#' && s[1] != '#') {
1599 *s = '\0';
1600 args[n++] = p;
1601 p = s + 1;
1602 }
1603 }
1604 args[n++] = p;
1605 args[n++] = mp->mnt_dir;
1606 args[n] = NULL;
1607 rc = wait4pid(xspawn(args));
1608 goto report_error;
1609 }
1610
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001611 // Might this be an CIFS filesystem?
1612
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001613 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001614 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1615 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1616 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001617 ) {
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001618 len_and_sockaddr *lsa;
1619 char *ip, *dotted;
1620 char *s;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001621
1622 rc = 1;
1623 // Replace '/' with '\' and verify that unc points to "//server/share".
1624
1625 for (s = mp->mnt_fsname; *s; ++s)
1626 if (*s == '/') *s = '\\';
1627
1628 // get server IP
1629
1630 s = strrchr(mp->mnt_fsname, '\\');
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001631 if (s <= mp->mnt_fsname+1) goto report_error;
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001632 *s = '\0';
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001633 lsa = host2sockaddr(mp->mnt_fsname+2, 0);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001634 *s = '\\';
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001635 if (!lsa) goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001636
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001637 // insert ip=... option into string flags.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001638
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001639 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001640 ip = xasprintf("ip=%s", dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001641 parse_mount_options(ip, &filteropts);
1642
1643 // compose new unc '\\server-ip\share'
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001644 // (s => slash after hostname)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001645
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001646 mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001647
1648 // lock is required
1649 vfsflags |= MS_MANDLOCK;
1650
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001651 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001652 rc = mount_it_now(mp, vfsflags, filteropts);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001653 if (ENABLE_FEATURE_CLEAN_UP) {
1654 free(mp->mnt_fsname);
1655 free(ip);
1656 free(dotted);
1657 free(lsa);
1658 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001659 goto report_error;
1660 }
1661
1662 // Might this be an NFS filesystem?
1663
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001664 if (ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001665 && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001666 && strchr(mp->mnt_fsname, ':') != NULL
1667 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001668 rc = nfsmount(mp, vfsflags, filteropts);
1669 goto report_error;
1670 }
1671
1672 // Look at the file. (Not found isn't a failure for remount, or for
1673 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001674 // (We use stat, not lstat, in order to allow
1675 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001676
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001677 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001678 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1679 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001680 // Do we need to allocate a loopback device for it?
1681
1682 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1683 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001684 mp->mnt_fsname = NULL; /* will receive malloced loop dev name */
1685 if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) {
1686 if (errno == EPERM || errno == EACCES)
1687 bb_error_msg(bb_msg_perm_denied_are_you_root);
1688 else
1689 bb_perror_msg("cannot setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00001690 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001691 }
1692
1693 // Autodetect bind mounts
1694
1695 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1696 vfsflags |= MS_BIND;
1697 }
1698
1699 /* If we know the fstype (or don't need to), jump straight
1700 * to the actual mount. */
1701
1702 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1703 rc = mount_it_now(mp, vfsflags, filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001704 else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001705 // Loop through filesystem types until mount succeeds
1706 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001707
1708 /* Initialize list of block backed filesystems. This has to be
1709 * done here so that during "mount -a", mounts after /proc shows up
1710 * can autodetect. */
1711
1712 if (!fslist) {
1713 fslist = get_block_backed_filesystems();
1714 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1715 atexit(delete_block_backed_filesystems);
1716 }
1717
1718 for (fl = fslist; fl; fl = fl->link) {
1719 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00001720 rc = mount_it_now(mp, vfsflags, filteropts);
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001721 if (!rc) break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001722 }
1723 }
1724
1725 // If mount failed, clean up loop file (if any).
1726
1727 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1728 del_loop(mp->mnt_fsname);
1729 if (ENABLE_FEATURE_CLEAN_UP) {
1730 free(loopFile);
1731 free(mp->mnt_fsname);
1732 }
1733 }
1734
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001735 report_error:
1736 if (ENABLE_FEATURE_CLEAN_UP)
1737 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001738
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00001739 if (errno == EBUSY && ignore_busy)
1740 return 0;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001741 if (rc < 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001742 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001743 return rc;
1744}
1745
1746// Parse options, if necessary parse fstab/mtab, and call singlemount for
1747// each directory to be mounted.
1748
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001749static const char must_be_root[] ALIGN1 = "you must be root";
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001750
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001751int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001752int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001753{
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001754 char *cmdopts = xstrdup("");
1755 char *fstype = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001756 char *storage_path;
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001757 char *opt_o;
1758 const char *fstabname;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001759 FILE *fstab;
Denis Vlasenko9c99b622006-09-17 15:05:31 +00001760 int i, j, rc = 0;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001761 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001762 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001763 SKIP_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001764
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001765 USE_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00001766
Denis Vlasenkof732e962008-02-18 12:07:49 +00001767 // Parse long options, like --bind and --move. Note that -o option
1768 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001769 for (i = j = 1; argv[i]; i++) {
1770 if (argv[i][0] == '-' && argv[i][1] == '-')
1771 append_mount_options(&cmdopts, argv[i] + 2);
1772 else
1773 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001774 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001775 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001776
1777 // Parse remaining options
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001778 // Max 2 params; -v is a counter
1779 opt_complementary = "?2" USE_FEATURE_MOUNT_VERBOSE(":vv");
Denis Vlasenkof732e962008-02-18 12:07:49 +00001780 opt = getopt32(argv, OPTION_STR, &opt_o, &fstype
1781 USE_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00001782 if (opt & OPT_o) append_mount_options(&cmdopts, opt_o); // -o
1783 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1784 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001785 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001786
1787 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001788 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00001789 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001790 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1791
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001792 if (!mountTable)
1793 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001794
Denis Vlasenko2535f122007-09-15 13:28:30 +00001795 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001796 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001797 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001798 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00001799 // util-linux 2.12a happily shows rootfs...
1800 //if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001801
1802 if (!fstype || !strcmp(mtpair->mnt_type, fstype))
1803 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1804 mtpair->mnt_dir, mtpair->mnt_type,
1805 mtpair->mnt_opts);
1806 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001807 if (ENABLE_FEATURE_CLEAN_UP)
1808 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001809 return EXIT_SUCCESS;
1810 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001811 storage_path = NULL;
1812 } else {
1813 // When we have two arguments, the second is the directory and we can
1814 // skip looking at fstab entirely. We can always abspath() the directory
1815 // argument when we get it.
1816 if (argv[1]) {
1817 if (nonroot)
1818 bb_error_msg_and_die(must_be_root);
1819 mtpair->mnt_fsname = argv[0];
1820 mtpair->mnt_dir = argv[1];
1821 mtpair->mnt_type = fstype;
1822 mtpair->mnt_opts = cmdopts;
1823 if (ENABLE_FEATURE_MOUNT_LABEL) {
1824 resolve_mount_spec(&mtpair->mnt_fsname);
1825 }
1826 rc = singlemount(mtpair, 0);
1827 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001828 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001829 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001830 }
1831
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001832 // Past this point, we are handling either "mount -a [opts]"
1833 // or "mount [opts] single_param"
1834
Denis Vlasenkob4133682008-02-18 13:05:38 +00001835 i = parse_mount_options(cmdopts, 0); // FIXME: should be "long", not "int"
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001836 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
1837 bb_error_msg_and_die(must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00001838
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001839 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001840 if (ENABLE_FEATURE_MOUNT_FLAGS
1841 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1842 ) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001843 rc = verbose_mount(/*source:*/ "", /*target:*/ argv[0],
1844 /*type:*/ "", /*flags:*/ i, /*data:*/ "");
1845 if (rc)
1846 bb_simple_perror_msg_and_die(argv[0]);
1847 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001848 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001849
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001850 // Open either fstab or mtab
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001851 fstabname = "/etc/fstab";
1852 if (i & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001853 // WARNING. I am not sure this matches util-linux's
1854 // behavior. It's possible util-linux does not
1855 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001856 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001857 }
1858 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001859 if (!fstab)
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001860 bb_perror_msg_and_die("cannot read %s", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001861
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001862 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00001863 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001864 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001865 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001866
1867 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00001868 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001869 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001870 GETMNTENT_BUFSIZE/2)
1871 ) { // End of fstab/mtab is reached
1872 mtcur = mtother; // the thing we found last time
1873 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001874 }
1875
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001876 // If we're trying to mount something specific and this isn't it,
1877 // skip it. Note we must match the exact text in fstab (ala
1878 // "proc") or a full path from root
1879 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001880
1881 // Is this what we're looking for?
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001882 if (strcmp(argv[0], mtcur->mnt_fsname) &&
1883 strcmp(storage_path, mtcur->mnt_fsname) &&
1884 strcmp(argv[0], mtcur->mnt_dir) &&
1885 strcmp(storage_path, mtcur->mnt_dir)) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001886
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001887 // Remember this entry. Something later may have
1888 // overmounted it, and we want the _last_ match.
1889 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001890
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001891 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001892 } else {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001893 // Do we need to match a filesystem type?
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001894 if (fstype && match_fstype(mtcur, fstype))
1895 continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001896
1897 // Skip noauto and swap anyway.
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001898 if (parse_mount_options(mtcur->mnt_opts, 0) & (MOUNT_NOAUTO | MOUNT_SWAP))
1899 continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001900
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001901 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001902 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001903 if (nonroot)
1904 bb_error_msg_and_die(must_be_root);
1905
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001906 // Mount this thing
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001907 if (ENABLE_FEATURE_MOUNT_LABEL)
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001908 resolve_mount_spec(&mtpair->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001909
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001910 // NFS mounts want this to be xrealloc-able
1911 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001912 if (singlemount(mtcur, 1)) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001913 // Count number of failed mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001914 rc++;
1915 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001916 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001917 }
1918 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001919
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001920 // End of fstab/mtab is reached.
1921 // Were we looking for something specific?
1922 if (argv[0]) {
1923 // If we didn't find anything, complain
1924 if (!mtcur->mnt_fsname)
1925 bb_error_msg_and_die("can't find %s in %s",
1926 argv[0], fstabname);
1927 if (nonroot) {
1928 // fstab must have "users" or "user"
1929 if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))
1930 bb_error_msg_and_die(must_be_root);
1931 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001932
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001933 // Mount the last thing we found
1934 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
1935 append_mount_options(&(mtcur->mnt_opts), cmdopts);
1936 if (ENABLE_FEATURE_MOUNT_LABEL) {
1937 resolve_mount_spec(&mtpair->mnt_fsname);
1938 }
1939 rc = singlemount(mtcur, 0);
1940 if (ENABLE_FEATURE_CLEAN_UP)
1941 free(mtcur->mnt_opts);
1942 }
1943
1944 if (ENABLE_FEATURE_CLEAN_UP)
1945 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001946 if (ENABLE_FEATURE_CLEAN_UP) {
1947 free(storage_path);
1948 free(cmdopts);
1949 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001950 return rc;
1951}