blob: 0f213bb30e6e952bf200d0c284ca997bfb96582e [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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02009 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Erik Andersenb7cc49d2000-01-13 06:38:14 +000010 */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +000011// Design notes: There is no spec for mount. Remind me to write one.
12//
13// mount_main() calls singlemount() which calls mount_it_now().
14//
15// mount_main() can loop through /etc/fstab for mount -a
16// singlemount() can loop through /etc/filesystems for fstype detection.
17// mount_it_now() does the actual mount.
18//
Eric Andersencc8ed391999-10-05 16:24:54 +000019#include <mntent.h>
Bernhard Reutner-Fischerf4701962008-01-27 12:50:12 +000020#include <syslog.h>
Denys Vlasenkoda49f582009-07-08 02:58:38 +020021#include <sys/mount.h>
Denys Vlasenko102ff762009-11-21 17:14:08 +010022// Grab more as needed from util-linux's mount/mount_constants.h
23#ifndef MS_DIRSYNC
24# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
25#endif
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +020026#ifndef MS_UNION
27# define MS_UNION (1 << 8)
28#endif
Denys Vlasenkoda49f582009-07-08 02:58:38 +020029#ifndef MS_BIND
30# define MS_BIND (1 << 12)
31#endif
32#ifndef MS_MOVE
33# define MS_MOVE (1 << 13)
34#endif
35#ifndef MS_RECURSIVE
36# define MS_RECURSIVE (1 << 14)
37#endif
38#ifndef MS_SILENT
39# define MS_SILENT (1 << 15)
40#endif
Denys Vlasenko102ff762009-11-21 17:14:08 +010041// The shared subtree stuff, which went in around 2.6.15
Denys Vlasenkoda49f582009-07-08 02:58:38 +020042#ifndef MS_UNBINDABLE
43# define MS_UNBINDABLE (1 << 17)
44#endif
45#ifndef MS_PRIVATE
46# define MS_PRIVATE (1 << 18)
47#endif
48#ifndef MS_SLAVE
49# define MS_SLAVE (1 << 19)
50#endif
51#ifndef MS_SHARED
52# define MS_SHARED (1 << 20)
53#endif
54#ifndef MS_RELATIME
55# define MS_RELATIME (1 << 21)
56#endif
Eric Andersenbd22ed82000-07-08 18:55:24 +000057
Denys Vlasenko102ff762009-11-21 17:14:08 +010058#include "libbb.h"
Denis Vlasenko6aa76962008-03-18 01:44:52 +000059#if ENABLE_FEATURE_MOUNT_LABEL
Natanael Copa9aff2992009-09-20 04:28:22 +020060# include "volume_id.h"
61#else
62# define resolve_mount_spec(fsname) ((void)0)
Denis Vlasenko6aa76962008-03-18 01:44:52 +000063#endif
Denis Vlasenkode7684a2008-02-18 21:08:49 +000064
Denis Vlasenko30e5cf82008-12-05 16:40:36 +000065// Needed for nfs support only
Denis Vlasenko30a64cd2006-09-15 15:12:00 +000066#include <sys/utsname.h>
67#undef TRUE
68#undef FALSE
Denys Vlasenkocc428142009-12-16 02:06:56 +010069#if ENABLE_FEATURE_MOUNT_NFS
70/* This is just a warning of a common mistake. Possibly this should be a
71 * uclibc faq entry rather than in busybox... */
72# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
73# error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
74# endif
75# include <rpc/rpc.h>
76# include <rpc/pmap_prot.h>
77# include <rpc/pmap_clnt.h>
78#endif
Denis Vlasenko30a64cd2006-09-15 15:12:00 +000079
80
Denis Vlasenko908d6b72006-12-18 23:07:42 +000081#if defined(__dietlibc__)
Denis Vlasenko30e5cf82008-12-05 16:40:36 +000082// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
83// dietlibc-0.30 does not have implementation of getmntent_r()
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +000084static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000085 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
Denis Vlasenko908d6b72006-12-18 23:07:42 +000086{
Denis Vlasenko908d6b72006-12-18 23:07:42 +000087 struct mntent* ment = getmntent(stream);
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +000088 return memcpy(result, ment, sizeof(*ment));
Denis Vlasenko908d6b72006-12-18 23:07:42 +000089}
90#endif
91
92
Rob Landleydc0955b2006-03-14 18:16:25 +000093// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +000094enum {
Denis Vlasenkoa4522c52008-03-17 08:46:43 +000095 MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
96 MOUNT_NOAUTO = (1 << 29),
97 MOUNT_SWAP = (1 << 30),
Denis Vlasenko13c5a682006-10-16 22:39:51 +000098};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +000099
100
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000101#define OPTION_STR "o:t:rwanfvsiO:"
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000102enum {
103 OPT_o = (1 << 0),
104 OPT_t = (1 << 1),
105 OPT_r = (1 << 2),
106 OPT_w = (1 << 3),
107 OPT_a = (1 << 4),
108 OPT_n = (1 << 5),
109 OPT_f = (1 << 6),
110 OPT_v = (1 << 7),
111 OPT_s = (1 << 8),
112 OPT_i = (1 << 9),
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000113 OPT_O = (1 << 10),
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000114};
115
116#if ENABLE_FEATURE_MTAB_SUPPORT
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200117#define USE_MTAB (!(option_mask32 & OPT_n))
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000118#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200119#define USE_MTAB 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000120#endif
121
122#if ENABLE_FEATURE_MOUNT_FAKE
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200123#define FAKE_IT (option_mask32 & OPT_f)
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000124#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200125#define FAKE_IT 0
126#endif
127
128#if ENABLE_FEATURE_MOUNT_HELPERS
129#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
130#else
131#define HELPERS_ALLOWED 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000132#endif
133
134
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000135// TODO: more "user" flag compatibility.
136// "user" option (from mount manpage):
137// Only the user that mounted a filesystem can unmount it again.
138// If any user should be able to unmount, then use users instead of user
139// in the fstab line. The owner option is similar to the user option,
140// with the restriction that the user must be the owner of the special file.
141// This may be useful e.g. for /dev/fd if a login script makes
142// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000143
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000144// Standard mount options (from -o options or --options),
145// with corresponding flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000146static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000147 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000148
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000149 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000150 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000151 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000152
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000153 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000154 /* "defaults" */ 0,
155 /* "quiet" 0 - do not filter out, vfat wants to see it */
156 /* "noauto" */ MOUNT_NOAUTO,
157 /* "sw" */ MOUNT_SWAP,
158 /* "swap" */ MOUNT_SWAP,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000159 IF_DESKTOP(/* "user" */ MOUNT_USERS,)
160 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000161 /* "_netdev" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000162 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000163
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000164 IF_FEATURE_MOUNT_FLAGS(
Rob Landleye3781b72006-08-08 01:39:49 +0000165 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000166 /* "nosuid" */ MS_NOSUID,
167 /* "suid" */ ~MS_NOSUID,
168 /* "dev" */ ~MS_NODEV,
169 /* "nodev" */ MS_NODEV,
170 /* "exec" */ ~MS_NOEXEC,
171 /* "noexec" */ MS_NOEXEC,
172 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000173 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000174 /* "async" */ ~MS_SYNCHRONOUS,
175 /* "atime" */ ~MS_NOATIME,
176 /* "noatime" */ MS_NOATIME,
177 /* "diratime" */ ~MS_NODIRATIME,
178 /* "nodiratime" */ MS_NODIRATIME,
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000179 /* "mand" */ MS_MANDLOCK,
180 /* "nomand" */ ~MS_MANDLOCK,
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000181 /* "relatime" */ MS_RELATIME,
182 /* "norelatime" */ ~MS_RELATIME,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000183 /* "loud" */ ~MS_SILENT,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000184
Rob Landleye3781b72006-08-08 01:39:49 +0000185 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200186 /* "union" */ MS_UNION,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000187 /* "bind" */ MS_BIND,
188 /* "move" */ MS_MOVE,
189 /* "shared" */ MS_SHARED,
190 /* "slave" */ MS_SLAVE,
191 /* "private" */ MS_PRIVATE,
192 /* "unbindable" */ MS_UNBINDABLE,
193 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
194 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
195 /* "rprivate" */ MS_SLAVE|MS_RECURSIVE,
196 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000197 )
198
199 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000200 /* "ro" */ MS_RDONLY, // vfs flag
201 /* "rw" */ ~MS_RDONLY, // vfs flag
202 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000203};
204
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000205static const char mount_option_str[] =
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000206 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000207 "loop\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000208 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000209 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000210 "defaults\0"
211 // "quiet\0" - do not filter out, vfat wants to see it
212 "noauto\0"
213 "sw\0"
214 "swap\0"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000215 IF_DESKTOP("user\0")
216 IF_DESKTOP("users\0")
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000217 "_netdev\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000218 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000219 IF_FEATURE_MOUNT_FLAGS(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000220 // vfs flags
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000221 "nosuid\0"
222 "suid\0"
223 "dev\0"
224 "nodev\0"
225 "exec\0"
226 "noexec\0"
227 "sync\0"
228 "dirsync\0"
229 "async\0"
230 "atime\0"
231 "noatime\0"
232 "diratime\0"
233 "nodiratime\0"
234 "mand\0"
235 "nomand\0"
236 "relatime\0"
237 "norelatime\0"
238 "loud\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000239
240 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200241 "union\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000242 "bind\0"
243 "move\0"
244 "shared\0"
245 "slave\0"
246 "private\0"
247 "unbindable\0"
248 "rshared\0"
249 "rslave\0"
250 "rprivate\0"
251 "runbindable\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000252 )
253
254 // Always understood.
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000255 "ro\0" // vfs flag
256 "rw\0" // vfs flag
257 "remount\0" // action flag
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000258;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000259
Denis Vlasenkof732e962008-02-18 12:07:49 +0000260
261struct globals {
262#if ENABLE_FEATURE_MOUNT_NFS
263 smalluint nfs_mount_version;
264#endif
265#if ENABLE_FEATURE_MOUNT_VERBOSE
266 unsigned verbose;
267#endif
268 llist_t *fslist;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000269 char getmntent_buf[1];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100270} FIX_ALIASING;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000271enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
Denis Vlasenkof732e962008-02-18 12:07:49 +0000272#define G (*(struct globals*)&bb_common_bufsiz1)
273#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000274#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000275#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000276#else
277#define verbose 0
278#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000279#define fslist (G.fslist )
280#define getmntent_buf (G.getmntent_buf )
281
282
283#if ENABLE_FEATURE_MOUNT_VERBOSE
284static int verbose_mount(const char *source, const char *target,
285 const char *filesystemtype,
286 unsigned long mountflags, const void *data)
287{
288 int rc;
289
290 errno = 0;
291 rc = mount(source, target, filesystemtype, mountflags, data);
292 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000293 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000294 source, target, filesystemtype,
295 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000296 return rc;
297}
298#else
299#define verbose_mount(...) mount(__VA_ARGS__)
300#endif
301
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000302// Append mount options to string
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000303static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000304{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000305 if (*oldopts && **oldopts) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000306 // Do not insert options which are already there
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000307 while (newopts[0]) {
308 char *p;
309 int len = strlen(newopts);
310 p = strchr(newopts, ',');
311 if (p) len = p - newopts;
312 p = *oldopts;
313 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000314 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000315 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000316 goto skip;
317 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000318 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000319 p++;
320 }
321 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
322 free(*oldopts);
323 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000324 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000325 newopts += len;
326 while (newopts[0] == ',') newopts++;
327 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000328 } else {
329 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000330 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000331 }
332}
333
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000334// Use the mount_options list to parse options into flags.
Alexander Shishkin77650952010-10-28 06:10:03 +0200335// Also update list of unrecognized options if unrecognized != NULL
Denis Vlasenkob4133682008-02-18 13:05:38 +0000336static long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000337{
Denis Vlasenkob4133682008-02-18 13:05:38 +0000338 long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000339
Rob Landley6a6798b2005-08-10 20:35:54 +0000340 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000341 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000342 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000343 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000344 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000345
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000346 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000347
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000348// FIXME: use hasmntopt()
Rob Landley6a6798b2005-08-10 20:35:54 +0000349 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000350 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Alexander Shishkin77650952010-10-28 06:10:03 +0200351 if (strcasecmp(option_str, options) == 0) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000352 long fl = mount_options[i];
Alexander Shishkin77650952010-10-28 06:10:03 +0200353 if (fl < 0)
354 flags &= fl;
355 else
356 flags |= fl;
357 goto found;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000358 }
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000359 option_str += strlen(option_str) + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000360 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200361 // We did not recognize this option.
362 // If "unrecognized" is not NULL, append option there.
363 // Note that we should not append *empty* option -
364 // in this case we want to pass NULL, not "", to "data"
365 // parameter of mount(2) syscall.
366 // This is crucial for filesystems that don't accept
367 // any arbitrary mount options, like cgroup fs:
368 // "mount -t cgroup none /mnt"
369 if (options[0] && unrecognized) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000370 // Add it to strflags, to pass on to kernel
Alexander Shishkin77650952010-10-28 06:10:03 +0200371 char *p = *unrecognized;
372 unsigned len = p ? strlen(p) : 0;
373 *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000374
Rob Landley6a6798b2005-08-10 20:35:54 +0000375 // Comma separated if it's not the first one
Alexander Shishkin77650952010-10-28 06:10:03 +0200376 if (len) p[len++] = ',';
377 strcpy(p + len, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000378 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200379 found:
Denis Vlasenko2535f122007-09-15 13:28:30 +0000380 if (!comma)
381 break;
382 // Advance to next option
383 *comma = ',';
384 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000385 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000386
Rob Landleydc0955b2006-03-14 18:16:25 +0000387 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000388}
389
Rob Landleydc0955b2006-03-14 18:16:25 +0000390// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000391static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000392{
Denis Vlasenko87468852007-04-13 23:22:00 +0000393 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000394 "/etc/filesystems",
395 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000396 };
397 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200398 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000399 int i;
400 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000401
Denis Vlasenko87468852007-04-13 23:22:00 +0000402 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000403 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000404 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000405
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000406 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200407 if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
Denis Vlasenko372686b2006-10-12 22:42:33 +0000408 continue;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000409 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200410 if (*fs == '#' || *fs == '*' || !*fs)
411 continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000412
Denis Vlasenko372686b2006-10-12 22:42:33 +0000413 llist_add_to_end(&list, xstrdup(fs));
414 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000415 }
416 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
417 }
418
419 return list;
420}
421
Rob Landleydc0955b2006-03-14 18:16:25 +0000422#if ENABLE_FEATURE_CLEAN_UP
423static void delete_block_backed_filesystems(void)
424{
Rob Landleya6b5b602006-05-08 19:03:07 +0000425 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000426}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000427#else
428void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000429#endif
430
Rob Landleydc0955b2006-03-14 18:16:25 +0000431// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000432// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000433static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000434{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000435 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000436
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200437 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000438 if (verbose >= 2)
439 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
440 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
441 vfsflags, filteropts);
442 goto mtab;
443 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000444
Rob Landleydc0955b2006-03-14 18:16:25 +0000445 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000446 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000447 errno = 0;
448 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000449 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000450
451 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000452 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200453 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200454 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000455 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000456 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000457 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200458 if (FAKE_IT)
459 args[rc++] = (char *)"-f";
460 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
461 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000462 args[rc++] = mp->mnt_fsname;
463 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000464 if (filteropts) {
465 args[rc++] = (char *)"-o";
466 args[rc++] = filteropts;
467 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000468 args[rc] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +0100469 rc = spawn_and_wait(args);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000470 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000471 if (!rc)
472 break;
473 errno = errno_save;
474 }
475
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000476 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000477 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000478 if (!(vfsflags & MS_SILENT))
479 bb_error_msg("%s is write-protected, mounting read-only",
480 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000481 vfsflags |= MS_RDONLY;
482 }
483
Rob Landleydc0955b2006-03-14 18:16:25 +0000484 // Abort entirely if permission denied.
485
486 if (rc && errno == EPERM)
487 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
488
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000489 // If the mount was successful, and we're maintaining an old-style
490 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000491 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200492 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000493 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000494 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000495 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000496 int i;
497
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000498 if (!mountTable) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000499 bb_error_msg("no %s", bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000500 goto ret;
501 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000502
503 // Add vfs string flags
504
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000505 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
506 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
507 append_mount_options(&(mp->mnt_opts), option_str);
508 option_str += strlen(option_str) + 1;
509 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000510
511 // Remove trailing / (if any) from directory we mounted on
512
Denis Vlasenko727ef942006-09-14 13:19:19 +0000513 i = strlen(mp->mnt_dir) - 1;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000514 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000515
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000516 // Convert to canonical pathnames as needed
Denis Vlasenko727ef942006-09-14 13:19:19 +0000517
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000518 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000519 fsname = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000520 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000521 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000522 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000523 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000524 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000525
526 // Write and close.
527
Denis Vlasenko727ef942006-09-14 13:19:19 +0000528 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000529 endmntent(mountTable);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000530 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000531 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000532 free(fsname);
533 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000534 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000535 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000536 return rc;
537}
538
Denis Vlasenko25098f72006-09-14 15:46:33 +0000539#if ENABLE_FEATURE_MOUNT_NFS
540
541/*
542 * Linux NFS mount
543 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
544 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +0200545 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko25098f72006-09-14 15:46:33 +0000546 *
547 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
548 * numbers to be specified on the command line.
549 *
550 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
551 * Omit the call to connect() for Linux version 1.3.11 or later.
552 *
553 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
554 * Implemented the "bg", "fg" and "retry" mount options for NFS.
555 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000556 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000557 * - added Native Language Support
558 *
559 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
560 * plus NFSv3 stuff.
561 */
562
Denis Vlasenko25098f72006-09-14 15:46:33 +0000563#define MOUNTPORT 635
564#define MNTPATHLEN 1024
565#define MNTNAMLEN 255
566#define FHSIZE 32
567#define FHSIZE3 64
568
569typedef char fhandle[FHSIZE];
570
571typedef struct {
572 unsigned int fhandle3_len;
573 char *fhandle3_val;
574} fhandle3;
575
576enum mountstat3 {
577 MNT_OK = 0,
578 MNT3ERR_PERM = 1,
579 MNT3ERR_NOENT = 2,
580 MNT3ERR_IO = 5,
581 MNT3ERR_ACCES = 13,
582 MNT3ERR_NOTDIR = 20,
583 MNT3ERR_INVAL = 22,
584 MNT3ERR_NAMETOOLONG = 63,
585 MNT3ERR_NOTSUPP = 10004,
586 MNT3ERR_SERVERFAULT = 10006,
587};
588typedef enum mountstat3 mountstat3;
589
590struct fhstatus {
591 unsigned int fhs_status;
592 union {
593 fhandle fhs_fhandle;
594 } fhstatus_u;
595};
596typedef struct fhstatus fhstatus;
597
598struct mountres3_ok {
599 fhandle3 fhandle;
600 struct {
601 unsigned int auth_flavours_len;
602 char *auth_flavours_val;
603 } auth_flavours;
604};
605typedef struct mountres3_ok mountres3_ok;
606
607struct mountres3 {
608 mountstat3 fhs_status;
609 union {
610 mountres3_ok mountinfo;
611 } mountres3_u;
612};
613typedef struct mountres3 mountres3;
614
615typedef char *dirpath;
616
617typedef char *name;
618
619typedef struct mountbody *mountlist;
620
621struct mountbody {
622 name ml_hostname;
623 dirpath ml_directory;
624 mountlist ml_next;
625};
626typedef struct mountbody mountbody;
627
628typedef struct groupnode *groups;
629
630struct groupnode {
631 name gr_name;
632 groups gr_next;
633};
634typedef struct groupnode groupnode;
635
636typedef struct exportnode *exports;
637
638struct exportnode {
639 dirpath ex_dir;
640 groups ex_groups;
641 exports ex_next;
642};
643typedef struct exportnode exportnode;
644
645struct ppathcnf {
646 int pc_link_max;
647 short pc_max_canon;
648 short pc_max_input;
649 short pc_name_max;
650 short pc_path_max;
651 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000652 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000653 char pc_xxx;
654 short pc_mask[2];
655};
656typedef struct ppathcnf ppathcnf;
657
658#define MOUNTPROG 100005
659#define MOUNTVERS 1
660
661#define MOUNTPROC_NULL 0
662#define MOUNTPROC_MNT 1
663#define MOUNTPROC_DUMP 2
664#define MOUNTPROC_UMNT 3
665#define MOUNTPROC_UMNTALL 4
666#define MOUNTPROC_EXPORT 5
667#define MOUNTPROC_EXPORTALL 6
668
669#define MOUNTVERS_POSIX 2
670
671#define MOUNTPROC_PATHCONF 7
672
673#define MOUNT_V3 3
674
675#define MOUNTPROC3_NULL 0
676#define MOUNTPROC3_MNT 1
677#define MOUNTPROC3_DUMP 2
678#define MOUNTPROC3_UMNT 3
679#define MOUNTPROC3_UMNTALL 4
680#define MOUNTPROC3_EXPORT 5
681
682enum {
683#ifndef NFS_FHSIZE
684 NFS_FHSIZE = 32,
685#endif
686#ifndef NFS_PORT
687 NFS_PORT = 2049
688#endif
689};
690
Denis Vlasenko25098f72006-09-14 15:46:33 +0000691/*
692 * We want to be able to compile mount on old kernels in such a way
693 * that the binary will work well on more recent kernels.
694 * Thus, if necessary we teach nfsmount.c the structure of new fields
695 * that will come later.
696 *
697 * Moreover, the new kernel includes conflict with glibc includes
698 * so it is easiest to ignore the kernel altogether (at compile time).
699 */
700
701struct nfs2_fh {
702 char data[32];
703};
704struct nfs3_fh {
705 unsigned short size;
706 unsigned char data[64];
707};
708
709struct nfs_mount_data {
710 int version; /* 1 */
711 int fd; /* 1 */
712 struct nfs2_fh old_root; /* 1 */
713 int flags; /* 1 */
714 int rsize; /* 1 */
715 int wsize; /* 1 */
716 int timeo; /* 1 */
717 int retrans; /* 1 */
718 int acregmin; /* 1 */
719 int acregmax; /* 1 */
720 int acdirmin; /* 1 */
721 int acdirmax; /* 1 */
722 struct sockaddr_in addr; /* 1 */
723 char hostname[256]; /* 1 */
724 int namlen; /* 2 */
725 unsigned int bsize; /* 3 */
726 struct nfs3_fh root; /* 4 */
727};
728
729/* bits in the flags field */
730enum {
731 NFS_MOUNT_SOFT = 0x0001, /* 1 */
732 NFS_MOUNT_INTR = 0x0002, /* 1 */
733 NFS_MOUNT_SECURE = 0x0004, /* 1 */
734 NFS_MOUNT_POSIX = 0x0008, /* 1 */
735 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
736 NFS_MOUNT_NOAC = 0x0020, /* 1 */
737 NFS_MOUNT_TCP = 0x0040, /* 2 */
738 NFS_MOUNT_VER3 = 0x0080, /* 3 */
739 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000740 NFS_MOUNT_NONLM = 0x0200, /* 3 */
741 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +0000742};
743
744
745/*
746 * We need to translate between nfs status return values and
747 * the local errno values which may not be the same.
748 *
749 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
750 * "after #include <errno.h> the symbol errno is reserved for any use,
751 * it cannot even be used as a struct tag or field name".
752 */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000753#ifndef EDQUOT
Denys Vlasenkocc428142009-12-16 02:06:56 +0100754# define EDQUOT ENOSPC
Denis Vlasenko25098f72006-09-14 15:46:33 +0000755#endif
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000756/* Convert each NFSERR_BLAH into EBLAH */
Denys Vlasenkocc428142009-12-16 02:06:56 +0100757static const uint8_t nfs_err_stat[] = {
758 1, 2, 5, 6, 13, 17,
759 19, 20, 21, 22, 27, 28,
760 30, 63, 66, 69, 70, 71
761};
Denys Vlasenkodc1fd2e2010-05-19 17:01:29 +0200762#if ( \
763 EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
764 ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
765 EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
766typedef uint8_t nfs_err_type;
767#else
768typedef uint16_t nfs_err_type;
769#endif
770static const nfs_err_type nfs_err_errnum[] = {
Denys Vlasenkocc428142009-12-16 02:06:56 +0100771 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
772 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
773 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
Denis Vlasenko25098f72006-09-14 15:46:33 +0000774};
Denis Vlasenko25098f72006-09-14 15:46:33 +0000775static char *nfs_strerror(int status)
776{
777 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000778
Denys Vlasenkocc428142009-12-16 02:06:56 +0100779 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
780 if (nfs_err_stat[i] == status)
781 return strerror(nfs_err_errnum[i]);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000782 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000783 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000784}
785
786static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
787{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200788 return xdr_opaque(xdrs, objp, FHSIZE);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000789}
790
791static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
792{
793 if (!xdr_u_int(xdrs, &objp->fhs_status))
794 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +0200795 if (objp->fhs_status == 0)
796 return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000797 return TRUE;
798}
799
800static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
801{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200802 return xdr_string(xdrs, objp, MNTPATHLEN);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000803}
804
805static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
806{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200807 return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
808 (unsigned int *) &objp->fhandle3_len,
809 FHSIZE3);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000810}
811
812static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
813{
814 if (!xdr_fhandle3(xdrs, &objp->fhandle))
815 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +0200816 return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
817 &(objp->auth_flavours.auth_flavours_len),
818 ~0,
819 sizeof(int),
820 (xdrproc_t) xdr_int);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000821}
822
823static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
824{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200825 return xdr_enum(xdrs, (enum_t *) objp);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000826}
827
828static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
829{
830 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
831 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +0200832 if (objp->fhs_status == MNT_OK)
833 return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000834 return TRUE;
835}
836
837#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
838
Denis Vlasenko25098f72006-09-14 15:46:33 +0000839/*
840 * Unfortunately, the kernel prints annoying console messages
841 * in case of an unexpected nfs mount version (instead of
842 * just returning some error). Therefore we'll have to try
843 * and figure out what version the kernel expects.
844 *
845 * Variables:
846 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
847 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
848 * nfs_mount_version: version this source and running kernel can handle
849 */
850static void
851find_kernel_nfs_mount_version(void)
852{
Denis Vlasenkob9256052007-09-28 10:29:17 +0000853 int kernel_version;
854
855 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000856 return;
857
858 nfs_mount_version = 4; /* default */
859
860 kernel_version = get_linux_version_code();
861 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +0100862 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +0000863 nfs_mount_version = 3;
864 /* else v4 since 2.3.99pre4 */
865 }
866}
867
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000868static void
Denis Vlasenkob9256052007-09-28 10:29:17 +0000869get_mountport(struct pmap *pm_mnt,
870 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +0000871 long unsigned prog,
872 long unsigned version,
873 long unsigned proto,
874 long unsigned port)
875{
876 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000877
878 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +0000879/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
880 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000881 pmap = pmap_getmaps(server_addr);
882
883 if (version > MAX_NFSPROT)
884 version = MAX_NFSPROT;
885 if (!prog)
886 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000887 pm_mnt->pm_prog = prog;
888 pm_mnt->pm_vers = version;
889 pm_mnt->pm_prot = proto;
890 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000891
Denis Vlasenko25098f72006-09-14 15:46:33 +0000892 while (pmap) {
893 if (pmap->pml_map.pm_prog != prog)
894 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000895 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000896 goto next;
897 if (version > 2 && pmap->pml_map.pm_vers != version)
898 goto next;
899 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
900 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100901 if (pmap->pml_map.pm_vers > MAX_NFSPROT
902 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
903 || (port && pmap->pml_map.pm_port != port)
904 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +0000905 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100906 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000907 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
908 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +0000909 pmap = pmap->pml_next;
910 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000911 if (!pm_mnt->pm_vers)
912 pm_mnt->pm_vers = MOUNTVERS;
913 if (!pm_mnt->pm_port)
914 pm_mnt->pm_port = MOUNTPORT;
915 if (!pm_mnt->pm_prot)
916 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000917}
918
Denis Vlasenkof0000652007-09-04 18:30:26 +0000919#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +0000920static int daemonize(void)
921{
Denis Vlasenko25098f72006-09-14 15:46:33 +0000922 int pid = fork();
923 if (pid < 0) /* error */
924 return -errno;
925 if (pid > 0) /* parent */
926 return 0;
927 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000928 close(0);
929 xopen(bb_dev_null, O_RDWR);
930 xdup2(0, 1);
931 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000932 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000933 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000934 logmode = LOGMODE_SYSLOG;
935 return 1;
936}
Denis Vlasenkof0000652007-09-04 18:30:26 +0000937#else
938static inline int daemonize(void) { return -ENOSYS; }
939#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000940
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000941/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000942static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000943{
944 return 0;
945}
946
947/* RPC strerror analogs are terminally idiotic:
948 * *mandatory* prefix and \n at end.
949 * This hopefully helps. Usage:
950 * error_msg_rpc(clnt_*error*(" ")) */
951static void error_msg_rpc(const char *msg)
952{
Denis Vlasenko23514fe2006-09-19 14:07:52 +0000953 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000954 while (msg[0] == ' ' || msg[0] == ':') msg++;
955 len = strlen(msg);
956 while (len && msg[len-1] == '\n') len--;
957 bb_error_msg("%.*s", len, msg);
958}
959
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000960/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko810b7162009-05-13 23:48:59 +0200961static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000962{
963 CLIENT *mclient;
964 char *hostname;
965 char *pathname;
966 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +0200967 /* prior to 2.6.23, kernel took NFS options in a form of this struct
968 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
969 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000970 struct nfs_mount_data data;
971 char *opt;
972 struct hostent *hp;
973 struct sockaddr_in server_addr;
974 struct sockaddr_in mount_server_addr;
975 int msock, fsock;
976 union {
977 struct fhstatus nfsv2;
978 struct mountres3 nfsv3;
979 } status;
980 int daemonized;
981 char *s;
982 int port;
983 int mountport;
984 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000985#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000986 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000987#else
988 enum { bg = 0 };
989#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000990 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000991 int mountprog;
992 int mountvers;
993 int nfsprog;
994 int nfsvers;
995 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +0200996 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000997 smallint tcp;
998 smallint soft;
999 int intr;
1000 int posix;
1001 int nocto;
1002 int noac;
1003 int nordirplus;
1004 int nolock;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001005
1006 find_kernel_nfs_mount_version();
1007
1008 daemonized = 0;
1009 mounthost = NULL;
1010 retval = ETIMEDOUT;
1011 msock = fsock = -1;
1012 mclient = NULL;
1013
1014 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1015
1016 filteropts = xstrdup(filteropts); /* going to trash it later... */
1017
1018 hostname = xstrdup(mp->mnt_fsname);
1019 /* mount_main() guarantees that ':' is there */
1020 s = strchr(hostname, ':');
1021 pathname = s + 1;
1022 *s = '\0';
1023 /* Ignore all but first hostname in replicated mounts
1024 until they can be fully supported. (mack@sgi.com) */
1025 s = strchr(hostname, ',');
1026 if (s) {
1027 *s = '\0';
1028 bb_error_msg("warning: multiple hostnames not supported");
1029 }
1030
1031 server_addr.sin_family = AF_INET;
1032 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1033 hp = gethostbyname(hostname);
1034 if (hp == NULL) {
1035 bb_herror_msg("%s", hostname);
1036 goto fail;
1037 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001038 if (hp->h_length != (int)sizeof(struct in_addr)) {
1039 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001040 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001041 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001042 }
1043
1044 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1045
1046 /* add IP address to mtab options for use when unmounting */
1047
1048 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1049 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1050 } else {
1051 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1052 mp->mnt_opts[0] ? "," : "",
1053 inet_ntoa(server_addr.sin_addr));
1054 free(mp->mnt_opts);
1055 mp->mnt_opts = tmp;
1056 }
1057
1058 /* Set default options.
1059 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1060 * let the kernel decide.
1061 * timeo is filled in after we know whether it'll be TCP or UDP. */
1062 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001063 data.retrans = 3;
1064 data.acregmin = 3;
1065 data.acregmax = 60;
1066 data.acdirmin = 30;
1067 data.acdirmax = 60;
1068 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001069
Denis Vlasenko25098f72006-09-14 15:46:33 +00001070 soft = 0;
1071 intr = 0;
1072 posix = 0;
1073 nocto = 0;
1074 nolock = 0;
1075 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001076 nordirplus = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001077 retry = 10000; /* 10000 minutes ~ 1 week */
1078 tcp = 0;
1079
1080 mountprog = MOUNTPROG;
1081 mountvers = 0;
1082 port = 0;
1083 mountport = 0;
1084 nfsprog = 100003;
1085 nfsvers = 0;
1086
1087 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001088 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001089 char *opteq = strchr(opt, '=');
1090 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001091 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001092 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001093 /* 0 */ "rsize\0"
1094 /* 1 */ "wsize\0"
1095 /* 2 */ "timeo\0"
1096 /* 3 */ "retrans\0"
1097 /* 4 */ "acregmin\0"
1098 /* 5 */ "acregmax\0"
1099 /* 6 */ "acdirmin\0"
1100 /* 7 */ "acdirmax\0"
1101 /* 8 */ "actimeo\0"
1102 /* 9 */ "retry\0"
1103 /* 10 */ "port\0"
1104 /* 11 */ "mountport\0"
1105 /* 12 */ "mounthost\0"
1106 /* 13 */ "mountprog\0"
1107 /* 14 */ "mountvers\0"
1108 /* 15 */ "nfsprog\0"
1109 /* 16 */ "nfsvers\0"
1110 /* 17 */ "vers\0"
1111 /* 18 */ "proto\0"
1112 /* 19 */ "namlen\0"
1113 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001114
1115 *opteq++ = '\0';
1116 idx = index_in_strings(options, opt);
1117 switch (idx) {
1118 case 12: // "mounthost"
1119 mounthost = xstrndup(opteq,
1120 strcspn(opteq, " \t\n\r,"));
1121 continue;
1122 case 18: // "proto"
1123 if (!strncmp(opteq, "tcp", 3))
1124 tcp = 1;
1125 else if (!strncmp(opteq, "udp", 3))
1126 tcp = 0;
1127 else
1128 bb_error_msg("warning: unrecognized proto= option");
1129 continue;
1130 case 20: // "addr" - ignore
1131 continue;
1132 }
1133
Denys Vlasenko77832482010-08-12 14:14:45 +02001134 val = xatoi_positive(opteq);
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001135 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001136 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001137 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001138 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001139 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001140 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001141 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001142 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001143 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001144 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001145 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001146 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001147 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001148 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001149 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001150 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001151 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001152 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001153 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001154 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001155 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001156 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001157 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001158 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001159 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001160 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001161 data.acregmin = val;
1162 data.acregmax = val;
1163 data.acdirmin = val;
1164 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001165 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001166 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001167 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001168 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001169 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001170 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001171 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001172 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001173 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001174 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001175 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001176 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001177 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001178 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001179 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001180 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001181 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001182 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001183 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001184 case 16: // "nfsvers"
1185 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001186 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001187 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001188 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001189 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001190 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001191 //else
1192 // bb_error_msg("warning: option namlen is not supported\n");
1193 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001194 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001195 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1196 goto fail;
1197 }
1198 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001199 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001200 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001201 "bg\0"
1202 "fg\0"
1203 "soft\0"
1204 "hard\0"
1205 "intr\0"
1206 "posix\0"
1207 "cto\0"
1208 "ac\0"
1209 "tcp\0"
1210 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001211 "lock\0"
1212 "rdirplus\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001213 int val = 1;
1214 if (!strncmp(opt, "no", 2)) {
1215 val = 0;
1216 opt += 2;
1217 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001218 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001219 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001220#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001221 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001222#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001223 break;
1224 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001225#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001226 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001227#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001228 break;
1229 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001230 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001231 break;
1232 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001233 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001234 break;
1235 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001236 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001237 break;
1238 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001239 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001240 break;
1241 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001242 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001243 break;
1244 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001245 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001246 break;
1247 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001248 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001249 break;
1250 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001251 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001252 break;
1253 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001254 if (nfs_mount_version >= 3)
1255 nolock = !val;
1256 else
1257 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001258 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001259 case 11: //rdirplus
1260 nordirplus = !val;
1261 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001262 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001263 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1264 goto fail;
1265 }
1266 }
1267 }
1268 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1269
1270 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1271 | (intr ? NFS_MOUNT_INTR : 0)
1272 | (posix ? NFS_MOUNT_POSIX : 0)
1273 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001274 | (noac ? NFS_MOUNT_NOAC : 0)
1275 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001276 if (nfs_mount_version >= 2)
1277 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1278 if (nfs_mount_version >= 3)
1279 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1280 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1281 bb_error_msg("NFSv%d not supported", nfsvers);
1282 goto fail;
1283 }
1284 if (nfsvers && !mountvers)
1285 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1286 if (nfsvers && nfsvers < mountvers) {
1287 mountvers = nfsvers;
1288 }
1289
1290 /* Adjust options if none specified */
1291 if (!data.timeo)
1292 data.timeo = tcp ? 70 : 7;
1293
Denis Vlasenko25098f72006-09-14 15:46:33 +00001294 data.version = nfs_mount_version;
1295
1296 if (vfsflags & MS_REMOUNT)
1297 goto do_mount;
1298
1299 /*
1300 * If the previous mount operation on the same host was
1301 * backgrounded, and the "bg" for this mount is also set,
1302 * give up immediately, to avoid the initial timeout.
1303 */
1304 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001305 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001306 if (daemonized <= 0) { /* parent or error */
1307 retval = -daemonized;
1308 goto ret;
1309 }
1310 }
1311
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001312 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001313 /* See if the nfs host = mount host. */
1314 if (mounthost) {
1315 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1316 mount_server_addr.sin_family = AF_INET;
1317 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1318 } else {
1319 hp = gethostbyname(mounthost);
1320 if (hp == NULL) {
1321 bb_herror_msg("%s", mounthost);
1322 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001323 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001324 if (hp->h_length != (int)sizeof(struct in_addr)) {
1325 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001326 }
1327 mount_server_addr.sin_family = AF_INET;
Denys Vlasenko99069332010-02-27 19:38:19 +01001328 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001329 }
1330 }
1331
1332 /*
1333 * The following loop implements the mount retries. When the mount
1334 * times out, and the "bg" option is set, we background ourself
1335 * and continue trying.
1336 *
1337 * The case where the mount point is not present and the "bg"
1338 * option is set, is treated as a timeout. This is done to
1339 * support nested mounts.
1340 *
1341 * The "retry" count specified by the user is the number of
1342 * minutes to retry before giving up.
1343 */
1344 {
1345 struct timeval total_timeout;
1346 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001347 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001348 time_t t;
1349 time_t prevt;
1350 time_t timeout;
1351
1352 retry_timeout.tv_sec = 3;
1353 retry_timeout.tv_usec = 0;
1354 total_timeout.tv_sec = 20;
1355 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001356/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001357 timeout = time(NULL) + 60 * retry;
1358 prevt = 0;
1359 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001360 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001361 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001362 if (t - prevt < 30)
1363 sleep(30);
1364
Denis Vlasenkob9256052007-09-28 10:29:17 +00001365 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001366 mountprog,
1367 mountvers,
1368 proto,
1369 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001370 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001371
1372 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001373 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001374 msock = RPC_ANYSOCK;
1375
Denis Vlasenkob9256052007-09-28 10:29:17 +00001376 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001377 case IPPROTO_UDP:
1378 mclient = clntudp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001379 pm_mnt.pm_prog,
1380 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001381 retry_timeout,
1382 &msock);
1383 if (mclient)
1384 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001385 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001386 msock = RPC_ANYSOCK;
1387 case IPPROTO_TCP:
1388 mclient = clnttcp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001389 pm_mnt.pm_prog,
1390 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001391 &msock, 0, 0);
1392 break;
1393 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001394 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001395 }
1396 if (!mclient) {
1397 if (!daemonized && prevt == 0)
1398 error_msg_rpc(clnt_spcreateerror(" "));
1399 } else {
1400 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001401
1402 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001403 mclient->cl_auth = authunix_create_default();
1404
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001405 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001406 * that xdr_array allocates memory for us
1407 */
1408 memset(&status, 0, sizeof(status));
1409
Denis Vlasenkob9256052007-09-28 10:29:17 +00001410 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001411 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1412 (xdrproc_t) xdr_dirpath,
1413 (caddr_t) &pathname,
1414 (xdrproc_t) xdr_mountres3,
1415 (caddr_t) &status,
1416 total_timeout);
1417 else
1418 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1419 (xdrproc_t) xdr_dirpath,
1420 (caddr_t) &pathname,
1421 (xdrproc_t) xdr_fhstatus,
1422 (caddr_t) &status,
1423 total_timeout);
1424
1425 if (clnt_stat == RPC_SUCCESS)
1426 goto prepare_kernel_data; /* we're done */
1427 if (errno != ECONNREFUSED) {
1428 error_msg_rpc(clnt_sperror(mclient, " "));
1429 goto fail; /* don't retry */
1430 }
1431 /* Connection refused */
1432 if (!daemonized && prevt == 0) /* print just once */
1433 error_msg_rpc(clnt_sperror(mclient, " "));
1434 auth_destroy(mclient->cl_auth);
1435 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001436 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001437 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001438 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001439 }
1440
1441 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001442 if (!bg)
1443 goto fail;
1444 if (!daemonized) {
1445 daemonized = daemonize();
1446 if (daemonized <= 0) { /* parent or error */
1447 retval = -daemonized;
1448 goto ret;
1449 }
1450 }
1451 prevt = t;
1452 t = time(NULL);
1453 if (t >= timeout)
1454 /* TODO error message */
1455 goto fail;
1456
1457 goto retry;
1458 }
1459
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001460 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001461
1462 if (nfsvers == 2) {
1463 if (status.nfsv2.fhs_status != 0) {
1464 bb_error_msg("%s:%s failed, reason given by server: %s",
1465 hostname, pathname,
1466 nfs_strerror(status.nfsv2.fhs_status));
1467 goto fail;
1468 }
1469 memcpy(data.root.data,
1470 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1471 NFS_FHSIZE);
1472 data.root.size = NFS_FHSIZE;
1473 memcpy(data.old_root.data,
1474 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1475 NFS_FHSIZE);
1476 } else {
1477 fhandle3 *my_fhandle;
1478 if (status.nfsv3.fhs_status != 0) {
1479 bb_error_msg("%s:%s failed, reason given by server: %s",
1480 hostname, pathname,
1481 nfs_strerror(status.nfsv3.fhs_status));
1482 goto fail;
1483 }
1484 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1485 memset(data.old_root.data, 0, NFS_FHSIZE);
1486 memset(&data.root, 0, sizeof(data.root));
1487 data.root.size = my_fhandle->fhandle3_len;
1488 memcpy(data.root.data,
1489 (char *) my_fhandle->fhandle3_val,
1490 my_fhandle->fhandle3_len);
1491
1492 data.flags |= NFS_MOUNT_VER3;
1493 }
1494
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001495 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001496 if (tcp) {
1497 if (nfs_mount_version < 3) {
1498 bb_error_msg("NFS over TCP is not supported");
1499 goto fail;
1500 }
1501 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1502 } else
1503 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1504 if (fsock < 0) {
1505 bb_perror_msg("nfs socket");
1506 goto fail;
1507 }
1508 if (bindresvport(fsock, 0) < 0) {
1509 bb_perror_msg("nfs bindresvport");
1510 goto fail;
1511 }
1512 if (port == 0) {
1513 server_addr.sin_port = PMAPPORT;
1514 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1515 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1516 if (port == 0)
1517 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001518 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001519 server_addr.sin_port = htons(port);
1520
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001521 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001522 data.fd = fsock;
1523 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1524 strncpy(data.hostname, hostname, sizeof(data.hostname));
1525
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001526 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001527 auth_destroy(mclient->cl_auth);
1528 clnt_destroy(mclient);
1529 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001530 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001531
1532 if (bg) {
1533 /* We must wait until mount directory is available */
1534 struct stat statbuf;
1535 int delay = 1;
1536 while (stat(mp->mnt_dir, &statbuf) == -1) {
1537 if (!daemonized) {
1538 daemonized = daemonize();
1539 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001540/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001541 retval = -daemonized;
1542 goto ret;
1543 }
1544 }
1545 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1546 delay *= 2;
1547 if (delay > 30)
1548 delay = 30;
1549 }
1550 }
1551
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001552 /* Perform actual mount */
1553 do_mount:
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001554 mp->mnt_type = (char*)"nfs";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001555 retval = mount_it_now(mp, vfsflags, (char*)&data);
1556 goto ret;
1557
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001558 /* Abort */
1559 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001560 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001561 if (mclient) {
1562 auth_destroy(mclient->cl_auth);
1563 clnt_destroy(mclient);
1564 }
1565 close(msock);
1566 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001567 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001568 close(fsock);
1569
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001570 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001571 free(hostname);
1572 free(mounthost);
1573 free(filteropts);
1574 return retval;
1575}
1576
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001577#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001578
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001579// Never called. Call should be optimized out.
Denis Vlasenkob4133682008-02-18 13:05:38 +00001580int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001581
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001582#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001583
1584// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1585// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001586// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001587static int singlemount(struct mntent *mp, int ignore_busy)
1588{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001589 int rc = -1;
1590 long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001591 char *loopFile = NULL, *filteropts = NULL;
1592 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001593 struct stat st;
1594
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001595 errno = 0;
1596
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001597 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1598
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001599 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001600 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1601 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001602
Denis Vlasenko2535f122007-09-15 13:28:30 +00001603 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001604 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1605 char *args[35];
1606 char *s;
1607 int n;
1608 // fsname: "cmd#arg1#arg2..."
1609 // WARNING: allows execution of arbitrary commands!
1610 // Try "mount 'sh#-c#sh' bogus_dir".
1611 // It is safe ONLY because non-root
1612 // cannot use two-argument mount command
1613 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1614 // "mount: can't find sh#-c#sh in /etc/fstab"
1615 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1616
1617 s = mp->mnt_fsname;
1618 n = 0;
1619 args[n++] = s;
1620 while (*s && n < 35 - 2) {
1621 if (*s++ == '#' && *s != '#') {
1622 s[-1] = '\0';
1623 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001624 }
1625 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001626 args[n++] = mp->mnt_dir;
1627 args[n] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +01001628 rc = spawn_and_wait(args);
Denis Vlasenko2535f122007-09-15 13:28:30 +00001629 goto report_error;
1630 }
1631
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001632 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001633 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001634 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1635 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1636 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001637 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001638 int len;
1639 char c;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001640 len_and_sockaddr *lsa;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001641 char *hostname, *dotted, *ip;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001642
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001643 hostname = mp->mnt_fsname + 2;
1644 len = strcspn(hostname, "/\\");
1645 if (len == 0 || hostname[len] == '\0')
Denis Vlasenko5c329932009-04-12 12:16:21 +00001646 goto report_error;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001647 c = hostname[len];
1648 hostname[len] = '\0';
1649 lsa = host2sockaddr(hostname, 0);
1650 hostname[len] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001651 if (!lsa)
1652 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001653
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001654 // Insert "ip=..." option into options
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001655 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001656 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001657 ip = xasprintf("ip=%s", dotted);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001658 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001659 parse_mount_options(ip, &filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001660 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001661
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001662 // "-o mand" is required [why?]
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001663 vfsflags |= MS_MANDLOCK;
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001664 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001665 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001666
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001667 goto report_error;
1668 }
1669
1670 // Might this be an NFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001671 if (ENABLE_FEATURE_MOUNT_NFS
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001672 && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001673 && strchr(mp->mnt_fsname, ':') != NULL
1674 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001675 rc = nfsmount(mp, vfsflags, filteropts);
1676 goto report_error;
1677 }
1678
1679 // Look at the file. (Not found isn't a failure for remount, or for
1680 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001681 // (We use stat, not lstat, in order to allow
1682 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001683 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001684 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1685 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001686 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001687 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1688 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001689 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001690 if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001691 if (errno == EPERM || errno == EACCES)
1692 bb_error_msg(bb_msg_perm_denied_are_you_root);
1693 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01001694 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00001695 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001696 }
1697
1698 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001699 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1700 vfsflags |= MS_BIND;
1701 }
1702
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001703 // If we know the fstype (or don't need to), jump straight
1704 // to the actual mount.
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001705 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001706 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001707 } else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001708 // Loop through filesystem types until mount succeeds
1709 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001710
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001711 // Initialize list of block backed filesystems.
1712 // This has to be done here so that during "mount -a",
1713 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001714 if (!fslist) {
1715 fslist = get_block_backed_filesystems();
1716 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1717 atexit(delete_block_backed_filesystems);
1718 }
1719
1720 for (fl = fslist; fl; fl = fl->link) {
1721 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00001722 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001723 if (!rc)
1724 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001725 }
1726 }
1727
1728 // If mount failed, clean up loop file (if any).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001729 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1730 del_loop(mp->mnt_fsname);
1731 if (ENABLE_FEATURE_CLEAN_UP) {
1732 free(loopFile);
1733 free(mp->mnt_fsname);
1734 }
1735 }
1736
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001737 report_error:
1738 if (ENABLE_FEATURE_CLEAN_UP)
1739 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001740
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00001741 if (errno == EBUSY && ignore_busy)
1742 return 0;
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001743 if (rc != 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001744 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001745 return rc;
1746}
1747
Michael Abbott6b5accb2009-12-04 03:33:07 +01001748// -O support
1749// -O interprets a list of filter options which select whether a mount
1750// point will be mounted: only mounts with options matching *all* filtering
1751// options will be selected.
1752// By default each -O filter option must be present in the list of mount
1753// options, but if it is prefixed by "no" then it must be absent.
1754// For example,
1755// -O a,nob,c matches -o a,c but fails to match -o a,b,c
1756// (and also fails to match -o a because -o c is absent).
1757//
1758// It is different from -t in that each option is matched exactly; a leading
1759// "no" at the beginning of one option does not negate the rest.
1760static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001761{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001762 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01001763 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001764
Michael Abbott6b5accb2009-12-04 03:33:07 +01001765 while (*O_opt) {
1766 const char *fs_opt = fs_opt_in;
1767 int O_len;
1768 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001769
Michael Abbott6b5accb2009-12-04 03:33:07 +01001770 // If option begins with "no" then treat as an inverted match:
1771 // matching is a failure
1772 match = 0;
1773 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
1774 match = 1;
1775 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001776 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001777 // Isolate the current O option
1778 O_len = strchrnul(O_opt, ',') - O_opt;
1779 // Check for a match against existing options
1780 while (1) {
1781 if (strncmp(fs_opt, O_opt, O_len) == 0
1782 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
1783 ) {
1784 if (match)
1785 return 0; // "no" prefix, but option found
1786 match = 1; // current O option found, go check next one
1787 break;
1788 }
1789 fs_opt = strchr(fs_opt, ',');
1790 if (!fs_opt)
1791 break;
1792 fs_opt++;
1793 }
1794 if (match == 0)
1795 return 0; // match wanted but not found
1796 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001797 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01001798 // Step to the next O option
1799 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001800 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001801 // If we get here then everything matched
1802 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001803}
1804
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001805// Parse options, if necessary parse fstab/mtab, and call singlemount for
1806// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001807int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001808int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001809{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001810 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001811 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001812 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001813 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001814 llist_t *lst_o = NULL;
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001815 const char *fstabname;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001816 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001817 int i, j;
1818 int rc = EXIT_SUCCESS;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001819 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001820 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001821 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001822
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001823 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00001824
Denis Vlasenkof732e962008-02-18 12:07:49 +00001825 // Parse long options, like --bind and --move. Note that -o option
1826 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001827 for (i = j = 1; argv[i]; i++) {
1828 if (argv[i][0] == '-' && argv[i][1] == '-')
1829 append_mount_options(&cmdopts, argv[i] + 2);
1830 else
1831 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001832 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001833 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001834
1835 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001836 // Max 2 params; -o is a list, -v is a counter
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001837 opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001838 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001839 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001840 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00001841 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1842 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001843 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001844
1845 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001846 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00001847 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001848 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1849
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001850 if (!mountTable)
1851 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001852
Denis Vlasenko2535f122007-09-15 13:28:30 +00001853 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001854 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001855 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001856 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00001857 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001858 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001859
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001860 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001861 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1862 mtpair->mnt_dir, mtpair->mnt_type,
1863 mtpair->mnt_opts);
1864 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001865 if (ENABLE_FEATURE_CLEAN_UP)
1866 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001867 return EXIT_SUCCESS;
1868 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001869 storage_path = NULL;
1870 } else {
1871 // When we have two arguments, the second is the directory and we can
1872 // skip looking at fstab entirely. We can always abspath() the directory
1873 // argument when we get it.
1874 if (argv[1]) {
1875 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001876 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001877 mtpair->mnt_fsname = argv[0];
1878 mtpair->mnt_dir = argv[1];
1879 mtpair->mnt_type = fstype;
1880 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001881 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001882 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001883 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001884 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001885 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001886 }
1887
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001888 // Past this point, we are handling either "mount -a [opts]"
1889 // or "mount [opts] single_param"
1890
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001891 i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001892 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001893 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00001894
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001895 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001896 if (ENABLE_FEATURE_MOUNT_FLAGS
1897 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1898 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001899 // verbose_mount(source, target, type, flags, data)
1900 rc = verbose_mount("", argv[0], "", i, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001901 if (rc)
1902 bb_simple_perror_msg_and_die(argv[0]);
1903 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001904 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001905
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001906 // Open either fstab or mtab
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001907 fstabname = "/etc/fstab";
1908 if (i & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001909 // WARNING. I am not sure this matches util-linux's
1910 // behavior. It's possible util-linux does not
1911 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001912 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001913 }
1914 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001915 if (!fstab)
Denys Vlasenko651a2692010-03-23 16:25:17 +01001916 bb_perror_msg_and_die("can't read '%s'", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001917
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001918 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00001919 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001920 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001921 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001922
1923 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00001924 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001925 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001926 GETMNTENT_BUFSIZE/2)
1927 ) { // End of fstab/mtab is reached
1928 mtcur = mtother; // the thing we found last time
1929 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001930 }
1931
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001932 // If we're trying to mount something specific and this isn't it,
1933 // skip it. Note we must match the exact text in fstab (ala
1934 // "proc") or a full path from root
1935 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001936
1937 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001938 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
1939 && strcmp(storage_path, mtcur->mnt_fsname) != 0
1940 && strcmp(argv[0], mtcur->mnt_dir) != 0
1941 && strcmp(storage_path, mtcur->mnt_dir) != 0
1942 ) {
1943 continue; // no
1944 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001945
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001946 // Remember this entry. Something later may have
1947 // overmounted it, and we want the _last_ match.
1948 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001949
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001950 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001951 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001952 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001953 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001954 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001955 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001956 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001957
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001958 // Does type match? (NULL matches always)
1959 if (!match_fstype(mtcur, fstype))
1960 continue;
1961
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001962 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001963 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
1964 // swap is bogus "fstype", parse_mount_options can't check fstypes
1965 || strcasecmp(mtcur->mnt_type, "swap") == 0
1966 ) {
1967 continue;
1968 }
1969
1970 // Does (at least one) option match?
1971 // (NULL matches always)
1972 if (!match_opt(mtcur->mnt_opts, O_optmatch))
1973 continue;
1974
1975 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001976
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001977 // NFS mounts want this to be xrealloc-able
1978 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001979
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001980 // If nothing is mounted on this directory...
1981 // (otherwise repeated "mount -a" mounts everything again)
1982 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
1983 // We do not check fsname match of found mount point -
1984 // "/" may have fsname of "/dev/root" while fstab
1985 // says "/dev/something_else".
1986 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01001987 if (verbose) {
1988 bb_error_msg("according to %s, "
1989 "%s is already mounted on %s",
1990 bb_path_mtab_file,
1991 mp->mnt_fsname, mp->mnt_dir);
1992 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001993 } else {
1994 // ...mount this thing
1995 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
1996 // Count number of failed mounts
1997 rc++;
1998 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001999 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002000 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002001 }
2002 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002003
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002004 // End of fstab/mtab is reached.
2005 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002006 if (argv[0]) { // yes
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002007 long l;
2008
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002009 // If we didn't find anything, complain
2010 if (!mtcur->mnt_fsname)
2011 bb_error_msg_and_die("can't find %s in %s",
2012 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002013
2014 // What happens when we try to "mount swap_partition"?
2015 // (fstab containts "swap_partition swap swap defaults 0 0")
2016 // util-linux-ng 2.13.1 does this:
2017 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2018 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2019 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2020 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2021 // exit_group(32) = ?
2022#if 0
2023 // In case we want to simply skip swap partitions:
2024 l = parse_mount_options(mtcur->mnt_opts, NULL);
2025 if ((l & MOUNT_SWAP)
2026 // swap is bogus "fstype", parse_mount_options can't check fstypes
2027 || strcasecmp(mtcur->mnt_type, "swap") == 0
2028 ) {
2029 goto ret;
2030 }
2031#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002032 if (nonroot) {
2033 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002034 l = parse_mount_options(mtcur->mnt_opts, NULL);
2035 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002036 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002037 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002038
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002039 //util-linux-2.12 does not do this check.
2040 //// If nothing is mounted on this directory...
2041 //// (otherwise repeated "mount FOO" mounts FOO again)
2042 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2043 //if (mp) {
2044 // bb_error_msg("according to %s, "
2045 // "%s is already mounted on %s",
2046 // bb_path_mtab_file,
2047 // mp->mnt_fsname, mp->mnt_dir);
2048 //} else {
2049 // ...mount the last thing we found
2050 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2051 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2052 resolve_mount_spec(&mtpair->mnt_fsname);
2053 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2054 if (ENABLE_FEATURE_CLEAN_UP)
2055 free(mtcur->mnt_opts);
2056 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002057 }
2058
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002059 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002060 if (ENABLE_FEATURE_CLEAN_UP)
2061 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002062 if (ENABLE_FEATURE_CLEAN_UP) {
2063 free(storage_path);
2064 free(cmdopts);
2065 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002066
2067//TODO: exitcode should be ORed mask of (from "man mount"):
2068// 0 success
2069// 1 incorrect invocation or permissions
2070// 2 system error (out of memory, cannot fork, no more loop devices)
2071// 4 internal mount bug or missing nfs support in mount
2072// 8 user interrupt
2073//16 problems writing or locking /etc/mtab
2074//32 mount failure
2075//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002076 return rc;
2077}