blob: 9107e4308284ef76a99c6f5fbbfa0a9f8d71ae1d [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
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 *
535 * Licensed under GPLv2, see file LICENSE in this tarball for details.
536 *
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{
778 if (!xdr_opaque(xdrs, objp, FHSIZE))
779 return FALSE;
780 return TRUE;
781}
782
783static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
784{
785 if (!xdr_u_int(xdrs, &objp->fhs_status))
786 return FALSE;
787 switch (objp->fhs_status) {
788 case 0:
789 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
790 return FALSE;
791 break;
792 default:
793 break;
794 }
795 return TRUE;
796}
797
798static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
799{
800 if (!xdr_string(xdrs, objp, MNTPATHLEN))
801 return FALSE;
802 return TRUE;
803}
804
805static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
806{
Denys Vlasenkocc428142009-12-16 02:06:56 +0100807 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
808 (unsigned int *) &objp->fhandle3_len,
809 FHSIZE3)
810 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +0000811 return FALSE;
Denys Vlasenkocc428142009-12-16 02:06:56 +0100812 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000813 return TRUE;
814}
815
816static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
817{
818 if (!xdr_fhandle3(xdrs, &objp->fhandle))
819 return FALSE;
Denys Vlasenkocc428142009-12-16 02:06:56 +0100820 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
821 &(objp->auth_flavours.auth_flavours_len),
822 ~0,
823 sizeof(int),
824 (xdrproc_t) xdr_int)
825 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +0000826 return FALSE;
Denys Vlasenkocc428142009-12-16 02:06:56 +0100827 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000828 return TRUE;
829}
830
831static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
832{
833 if (!xdr_enum(xdrs, (enum_t *) objp))
834 return FALSE;
835 return TRUE;
836}
837
838static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
839{
840 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
841 return FALSE;
842 switch (objp->fhs_status) {
843 case MNT_OK:
844 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
845 return FALSE;
846 break;
847 default:
848 break;
849 }
850 return TRUE;
851}
852
853#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
854
Denis Vlasenko25098f72006-09-14 15:46:33 +0000855/*
856 * Unfortunately, the kernel prints annoying console messages
857 * in case of an unexpected nfs mount version (instead of
858 * just returning some error). Therefore we'll have to try
859 * and figure out what version the kernel expects.
860 *
861 * Variables:
862 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
863 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
864 * nfs_mount_version: version this source and running kernel can handle
865 */
866static void
867find_kernel_nfs_mount_version(void)
868{
Denis Vlasenkob9256052007-09-28 10:29:17 +0000869 int kernel_version;
870
871 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000872 return;
873
874 nfs_mount_version = 4; /* default */
875
876 kernel_version = get_linux_version_code();
877 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +0100878 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +0000879 nfs_mount_version = 3;
880 /* else v4 since 2.3.99pre4 */
881 }
882}
883
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000884static void
Denis Vlasenkob9256052007-09-28 10:29:17 +0000885get_mountport(struct pmap *pm_mnt,
886 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +0000887 long unsigned prog,
888 long unsigned version,
889 long unsigned proto,
890 long unsigned port)
891{
892 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000893
894 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +0000895/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
896 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000897 pmap = pmap_getmaps(server_addr);
898
899 if (version > MAX_NFSPROT)
900 version = MAX_NFSPROT;
901 if (!prog)
902 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000903 pm_mnt->pm_prog = prog;
904 pm_mnt->pm_vers = version;
905 pm_mnt->pm_prot = proto;
906 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000907
Denis Vlasenko25098f72006-09-14 15:46:33 +0000908 while (pmap) {
909 if (pmap->pml_map.pm_prog != prog)
910 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000911 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000912 goto next;
913 if (version > 2 && pmap->pml_map.pm_vers != version)
914 goto next;
915 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
916 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100917 if (pmap->pml_map.pm_vers > MAX_NFSPROT
918 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
919 || (port && pmap->pml_map.pm_port != port)
920 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +0000921 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100922 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000923 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
924 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +0000925 pmap = pmap->pml_next;
926 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000927 if (!pm_mnt->pm_vers)
928 pm_mnt->pm_vers = MOUNTVERS;
929 if (!pm_mnt->pm_port)
930 pm_mnt->pm_port = MOUNTPORT;
931 if (!pm_mnt->pm_prot)
932 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000933}
934
Denis Vlasenkof0000652007-09-04 18:30:26 +0000935#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +0000936static int daemonize(void)
937{
Denis Vlasenko25098f72006-09-14 15:46:33 +0000938 int pid = fork();
939 if (pid < 0) /* error */
940 return -errno;
941 if (pid > 0) /* parent */
942 return 0;
943 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000944 close(0);
945 xopen(bb_dev_null, O_RDWR);
946 xdup2(0, 1);
947 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000948 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000949 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000950 logmode = LOGMODE_SYSLOG;
951 return 1;
952}
Denis Vlasenkof0000652007-09-04 18:30:26 +0000953#else
954static inline int daemonize(void) { return -ENOSYS; }
955#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000956
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000957/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000958static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000959{
960 return 0;
961}
962
963/* RPC strerror analogs are terminally idiotic:
964 * *mandatory* prefix and \n at end.
965 * This hopefully helps. Usage:
966 * error_msg_rpc(clnt_*error*(" ")) */
967static void error_msg_rpc(const char *msg)
968{
Denis Vlasenko23514fe2006-09-19 14:07:52 +0000969 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000970 while (msg[0] == ' ' || msg[0] == ':') msg++;
971 len = strlen(msg);
972 while (len && msg[len-1] == '\n') len--;
973 bb_error_msg("%.*s", len, msg);
974}
975
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000976/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko810b7162009-05-13 23:48:59 +0200977static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000978{
979 CLIENT *mclient;
980 char *hostname;
981 char *pathname;
982 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +0200983 /* prior to 2.6.23, kernel took NFS options in a form of this struct
984 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
985 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000986 struct nfs_mount_data data;
987 char *opt;
988 struct hostent *hp;
989 struct sockaddr_in server_addr;
990 struct sockaddr_in mount_server_addr;
991 int msock, fsock;
992 union {
993 struct fhstatus nfsv2;
994 struct mountres3 nfsv3;
995 } status;
996 int daemonized;
997 char *s;
998 int port;
999 int mountport;
1000 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001001#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001002 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001003#else
1004 enum { bg = 0 };
1005#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001006 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001007 int mountprog;
1008 int mountvers;
1009 int nfsprog;
1010 int nfsvers;
1011 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001012 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001013 smallint tcp;
1014 smallint soft;
1015 int intr;
1016 int posix;
1017 int nocto;
1018 int noac;
1019 int nordirplus;
1020 int nolock;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001021
1022 find_kernel_nfs_mount_version();
1023
1024 daemonized = 0;
1025 mounthost = NULL;
1026 retval = ETIMEDOUT;
1027 msock = fsock = -1;
1028 mclient = NULL;
1029
1030 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1031
1032 filteropts = xstrdup(filteropts); /* going to trash it later... */
1033
1034 hostname = xstrdup(mp->mnt_fsname);
1035 /* mount_main() guarantees that ':' is there */
1036 s = strchr(hostname, ':');
1037 pathname = s + 1;
1038 *s = '\0';
1039 /* Ignore all but first hostname in replicated mounts
1040 until they can be fully supported. (mack@sgi.com) */
1041 s = strchr(hostname, ',');
1042 if (s) {
1043 *s = '\0';
1044 bb_error_msg("warning: multiple hostnames not supported");
1045 }
1046
1047 server_addr.sin_family = AF_INET;
1048 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1049 hp = gethostbyname(hostname);
1050 if (hp == NULL) {
1051 bb_herror_msg("%s", hostname);
1052 goto fail;
1053 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001054 if (hp->h_length != (int)sizeof(struct in_addr)) {
1055 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001056 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001057 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001058 }
1059
1060 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1061
1062 /* add IP address to mtab options for use when unmounting */
1063
1064 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1065 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1066 } else {
1067 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1068 mp->mnt_opts[0] ? "," : "",
1069 inet_ntoa(server_addr.sin_addr));
1070 free(mp->mnt_opts);
1071 mp->mnt_opts = tmp;
1072 }
1073
1074 /* Set default options.
1075 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1076 * let the kernel decide.
1077 * timeo is filled in after we know whether it'll be TCP or UDP. */
1078 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001079 data.retrans = 3;
1080 data.acregmin = 3;
1081 data.acregmax = 60;
1082 data.acdirmin = 30;
1083 data.acdirmax = 60;
1084 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001085
Denis Vlasenko25098f72006-09-14 15:46:33 +00001086 soft = 0;
1087 intr = 0;
1088 posix = 0;
1089 nocto = 0;
1090 nolock = 0;
1091 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001092 nordirplus = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001093 retry = 10000; /* 10000 minutes ~ 1 week */
1094 tcp = 0;
1095
1096 mountprog = MOUNTPROG;
1097 mountvers = 0;
1098 port = 0;
1099 mountport = 0;
1100 nfsprog = 100003;
1101 nfsvers = 0;
1102
1103 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001104 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001105 char *opteq = strchr(opt, '=');
1106 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001107 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001108 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001109 /* 0 */ "rsize\0"
1110 /* 1 */ "wsize\0"
1111 /* 2 */ "timeo\0"
1112 /* 3 */ "retrans\0"
1113 /* 4 */ "acregmin\0"
1114 /* 5 */ "acregmax\0"
1115 /* 6 */ "acdirmin\0"
1116 /* 7 */ "acdirmax\0"
1117 /* 8 */ "actimeo\0"
1118 /* 9 */ "retry\0"
1119 /* 10 */ "port\0"
1120 /* 11 */ "mountport\0"
1121 /* 12 */ "mounthost\0"
1122 /* 13 */ "mountprog\0"
1123 /* 14 */ "mountvers\0"
1124 /* 15 */ "nfsprog\0"
1125 /* 16 */ "nfsvers\0"
1126 /* 17 */ "vers\0"
1127 /* 18 */ "proto\0"
1128 /* 19 */ "namlen\0"
1129 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001130
1131 *opteq++ = '\0';
1132 idx = index_in_strings(options, opt);
1133 switch (idx) {
1134 case 12: // "mounthost"
1135 mounthost = xstrndup(opteq,
1136 strcspn(opteq, " \t\n\r,"));
1137 continue;
1138 case 18: // "proto"
1139 if (!strncmp(opteq, "tcp", 3))
1140 tcp = 1;
1141 else if (!strncmp(opteq, "udp", 3))
1142 tcp = 0;
1143 else
1144 bb_error_msg("warning: unrecognized proto= option");
1145 continue;
1146 case 20: // "addr" - ignore
1147 continue;
1148 }
1149
1150 val = xatoi_u(opteq);
1151 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001152 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001153 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001154 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001155 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001156 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001157 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001158 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001159 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001160 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001161 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001162 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001163 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001164 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001165 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001166 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001167 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001168 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001169 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001170 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001171 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001172 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001173 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001174 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001175 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001176 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001177 data.acregmin = val;
1178 data.acregmax = val;
1179 data.acdirmin = val;
1180 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001181 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001182 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001183 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001184 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001185 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001186 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001187 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001188 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001189 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001190 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001191 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001192 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001193 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001194 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001195 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001196 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001197 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001198 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001199 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001200 case 16: // "nfsvers"
1201 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001202 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001203 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001204 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001205 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001206 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001207 //else
1208 // bb_error_msg("warning: option namlen is not supported\n");
1209 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001210 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001211 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1212 goto fail;
1213 }
1214 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001215 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001216 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001217 "bg\0"
1218 "fg\0"
1219 "soft\0"
1220 "hard\0"
1221 "intr\0"
1222 "posix\0"
1223 "cto\0"
1224 "ac\0"
1225 "tcp\0"
1226 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001227 "lock\0"
1228 "rdirplus\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001229 int val = 1;
1230 if (!strncmp(opt, "no", 2)) {
1231 val = 0;
1232 opt += 2;
1233 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001234 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001235 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001236#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001237 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001238#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001239 break;
1240 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001241#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001242 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001243#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001244 break;
1245 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001246 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001247 break;
1248 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001249 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001250 break;
1251 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001252 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001253 break;
1254 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001255 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001256 break;
1257 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001258 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001259 break;
1260 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001261 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001262 break;
1263 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001264 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001265 break;
1266 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001267 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001268 break;
1269 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001270 if (nfs_mount_version >= 3)
1271 nolock = !val;
1272 else
1273 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001274 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001275 case 11: //rdirplus
1276 nordirplus = !val;
1277 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001278 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001279 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1280 goto fail;
1281 }
1282 }
1283 }
1284 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1285
1286 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1287 | (intr ? NFS_MOUNT_INTR : 0)
1288 | (posix ? NFS_MOUNT_POSIX : 0)
1289 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001290 | (noac ? NFS_MOUNT_NOAC : 0)
1291 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001292 if (nfs_mount_version >= 2)
1293 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1294 if (nfs_mount_version >= 3)
1295 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1296 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1297 bb_error_msg("NFSv%d not supported", nfsvers);
1298 goto fail;
1299 }
1300 if (nfsvers && !mountvers)
1301 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1302 if (nfsvers && nfsvers < mountvers) {
1303 mountvers = nfsvers;
1304 }
1305
1306 /* Adjust options if none specified */
1307 if (!data.timeo)
1308 data.timeo = tcp ? 70 : 7;
1309
Denis Vlasenko25098f72006-09-14 15:46:33 +00001310 data.version = nfs_mount_version;
1311
1312 if (vfsflags & MS_REMOUNT)
1313 goto do_mount;
1314
1315 /*
1316 * If the previous mount operation on the same host was
1317 * backgrounded, and the "bg" for this mount is also set,
1318 * give up immediately, to avoid the initial timeout.
1319 */
1320 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001321 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001322 if (daemonized <= 0) { /* parent or error */
1323 retval = -daemonized;
1324 goto ret;
1325 }
1326 }
1327
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001328 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001329 /* See if the nfs host = mount host. */
1330 if (mounthost) {
1331 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1332 mount_server_addr.sin_family = AF_INET;
1333 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1334 } else {
1335 hp = gethostbyname(mounthost);
1336 if (hp == NULL) {
1337 bb_herror_msg("%s", mounthost);
1338 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001339 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001340 if (hp->h_length != (int)sizeof(struct in_addr)) {
1341 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001342 }
1343 mount_server_addr.sin_family = AF_INET;
Denys Vlasenko99069332010-02-27 19:38:19 +01001344 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001345 }
1346 }
1347
1348 /*
1349 * The following loop implements the mount retries. When the mount
1350 * times out, and the "bg" option is set, we background ourself
1351 * and continue trying.
1352 *
1353 * The case where the mount point is not present and the "bg"
1354 * option is set, is treated as a timeout. This is done to
1355 * support nested mounts.
1356 *
1357 * The "retry" count specified by the user is the number of
1358 * minutes to retry before giving up.
1359 */
1360 {
1361 struct timeval total_timeout;
1362 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001363 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001364 time_t t;
1365 time_t prevt;
1366 time_t timeout;
1367
1368 retry_timeout.tv_sec = 3;
1369 retry_timeout.tv_usec = 0;
1370 total_timeout.tv_sec = 20;
1371 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001372/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001373 timeout = time(NULL) + 60 * retry;
1374 prevt = 0;
1375 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001376 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001377 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001378 if (t - prevt < 30)
1379 sleep(30);
1380
Denis Vlasenkob9256052007-09-28 10:29:17 +00001381 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001382 mountprog,
1383 mountvers,
1384 proto,
1385 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001386 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001387
1388 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001389 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001390 msock = RPC_ANYSOCK;
1391
Denis Vlasenkob9256052007-09-28 10:29:17 +00001392 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001393 case IPPROTO_UDP:
1394 mclient = clntudp_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 retry_timeout,
1398 &msock);
1399 if (mclient)
1400 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001401 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001402 msock = RPC_ANYSOCK;
1403 case IPPROTO_TCP:
1404 mclient = clnttcp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001405 pm_mnt.pm_prog,
1406 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001407 &msock, 0, 0);
1408 break;
1409 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001410 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001411 }
1412 if (!mclient) {
1413 if (!daemonized && prevt == 0)
1414 error_msg_rpc(clnt_spcreateerror(" "));
1415 } else {
1416 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001417
1418 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001419 mclient->cl_auth = authunix_create_default();
1420
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001421 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001422 * that xdr_array allocates memory for us
1423 */
1424 memset(&status, 0, sizeof(status));
1425
Denis Vlasenkob9256052007-09-28 10:29:17 +00001426 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001427 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1428 (xdrproc_t) xdr_dirpath,
1429 (caddr_t) &pathname,
1430 (xdrproc_t) xdr_mountres3,
1431 (caddr_t) &status,
1432 total_timeout);
1433 else
1434 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1435 (xdrproc_t) xdr_dirpath,
1436 (caddr_t) &pathname,
1437 (xdrproc_t) xdr_fhstatus,
1438 (caddr_t) &status,
1439 total_timeout);
1440
1441 if (clnt_stat == RPC_SUCCESS)
1442 goto prepare_kernel_data; /* we're done */
1443 if (errno != ECONNREFUSED) {
1444 error_msg_rpc(clnt_sperror(mclient, " "));
1445 goto fail; /* don't retry */
1446 }
1447 /* Connection refused */
1448 if (!daemonized && prevt == 0) /* print just once */
1449 error_msg_rpc(clnt_sperror(mclient, " "));
1450 auth_destroy(mclient->cl_auth);
1451 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001452 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001453 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001454 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001455 }
1456
1457 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001458 if (!bg)
1459 goto fail;
1460 if (!daemonized) {
1461 daemonized = daemonize();
1462 if (daemonized <= 0) { /* parent or error */
1463 retval = -daemonized;
1464 goto ret;
1465 }
1466 }
1467 prevt = t;
1468 t = time(NULL);
1469 if (t >= timeout)
1470 /* TODO error message */
1471 goto fail;
1472
1473 goto retry;
1474 }
1475
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001476 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001477
1478 if (nfsvers == 2) {
1479 if (status.nfsv2.fhs_status != 0) {
1480 bb_error_msg("%s:%s failed, reason given by server: %s",
1481 hostname, pathname,
1482 nfs_strerror(status.nfsv2.fhs_status));
1483 goto fail;
1484 }
1485 memcpy(data.root.data,
1486 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1487 NFS_FHSIZE);
1488 data.root.size = NFS_FHSIZE;
1489 memcpy(data.old_root.data,
1490 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1491 NFS_FHSIZE);
1492 } else {
1493 fhandle3 *my_fhandle;
1494 if (status.nfsv3.fhs_status != 0) {
1495 bb_error_msg("%s:%s failed, reason given by server: %s",
1496 hostname, pathname,
1497 nfs_strerror(status.nfsv3.fhs_status));
1498 goto fail;
1499 }
1500 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1501 memset(data.old_root.data, 0, NFS_FHSIZE);
1502 memset(&data.root, 0, sizeof(data.root));
1503 data.root.size = my_fhandle->fhandle3_len;
1504 memcpy(data.root.data,
1505 (char *) my_fhandle->fhandle3_val,
1506 my_fhandle->fhandle3_len);
1507
1508 data.flags |= NFS_MOUNT_VER3;
1509 }
1510
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001511 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001512 if (tcp) {
1513 if (nfs_mount_version < 3) {
1514 bb_error_msg("NFS over TCP is not supported");
1515 goto fail;
1516 }
1517 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1518 } else
1519 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1520 if (fsock < 0) {
1521 bb_perror_msg("nfs socket");
1522 goto fail;
1523 }
1524 if (bindresvport(fsock, 0) < 0) {
1525 bb_perror_msg("nfs bindresvport");
1526 goto fail;
1527 }
1528 if (port == 0) {
1529 server_addr.sin_port = PMAPPORT;
1530 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1531 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1532 if (port == 0)
1533 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001534 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001535 server_addr.sin_port = htons(port);
1536
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001537 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001538 data.fd = fsock;
1539 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1540 strncpy(data.hostname, hostname, sizeof(data.hostname));
1541
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001542 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001543 auth_destroy(mclient->cl_auth);
1544 clnt_destroy(mclient);
1545 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001546 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001547
1548 if (bg) {
1549 /* We must wait until mount directory is available */
1550 struct stat statbuf;
1551 int delay = 1;
1552 while (stat(mp->mnt_dir, &statbuf) == -1) {
1553 if (!daemonized) {
1554 daemonized = daemonize();
1555 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001556/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001557 retval = -daemonized;
1558 goto ret;
1559 }
1560 }
1561 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1562 delay *= 2;
1563 if (delay > 30)
1564 delay = 30;
1565 }
1566 }
1567
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001568 /* Perform actual mount */
1569 do_mount:
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001570 mp->mnt_type = (char*)"nfs";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001571 retval = mount_it_now(mp, vfsflags, (char*)&data);
1572 goto ret;
1573
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001574 /* Abort */
1575 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001576 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001577 if (mclient) {
1578 auth_destroy(mclient->cl_auth);
1579 clnt_destroy(mclient);
1580 }
1581 close(msock);
1582 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001583 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001584 close(fsock);
1585
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001586 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001587 free(hostname);
1588 free(mounthost);
1589 free(filteropts);
1590 return retval;
1591}
1592
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001593#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001594
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001595// Never called. Call should be optimized out.
Denis Vlasenkob4133682008-02-18 13:05:38 +00001596int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001597
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001598#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001599
1600// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1601// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001602// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001603static int singlemount(struct mntent *mp, int ignore_busy)
1604{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001605 int rc = -1;
1606 long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001607 char *loopFile = NULL, *filteropts = NULL;
1608 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001609 struct stat st;
1610
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001611 errno = 0;
1612
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001613 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1614
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001615 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001616 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1617 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001618
Denis Vlasenko2535f122007-09-15 13:28:30 +00001619 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001620 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1621 char *args[35];
1622 char *s;
1623 int n;
1624 // fsname: "cmd#arg1#arg2..."
1625 // WARNING: allows execution of arbitrary commands!
1626 // Try "mount 'sh#-c#sh' bogus_dir".
1627 // It is safe ONLY because non-root
1628 // cannot use two-argument mount command
1629 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1630 // "mount: can't find sh#-c#sh in /etc/fstab"
1631 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1632
1633 s = mp->mnt_fsname;
1634 n = 0;
1635 args[n++] = s;
1636 while (*s && n < 35 - 2) {
1637 if (*s++ == '#' && *s != '#') {
1638 s[-1] = '\0';
1639 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001640 }
1641 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001642 args[n++] = mp->mnt_dir;
1643 args[n] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +01001644 rc = spawn_and_wait(args);
Denis Vlasenko2535f122007-09-15 13:28:30 +00001645 goto report_error;
1646 }
1647
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001648 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001649 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001650 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1651 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1652 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001653 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001654 int len;
1655 char c;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001656 len_and_sockaddr *lsa;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001657 char *hostname, *dotted, *ip;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001658
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001659 hostname = mp->mnt_fsname + 2;
1660 len = strcspn(hostname, "/\\");
1661 if (len == 0 || hostname[len] == '\0')
Denis Vlasenko5c329932009-04-12 12:16:21 +00001662 goto report_error;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001663 c = hostname[len];
1664 hostname[len] = '\0';
1665 lsa = host2sockaddr(hostname, 0);
1666 hostname[len] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001667 if (!lsa)
1668 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001669
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001670 // Insert "ip=..." option into options
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001671 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001672 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001673 ip = xasprintf("ip=%s", dotted);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001674 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001675 parse_mount_options(ip, &filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001676 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001677
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001678 // "-o mand" is required [why?]
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001679 vfsflags |= MS_MANDLOCK;
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001680 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001681 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001682
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001683 goto report_error;
1684 }
1685
1686 // Might this be an NFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001687 if (ENABLE_FEATURE_MOUNT_NFS
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001688 && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001689 && strchr(mp->mnt_fsname, ':') != NULL
1690 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001691 rc = nfsmount(mp, vfsflags, filteropts);
1692 goto report_error;
1693 }
1694
1695 // Look at the file. (Not found isn't a failure for remount, or for
1696 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001697 // (We use stat, not lstat, in order to allow
1698 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001699 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001700 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1701 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001702 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001703 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1704 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001705 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001706 if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001707 if (errno == EPERM || errno == EACCES)
1708 bb_error_msg(bb_msg_perm_denied_are_you_root);
1709 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01001710 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00001711 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001712 }
1713
1714 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001715 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1716 vfsflags |= MS_BIND;
1717 }
1718
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001719 // If we know the fstype (or don't need to), jump straight
1720 // to the actual mount.
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001721 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001722 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001723 } else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001724 // Loop through filesystem types until mount succeeds
1725 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001726
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001727 // Initialize list of block backed filesystems.
1728 // This has to be done here so that during "mount -a",
1729 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001730 if (!fslist) {
1731 fslist = get_block_backed_filesystems();
1732 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1733 atexit(delete_block_backed_filesystems);
1734 }
1735
1736 for (fl = fslist; fl; fl = fl->link) {
1737 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00001738 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001739 if (!rc)
1740 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001741 }
1742 }
1743
1744 // If mount failed, clean up loop file (if any).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001745 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1746 del_loop(mp->mnt_fsname);
1747 if (ENABLE_FEATURE_CLEAN_UP) {
1748 free(loopFile);
1749 free(mp->mnt_fsname);
1750 }
1751 }
1752
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001753 report_error:
1754 if (ENABLE_FEATURE_CLEAN_UP)
1755 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001756
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00001757 if (errno == EBUSY && ignore_busy)
1758 return 0;
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001759 if (rc != 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001760 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001761 return rc;
1762}
1763
Michael Abbott6b5accb2009-12-04 03:33:07 +01001764// -O support
1765// -O interprets a list of filter options which select whether a mount
1766// point will be mounted: only mounts with options matching *all* filtering
1767// options will be selected.
1768// By default each -O filter option must be present in the list of mount
1769// options, but if it is prefixed by "no" then it must be absent.
1770// For example,
1771// -O a,nob,c matches -o a,c but fails to match -o a,b,c
1772// (and also fails to match -o a because -o c is absent).
1773//
1774// It is different from -t in that each option is matched exactly; a leading
1775// "no" at the beginning of one option does not negate the rest.
1776static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001777{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001778 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01001779 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001780
Michael Abbott6b5accb2009-12-04 03:33:07 +01001781 while (*O_opt) {
1782 const char *fs_opt = fs_opt_in;
1783 int O_len;
1784 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001785
Michael Abbott6b5accb2009-12-04 03:33:07 +01001786 // If option begins with "no" then treat as an inverted match:
1787 // matching is a failure
1788 match = 0;
1789 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
1790 match = 1;
1791 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001792 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001793 // Isolate the current O option
1794 O_len = strchrnul(O_opt, ',') - O_opt;
1795 // Check for a match against existing options
1796 while (1) {
1797 if (strncmp(fs_opt, O_opt, O_len) == 0
1798 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
1799 ) {
1800 if (match)
1801 return 0; // "no" prefix, but option found
1802 match = 1; // current O option found, go check next one
1803 break;
1804 }
1805 fs_opt = strchr(fs_opt, ',');
1806 if (!fs_opt)
1807 break;
1808 fs_opt++;
1809 }
1810 if (match == 0)
1811 return 0; // match wanted but not found
1812 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001813 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01001814 // Step to the next O option
1815 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001816 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001817 // If we get here then everything matched
1818 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001819}
1820
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001821// Parse options, if necessary parse fstab/mtab, and call singlemount for
1822// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001823int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001824int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001825{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001826 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001827 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001828 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001829 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001830 llist_t *lst_o = NULL;
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001831 const char *fstabname;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001832 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001833 int i, j;
1834 int rc = EXIT_SUCCESS;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001835 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001836 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001837 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001838
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001839 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00001840
Denis Vlasenkof732e962008-02-18 12:07:49 +00001841 // Parse long options, like --bind and --move. Note that -o option
1842 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001843 for (i = j = 1; argv[i]; i++) {
1844 if (argv[i][0] == '-' && argv[i][1] == '-')
1845 append_mount_options(&cmdopts, argv[i] + 2);
1846 else
1847 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001848 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001849 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001850
1851 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001852 // Max 2 params; -o is a list, -v is a counter
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001853 opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001854 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001855 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001856 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00001857 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1858 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001859 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001860
1861 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001862 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00001863 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001864 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1865
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001866 if (!mountTable)
1867 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001868
Denis Vlasenko2535f122007-09-15 13:28:30 +00001869 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001870 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001871 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001872 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00001873 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001874 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001875
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001876 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001877 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1878 mtpair->mnt_dir, mtpair->mnt_type,
1879 mtpair->mnt_opts);
1880 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001881 if (ENABLE_FEATURE_CLEAN_UP)
1882 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001883 return EXIT_SUCCESS;
1884 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001885 storage_path = NULL;
1886 } else {
1887 // When we have two arguments, the second is the directory and we can
1888 // skip looking at fstab entirely. We can always abspath() the directory
1889 // argument when we get it.
1890 if (argv[1]) {
1891 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001892 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001893 mtpair->mnt_fsname = argv[0];
1894 mtpair->mnt_dir = argv[1];
1895 mtpair->mnt_type = fstype;
1896 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001897 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001898 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001899 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001900 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001901 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001902 }
1903
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001904 // Past this point, we are handling either "mount -a [opts]"
1905 // or "mount [opts] single_param"
1906
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001907 i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001908 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001909 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00001910
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001911 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001912 if (ENABLE_FEATURE_MOUNT_FLAGS
1913 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1914 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001915 // verbose_mount(source, target, type, flags, data)
1916 rc = verbose_mount("", argv[0], "", i, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001917 if (rc)
1918 bb_simple_perror_msg_and_die(argv[0]);
1919 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001920 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001921
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001922 // Open either fstab or mtab
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001923 fstabname = "/etc/fstab";
1924 if (i & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001925 // WARNING. I am not sure this matches util-linux's
1926 // behavior. It's possible util-linux does not
1927 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001928 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001929 }
1930 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001931 if (!fstab)
Denys Vlasenko651a2692010-03-23 16:25:17 +01001932 bb_perror_msg_and_die("can't read '%s'", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001933
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001934 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00001935 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001936 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001937 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001938
1939 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00001940 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001941 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001942 GETMNTENT_BUFSIZE/2)
1943 ) { // End of fstab/mtab is reached
1944 mtcur = mtother; // the thing we found last time
1945 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001946 }
1947
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001948 // If we're trying to mount something specific and this isn't it,
1949 // skip it. Note we must match the exact text in fstab (ala
1950 // "proc") or a full path from root
1951 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001952
1953 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001954 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
1955 && strcmp(storage_path, mtcur->mnt_fsname) != 0
1956 && strcmp(argv[0], mtcur->mnt_dir) != 0
1957 && strcmp(storage_path, mtcur->mnt_dir) != 0
1958 ) {
1959 continue; // no
1960 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001961
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001962 // Remember this entry. Something later may have
1963 // overmounted it, and we want the _last_ match.
1964 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001965
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001966 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001967 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001968 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001969 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001970 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001971 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001972 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001973
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001974 // Does type match? (NULL matches always)
1975 if (!match_fstype(mtcur, fstype))
1976 continue;
1977
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001978 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001979 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
1980 // swap is bogus "fstype", parse_mount_options can't check fstypes
1981 || strcasecmp(mtcur->mnt_type, "swap") == 0
1982 ) {
1983 continue;
1984 }
1985
1986 // Does (at least one) option match?
1987 // (NULL matches always)
1988 if (!match_opt(mtcur->mnt_opts, O_optmatch))
1989 continue;
1990
1991 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001992
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001993 // NFS mounts want this to be xrealloc-able
1994 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001995
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001996 // If nothing is mounted on this directory...
1997 // (otherwise repeated "mount -a" mounts everything again)
1998 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
1999 // We do not check fsname match of found mount point -
2000 // "/" may have fsname of "/dev/root" while fstab
2001 // says "/dev/something_else".
2002 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01002003 if (verbose) {
2004 bb_error_msg("according to %s, "
2005 "%s is already mounted on %s",
2006 bb_path_mtab_file,
2007 mp->mnt_fsname, mp->mnt_dir);
2008 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002009 } else {
2010 // ...mount this thing
2011 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2012 // Count number of failed mounts
2013 rc++;
2014 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002015 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002016 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002017 }
2018 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002019
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002020 // End of fstab/mtab is reached.
2021 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002022 if (argv[0]) { // yes
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002023 long l;
2024
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002025 // If we didn't find anything, complain
2026 if (!mtcur->mnt_fsname)
2027 bb_error_msg_and_die("can't find %s in %s",
2028 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002029
2030 // What happens when we try to "mount swap_partition"?
2031 // (fstab containts "swap_partition swap swap defaults 0 0")
2032 // util-linux-ng 2.13.1 does this:
2033 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2034 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2035 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2036 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2037 // exit_group(32) = ?
2038#if 0
2039 // In case we want to simply skip swap partitions:
2040 l = parse_mount_options(mtcur->mnt_opts, NULL);
2041 if ((l & MOUNT_SWAP)
2042 // swap is bogus "fstype", parse_mount_options can't check fstypes
2043 || strcasecmp(mtcur->mnt_type, "swap") == 0
2044 ) {
2045 goto ret;
2046 }
2047#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002048 if (nonroot) {
2049 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002050 l = parse_mount_options(mtcur->mnt_opts, NULL);
2051 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002052 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002053 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002054
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002055 //util-linux-2.12 does not do this check.
2056 //// If nothing is mounted on this directory...
2057 //// (otherwise repeated "mount FOO" mounts FOO again)
2058 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2059 //if (mp) {
2060 // bb_error_msg("according to %s, "
2061 // "%s is already mounted on %s",
2062 // bb_path_mtab_file,
2063 // mp->mnt_fsname, mp->mnt_dir);
2064 //} else {
2065 // ...mount the last thing we found
2066 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2067 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2068 resolve_mount_spec(&mtpair->mnt_fsname);
2069 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2070 if (ENABLE_FEATURE_CLEAN_UP)
2071 free(mtcur->mnt_opts);
2072 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002073 }
2074
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002075 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002076 if (ENABLE_FEATURE_CLEAN_UP)
2077 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002078 if (ENABLE_FEATURE_CLEAN_UP) {
2079 free(storage_path);
2080 free(cmdopts);
2081 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002082
2083//TODO: exitcode should be ORed mask of (from "man mount"):
2084// 0 success
2085// 1 incorrect invocation or permissions
2086// 2 system error (out of memory, cannot fork, no more loop devices)
2087// 4 internal mount bug or missing nfs support in mount
2088// 8 user interrupt
2089//16 problems writing or locking /etc/mtab
2090//32 mount failure
2091//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002092 return rc;
2093}