blob: 989e5d1a8fd92dfea077572aa6e9c9785c8dd9b8 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002/*
Eric Andersen596e5461999-10-07 08:30:23 +00003 * Mini mount implementation for busybox
4 *
Eric Andersenc4996011999-10-20 22:08:37 +00005 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00006 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Rob Landleydc0955b2006-03-14 18:16:25 +00007 * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
Eric Andersen596e5461999-10-07 08:30:23 +00008 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02009 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Erik Andersenb7cc49d2000-01-13 06:38:14 +000010 */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +000011// Design notes: There is no spec for mount. Remind me to write one.
12//
13// mount_main() calls singlemount() which calls mount_it_now().
14//
15// mount_main() can loop through /etc/fstab for mount -a
16// singlemount() can loop through /etc/filesystems for fstype detection.
17// mount_it_now() does the actual mount.
18//
Eric Andersencc8ed391999-10-05 16:24:54 +000019#include <mntent.h>
Bernhard Reutner-Fischerf4701962008-01-27 12:50:12 +000020#include <syslog.h>
Denys Vlasenkoda49f582009-07-08 02:58:38 +020021#include <sys/mount.h>
Denys Vlasenko102ff762009-11-21 17:14:08 +010022// Grab more as needed from util-linux's mount/mount_constants.h
23#ifndef MS_DIRSYNC
24# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
25#endif
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +020026#ifndef MS_UNION
27# define MS_UNION (1 << 8)
28#endif
Denys Vlasenkoda49f582009-07-08 02:58:38 +020029#ifndef MS_BIND
30# define MS_BIND (1 << 12)
31#endif
32#ifndef MS_MOVE
33# define MS_MOVE (1 << 13)
34#endif
35#ifndef MS_RECURSIVE
36# define MS_RECURSIVE (1 << 14)
37#endif
38#ifndef MS_SILENT
39# define MS_SILENT (1 << 15)
40#endif
Denys Vlasenko102ff762009-11-21 17:14:08 +010041// The shared subtree stuff, which went in around 2.6.15
Denys Vlasenkoda49f582009-07-08 02:58:38 +020042#ifndef MS_UNBINDABLE
43# define MS_UNBINDABLE (1 << 17)
44#endif
45#ifndef MS_PRIVATE
46# define MS_PRIVATE (1 << 18)
47#endif
48#ifndef MS_SLAVE
49# define MS_SLAVE (1 << 19)
50#endif
51#ifndef MS_SHARED
52# define MS_SHARED (1 << 20)
53#endif
54#ifndef MS_RELATIME
55# define MS_RELATIME (1 << 21)
56#endif
Eric Andersenbd22ed82000-07-08 18:55:24 +000057
Denys Vlasenko102ff762009-11-21 17:14:08 +010058#include "libbb.h"
Denis Vlasenko6aa76962008-03-18 01:44:52 +000059#if ENABLE_FEATURE_MOUNT_LABEL
Natanael Copa9aff2992009-09-20 04:28:22 +020060# include "volume_id.h"
61#else
62# define resolve_mount_spec(fsname) ((void)0)
Denis Vlasenko6aa76962008-03-18 01:44:52 +000063#endif
Denis Vlasenkode7684a2008-02-18 21:08:49 +000064
Denis Vlasenko30e5cf82008-12-05 16:40:36 +000065// Needed for nfs support only
Denis Vlasenko30a64cd2006-09-15 15:12:00 +000066#include <sys/utsname.h>
67#undef TRUE
68#undef FALSE
Denys Vlasenkocc428142009-12-16 02:06:56 +010069#if ENABLE_FEATURE_MOUNT_NFS
70/* This is just a warning of a common mistake. Possibly this should be a
71 * uclibc faq entry rather than in busybox... */
72# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
73# error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
74# endif
75# include <rpc/rpc.h>
76# include <rpc/pmap_prot.h>
77# include <rpc/pmap_clnt.h>
78#endif
Denis Vlasenko30a64cd2006-09-15 15:12:00 +000079
80
Denis Vlasenko908d6b72006-12-18 23:07:42 +000081#if defined(__dietlibc__)
Denis Vlasenko30e5cf82008-12-05 16:40:36 +000082// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
83// dietlibc-0.30 does not have implementation of getmntent_r()
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +000084static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000085 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
Denis Vlasenko908d6b72006-12-18 23:07:42 +000086{
Denis Vlasenko908d6b72006-12-18 23:07:42 +000087 struct mntent* ment = getmntent(stream);
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +000088 return memcpy(result, ment, sizeof(*ment));
Denis Vlasenko908d6b72006-12-18 23:07:42 +000089}
90#endif
91
92
Rob Landleydc0955b2006-03-14 18:16:25 +000093// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +000094enum {
Denis Vlasenkoa4522c52008-03-17 08:46:43 +000095 MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
96 MOUNT_NOAUTO = (1 << 29),
97 MOUNT_SWAP = (1 << 30),
Denis Vlasenko13c5a682006-10-16 22:39:51 +000098};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +000099
100
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000101#define OPTION_STR "o:t:rwanfvsiO:"
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000102enum {
103 OPT_o = (1 << 0),
104 OPT_t = (1 << 1),
105 OPT_r = (1 << 2),
106 OPT_w = (1 << 3),
107 OPT_a = (1 << 4),
108 OPT_n = (1 << 5),
109 OPT_f = (1 << 6),
110 OPT_v = (1 << 7),
111 OPT_s = (1 << 8),
112 OPT_i = (1 << 9),
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000113 OPT_O = (1 << 10),
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000114};
115
116#if ENABLE_FEATURE_MTAB_SUPPORT
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200117#define USE_MTAB (!(option_mask32 & OPT_n))
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000118#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200119#define USE_MTAB 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000120#endif
121
122#if ENABLE_FEATURE_MOUNT_FAKE
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200123#define FAKE_IT (option_mask32 & OPT_f)
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000124#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200125#define FAKE_IT 0
126#endif
127
128#if ENABLE_FEATURE_MOUNT_HELPERS
129#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
130#else
131#define HELPERS_ALLOWED 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000132#endif
133
134
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000135// TODO: more "user" flag compatibility.
136// "user" option (from mount manpage):
137// Only the user that mounted a filesystem can unmount it again.
138// If any user should be able to unmount, then use users instead of user
139// in the fstab line. The owner option is similar to the user option,
140// with the restriction that the user must be the owner of the special file.
141// This may be useful e.g. for /dev/fd if a login script makes
142// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000143
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000144// Standard mount options (from -o options or --options),
145// with corresponding flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000146static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000147 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000148
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000149 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000150 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000151 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000152
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000153 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000154 /* "defaults" */ 0,
155 /* "quiet" 0 - do not filter out, vfat wants to see it */
156 /* "noauto" */ MOUNT_NOAUTO,
157 /* "sw" */ MOUNT_SWAP,
158 /* "swap" */ MOUNT_SWAP,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000159 IF_DESKTOP(/* "user" */ MOUNT_USERS,)
160 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000161 /* "_netdev" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000162 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000163
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000164 IF_FEATURE_MOUNT_FLAGS(
Rob Landleye3781b72006-08-08 01:39:49 +0000165 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000166 /* "nosuid" */ MS_NOSUID,
167 /* "suid" */ ~MS_NOSUID,
168 /* "dev" */ ~MS_NODEV,
169 /* "nodev" */ MS_NODEV,
170 /* "exec" */ ~MS_NOEXEC,
171 /* "noexec" */ MS_NOEXEC,
172 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000173 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000174 /* "async" */ ~MS_SYNCHRONOUS,
175 /* "atime" */ ~MS_NOATIME,
176 /* "noatime" */ MS_NOATIME,
177 /* "diratime" */ ~MS_NODIRATIME,
178 /* "nodiratime" */ MS_NODIRATIME,
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000179 /* "mand" */ MS_MANDLOCK,
180 /* "nomand" */ ~MS_MANDLOCK,
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000181 /* "relatime" */ MS_RELATIME,
182 /* "norelatime" */ ~MS_RELATIME,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000183 /* "loud" */ ~MS_SILENT,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000184
Rob Landleye3781b72006-08-08 01:39:49 +0000185 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200186 /* "union" */ MS_UNION,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000187 /* "bind" */ MS_BIND,
188 /* "move" */ MS_MOVE,
189 /* "shared" */ MS_SHARED,
190 /* "slave" */ MS_SLAVE,
191 /* "private" */ MS_PRIVATE,
192 /* "unbindable" */ MS_UNBINDABLE,
193 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
194 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
195 /* "rprivate" */ MS_SLAVE|MS_RECURSIVE,
196 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000197 )
198
199 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000200 /* "ro" */ MS_RDONLY, // vfs flag
201 /* "rw" */ ~MS_RDONLY, // vfs flag
202 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000203};
204
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000205static const char mount_option_str[] =
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000206 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000207 "loop\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000208 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000209 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000210 "defaults\0"
211 // "quiet\0" - do not filter out, vfat wants to see it
212 "noauto\0"
213 "sw\0"
214 "swap\0"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000215 IF_DESKTOP("user\0")
216 IF_DESKTOP("users\0")
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000217 "_netdev\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000218 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000219 IF_FEATURE_MOUNT_FLAGS(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000220 // vfs flags
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000221 "nosuid\0"
222 "suid\0"
223 "dev\0"
224 "nodev\0"
225 "exec\0"
226 "noexec\0"
227 "sync\0"
228 "dirsync\0"
229 "async\0"
230 "atime\0"
231 "noatime\0"
232 "diratime\0"
233 "nodiratime\0"
234 "mand\0"
235 "nomand\0"
236 "relatime\0"
237 "norelatime\0"
238 "loud\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000239
240 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200241 "union\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000242 "bind\0"
243 "move\0"
Roman Borisov945fd172011-02-25 14:50:39 +0300244 "make-shared\0"
245 "make-slave\0"
246 "make-private\0"
247 "make-unbindable\0"
248 "make-rshared\0"
249 "make-rslave\0"
250 "make-rprivate\0"
251 "make-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
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100282#if ENABLE_FEATURE_MTAB_SUPPORT
283/*
284 * update_mtab_entry_on_move() is used to update entry in case of mount --move.
285 * we are looking for existing entries mnt_dir which is equal to mnt_fsname of
286 * input mntent and replace it by new one.
287 */
288static void FAST_FUNC update_mtab_entry_on_move(const struct mntent *mp)
289{
290 struct mntent *entries, *m;
291 int i, count;
292 FILE *mountTable;
293
294 mountTable = setmntent(bb_path_mtab_file, "r");
295 if (!mountTable) {
296 bb_perror_msg(bb_path_mtab_file);
297 return;
298 }
299
300 entries = NULL;
301 count = 0;
302 while ((m = getmntent(mountTable)) != NULL) {
303 entries = xrealloc_vector(entries, 3, count);
304 entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
305 entries[count].mnt_dir = xstrdup(m->mnt_dir);
306 entries[count].mnt_type = xstrdup(m->mnt_type);
307 entries[count].mnt_opts = xstrdup(m->mnt_opts);
308 entries[count].mnt_freq = m->mnt_freq;
309 entries[count].mnt_passno = m->mnt_passno;
310 count++;
311 }
312 endmntent(mountTable);
313
314 mountTable = setmntent(bb_path_mtab_file, "w");
315 if (mountTable) {
316 for (i = 0; i < count; i++) {
317 if (strcmp(entries[i].mnt_dir, mp->mnt_fsname) != 0)
318 addmntent(mountTable, &entries[i]);
319 else
320 addmntent(mountTable, mp);
321 }
322 endmntent(mountTable);
323 } else if (errno != EROFS)
324 bb_perror_msg(bb_path_mtab_file);
325
326 if (ENABLE_FEATURE_CLEAN_UP) {
327 for (i = 0; i < count; i++) {
328 free(entries[i].mnt_fsname);
329 free(entries[i].mnt_dir);
330 free(entries[i].mnt_type);
331 free(entries[i].mnt_opts);
332 }
333 free(entries);
334 }
335}
336#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000337
338#if ENABLE_FEATURE_MOUNT_VERBOSE
339static int verbose_mount(const char *source, const char *target,
340 const char *filesystemtype,
341 unsigned long mountflags, const void *data)
342{
343 int rc;
344
345 errno = 0;
346 rc = mount(source, target, filesystemtype, mountflags, data);
347 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000348 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000349 source, target, filesystemtype,
350 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000351 return rc;
352}
353#else
354#define verbose_mount(...) mount(__VA_ARGS__)
355#endif
356
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000357// Append mount options to string
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000358static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000359{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000360 if (*oldopts && **oldopts) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000361 // Do not insert options which are already there
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000362 while (newopts[0]) {
363 char *p;
364 int len = strlen(newopts);
365 p = strchr(newopts, ',');
366 if (p) len = p - newopts;
367 p = *oldopts;
368 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000369 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000370 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000371 goto skip;
372 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000373 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000374 p++;
375 }
376 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
377 free(*oldopts);
378 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000379 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000380 newopts += len;
381 while (newopts[0] == ',') newopts++;
382 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000383 } else {
384 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000385 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000386 }
387}
388
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000389// Use the mount_options list to parse options into flags.
Alexander Shishkin77650952010-10-28 06:10:03 +0200390// Also update list of unrecognized options if unrecognized != NULL
Denis Vlasenkob4133682008-02-18 13:05:38 +0000391static long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000392{
Denis Vlasenkob4133682008-02-18 13:05:38 +0000393 long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000394
Rob Landley6a6798b2005-08-10 20:35:54 +0000395 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000396 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000397 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000398 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000399 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000400
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000401 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000402
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000403// FIXME: use hasmntopt()
Rob Landley6a6798b2005-08-10 20:35:54 +0000404 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000405 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Alexander Shishkin77650952010-10-28 06:10:03 +0200406 if (strcasecmp(option_str, options) == 0) {
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000407 long fl = mount_options[i];
Alexander Shishkin77650952010-10-28 06:10:03 +0200408 if (fl < 0)
409 flags &= fl;
410 else
411 flags |= fl;
412 goto found;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000413 }
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000414 option_str += strlen(option_str) + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000415 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200416 // We did not recognize this option.
417 // If "unrecognized" is not NULL, append option there.
418 // Note that we should not append *empty* option -
419 // in this case we want to pass NULL, not "", to "data"
420 // parameter of mount(2) syscall.
421 // This is crucial for filesystems that don't accept
422 // any arbitrary mount options, like cgroup fs:
423 // "mount -t cgroup none /mnt"
424 if (options[0] && unrecognized) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000425 // Add it to strflags, to pass on to kernel
Alexander Shishkin77650952010-10-28 06:10:03 +0200426 char *p = *unrecognized;
427 unsigned len = p ? strlen(p) : 0;
428 *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000429
Rob Landley6a6798b2005-08-10 20:35:54 +0000430 // Comma separated if it's not the first one
Alexander Shishkin77650952010-10-28 06:10:03 +0200431 if (len) p[len++] = ',';
432 strcpy(p + len, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000433 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200434 found:
Denis Vlasenko2535f122007-09-15 13:28:30 +0000435 if (!comma)
436 break;
437 // Advance to next option
438 *comma = ',';
439 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000440 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000441
Rob Landleydc0955b2006-03-14 18:16:25 +0000442 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000443}
444
Rob Landleydc0955b2006-03-14 18:16:25 +0000445// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000446static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000447{
Denis Vlasenko87468852007-04-13 23:22:00 +0000448 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000449 "/etc/filesystems",
450 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000451 };
452 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200453 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000454 int i;
455 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000456
Denis Vlasenko87468852007-04-13 23:22:00 +0000457 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000458 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000459 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000460
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000461 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200462 if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
Denis Vlasenko372686b2006-10-12 22:42:33 +0000463 continue;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000464 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200465 if (*fs == '#' || *fs == '*' || !*fs)
466 continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000467
Denis Vlasenko372686b2006-10-12 22:42:33 +0000468 llist_add_to_end(&list, xstrdup(fs));
469 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000470 }
471 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
472 }
473
474 return list;
475}
476
Rob Landleydc0955b2006-03-14 18:16:25 +0000477#if ENABLE_FEATURE_CLEAN_UP
478static void delete_block_backed_filesystems(void)
479{
Rob Landleya6b5b602006-05-08 19:03:07 +0000480 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000481}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000482#else
483void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000484#endif
485
Rob Landleydc0955b2006-03-14 18:16:25 +0000486// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000487// NB: mp->xxx fields may be trashed on exit
Denis Vlasenkob4133682008-02-18 13:05:38 +0000488static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000489{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000490 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000491
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200492 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000493 if (verbose >= 2)
494 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
495 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
496 vfsflags, filteropts);
497 goto mtab;
498 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000499
Rob Landleydc0955b2006-03-14 18:16:25 +0000500 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000501 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000502 errno = 0;
503 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000504 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000505
506 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000507 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200508 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200509 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000510 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000511 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000512 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200513 if (FAKE_IT)
514 args[rc++] = (char *)"-f";
515 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
516 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000517 args[rc++] = mp->mnt_fsname;
518 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000519 if (filteropts) {
520 args[rc++] = (char *)"-o";
521 args[rc++] = filteropts;
522 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000523 args[rc] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +0100524 rc = spawn_and_wait(args);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000525 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000526 if (!rc)
527 break;
528 errno = errno_save;
529 }
530
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000531 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000532 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000533 if (!(vfsflags & MS_SILENT))
534 bb_error_msg("%s is write-protected, mounting read-only",
535 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000536 vfsflags |= MS_RDONLY;
537 }
538
Rob Landleydc0955b2006-03-14 18:16:25 +0000539 // Abort entirely if permission denied.
540
541 if (rc && errno == EPERM)
542 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
543
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000544 // If the mount was successful, and we're maintaining an old-style
545 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000546 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200547 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000548 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000549 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000550 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000551 int i;
552
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000553 if (!mountTable) {
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100554 bb_perror_msg(bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000555 goto ret;
556 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000557
558 // Add vfs string flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000559 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
560 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
561 append_mount_options(&(mp->mnt_opts), option_str);
562 option_str += strlen(option_str) + 1;
563 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000564
565 // Remove trailing / (if any) from directory we mounted on
Denis Vlasenko727ef942006-09-14 13:19:19 +0000566 i = strlen(mp->mnt_dir) - 1;
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100567 while (i > 0 && mp->mnt_dir[i] == '/')
Denys Vlasenkoc6450c92011-02-28 11:09:49 +0100568 mp->mnt_dir[i--] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000569
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000570 // Convert to canonical pathnames as needed
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000571 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100572 fsname = NULL;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000573 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000574 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000575 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000576 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000577 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000578
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100579 // Write and close
580#if ENABLE_FEATURE_MTAB_SUPPORT
581 if (vfsflags & MS_MOVE)
582 update_mtab_entry_on_move(mp);
583 else
584#endif
585 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000586 endmntent(mountTable);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100587
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000588 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000589 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000590 free(fsname);
591 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000592 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000593 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000594 return rc;
595}
596
Denis Vlasenko25098f72006-09-14 15:46:33 +0000597#if ENABLE_FEATURE_MOUNT_NFS
598
599/*
600 * Linux NFS mount
601 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
602 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +0200603 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko25098f72006-09-14 15:46:33 +0000604 *
605 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
606 * numbers to be specified on the command line.
607 *
608 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
609 * Omit the call to connect() for Linux version 1.3.11 or later.
610 *
611 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
612 * Implemented the "bg", "fg" and "retry" mount options for NFS.
613 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000614 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000615 * - added Native Language Support
616 *
617 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
618 * plus NFSv3 stuff.
619 */
620
Denis Vlasenko25098f72006-09-14 15:46:33 +0000621#define MOUNTPORT 635
622#define MNTPATHLEN 1024
623#define MNTNAMLEN 255
624#define FHSIZE 32
625#define FHSIZE3 64
626
627typedef char fhandle[FHSIZE];
628
629typedef struct {
630 unsigned int fhandle3_len;
631 char *fhandle3_val;
632} fhandle3;
633
634enum mountstat3 {
635 MNT_OK = 0,
636 MNT3ERR_PERM = 1,
637 MNT3ERR_NOENT = 2,
638 MNT3ERR_IO = 5,
639 MNT3ERR_ACCES = 13,
640 MNT3ERR_NOTDIR = 20,
641 MNT3ERR_INVAL = 22,
642 MNT3ERR_NAMETOOLONG = 63,
643 MNT3ERR_NOTSUPP = 10004,
644 MNT3ERR_SERVERFAULT = 10006,
645};
646typedef enum mountstat3 mountstat3;
647
648struct fhstatus {
649 unsigned int fhs_status;
650 union {
651 fhandle fhs_fhandle;
652 } fhstatus_u;
653};
654typedef struct fhstatus fhstatus;
655
656struct mountres3_ok {
657 fhandle3 fhandle;
658 struct {
659 unsigned int auth_flavours_len;
660 char *auth_flavours_val;
661 } auth_flavours;
662};
663typedef struct mountres3_ok mountres3_ok;
664
665struct mountres3 {
666 mountstat3 fhs_status;
667 union {
668 mountres3_ok mountinfo;
669 } mountres3_u;
670};
671typedef struct mountres3 mountres3;
672
673typedef char *dirpath;
674
675typedef char *name;
676
677typedef struct mountbody *mountlist;
678
679struct mountbody {
680 name ml_hostname;
681 dirpath ml_directory;
682 mountlist ml_next;
683};
684typedef struct mountbody mountbody;
685
686typedef struct groupnode *groups;
687
688struct groupnode {
689 name gr_name;
690 groups gr_next;
691};
692typedef struct groupnode groupnode;
693
694typedef struct exportnode *exports;
695
696struct exportnode {
697 dirpath ex_dir;
698 groups ex_groups;
699 exports ex_next;
700};
701typedef struct exportnode exportnode;
702
703struct ppathcnf {
704 int pc_link_max;
705 short pc_max_canon;
706 short pc_max_input;
707 short pc_name_max;
708 short pc_path_max;
709 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000710 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000711 char pc_xxx;
712 short pc_mask[2];
713};
714typedef struct ppathcnf ppathcnf;
715
716#define MOUNTPROG 100005
717#define MOUNTVERS 1
718
719#define MOUNTPROC_NULL 0
720#define MOUNTPROC_MNT 1
721#define MOUNTPROC_DUMP 2
722#define MOUNTPROC_UMNT 3
723#define MOUNTPROC_UMNTALL 4
724#define MOUNTPROC_EXPORT 5
725#define MOUNTPROC_EXPORTALL 6
726
727#define MOUNTVERS_POSIX 2
728
729#define MOUNTPROC_PATHCONF 7
730
731#define MOUNT_V3 3
732
733#define MOUNTPROC3_NULL 0
734#define MOUNTPROC3_MNT 1
735#define MOUNTPROC3_DUMP 2
736#define MOUNTPROC3_UMNT 3
737#define MOUNTPROC3_UMNTALL 4
738#define MOUNTPROC3_EXPORT 5
739
740enum {
741#ifndef NFS_FHSIZE
742 NFS_FHSIZE = 32,
743#endif
744#ifndef NFS_PORT
745 NFS_PORT = 2049
746#endif
747};
748
Denis Vlasenko25098f72006-09-14 15:46:33 +0000749/*
750 * We want to be able to compile mount on old kernels in such a way
751 * that the binary will work well on more recent kernels.
752 * Thus, if necessary we teach nfsmount.c the structure of new fields
753 * that will come later.
754 *
755 * Moreover, the new kernel includes conflict with glibc includes
756 * so it is easiest to ignore the kernel altogether (at compile time).
757 */
758
759struct nfs2_fh {
760 char data[32];
761};
762struct nfs3_fh {
763 unsigned short size;
764 unsigned char data[64];
765};
766
767struct nfs_mount_data {
768 int version; /* 1 */
769 int fd; /* 1 */
770 struct nfs2_fh old_root; /* 1 */
771 int flags; /* 1 */
772 int rsize; /* 1 */
773 int wsize; /* 1 */
774 int timeo; /* 1 */
775 int retrans; /* 1 */
776 int acregmin; /* 1 */
777 int acregmax; /* 1 */
778 int acdirmin; /* 1 */
779 int acdirmax; /* 1 */
780 struct sockaddr_in addr; /* 1 */
781 char hostname[256]; /* 1 */
782 int namlen; /* 2 */
783 unsigned int bsize; /* 3 */
784 struct nfs3_fh root; /* 4 */
785};
786
787/* bits in the flags field */
788enum {
789 NFS_MOUNT_SOFT = 0x0001, /* 1 */
790 NFS_MOUNT_INTR = 0x0002, /* 1 */
791 NFS_MOUNT_SECURE = 0x0004, /* 1 */
792 NFS_MOUNT_POSIX = 0x0008, /* 1 */
793 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
794 NFS_MOUNT_NOAC = 0x0020, /* 1 */
795 NFS_MOUNT_TCP = 0x0040, /* 2 */
796 NFS_MOUNT_VER3 = 0x0080, /* 3 */
797 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000798 NFS_MOUNT_NONLM = 0x0200, /* 3 */
799 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +0000800};
801
802
803/*
804 * We need to translate between nfs status return values and
805 * the local errno values which may not be the same.
806 *
807 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
808 * "after #include <errno.h> the symbol errno is reserved for any use,
809 * it cannot even be used as a struct tag or field name".
810 */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000811#ifndef EDQUOT
Denys Vlasenkocc428142009-12-16 02:06:56 +0100812# define EDQUOT ENOSPC
Denis Vlasenko25098f72006-09-14 15:46:33 +0000813#endif
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000814/* Convert each NFSERR_BLAH into EBLAH */
Denys Vlasenkocc428142009-12-16 02:06:56 +0100815static const uint8_t nfs_err_stat[] = {
816 1, 2, 5, 6, 13, 17,
817 19, 20, 21, 22, 27, 28,
818 30, 63, 66, 69, 70, 71
819};
Denys Vlasenkodc1fd2e2010-05-19 17:01:29 +0200820#if ( \
821 EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
822 ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
823 EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
824typedef uint8_t nfs_err_type;
825#else
826typedef uint16_t nfs_err_type;
827#endif
828static const nfs_err_type nfs_err_errnum[] = {
Denys Vlasenkocc428142009-12-16 02:06:56 +0100829 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
830 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
831 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
Denis Vlasenko25098f72006-09-14 15:46:33 +0000832};
Denis Vlasenko25098f72006-09-14 15:46:33 +0000833static char *nfs_strerror(int status)
834{
835 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000836
Denys Vlasenkocc428142009-12-16 02:06:56 +0100837 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
838 if (nfs_err_stat[i] == status)
839 return strerror(nfs_err_errnum[i]);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000840 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000841 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000842}
843
844static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
845{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200846 return xdr_opaque(xdrs, objp, FHSIZE);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000847}
848
849static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
850{
851 if (!xdr_u_int(xdrs, &objp->fhs_status))
852 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +0200853 if (objp->fhs_status == 0)
854 return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000855 return TRUE;
856}
857
858static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
859{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200860 return xdr_string(xdrs, objp, MNTPATHLEN);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000861}
862
863static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
864{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200865 return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
866 (unsigned int *) &objp->fhandle3_len,
867 FHSIZE3);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000868}
869
870static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
871{
872 if (!xdr_fhandle3(xdrs, &objp->fhandle))
873 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +0200874 return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
875 &(objp->auth_flavours.auth_flavours_len),
876 ~0,
877 sizeof(int),
878 (xdrproc_t) xdr_int);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000879}
880
881static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
882{
Alexander Shishkin54779a42010-10-22 13:35:47 +0200883 return xdr_enum(xdrs, (enum_t *) objp);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000884}
885
886static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
887{
888 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
889 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +0200890 if (objp->fhs_status == MNT_OK)
891 return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000892 return TRUE;
893}
894
895#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
896
Denis Vlasenko25098f72006-09-14 15:46:33 +0000897/*
898 * Unfortunately, the kernel prints annoying console messages
899 * in case of an unexpected nfs mount version (instead of
900 * just returning some error). Therefore we'll have to try
901 * and figure out what version the kernel expects.
902 *
903 * Variables:
904 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
905 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
906 * nfs_mount_version: version this source and running kernel can handle
907 */
908static void
909find_kernel_nfs_mount_version(void)
910{
Denis Vlasenkob9256052007-09-28 10:29:17 +0000911 int kernel_version;
912
913 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000914 return;
915
916 nfs_mount_version = 4; /* default */
917
918 kernel_version = get_linux_version_code();
919 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +0100920 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +0000921 nfs_mount_version = 3;
922 /* else v4 since 2.3.99pre4 */
923 }
924}
925
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +0000926static void
Denis Vlasenkob9256052007-09-28 10:29:17 +0000927get_mountport(struct pmap *pm_mnt,
928 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +0000929 long unsigned prog,
930 long unsigned version,
931 long unsigned proto,
932 long unsigned port)
933{
934 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000935
936 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +0000937/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
938 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000939 pmap = pmap_getmaps(server_addr);
940
941 if (version > MAX_NFSPROT)
942 version = MAX_NFSPROT;
943 if (!prog)
944 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000945 pm_mnt->pm_prog = prog;
946 pm_mnt->pm_vers = version;
947 pm_mnt->pm_prot = proto;
948 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000949
Denis Vlasenko25098f72006-09-14 15:46:33 +0000950 while (pmap) {
951 if (pmap->pml_map.pm_prog != prog)
952 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +0000953 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +0000954 goto next;
955 if (version > 2 && pmap->pml_map.pm_vers != version)
956 goto next;
957 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
958 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100959 if (pmap->pml_map.pm_vers > MAX_NFSPROT
960 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
961 || (port && pmap->pml_map.pm_port != port)
962 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +0000963 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100964 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000965 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
966 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +0000967 pmap = pmap->pml_next;
968 }
Denis Vlasenkob9256052007-09-28 10:29:17 +0000969 if (!pm_mnt->pm_vers)
970 pm_mnt->pm_vers = MOUNTVERS;
971 if (!pm_mnt->pm_port)
972 pm_mnt->pm_port = MOUNTPORT;
973 if (!pm_mnt->pm_prot)
974 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000975}
976
Denis Vlasenkof0000652007-09-04 18:30:26 +0000977#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +0000978static int daemonize(void)
979{
Denis Vlasenko25098f72006-09-14 15:46:33 +0000980 int pid = fork();
981 if (pid < 0) /* error */
982 return -errno;
983 if (pid > 0) /* parent */
984 return 0;
985 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000986 close(0);
987 xopen(bb_dev_null, O_RDWR);
988 xdup2(0, 1);
989 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000990 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000991 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +0000992 logmode = LOGMODE_SYSLOG;
993 return 1;
994}
Denis Vlasenkof0000652007-09-04 18:30:26 +0000995#else
996static inline int daemonize(void) { return -ENOSYS; }
997#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +0000998
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000999/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001000static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001001{
1002 return 0;
1003}
1004
1005/* RPC strerror analogs are terminally idiotic:
1006 * *mandatory* prefix and \n at end.
1007 * This hopefully helps. Usage:
1008 * error_msg_rpc(clnt_*error*(" ")) */
1009static void error_msg_rpc(const char *msg)
1010{
Denis Vlasenko23514fe2006-09-19 14:07:52 +00001011 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001012 while (msg[0] == ' ' || msg[0] == ':') msg++;
1013 len = strlen(msg);
1014 while (len && msg[len-1] == '\n') len--;
1015 bb_error_msg("%.*s", len, msg);
1016}
1017
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001018/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko810b7162009-05-13 23:48:59 +02001019static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001020{
1021 CLIENT *mclient;
1022 char *hostname;
1023 char *pathname;
1024 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001025 /* prior to 2.6.23, kernel took NFS options in a form of this struct
1026 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
1027 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001028 struct nfs_mount_data data;
1029 char *opt;
1030 struct hostent *hp;
1031 struct sockaddr_in server_addr;
1032 struct sockaddr_in mount_server_addr;
1033 int msock, fsock;
1034 union {
1035 struct fhstatus nfsv2;
1036 struct mountres3 nfsv3;
1037 } status;
1038 int daemonized;
1039 char *s;
1040 int port;
1041 int mountport;
1042 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001043#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001044 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001045#else
1046 enum { bg = 0 };
1047#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001048 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001049 int mountprog;
1050 int mountvers;
1051 int nfsprog;
1052 int nfsvers;
1053 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001054 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001055 smallint tcp;
1056 smallint soft;
1057 int intr;
1058 int posix;
1059 int nocto;
1060 int noac;
1061 int nordirplus;
1062 int nolock;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001063
1064 find_kernel_nfs_mount_version();
1065
1066 daemonized = 0;
1067 mounthost = NULL;
1068 retval = ETIMEDOUT;
1069 msock = fsock = -1;
1070 mclient = NULL;
1071
1072 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1073
1074 filteropts = xstrdup(filteropts); /* going to trash it later... */
1075
1076 hostname = xstrdup(mp->mnt_fsname);
1077 /* mount_main() guarantees that ':' is there */
1078 s = strchr(hostname, ':');
1079 pathname = s + 1;
1080 *s = '\0';
1081 /* Ignore all but first hostname in replicated mounts
1082 until they can be fully supported. (mack@sgi.com) */
1083 s = strchr(hostname, ',');
1084 if (s) {
1085 *s = '\0';
1086 bb_error_msg("warning: multiple hostnames not supported");
1087 }
1088
1089 server_addr.sin_family = AF_INET;
1090 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1091 hp = gethostbyname(hostname);
1092 if (hp == NULL) {
1093 bb_herror_msg("%s", hostname);
1094 goto fail;
1095 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001096 if (hp->h_length != (int)sizeof(struct in_addr)) {
1097 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001098 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001099 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001100 }
1101
1102 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1103
1104 /* add IP address to mtab options for use when unmounting */
1105
1106 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1107 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1108 } else {
1109 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1110 mp->mnt_opts[0] ? "," : "",
1111 inet_ntoa(server_addr.sin_addr));
1112 free(mp->mnt_opts);
1113 mp->mnt_opts = tmp;
1114 }
1115
1116 /* Set default options.
1117 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1118 * let the kernel decide.
1119 * timeo is filled in after we know whether it'll be TCP or UDP. */
1120 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001121 data.retrans = 3;
1122 data.acregmin = 3;
1123 data.acregmax = 60;
1124 data.acdirmin = 30;
1125 data.acdirmax = 60;
1126 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001127
Denis Vlasenko25098f72006-09-14 15:46:33 +00001128 soft = 0;
1129 intr = 0;
1130 posix = 0;
1131 nocto = 0;
1132 nolock = 0;
1133 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001134 nordirplus = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001135 retry = 10000; /* 10000 minutes ~ 1 week */
1136 tcp = 0;
1137
1138 mountprog = MOUNTPROG;
1139 mountvers = 0;
1140 port = 0;
1141 mountport = 0;
1142 nfsprog = 100003;
1143 nfsvers = 0;
1144
1145 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001146 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001147 char *opteq = strchr(opt, '=');
1148 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001149 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001150 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001151 /* 0 */ "rsize\0"
1152 /* 1 */ "wsize\0"
1153 /* 2 */ "timeo\0"
1154 /* 3 */ "retrans\0"
1155 /* 4 */ "acregmin\0"
1156 /* 5 */ "acregmax\0"
1157 /* 6 */ "acdirmin\0"
1158 /* 7 */ "acdirmax\0"
1159 /* 8 */ "actimeo\0"
1160 /* 9 */ "retry\0"
1161 /* 10 */ "port\0"
1162 /* 11 */ "mountport\0"
1163 /* 12 */ "mounthost\0"
1164 /* 13 */ "mountprog\0"
1165 /* 14 */ "mountvers\0"
1166 /* 15 */ "nfsprog\0"
1167 /* 16 */ "nfsvers\0"
1168 /* 17 */ "vers\0"
1169 /* 18 */ "proto\0"
1170 /* 19 */ "namlen\0"
1171 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001172
1173 *opteq++ = '\0';
1174 idx = index_in_strings(options, opt);
1175 switch (idx) {
1176 case 12: // "mounthost"
1177 mounthost = xstrndup(opteq,
1178 strcspn(opteq, " \t\n\r,"));
1179 continue;
1180 case 18: // "proto"
1181 if (!strncmp(opteq, "tcp", 3))
1182 tcp = 1;
1183 else if (!strncmp(opteq, "udp", 3))
1184 tcp = 0;
1185 else
1186 bb_error_msg("warning: unrecognized proto= option");
1187 continue;
1188 case 20: // "addr" - ignore
1189 continue;
Peter Korsgaard301fe502011-02-21 17:52:13 +01001190 case -1: // unknown
1191 if (vfsflags & MS_REMOUNT)
1192 continue;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001193 }
1194
Denys Vlasenko77832482010-08-12 14:14:45 +02001195 val = xatoi_positive(opteq);
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001196 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001197 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001198 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001199 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001200 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001201 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001202 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001203 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001204 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001205 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001206 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001207 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001208 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001209 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001210 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001211 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001212 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001213 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001214 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001215 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001216 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001217 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001218 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001219 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001220 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001221 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001222 data.acregmin = val;
1223 data.acregmax = val;
1224 data.acdirmin = val;
1225 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001226 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001227 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001228 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001229 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001230 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001231 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001232 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001233 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001234 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001235 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001236 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001237 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001238 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001239 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001240 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001241 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001242 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001243 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001244 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001245 case 16: // "nfsvers"
1246 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001247 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001248 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001249 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001250 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001251 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001252 //else
1253 // bb_error_msg("warning: option namlen is not supported\n");
1254 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001255 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001256 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1257 goto fail;
1258 }
1259 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001260 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001261 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001262 "bg\0"
1263 "fg\0"
1264 "soft\0"
1265 "hard\0"
1266 "intr\0"
1267 "posix\0"
1268 "cto\0"
1269 "ac\0"
1270 "tcp\0"
1271 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001272 "lock\0"
1273 "rdirplus\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001274 int val = 1;
1275 if (!strncmp(opt, "no", 2)) {
1276 val = 0;
1277 opt += 2;
1278 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001279 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001280 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001281#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001282 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001283#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001284 break;
1285 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001286#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001287 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001288#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001289 break;
1290 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001291 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001292 break;
1293 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001294 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001295 break;
1296 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001297 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001298 break;
1299 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001300 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001301 break;
1302 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001303 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001304 break;
1305 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001306 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001307 break;
1308 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001309 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001310 break;
1311 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001312 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001313 break;
1314 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001315 if (nfs_mount_version >= 3)
1316 nolock = !val;
1317 else
1318 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001319 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001320 case 11: //rdirplus
1321 nordirplus = !val;
1322 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001323 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001324 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1325 goto fail;
1326 }
1327 }
1328 }
1329 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1330
1331 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1332 | (intr ? NFS_MOUNT_INTR : 0)
1333 | (posix ? NFS_MOUNT_POSIX : 0)
1334 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001335 | (noac ? NFS_MOUNT_NOAC : 0)
1336 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001337 if (nfs_mount_version >= 2)
1338 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1339 if (nfs_mount_version >= 3)
1340 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1341 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1342 bb_error_msg("NFSv%d not supported", nfsvers);
1343 goto fail;
1344 }
1345 if (nfsvers && !mountvers)
1346 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1347 if (nfsvers && nfsvers < mountvers) {
1348 mountvers = nfsvers;
1349 }
1350
1351 /* Adjust options if none specified */
1352 if (!data.timeo)
1353 data.timeo = tcp ? 70 : 7;
1354
Denis Vlasenko25098f72006-09-14 15:46:33 +00001355 data.version = nfs_mount_version;
1356
1357 if (vfsflags & MS_REMOUNT)
1358 goto do_mount;
1359
1360 /*
1361 * If the previous mount operation on the same host was
1362 * backgrounded, and the "bg" for this mount is also set,
1363 * give up immediately, to avoid the initial timeout.
1364 */
1365 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001366 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001367 if (daemonized <= 0) { /* parent or error */
1368 retval = -daemonized;
1369 goto ret;
1370 }
1371 }
1372
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001373 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001374 /* See if the nfs host = mount host. */
1375 if (mounthost) {
1376 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1377 mount_server_addr.sin_family = AF_INET;
1378 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1379 } else {
1380 hp = gethostbyname(mounthost);
1381 if (hp == NULL) {
1382 bb_herror_msg("%s", mounthost);
1383 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001384 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001385 if (hp->h_length != (int)sizeof(struct in_addr)) {
1386 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001387 }
1388 mount_server_addr.sin_family = AF_INET;
Denys Vlasenko99069332010-02-27 19:38:19 +01001389 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001390 }
1391 }
1392
1393 /*
1394 * The following loop implements the mount retries. When the mount
1395 * times out, and the "bg" option is set, we background ourself
1396 * and continue trying.
1397 *
1398 * The case where the mount point is not present and the "bg"
1399 * option is set, is treated as a timeout. This is done to
1400 * support nested mounts.
1401 *
1402 * The "retry" count specified by the user is the number of
1403 * minutes to retry before giving up.
1404 */
1405 {
1406 struct timeval total_timeout;
1407 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001408 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001409 time_t t;
1410 time_t prevt;
1411 time_t timeout;
1412
1413 retry_timeout.tv_sec = 3;
1414 retry_timeout.tv_usec = 0;
1415 total_timeout.tv_sec = 20;
1416 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001417/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001418 timeout = time(NULL) + 60 * retry;
1419 prevt = 0;
1420 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001421 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001422 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001423 if (t - prevt < 30)
1424 sleep(30);
1425
Denis Vlasenkob9256052007-09-28 10:29:17 +00001426 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001427 mountprog,
1428 mountvers,
1429 proto,
1430 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001431 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001432
1433 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001434 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001435 msock = RPC_ANYSOCK;
1436
Denis Vlasenkob9256052007-09-28 10:29:17 +00001437 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001438 case IPPROTO_UDP:
1439 mclient = clntudp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001440 pm_mnt.pm_prog,
1441 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001442 retry_timeout,
1443 &msock);
1444 if (mclient)
1445 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001446 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001447 msock = RPC_ANYSOCK;
1448 case IPPROTO_TCP:
1449 mclient = clnttcp_create(&mount_server_addr,
Denis Vlasenkob9256052007-09-28 10:29:17 +00001450 pm_mnt.pm_prog,
1451 pm_mnt.pm_vers,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001452 &msock, 0, 0);
1453 break;
1454 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001455 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001456 }
1457 if (!mclient) {
1458 if (!daemonized && prevt == 0)
1459 error_msg_rpc(clnt_spcreateerror(" "));
1460 } else {
1461 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001462
1463 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001464 mclient->cl_auth = authunix_create_default();
1465
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001466 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001467 * that xdr_array allocates memory for us
1468 */
1469 memset(&status, 0, sizeof(status));
1470
Denis Vlasenkob9256052007-09-28 10:29:17 +00001471 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001472 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1473 (xdrproc_t) xdr_dirpath,
1474 (caddr_t) &pathname,
1475 (xdrproc_t) xdr_mountres3,
1476 (caddr_t) &status,
1477 total_timeout);
1478 else
1479 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1480 (xdrproc_t) xdr_dirpath,
1481 (caddr_t) &pathname,
1482 (xdrproc_t) xdr_fhstatus,
1483 (caddr_t) &status,
1484 total_timeout);
1485
1486 if (clnt_stat == RPC_SUCCESS)
1487 goto prepare_kernel_data; /* we're done */
1488 if (errno != ECONNREFUSED) {
1489 error_msg_rpc(clnt_sperror(mclient, " "));
1490 goto fail; /* don't retry */
1491 }
1492 /* Connection refused */
1493 if (!daemonized && prevt == 0) /* print just once */
1494 error_msg_rpc(clnt_sperror(mclient, " "));
1495 auth_destroy(mclient->cl_auth);
1496 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001497 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001498 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001499 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001500 }
1501
1502 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001503 if (!bg)
1504 goto fail;
1505 if (!daemonized) {
1506 daemonized = daemonize();
1507 if (daemonized <= 0) { /* parent or error */
1508 retval = -daemonized;
1509 goto ret;
1510 }
1511 }
1512 prevt = t;
1513 t = time(NULL);
1514 if (t >= timeout)
1515 /* TODO error message */
1516 goto fail;
1517
1518 goto retry;
1519 }
1520
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001521 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001522
1523 if (nfsvers == 2) {
1524 if (status.nfsv2.fhs_status != 0) {
1525 bb_error_msg("%s:%s failed, reason given by server: %s",
1526 hostname, pathname,
1527 nfs_strerror(status.nfsv2.fhs_status));
1528 goto fail;
1529 }
1530 memcpy(data.root.data,
1531 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1532 NFS_FHSIZE);
1533 data.root.size = NFS_FHSIZE;
1534 memcpy(data.old_root.data,
1535 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1536 NFS_FHSIZE);
1537 } else {
1538 fhandle3 *my_fhandle;
1539 if (status.nfsv3.fhs_status != 0) {
1540 bb_error_msg("%s:%s failed, reason given by server: %s",
1541 hostname, pathname,
1542 nfs_strerror(status.nfsv3.fhs_status));
1543 goto fail;
1544 }
1545 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1546 memset(data.old_root.data, 0, NFS_FHSIZE);
1547 memset(&data.root, 0, sizeof(data.root));
1548 data.root.size = my_fhandle->fhandle3_len;
1549 memcpy(data.root.data,
1550 (char *) my_fhandle->fhandle3_val,
1551 my_fhandle->fhandle3_len);
1552
1553 data.flags |= NFS_MOUNT_VER3;
1554 }
1555
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001556 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001557 if (tcp) {
1558 if (nfs_mount_version < 3) {
1559 bb_error_msg("NFS over TCP is not supported");
1560 goto fail;
1561 }
1562 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1563 } else
1564 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1565 if (fsock < 0) {
1566 bb_perror_msg("nfs socket");
1567 goto fail;
1568 }
1569 if (bindresvport(fsock, 0) < 0) {
1570 bb_perror_msg("nfs bindresvport");
1571 goto fail;
1572 }
1573 if (port == 0) {
1574 server_addr.sin_port = PMAPPORT;
1575 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1576 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1577 if (port == 0)
1578 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001579 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001580 server_addr.sin_port = htons(port);
1581
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001582 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001583 data.fd = fsock;
1584 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1585 strncpy(data.hostname, hostname, sizeof(data.hostname));
1586
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001587 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001588 auth_destroy(mclient->cl_auth);
1589 clnt_destroy(mclient);
1590 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001591 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001592
1593 if (bg) {
1594 /* We must wait until mount directory is available */
1595 struct stat statbuf;
1596 int delay = 1;
1597 while (stat(mp->mnt_dir, &statbuf) == -1) {
1598 if (!daemonized) {
1599 daemonized = daemonize();
1600 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001601/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001602 retval = -daemonized;
1603 goto ret;
1604 }
1605 }
1606 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1607 delay *= 2;
1608 if (delay > 30)
1609 delay = 30;
1610 }
1611 }
1612
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001613 /* Perform actual mount */
1614 do_mount:
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001615 mp->mnt_type = (char*)"nfs";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001616 retval = mount_it_now(mp, vfsflags, (char*)&data);
1617 goto ret;
1618
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001619 /* Abort */
1620 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001621 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001622 if (mclient) {
1623 auth_destroy(mclient->cl_auth);
1624 clnt_destroy(mclient);
1625 }
1626 close(msock);
1627 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001628 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001629 close(fsock);
1630
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001631 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001632 free(hostname);
1633 free(mounthost);
1634 free(filteropts);
1635 return retval;
1636}
1637
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001638#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001639
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001640// Never called. Call should be optimized out.
Denis Vlasenkob4133682008-02-18 13:05:38 +00001641int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001642
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001643#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001644
1645// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1646// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001647// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001648static int singlemount(struct mntent *mp, int ignore_busy)
1649{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001650 int rc = -1;
1651 long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001652 char *loopFile = NULL, *filteropts = NULL;
1653 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001654 struct stat st;
1655
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001656 errno = 0;
1657
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001658 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1659
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001660 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001661 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1662 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001663
Denis Vlasenko2535f122007-09-15 13:28:30 +00001664 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001665 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1666 char *args[35];
1667 char *s;
1668 int n;
1669 // fsname: "cmd#arg1#arg2..."
1670 // WARNING: allows execution of arbitrary commands!
1671 // Try "mount 'sh#-c#sh' bogus_dir".
1672 // It is safe ONLY because non-root
1673 // cannot use two-argument mount command
1674 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1675 // "mount: can't find sh#-c#sh in /etc/fstab"
1676 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1677
1678 s = mp->mnt_fsname;
1679 n = 0;
1680 args[n++] = s;
1681 while (*s && n < 35 - 2) {
1682 if (*s++ == '#' && *s != '#') {
1683 s[-1] = '\0';
1684 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001685 }
1686 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001687 args[n++] = mp->mnt_dir;
1688 args[n] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +01001689 rc = spawn_and_wait(args);
Denis Vlasenko2535f122007-09-15 13:28:30 +00001690 goto report_error;
1691 }
1692
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001693 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001694 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001695 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1696 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1697 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001698 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001699 int len;
1700 char c;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001701 len_and_sockaddr *lsa;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001702 char *hostname, *dotted, *ip;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001703
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001704 hostname = mp->mnt_fsname + 2;
1705 len = strcspn(hostname, "/\\");
1706 if (len == 0 || hostname[len] == '\0')
Denis Vlasenko5c329932009-04-12 12:16:21 +00001707 goto report_error;
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001708 c = hostname[len];
1709 hostname[len] = '\0';
1710 lsa = host2sockaddr(hostname, 0);
1711 hostname[len] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001712 if (!lsa)
1713 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001714
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001715 // Insert "ip=..." option into options
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001716 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001717 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001718 ip = xasprintf("ip=%s", dotted);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001719 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001720 parse_mount_options(ip, &filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001721 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001722
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001723 // "-o mand" is required [why?]
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001724 vfsflags |= MS_MANDLOCK;
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001725 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001726 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001727
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001728 goto report_error;
1729 }
1730
1731 // Might this be an NFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001732 if (ENABLE_FEATURE_MOUNT_NFS
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001733 && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001734 && strchr(mp->mnt_fsname, ':') != NULL
1735 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001736 rc = nfsmount(mp, vfsflags, filteropts);
1737 goto report_error;
1738 }
1739
1740 // Look at the file. (Not found isn't a failure for remount, or for
1741 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001742 // (We use stat, not lstat, in order to allow
1743 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001744 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001745 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1746 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001747 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001748 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1749 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001750 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001751 if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001752 if (errno == EPERM || errno == EACCES)
1753 bb_error_msg(bb_msg_perm_denied_are_you_root);
1754 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01001755 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00001756 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001757 }
1758
1759 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001760 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1761 vfsflags |= MS_BIND;
1762 }
1763
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001764 // If we know the fstype (or don't need to), jump straight
1765 // to the actual mount.
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001766 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001767 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001768 } else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001769 // Loop through filesystem types until mount succeeds
1770 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001771
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001772 // Initialize list of block backed filesystems.
1773 // This has to be done here so that during "mount -a",
1774 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001775 if (!fslist) {
1776 fslist = get_block_backed_filesystems();
1777 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1778 atexit(delete_block_backed_filesystems);
1779 }
1780
1781 for (fl = fslist; fl; fl = fl->link) {
1782 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00001783 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001784 if (!rc)
1785 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001786 }
1787 }
1788
1789 // If mount failed, clean up loop file (if any).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001790 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1791 del_loop(mp->mnt_fsname);
1792 if (ENABLE_FEATURE_CLEAN_UP) {
1793 free(loopFile);
1794 free(mp->mnt_fsname);
1795 }
1796 }
1797
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001798 report_error:
1799 if (ENABLE_FEATURE_CLEAN_UP)
1800 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001801
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00001802 if (errno == EBUSY && ignore_busy)
1803 return 0;
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02001804 if (rc != 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00001805 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001806 return rc;
1807}
1808
Michael Abbott6b5accb2009-12-04 03:33:07 +01001809// -O support
1810// -O interprets a list of filter options which select whether a mount
1811// point will be mounted: only mounts with options matching *all* filtering
1812// options will be selected.
1813// By default each -O filter option must be present in the list of mount
1814// options, but if it is prefixed by "no" then it must be absent.
1815// For example,
1816// -O a,nob,c matches -o a,c but fails to match -o a,b,c
1817// (and also fails to match -o a because -o c is absent).
1818//
1819// It is different from -t in that each option is matched exactly; a leading
1820// "no" at the beginning of one option does not negate the rest.
1821static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001822{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001823 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01001824 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001825
Michael Abbott6b5accb2009-12-04 03:33:07 +01001826 while (*O_opt) {
1827 const char *fs_opt = fs_opt_in;
1828 int O_len;
1829 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001830
Michael Abbott6b5accb2009-12-04 03:33:07 +01001831 // If option begins with "no" then treat as an inverted match:
1832 // matching is a failure
1833 match = 0;
1834 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
1835 match = 1;
1836 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001837 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001838 // Isolate the current O option
1839 O_len = strchrnul(O_opt, ',') - O_opt;
1840 // Check for a match against existing options
1841 while (1) {
1842 if (strncmp(fs_opt, O_opt, O_len) == 0
1843 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
1844 ) {
1845 if (match)
1846 return 0; // "no" prefix, but option found
1847 match = 1; // current O option found, go check next one
1848 break;
1849 }
1850 fs_opt = strchr(fs_opt, ',');
1851 if (!fs_opt)
1852 break;
1853 fs_opt++;
1854 }
1855 if (match == 0)
1856 return 0; // match wanted but not found
1857 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001858 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01001859 // Step to the next O option
1860 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001861 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01001862 // If we get here then everything matched
1863 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001864}
1865
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001866// Parse options, if necessary parse fstab/mtab, and call singlemount for
1867// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001868int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001869int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001870{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001871 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001872 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001873 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001874 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001875 llist_t *lst_o = NULL;
Denis Vlasenko85f9e322006-09-19 14:14:12 +00001876 const char *fstabname;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001877 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001878 int i, j;
1879 int rc = EXIT_SUCCESS;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00001880 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001881 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001882 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001883
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001884 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00001885
Denis Vlasenkof732e962008-02-18 12:07:49 +00001886 // Parse long options, like --bind and --move. Note that -o option
1887 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001888 for (i = j = 1; argv[i]; i++) {
1889 if (argv[i][0] == '-' && argv[i][1] == '-')
1890 append_mount_options(&cmdopts, argv[i] + 2);
1891 else
1892 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001893 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001894 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001895
1896 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001897 // Max 2 params; -o is a list, -v is a counter
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001898 opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001899 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00001900 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00001901 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00001902 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1903 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001904 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001905
1906 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001907 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00001908 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001909 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1910
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001911 if (!mountTable)
1912 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001913
Denis Vlasenko2535f122007-09-15 13:28:30 +00001914 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001915 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001916 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001917 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00001918 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001919 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001920
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001921 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001922 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1923 mtpair->mnt_dir, mtpair->mnt_type,
1924 mtpair->mnt_opts);
1925 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001926 if (ENABLE_FEATURE_CLEAN_UP)
1927 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001928 return EXIT_SUCCESS;
1929 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001930 storage_path = NULL;
1931 } else {
1932 // When we have two arguments, the second is the directory and we can
1933 // skip looking at fstab entirely. We can always abspath() the directory
1934 // argument when we get it.
1935 if (argv[1]) {
1936 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001937 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001938 mtpair->mnt_fsname = argv[0];
1939 mtpair->mnt_dir = argv[1];
1940 mtpair->mnt_type = fstype;
1941 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00001942 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001943 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001944 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00001945 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001946 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001947 }
1948
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001949 // Past this point, we are handling either "mount -a [opts]"
1950 // or "mount [opts] single_param"
1951
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00001952 i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001953 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01001954 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00001955
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001956 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001957 if (ENABLE_FEATURE_MOUNT_FLAGS
1958 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1959 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001960 // verbose_mount(source, target, type, flags, data)
1961 rc = verbose_mount("", argv[0], "", i, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001962 if (rc)
1963 bb_simple_perror_msg_and_die(argv[0]);
1964 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001965 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001966
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001967 // Open either fstab or mtab
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001968 fstabname = "/etc/fstab";
1969 if (i & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001970 // WARNING. I am not sure this matches util-linux's
1971 // behavior. It's possible util-linux does not
1972 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001973 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00001974 }
1975 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00001976 if (!fstab)
Denys Vlasenko651a2692010-03-23 16:25:17 +01001977 bb_perror_msg_and_die("can't read '%s'", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001978
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001979 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00001980 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001981 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001982 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001983
1984 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00001985 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00001986 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001987 GETMNTENT_BUFSIZE/2)
1988 ) { // End of fstab/mtab is reached
1989 mtcur = mtother; // the thing we found last time
1990 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001991 }
1992
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00001993 // If we're trying to mount something specific and this isn't it,
1994 // skip it. Note we must match the exact text in fstab (ala
1995 // "proc") or a full path from root
1996 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001997
1998 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01001999 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
2000 && strcmp(storage_path, mtcur->mnt_fsname) != 0
2001 && strcmp(argv[0], mtcur->mnt_dir) != 0
2002 && strcmp(storage_path, mtcur->mnt_dir) != 0
2003 ) {
2004 continue; // no
2005 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002006
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002007 // Remember this entry. Something later may have
2008 // overmounted it, and we want the _last_ match.
2009 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002010
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002011 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002012 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002013 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002014 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002015 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002016 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002017 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002018
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002019 // Does type match? (NULL matches always)
2020 if (!match_fstype(mtcur, fstype))
2021 continue;
2022
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002023 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002024 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
2025 // swap is bogus "fstype", parse_mount_options can't check fstypes
2026 || strcasecmp(mtcur->mnt_type, "swap") == 0
2027 ) {
2028 continue;
2029 }
2030
2031 // Does (at least one) option match?
2032 // (NULL matches always)
2033 if (!match_opt(mtcur->mnt_opts, O_optmatch))
2034 continue;
2035
2036 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002037
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002038 // NFS mounts want this to be xrealloc-able
2039 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002040
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002041 // If nothing is mounted on this directory...
2042 // (otherwise repeated "mount -a" mounts everything again)
2043 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2044 // We do not check fsname match of found mount point -
2045 // "/" may have fsname of "/dev/root" while fstab
2046 // says "/dev/something_else".
2047 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01002048 if (verbose) {
2049 bb_error_msg("according to %s, "
2050 "%s is already mounted on %s",
2051 bb_path_mtab_file,
2052 mp->mnt_fsname, mp->mnt_dir);
2053 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002054 } else {
2055 // ...mount this thing
2056 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2057 // Count number of failed mounts
2058 rc++;
2059 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002060 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002061 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002062 }
2063 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002064
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002065 // End of fstab/mtab is reached.
2066 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002067 if (argv[0]) { // yes
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002068 long l;
2069
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002070 // If we didn't find anything, complain
2071 if (!mtcur->mnt_fsname)
2072 bb_error_msg_and_die("can't find %s in %s",
2073 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002074
2075 // What happens when we try to "mount swap_partition"?
2076 // (fstab containts "swap_partition swap swap defaults 0 0")
2077 // util-linux-ng 2.13.1 does this:
2078 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2079 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2080 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2081 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2082 // exit_group(32) = ?
2083#if 0
2084 // In case we want to simply skip swap partitions:
2085 l = parse_mount_options(mtcur->mnt_opts, NULL);
2086 if ((l & MOUNT_SWAP)
2087 // swap is bogus "fstype", parse_mount_options can't check fstypes
2088 || strcasecmp(mtcur->mnt_type, "swap") == 0
2089 ) {
2090 goto ret;
2091 }
2092#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002093 if (nonroot) {
2094 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002095 l = parse_mount_options(mtcur->mnt_opts, NULL);
2096 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002097 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002098 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002099
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002100 //util-linux-2.12 does not do this check.
2101 //// If nothing is mounted on this directory...
2102 //// (otherwise repeated "mount FOO" mounts FOO again)
2103 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2104 //if (mp) {
2105 // bb_error_msg("according to %s, "
2106 // "%s is already mounted on %s",
2107 // bb_path_mtab_file,
2108 // mp->mnt_fsname, mp->mnt_dir);
2109 //} else {
2110 // ...mount the last thing we found
2111 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2112 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2113 resolve_mount_spec(&mtpair->mnt_fsname);
2114 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2115 if (ENABLE_FEATURE_CLEAN_UP)
2116 free(mtcur->mnt_opts);
2117 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002118 }
2119
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002120 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002121 if (ENABLE_FEATURE_CLEAN_UP)
2122 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002123 if (ENABLE_FEATURE_CLEAN_UP) {
2124 free(storage_path);
2125 free(cmdopts);
2126 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002127
2128//TODO: exitcode should be ORed mask of (from "man mount"):
2129// 0 success
2130// 1 incorrect invocation or permissions
2131// 2 system error (out of memory, cannot fork, no more loop devices)
2132// 4 internal mount bug or missing nfs support in mount
2133// 8 user interrupt
2134//16 problems writing or locking /etc/mtab
2135//32 mount failure
2136//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002137 return rc;
2138}