blob: 23a3459311bb6d35cdfffffa0b11840339cee7e9 [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];
Denis Vlasenkof732e962008-02-18 12:07:49 +0000270
271};
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000272enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
Denis Vlasenkof732e962008-02-18 12:07:49 +0000273#define G (*(struct globals*)&bb_common_bufsiz1)
274#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000275#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000276#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000277#else
278#define verbose 0
279#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000280#define fslist (G.fslist )
281#define getmntent_buf (G.getmntent_buf )
282
283
284#if ENABLE_FEATURE_MOUNT_VERBOSE
285static int verbose_mount(const char *source, const char *target,
286 const char *filesystemtype,
287 unsigned long mountflags, const void *data)
288{
289 int rc;
290
291 errno = 0;
292 rc = mount(source, target, filesystemtype, mountflags, data);
293 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000294 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000295 source, target, filesystemtype,
296 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000297 return rc;
298}
299#else
300#define verbose_mount(...) mount(__VA_ARGS__)
301#endif
302
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000303// Append mount options to string
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000304static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000305{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000306 if (*oldopts && **oldopts) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000307 // Do not insert options which are already there
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000308 while (newopts[0]) {
309 char *p;
310 int len = strlen(newopts);
311 p = strchr(newopts, ',');
312 if (p) len = p - newopts;
313 p = *oldopts;
314 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000315 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000316 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000317 goto skip;
318 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000319 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000320 p++;
321 }
322 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
323 free(*oldopts);
324 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000325 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000326 newopts += len;
327 while (newopts[0] == ',') newopts++;
328 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000329 } else {
330 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000331 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000332 }
333}
334
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000335// Use the mount_options list to parse options into flags.
336// Also return list of unrecognized options if unrecognized != NULL
Denis Vlasenkob4133682008-02-18 13:05:38 +0000337static long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000338{
Denis Vlasenkob4133682008-02-18 13:05:38 +0000339 long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000340
Rob Landley6a6798b2005-08-10 20:35:54 +0000341 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000342 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000343 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000344 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000345 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000346
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000347 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000348
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000349// FIXME: use hasmntopt()
Rob Landley6a6798b2005-08-10 20:35:54 +0000350 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000351 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000352 if (!strcasecmp(option_str, options)) {
353 long fl = mount_options[i];
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000354 if (fl < 0) flags &= fl;
Rob Landleydc0955b2006-03-14 18:16:25 +0000355 else flags |= fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000356 break;
357 }
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000358 option_str += strlen(option_str) + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000359 }
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000360 // If unrecognized not NULL, append unrecognized mount options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000361 if (unrecognized && i == ARRAY_SIZE(mount_options)) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000362 // Add it to strflags, to pass on to kernel
Rob Landleydc0955b2006-03-14 18:16:25 +0000363 i = *unrecognized ? strlen(*unrecognized) : 0;
Denis Vlasenkodeeed592008-07-08 05:14:36 +0000364 *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000365
Rob Landley6a6798b2005-08-10 20:35:54 +0000366 // Comma separated if it's not the first one
Rob Landleydc0955b2006-03-14 18:16:25 +0000367 if (i) (*unrecognized)[i++] = ',';
368 strcpy((*unrecognized)+i, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000369 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000370
Denis Vlasenko2535f122007-09-15 13:28:30 +0000371 if (!comma)
372 break;
373 // Advance to next option
374 *comma = ',';
375 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000376 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000377
Rob Landleydc0955b2006-03-14 18:16:25 +0000378 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000379}
380
Rob Landleydc0955b2006-03-14 18:16:25 +0000381// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000382static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000383{
Denis Vlasenko87468852007-04-13 23:22:00 +0000384 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000385 "/etc/filesystems",
386 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000387 };
388 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200389 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000390 int i;
391 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000392
Denis Vlasenko87468852007-04-13 23:22:00 +0000393 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000394 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000395 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000396
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000397 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200398 if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
Denis Vlasenko372686b2006-10-12 22:42:33 +0000399 continue;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000400 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200401 if (*fs == '#' || *fs == '*' || !*fs)
402 continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000403
Denis Vlasenko372686b2006-10-12 22:42:33 +0000404 llist_add_to_end(&list, xstrdup(fs));
405 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000406 }
407 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
408 }
409
410 return list;
411}
412
Rob Landleydc0955b2006-03-14 18:16:25 +0000413#if ENABLE_FEATURE_CLEAN_UP
414static void delete_block_backed_filesystems(void)
415{
Rob Landleya6b5b602006-05-08 19:03:07 +0000416 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000417}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000418#else
419void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000420#endif
421
Rob Landleydc0955b2006-03-14 18:16:25 +0000422// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000423// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000424static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000425{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000426 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000427
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200428 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000429 if (verbose >= 2)
430 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
431 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
432 vfsflags, filteropts);
433 goto mtab;
434 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000435
Rob Landleydc0955b2006-03-14 18:16:25 +0000436 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000437 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000438 errno = 0;
439 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000440 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000441
442 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000443 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200444 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200445 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000446 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000447 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000448 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200449 if (FAKE_IT)
450 args[rc++] = (char *)"-f";
451 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
452 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000453 args[rc++] = mp->mnt_fsname;
454 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000455 if (filteropts) {
456 args[rc++] = (char *)"-o";
457 args[rc++] = filteropts;
458 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000459 args[rc] = NULL;
460 rc = wait4pid(spawn(args));
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000461 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000462 if (!rc)
463 break;
464 errno = errno_save;
465 }
466
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000467 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000468 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000469 if (!(vfsflags & MS_SILENT))
470 bb_error_msg("%s is write-protected, mounting read-only",
471 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000472 vfsflags |= MS_RDONLY;
473 }
474
Rob Landleydc0955b2006-03-14 18:16:25 +0000475 // Abort entirely if permission denied.
476
477 if (rc && errno == EPERM)
478 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
479
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000480 // If the mount was successful, and we're maintaining an old-style
481 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000482 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200483 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000484 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000485 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000486 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000487 int i;
488
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000489 if (!mountTable) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000490 bb_error_msg("no %s", bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000491 goto ret;
492 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000493
494 // Add vfs string flags
495
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000496 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
497 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
498 append_mount_options(&(mp->mnt_opts), option_str);
499 option_str += strlen(option_str) + 1;
500 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000501
502 // Remove trailing / (if any) from directory we mounted on
503
Denis Vlasenko727ef942006-09-14 13:19:19 +0000504 i = strlen(mp->mnt_dir) - 1;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000505 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000506
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000507 // Convert to canonical pathnames as needed
Denis Vlasenko727ef942006-09-14 13:19:19 +0000508
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000509 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000510 fsname = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000511 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000512 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000513 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000514 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000515 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000516
517 // Write and close.
518
Denis Vlasenko727ef942006-09-14 13:19:19 +0000519 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000520 endmntent(mountTable);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000521 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000522 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000523 free(fsname);
524 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000525 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000526 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000527 return rc;
528}
529
Denis Vlasenko25098f72006-09-14 15:46:33 +0000530#if ENABLE_FEATURE_MOUNT_NFS
531
532/*
533 * Linux NFS mount
534 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
535 *
536 * Licensed under GPLv2, see file LICENSE in this tarball for details.
537 *
538 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
539 * numbers to be specified on the command line.
540 *
541 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
542 * Omit the call to connect() for Linux version 1.3.11 or later.
543 *
544 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
545 * Implemented the "bg", "fg" and "retry" mount options for NFS.
546 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000547 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000548 * - added Native Language Support
549 *
550 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
551 * plus NFSv3 stuff.
552 */
553
Denis Vlasenko25098f72006-09-14 15:46:33 +0000554#define MOUNTPORT 635
555#define MNTPATHLEN 1024
556#define MNTNAMLEN 255
557#define FHSIZE 32
558#define FHSIZE3 64
559
560typedef char fhandle[FHSIZE];
561
562typedef struct {
563 unsigned int fhandle3_len;
564 char *fhandle3_val;
565} fhandle3;
566
567enum mountstat3 {
568 MNT_OK = 0,
569 MNT3ERR_PERM = 1,
570 MNT3ERR_NOENT = 2,
571 MNT3ERR_IO = 5,
572 MNT3ERR_ACCES = 13,
573 MNT3ERR_NOTDIR = 20,
574 MNT3ERR_INVAL = 22,
575 MNT3ERR_NAMETOOLONG = 63,
576 MNT3ERR_NOTSUPP = 10004,
577 MNT3ERR_SERVERFAULT = 10006,
578};
579typedef enum mountstat3 mountstat3;
580
581struct fhstatus {
582 unsigned int fhs_status;
583 union {
584 fhandle fhs_fhandle;
585 } fhstatus_u;
586};
587typedef struct fhstatus fhstatus;
588
589struct mountres3_ok {
590 fhandle3 fhandle;
591 struct {
592 unsigned int auth_flavours_len;
593 char *auth_flavours_val;
594 } auth_flavours;
595};
596typedef struct mountres3_ok mountres3_ok;
597
598struct mountres3 {
599 mountstat3 fhs_status;
600 union {
601 mountres3_ok mountinfo;
602 } mountres3_u;
603};
604typedef struct mountres3 mountres3;
605
606typedef char *dirpath;
607
608typedef char *name;
609
610typedef struct mountbody *mountlist;
611
612struct mountbody {
613 name ml_hostname;
614 dirpath ml_directory;
615 mountlist ml_next;
616};
617typedef struct mountbody mountbody;
618
619typedef struct groupnode *groups;
620
621struct groupnode {
622 name gr_name;
623 groups gr_next;
624};
625typedef struct groupnode groupnode;
626
627typedef struct exportnode *exports;
628
629struct exportnode {
630 dirpath ex_dir;
631 groups ex_groups;
632 exports ex_next;
633};
634typedef struct exportnode exportnode;
635
636struct ppathcnf {
637 int pc_link_max;
638 short pc_max_canon;
639 short pc_max_input;
640 short pc_name_max;
641 short pc_path_max;
642 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000643 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000644 char pc_xxx;
645 short pc_mask[2];
646};
647typedef struct ppathcnf ppathcnf;
648
649#define MOUNTPROG 100005
650#define MOUNTVERS 1
651
652#define MOUNTPROC_NULL 0
653#define MOUNTPROC_MNT 1
654#define MOUNTPROC_DUMP 2
655#define MOUNTPROC_UMNT 3
656#define MOUNTPROC_UMNTALL 4
657#define MOUNTPROC_EXPORT 5
658#define MOUNTPROC_EXPORTALL 6
659
660#define MOUNTVERS_POSIX 2
661
662#define MOUNTPROC_PATHCONF 7
663
664#define MOUNT_V3 3
665
666#define MOUNTPROC3_NULL 0
667#define MOUNTPROC3_MNT 1
668#define MOUNTPROC3_DUMP 2
669#define MOUNTPROC3_UMNT 3
670#define MOUNTPROC3_UMNTALL 4
671#define MOUNTPROC3_EXPORT 5
672
673enum {
674#ifndef NFS_FHSIZE
675 NFS_FHSIZE = 32,
676#endif
677#ifndef NFS_PORT
678 NFS_PORT = 2049
679#endif
680};
681
Denis Vlasenko25098f72006-09-14 15:46:33 +0000682/*
683 * We want to be able to compile mount on old kernels in such a way
684 * that the binary will work well on more recent kernels.
685 * Thus, if necessary we teach nfsmount.c the structure of new fields
686 * that will come later.
687 *
688 * Moreover, the new kernel includes conflict with glibc includes
689 * so it is easiest to ignore the kernel altogether (at compile time).
690 */
691
692struct nfs2_fh {
693 char data[32];
694};
695struct nfs3_fh {
696 unsigned short size;
697 unsigned char data[64];
698};
699
700struct nfs_mount_data {
701 int version; /* 1 */
702 int fd; /* 1 */
703 struct nfs2_fh old_root; /* 1 */
704 int flags; /* 1 */
705 int rsize; /* 1 */
706 int wsize; /* 1 */
707 int timeo; /* 1 */
708 int retrans; /* 1 */
709 int acregmin; /* 1 */
710 int acregmax; /* 1 */
711 int acdirmin; /* 1 */
712 int acdirmax; /* 1 */
713 struct sockaddr_in addr; /* 1 */
714 char hostname[256]; /* 1 */
715 int namlen; /* 2 */
716 unsigned int bsize; /* 3 */
717 struct nfs3_fh root; /* 4 */
718};
719
720/* bits in the flags field */
721enum {
722 NFS_MOUNT_SOFT = 0x0001, /* 1 */
723 NFS_MOUNT_INTR = 0x0002, /* 1 */
724 NFS_MOUNT_SECURE = 0x0004, /* 1 */
725 NFS_MOUNT_POSIX = 0x0008, /* 1 */
726 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
727 NFS_MOUNT_NOAC = 0x0020, /* 1 */
728 NFS_MOUNT_TCP = 0x0040, /* 2 */
729 NFS_MOUNT_VER3 = 0x0080, /* 3 */
730 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000731 NFS_MOUNT_NONLM = 0x0200, /* 3 */
732 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +0000733};
734
735
736/*
737 * We need to translate between nfs status return values and
738 * the local errno values which may not be the same.
739 *
740 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
741 * "after #include <errno.h> the symbol errno is reserved for any use,
742 * it cannot even be used as a struct tag or field name".
743 */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000744#ifndef EDQUOT
Denys Vlasenkocc428142009-12-16 02:06:56 +0100745# define EDQUOT ENOSPC
Denis Vlasenko25098f72006-09-14 15:46:33 +0000746#endif
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000747/* Convert each NFSERR_BLAH into EBLAH */
Denys Vlasenkocc428142009-12-16 02:06:56 +0100748static const uint8_t nfs_err_stat[] = {
749 1, 2, 5, 6, 13, 17,
750 19, 20, 21, 22, 27, 28,
751 30, 63, 66, 69, 70, 71
752};
753static const uint8_t nfs_err_errnum[] = {
754 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
755 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
756 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
Denis Vlasenko25098f72006-09-14 15:46:33 +0000757};
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
Denys Vlasenkocc428142009-12-16 02:06:56 +0100762 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
763 if (nfs_err_stat[i] == status)
764 return strerror(nfs_err_errnum[i]);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000765 }
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{
Denys Vlasenkocc428142009-12-16 02:06:56 +0100800 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
801 (unsigned int *) &objp->fhandle3_len,
802 FHSIZE3)
803 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +0000804 return FALSE;
Denys Vlasenkocc428142009-12-16 02:06:56 +0100805 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000806 return TRUE;
807}
808
809static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
810{
811 if (!xdr_fhandle3(xdrs, &objp->fhandle))
812 return FALSE;
Denys Vlasenkocc428142009-12-16 02:06:56 +0100813 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
814 &(objp->auth_flavours.auth_flavours_len),
815 ~0,
816 sizeof(int),
817 (xdrproc_t) xdr_int)
818 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +0000819 return FALSE;
Denys Vlasenkocc428142009-12-16 02:06:56 +0100820 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000821 return TRUE;
822}
823
824static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
825{
826 if (!xdr_enum(xdrs, (enum_t *) objp))
827 return FALSE;
828 return TRUE;
829}
830
831static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
832{
833 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
834 return FALSE;
835 switch (objp->fhs_status) {
836 case MNT_OK:
837 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
838 return FALSE;
839 break;
840 default:
841 break;
842 }
843 return TRUE;
844}
845
846#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
847
Denis Vlasenko25098f72006-09-14 15:46:33 +0000848/*
849 * Unfortunately, the kernel prints annoying console messages
850 * in case of an unexpected nfs mount version (instead of
851 * just returning some error). Therefore we'll have to try
852 * and figure out what version the kernel expects.
853 *
854 * Variables:
855 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
856 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
857 * nfs_mount_version: version this source and running kernel can handle
858 */
859static void
860find_kernel_nfs_mount_version(void)
861{
Denis Vlasenkob9256052007-09-28 10:29:17 +0000862 int kernel_version;
863
864 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000865 return;
866
867 nfs_mount_version = 4; /* default */
868
869 kernel_version = get_linux_version_code();
870 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +0100871 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +0000872 nfs_mount_version = 3;
873 /* else v4 since 2.3.99pre4 */
874 }
875}
876
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000877static void
Denis Vlasenkob9256052007-09-28 10:29:17 +0000878get_mountport(struct pmap *pm_mnt,
879 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +0000880 long unsigned prog,
881 long unsigned version,
882 long unsigned proto,
883 long unsigned port)
884{
885 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000886
887 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +0000888/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
889 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000890 pmap = pmap_getmaps(server_addr);
891
892 if (version > MAX_NFSPROT)
893 version = MAX_NFSPROT;
894 if (!prog)
895 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000896 pm_mnt->pm_prog = prog;
897 pm_mnt->pm_vers = version;
898 pm_mnt->pm_prot = proto;
899 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000900
Denis Vlasenko25098f72006-09-14 15:46:33 +0000901 while (pmap) {
902 if (pmap->pml_map.pm_prog != prog)
903 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000904 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000905 goto next;
906 if (version > 2 && pmap->pml_map.pm_vers != version)
907 goto next;
908 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
909 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100910 if (pmap->pml_map.pm_vers > MAX_NFSPROT
911 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
912 || (port && pmap->pml_map.pm_port != port)
913 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +0000914 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100915 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000916 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
917 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +0000918 pmap = pmap->pml_next;
919 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000920 if (!pm_mnt->pm_vers)
921 pm_mnt->pm_vers = MOUNTVERS;
922 if (!pm_mnt->pm_port)
923 pm_mnt->pm_port = MOUNTPORT;
924 if (!pm_mnt->pm_prot)
925 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000926}
927
Denis Vlasenkof0000652007-09-04 18:30:26 +0000928#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +0000929static int daemonize(void)
930{
Denis Vlasenko25098f72006-09-14 15:46:33 +0000931 int pid = fork();
932 if (pid < 0) /* error */
933 return -errno;
934 if (pid > 0) /* parent */
935 return 0;
936 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000937 close(0);
938 xopen(bb_dev_null, O_RDWR);
939 xdup2(0, 1);
940 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000941 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000942 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000943 logmode = LOGMODE_SYSLOG;
944 return 1;
945}
Denis Vlasenkof0000652007-09-04 18:30:26 +0000946#else
947static inline int daemonize(void) { return -ENOSYS; }
948#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000949
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000950/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000951static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000952{
953 return 0;
954}
955
956/* RPC strerror analogs are terminally idiotic:
957 * *mandatory* prefix and \n at end.
958 * This hopefully helps. Usage:
959 * error_msg_rpc(clnt_*error*(" ")) */
960static void error_msg_rpc(const char *msg)
961{
Denis Vlasenko23514fe2006-09-19 14:07:52 +0000962 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000963 while (msg[0] == ' ' || msg[0] == ':') msg++;
964 len = strlen(msg);
965 while (len && msg[len-1] == '\n') len--;
966 bb_error_msg("%.*s", len, msg);
967}
968
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000969/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko810b7162009-05-13 23:48:59 +0200970static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000971{
972 CLIENT *mclient;
973 char *hostname;
974 char *pathname;
975 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +0200976 /* prior to 2.6.23, kernel took NFS options in a form of this struct
977 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
978 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000979 struct nfs_mount_data data;
980 char *opt;
981 struct hostent *hp;
982 struct sockaddr_in server_addr;
983 struct sockaddr_in mount_server_addr;
984 int msock, fsock;
985 union {
986 struct fhstatus nfsv2;
987 struct mountres3 nfsv3;
988 } status;
989 int daemonized;
990 char *s;
991 int port;
992 int mountport;
993 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000994#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000995 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +0000996#else
997 enum { bg = 0 };
998#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000999 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001000 int mountprog;
1001 int mountvers;
1002 int nfsprog;
1003 int nfsvers;
1004 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001005 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001006 smallint tcp;
1007 smallint soft;
1008 int intr;
1009 int posix;
1010 int nocto;
1011 int noac;
1012 int nordirplus;
1013 int nolock;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001014
1015 find_kernel_nfs_mount_version();
1016
1017 daemonized = 0;
1018 mounthost = NULL;
1019 retval = ETIMEDOUT;
1020 msock = fsock = -1;
1021 mclient = NULL;
1022
1023 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1024
1025 filteropts = xstrdup(filteropts); /* going to trash it later... */
1026
1027 hostname = xstrdup(mp->mnt_fsname);
1028 /* mount_main() guarantees that ':' is there */
1029 s = strchr(hostname, ':');
1030 pathname = s + 1;
1031 *s = '\0';
1032 /* Ignore all but first hostname in replicated mounts
1033 until they can be fully supported. (mack@sgi.com) */
1034 s = strchr(hostname, ',');
1035 if (s) {
1036 *s = '\0';
1037 bb_error_msg("warning: multiple hostnames not supported");
1038 }
1039
1040 server_addr.sin_family = AF_INET;
1041 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1042 hp = gethostbyname(hostname);
1043 if (hp == NULL) {
1044 bb_herror_msg("%s", hostname);
1045 goto fail;
1046 }
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001047 if ((size_t)hp->h_length > sizeof(struct in_addr)) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001048 bb_error_msg("got bad hp->h_length");
1049 hp->h_length = sizeof(struct in_addr);
1050 }
1051 memcpy(&server_addr.sin_addr,
1052 hp->h_addr, hp->h_length);
1053 }
1054
1055 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1056
1057 /* add IP address to mtab options for use when unmounting */
1058
1059 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1060 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1061 } else {
1062 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1063 mp->mnt_opts[0] ? "," : "",
1064 inet_ntoa(server_addr.sin_addr));
1065 free(mp->mnt_opts);
1066 mp->mnt_opts = tmp;
1067 }
1068
1069 /* Set default options.
1070 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1071 * let the kernel decide.
1072 * timeo is filled in after we know whether it'll be TCP or UDP. */
1073 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001074 data.retrans = 3;
1075 data.acregmin = 3;
1076 data.acregmax = 60;
1077 data.acdirmin = 30;
1078 data.acdirmax = 60;
1079 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001080
Denis Vlasenko25098f72006-09-14 15:46:33 +00001081 soft = 0;
1082 intr = 0;
1083 posix = 0;
1084 nocto = 0;
1085 nolock = 0;
1086 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001087 nordirplus = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001088 retry = 10000; /* 10000 minutes ~ 1 week */
1089 tcp = 0;
1090
1091 mountprog = MOUNTPROG;
1092 mountvers = 0;
1093 port = 0;
1094 mountport = 0;
1095 nfsprog = 100003;
1096 nfsvers = 0;
1097
1098 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001099 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001100 char *opteq = strchr(opt, '=');
1101 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001102 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001103 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001104 /* 0 */ "rsize\0"
1105 /* 1 */ "wsize\0"
1106 /* 2 */ "timeo\0"
1107 /* 3 */ "retrans\0"
1108 /* 4 */ "acregmin\0"
1109 /* 5 */ "acregmax\0"
1110 /* 6 */ "acdirmin\0"
1111 /* 7 */ "acdirmax\0"
1112 /* 8 */ "actimeo\0"
1113 /* 9 */ "retry\0"
1114 /* 10 */ "port\0"
1115 /* 11 */ "mountport\0"
1116 /* 12 */ "mounthost\0"
1117 /* 13 */ "mountprog\0"
1118 /* 14 */ "mountvers\0"
1119 /* 15 */ "nfsprog\0"
1120 /* 16 */ "nfsvers\0"
1121 /* 17 */ "vers\0"
1122 /* 18 */ "proto\0"
1123 /* 19 */ "namlen\0"
1124 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001125
1126 *opteq++ = '\0';
1127 idx = index_in_strings(options, opt);
1128 switch (idx) {
1129 case 12: // "mounthost"
1130 mounthost = xstrndup(opteq,
1131 strcspn(opteq, " \t\n\r,"));
1132 continue;
1133 case 18: // "proto"
1134 if (!strncmp(opteq, "tcp", 3))
1135 tcp = 1;
1136 else if (!strncmp(opteq, "udp", 3))
1137 tcp = 0;
1138 else
1139 bb_error_msg("warning: unrecognized proto= option");
1140 continue;
1141 case 20: // "addr" - ignore
1142 continue;
1143 }
1144
1145 val = xatoi_u(opteq);
1146 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001147 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001148 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001149 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001150 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001151 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001152 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001153 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001154 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001155 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001156 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001157 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001158 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001159 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001160 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001161 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001162 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001163 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001164 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001165 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001166 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001167 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001168 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001169 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001170 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001171 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001172 data.acregmin = val;
1173 data.acregmax = val;
1174 data.acdirmin = val;
1175 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001176 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001177 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001178 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001179 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001180 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001181 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001182 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001183 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001184 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001185 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001186 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001187 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001188 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001189 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001190 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001191 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001192 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001193 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001194 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001195 case 16: // "nfsvers"
1196 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001197 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001198 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001199 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001200 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001201 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001202 //else
1203 // bb_error_msg("warning: option namlen is not supported\n");
1204 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001205 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001206 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1207 goto fail;
1208 }
1209 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001210 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001211 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001212 "bg\0"
1213 "fg\0"
1214 "soft\0"
1215 "hard\0"
1216 "intr\0"
1217 "posix\0"
1218 "cto\0"
1219 "ac\0"
1220 "tcp\0"
1221 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001222 "lock\0"
1223 "rdirplus\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001224 int val = 1;
1225 if (!strncmp(opt, "no", 2)) {
1226 val = 0;
1227 opt += 2;
1228 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001229 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001230 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001231#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001232 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001233#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001234 break;
1235 case 1: // "fg"
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 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001241 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001242 break;
1243 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001244 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001245 break;
1246 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001247 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001248 break;
1249 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001250 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001251 break;
1252 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001253 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001254 break;
1255 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001256 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001257 break;
1258 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001259 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001260 break;
1261 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001262 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001263 break;
1264 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001265 if (nfs_mount_version >= 3)
1266 nolock = !val;
1267 else
1268 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001269 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001270 case 11: //rdirplus
1271 nordirplus = !val;
1272 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001273 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001274 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1275 goto fail;
1276 }
1277 }
1278 }
1279 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1280
1281 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1282 | (intr ? NFS_MOUNT_INTR : 0)
1283 | (posix ? NFS_MOUNT_POSIX : 0)
1284 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001285 | (noac ? NFS_MOUNT_NOAC : 0)
1286 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001287 if (nfs_mount_version >= 2)
1288 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1289 if (nfs_mount_version >= 3)
1290 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1291 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1292 bb_error_msg("NFSv%d not supported", nfsvers);
1293 goto fail;
1294 }
1295 if (nfsvers && !mountvers)
1296 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1297 if (nfsvers && nfsvers < mountvers) {
1298 mountvers = nfsvers;
1299 }
1300
1301 /* Adjust options if none specified */
1302 if (!data.timeo)
1303 data.timeo = tcp ? 70 : 7;
1304
Denis Vlasenko25098f72006-09-14 15:46:33 +00001305 data.version = nfs_mount_version;
1306
1307 if (vfsflags & MS_REMOUNT)
1308 goto do_mount;
1309
1310 /*
1311 * If the previous mount operation on the same host was
1312 * backgrounded, and the "bg" for this mount is also set,
1313 * give up immediately, to avoid the initial timeout.
1314 */
1315 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001316 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001317 if (daemonized <= 0) { /* parent or error */
1318 retval = -daemonized;
1319 goto ret;
1320 }
1321 }
1322
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001323 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001324 /* See if the nfs host = mount host. */
1325 if (mounthost) {
1326 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1327 mount_server_addr.sin_family = AF_INET;
1328 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1329 } else {
1330 hp = gethostbyname(mounthost);
1331 if (hp == NULL) {
1332 bb_herror_msg("%s", mounthost);
1333 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001334 }
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001335 if ((size_t)hp->h_length > sizeof(struct in_addr)) {
1336 bb_error_msg("got bad hp->h_length");
1337 hp->h_length = sizeof(struct in_addr);
1338 }
1339 mount_server_addr.sin_family = AF_INET;
1340 memcpy(&mount_server_addr.sin_addr,
1341 hp->h_addr, hp->h_length);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001342 }
1343 }
1344
1345 /*
1346 * The following loop implements the mount retries. When the mount
1347 * times out, and the "bg" option is set, we background ourself
1348 * and continue trying.
1349 *
1350 * The case where the mount point is not present and the "bg"
1351 * option is set, is treated as a timeout. This is done to
1352 * support nested mounts.
1353 *
1354 * The "retry" count specified by the user is the number of
1355 * minutes to retry before giving up.
1356 */
1357 {
1358 struct timeval total_timeout;
1359 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001360 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001361 time_t t;
1362 time_t prevt;
1363 time_t timeout;
1364
1365 retry_timeout.tv_sec = 3;
1366 retry_timeout.tv_usec = 0;
1367 total_timeout.tv_sec = 20;
1368 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001369/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001370 timeout = time(NULL) + 60 * retry;
1371 prevt = 0;
1372 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001373 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001374 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001375 if (t - prevt < 30)
1376 sleep(30);
1377
Denis Vlasenkob9256052007-09-28 10:29:17 +00001378 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001379 mountprog,
1380 mountvers,
1381 proto,
1382 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001383 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001384
1385 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001386 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001387 msock = RPC_ANYSOCK;
1388
Denis Vlasenkob9256052007-09-28 10:29:17 +00001389 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001390 case IPPROTO_UDP:
1391 mclient = clntudp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001392 pm_mnt.pm_prog,
1393 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001394 retry_timeout,
1395 &msock);
1396 if (mclient)
1397 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001398 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001399 msock = RPC_ANYSOCK;
1400 case IPPROTO_TCP:
1401 mclient = clnttcp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001402 pm_mnt.pm_prog,
1403 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001404 &msock, 0, 0);
1405 break;
1406 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001407 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001408 }
1409 if (!mclient) {
1410 if (!daemonized && prevt == 0)
1411 error_msg_rpc(clnt_spcreateerror(" "));
1412 } else {
1413 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001414
1415 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001416 mclient->cl_auth = authunix_create_default();
1417
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001418 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001419 * that xdr_array allocates memory for us
1420 */
1421 memset(&status, 0, sizeof(status));
1422
Denis Vlasenkob9256052007-09-28 10:29:17 +00001423 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001424 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1425 (xdrproc_t) xdr_dirpath,
1426 (caddr_t) &pathname,
1427 (xdrproc_t) xdr_mountres3,
1428 (caddr_t) &status,
1429 total_timeout);
1430 else
1431 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1432 (xdrproc_t) xdr_dirpath,
1433 (caddr_t) &pathname,
1434 (xdrproc_t) xdr_fhstatus,
1435 (caddr_t) &status,
1436 total_timeout);
1437
1438 if (clnt_stat == RPC_SUCCESS)
1439 goto prepare_kernel_data; /* we're done */
1440 if (errno != ECONNREFUSED) {
1441 error_msg_rpc(clnt_sperror(mclient, " "));
1442 goto fail; /* don't retry */
1443 }
1444 /* Connection refused */
1445 if (!daemonized && prevt == 0) /* print just once */
1446 error_msg_rpc(clnt_sperror(mclient, " "));
1447 auth_destroy(mclient->cl_auth);
1448 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001449 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001450 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001451 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001452 }
1453
1454 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001455 if (!bg)
1456 goto fail;
1457 if (!daemonized) {
1458 daemonized = daemonize();
1459 if (daemonized <= 0) { /* parent or error */
1460 retval = -daemonized;
1461 goto ret;
1462 }
1463 }
1464 prevt = t;
1465 t = time(NULL);
1466 if (t >= timeout)
1467 /* TODO error message */
1468 goto fail;
1469
1470 goto retry;
1471 }
1472
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001473 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001474
1475 if (nfsvers == 2) {
1476 if (status.nfsv2.fhs_status != 0) {
1477 bb_error_msg("%s:%s failed, reason given by server: %s",
1478 hostname, pathname,
1479 nfs_strerror(status.nfsv2.fhs_status));
1480 goto fail;
1481 }
1482 memcpy(data.root.data,
1483 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1484 NFS_FHSIZE);
1485 data.root.size = NFS_FHSIZE;
1486 memcpy(data.old_root.data,
1487 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1488 NFS_FHSIZE);
1489 } else {
1490 fhandle3 *my_fhandle;
1491 if (status.nfsv3.fhs_status != 0) {
1492 bb_error_msg("%s:%s failed, reason given by server: %s",
1493 hostname, pathname,
1494 nfs_strerror(status.nfsv3.fhs_status));
1495 goto fail;
1496 }
1497 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1498 memset(data.old_root.data, 0, NFS_FHSIZE);
1499 memset(&data.root, 0, sizeof(data.root));
1500 data.root.size = my_fhandle->fhandle3_len;
1501 memcpy(data.root.data,
1502 (char *) my_fhandle->fhandle3_val,
1503 my_fhandle->fhandle3_len);
1504
1505 data.flags |= NFS_MOUNT_VER3;
1506 }
1507
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001508 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001509 if (tcp) {
1510 if (nfs_mount_version < 3) {
1511 bb_error_msg("NFS over TCP is not supported");
1512 goto fail;
1513 }
1514 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1515 } else
1516 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1517 if (fsock < 0) {
1518 bb_perror_msg("nfs socket");
1519 goto fail;
1520 }
1521 if (bindresvport(fsock, 0) < 0) {
1522 bb_perror_msg("nfs bindresvport");
1523 goto fail;
1524 }
1525 if (port == 0) {
1526 server_addr.sin_port = PMAPPORT;
1527 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1528 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1529 if (port == 0)
1530 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001531 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001532 server_addr.sin_port = htons(port);
1533
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001534 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001535 data.fd = fsock;
1536 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1537 strncpy(data.hostname, hostname, sizeof(data.hostname));
1538
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001539 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001540 auth_destroy(mclient->cl_auth);
1541 clnt_destroy(mclient);
1542 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001543 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001544
1545 if (bg) {
1546 /* We must wait until mount directory is available */
1547 struct stat statbuf;
1548 int delay = 1;
1549 while (stat(mp->mnt_dir, &statbuf) == -1) {
1550 if (!daemonized) {
1551 daemonized = daemonize();
1552 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001553/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001554 retval = -daemonized;
1555 goto ret;
1556 }
1557 }
1558 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1559 delay *= 2;
1560 if (delay > 30)
1561 delay = 30;
1562 }
1563 }
1564
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001565 /* Perform actual mount */
1566 do_mount:
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001567 mp->mnt_type = (char*)"nfs";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001568 retval = mount_it_now(mp, vfsflags, (char*)&data);
1569 goto ret;
1570
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001571 /* Abort */
1572 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001573 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001574 if (mclient) {
1575 auth_destroy(mclient->cl_auth);
1576 clnt_destroy(mclient);
1577 }
1578 close(msock);
1579 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001580 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001581 close(fsock);
1582
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001583 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001584 free(hostname);
1585 free(mounthost);
1586 free(filteropts);
1587 return retval;
1588}
1589
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001590#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001591
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001592// Never called. Call should be optimized out.
Denis Vlasenkob4133682008-02-18 13:05:38 +00001593int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001594
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001595#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001596
1597// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1598// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001599// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001600static int singlemount(struct mntent *mp, int ignore_busy)
1601{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001602 int rc = -1;
1603 long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001604 char *loopFile = NULL, *filteropts = NULL;
1605 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001606 struct stat st;
1607
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001608 errno = 0;
1609
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001610 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1611
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001612 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001613 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1614 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001615
Denis Vlasenko2535f122007-09-15 13:28:30 +00001616 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001617 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1618 char *args[35];
1619 char *s;
1620 int n;
1621 // fsname: "cmd#arg1#arg2..."
1622 // WARNING: allows execution of arbitrary commands!
1623 // Try "mount 'sh#-c#sh' bogus_dir".
1624 // It is safe ONLY because non-root
1625 // cannot use two-argument mount command
1626 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1627 // "mount: can't find sh#-c#sh in /etc/fstab"
1628 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1629
1630 s = mp->mnt_fsname;
1631 n = 0;
1632 args[n++] = s;
1633 while (*s && n < 35 - 2) {
1634 if (*s++ == '#' && *s != '#') {
1635 s[-1] = '\0';
1636 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001637 }
1638 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001639 args[n++] = mp->mnt_dir;
1640 args[n] = NULL;
1641 rc = wait4pid(xspawn(args));
1642 goto report_error;
1643 }
1644
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001645 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001646 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001647 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1648 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1649 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001650 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001651 int len;
1652 char c;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001653 len_and_sockaddr *lsa;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001654 char *hostname, *dotted, *ip;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001655
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001656 hostname = mp->mnt_fsname + 2;
1657 len = strcspn(hostname, "/\\");
1658 if (len == 0 || hostname[len] == '\0')
Denis Vlasenko5c329932009-04-12 12:16:21 +00001659 goto report_error;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001660 c = hostname[len];
1661 hostname[len] = '\0';
1662 lsa = host2sockaddr(hostname, 0);
1663 hostname[len] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001664 if (!lsa)
1665 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001666
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001667 // Insert "ip=..." option into options
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001668 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001669 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001670 ip = xasprintf("ip=%s", dotted);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001671 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001672 parse_mount_options(ip, &filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001673 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001674
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001675 // "-o mand" is required [why?]
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001676 vfsflags |= MS_MANDLOCK;
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001677 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001678 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001679
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001680 goto report_error;
1681 }
1682
1683 // Might this be an NFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001684 if (ENABLE_FEATURE_MOUNT_NFS
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001685 && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001686 && strchr(mp->mnt_fsname, ':') != NULL
1687 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001688 rc = nfsmount(mp, vfsflags, filteropts);
1689 goto report_error;
1690 }
1691
1692 // Look at the file. (Not found isn't a failure for remount, or for
1693 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001694 // (We use stat, not lstat, in order to allow
1695 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001696 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001697 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1698 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001699 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001700 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1701 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001702 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001703 if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001704 if (errno == EPERM || errno == EACCES)
1705 bb_error_msg(bb_msg_perm_denied_are_you_root);
1706 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01001707 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00001708 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001709 }
1710
1711 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001712 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1713 vfsflags |= MS_BIND;
1714 }
1715
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001716 // If we know the fstype (or don't need to), jump straight
1717 // to the actual mount.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001718 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1719 rc = mount_it_now(mp, vfsflags, filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001720 else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001721 // Loop through filesystem types until mount succeeds
1722 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001723
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001724 // Initialize list of block backed filesystems.
1725 // This has to be done here so that during "mount -a",
1726 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001727 if (!fslist) {
1728 fslist = get_block_backed_filesystems();
1729 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1730 atexit(delete_block_backed_filesystems);
1731 }
1732
1733 for (fl = fslist; fl; fl = fl->link) {
1734 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00001735 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001736 if (!rc)
1737 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001738 }
1739 }
1740
1741 // If mount failed, clean up loop file (if any).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001742 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1743 del_loop(mp->mnt_fsname);
1744 if (ENABLE_FEATURE_CLEAN_UP) {
1745 free(loopFile);
1746 free(mp->mnt_fsname);
1747 }
1748 }
1749
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001750 report_error:
1751 if (ENABLE_FEATURE_CLEAN_UP)
1752 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001753
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00001754 if (errno == EBUSY && ignore_busy)
1755 return 0;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001756 if (rc < 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001757 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001758 return rc;
1759}
1760
Michael Abbott6b5accb2009-12-04 03:33:07 +01001761// -O support
1762// -O interprets a list of filter options which select whether a mount
1763// point will be mounted: only mounts with options matching *all* filtering
1764// options will be selected.
1765// By default each -O filter option must be present in the list of mount
1766// options, but if it is prefixed by "no" then it must be absent.
1767// For example,
1768// -O a,nob,c matches -o a,c but fails to match -o a,b,c
1769// (and also fails to match -o a because -o c is absent).
1770//
1771// It is different from -t in that each option is matched exactly; a leading
1772// "no" at the beginning of one option does not negate the rest.
1773static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001774{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001775 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01001776 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001777
Michael Abbott6b5accb2009-12-04 03:33:07 +01001778 while (*O_opt) {
1779 const char *fs_opt = fs_opt_in;
1780 int O_len;
1781 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001782
Michael Abbott6b5accb2009-12-04 03:33:07 +01001783 // If option begins with "no" then treat as an inverted match:
1784 // matching is a failure
1785 match = 0;
1786 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
1787 match = 1;
1788 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001789 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001790 // Isolate the current O option
1791 O_len = strchrnul(O_opt, ',') - O_opt;
1792 // Check for a match against existing options
1793 while (1) {
1794 if (strncmp(fs_opt, O_opt, O_len) == 0
1795 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
1796 ) {
1797 if (match)
1798 return 0; // "no" prefix, but option found
1799 match = 1; // current O option found, go check next one
1800 break;
1801 }
1802 fs_opt = strchr(fs_opt, ',');
1803 if (!fs_opt)
1804 break;
1805 fs_opt++;
1806 }
1807 if (match == 0)
1808 return 0; // match wanted but not found
1809 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001810 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01001811 // Step to the next O option
1812 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001813 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001814 // If we get here then everything matched
1815 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001816}
1817
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001818// Parse options, if necessary parse fstab/mtab, and call singlemount for
1819// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001820int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001821int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001822{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001823 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001824 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001825 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001826 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001827 llist_t *lst_o = NULL;
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001828 const char *fstabname;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001829 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001830 int i, j;
1831 int rc = EXIT_SUCCESS;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001832 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001833 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001834 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001835
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001836 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00001837
Denis Vlasenkof732e962008-02-18 12:07:49 +00001838 // Parse long options, like --bind and --move. Note that -o option
1839 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001840 for (i = j = 1; argv[i]; i++) {
1841 if (argv[i][0] == '-' && argv[i][1] == '-')
1842 append_mount_options(&cmdopts, argv[i] + 2);
1843 else
1844 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001845 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001846 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001847
1848 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001849 // Max 2 params; -o is a list, -v is a counter
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001850 opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001851 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001852 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001853 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00001854 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1855 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001856 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001857
1858 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001859 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00001860 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001861 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1862
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001863 if (!mountTable)
1864 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001865
Denis Vlasenko2535f122007-09-15 13:28:30 +00001866 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001867 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001868 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001869 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00001870 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001871 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001872
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001873 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001874 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1875 mtpair->mnt_dir, mtpair->mnt_type,
1876 mtpair->mnt_opts);
1877 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001878 if (ENABLE_FEATURE_CLEAN_UP)
1879 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001880 return EXIT_SUCCESS;
1881 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001882 storage_path = NULL;
1883 } else {
1884 // When we have two arguments, the second is the directory and we can
1885 // skip looking at fstab entirely. We can always abspath() the directory
1886 // argument when we get it.
1887 if (argv[1]) {
1888 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001889 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001890 mtpair->mnt_fsname = argv[0];
1891 mtpair->mnt_dir = argv[1];
1892 mtpair->mnt_type = fstype;
1893 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001894 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001895 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001896 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001897 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001898 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001899 }
1900
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001901 // Past this point, we are handling either "mount -a [opts]"
1902 // or "mount [opts] single_param"
1903
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001904 i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001905 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001906 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00001907
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001908 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001909 if (ENABLE_FEATURE_MOUNT_FLAGS
1910 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1911 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001912 // verbose_mount(source, target, type, flags, data)
1913 rc = verbose_mount("", argv[0], "", i, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001914 if (rc)
1915 bb_simple_perror_msg_and_die(argv[0]);
1916 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001917 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001918
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001919 // Open either fstab or mtab
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001920 fstabname = "/etc/fstab";
1921 if (i & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001922 // WARNING. I am not sure this matches util-linux's
1923 // behavior. It's possible util-linux does not
1924 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001925 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001926 }
1927 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001928 if (!fstab)
Denys Vlasenko6331cf02009-11-13 09:08:27 +01001929 bb_perror_msg_and_die("can't read %s", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001930
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001931 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00001932 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001933 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001934 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001935
1936 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00001937 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001938 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001939 GETMNTENT_BUFSIZE/2)
1940 ) { // End of fstab/mtab is reached
1941 mtcur = mtother; // the thing we found last time
1942 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001943 }
1944
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001945 // If we're trying to mount something specific and this isn't it,
1946 // skip it. Note we must match the exact text in fstab (ala
1947 // "proc") or a full path from root
1948 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001949
1950 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001951 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
1952 && strcmp(storage_path, mtcur->mnt_fsname) != 0
1953 && strcmp(argv[0], mtcur->mnt_dir) != 0
1954 && strcmp(storage_path, mtcur->mnt_dir) != 0
1955 ) {
1956 continue; // no
1957 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001958
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001959 // Remember this entry. Something later may have
1960 // overmounted it, and we want the _last_ match.
1961 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001962
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001963 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001964 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001965 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001966 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001967 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001968 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001969 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001970
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001971 // Does type match? (NULL matches always)
1972 if (!match_fstype(mtcur, fstype))
1973 continue;
1974
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001975 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001976 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
1977 // swap is bogus "fstype", parse_mount_options can't check fstypes
1978 || strcasecmp(mtcur->mnt_type, "swap") == 0
1979 ) {
1980 continue;
1981 }
1982
1983 // Does (at least one) option match?
1984 // (NULL matches always)
1985 if (!match_opt(mtcur->mnt_opts, O_optmatch))
1986 continue;
1987
1988 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001989
Denis Vlasenko666da5e2006-12-26 18:17:42 +00001990 // NFS mounts want this to be xrealloc-able
1991 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001992
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001993 // If nothing is mounted on this directory...
1994 // (otherwise repeated "mount -a" mounts everything again)
1995 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
1996 // We do not check fsname match of found mount point -
1997 // "/" may have fsname of "/dev/root" while fstab
1998 // says "/dev/something_else".
1999 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01002000 if (verbose) {
2001 bb_error_msg("according to %s, "
2002 "%s is already mounted on %s",
2003 bb_path_mtab_file,
2004 mp->mnt_fsname, mp->mnt_dir);
2005 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002006 } else {
2007 // ...mount this thing
2008 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2009 // Count number of failed mounts
2010 rc++;
2011 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002012 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002013 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002014 }
2015 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002016
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002017 // End of fstab/mtab is reached.
2018 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002019 if (argv[0]) { // yes
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002020 long l;
2021
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002022 // If we didn't find anything, complain
2023 if (!mtcur->mnt_fsname)
2024 bb_error_msg_and_die("can't find %s in %s",
2025 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002026
2027 // What happens when we try to "mount swap_partition"?
2028 // (fstab containts "swap_partition swap swap defaults 0 0")
2029 // util-linux-ng 2.13.1 does this:
2030 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2031 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2032 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2033 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2034 // exit_group(32) = ?
2035#if 0
2036 // In case we want to simply skip swap partitions:
2037 l = parse_mount_options(mtcur->mnt_opts, NULL);
2038 if ((l & MOUNT_SWAP)
2039 // swap is bogus "fstype", parse_mount_options can't check fstypes
2040 || strcasecmp(mtcur->mnt_type, "swap") == 0
2041 ) {
2042 goto ret;
2043 }
2044#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002045 if (nonroot) {
2046 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002047 l = parse_mount_options(mtcur->mnt_opts, NULL);
2048 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002049 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002050 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002051
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002052 //util-linux-2.12 does not do this check.
2053 //// If nothing is mounted on this directory...
2054 //// (otherwise repeated "mount FOO" mounts FOO again)
2055 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2056 //if (mp) {
2057 // bb_error_msg("according to %s, "
2058 // "%s is already mounted on %s",
2059 // bb_path_mtab_file,
2060 // mp->mnt_fsname, mp->mnt_dir);
2061 //} else {
2062 // ...mount the last thing we found
2063 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2064 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2065 resolve_mount_spec(&mtpair->mnt_fsname);
2066 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2067 if (ENABLE_FEATURE_CLEAN_UP)
2068 free(mtcur->mnt_opts);
2069 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002070 }
2071
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002072 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002073 if (ENABLE_FEATURE_CLEAN_UP)
2074 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002075 if (ENABLE_FEATURE_CLEAN_UP) {
2076 free(storage_path);
2077 free(cmdopts);
2078 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002079
2080//TODO: exitcode should be ORed mask of (from "man mount"):
2081// 0 success
2082// 1 incorrect invocation or permissions
2083// 2 system error (out of memory, cannot fork, no more loop devices)
2084// 4 internal mount bug or missing nfs support in mount
2085// 8 user interrupt
2086//16 problems writing or locking /etc/mtab
2087//32 mount failure
2088//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002089 return rc;
2090}