blob: 9d87f766c3b1980fcf23aee460ef7afff7cb3bfa [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002/*
Eric Andersen596e5461999-10-07 08:30:23 +00003 * Mini mount implementation for busybox
4 *
Eric Andersenc4996011999-10-20 22:08:37 +00005 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00006 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Rob Landleydc0955b2006-03-14 18:16:25 +00007 * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
Eric Andersen596e5461999-10-07 08:30:23 +00008 *
Rob Landley7b363fd2005-12-20 17:18:01 +00009 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Erik Andersenb7cc49d2000-01-13 06:38:14 +000010 */
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
69#include <rpc/rpc.h>
70#include <rpc/pmap_prot.h>
71#include <rpc/pmap_clnt.h>
72
73
Denis Vlasenko908d6b72006-12-18 23:07:42 +000074#if defined(__dietlibc__)
Denis Vlasenko30e5cf82008-12-05 16:40:36 +000075// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
76// dietlibc-0.30 does not have implementation of getmntent_r()
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +000077static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000078 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
Denis Vlasenko908d6b72006-12-18 23:07:42 +000079{
Denis Vlasenko908d6b72006-12-18 23:07:42 +000080 struct mntent* ment = getmntent(stream);
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +000081 return memcpy(result, ment, sizeof(*ment));
Denis Vlasenko908d6b72006-12-18 23:07:42 +000082}
83#endif
84
85
Rob Landleydc0955b2006-03-14 18:16:25 +000086// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +000087enum {
Denis Vlasenkoa4522c52008-03-17 08:46:43 +000088 MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
89 MOUNT_NOAUTO = (1 << 29),
90 MOUNT_SWAP = (1 << 30),
Denis Vlasenko13c5a682006-10-16 22:39:51 +000091};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +000092
93
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +000094#define OPTION_STR "o:t:rwanfvsiO:"
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +000095enum {
96 OPT_o = (1 << 0),
97 OPT_t = (1 << 1),
98 OPT_r = (1 << 2),
99 OPT_w = (1 << 3),
100 OPT_a = (1 << 4),
101 OPT_n = (1 << 5),
102 OPT_f = (1 << 6),
103 OPT_v = (1 << 7),
104 OPT_s = (1 << 8),
105 OPT_i = (1 << 9),
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000106 OPT_O = (1 << 10),
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000107};
108
109#if ENABLE_FEATURE_MTAB_SUPPORT
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200110#define USE_MTAB (!(option_mask32 & OPT_n))
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000111#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200112#define USE_MTAB 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000113#endif
114
115#if ENABLE_FEATURE_MOUNT_FAKE
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200116#define FAKE_IT (option_mask32 & OPT_f)
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000117#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200118#define FAKE_IT 0
119#endif
120
121#if ENABLE_FEATURE_MOUNT_HELPERS
122#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
123#else
124#define HELPERS_ALLOWED 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000125#endif
126
127
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000128// TODO: more "user" flag compatibility.
129// "user" option (from mount manpage):
130// Only the user that mounted a filesystem can unmount it again.
131// If any user should be able to unmount, then use users instead of user
132// in the fstab line. The owner option is similar to the user option,
133// with the restriction that the user must be the owner of the special file.
134// This may be useful e.g. for /dev/fd if a login script makes
135// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000136
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000137// Standard mount options (from -o options or --options),
138// with corresponding flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000139static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000140 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000141
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000142 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000143 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000144 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000145
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000146 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000147 /* "defaults" */ 0,
148 /* "quiet" 0 - do not filter out, vfat wants to see it */
149 /* "noauto" */ MOUNT_NOAUTO,
150 /* "sw" */ MOUNT_SWAP,
151 /* "swap" */ MOUNT_SWAP,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000152 IF_DESKTOP(/* "user" */ MOUNT_USERS,)
153 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000154 /* "_netdev" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000155 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000156
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000157 IF_FEATURE_MOUNT_FLAGS(
Rob Landleye3781b72006-08-08 01:39:49 +0000158 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000159 /* "nosuid" */ MS_NOSUID,
160 /* "suid" */ ~MS_NOSUID,
161 /* "dev" */ ~MS_NODEV,
162 /* "nodev" */ MS_NODEV,
163 /* "exec" */ ~MS_NOEXEC,
164 /* "noexec" */ MS_NOEXEC,
165 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000166 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000167 /* "async" */ ~MS_SYNCHRONOUS,
168 /* "atime" */ ~MS_NOATIME,
169 /* "noatime" */ MS_NOATIME,
170 /* "diratime" */ ~MS_NODIRATIME,
171 /* "nodiratime" */ MS_NODIRATIME,
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000172 /* "mand" */ MS_MANDLOCK,
173 /* "nomand" */ ~MS_MANDLOCK,
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000174 /* "relatime" */ MS_RELATIME,
175 /* "norelatime" */ ~MS_RELATIME,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000176 /* "loud" */ ~MS_SILENT,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000177
Rob Landleye3781b72006-08-08 01:39:49 +0000178 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200179 /* "union" */ MS_UNION,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000180 /* "bind" */ MS_BIND,
181 /* "move" */ MS_MOVE,
182 /* "shared" */ MS_SHARED,
183 /* "slave" */ MS_SLAVE,
184 /* "private" */ MS_PRIVATE,
185 /* "unbindable" */ MS_UNBINDABLE,
186 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
187 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
188 /* "rprivate" */ MS_SLAVE|MS_RECURSIVE,
189 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000190 )
191
192 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000193 /* "ro" */ MS_RDONLY, // vfs flag
194 /* "rw" */ ~MS_RDONLY, // vfs flag
195 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000196};
197
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000198static const char mount_option_str[] =
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000199 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000200 "loop\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000201 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000202 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000203 "defaults\0"
204 // "quiet\0" - do not filter out, vfat wants to see it
205 "noauto\0"
206 "sw\0"
207 "swap\0"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000208 IF_DESKTOP("user\0")
209 IF_DESKTOP("users\0")
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000210 "_netdev\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000211 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000212 IF_FEATURE_MOUNT_FLAGS(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000213 // vfs flags
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000214 "nosuid\0"
215 "suid\0"
216 "dev\0"
217 "nodev\0"
218 "exec\0"
219 "noexec\0"
220 "sync\0"
221 "dirsync\0"
222 "async\0"
223 "atime\0"
224 "noatime\0"
225 "diratime\0"
226 "nodiratime\0"
227 "mand\0"
228 "nomand\0"
229 "relatime\0"
230 "norelatime\0"
231 "loud\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000232
233 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200234 "union\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000235 "bind\0"
236 "move\0"
237 "shared\0"
238 "slave\0"
239 "private\0"
240 "unbindable\0"
241 "rshared\0"
242 "rslave\0"
243 "rprivate\0"
244 "runbindable\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000245 )
246
247 // Always understood.
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000248 "ro\0" // vfs flag
249 "rw\0" // vfs flag
250 "remount\0" // action flag
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000251;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000252
Denis Vlasenkof732e962008-02-18 12:07:49 +0000253
254struct globals {
255#if ENABLE_FEATURE_MOUNT_NFS
256 smalluint nfs_mount_version;
257#endif
258#if ENABLE_FEATURE_MOUNT_VERBOSE
259 unsigned verbose;
260#endif
261 llist_t *fslist;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000262 char getmntent_buf[1];
Denis Vlasenkof732e962008-02-18 12:07:49 +0000263
264};
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000265enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
Denis Vlasenkof732e962008-02-18 12:07:49 +0000266#define G (*(struct globals*)&bb_common_bufsiz1)
267#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000268#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000269#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000270#else
271#define verbose 0
272#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000273#define fslist (G.fslist )
274#define getmntent_buf (G.getmntent_buf )
275
276
277#if ENABLE_FEATURE_MOUNT_VERBOSE
278static int verbose_mount(const char *source, const char *target,
279 const char *filesystemtype,
280 unsigned long mountflags, const void *data)
281{
282 int rc;
283
284 errno = 0;
285 rc = mount(source, target, filesystemtype, mountflags, data);
286 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000287 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000288 source, target, filesystemtype,
289 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000290 return rc;
291}
292#else
293#define verbose_mount(...) mount(__VA_ARGS__)
294#endif
295
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000296// Append mount options to string
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000297static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000298{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000299 if (*oldopts && **oldopts) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000300 // Do not insert options which are already there
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000301 while (newopts[0]) {
302 char *p;
303 int len = strlen(newopts);
304 p = strchr(newopts, ',');
305 if (p) len = p - newopts;
306 p = *oldopts;
307 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000308 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000309 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000310 goto skip;
311 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000312 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000313 p++;
314 }
315 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
316 free(*oldopts);
317 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000318 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000319 newopts += len;
320 while (newopts[0] == ',') newopts++;
321 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000322 } else {
323 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000324 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000325 }
326}
327
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000328// Use the mount_options list to parse options into flags.
329// Also return list of unrecognized options if unrecognized != NULL
Denis Vlasenkob4133682008-02-18 13:05:38 +0000330static long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000331{
Denis Vlasenkob4133682008-02-18 13:05:38 +0000332 long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000333
Rob Landley6a6798b2005-08-10 20:35:54 +0000334 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000335 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000336 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000337 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000338 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000339
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000340 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000341
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000342// FIXME: use hasmntopt()
Rob Landley6a6798b2005-08-10 20:35:54 +0000343 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000344 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000345 if (!strcasecmp(option_str, options)) {
346 long fl = mount_options[i];
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000347 if (fl < 0) flags &= fl;
Rob Landleydc0955b2006-03-14 18:16:25 +0000348 else flags |= fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000349 break;
350 }
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000351 option_str += strlen(option_str) + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000352 }
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000353 // If unrecognized not NULL, append unrecognized mount options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000354 if (unrecognized && i == ARRAY_SIZE(mount_options)) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000355 // Add it to strflags, to pass on to kernel
Rob Landleydc0955b2006-03-14 18:16:25 +0000356 i = *unrecognized ? strlen(*unrecognized) : 0;
Denis Vlasenkodeeed592008-07-08 05:14:36 +0000357 *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000358
Rob Landley6a6798b2005-08-10 20:35:54 +0000359 // Comma separated if it's not the first one
Rob Landleydc0955b2006-03-14 18:16:25 +0000360 if (i) (*unrecognized)[i++] = ',';
361 strcpy((*unrecognized)+i, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000362 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000363
Denis Vlasenko2535f122007-09-15 13:28:30 +0000364 if (!comma)
365 break;
366 // Advance to next option
367 *comma = ',';
368 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000369 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000370
Rob Landleydc0955b2006-03-14 18:16:25 +0000371 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000372}
373
Rob Landleydc0955b2006-03-14 18:16:25 +0000374// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000375static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000376{
Denis Vlasenko87468852007-04-13 23:22:00 +0000377 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000378 "/etc/filesystems",
379 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000380 };
381 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200382 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000383 int i;
384 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000385
Denis Vlasenko87468852007-04-13 23:22:00 +0000386 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000387 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000388 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000389
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000390 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200391 if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
Denis Vlasenko372686b2006-10-12 22:42:33 +0000392 continue;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000393 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200394 if (*fs == '#' || *fs == '*' || !*fs)
395 continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000396
Denis Vlasenko372686b2006-10-12 22:42:33 +0000397 llist_add_to_end(&list, xstrdup(fs));
398 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000399 }
400 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
401 }
402
403 return list;
404}
405
Rob Landleydc0955b2006-03-14 18:16:25 +0000406#if ENABLE_FEATURE_CLEAN_UP
407static void delete_block_backed_filesystems(void)
408{
Rob Landleya6b5b602006-05-08 19:03:07 +0000409 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000410}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000411#else
412void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000413#endif
414
Rob Landleydc0955b2006-03-14 18:16:25 +0000415// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000416// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000417static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000418{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000419 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000420
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200421 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000422 if (verbose >= 2)
423 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
424 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
425 vfsflags, filteropts);
426 goto mtab;
427 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000428
Rob Landleydc0955b2006-03-14 18:16:25 +0000429 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000430 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000431 errno = 0;
432 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000433 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000434
435 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000436 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200437 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200438 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000439 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000440 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000441 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200442 if (FAKE_IT)
443 args[rc++] = (char *)"-f";
444 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
445 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000446 args[rc++] = mp->mnt_fsname;
447 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000448 if (filteropts) {
449 args[rc++] = (char *)"-o";
450 args[rc++] = filteropts;
451 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000452 args[rc] = NULL;
453 rc = wait4pid(spawn(args));
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000454 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000455 if (!rc)
456 break;
457 errno = errno_save;
458 }
459
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000460 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000461 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000462 if (!(vfsflags & MS_SILENT))
463 bb_error_msg("%s is write-protected, mounting read-only",
464 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000465 vfsflags |= MS_RDONLY;
466 }
467
Rob Landleydc0955b2006-03-14 18:16:25 +0000468 // Abort entirely if permission denied.
469
470 if (rc && errno == EPERM)
471 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
472
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000473 // If the mount was successful, and we're maintaining an old-style
474 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000475 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200476 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000477 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000478 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000479 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000480 int i;
481
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000482 if (!mountTable) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000483 bb_error_msg("no %s", bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000484 goto ret;
485 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000486
487 // Add vfs string flags
488
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000489 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
490 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
491 append_mount_options(&(mp->mnt_opts), option_str);
492 option_str += strlen(option_str) + 1;
493 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000494
495 // Remove trailing / (if any) from directory we mounted on
496
Denis Vlasenko727ef942006-09-14 13:19:19 +0000497 i = strlen(mp->mnt_dir) - 1;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000498 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000499
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000500 // Convert to canonical pathnames as needed
Denis Vlasenko727ef942006-09-14 13:19:19 +0000501
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000502 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000503 fsname = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000504 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000505 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000506 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000507 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000508 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000509
510 // Write and close.
511
Denis Vlasenko727ef942006-09-14 13:19:19 +0000512 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000513 endmntent(mountTable);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000514 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000515 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000516 free(fsname);
517 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000518 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000519 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000520 return rc;
521}
522
Denis Vlasenko25098f72006-09-14 15:46:33 +0000523#if ENABLE_FEATURE_MOUNT_NFS
524
525/*
526 * Linux NFS mount
527 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
528 *
529 * Licensed under GPLv2, see file LICENSE in this tarball for details.
530 *
531 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
532 * numbers to be specified on the command line.
533 *
534 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
535 * Omit the call to connect() for Linux version 1.3.11 or later.
536 *
537 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
538 * Implemented the "bg", "fg" and "retry" mount options for NFS.
539 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000540 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000541 * - added Native Language Support
542 *
543 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
544 * plus NFSv3 stuff.
545 */
546
Denis Vlasenko25098f72006-09-14 15:46:33 +0000547/* This is just a warning of a common mistake. Possibly this should be a
548 * uclibc faq entry rather than in busybox... */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000549#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000550#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
551#endif
552
553#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 */
743
744#ifndef EDQUOT
745#define EDQUOT ENOSPC
746#endif
747
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000748/* Convert each NFSERR_BLAH into EBLAH */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000749static const struct {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000750 short stat;
751 short errnum;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000752} nfs_errtbl[] = {
753 {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
754 {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
755 {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
756 {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
757};
Denis Vlasenko25098f72006-09-14 15:46:33 +0000758static char *nfs_strerror(int status)
759{
760 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000761
762 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
763 if (nfs_errtbl[i].stat == status)
764 return strerror(nfs_errtbl[i].errnum);
765 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000766 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000767}
768
769static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
770{
771 if (!xdr_opaque(xdrs, objp, FHSIZE))
772 return FALSE;
773 return TRUE;
774}
775
776static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
777{
778 if (!xdr_u_int(xdrs, &objp->fhs_status))
779 return FALSE;
780 switch (objp->fhs_status) {
781 case 0:
782 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
783 return FALSE;
784 break;
785 default:
786 break;
787 }
788 return TRUE;
789}
790
791static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
792{
793 if (!xdr_string(xdrs, objp, MNTPATHLEN))
794 return FALSE;
795 return TRUE;
796}
797
798static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
799{
800 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
801 return FALSE;
802 return TRUE;
803}
804
805static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
806{
807 if (!xdr_fhandle3(xdrs, &objp->fhandle))
808 return FALSE;
809 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
Denys Vlasenko810b7162009-05-13 23:48:59 +0200810 sizeof(int), (xdrproc_t) xdr_int))
Denis Vlasenko25098f72006-09-14 15:46:33 +0000811 return FALSE;
812 return TRUE;
813}
814
815static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
816{
817 if (!xdr_enum(xdrs, (enum_t *) objp))
818 return FALSE;
819 return TRUE;
820}
821
822static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
823{
824 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
825 return FALSE;
826 switch (objp->fhs_status) {
827 case MNT_OK:
828 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
829 return FALSE;
830 break;
831 default:
832 break;
833 }
834 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) {
862 if (kernel_version < KERNEL_VERSION(2,1,32))
863 nfs_mount_version = 1;
864 else if (kernel_version < KERNEL_VERSION(2,2,18) ||
865 (kernel_version >= KERNEL_VERSION(2,3,0) &&
866 kernel_version < KERNEL_VERSION(2,3,99)))
867 nfs_mount_version = 3;
868 /* else v4 since 2.3.99pre4 */
869 }
870}
871
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000872static void
Denis Vlasenkob9256052007-09-28 10:29:17 +0000873get_mountport(struct pmap *pm_mnt,
874 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +0000875 long unsigned prog,
876 long unsigned version,
877 long unsigned proto,
878 long unsigned port)
879{
880 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000881
882 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +0000883/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
884 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000885 pmap = pmap_getmaps(server_addr);
886
887 if (version > MAX_NFSPROT)
888 version = MAX_NFSPROT;
889 if (!prog)
890 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000891 pm_mnt->pm_prog = prog;
892 pm_mnt->pm_vers = version;
893 pm_mnt->pm_prot = proto;
894 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000895
Denis Vlasenko25098f72006-09-14 15:46:33 +0000896 while (pmap) {
897 if (pmap->pml_map.pm_prog != prog)
898 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000899 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000900 goto next;
901 if (version > 2 && pmap->pml_map.pm_vers != version)
902 goto next;
903 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
904 goto next;
905 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
Denis Vlasenkob9256052007-09-28 10:29:17 +0000906 (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
Denis Vlasenko25098f72006-09-14 15:46:33 +0000907 (port && pmap->pml_map.pm_port != port))
908 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000909 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
910 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +0000911 pmap = pmap->pml_next;
912 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000913 if (!pm_mnt->pm_vers)
914 pm_mnt->pm_vers = MOUNTVERS;
915 if (!pm_mnt->pm_port)
916 pm_mnt->pm_port = MOUNTPORT;
917 if (!pm_mnt->pm_prot)
918 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000919}
920
Denis Vlasenkof0000652007-09-04 18:30:26 +0000921#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +0000922static int daemonize(void)
923{
Denis Vlasenko25098f72006-09-14 15:46:33 +0000924 int pid = fork();
925 if (pid < 0) /* error */
926 return -errno;
927 if (pid > 0) /* parent */
928 return 0;
929 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000930 close(0);
931 xopen(bb_dev_null, O_RDWR);
932 xdup2(0, 1);
933 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000934 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000935 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000936 logmode = LOGMODE_SYSLOG;
937 return 1;
938}
Denis Vlasenkof0000652007-09-04 18:30:26 +0000939#else
940static inline int daemonize(void) { return -ENOSYS; }
941#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000942
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000943/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000944static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000945{
946 return 0;
947}
948
949/* RPC strerror analogs are terminally idiotic:
950 * *mandatory* prefix and \n at end.
951 * This hopefully helps. Usage:
952 * error_msg_rpc(clnt_*error*(" ")) */
953static void error_msg_rpc(const char *msg)
954{
Denis Vlasenko23514fe2006-09-19 14:07:52 +0000955 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000956 while (msg[0] == ' ' || msg[0] == ':') msg++;
957 len = strlen(msg);
958 while (len && msg[len-1] == '\n') len--;
959 bb_error_msg("%.*s", len, msg);
960}
961
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000962/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko810b7162009-05-13 23:48:59 +0200963static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000964{
965 CLIENT *mclient;
966 char *hostname;
967 char *pathname;
968 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +0200969 /* prior to 2.6.23, kernel took NFS options in a form of this struct
970 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
971 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000972 struct nfs_mount_data data;
973 char *opt;
974 struct hostent *hp;
975 struct sockaddr_in server_addr;
976 struct sockaddr_in mount_server_addr;
977 int msock, fsock;
978 union {
979 struct fhstatus nfsv2;
980 struct mountres3 nfsv3;
981 } status;
982 int daemonized;
983 char *s;
984 int port;
985 int mountport;
986 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000987#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000988 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000989#else
990 enum { bg = 0 };
991#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000992 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000993 int mountprog;
994 int mountvers;
995 int nfsprog;
996 int nfsvers;
997 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +0200998 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000999 smallint tcp;
1000 smallint soft;
1001 int intr;
1002 int posix;
1003 int nocto;
1004 int noac;
1005 int nordirplus;
1006 int nolock;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001007
1008 find_kernel_nfs_mount_version();
1009
1010 daemonized = 0;
1011 mounthost = NULL;
1012 retval = ETIMEDOUT;
1013 msock = fsock = -1;
1014 mclient = NULL;
1015
1016 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1017
1018 filteropts = xstrdup(filteropts); /* going to trash it later... */
1019
1020 hostname = xstrdup(mp->mnt_fsname);
1021 /* mount_main() guarantees that ':' is there */
1022 s = strchr(hostname, ':');
1023 pathname = s + 1;
1024 *s = '\0';
1025 /* Ignore all but first hostname in replicated mounts
1026 until they can be fully supported. (mack@sgi.com) */
1027 s = strchr(hostname, ',');
1028 if (s) {
1029 *s = '\0';
1030 bb_error_msg("warning: multiple hostnames not supported");
1031 }
1032
1033 server_addr.sin_family = AF_INET;
1034 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1035 hp = gethostbyname(hostname);
1036 if (hp == NULL) {
1037 bb_herror_msg("%s", hostname);
1038 goto fail;
1039 }
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001040 if ((size_t)hp->h_length > sizeof(struct in_addr)) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001041 bb_error_msg("got bad hp->h_length");
1042 hp->h_length = sizeof(struct in_addr);
1043 }
1044 memcpy(&server_addr.sin_addr,
1045 hp->h_addr, hp->h_length);
1046 }
1047
1048 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1049
1050 /* add IP address to mtab options for use when unmounting */
1051
1052 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1053 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1054 } else {
1055 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1056 mp->mnt_opts[0] ? "," : "",
1057 inet_ntoa(server_addr.sin_addr));
1058 free(mp->mnt_opts);
1059 mp->mnt_opts = tmp;
1060 }
1061
1062 /* Set default options.
1063 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1064 * let the kernel decide.
1065 * timeo is filled in after we know whether it'll be TCP or UDP. */
1066 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001067 data.retrans = 3;
1068 data.acregmin = 3;
1069 data.acregmax = 60;
1070 data.acdirmin = 30;
1071 data.acdirmax = 60;
1072 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001073
Denis Vlasenko25098f72006-09-14 15:46:33 +00001074 soft = 0;
1075 intr = 0;
1076 posix = 0;
1077 nocto = 0;
1078 nolock = 0;
1079 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001080 nordirplus = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001081 retry = 10000; /* 10000 minutes ~ 1 week */
1082 tcp = 0;
1083
1084 mountprog = MOUNTPROG;
1085 mountvers = 0;
1086 port = 0;
1087 mountport = 0;
1088 nfsprog = 100003;
1089 nfsvers = 0;
1090
1091 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001092 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001093 char *opteq = strchr(opt, '=');
1094 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001095 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001096 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001097 /* 0 */ "rsize\0"
1098 /* 1 */ "wsize\0"
1099 /* 2 */ "timeo\0"
1100 /* 3 */ "retrans\0"
1101 /* 4 */ "acregmin\0"
1102 /* 5 */ "acregmax\0"
1103 /* 6 */ "acdirmin\0"
1104 /* 7 */ "acdirmax\0"
1105 /* 8 */ "actimeo\0"
1106 /* 9 */ "retry\0"
1107 /* 10 */ "port\0"
1108 /* 11 */ "mountport\0"
1109 /* 12 */ "mounthost\0"
1110 /* 13 */ "mountprog\0"
1111 /* 14 */ "mountvers\0"
1112 /* 15 */ "nfsprog\0"
1113 /* 16 */ "nfsvers\0"
1114 /* 17 */ "vers\0"
1115 /* 18 */ "proto\0"
1116 /* 19 */ "namlen\0"
1117 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001118
1119 *opteq++ = '\0';
1120 idx = index_in_strings(options, opt);
1121 switch (idx) {
1122 case 12: // "mounthost"
1123 mounthost = xstrndup(opteq,
1124 strcspn(opteq, " \t\n\r,"));
1125 continue;
1126 case 18: // "proto"
1127 if (!strncmp(opteq, "tcp", 3))
1128 tcp = 1;
1129 else if (!strncmp(opteq, "udp", 3))
1130 tcp = 0;
1131 else
1132 bb_error_msg("warning: unrecognized proto= option");
1133 continue;
1134 case 20: // "addr" - ignore
1135 continue;
1136 }
1137
1138 val = xatoi_u(opteq);
1139 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001140 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001141 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001142 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001143 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001144 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001145 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001146 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001147 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001148 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001149 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001150 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001151 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001152 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001153 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001154 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001155 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001156 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001157 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001158 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001159 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001160 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001161 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001162 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001163 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001164 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001165 data.acregmin = val;
1166 data.acregmax = val;
1167 data.acdirmin = val;
1168 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001169 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001170 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001171 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001172 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001173 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001174 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001175 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001176 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001177 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001178 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001179 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001180 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001181 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001182 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001183 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001184 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001185 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001186 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001187 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001188 case 16: // "nfsvers"
1189 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001190 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001191 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001192 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001193 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001194 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001195 //else
1196 // bb_error_msg("warning: option namlen is not supported\n");
1197 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001198 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001199 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1200 goto fail;
1201 }
1202 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001203 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001204 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001205 "bg\0"
1206 "fg\0"
1207 "soft\0"
1208 "hard\0"
1209 "intr\0"
1210 "posix\0"
1211 "cto\0"
1212 "ac\0"
1213 "tcp\0"
1214 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001215 "lock\0"
1216 "rdirplus\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001217 int val = 1;
1218 if (!strncmp(opt, "no", 2)) {
1219 val = 0;
1220 opt += 2;
1221 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001222 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001223 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001224#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001225 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001226#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001227 break;
1228 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001229#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001230 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001231#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001232 break;
1233 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001234 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001235 break;
1236 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001237 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001238 break;
1239 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001240 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001241 break;
1242 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001243 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001244 break;
1245 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001246 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001247 break;
1248 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001249 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001250 break;
1251 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001252 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001253 break;
1254 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001255 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001256 break;
1257 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001258 if (nfs_mount_version >= 3)
1259 nolock = !val;
1260 else
1261 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001262 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001263 case 11: //rdirplus
1264 nordirplus = !val;
1265 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001266 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001267 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1268 goto fail;
1269 }
1270 }
1271 }
1272 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1273
1274 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1275 | (intr ? NFS_MOUNT_INTR : 0)
1276 | (posix ? NFS_MOUNT_POSIX : 0)
1277 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001278 | (noac ? NFS_MOUNT_NOAC : 0)
1279 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001280 if (nfs_mount_version >= 2)
1281 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1282 if (nfs_mount_version >= 3)
1283 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1284 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1285 bb_error_msg("NFSv%d not supported", nfsvers);
1286 goto fail;
1287 }
1288 if (nfsvers && !mountvers)
1289 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1290 if (nfsvers && nfsvers < mountvers) {
1291 mountvers = nfsvers;
1292 }
1293
1294 /* Adjust options if none specified */
1295 if (!data.timeo)
1296 data.timeo = tcp ? 70 : 7;
1297
Denis Vlasenko25098f72006-09-14 15:46:33 +00001298 data.version = nfs_mount_version;
1299
1300 if (vfsflags & MS_REMOUNT)
1301 goto do_mount;
1302
1303 /*
1304 * If the previous mount operation on the same host was
1305 * backgrounded, and the "bg" for this mount is also set,
1306 * give up immediately, to avoid the initial timeout.
1307 */
1308 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001309 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001310 if (daemonized <= 0) { /* parent or error */
1311 retval = -daemonized;
1312 goto ret;
1313 }
1314 }
1315
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001316 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001317 /* See if the nfs host = mount host. */
1318 if (mounthost) {
1319 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1320 mount_server_addr.sin_family = AF_INET;
1321 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1322 } else {
1323 hp = gethostbyname(mounthost);
1324 if (hp == NULL) {
1325 bb_herror_msg("%s", mounthost);
1326 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001327 }
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001328 if ((size_t)hp->h_length > sizeof(struct in_addr)) {
1329 bb_error_msg("got bad hp->h_length");
1330 hp->h_length = sizeof(struct in_addr);
1331 }
1332 mount_server_addr.sin_family = AF_INET;
1333 memcpy(&mount_server_addr.sin_addr,
1334 hp->h_addr, hp->h_length);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001335 }
1336 }
1337
1338 /*
1339 * The following loop implements the mount retries. When the mount
1340 * times out, and the "bg" option is set, we background ourself
1341 * and continue trying.
1342 *
1343 * The case where the mount point is not present and the "bg"
1344 * option is set, is treated as a timeout. This is done to
1345 * support nested mounts.
1346 *
1347 * The "retry" count specified by the user is the number of
1348 * minutes to retry before giving up.
1349 */
1350 {
1351 struct timeval total_timeout;
1352 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001353 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001354 time_t t;
1355 time_t prevt;
1356 time_t timeout;
1357
1358 retry_timeout.tv_sec = 3;
1359 retry_timeout.tv_usec = 0;
1360 total_timeout.tv_sec = 20;
1361 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001362/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001363 timeout = time(NULL) + 60 * retry;
1364 prevt = 0;
1365 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001366 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001367 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001368 if (t - prevt < 30)
1369 sleep(30);
1370
Denis Vlasenkob9256052007-09-28 10:29:17 +00001371 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001372 mountprog,
1373 mountvers,
1374 proto,
1375 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001376 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001377
1378 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001379 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001380 msock = RPC_ANYSOCK;
1381
Denis Vlasenkob9256052007-09-28 10:29:17 +00001382 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001383 case IPPROTO_UDP:
1384 mclient = clntudp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001385 pm_mnt.pm_prog,
1386 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001387 retry_timeout,
1388 &msock);
1389 if (mclient)
1390 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001391 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001392 msock = RPC_ANYSOCK;
1393 case IPPROTO_TCP:
1394 mclient = clnttcp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001395 pm_mnt.pm_prog,
1396 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001397 &msock, 0, 0);
1398 break;
1399 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001400 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001401 }
1402 if (!mclient) {
1403 if (!daemonized && prevt == 0)
1404 error_msg_rpc(clnt_spcreateerror(" "));
1405 } else {
1406 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001407
1408 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001409 mclient->cl_auth = authunix_create_default();
1410
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001411 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001412 * that xdr_array allocates memory for us
1413 */
1414 memset(&status, 0, sizeof(status));
1415
Denis Vlasenkob9256052007-09-28 10:29:17 +00001416 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001417 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1418 (xdrproc_t) xdr_dirpath,
1419 (caddr_t) &pathname,
1420 (xdrproc_t) xdr_mountres3,
1421 (caddr_t) &status,
1422 total_timeout);
1423 else
1424 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1425 (xdrproc_t) xdr_dirpath,
1426 (caddr_t) &pathname,
1427 (xdrproc_t) xdr_fhstatus,
1428 (caddr_t) &status,
1429 total_timeout);
1430
1431 if (clnt_stat == RPC_SUCCESS)
1432 goto prepare_kernel_data; /* we're done */
1433 if (errno != ECONNREFUSED) {
1434 error_msg_rpc(clnt_sperror(mclient, " "));
1435 goto fail; /* don't retry */
1436 }
1437 /* Connection refused */
1438 if (!daemonized && prevt == 0) /* print just once */
1439 error_msg_rpc(clnt_sperror(mclient, " "));
1440 auth_destroy(mclient->cl_auth);
1441 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001442 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001443 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001444 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001445 }
1446
1447 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001448 if (!bg)
1449 goto fail;
1450 if (!daemonized) {
1451 daemonized = daemonize();
1452 if (daemonized <= 0) { /* parent or error */
1453 retval = -daemonized;
1454 goto ret;
1455 }
1456 }
1457 prevt = t;
1458 t = time(NULL);
1459 if (t >= timeout)
1460 /* TODO error message */
1461 goto fail;
1462
1463 goto retry;
1464 }
1465
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001466 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001467
1468 if (nfsvers == 2) {
1469 if (status.nfsv2.fhs_status != 0) {
1470 bb_error_msg("%s:%s failed, reason given by server: %s",
1471 hostname, pathname,
1472 nfs_strerror(status.nfsv2.fhs_status));
1473 goto fail;
1474 }
1475 memcpy(data.root.data,
1476 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1477 NFS_FHSIZE);
1478 data.root.size = NFS_FHSIZE;
1479 memcpy(data.old_root.data,
1480 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1481 NFS_FHSIZE);
1482 } else {
1483 fhandle3 *my_fhandle;
1484 if (status.nfsv3.fhs_status != 0) {
1485 bb_error_msg("%s:%s failed, reason given by server: %s",
1486 hostname, pathname,
1487 nfs_strerror(status.nfsv3.fhs_status));
1488 goto fail;
1489 }
1490 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1491 memset(data.old_root.data, 0, NFS_FHSIZE);
1492 memset(&data.root, 0, sizeof(data.root));
1493 data.root.size = my_fhandle->fhandle3_len;
1494 memcpy(data.root.data,
1495 (char *) my_fhandle->fhandle3_val,
1496 my_fhandle->fhandle3_len);
1497
1498 data.flags |= NFS_MOUNT_VER3;
1499 }
1500
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001501 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001502 if (tcp) {
1503 if (nfs_mount_version < 3) {
1504 bb_error_msg("NFS over TCP is not supported");
1505 goto fail;
1506 }
1507 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1508 } else
1509 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1510 if (fsock < 0) {
1511 bb_perror_msg("nfs socket");
1512 goto fail;
1513 }
1514 if (bindresvport(fsock, 0) < 0) {
1515 bb_perror_msg("nfs bindresvport");
1516 goto fail;
1517 }
1518 if (port == 0) {
1519 server_addr.sin_port = PMAPPORT;
1520 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1521 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1522 if (port == 0)
1523 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001524 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001525 server_addr.sin_port = htons(port);
1526
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001527 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001528 data.fd = fsock;
1529 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1530 strncpy(data.hostname, hostname, sizeof(data.hostname));
1531
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001532 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001533 auth_destroy(mclient->cl_auth);
1534 clnt_destroy(mclient);
1535 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001536 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001537
1538 if (bg) {
1539 /* We must wait until mount directory is available */
1540 struct stat statbuf;
1541 int delay = 1;
1542 while (stat(mp->mnt_dir, &statbuf) == -1) {
1543 if (!daemonized) {
1544 daemonized = daemonize();
1545 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001546/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001547 retval = -daemonized;
1548 goto ret;
1549 }
1550 }
1551 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1552 delay *= 2;
1553 if (delay > 30)
1554 delay = 30;
1555 }
1556 }
1557
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001558 /* Perform actual mount */
1559 do_mount:
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001560 mp->mnt_type = (char*)"nfs";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001561 retval = mount_it_now(mp, vfsflags, (char*)&data);
1562 goto ret;
1563
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001564 /* Abort */
1565 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001566 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001567 if (mclient) {
1568 auth_destroy(mclient->cl_auth);
1569 clnt_destroy(mclient);
1570 }
1571 close(msock);
1572 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001573 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001574 close(fsock);
1575
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001576 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001577 free(hostname);
1578 free(mounthost);
1579 free(filteropts);
1580 return retval;
1581}
1582
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001583#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001584
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001585// Never called. Call should be optimized out.
Denis Vlasenkob4133682008-02-18 13:05:38 +00001586int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001587
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001588#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001589
1590// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1591// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001592// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001593static int singlemount(struct mntent *mp, int ignore_busy)
1594{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001595 int rc = -1;
1596 long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001597 char *loopFile = NULL, *filteropts = NULL;
1598 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001599 struct stat st;
1600
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001601 errno = 0;
1602
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001603 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1604
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001605 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001606 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1607 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001608
Denis Vlasenko2535f122007-09-15 13:28:30 +00001609 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001610 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1611 char *args[35];
1612 char *s;
1613 int n;
1614 // fsname: "cmd#arg1#arg2..."
1615 // WARNING: allows execution of arbitrary commands!
1616 // Try "mount 'sh#-c#sh' bogus_dir".
1617 // It is safe ONLY because non-root
1618 // cannot use two-argument mount command
1619 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1620 // "mount: can't find sh#-c#sh in /etc/fstab"
1621 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1622
1623 s = mp->mnt_fsname;
1624 n = 0;
1625 args[n++] = s;
1626 while (*s && n < 35 - 2) {
1627 if (*s++ == '#' && *s != '#') {
1628 s[-1] = '\0';
1629 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001630 }
1631 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001632 args[n++] = mp->mnt_dir;
1633 args[n] = NULL;
1634 rc = wait4pid(xspawn(args));
1635 goto report_error;
1636 }
1637
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001638 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001639 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001640 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1641 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1642 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001643 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001644 int len;
1645 char c;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001646 len_and_sockaddr *lsa;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001647 char *hostname, *dotted, *ip;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001648
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001649 hostname = mp->mnt_fsname + 2;
1650 len = strcspn(hostname, "/\\");
1651 if (len == 0 || hostname[len] == '\0')
Denis Vlasenko5c329932009-04-12 12:16:21 +00001652 goto report_error;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001653 c = hostname[len];
1654 hostname[len] = '\0';
1655 lsa = host2sockaddr(hostname, 0);
1656 hostname[len] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001657 if (!lsa)
1658 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001659
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001660 // Insert "ip=..." option into options
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001661 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001662 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001663 ip = xasprintf("ip=%s", dotted);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001664 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001665 parse_mount_options(ip, &filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001666 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001667
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001668 // "-o mand" is required [why?]
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001669 vfsflags |= MS_MANDLOCK;
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001670 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001671 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001672
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001673 goto report_error;
1674 }
1675
1676 // Might this be an NFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001677 if (ENABLE_FEATURE_MOUNT_NFS
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001678 && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001679 && strchr(mp->mnt_fsname, ':') != NULL
1680 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001681 rc = nfsmount(mp, vfsflags, filteropts);
1682 goto report_error;
1683 }
1684
1685 // Look at the file. (Not found isn't a failure for remount, or for
1686 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001687 // (We use stat, not lstat, in order to allow
1688 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001689 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001690 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1691 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001692 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001693 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1694 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001695 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001696 if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001697 if (errno == EPERM || errno == EACCES)
1698 bb_error_msg(bb_msg_perm_denied_are_you_root);
1699 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01001700 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00001701 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001702 }
1703
1704 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001705 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1706 vfsflags |= MS_BIND;
1707 }
1708
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001709 // If we know the fstype (or don't need to), jump straight
1710 // to the actual mount.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001711 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1712 rc = mount_it_now(mp, vfsflags, filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001713 else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001714 // Loop through filesystem types until mount succeeds
1715 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001716
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001717 // Initialize list of block backed filesystems.
1718 // This has to be done here so that during "mount -a",
1719 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001720 if (!fslist) {
1721 fslist = get_block_backed_filesystems();
1722 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1723 atexit(delete_block_backed_filesystems);
1724 }
1725
1726 for (fl = fslist; fl; fl = fl->link) {
1727 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00001728 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001729 if (!rc)
1730 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001731 }
1732 }
1733
1734 // If mount failed, clean up loop file (if any).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001735 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1736 del_loop(mp->mnt_fsname);
1737 if (ENABLE_FEATURE_CLEAN_UP) {
1738 free(loopFile);
1739 free(mp->mnt_fsname);
1740 }
1741 }
1742
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001743 report_error:
1744 if (ENABLE_FEATURE_CLEAN_UP)
1745 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001746
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00001747 if (errno == EBUSY && ignore_busy)
1748 return 0;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001749 if (rc < 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001750 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001751 return rc;
1752}
1753
Michael Abbott6b5accb2009-12-04 03:33:07 +01001754// -O support
1755// -O interprets a list of filter options which select whether a mount
1756// point will be mounted: only mounts with options matching *all* filtering
1757// options will be selected.
1758// By default each -O filter option must be present in the list of mount
1759// options, but if it is prefixed by "no" then it must be absent.
1760// For example,
1761// -O a,nob,c matches -o a,c but fails to match -o a,b,c
1762// (and also fails to match -o a because -o c is absent).
1763//
1764// It is different from -t in that each option is matched exactly; a leading
1765// "no" at the beginning of one option does not negate the rest.
1766static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001767{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001768 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01001769 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001770
Michael Abbott6b5accb2009-12-04 03:33:07 +01001771 while (*O_opt) {
1772 const char *fs_opt = fs_opt_in;
1773 int O_len;
1774 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001775
Michael Abbott6b5accb2009-12-04 03:33:07 +01001776 // If option begins with "no" then treat as an inverted match:
1777 // matching is a failure
1778 match = 0;
1779 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
1780 match = 1;
1781 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001782 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001783 // Isolate the current O option
1784 O_len = strchrnul(O_opt, ',') - O_opt;
1785 // Check for a match against existing options
1786 while (1) {
1787 if (strncmp(fs_opt, O_opt, O_len) == 0
1788 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
1789 ) {
1790 if (match)
1791 return 0; // "no" prefix, but option found
1792 match = 1; // current O option found, go check next one
1793 break;
1794 }
1795 fs_opt = strchr(fs_opt, ',');
1796 if (!fs_opt)
1797 break;
1798 fs_opt++;
1799 }
1800 if (match == 0)
1801 return 0; // match wanted but not found
1802 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001803 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01001804 // Step to the next O option
1805 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001806 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001807 // If we get here then everything matched
1808 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001809}
1810
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001811// Parse options, if necessary parse fstab/mtab, and call singlemount for
1812// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001813int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001814int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001815{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001816 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001817 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001818 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001819 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001820 llist_t *lst_o = NULL;
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001821 const char *fstabname;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001822 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001823 int i, j;
1824 int rc = EXIT_SUCCESS;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001825 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001826 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001827 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001828
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001829 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00001830
Denis Vlasenkof732e962008-02-18 12:07:49 +00001831 // Parse long options, like --bind and --move. Note that -o option
1832 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001833 for (i = j = 1; argv[i]; i++) {
1834 if (argv[i][0] == '-' && argv[i][1] == '-')
1835 append_mount_options(&cmdopts, argv[i] + 2);
1836 else
1837 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001838 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001839 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001840
1841 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001842 // Max 2 params; -o is a list, -v is a counter
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001843 opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001844 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001845 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001846 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00001847 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1848 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001849 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001850
1851 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001852 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00001853 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001854 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1855
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001856 if (!mountTable)
1857 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001858
Denis Vlasenko2535f122007-09-15 13:28:30 +00001859 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001860 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001861 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001862 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00001863 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001864 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001865
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001866 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001867 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1868 mtpair->mnt_dir, mtpair->mnt_type,
1869 mtpair->mnt_opts);
1870 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001871 if (ENABLE_FEATURE_CLEAN_UP)
1872 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001873 return EXIT_SUCCESS;
1874 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001875 storage_path = NULL;
1876 } else {
1877 // When we have two arguments, the second is the directory and we can
1878 // skip looking at fstab entirely. We can always abspath() the directory
1879 // argument when we get it.
1880 if (argv[1]) {
1881 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001882 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001883 mtpair->mnt_fsname = argv[0];
1884 mtpair->mnt_dir = argv[1];
1885 mtpair->mnt_type = fstype;
1886 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001887 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001888 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001889 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001890 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001891 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001892 }
1893
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001894 // Past this point, we are handling either "mount -a [opts]"
1895 // or "mount [opts] single_param"
1896
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001897 i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001898 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001899 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00001900
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001901 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001902 if (ENABLE_FEATURE_MOUNT_FLAGS
1903 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1904 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001905 // verbose_mount(source, target, type, flags, data)
1906 rc = verbose_mount("", argv[0], "", i, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001907 if (rc)
1908 bb_simple_perror_msg_and_die(argv[0]);
1909 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001910 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001911
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001912 // Open either fstab or mtab
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001913 fstabname = "/etc/fstab";
1914 if (i & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001915 // WARNING. I am not sure this matches util-linux's
1916 // behavior. It's possible util-linux does not
1917 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001918 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001919 }
1920 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001921 if (!fstab)
Denys Vlasenko6331cf02009-11-13 09:08:27 +01001922 bb_perror_msg_and_die("can't read %s", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001923
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001924 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00001925 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001926 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001927 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001928
1929 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00001930 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001931 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001932 GETMNTENT_BUFSIZE/2)
1933 ) { // End of fstab/mtab is reached
1934 mtcur = mtother; // the thing we found last time
1935 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001936 }
1937
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001938 // If we're trying to mount something specific and this isn't it,
1939 // skip it. Note we must match the exact text in fstab (ala
1940 // "proc") or a full path from root
1941 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001942
1943 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001944 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
1945 && strcmp(storage_path, mtcur->mnt_fsname) != 0
1946 && strcmp(argv[0], mtcur->mnt_dir) != 0
1947 && strcmp(storage_path, mtcur->mnt_dir) != 0
1948 ) {
1949 continue; // no
1950 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001951
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001952 // Remember this entry. Something later may have
1953 // overmounted it, and we want the _last_ match.
1954 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001955
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001956 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001957 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001958 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001959 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001960 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001961 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001962 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001963
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001964 // Does type match? (NULL matches always)
1965 if (!match_fstype(mtcur, fstype))
1966 continue;
1967
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001968 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001969 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
1970 // swap is bogus "fstype", parse_mount_options can't check fstypes
1971 || strcasecmp(mtcur->mnt_type, "swap") == 0
1972 ) {
1973 continue;
1974 }
1975
1976 // Does (at least one) option match?
1977 // (NULL matches always)
1978 if (!match_opt(mtcur->mnt_opts, O_optmatch))
1979 continue;
1980
1981 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001982
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001983 // NFS mounts want this to be xrealloc-able
1984 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001985
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001986 // If nothing is mounted on this directory...
1987 // (otherwise repeated "mount -a" mounts everything again)
1988 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
1989 // We do not check fsname match of found mount point -
1990 // "/" may have fsname of "/dev/root" while fstab
1991 // says "/dev/something_else".
1992 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01001993 if (verbose) {
1994 bb_error_msg("according to %s, "
1995 "%s is already mounted on %s",
1996 bb_path_mtab_file,
1997 mp->mnt_fsname, mp->mnt_dir);
1998 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001999 } else {
2000 // ...mount this thing
2001 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2002 // Count number of failed mounts
2003 rc++;
2004 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002005 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002006 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002007 }
2008 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002009
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002010 // End of fstab/mtab is reached.
2011 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002012 if (argv[0]) { // yes
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002013 long l;
2014
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002015 // If we didn't find anything, complain
2016 if (!mtcur->mnt_fsname)
2017 bb_error_msg_and_die("can't find %s in %s",
2018 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002019
2020 // What happens when we try to "mount swap_partition"?
2021 // (fstab containts "swap_partition swap swap defaults 0 0")
2022 // util-linux-ng 2.13.1 does this:
2023 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2024 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2025 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2026 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2027 // exit_group(32) = ?
2028#if 0
2029 // In case we want to simply skip swap partitions:
2030 l = parse_mount_options(mtcur->mnt_opts, NULL);
2031 if ((l & MOUNT_SWAP)
2032 // swap is bogus "fstype", parse_mount_options can't check fstypes
2033 || strcasecmp(mtcur->mnt_type, "swap") == 0
2034 ) {
2035 goto ret;
2036 }
2037#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002038 if (nonroot) {
2039 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002040 l = parse_mount_options(mtcur->mnt_opts, NULL);
2041 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002042 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002043 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002044
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002045 //util-linux-2.12 does not do this check.
2046 //// If nothing is mounted on this directory...
2047 //// (otherwise repeated "mount FOO" mounts FOO again)
2048 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2049 //if (mp) {
2050 // bb_error_msg("according to %s, "
2051 // "%s is already mounted on %s",
2052 // bb_path_mtab_file,
2053 // mp->mnt_fsname, mp->mnt_dir);
2054 //} else {
2055 // ...mount the last thing we found
2056 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2057 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2058 resolve_mount_spec(&mtpair->mnt_fsname);
2059 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2060 if (ENABLE_FEATURE_CLEAN_UP)
2061 free(mtcur->mnt_opts);
2062 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002063 }
2064
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002065 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002066 if (ENABLE_FEATURE_CLEAN_UP)
2067 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002068 if (ENABLE_FEATURE_CLEAN_UP) {
2069 free(storage_path);
2070 free(cmdopts);
2071 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002072
2073//TODO: exitcode should be ORed mask of (from "man mount"):
2074// 0 success
2075// 1 incorrect invocation or permissions
2076// 2 system error (out of memory, cannot fork, no more loop devices)
2077// 4 internal mount bug or missing nfs support in mount
2078// 8 user interrupt
2079//16 problems writing or locking /etc/mtab
2080//32 mount failure
2081//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002082 return rc;
2083}