blob: 3ac8ce093ec7894f08d2843baa3c6c34dbeb1fdb [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.
335// Also return 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++) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000351 if (!strcasecmp(option_str, options)) {
352 long fl = mount_options[i];
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000353 if (fl < 0) flags &= fl;
Rob Landleydc0955b2006-03-14 18:16:25 +0000354 else flags |= fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000355 break;
356 }
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000357 option_str += strlen(option_str) + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000358 }
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000359 // If unrecognized not NULL, append unrecognized mount options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000360 if (unrecognized && i == ARRAY_SIZE(mount_options)) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000361 // Add it to strflags, to pass on to kernel
Rob Landleydc0955b2006-03-14 18:16:25 +0000362 i = *unrecognized ? strlen(*unrecognized) : 0;
Denis Vlasenkodeeed592008-07-08 05:14:36 +0000363 *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000364
Rob Landley6a6798b2005-08-10 20:35:54 +0000365 // Comma separated if it's not the first one
Rob Landleydc0955b2006-03-14 18:16:25 +0000366 if (i) (*unrecognized)[i++] = ',';
367 strcpy((*unrecognized)+i, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000368 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000369
Denis Vlasenko2535f122007-09-15 13:28:30 +0000370 if (!comma)
371 break;
372 // Advance to next option
373 *comma = ',';
374 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000375 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000376
Rob Landleydc0955b2006-03-14 18:16:25 +0000377 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000378}
379
Rob Landleydc0955b2006-03-14 18:16:25 +0000380// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000381static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000382{
Denis Vlasenko87468852007-04-13 23:22:00 +0000383 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000384 "/etc/filesystems",
385 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000386 };
387 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200388 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000389 int i;
390 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000391
Denis Vlasenko87468852007-04-13 23:22:00 +0000392 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000393 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000394 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000395
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000396 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200397 if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
Denis Vlasenko372686b2006-10-12 22:42:33 +0000398 continue;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000399 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200400 if (*fs == '#' || *fs == '*' || !*fs)
401 continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000402
Denis Vlasenko372686b2006-10-12 22:42:33 +0000403 llist_add_to_end(&list, xstrdup(fs));
404 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000405 }
406 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
407 }
408
409 return list;
410}
411
Rob Landleydc0955b2006-03-14 18:16:25 +0000412#if ENABLE_FEATURE_CLEAN_UP
413static void delete_block_backed_filesystems(void)
414{
Rob Landleya6b5b602006-05-08 19:03:07 +0000415 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000416}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000417#else
418void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000419#endif
420
Rob Landleydc0955b2006-03-14 18:16:25 +0000421// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000422// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000423static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000424{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000425 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000426
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200427 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000428 if (verbose >= 2)
429 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
430 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
431 vfsflags, filteropts);
432 goto mtab;
433 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000434
Rob Landleydc0955b2006-03-14 18:16:25 +0000435 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000436 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000437 errno = 0;
438 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000439 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000440
441 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000442 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200443 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200444 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000445 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000446 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000447 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200448 if (FAKE_IT)
449 args[rc++] = (char *)"-f";
450 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
451 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000452 args[rc++] = mp->mnt_fsname;
453 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000454 if (filteropts) {
455 args[rc++] = (char *)"-o";
456 args[rc++] = filteropts;
457 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000458 args[rc] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +0100459 rc = spawn_and_wait(args);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000460 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000461 if (!rc)
462 break;
463 errno = errno_save;
464 }
465
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000466 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000467 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000468 if (!(vfsflags & MS_SILENT))
469 bb_error_msg("%s is write-protected, mounting read-only",
470 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000471 vfsflags |= MS_RDONLY;
472 }
473
Rob Landleydc0955b2006-03-14 18:16:25 +0000474 // Abort entirely if permission denied.
475
476 if (rc && errno == EPERM)
477 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
478
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000479 // If the mount was successful, and we're maintaining an old-style
480 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000481 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200482 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000483 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000484 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000485 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000486 int i;
487
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000488 if (!mountTable) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000489 bb_error_msg("no %s", bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000490 goto ret;
491 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000492
493 // Add vfs string flags
494
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000495 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
496 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
497 append_mount_options(&(mp->mnt_opts), option_str);
498 option_str += strlen(option_str) + 1;
499 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000500
501 // Remove trailing / (if any) from directory we mounted on
502
Denis Vlasenko727ef942006-09-14 13:19:19 +0000503 i = strlen(mp->mnt_dir) - 1;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000504 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000505
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000506 // Convert to canonical pathnames as needed
Denis Vlasenko727ef942006-09-14 13:19:19 +0000507
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000508 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000509 fsname = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000510 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000511 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000512 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000513 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000514 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000515
516 // Write and close.
517
Denis Vlasenko727ef942006-09-14 13:19:19 +0000518 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000519 endmntent(mountTable);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000520 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000521 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000522 free(fsname);
523 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000524 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000525 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000526 return rc;
527}
528
Denis Vlasenko25098f72006-09-14 15:46:33 +0000529#if ENABLE_FEATURE_MOUNT_NFS
530
531/*
532 * Linux NFS mount
533 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
534 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +0200535 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko25098f72006-09-14 15:46:33 +0000536 *
537 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
538 * numbers to be specified on the command line.
539 *
540 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
541 * Omit the call to connect() for Linux version 1.3.11 or later.
542 *
543 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
544 * Implemented the "bg", "fg" and "retry" mount options for NFS.
545 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000546 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000547 * - added Native Language Support
548 *
549 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
550 * plus NFSv3 stuff.
551 */
552
Denis Vlasenko25098f72006-09-14 15:46:33 +0000553#define MOUNTPORT 635
554#define MNTPATHLEN 1024
555#define MNTNAMLEN 255
556#define FHSIZE 32
557#define FHSIZE3 64
558
559typedef char fhandle[FHSIZE];
560
561typedef struct {
562 unsigned int fhandle3_len;
563 char *fhandle3_val;
564} fhandle3;
565
566enum mountstat3 {
567 MNT_OK = 0,
568 MNT3ERR_PERM = 1,
569 MNT3ERR_NOENT = 2,
570 MNT3ERR_IO = 5,
571 MNT3ERR_ACCES = 13,
572 MNT3ERR_NOTDIR = 20,
573 MNT3ERR_INVAL = 22,
574 MNT3ERR_NAMETOOLONG = 63,
575 MNT3ERR_NOTSUPP = 10004,
576 MNT3ERR_SERVERFAULT = 10006,
577};
578typedef enum mountstat3 mountstat3;
579
580struct fhstatus {
581 unsigned int fhs_status;
582 union {
583 fhandle fhs_fhandle;
584 } fhstatus_u;
585};
586typedef struct fhstatus fhstatus;
587
588struct mountres3_ok {
589 fhandle3 fhandle;
590 struct {
591 unsigned int auth_flavours_len;
592 char *auth_flavours_val;
593 } auth_flavours;
594};
595typedef struct mountres3_ok mountres3_ok;
596
597struct mountres3 {
598 mountstat3 fhs_status;
599 union {
600 mountres3_ok mountinfo;
601 } mountres3_u;
602};
603typedef struct mountres3 mountres3;
604
605typedef char *dirpath;
606
607typedef char *name;
608
609typedef struct mountbody *mountlist;
610
611struct mountbody {
612 name ml_hostname;
613 dirpath ml_directory;
614 mountlist ml_next;
615};
616typedef struct mountbody mountbody;
617
618typedef struct groupnode *groups;
619
620struct groupnode {
621 name gr_name;
622 groups gr_next;
623};
624typedef struct groupnode groupnode;
625
626typedef struct exportnode *exports;
627
628struct exportnode {
629 dirpath ex_dir;
630 groups ex_groups;
631 exports ex_next;
632};
633typedef struct exportnode exportnode;
634
635struct ppathcnf {
636 int pc_link_max;
637 short pc_max_canon;
638 short pc_max_input;
639 short pc_name_max;
640 short pc_path_max;
641 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000642 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000643 char pc_xxx;
644 short pc_mask[2];
645};
646typedef struct ppathcnf ppathcnf;
647
648#define MOUNTPROG 100005
649#define MOUNTVERS 1
650
651#define MOUNTPROC_NULL 0
652#define MOUNTPROC_MNT 1
653#define MOUNTPROC_DUMP 2
654#define MOUNTPROC_UMNT 3
655#define MOUNTPROC_UMNTALL 4
656#define MOUNTPROC_EXPORT 5
657#define MOUNTPROC_EXPORTALL 6
658
659#define MOUNTVERS_POSIX 2
660
661#define MOUNTPROC_PATHCONF 7
662
663#define MOUNT_V3 3
664
665#define MOUNTPROC3_NULL 0
666#define MOUNTPROC3_MNT 1
667#define MOUNTPROC3_DUMP 2
668#define MOUNTPROC3_UMNT 3
669#define MOUNTPROC3_UMNTALL 4
670#define MOUNTPROC3_EXPORT 5
671
672enum {
673#ifndef NFS_FHSIZE
674 NFS_FHSIZE = 32,
675#endif
676#ifndef NFS_PORT
677 NFS_PORT = 2049
678#endif
679};
680
Denis Vlasenko25098f72006-09-14 15:46:33 +0000681/*
682 * We want to be able to compile mount on old kernels in such a way
683 * that the binary will work well on more recent kernels.
684 * Thus, if necessary we teach nfsmount.c the structure of new fields
685 * that will come later.
686 *
687 * Moreover, the new kernel includes conflict with glibc includes
688 * so it is easiest to ignore the kernel altogether (at compile time).
689 */
690
691struct nfs2_fh {
692 char data[32];
693};
694struct nfs3_fh {
695 unsigned short size;
696 unsigned char data[64];
697};
698
699struct nfs_mount_data {
700 int version; /* 1 */
701 int fd; /* 1 */
702 struct nfs2_fh old_root; /* 1 */
703 int flags; /* 1 */
704 int rsize; /* 1 */
705 int wsize; /* 1 */
706 int timeo; /* 1 */
707 int retrans; /* 1 */
708 int acregmin; /* 1 */
709 int acregmax; /* 1 */
710 int acdirmin; /* 1 */
711 int acdirmax; /* 1 */
712 struct sockaddr_in addr; /* 1 */
713 char hostname[256]; /* 1 */
714 int namlen; /* 2 */
715 unsigned int bsize; /* 3 */
716 struct nfs3_fh root; /* 4 */
717};
718
719/* bits in the flags field */
720enum {
721 NFS_MOUNT_SOFT = 0x0001, /* 1 */
722 NFS_MOUNT_INTR = 0x0002, /* 1 */
723 NFS_MOUNT_SECURE = 0x0004, /* 1 */
724 NFS_MOUNT_POSIX = 0x0008, /* 1 */
725 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
726 NFS_MOUNT_NOAC = 0x0020, /* 1 */
727 NFS_MOUNT_TCP = 0x0040, /* 2 */
728 NFS_MOUNT_VER3 = 0x0080, /* 3 */
729 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000730 NFS_MOUNT_NONLM = 0x0200, /* 3 */
731 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +0000732};
733
734
735/*
736 * We need to translate between nfs status return values and
737 * the local errno values which may not be the same.
738 *
739 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
740 * "after #include <errno.h> the symbol errno is reserved for any use,
741 * it cannot even be used as a struct tag or field name".
742 */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000743#ifndef EDQUOT
Denys Vlasenkocc428142009-12-16 02:06:56 +0100744# define EDQUOT ENOSPC
Denis Vlasenko25098f72006-09-14 15:46:33 +0000745#endif
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000746/* Convert each NFSERR_BLAH into EBLAH */
Denys Vlasenkocc428142009-12-16 02:06:56 +0100747static const uint8_t nfs_err_stat[] = {
748 1, 2, 5, 6, 13, 17,
749 19, 20, 21, 22, 27, 28,
750 30, 63, 66, 69, 70, 71
751};
Denys Vlasenkodc1fd2e2010-05-19 17:01:29 +0200752#if ( \
753 EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
754 ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
755 EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
756typedef uint8_t nfs_err_type;
757#else
758typedef uint16_t nfs_err_type;
759#endif
760static const nfs_err_type nfs_err_errnum[] = {
Denys Vlasenkocc428142009-12-16 02:06:56 +0100761 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
762 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
763 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
Denis Vlasenko25098f72006-09-14 15:46:33 +0000764};
Denis Vlasenko25098f72006-09-14 15:46:33 +0000765static char *nfs_strerror(int status)
766{
767 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000768
Denys Vlasenkocc428142009-12-16 02:06:56 +0100769 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
770 if (nfs_err_stat[i] == status)
771 return strerror(nfs_err_errnum[i]);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000772 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000773 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000774}
775
776static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
777{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200778 return xdr_opaque(xdrs, objp, FHSIZE);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000779}
780
781static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
782{
783 if (!xdr_u_int(xdrs, &objp->fhs_status))
784 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +0200785 if (objp->fhs_status == 0)
786 return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000787 return TRUE;
788}
789
790static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
791{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200792 return xdr_string(xdrs, objp, MNTPATHLEN);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000793}
794
795static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
796{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200797 return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
798 (unsigned int *) &objp->fhandle3_len,
799 FHSIZE3);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000800}
801
802static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
803{
804 if (!xdr_fhandle3(xdrs, &objp->fhandle))
805 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +0200806 return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
807 &(objp->auth_flavours.auth_flavours_len),
808 ~0,
809 sizeof(int),
810 (xdrproc_t) xdr_int);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000811}
812
813static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
814{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200815 return xdr_enum(xdrs, (enum_t *) objp);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000816}
817
818static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
819{
820 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
821 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +0200822 if (objp->fhs_status == MNT_OK)
823 return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000824 return TRUE;
825}
826
827#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
828
Denis Vlasenko25098f72006-09-14 15:46:33 +0000829/*
830 * Unfortunately, the kernel prints annoying console messages
831 * in case of an unexpected nfs mount version (instead of
832 * just returning some error). Therefore we'll have to try
833 * and figure out what version the kernel expects.
834 *
835 * Variables:
836 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
837 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
838 * nfs_mount_version: version this source and running kernel can handle
839 */
840static void
841find_kernel_nfs_mount_version(void)
842{
Denis Vlasenkob9256052007-09-28 10:29:17 +0000843 int kernel_version;
844
845 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000846 return;
847
848 nfs_mount_version = 4; /* default */
849
850 kernel_version = get_linux_version_code();
851 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +0100852 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +0000853 nfs_mount_version = 3;
854 /* else v4 since 2.3.99pre4 */
855 }
856}
857
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000858static void
Denis Vlasenkob9256052007-09-28 10:29:17 +0000859get_mountport(struct pmap *pm_mnt,
860 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +0000861 long unsigned prog,
862 long unsigned version,
863 long unsigned proto,
864 long unsigned port)
865{
866 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000867
868 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +0000869/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
870 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000871 pmap = pmap_getmaps(server_addr);
872
873 if (version > MAX_NFSPROT)
874 version = MAX_NFSPROT;
875 if (!prog)
876 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000877 pm_mnt->pm_prog = prog;
878 pm_mnt->pm_vers = version;
879 pm_mnt->pm_prot = proto;
880 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000881
Denis Vlasenko25098f72006-09-14 15:46:33 +0000882 while (pmap) {
883 if (pmap->pml_map.pm_prog != prog)
884 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000885 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000886 goto next;
887 if (version > 2 && pmap->pml_map.pm_vers != version)
888 goto next;
889 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
890 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100891 if (pmap->pml_map.pm_vers > MAX_NFSPROT
892 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
893 || (port && pmap->pml_map.pm_port != port)
894 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +0000895 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100896 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000897 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
898 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +0000899 pmap = pmap->pml_next;
900 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000901 if (!pm_mnt->pm_vers)
902 pm_mnt->pm_vers = MOUNTVERS;
903 if (!pm_mnt->pm_port)
904 pm_mnt->pm_port = MOUNTPORT;
905 if (!pm_mnt->pm_prot)
906 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000907}
908
Denis Vlasenkof0000652007-09-04 18:30:26 +0000909#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +0000910static int daemonize(void)
911{
Denis Vlasenko25098f72006-09-14 15:46:33 +0000912 int pid = fork();
913 if (pid < 0) /* error */
914 return -errno;
915 if (pid > 0) /* parent */
916 return 0;
917 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000918 close(0);
919 xopen(bb_dev_null, O_RDWR);
920 xdup2(0, 1);
921 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000922 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000923 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000924 logmode = LOGMODE_SYSLOG;
925 return 1;
926}
Denis Vlasenkof0000652007-09-04 18:30:26 +0000927#else
928static inline int daemonize(void) { return -ENOSYS; }
929#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000930
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000931/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000932static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000933{
934 return 0;
935}
936
937/* RPC strerror analogs are terminally idiotic:
938 * *mandatory* prefix and \n at end.
939 * This hopefully helps. Usage:
940 * error_msg_rpc(clnt_*error*(" ")) */
941static void error_msg_rpc(const char *msg)
942{
Denis Vlasenko23514fe2006-09-19 14:07:52 +0000943 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000944 while (msg[0] == ' ' || msg[0] == ':') msg++;
945 len = strlen(msg);
946 while (len && msg[len-1] == '\n') len--;
947 bb_error_msg("%.*s", len, msg);
948}
949
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000950/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko810b7162009-05-13 23:48:59 +0200951static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000952{
953 CLIENT *mclient;
954 char *hostname;
955 char *pathname;
956 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +0200957 /* prior to 2.6.23, kernel took NFS options in a form of this struct
958 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
959 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000960 struct nfs_mount_data data;
961 char *opt;
962 struct hostent *hp;
963 struct sockaddr_in server_addr;
964 struct sockaddr_in mount_server_addr;
965 int msock, fsock;
966 union {
967 struct fhstatus nfsv2;
968 struct mountres3 nfsv3;
969 } status;
970 int daemonized;
971 char *s;
972 int port;
973 int mountport;
974 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000975#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000976 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000977#else
978 enum { bg = 0 };
979#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000980 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000981 int mountprog;
982 int mountvers;
983 int nfsprog;
984 int nfsvers;
985 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +0200986 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000987 smallint tcp;
988 smallint soft;
989 int intr;
990 int posix;
991 int nocto;
992 int noac;
993 int nordirplus;
994 int nolock;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000995
996 find_kernel_nfs_mount_version();
997
998 daemonized = 0;
999 mounthost = NULL;
1000 retval = ETIMEDOUT;
1001 msock = fsock = -1;
1002 mclient = NULL;
1003
1004 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1005
1006 filteropts = xstrdup(filteropts); /* going to trash it later... */
1007
1008 hostname = xstrdup(mp->mnt_fsname);
1009 /* mount_main() guarantees that ':' is there */
1010 s = strchr(hostname, ':');
1011 pathname = s + 1;
1012 *s = '\0';
1013 /* Ignore all but first hostname in replicated mounts
1014 until they can be fully supported. (mack@sgi.com) */
1015 s = strchr(hostname, ',');
1016 if (s) {
1017 *s = '\0';
1018 bb_error_msg("warning: multiple hostnames not supported");
1019 }
1020
1021 server_addr.sin_family = AF_INET;
1022 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1023 hp = gethostbyname(hostname);
1024 if (hp == NULL) {
1025 bb_herror_msg("%s", hostname);
1026 goto fail;
1027 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001028 if (hp->h_length != (int)sizeof(struct in_addr)) {
1029 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001030 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001031 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001032 }
1033
1034 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1035
1036 /* add IP address to mtab options for use when unmounting */
1037
1038 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1039 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1040 } else {
1041 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1042 mp->mnt_opts[0] ? "," : "",
1043 inet_ntoa(server_addr.sin_addr));
1044 free(mp->mnt_opts);
1045 mp->mnt_opts = tmp;
1046 }
1047
1048 /* Set default options.
1049 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1050 * let the kernel decide.
1051 * timeo is filled in after we know whether it'll be TCP or UDP. */
1052 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001053 data.retrans = 3;
1054 data.acregmin = 3;
1055 data.acregmax = 60;
1056 data.acdirmin = 30;
1057 data.acdirmax = 60;
1058 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001059
Denis Vlasenko25098f72006-09-14 15:46:33 +00001060 soft = 0;
1061 intr = 0;
1062 posix = 0;
1063 nocto = 0;
1064 nolock = 0;
1065 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001066 nordirplus = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001067 retry = 10000; /* 10000 minutes ~ 1 week */
1068 tcp = 0;
1069
1070 mountprog = MOUNTPROG;
1071 mountvers = 0;
1072 port = 0;
1073 mountport = 0;
1074 nfsprog = 100003;
1075 nfsvers = 0;
1076
1077 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001078 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001079 char *opteq = strchr(opt, '=');
1080 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001081 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001082 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001083 /* 0 */ "rsize\0"
1084 /* 1 */ "wsize\0"
1085 /* 2 */ "timeo\0"
1086 /* 3 */ "retrans\0"
1087 /* 4 */ "acregmin\0"
1088 /* 5 */ "acregmax\0"
1089 /* 6 */ "acdirmin\0"
1090 /* 7 */ "acdirmax\0"
1091 /* 8 */ "actimeo\0"
1092 /* 9 */ "retry\0"
1093 /* 10 */ "port\0"
1094 /* 11 */ "mountport\0"
1095 /* 12 */ "mounthost\0"
1096 /* 13 */ "mountprog\0"
1097 /* 14 */ "mountvers\0"
1098 /* 15 */ "nfsprog\0"
1099 /* 16 */ "nfsvers\0"
1100 /* 17 */ "vers\0"
1101 /* 18 */ "proto\0"
1102 /* 19 */ "namlen\0"
1103 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001104
1105 *opteq++ = '\0';
1106 idx = index_in_strings(options, opt);
1107 switch (idx) {
1108 case 12: // "mounthost"
1109 mounthost = xstrndup(opteq,
1110 strcspn(opteq, " \t\n\r,"));
1111 continue;
1112 case 18: // "proto"
1113 if (!strncmp(opteq, "tcp", 3))
1114 tcp = 1;
1115 else if (!strncmp(opteq, "udp", 3))
1116 tcp = 0;
1117 else
1118 bb_error_msg("warning: unrecognized proto= option");
1119 continue;
1120 case 20: // "addr" - ignore
1121 continue;
1122 }
1123
Denys Vlasenko77832482010-08-12 14:14:45 +02001124 val = xatoi_positive(opteq);
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001125 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001126 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001127 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001128 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001129 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001130 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001131 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001132 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001133 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001134 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001135 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001136 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001137 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001138 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001139 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001140 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001141 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001142 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001143 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001144 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001145 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001146 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001147 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001148 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001149 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001150 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001151 data.acregmin = val;
1152 data.acregmax = val;
1153 data.acdirmin = val;
1154 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001155 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001156 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001157 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001158 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001159 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001160 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001161 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001162 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001163 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001164 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001165 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001166 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001167 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001168 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001169 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001170 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001171 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001172 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001173 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001174 case 16: // "nfsvers"
1175 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001176 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001177 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001178 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001179 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001180 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001181 //else
1182 // bb_error_msg("warning: option namlen is not supported\n");
1183 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001184 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001185 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1186 goto fail;
1187 }
1188 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001189 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001190 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001191 "bg\0"
1192 "fg\0"
1193 "soft\0"
1194 "hard\0"
1195 "intr\0"
1196 "posix\0"
1197 "cto\0"
1198 "ac\0"
1199 "tcp\0"
1200 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001201 "lock\0"
1202 "rdirplus\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001203 int val = 1;
1204 if (!strncmp(opt, "no", 2)) {
1205 val = 0;
1206 opt += 2;
1207 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001208 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001209 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001210#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001211 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001212#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001213 break;
1214 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001215#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001216 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001217#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001218 break;
1219 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001220 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001221 break;
1222 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001223 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001224 break;
1225 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001226 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001227 break;
1228 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001229 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001230 break;
1231 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001232 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001233 break;
1234 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001235 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001236 break;
1237 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001238 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001239 break;
1240 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001241 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001242 break;
1243 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001244 if (nfs_mount_version >= 3)
1245 nolock = !val;
1246 else
1247 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001248 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001249 case 11: //rdirplus
1250 nordirplus = !val;
1251 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001252 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001253 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1254 goto fail;
1255 }
1256 }
1257 }
1258 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1259
1260 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1261 | (intr ? NFS_MOUNT_INTR : 0)
1262 | (posix ? NFS_MOUNT_POSIX : 0)
1263 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001264 | (noac ? NFS_MOUNT_NOAC : 0)
1265 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001266 if (nfs_mount_version >= 2)
1267 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1268 if (nfs_mount_version >= 3)
1269 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1270 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1271 bb_error_msg("NFSv%d not supported", nfsvers);
1272 goto fail;
1273 }
1274 if (nfsvers && !mountvers)
1275 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1276 if (nfsvers && nfsvers < mountvers) {
1277 mountvers = nfsvers;
1278 }
1279
1280 /* Adjust options if none specified */
1281 if (!data.timeo)
1282 data.timeo = tcp ? 70 : 7;
1283
Denis Vlasenko25098f72006-09-14 15:46:33 +00001284 data.version = nfs_mount_version;
1285
1286 if (vfsflags & MS_REMOUNT)
1287 goto do_mount;
1288
1289 /*
1290 * If the previous mount operation on the same host was
1291 * backgrounded, and the "bg" for this mount is also set,
1292 * give up immediately, to avoid the initial timeout.
1293 */
1294 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001295 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001296 if (daemonized <= 0) { /* parent or error */
1297 retval = -daemonized;
1298 goto ret;
1299 }
1300 }
1301
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001302 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001303 /* See if the nfs host = mount host. */
1304 if (mounthost) {
1305 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1306 mount_server_addr.sin_family = AF_INET;
1307 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1308 } else {
1309 hp = gethostbyname(mounthost);
1310 if (hp == NULL) {
1311 bb_herror_msg("%s", mounthost);
1312 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001313 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001314 if (hp->h_length != (int)sizeof(struct in_addr)) {
1315 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001316 }
1317 mount_server_addr.sin_family = AF_INET;
Denys Vlasenko99069332010-02-27 19:38:19 +01001318 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001319 }
1320 }
1321
1322 /*
1323 * The following loop implements the mount retries. When the mount
1324 * times out, and the "bg" option is set, we background ourself
1325 * and continue trying.
1326 *
1327 * The case where the mount point is not present and the "bg"
1328 * option is set, is treated as a timeout. This is done to
1329 * support nested mounts.
1330 *
1331 * The "retry" count specified by the user is the number of
1332 * minutes to retry before giving up.
1333 */
1334 {
1335 struct timeval total_timeout;
1336 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001337 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001338 time_t t;
1339 time_t prevt;
1340 time_t timeout;
1341
1342 retry_timeout.tv_sec = 3;
1343 retry_timeout.tv_usec = 0;
1344 total_timeout.tv_sec = 20;
1345 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001346/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001347 timeout = time(NULL) + 60 * retry;
1348 prevt = 0;
1349 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001350 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001351 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001352 if (t - prevt < 30)
1353 sleep(30);
1354
Denis Vlasenkob9256052007-09-28 10:29:17 +00001355 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001356 mountprog,
1357 mountvers,
1358 proto,
1359 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001360 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001361
1362 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001363 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001364 msock = RPC_ANYSOCK;
1365
Denis Vlasenkob9256052007-09-28 10:29:17 +00001366 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001367 case IPPROTO_UDP:
1368 mclient = clntudp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001369 pm_mnt.pm_prog,
1370 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001371 retry_timeout,
1372 &msock);
1373 if (mclient)
1374 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001375 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001376 msock = RPC_ANYSOCK;
1377 case IPPROTO_TCP:
1378 mclient = clnttcp_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 &msock, 0, 0);
1382 break;
1383 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001384 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001385 }
1386 if (!mclient) {
1387 if (!daemonized && prevt == 0)
1388 error_msg_rpc(clnt_spcreateerror(" "));
1389 } else {
1390 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001391
1392 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001393 mclient->cl_auth = authunix_create_default();
1394
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001395 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001396 * that xdr_array allocates memory for us
1397 */
1398 memset(&status, 0, sizeof(status));
1399
Denis Vlasenkob9256052007-09-28 10:29:17 +00001400 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001401 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1402 (xdrproc_t) xdr_dirpath,
1403 (caddr_t) &pathname,
1404 (xdrproc_t) xdr_mountres3,
1405 (caddr_t) &status,
1406 total_timeout);
1407 else
1408 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1409 (xdrproc_t) xdr_dirpath,
1410 (caddr_t) &pathname,
1411 (xdrproc_t) xdr_fhstatus,
1412 (caddr_t) &status,
1413 total_timeout);
1414
1415 if (clnt_stat == RPC_SUCCESS)
1416 goto prepare_kernel_data; /* we're done */
1417 if (errno != ECONNREFUSED) {
1418 error_msg_rpc(clnt_sperror(mclient, " "));
1419 goto fail; /* don't retry */
1420 }
1421 /* Connection refused */
1422 if (!daemonized && prevt == 0) /* print just once */
1423 error_msg_rpc(clnt_sperror(mclient, " "));
1424 auth_destroy(mclient->cl_auth);
1425 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001426 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001427 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001428 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001429 }
1430
1431 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001432 if (!bg)
1433 goto fail;
1434 if (!daemonized) {
1435 daemonized = daemonize();
1436 if (daemonized <= 0) { /* parent or error */
1437 retval = -daemonized;
1438 goto ret;
1439 }
1440 }
1441 prevt = t;
1442 t = time(NULL);
1443 if (t >= timeout)
1444 /* TODO error message */
1445 goto fail;
1446
1447 goto retry;
1448 }
1449
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001450 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001451
1452 if (nfsvers == 2) {
1453 if (status.nfsv2.fhs_status != 0) {
1454 bb_error_msg("%s:%s failed, reason given by server: %s",
1455 hostname, pathname,
1456 nfs_strerror(status.nfsv2.fhs_status));
1457 goto fail;
1458 }
1459 memcpy(data.root.data,
1460 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1461 NFS_FHSIZE);
1462 data.root.size = NFS_FHSIZE;
1463 memcpy(data.old_root.data,
1464 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1465 NFS_FHSIZE);
1466 } else {
1467 fhandle3 *my_fhandle;
1468 if (status.nfsv3.fhs_status != 0) {
1469 bb_error_msg("%s:%s failed, reason given by server: %s",
1470 hostname, pathname,
1471 nfs_strerror(status.nfsv3.fhs_status));
1472 goto fail;
1473 }
1474 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1475 memset(data.old_root.data, 0, NFS_FHSIZE);
1476 memset(&data.root, 0, sizeof(data.root));
1477 data.root.size = my_fhandle->fhandle3_len;
1478 memcpy(data.root.data,
1479 (char *) my_fhandle->fhandle3_val,
1480 my_fhandle->fhandle3_len);
1481
1482 data.flags |= NFS_MOUNT_VER3;
1483 }
1484
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001485 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001486 if (tcp) {
1487 if (nfs_mount_version < 3) {
1488 bb_error_msg("NFS over TCP is not supported");
1489 goto fail;
1490 }
1491 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1492 } else
1493 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1494 if (fsock < 0) {
1495 bb_perror_msg("nfs socket");
1496 goto fail;
1497 }
1498 if (bindresvport(fsock, 0) < 0) {
1499 bb_perror_msg("nfs bindresvport");
1500 goto fail;
1501 }
1502 if (port == 0) {
1503 server_addr.sin_port = PMAPPORT;
1504 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1505 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1506 if (port == 0)
1507 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001508 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001509 server_addr.sin_port = htons(port);
1510
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001511 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001512 data.fd = fsock;
1513 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1514 strncpy(data.hostname, hostname, sizeof(data.hostname));
1515
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001516 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001517 auth_destroy(mclient->cl_auth);
1518 clnt_destroy(mclient);
1519 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001520 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001521
1522 if (bg) {
1523 /* We must wait until mount directory is available */
1524 struct stat statbuf;
1525 int delay = 1;
1526 while (stat(mp->mnt_dir, &statbuf) == -1) {
1527 if (!daemonized) {
1528 daemonized = daemonize();
1529 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001530/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001531 retval = -daemonized;
1532 goto ret;
1533 }
1534 }
1535 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1536 delay *= 2;
1537 if (delay > 30)
1538 delay = 30;
1539 }
1540 }
1541
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001542 /* Perform actual mount */
1543 do_mount:
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001544 mp->mnt_type = (char*)"nfs";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001545 retval = mount_it_now(mp, vfsflags, (char*)&data);
1546 goto ret;
1547
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001548 /* Abort */
1549 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001550 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001551 if (mclient) {
1552 auth_destroy(mclient->cl_auth);
1553 clnt_destroy(mclient);
1554 }
1555 close(msock);
1556 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001557 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001558 close(fsock);
1559
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001560 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001561 free(hostname);
1562 free(mounthost);
1563 free(filteropts);
1564 return retval;
1565}
1566
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001567#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001568
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001569// Never called. Call should be optimized out.
Denis Vlasenkob4133682008-02-18 13:05:38 +00001570int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001571
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001572#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001573
1574// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1575// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001576// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001577static int singlemount(struct mntent *mp, int ignore_busy)
1578{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001579 int rc = -1;
1580 long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001581 char *loopFile = NULL, *filteropts = NULL;
1582 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001583 struct stat st;
1584
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001585 errno = 0;
1586
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001587 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1588
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001589 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001590 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1591 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001592
Denis Vlasenko2535f122007-09-15 13:28:30 +00001593 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001594 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1595 char *args[35];
1596 char *s;
1597 int n;
1598 // fsname: "cmd#arg1#arg2..."
1599 // WARNING: allows execution of arbitrary commands!
1600 // Try "mount 'sh#-c#sh' bogus_dir".
1601 // It is safe ONLY because non-root
1602 // cannot use two-argument mount command
1603 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1604 // "mount: can't find sh#-c#sh in /etc/fstab"
1605 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1606
1607 s = mp->mnt_fsname;
1608 n = 0;
1609 args[n++] = s;
1610 while (*s && n < 35 - 2) {
1611 if (*s++ == '#' && *s != '#') {
1612 s[-1] = '\0';
1613 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001614 }
1615 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001616 args[n++] = mp->mnt_dir;
1617 args[n] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +01001618 rc = spawn_and_wait(args);
Denis Vlasenko2535f122007-09-15 13:28:30 +00001619 goto report_error;
1620 }
1621
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001622 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001623 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001624 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1625 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1626 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001627 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001628 int len;
1629 char c;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001630 len_and_sockaddr *lsa;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001631 char *hostname, *dotted, *ip;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001632
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001633 hostname = mp->mnt_fsname + 2;
1634 len = strcspn(hostname, "/\\");
1635 if (len == 0 || hostname[len] == '\0')
Denis Vlasenko5c329932009-04-12 12:16:21 +00001636 goto report_error;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001637 c = hostname[len];
1638 hostname[len] = '\0';
1639 lsa = host2sockaddr(hostname, 0);
1640 hostname[len] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001641 if (!lsa)
1642 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001643
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001644 // Insert "ip=..." option into options
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001645 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001646 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001647 ip = xasprintf("ip=%s", dotted);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001648 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001649 parse_mount_options(ip, &filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001650 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001651
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001652 // "-o mand" is required [why?]
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001653 vfsflags |= MS_MANDLOCK;
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001654 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001655 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001656
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001657 goto report_error;
1658 }
1659
1660 // Might this be an NFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001661 if (ENABLE_FEATURE_MOUNT_NFS
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001662 && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001663 && strchr(mp->mnt_fsname, ':') != NULL
1664 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001665 rc = nfsmount(mp, vfsflags, filteropts);
1666 goto report_error;
1667 }
1668
1669 // Look at the file. (Not found isn't a failure for remount, or for
1670 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001671 // (We use stat, not lstat, in order to allow
1672 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001673 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001674 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1675 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001676 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001677 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1678 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001679 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001680 if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001681 if (errno == EPERM || errno == EACCES)
1682 bb_error_msg(bb_msg_perm_denied_are_you_root);
1683 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01001684 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00001685 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001686 }
1687
1688 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001689 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1690 vfsflags |= MS_BIND;
1691 }
1692
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001693 // If we know the fstype (or don't need to), jump straight
1694 // to the actual mount.
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001695 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001696 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001697 } else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001698 // Loop through filesystem types until mount succeeds
1699 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001700
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001701 // Initialize list of block backed filesystems.
1702 // This has to be done here so that during "mount -a",
1703 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001704 if (!fslist) {
1705 fslist = get_block_backed_filesystems();
1706 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1707 atexit(delete_block_backed_filesystems);
1708 }
1709
1710 for (fl = fslist; fl; fl = fl->link) {
1711 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00001712 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001713 if (!rc)
1714 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001715 }
1716 }
1717
1718 // If mount failed, clean up loop file (if any).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001719 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1720 del_loop(mp->mnt_fsname);
1721 if (ENABLE_FEATURE_CLEAN_UP) {
1722 free(loopFile);
1723 free(mp->mnt_fsname);
1724 }
1725 }
1726
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001727 report_error:
1728 if (ENABLE_FEATURE_CLEAN_UP)
1729 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001730
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00001731 if (errno == EBUSY && ignore_busy)
1732 return 0;
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001733 if (rc != 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001734 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001735 return rc;
1736}
1737
Michael Abbott6b5accb2009-12-04 03:33:07 +01001738// -O support
1739// -O interprets a list of filter options which select whether a mount
1740// point will be mounted: only mounts with options matching *all* filtering
1741// options will be selected.
1742// By default each -O filter option must be present in the list of mount
1743// options, but if it is prefixed by "no" then it must be absent.
1744// For example,
1745// -O a,nob,c matches -o a,c but fails to match -o a,b,c
1746// (and also fails to match -o a because -o c is absent).
1747//
1748// It is different from -t in that each option is matched exactly; a leading
1749// "no" at the beginning of one option does not negate the rest.
1750static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001751{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001752 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01001753 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001754
Michael Abbott6b5accb2009-12-04 03:33:07 +01001755 while (*O_opt) {
1756 const char *fs_opt = fs_opt_in;
1757 int O_len;
1758 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001759
Michael Abbott6b5accb2009-12-04 03:33:07 +01001760 // If option begins with "no" then treat as an inverted match:
1761 // matching is a failure
1762 match = 0;
1763 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
1764 match = 1;
1765 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001766 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001767 // Isolate the current O option
1768 O_len = strchrnul(O_opt, ',') - O_opt;
1769 // Check for a match against existing options
1770 while (1) {
1771 if (strncmp(fs_opt, O_opt, O_len) == 0
1772 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
1773 ) {
1774 if (match)
1775 return 0; // "no" prefix, but option found
1776 match = 1; // current O option found, go check next one
1777 break;
1778 }
1779 fs_opt = strchr(fs_opt, ',');
1780 if (!fs_opt)
1781 break;
1782 fs_opt++;
1783 }
1784 if (match == 0)
1785 return 0; // match wanted but not found
1786 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001787 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01001788 // Step to the next O option
1789 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001790 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001791 // If we get here then everything matched
1792 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001793}
1794
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001795// Parse options, if necessary parse fstab/mtab, and call singlemount for
1796// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001797int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001798int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001799{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001800 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001801 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001802 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001803 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001804 llist_t *lst_o = NULL;
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001805 const char *fstabname;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001806 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001807 int i, j;
1808 int rc = EXIT_SUCCESS;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001809 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001810 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001811 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001812
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001813 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00001814
Denis Vlasenkof732e962008-02-18 12:07:49 +00001815 // Parse long options, like --bind and --move. Note that -o option
1816 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001817 for (i = j = 1; argv[i]; i++) {
1818 if (argv[i][0] == '-' && argv[i][1] == '-')
1819 append_mount_options(&cmdopts, argv[i] + 2);
1820 else
1821 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001822 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001823 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001824
1825 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001826 // Max 2 params; -o is a list, -v is a counter
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001827 opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001828 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001829 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001830 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00001831 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1832 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001833 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001834
1835 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001836 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00001837 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001838 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1839
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001840 if (!mountTable)
1841 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001842
Denis Vlasenko2535f122007-09-15 13:28:30 +00001843 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001844 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001845 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001846 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00001847 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001848 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001849
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001850 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001851 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1852 mtpair->mnt_dir, mtpair->mnt_type,
1853 mtpair->mnt_opts);
1854 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001855 if (ENABLE_FEATURE_CLEAN_UP)
1856 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001857 return EXIT_SUCCESS;
1858 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001859 storage_path = NULL;
1860 } else {
1861 // When we have two arguments, the second is the directory and we can
1862 // skip looking at fstab entirely. We can always abspath() the directory
1863 // argument when we get it.
1864 if (argv[1]) {
1865 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001866 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001867 mtpair->mnt_fsname = argv[0];
1868 mtpair->mnt_dir = argv[1];
1869 mtpair->mnt_type = fstype;
1870 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001871 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001872 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001873 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001874 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001875 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001876 }
1877
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001878 // Past this point, we are handling either "mount -a [opts]"
1879 // or "mount [opts] single_param"
1880
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001881 i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001882 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001883 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00001884
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001885 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001886 if (ENABLE_FEATURE_MOUNT_FLAGS
1887 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1888 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001889 // verbose_mount(source, target, type, flags, data)
1890 rc = verbose_mount("", argv[0], "", i, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001891 if (rc)
1892 bb_simple_perror_msg_and_die(argv[0]);
1893 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001894 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001895
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001896 // Open either fstab or mtab
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001897 fstabname = "/etc/fstab";
1898 if (i & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001899 // WARNING. I am not sure this matches util-linux's
1900 // behavior. It's possible util-linux does not
1901 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001902 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001903 }
1904 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001905 if (!fstab)
Denys Vlasenko651a2692010-03-23 16:25:17 +01001906 bb_perror_msg_and_die("can't read '%s'", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001907
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001908 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00001909 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001910 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001911 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001912
1913 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00001914 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001915 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001916 GETMNTENT_BUFSIZE/2)
1917 ) { // End of fstab/mtab is reached
1918 mtcur = mtother; // the thing we found last time
1919 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001920 }
1921
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001922 // If we're trying to mount something specific and this isn't it,
1923 // skip it. Note we must match the exact text in fstab (ala
1924 // "proc") or a full path from root
1925 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001926
1927 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001928 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
1929 && strcmp(storage_path, mtcur->mnt_fsname) != 0
1930 && strcmp(argv[0], mtcur->mnt_dir) != 0
1931 && strcmp(storage_path, mtcur->mnt_dir) != 0
1932 ) {
1933 continue; // no
1934 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001935
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001936 // Remember this entry. Something later may have
1937 // overmounted it, and we want the _last_ match.
1938 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001939
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001940 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001941 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001942 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001943 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001944 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001945 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001946 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001947
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001948 // Does type match? (NULL matches always)
1949 if (!match_fstype(mtcur, fstype))
1950 continue;
1951
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001952 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001953 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
1954 // swap is bogus "fstype", parse_mount_options can't check fstypes
1955 || strcasecmp(mtcur->mnt_type, "swap") == 0
1956 ) {
1957 continue;
1958 }
1959
1960 // Does (at least one) option match?
1961 // (NULL matches always)
1962 if (!match_opt(mtcur->mnt_opts, O_optmatch))
1963 continue;
1964
1965 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001966
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001967 // NFS mounts want this to be xrealloc-able
1968 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001969
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001970 // If nothing is mounted on this directory...
1971 // (otherwise repeated "mount -a" mounts everything again)
1972 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
1973 // We do not check fsname match of found mount point -
1974 // "/" may have fsname of "/dev/root" while fstab
1975 // says "/dev/something_else".
1976 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01001977 if (verbose) {
1978 bb_error_msg("according to %s, "
1979 "%s is already mounted on %s",
1980 bb_path_mtab_file,
1981 mp->mnt_fsname, mp->mnt_dir);
1982 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001983 } else {
1984 // ...mount this thing
1985 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
1986 // Count number of failed mounts
1987 rc++;
1988 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001989 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001990 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001991 }
1992 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001993
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001994 // End of fstab/mtab is reached.
1995 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001996 if (argv[0]) { // yes
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001997 long l;
1998
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001999 // If we didn't find anything, complain
2000 if (!mtcur->mnt_fsname)
2001 bb_error_msg_and_die("can't find %s in %s",
2002 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002003
2004 // What happens when we try to "mount swap_partition"?
2005 // (fstab containts "swap_partition swap swap defaults 0 0")
2006 // util-linux-ng 2.13.1 does this:
2007 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2008 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2009 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2010 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2011 // exit_group(32) = ?
2012#if 0
2013 // In case we want to simply skip swap partitions:
2014 l = parse_mount_options(mtcur->mnt_opts, NULL);
2015 if ((l & MOUNT_SWAP)
2016 // swap is bogus "fstype", parse_mount_options can't check fstypes
2017 || strcasecmp(mtcur->mnt_type, "swap") == 0
2018 ) {
2019 goto ret;
2020 }
2021#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002022 if (nonroot) {
2023 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002024 l = parse_mount_options(mtcur->mnt_opts, NULL);
2025 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002026 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002027 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002028
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002029 //util-linux-2.12 does not do this check.
2030 //// If nothing is mounted on this directory...
2031 //// (otherwise repeated "mount FOO" mounts FOO again)
2032 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2033 //if (mp) {
2034 // bb_error_msg("according to %s, "
2035 // "%s is already mounted on %s",
2036 // bb_path_mtab_file,
2037 // mp->mnt_fsname, mp->mnt_dir);
2038 //} else {
2039 // ...mount the last thing we found
2040 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2041 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2042 resolve_mount_spec(&mtpair->mnt_fsname);
2043 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2044 if (ENABLE_FEATURE_CLEAN_UP)
2045 free(mtcur->mnt_opts);
2046 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002047 }
2048
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002049 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002050 if (ENABLE_FEATURE_CLEAN_UP)
2051 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002052 if (ENABLE_FEATURE_CLEAN_UP) {
2053 free(storage_path);
2054 free(cmdopts);
2055 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002056
2057//TODO: exitcode should be ORed mask of (from "man mount"):
2058// 0 success
2059// 1 incorrect invocation or permissions
2060// 2 system error (out of memory, cannot fork, no more loop devices)
2061// 4 internal mount bug or missing nfs support in mount
2062// 8 user interrupt
2063//16 problems writing or locking /etc/mtab
2064//32 mount failure
2065//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002066 return rc;
2067}