blob: 4f5dced1048b0968d92ee14e9ba577bb6bbe5938 [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//
Pere Orga5bc8c002011-04-11 03:29:49 +020019
Isaac Dunham7b434a62015-03-11 16:07:24 +010020//config:config MOUNT
21//config: bool "mount"
22//config: default y
23//config: select PLATFORM_LINUX
24//config: help
25//config: All files and filesystems in Unix are arranged into one big directory
26//config: tree. The 'mount' utility is used to graft a filesystem onto a
27//config: particular part of the tree. A filesystem can either live on a block
28//config: device, or it can be accessible over the network, as is the case with
29//config: NFS filesystems. Most people using BusyBox will also want to enable
30//config: the 'mount' utility.
31//config:
32//config:config FEATURE_MOUNT_FAKE
33//config: bool "Support option -f"
34//config: default y
35//config: depends on MOUNT
36//config: help
37//config: Enable support for faking a file system mount.
38//config:
39//config:config FEATURE_MOUNT_VERBOSE
40//config: bool "Support option -v"
41//config: default y
42//config: depends on MOUNT
43//config: help
44//config: Enable multi-level -v[vv...] verbose messages. Useful if you
45//config: debug mount problems and want to see what is exactly passed
46//config: to the kernel.
47//config:
48//config:config FEATURE_MOUNT_HELPERS
49//config: bool "Support mount helpers"
50//config: default n
51//config: depends on MOUNT
52//config: help
53//config: Enable mounting of virtual file systems via external helpers.
54//config: E.g. "mount obexfs#-b00.11.22.33.44.55 /mnt" will in effect call
55//config: "obexfs -b00.11.22.33.44.55 /mnt"
56//config: Also "mount -t sometype [-o opts] fs /mnt" will try
57//config: "sometype [-o opts] fs /mnt" if simple mount syscall fails.
58//config: The idea is to use such virtual filesystems in /etc/fstab.
59//config:
60//config:config FEATURE_MOUNT_LABEL
61//config: bool "Support specifying devices by label or UUID"
62//config: default y
63//config: depends on MOUNT
64//config: select VOLUMEID
65//config: help
66//config: This allows for specifying a device by label or uuid, rather than by
67//config: name. This feature utilizes the same functionality as blkid/findfs.
68//config: This also enables label or uuid support for swapon.
69//config:
70//config:config FEATURE_MOUNT_NFS
71//config: bool "Support mounting NFS file systems on Linux < 2.6.23"
72//config: default n
73//config: depends on MOUNT
74//config: select FEATURE_HAVE_RPC
75//config: select FEATURE_SYSLOG
76//config: help
77//config: Enable mounting of NFS file systems on Linux kernels prior
78//config: to version 2.6.23. Note that in this case mounting of NFS
79//config: over IPv6 will not be possible.
80//config:
81//config: Note that this option links in RPC support from libc,
82//config: which is rather large (~10 kbytes on uclibc).
83//config:
84//config:config FEATURE_MOUNT_CIFS
85//config: bool "Support mounting CIFS/SMB file systems"
86//config: default y
87//config: depends on MOUNT
88//config: help
89//config: Enable support for samba mounts.
90//config:
91//config:config FEATURE_MOUNT_FLAGS
92//config: depends on MOUNT
Denys Vlasenkof5604222017-01-10 14:58:54 +010093//config: bool "Support lots of -o flags"
Isaac Dunham7b434a62015-03-11 16:07:24 +010094//config: default y
95//config: help
96//config: Without this, mount only supports ro/rw/remount. With this, it
97//config: supports nosuid, suid, dev, nodev, exec, noexec, sync, async, atime,
98//config: noatime, diratime, nodiratime, loud, bind, move, shared, slave,
99//config: private, unbindable, rshared, rslave, rprivate, and runbindable.
100//config:
101//config:config FEATURE_MOUNT_FSTAB
102//config: depends on MOUNT
103//config: bool "Support /etc/fstab and -a"
104//config: default y
105//config: help
106//config: Support mount all and looking for files in /etc/fstab.
107//config:
108//config:config FEATURE_MOUNT_OTHERTAB
109//config: depends on FEATURE_MOUNT_FSTAB
110//config: bool "Support -T <alt_fstab>"
111//config: default y
112//config: help
113//config: Support mount -T (specifying an alternate fstab)
114
Denys Vlasenkodd898c92016-11-23 11:46:32 +0100115/* On full-blown systems, requires suid for user mounts.
116 * But it's not unthinkable to have it available in non-suid flavor on some systems,
117 * for viewing mount table.
118 * Therefore we use BB_SUID_MAYBE instead of BB_SUID_REQUIRE: */
119//applet:IF_MOUNT(APPLET(mount, BB_DIR_BIN, IF_DESKTOP(BB_SUID_MAYBE) IF_NOT_DESKTOP(BB_SUID_DROP)))
120
121//kbuild:lib-$(CONFIG_MOUNT) += mount.o
122
Pere Orga5bc8c002011-04-11 03:29:49 +0200123//usage:#define mount_trivial_usage
Isaac Dunham7b434a62015-03-11 16:07:24 +0100124//usage: "[OPTIONS] [-o OPT] DEVICE NODE"
Pere Orga5bc8c002011-04-11 03:29:49 +0200125//usage:#define mount_full_usage "\n\n"
126//usage: "Mount a filesystem. Filesystem autodetection requires /proc.\n"
Pere Orga5bc8c002011-04-11 03:29:49 +0200127//usage: "\n -a Mount all filesystems in fstab"
128//usage: IF_FEATURE_MOUNT_FAKE(
129//usage: IF_FEATURE_MTAB_SUPPORT(
130//usage: "\n -f Update /etc/mtab, but don't mount"
131//usage: )
132//usage: IF_NOT_FEATURE_MTAB_SUPPORT(
133//usage: "\n -f Dry run"
134//usage: )
135//usage: )
136//usage: IF_FEATURE_MOUNT_HELPERS(
137//usage: "\n -i Don't run mount helper"
138//usage: )
139//usage: IF_FEATURE_MTAB_SUPPORT(
140//usage: "\n -n Don't update /etc/mtab"
141//usage: )
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100142//usage: IF_FEATURE_MOUNT_VERBOSE(
143//usage: "\n -v Verbose"
144//usage: )
145////usage: "\n -s Sloppy (ignored)"
Pere Orga5bc8c002011-04-11 03:29:49 +0200146//usage: "\n -r Read-only mount"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100147////usage: "\n -w Read-write mount (default)"
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +0100148//usage: "\n -t FSTYPE[,...] Filesystem type(s)"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100149//usage: IF_FEATURE_MOUNT_OTHERTAB(
150//usage: "\n -T FILE Read FILE instead of /etc/fstab"
151//usage: )
Pere Orga5bc8c002011-04-11 03:29:49 +0200152//usage: "\n -O OPT Mount only filesystems with option OPT (-a only)"
153//usage: "\n-o OPT:"
154//usage: IF_FEATURE_MOUNT_LOOP(
155//usage: "\n loop Ignored (loop devices are autodetected)"
156//usage: )
157//usage: IF_FEATURE_MOUNT_FLAGS(
158//usage: "\n [a]sync Writes are [a]synchronous"
159//usage: "\n [no]atime Disable/enable updates to inode access times"
160//usage: "\n [no]diratime Disable/enable atime updates to directories"
161//usage: "\n [no]relatime Disable/enable atime updates relative to modification time"
162//usage: "\n [no]dev (Dis)allow use of special device files"
163//usage: "\n [no]exec (Dis)allow use of executable files"
164//usage: "\n [no]suid (Dis)allow set-user-id-root programs"
165//usage: "\n [r]shared Convert [recursively] to a shared subtree"
166//usage: "\n [r]slave Convert [recursively] to a slave subtree"
167//usage: "\n [r]private Convert [recursively] to a private subtree"
168//usage: "\n [un]bindable Make mount point [un]able to be bind mounted"
169//usage: "\n [r]bind Bind a file or directory [recursively] to another location"
170//usage: "\n move Relocate an existing mount point"
171//usage: )
172//usage: "\n remount Remount a mounted filesystem, changing flags"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100173//usage: "\n ro Same as -r"
Pere Orga5bc8c002011-04-11 03:29:49 +0200174//usage: "\n"
175//usage: "\nThere are filesystem-specific -o flags."
176//usage:
177//usage:#define mount_example_usage
178//usage: "$ mount\n"
179//usage: "/dev/hda3 on / type minix (rw)\n"
180//usage: "proc on /proc type proc (rw)\n"
181//usage: "devpts on /dev/pts type devpts (rw)\n"
182//usage: "$ mount /dev/fd0 /mnt -t msdos -o ro\n"
183//usage: "$ mount /tmp/diskimage /opt -t ext2 -o loop\n"
184//usage: "$ mount cd_image.iso mydir\n"
185//usage:#define mount_notes_usage
186//usage: "Returns 0 for success, number of failed mounts for -a, or errno for one mount."
187
Eric Andersencc8ed391999-10-05 16:24:54 +0000188#include <mntent.h>
Bernhard Reutner-Fischerf4701962008-01-27 12:50:12 +0000189#include <syslog.h>
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200190#include <sys/mount.h>
Denys Vlasenko102ff762009-11-21 17:14:08 +0100191// Grab more as needed from util-linux's mount/mount_constants.h
192#ifndef MS_DIRSYNC
193# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
194#endif
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200195#ifndef MS_UNION
196# define MS_UNION (1 << 8)
197#endif
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200198#ifndef MS_BIND
199# define MS_BIND (1 << 12)
200#endif
201#ifndef MS_MOVE
202# define MS_MOVE (1 << 13)
203#endif
204#ifndef MS_RECURSIVE
205# define MS_RECURSIVE (1 << 14)
206#endif
207#ifndef MS_SILENT
208# define MS_SILENT (1 << 15)
209#endif
Denys Vlasenko102ff762009-11-21 17:14:08 +0100210// The shared subtree stuff, which went in around 2.6.15
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200211#ifndef MS_UNBINDABLE
212# define MS_UNBINDABLE (1 << 17)
213#endif
214#ifndef MS_PRIVATE
215# define MS_PRIVATE (1 << 18)
216#endif
217#ifndef MS_SLAVE
218# define MS_SLAVE (1 << 19)
219#endif
220#ifndef MS_SHARED
221# define MS_SHARED (1 << 20)
222#endif
223#ifndef MS_RELATIME
224# define MS_RELATIME (1 << 21)
225#endif
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200226#ifndef MS_STRICTATIME
227# define MS_STRICTATIME (1 << 24)
228#endif
229
230/* Any ~MS_FOO value has this bit set: */
231#define BB_MS_INVERTED_VALUE (1u << 31)
Eric Andersenbd22ed82000-07-08 18:55:24 +0000232
Denys Vlasenko102ff762009-11-21 17:14:08 +0100233#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200234#include "common_bufsiz.h"
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000235#if ENABLE_FEATURE_MOUNT_LABEL
Natanael Copa9aff2992009-09-20 04:28:22 +0200236# include "volume_id.h"
237#else
238# define resolve_mount_spec(fsname) ((void)0)
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000239#endif
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000240
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000241// Needed for nfs support only
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000242#include <sys/utsname.h>
243#undef TRUE
244#undef FALSE
Denys Vlasenkocc428142009-12-16 02:06:56 +0100245#if ENABLE_FEATURE_MOUNT_NFS
246/* This is just a warning of a common mistake. Possibly this should be a
247 * uclibc faq entry rather than in busybox... */
248# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
249# error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
250# endif
251# include <rpc/rpc.h>
252# include <rpc/pmap_prot.h>
253# include <rpc/pmap_clnt.h>
254#endif
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000255
256
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000257#if defined(__dietlibc__)
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000258// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
259// dietlibc-0.30 does not have implementation of getmntent_r()
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000260static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000261 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000262{
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000263 struct mntent* ment = getmntent(stream);
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000264 return memcpy(result, ment, sizeof(*ment));
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000265}
266#endif
267
268
Rob Landleydc0955b2006-03-14 18:16:25 +0000269// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000270enum {
Denys Vlasenko911d2652015-12-30 20:11:34 +0100271 MOUNT_USERS = (1 << 27) * ENABLE_DESKTOP,
272 MOUNT_NOFAIL = (1 << 28) * ENABLE_DESKTOP,
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000273 MOUNT_NOAUTO = (1 << 29),
274 MOUNT_SWAP = (1 << 30),
Denys Vlasenko911d2652015-12-30 20:11:34 +0100275 MOUNT_FAKEFLAGS = MOUNT_USERS | MOUNT_NOFAIL | MOUNT_NOAUTO | MOUNT_SWAP
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000276};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000277
278
Denys Vlasenko237bedd2016-07-06 21:58:02 +0200279#define OPTION_STR "o:*t:rwanfvsiO:" IF_FEATURE_MOUNT_OTHERTAB("T:")
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000280enum {
281 OPT_o = (1 << 0),
282 OPT_t = (1 << 1),
283 OPT_r = (1 << 2),
284 OPT_w = (1 << 3),
285 OPT_a = (1 << 4),
286 OPT_n = (1 << 5),
287 OPT_f = (1 << 6),
288 OPT_v = (1 << 7),
289 OPT_s = (1 << 8),
290 OPT_i = (1 << 9),
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000291 OPT_O = (1 << 10),
Isaac Dunham7b434a62015-03-11 16:07:24 +0100292 OPT_T = (1 << 11),
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000293};
294
295#if ENABLE_FEATURE_MTAB_SUPPORT
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200296#define USE_MTAB (!(option_mask32 & OPT_n))
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000297#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200298#define USE_MTAB 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000299#endif
300
301#if ENABLE_FEATURE_MOUNT_FAKE
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200302#define FAKE_IT (option_mask32 & OPT_f)
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000303#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200304#define FAKE_IT 0
305#endif
306
307#if ENABLE_FEATURE_MOUNT_HELPERS
308#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
309#else
310#define HELPERS_ALLOWED 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000311#endif
312
313
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000314// TODO: more "user" flag compatibility.
315// "user" option (from mount manpage):
316// Only the user that mounted a filesystem can unmount it again.
317// If any user should be able to unmount, then use users instead of user
318// in the fstab line. The owner option is similar to the user option,
319// with the restriction that the user must be the owner of the special file.
320// This may be useful e.g. for /dev/fd if a login script makes
321// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000322
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000323// Standard mount options (from -o options or --options),
324// with corresponding flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000325static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000326 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000327
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000328 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000329 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000330 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000331
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000332 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000333 /* "defaults" */ 0,
334 /* "quiet" 0 - do not filter out, vfat wants to see it */
335 /* "noauto" */ MOUNT_NOAUTO,
336 /* "sw" */ MOUNT_SWAP,
337 /* "swap" */ MOUNT_SWAP,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000338 IF_DESKTOP(/* "user" */ MOUNT_USERS,)
339 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
Denys Vlasenko911d2652015-12-30 20:11:34 +0100340 IF_DESKTOP(/* "nofail" */ MOUNT_NOFAIL,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000341 /* "_netdev" */ 0,
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100342 IF_DESKTOP(/* "comment=" */ 0,) /* systemd uses this in fstab */
Rob Landleye3781b72006-08-08 01:39:49 +0000343 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000344
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000345 IF_FEATURE_MOUNT_FLAGS(
Rob Landleye3781b72006-08-08 01:39:49 +0000346 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000347 /* "nosuid" */ MS_NOSUID,
348 /* "suid" */ ~MS_NOSUID,
349 /* "dev" */ ~MS_NODEV,
350 /* "nodev" */ MS_NODEV,
351 /* "exec" */ ~MS_NOEXEC,
352 /* "noexec" */ MS_NOEXEC,
353 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000354 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000355 /* "async" */ ~MS_SYNCHRONOUS,
356 /* "atime" */ ~MS_NOATIME,
357 /* "noatime" */ MS_NOATIME,
358 /* "diratime" */ ~MS_NODIRATIME,
359 /* "nodiratime" */ MS_NODIRATIME,
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000360 /* "mand" */ MS_MANDLOCK,
361 /* "nomand" */ ~MS_MANDLOCK,
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000362 /* "relatime" */ MS_RELATIME,
363 /* "norelatime" */ ~MS_RELATIME,
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200364 /* "strictatime" */ MS_STRICTATIME,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000365 /* "loud" */ ~MS_SILENT,
Roman Borisov19311bf2011-03-24 15:08:43 +0300366 /* "rbind" */ MS_BIND|MS_RECURSIVE,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000367
Rob Landleye3781b72006-08-08 01:39:49 +0000368 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200369 /* "union" */ MS_UNION,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000370 /* "bind" */ MS_BIND,
371 /* "move" */ MS_MOVE,
372 /* "shared" */ MS_SHARED,
373 /* "slave" */ MS_SLAVE,
374 /* "private" */ MS_PRIVATE,
375 /* "unbindable" */ MS_UNBINDABLE,
376 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
377 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
Roman Borisovd3679d22011-03-23 11:20:25 +0300378 /* "rprivate" */ MS_PRIVATE|MS_RECURSIVE,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000379 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000380 )
381
382 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000383 /* "ro" */ MS_RDONLY, // vfs flag
384 /* "rw" */ ~MS_RDONLY, // vfs flag
385 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000386};
387
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200388static const char mount_option_str[] ALIGN1 =
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000389 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000390 "loop\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000391 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000392 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000393 "defaults\0"
394 // "quiet\0" - do not filter out, vfat wants to see it
395 "noauto\0"
396 "sw\0"
397 "swap\0"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000398 IF_DESKTOP("user\0")
399 IF_DESKTOP("users\0")
Denys Vlasenko911d2652015-12-30 20:11:34 +0100400 IF_DESKTOP("nofail\0")
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000401 "_netdev\0"
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100402 IF_DESKTOP("comment=\0") /* systemd uses this in fstab */
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000403 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000404 IF_FEATURE_MOUNT_FLAGS(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000405 // vfs flags
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000406 "nosuid\0"
407 "suid\0"
408 "dev\0"
409 "nodev\0"
410 "exec\0"
411 "noexec\0"
412 "sync\0"
413 "dirsync\0"
414 "async\0"
415 "atime\0"
416 "noatime\0"
417 "diratime\0"
418 "nodiratime\0"
419 "mand\0"
420 "nomand\0"
421 "relatime\0"
422 "norelatime\0"
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200423 "strictatime\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000424 "loud\0"
Roman Borisov19311bf2011-03-24 15:08:43 +0300425 "rbind\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000426
427 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200428 "union\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000429 "bind\0"
430 "move\0"
Roman Borisov945fd172011-02-25 14:50:39 +0300431 "make-shared\0"
432 "make-slave\0"
433 "make-private\0"
434 "make-unbindable\0"
435 "make-rshared\0"
436 "make-rslave\0"
437 "make-rprivate\0"
438 "make-runbindable\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000439 )
440
441 // Always understood.
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000442 "ro\0" // vfs flag
443 "rw\0" // vfs flag
444 "remount\0" // action flag
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000445;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000446
Denis Vlasenkof732e962008-02-18 12:07:49 +0000447
448struct globals {
449#if ENABLE_FEATURE_MOUNT_NFS
450 smalluint nfs_mount_version;
451#endif
452#if ENABLE_FEATURE_MOUNT_VERBOSE
453 unsigned verbose;
454#endif
455 llist_t *fslist;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000456 char getmntent_buf[1];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100457} FIX_ALIASING;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000458enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200459#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenkof732e962008-02-18 12:07:49 +0000460#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000461#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000462#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000463#else
464#define verbose 0
465#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000466#define fslist (G.fslist )
467#define getmntent_buf (G.getmntent_buf )
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200468#define INIT_G() do { setup_common_bufsiz(); } while (0)
Denis Vlasenkof732e962008-02-18 12:07:49 +0000469
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100470#if ENABLE_FEATURE_MTAB_SUPPORT
471/*
472 * update_mtab_entry_on_move() is used to update entry in case of mount --move.
473 * we are looking for existing entries mnt_dir which is equal to mnt_fsname of
474 * input mntent and replace it by new one.
475 */
476static void FAST_FUNC update_mtab_entry_on_move(const struct mntent *mp)
477{
478 struct mntent *entries, *m;
479 int i, count;
480 FILE *mountTable;
481
482 mountTable = setmntent(bb_path_mtab_file, "r");
483 if (!mountTable) {
484 bb_perror_msg(bb_path_mtab_file);
485 return;
486 }
487
488 entries = NULL;
489 count = 0;
490 while ((m = getmntent(mountTable)) != NULL) {
491 entries = xrealloc_vector(entries, 3, count);
492 entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
493 entries[count].mnt_dir = xstrdup(m->mnt_dir);
494 entries[count].mnt_type = xstrdup(m->mnt_type);
495 entries[count].mnt_opts = xstrdup(m->mnt_opts);
496 entries[count].mnt_freq = m->mnt_freq;
497 entries[count].mnt_passno = m->mnt_passno;
498 count++;
499 }
500 endmntent(mountTable);
501
502 mountTable = setmntent(bb_path_mtab_file, "w");
503 if (mountTable) {
504 for (i = 0; i < count; i++) {
505 if (strcmp(entries[i].mnt_dir, mp->mnt_fsname) != 0)
506 addmntent(mountTable, &entries[i]);
507 else
508 addmntent(mountTable, mp);
509 }
510 endmntent(mountTable);
511 } else if (errno != EROFS)
512 bb_perror_msg(bb_path_mtab_file);
513
514 if (ENABLE_FEATURE_CLEAN_UP) {
515 for (i = 0; i < count; i++) {
516 free(entries[i].mnt_fsname);
517 free(entries[i].mnt_dir);
518 free(entries[i].mnt_type);
519 free(entries[i].mnt_opts);
520 }
521 free(entries);
522 }
523}
524#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000525
526#if ENABLE_FEATURE_MOUNT_VERBOSE
527static int verbose_mount(const char *source, const char *target,
528 const char *filesystemtype,
529 unsigned long mountflags, const void *data)
530{
531 int rc;
532
533 errno = 0;
534 rc = mount(source, target, filesystemtype, mountflags, data);
535 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000536 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000537 source, target, filesystemtype,
538 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000539 return rc;
540}
541#else
542#define verbose_mount(...) mount(__VA_ARGS__)
543#endif
544
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000545// Append mount options to string
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000546static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000547{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000548 if (*oldopts && **oldopts) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000549 // Do not insert options which are already there
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000550 while (newopts[0]) {
551 char *p;
552 int len = strlen(newopts);
553 p = strchr(newopts, ',');
554 if (p) len = p - newopts;
555 p = *oldopts;
556 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000557 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000558 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000559 goto skip;
560 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000561 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000562 p++;
563 }
564 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
565 free(*oldopts);
566 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000567 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000568 newopts += len;
569 while (newopts[0] == ',') newopts++;
570 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000571 } else {
572 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000573 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000574 }
575}
576
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000577// Use the mount_options list to parse options into flags.
Alexander Shishkin77650952010-10-28 06:10:03 +0200578// Also update list of unrecognized options if unrecognized != NULL
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200579static unsigned long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000580{
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200581 unsigned long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000582
Rob Landley6a6798b2005-08-10 20:35:54 +0000583 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000584 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000585 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000586 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000587 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000588
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000589 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000590
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000591// FIXME: use hasmntopt()
Rob Landley6a6798b2005-08-10 20:35:54 +0000592 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000593 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200594 unsigned opt_len = strlen(option_str);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100595
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200596 if (strncasecmp(option_str, options, opt_len) == 0
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100597 && (options[opt_len] == '\0'
598 /* or is it "comment=" thingy in fstab? */
599 IF_FEATURE_MOUNT_FSTAB(IF_DESKTOP( || option_str[opt_len-1] == '=' ))
600 )
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200601 ) {
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200602 unsigned long fl = mount_options[i];
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200603 if (fl & BB_MS_INVERTED_VALUE)
Alexander Shishkin77650952010-10-28 06:10:03 +0200604 flags &= fl;
605 else
606 flags |= fl;
607 goto found;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000608 }
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200609 option_str += opt_len + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000610 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200611 // We did not recognize this option.
612 // If "unrecognized" is not NULL, append option there.
613 // Note that we should not append *empty* option -
614 // in this case we want to pass NULL, not "", to "data"
615 // parameter of mount(2) syscall.
616 // This is crucial for filesystems that don't accept
617 // any arbitrary mount options, like cgroup fs:
618 // "mount -t cgroup none /mnt"
619 if (options[0] && unrecognized) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000620 // Add it to strflags, to pass on to kernel
Alexander Shishkin77650952010-10-28 06:10:03 +0200621 char *p = *unrecognized;
622 unsigned len = p ? strlen(p) : 0;
623 *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000624
Rob Landley6a6798b2005-08-10 20:35:54 +0000625 // Comma separated if it's not the first one
Alexander Shishkin77650952010-10-28 06:10:03 +0200626 if (len) p[len++] = ',';
627 strcpy(p + len, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000628 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200629 found:
Denis Vlasenko2535f122007-09-15 13:28:30 +0000630 if (!comma)
631 break;
632 // Advance to next option
633 *comma = ',';
634 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000635 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000636
Rob Landleydc0955b2006-03-14 18:16:25 +0000637 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000638}
639
Rob Landleydc0955b2006-03-14 18:16:25 +0000640// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000641static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000642{
Denis Vlasenko87468852007-04-13 23:22:00 +0000643 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000644 "/etc/filesystems",
645 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000646 };
647 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200648 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000649 int i;
650 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000651
Denis Vlasenko87468852007-04-13 23:22:00 +0000652 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000653 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000654 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000655
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000656 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100657 if (is_prefixed_with(buf, "nodev") && isspace(buf[5]))
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100658 goto next;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000659 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200660 if (*fs == '#' || *fs == '*' || !*fs)
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100661 goto next;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000662
Denis Vlasenko372686b2006-10-12 22:42:33 +0000663 llist_add_to_end(&list, xstrdup(fs));
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100664 next:
Denis Vlasenko372686b2006-10-12 22:42:33 +0000665 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000666 }
667 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
668 }
669
670 return list;
671}
672
Rob Landleydc0955b2006-03-14 18:16:25 +0000673#if ENABLE_FEATURE_CLEAN_UP
674static void delete_block_backed_filesystems(void)
675{
Rob Landleya6b5b602006-05-08 19:03:07 +0000676 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000677}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000678#else
679void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000680#endif
681
Rob Landleydc0955b2006-03-14 18:16:25 +0000682// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000683// NB: mp->xxx fields may be trashed on exit
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200684static int mount_it_now(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000685{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000686 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000687
Denys Vlasenko911d2652015-12-30 20:11:34 +0100688 vfsflags &= ~(unsigned long)MOUNT_FAKEFLAGS;
689
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200690 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000691 if (verbose >= 2)
692 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
693 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
694 vfsflags, filteropts);
695 goto mtab;
696 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000697
Rob Landleydc0955b2006-03-14 18:16:25 +0000698 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000699 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000700 errno = 0;
701 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000702 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000703
704 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000705 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200706 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200707 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000708 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000709 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000710 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200711 if (FAKE_IT)
712 args[rc++] = (char *)"-f";
713 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
714 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000715 args[rc++] = mp->mnt_fsname;
716 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000717 if (filteropts) {
718 args[rc++] = (char *)"-o";
719 args[rc++] = filteropts;
720 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000721 args[rc] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +0100722 rc = spawn_and_wait(args);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000723 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000724 if (!rc)
725 break;
726 errno = errno_save;
727 }
728
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000729 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000730 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000731 if (!(vfsflags & MS_SILENT))
732 bb_error_msg("%s is write-protected, mounting read-only",
733 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000734 vfsflags |= MS_RDONLY;
735 }
736
Rob Landleydc0955b2006-03-14 18:16:25 +0000737 // Abort entirely if permission denied.
738
739 if (rc && errno == EPERM)
740 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
741
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000742 // If the mount was successful, and we're maintaining an old-style
743 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000744 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200745 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000746 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000747 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000748 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000749 int i;
750
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000751 if (!mountTable) {
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100752 bb_perror_msg(bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000753 goto ret;
754 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000755
756 // Add vfs string flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000757 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
758 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
759 append_mount_options(&(mp->mnt_opts), option_str);
760 option_str += strlen(option_str) + 1;
761 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000762
763 // Remove trailing / (if any) from directory we mounted on
Denis Vlasenko727ef942006-09-14 13:19:19 +0000764 i = strlen(mp->mnt_dir) - 1;
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100765 while (i > 0 && mp->mnt_dir[i] == '/')
Denys Vlasenkoc6450c92011-02-28 11:09:49 +0100766 mp->mnt_dir[i--] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000767
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000768 // Convert to canonical pathnames as needed
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000769 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100770 fsname = NULL;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000771 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000772 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000773 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000774 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000775 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000776
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100777 // Write and close
778#if ENABLE_FEATURE_MTAB_SUPPORT
779 if (vfsflags & MS_MOVE)
780 update_mtab_entry_on_move(mp);
781 else
782#endif
783 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000784 endmntent(mountTable);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100785
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000786 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000787 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000788 free(fsname);
789 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000790 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000791 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000792 return rc;
793}
794
Denis Vlasenko25098f72006-09-14 15:46:33 +0000795#if ENABLE_FEATURE_MOUNT_NFS
796
797/*
798 * Linux NFS mount
799 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
800 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +0200801 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko25098f72006-09-14 15:46:33 +0000802 *
803 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
804 * numbers to be specified on the command line.
805 *
806 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
807 * Omit the call to connect() for Linux version 1.3.11 or later.
808 *
809 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
810 * Implemented the "bg", "fg" and "retry" mount options for NFS.
811 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000812 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000813 * - added Native Language Support
814 *
815 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
816 * plus NFSv3 stuff.
817 */
818
Denis Vlasenko25098f72006-09-14 15:46:33 +0000819#define MOUNTPORT 635
820#define MNTPATHLEN 1024
821#define MNTNAMLEN 255
822#define FHSIZE 32
823#define FHSIZE3 64
824
825typedef char fhandle[FHSIZE];
826
827typedef struct {
828 unsigned int fhandle3_len;
829 char *fhandle3_val;
830} fhandle3;
831
832enum mountstat3 {
833 MNT_OK = 0,
834 MNT3ERR_PERM = 1,
835 MNT3ERR_NOENT = 2,
836 MNT3ERR_IO = 5,
837 MNT3ERR_ACCES = 13,
838 MNT3ERR_NOTDIR = 20,
839 MNT3ERR_INVAL = 22,
840 MNT3ERR_NAMETOOLONG = 63,
841 MNT3ERR_NOTSUPP = 10004,
842 MNT3ERR_SERVERFAULT = 10006,
843};
844typedef enum mountstat3 mountstat3;
845
846struct fhstatus {
847 unsigned int fhs_status;
848 union {
849 fhandle fhs_fhandle;
850 } fhstatus_u;
851};
852typedef struct fhstatus fhstatus;
853
854struct mountres3_ok {
855 fhandle3 fhandle;
856 struct {
857 unsigned int auth_flavours_len;
858 char *auth_flavours_val;
859 } auth_flavours;
860};
861typedef struct mountres3_ok mountres3_ok;
862
863struct mountres3 {
864 mountstat3 fhs_status;
865 union {
866 mountres3_ok mountinfo;
867 } mountres3_u;
868};
869typedef struct mountres3 mountres3;
870
871typedef char *dirpath;
872
873typedef char *name;
874
875typedef struct mountbody *mountlist;
876
877struct mountbody {
878 name ml_hostname;
879 dirpath ml_directory;
880 mountlist ml_next;
881};
882typedef struct mountbody mountbody;
883
884typedef struct groupnode *groups;
885
886struct groupnode {
887 name gr_name;
888 groups gr_next;
889};
890typedef struct groupnode groupnode;
891
892typedef struct exportnode *exports;
893
894struct exportnode {
895 dirpath ex_dir;
896 groups ex_groups;
897 exports ex_next;
898};
899typedef struct exportnode exportnode;
900
901struct ppathcnf {
902 int pc_link_max;
903 short pc_max_canon;
904 short pc_max_input;
905 short pc_name_max;
906 short pc_path_max;
907 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000908 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000909 char pc_xxx;
910 short pc_mask[2];
911};
912typedef struct ppathcnf ppathcnf;
913
914#define MOUNTPROG 100005
915#define MOUNTVERS 1
916
917#define MOUNTPROC_NULL 0
918#define MOUNTPROC_MNT 1
919#define MOUNTPROC_DUMP 2
920#define MOUNTPROC_UMNT 3
921#define MOUNTPROC_UMNTALL 4
922#define MOUNTPROC_EXPORT 5
923#define MOUNTPROC_EXPORTALL 6
924
925#define MOUNTVERS_POSIX 2
926
927#define MOUNTPROC_PATHCONF 7
928
929#define MOUNT_V3 3
930
931#define MOUNTPROC3_NULL 0
932#define MOUNTPROC3_MNT 1
933#define MOUNTPROC3_DUMP 2
934#define MOUNTPROC3_UMNT 3
935#define MOUNTPROC3_UMNTALL 4
936#define MOUNTPROC3_EXPORT 5
937
938enum {
939#ifndef NFS_FHSIZE
940 NFS_FHSIZE = 32,
941#endif
942#ifndef NFS_PORT
943 NFS_PORT = 2049
944#endif
945};
946
Denis Vlasenko25098f72006-09-14 15:46:33 +0000947/*
948 * We want to be able to compile mount on old kernels in such a way
949 * that the binary will work well on more recent kernels.
950 * Thus, if necessary we teach nfsmount.c the structure of new fields
951 * that will come later.
952 *
953 * Moreover, the new kernel includes conflict with glibc includes
954 * so it is easiest to ignore the kernel altogether (at compile time).
955 */
956
957struct nfs2_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100958 char data[32];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000959};
960struct nfs3_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100961 unsigned short size;
962 unsigned char data[64];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000963};
964
965struct nfs_mount_data {
Dave Lovefae473c2011-11-10 15:19:25 +0100966 int version; /* 1 */
967 int fd; /* 1 */
968 struct nfs2_fh old_root; /* 1 */
969 int flags; /* 1 */
970 int rsize; /* 1 */
971 int wsize; /* 1 */
972 int timeo; /* 1 */
973 int retrans; /* 1 */
974 int acregmin; /* 1 */
975 int acregmax; /* 1 */
976 int acdirmin; /* 1 */
977 int acdirmax; /* 1 */
978 struct sockaddr_in addr; /* 1 */
979 char hostname[256]; /* 1 */
980 int namlen; /* 2 */
981 unsigned int bsize; /* 3 */
982 struct nfs3_fh root; /* 4 */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000983};
984
985/* bits in the flags field */
986enum {
987 NFS_MOUNT_SOFT = 0x0001, /* 1 */
988 NFS_MOUNT_INTR = 0x0002, /* 1 */
989 NFS_MOUNT_SECURE = 0x0004, /* 1 */
990 NFS_MOUNT_POSIX = 0x0008, /* 1 */
991 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
992 NFS_MOUNT_NOAC = 0x0020, /* 1 */
993 NFS_MOUNT_TCP = 0x0040, /* 2 */
994 NFS_MOUNT_VER3 = 0x0080, /* 3 */
995 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000996 NFS_MOUNT_NONLM = 0x0200, /* 3 */
Dave Lovefae473c2011-11-10 15:19:25 +0100997 NFS_MOUNT_NOACL = 0x0800, /* 4 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000998 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +0000999};
1000
1001
1002/*
1003 * We need to translate between nfs status return values and
1004 * the local errno values which may not be the same.
1005 *
1006 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
1007 * "after #include <errno.h> the symbol errno is reserved for any use,
1008 * it cannot even be used as a struct tag or field name".
1009 */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001010#ifndef EDQUOT
Denys Vlasenkocc428142009-12-16 02:06:56 +01001011# define EDQUOT ENOSPC
Denis Vlasenko25098f72006-09-14 15:46:33 +00001012#endif
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001013/* Convert each NFSERR_BLAH into EBLAH */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02001014static const uint8_t nfs_err_stat[] ALIGN1 = {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001015 1, 2, 5, 6, 13, 17,
1016 19, 20, 21, 22, 27, 28,
1017 30, 63, 66, 69, 70, 71
1018};
Denys Vlasenkodc1fd2e2010-05-19 17:01:29 +02001019#if ( \
1020 EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
1021 ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
1022 EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
1023typedef uint8_t nfs_err_type;
1024#else
1025typedef uint16_t nfs_err_type;
1026#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02001027static const nfs_err_type nfs_err_errnum[] ALIGN2 = {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001028 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
1029 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
1030 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
Denis Vlasenko25098f72006-09-14 15:46:33 +00001031};
Denis Vlasenko25098f72006-09-14 15:46:33 +00001032static char *nfs_strerror(int status)
1033{
1034 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001035
Denys Vlasenkocc428142009-12-16 02:06:56 +01001036 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
1037 if (nfs_err_stat[i] == status)
1038 return strerror(nfs_err_errnum[i]);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001039 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001040 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001041}
1042
1043static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
1044{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001045 return xdr_opaque(xdrs, objp, FHSIZE);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001046}
1047
1048static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
1049{
1050 if (!xdr_u_int(xdrs, &objp->fhs_status))
Denys Vlasenko69675782013-01-14 01:34:48 +01001051 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001052 if (objp->fhs_status == 0)
1053 return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001054 return TRUE;
1055}
1056
1057static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
1058{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001059 return xdr_string(xdrs, objp, MNTPATHLEN);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001060}
1061
1062static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
1063{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001064 return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
Denys Vlasenko69675782013-01-14 01:34:48 +01001065 (unsigned int *) &objp->fhandle3_len,
1066 FHSIZE3);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001067}
1068
1069static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
1070{
1071 if (!xdr_fhandle3(xdrs, &objp->fhandle))
1072 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001073 return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
Denys Vlasenko69675782013-01-14 01:34:48 +01001074 &(objp->auth_flavours.auth_flavours_len),
1075 ~0,
1076 sizeof(int),
1077 (xdrproc_t) xdr_int);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001078}
1079
1080static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
1081{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001082 return xdr_enum(xdrs, (enum_t *) objp);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001083}
1084
1085static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
1086{
1087 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
1088 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001089 if (objp->fhs_status == MNT_OK)
1090 return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001091 return TRUE;
1092}
1093
1094#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
1095
Denis Vlasenko25098f72006-09-14 15:46:33 +00001096/*
1097 * Unfortunately, the kernel prints annoying console messages
1098 * in case of an unexpected nfs mount version (instead of
1099 * just returning some error). Therefore we'll have to try
1100 * and figure out what version the kernel expects.
1101 *
1102 * Variables:
1103 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
1104 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
1105 * nfs_mount_version: version this source and running kernel can handle
1106 */
1107static void
1108find_kernel_nfs_mount_version(void)
1109{
Denis Vlasenkob9256052007-09-28 10:29:17 +00001110 int kernel_version;
1111
1112 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001113 return;
1114
1115 nfs_mount_version = 4; /* default */
1116
1117 kernel_version = get_linux_version_code();
1118 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001119 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +00001120 nfs_mount_version = 3;
1121 /* else v4 since 2.3.99pre4 */
1122 }
1123}
1124
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +00001125static void
Denis Vlasenkob9256052007-09-28 10:29:17 +00001126get_mountport(struct pmap *pm_mnt,
1127 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001128 long unsigned prog,
1129 long unsigned version,
1130 long unsigned proto,
1131 long unsigned port)
1132{
1133 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001134
1135 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001136/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
1137 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001138 pmap = pmap_getmaps(server_addr);
1139
1140 if (version > MAX_NFSPROT)
1141 version = MAX_NFSPROT;
1142 if (!prog)
1143 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001144 pm_mnt->pm_prog = prog;
1145 pm_mnt->pm_vers = version;
1146 pm_mnt->pm_prot = proto;
1147 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001148
Denis Vlasenko25098f72006-09-14 15:46:33 +00001149 while (pmap) {
1150 if (pmap->pml_map.pm_prog != prog)
1151 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001152 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001153 goto next;
1154 if (version > 2 && pmap->pml_map.pm_vers != version)
1155 goto next;
1156 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
1157 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001158 if (pmap->pml_map.pm_vers > MAX_NFSPROT
1159 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
1160 || (port && pmap->pml_map.pm_port != port)
1161 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001162 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001163 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001164 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
1165 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001166 pmap = pmap->pml_next;
1167 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001168 if (!pm_mnt->pm_vers)
1169 pm_mnt->pm_vers = MOUNTVERS;
1170 if (!pm_mnt->pm_port)
1171 pm_mnt->pm_port = MOUNTPORT;
1172 if (!pm_mnt->pm_prot)
1173 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001174}
1175
Denis Vlasenkof0000652007-09-04 18:30:26 +00001176#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001177static int daemonize(void)
1178{
Denis Vlasenko25098f72006-09-14 15:46:33 +00001179 int pid = fork();
1180 if (pid < 0) /* error */
1181 return -errno;
1182 if (pid > 0) /* parent */
1183 return 0;
1184 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001185 close(0);
1186 xopen(bb_dev_null, O_RDWR);
1187 xdup2(0, 1);
1188 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001189 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +00001190 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001191 logmode = LOGMODE_SYSLOG;
1192 return 1;
1193}
Denis Vlasenkof0000652007-09-04 18:30:26 +00001194#else
1195static inline int daemonize(void) { return -ENOSYS; }
1196#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001197
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001198/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001199static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001200{
1201 return 0;
1202}
1203
1204/* RPC strerror analogs are terminally idiotic:
1205 * *mandatory* prefix and \n at end.
1206 * This hopefully helps. Usage:
1207 * error_msg_rpc(clnt_*error*(" ")) */
1208static void error_msg_rpc(const char *msg)
1209{
Denis Vlasenko23514fe2006-09-19 14:07:52 +00001210 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001211 while (msg[0] == ' ' || msg[0] == ':') msg++;
1212 len = strlen(msg);
1213 while (len && msg[len-1] == '\n') len--;
1214 bb_error_msg("%.*s", len, msg);
1215}
1216
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001217/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001218static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001219{
1220 CLIENT *mclient;
1221 char *hostname;
1222 char *pathname;
1223 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001224 /* prior to 2.6.23, kernel took NFS options in a form of this struct
1225 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
1226 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001227 struct nfs_mount_data data;
1228 char *opt;
1229 struct hostent *hp;
1230 struct sockaddr_in server_addr;
1231 struct sockaddr_in mount_server_addr;
1232 int msock, fsock;
1233 union {
1234 struct fhstatus nfsv2;
1235 struct mountres3 nfsv3;
1236 } status;
1237 int daemonized;
1238 char *s;
1239 int port;
1240 int mountport;
1241 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001242#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001243 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001244#else
1245 enum { bg = 0 };
1246#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001247 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001248 int mountprog;
1249 int mountvers;
1250 int nfsprog;
1251 int nfsvers;
1252 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001253 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001254 smallint tcp;
1255 smallint soft;
1256 int intr;
1257 int posix;
1258 int nocto;
1259 int noac;
1260 int nordirplus;
1261 int nolock;
Dave Lovefae473c2011-11-10 15:19:25 +01001262 int noacl;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001263
1264 find_kernel_nfs_mount_version();
1265
1266 daemonized = 0;
1267 mounthost = NULL;
1268 retval = ETIMEDOUT;
1269 msock = fsock = -1;
1270 mclient = NULL;
1271
1272 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1273
1274 filteropts = xstrdup(filteropts); /* going to trash it later... */
1275
1276 hostname = xstrdup(mp->mnt_fsname);
1277 /* mount_main() guarantees that ':' is there */
1278 s = strchr(hostname, ':');
1279 pathname = s + 1;
1280 *s = '\0';
1281 /* Ignore all but first hostname in replicated mounts
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001282 * until they can be fully supported. (mack@sgi.com) */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001283 s = strchr(hostname, ',');
1284 if (s) {
1285 *s = '\0';
1286 bb_error_msg("warning: multiple hostnames not supported");
1287 }
1288
1289 server_addr.sin_family = AF_INET;
1290 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1291 hp = gethostbyname(hostname);
1292 if (hp == NULL) {
1293 bb_herror_msg("%s", hostname);
1294 goto fail;
1295 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001296 if (hp->h_length != (int)sizeof(struct in_addr)) {
1297 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001298 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001299 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001300 }
1301
1302 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1303
1304 /* add IP address to mtab options for use when unmounting */
1305
1306 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1307 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1308 } else {
1309 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1310 mp->mnt_opts[0] ? "," : "",
1311 inet_ntoa(server_addr.sin_addr));
1312 free(mp->mnt_opts);
1313 mp->mnt_opts = tmp;
1314 }
1315
1316 /* Set default options.
1317 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1318 * let the kernel decide.
1319 * timeo is filled in after we know whether it'll be TCP or UDP. */
1320 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001321 data.retrans = 3;
1322 data.acregmin = 3;
1323 data.acregmax = 60;
1324 data.acdirmin = 30;
1325 data.acdirmax = 60;
1326 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001327
Denis Vlasenko25098f72006-09-14 15:46:33 +00001328 soft = 0;
1329 intr = 0;
1330 posix = 0;
1331 nocto = 0;
1332 nolock = 0;
1333 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001334 nordirplus = 0;
Dave Lovefae473c2011-11-10 15:19:25 +01001335 noacl = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001336 retry = 10000; /* 10000 minutes ~ 1 week */
Bernhard Reutner-Fischer88206292011-05-04 19:03:30 +02001337 tcp = 1; /* nfs-utils uses tcp per default */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001338
1339 mountprog = MOUNTPROG;
1340 mountvers = 0;
1341 port = 0;
1342 mountport = 0;
1343 nfsprog = 100003;
1344 nfsvers = 0;
1345
1346 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001347 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001348 char *opteq = strchr(opt, '=');
1349 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001350 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001351 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001352 /* 0 */ "rsize\0"
1353 /* 1 */ "wsize\0"
1354 /* 2 */ "timeo\0"
1355 /* 3 */ "retrans\0"
1356 /* 4 */ "acregmin\0"
1357 /* 5 */ "acregmax\0"
1358 /* 6 */ "acdirmin\0"
1359 /* 7 */ "acdirmax\0"
1360 /* 8 */ "actimeo\0"
1361 /* 9 */ "retry\0"
1362 /* 10 */ "port\0"
1363 /* 11 */ "mountport\0"
1364 /* 12 */ "mounthost\0"
1365 /* 13 */ "mountprog\0"
1366 /* 14 */ "mountvers\0"
1367 /* 15 */ "nfsprog\0"
1368 /* 16 */ "nfsvers\0"
1369 /* 17 */ "vers\0"
1370 /* 18 */ "proto\0"
1371 /* 19 */ "namlen\0"
1372 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001373
1374 *opteq++ = '\0';
1375 idx = index_in_strings(options, opt);
1376 switch (idx) {
1377 case 12: // "mounthost"
1378 mounthost = xstrndup(opteq,
1379 strcspn(opteq, " \t\n\r,"));
1380 continue;
1381 case 18: // "proto"
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001382 if (is_prefixed_with(opteq, "tcp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001383 tcp = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001384 else if (is_prefixed_with(opteq, "udp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001385 tcp = 0;
1386 else
1387 bb_error_msg("warning: unrecognized proto= option");
1388 continue;
1389 case 20: // "addr" - ignore
1390 continue;
Peter Korsgaard301fe502011-02-21 17:52:13 +01001391 case -1: // unknown
1392 if (vfsflags & MS_REMOUNT)
1393 continue;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001394 }
1395
Denys Vlasenko77832482010-08-12 14:14:45 +02001396 val = xatoi_positive(opteq);
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001397 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001398 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001399 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001400 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001401 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001402 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001403 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001404 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001405 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001406 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001407 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001408 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001409 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001410 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001411 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001412 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001413 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001414 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001415 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001416 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001417 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001418 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001419 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001420 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001421 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001422 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001423 data.acregmin = val;
1424 data.acregmax = val;
1425 data.acdirmin = val;
1426 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001427 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001428 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001429 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001430 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001431 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001432 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001433 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001434 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001435 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001436 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001437 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001438 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001439 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001440 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001441 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001442 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001443 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001444 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001445 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001446 case 16: // "nfsvers"
1447 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001448 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001449 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001450 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001451 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001452 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001453 //else
1454 // bb_error_msg("warning: option namlen is not supported\n");
1455 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001456 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001457 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1458 goto fail;
1459 }
1460 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001461 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001462 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001463 "bg\0"
1464 "fg\0"
1465 "soft\0"
1466 "hard\0"
1467 "intr\0"
1468 "posix\0"
1469 "cto\0"
1470 "ac\0"
1471 "tcp\0"
1472 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001473 "lock\0"
Dave Lovefae473c2011-11-10 15:19:25 +01001474 "rdirplus\0"
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001475 "acl\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001476 int val = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001477 if (is_prefixed_with(opt, "no")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001478 val = 0;
1479 opt += 2;
1480 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001481 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001482 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001483#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001484 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001485#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001486 break;
1487 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001488#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001489 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001490#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001491 break;
1492 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001493 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001494 break;
1495 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001496 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001497 break;
1498 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001499 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001500 break;
1501 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001502 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001503 break;
1504 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001505 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001506 break;
1507 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001508 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001509 break;
1510 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001511 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001512 break;
1513 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001514 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001515 break;
1516 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001517 if (nfs_mount_version >= 3)
1518 nolock = !val;
1519 else
1520 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001521 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001522 case 11: //rdirplus
1523 nordirplus = !val;
1524 break;
Dave Lovefae473c2011-11-10 15:19:25 +01001525 case 12: // acl
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001526 noacl = !val;
Dave Lovefae473c2011-11-10 15:19:25 +01001527 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001528 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001529 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1530 goto fail;
1531 }
1532 }
1533 }
1534 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1535
1536 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1537 | (intr ? NFS_MOUNT_INTR : 0)
1538 | (posix ? NFS_MOUNT_POSIX : 0)
1539 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001540 | (noac ? NFS_MOUNT_NOAC : 0)
Dave Lovefae473c2011-11-10 15:19:25 +01001541 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0)
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001542 | (noacl ? NFS_MOUNT_NOACL : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001543 if (nfs_mount_version >= 2)
1544 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1545 if (nfs_mount_version >= 3)
1546 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1547 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1548 bb_error_msg("NFSv%d not supported", nfsvers);
1549 goto fail;
1550 }
1551 if (nfsvers && !mountvers)
1552 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1553 if (nfsvers && nfsvers < mountvers) {
1554 mountvers = nfsvers;
1555 }
1556
1557 /* Adjust options if none specified */
1558 if (!data.timeo)
1559 data.timeo = tcp ? 70 : 7;
1560
Denis Vlasenko25098f72006-09-14 15:46:33 +00001561 data.version = nfs_mount_version;
1562
1563 if (vfsflags & MS_REMOUNT)
1564 goto do_mount;
1565
1566 /*
1567 * If the previous mount operation on the same host was
1568 * backgrounded, and the "bg" for this mount is also set,
1569 * give up immediately, to avoid the initial timeout.
1570 */
1571 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001572 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001573 if (daemonized <= 0) { /* parent or error */
1574 retval = -daemonized;
1575 goto ret;
1576 }
1577 }
1578
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001579 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001580 /* See if the nfs host = mount host. */
1581 if (mounthost) {
1582 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1583 mount_server_addr.sin_family = AF_INET;
1584 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1585 } else {
1586 hp = gethostbyname(mounthost);
1587 if (hp == NULL) {
1588 bb_herror_msg("%s", mounthost);
1589 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001590 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001591 if (hp->h_length != (int)sizeof(struct in_addr)) {
1592 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001593 }
1594 mount_server_addr.sin_family = AF_INET;
Denys Vlasenko99069332010-02-27 19:38:19 +01001595 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001596 }
1597 }
1598
1599 /*
1600 * The following loop implements the mount retries. When the mount
1601 * times out, and the "bg" option is set, we background ourself
1602 * and continue trying.
1603 *
1604 * The case where the mount point is not present and the "bg"
1605 * option is set, is treated as a timeout. This is done to
1606 * support nested mounts.
1607 *
1608 * The "retry" count specified by the user is the number of
1609 * minutes to retry before giving up.
1610 */
1611 {
1612 struct timeval total_timeout;
1613 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001614 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001615 time_t t;
1616 time_t prevt;
1617 time_t timeout;
1618
1619 retry_timeout.tv_sec = 3;
1620 retry_timeout.tv_usec = 0;
1621 total_timeout.tv_sec = 20;
1622 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001623/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001624 timeout = time(NULL) + 60 * retry;
1625 prevt = 0;
1626 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001627 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001628 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001629 if (t - prevt < 30)
1630 sleep(30);
1631
Denis Vlasenkob9256052007-09-28 10:29:17 +00001632 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001633 mountprog,
1634 mountvers,
1635 proto,
1636 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001637 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001638
1639 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001640 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001641 msock = RPC_ANYSOCK;
1642
Denis Vlasenkob9256052007-09-28 10:29:17 +00001643 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001644 case IPPROTO_UDP:
1645 mclient = clntudp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001646 pm_mnt.pm_prog,
1647 pm_mnt.pm_vers,
1648 retry_timeout,
1649 &msock);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001650 if (mclient)
1651 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001652 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001653 msock = RPC_ANYSOCK;
1654 case IPPROTO_TCP:
1655 mclient = clnttcp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001656 pm_mnt.pm_prog,
1657 pm_mnt.pm_vers,
1658 &msock, 0, 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001659 break;
1660 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001661 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001662 }
1663 if (!mclient) {
1664 if (!daemonized && prevt == 0)
1665 error_msg_rpc(clnt_spcreateerror(" "));
1666 } else {
1667 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001668
1669 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001670 mclient->cl_auth = authunix_create_default();
1671
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001672 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001673 * that xdr_array allocates memory for us
1674 */
1675 memset(&status, 0, sizeof(status));
1676
Denis Vlasenkob9256052007-09-28 10:29:17 +00001677 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001678 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001679 (xdrproc_t) xdr_dirpath,
1680 (caddr_t) &pathname,
1681 (xdrproc_t) xdr_mountres3,
1682 (caddr_t) &status,
1683 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001684 else
1685 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001686 (xdrproc_t) xdr_dirpath,
1687 (caddr_t) &pathname,
1688 (xdrproc_t) xdr_fhstatus,
1689 (caddr_t) &status,
1690 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001691
1692 if (clnt_stat == RPC_SUCCESS)
1693 goto prepare_kernel_data; /* we're done */
1694 if (errno != ECONNREFUSED) {
1695 error_msg_rpc(clnt_sperror(mclient, " "));
1696 goto fail; /* don't retry */
1697 }
1698 /* Connection refused */
1699 if (!daemonized && prevt == 0) /* print just once */
1700 error_msg_rpc(clnt_sperror(mclient, " "));
1701 auth_destroy(mclient->cl_auth);
1702 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001703 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001704 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001705 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001706 }
1707
1708 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001709 if (!bg)
1710 goto fail;
1711 if (!daemonized) {
1712 daemonized = daemonize();
1713 if (daemonized <= 0) { /* parent or error */
1714 retval = -daemonized;
1715 goto ret;
1716 }
1717 }
1718 prevt = t;
1719 t = time(NULL);
1720 if (t >= timeout)
1721 /* TODO error message */
1722 goto fail;
1723
1724 goto retry;
1725 }
1726
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001727 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001728
1729 if (nfsvers == 2) {
1730 if (status.nfsv2.fhs_status != 0) {
1731 bb_error_msg("%s:%s failed, reason given by server: %s",
1732 hostname, pathname,
1733 nfs_strerror(status.nfsv2.fhs_status));
1734 goto fail;
1735 }
1736 memcpy(data.root.data,
1737 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1738 NFS_FHSIZE);
1739 data.root.size = NFS_FHSIZE;
1740 memcpy(data.old_root.data,
1741 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1742 NFS_FHSIZE);
1743 } else {
1744 fhandle3 *my_fhandle;
1745 if (status.nfsv3.fhs_status != 0) {
1746 bb_error_msg("%s:%s failed, reason given by server: %s",
1747 hostname, pathname,
1748 nfs_strerror(status.nfsv3.fhs_status));
1749 goto fail;
1750 }
1751 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1752 memset(data.old_root.data, 0, NFS_FHSIZE);
1753 memset(&data.root, 0, sizeof(data.root));
1754 data.root.size = my_fhandle->fhandle3_len;
1755 memcpy(data.root.data,
1756 (char *) my_fhandle->fhandle3_val,
1757 my_fhandle->fhandle3_len);
1758
1759 data.flags |= NFS_MOUNT_VER3;
1760 }
1761
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001762 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001763 if (tcp) {
1764 if (nfs_mount_version < 3) {
1765 bb_error_msg("NFS over TCP is not supported");
1766 goto fail;
1767 }
1768 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1769 } else
1770 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1771 if (fsock < 0) {
1772 bb_perror_msg("nfs socket");
1773 goto fail;
1774 }
1775 if (bindresvport(fsock, 0) < 0) {
1776 bb_perror_msg("nfs bindresvport");
1777 goto fail;
1778 }
1779 if (port == 0) {
1780 server_addr.sin_port = PMAPPORT;
1781 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1782 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1783 if (port == 0)
1784 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001785 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001786 server_addr.sin_port = htons(port);
1787
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001788 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001789 data.fd = fsock;
1790 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1791 strncpy(data.hostname, hostname, sizeof(data.hostname));
1792
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001793 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001794 auth_destroy(mclient->cl_auth);
1795 clnt_destroy(mclient);
1796 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001797 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001798
1799 if (bg) {
1800 /* We must wait until mount directory is available */
1801 struct stat statbuf;
1802 int delay = 1;
1803 while (stat(mp->mnt_dir, &statbuf) == -1) {
1804 if (!daemonized) {
1805 daemonized = daemonize();
1806 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001807/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001808 retval = -daemonized;
1809 goto ret;
1810 }
1811 }
1812 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1813 delay *= 2;
1814 if (delay > 30)
1815 delay = 30;
1816 }
1817 }
1818
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001819 /* Perform actual mount */
1820 do_mount:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001821 retval = mount_it_now(mp, vfsflags, (char*)&data);
1822 goto ret;
1823
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001824 /* Abort */
1825 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001826 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001827 if (mclient) {
1828 auth_destroy(mclient->cl_auth);
1829 clnt_destroy(mclient);
1830 }
1831 close(msock);
1832 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001833 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001834 close(fsock);
1835
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001836 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001837 free(hostname);
1838 free(mounthost);
1839 free(filteropts);
1840 return retval;
1841}
1842
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001843#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001844
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001845/* Linux 2.6.23+ supports nfs mounts with options passed as a string.
1846 * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS.
1847 * (However, note that then you lose any chances that NFS over IPv6 would work).
1848 */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001849static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001850{
1851 len_and_sockaddr *lsa;
1852 char *opts;
1853 char *end;
1854 char *dotted;
1855 int ret;
1856
1857# if ENABLE_FEATURE_IPV6
1858 end = strchr(mp->mnt_fsname, ']');
1859 if (end && end[1] == ':')
1860 end++;
1861 else
1862# endif
1863 /* mount_main() guarantees that ':' is there */
1864 end = strchr(mp->mnt_fsname, ':');
1865
1866 *end = '\0';
Denys Vlasenko39b23312011-11-10 17:01:39 +01001867 lsa = xhost2sockaddr(mp->mnt_fsname, /*port:*/ 0);
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001868 *end = ':';
1869 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1870 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1871 opts = xasprintf("%s%saddr=%s",
1872 filteropts ? filteropts : "",
1873 filteropts ? "," : "",
1874 dotted
1875 );
1876 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
1877 ret = mount_it_now(mp, vfsflags, opts);
1878 if (ENABLE_FEATURE_CLEAN_UP) free(opts);
1879
1880 return ret;
1881}
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001882
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001883#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001884
1885// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1886// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001887// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001888static int singlemount(struct mntent *mp, int ignore_busy)
1889{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001890 int rc = -1;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001891 unsigned long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001892 char *loopFile = NULL, *filteropts = NULL;
1893 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001894 struct stat st;
1895
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001896 errno = 0;
1897
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001898 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1899
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001900 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001901 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1902 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001903
Denis Vlasenko2535f122007-09-15 13:28:30 +00001904 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001905 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1906 char *args[35];
1907 char *s;
1908 int n;
1909 // fsname: "cmd#arg1#arg2..."
1910 // WARNING: allows execution of arbitrary commands!
1911 // Try "mount 'sh#-c#sh' bogus_dir".
1912 // It is safe ONLY because non-root
1913 // cannot use two-argument mount command
1914 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1915 // "mount: can't find sh#-c#sh in /etc/fstab"
1916 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1917
1918 s = mp->mnt_fsname;
1919 n = 0;
1920 args[n++] = s;
1921 while (*s && n < 35 - 2) {
1922 if (*s++ == '#' && *s != '#') {
1923 s[-1] = '\0';
1924 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001925 }
1926 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001927 args[n++] = mp->mnt_dir;
1928 args[n] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +01001929 rc = spawn_and_wait(args);
Denis Vlasenko2535f122007-09-15 13:28:30 +00001930 goto report_error;
1931 }
1932
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001933 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001934 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001935 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1936 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1937 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001938 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001939 int len;
1940 char c;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001941 char *hostname, *share;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001942 len_and_sockaddr *lsa;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001943
1944 // Parse mp->mnt_fsname of the form "//hostname/share[/dir1/dir2]"
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001945
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001946 hostname = mp->mnt_fsname + 2;
1947 len = strcspn(hostname, "/\\");
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001948 share = hostname + len + 1;
1949 if (len == 0 // 3rd char is a [back]slash (IOW: empty hostname)
1950 || share[-1] == '\0' // no [back]slash after hostname
1951 || share[0] == '\0' // empty share name
Martin Santesson406ea152013-01-16 00:47:19 +01001952 ) {
Denis Vlasenko5c329932009-04-12 12:16:21 +00001953 goto report_error;
Martin Santesson406ea152013-01-16 00:47:19 +01001954 }
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001955 c = share[-1];
1956 share[-1] = '\0';
1957 len = strcspn(share, "/\\");
Martin Santesson406ea152013-01-16 00:47:19 +01001958
1959 // "unc=\\hostname\share" option is mandatory
1960 // after CIFS option parsing was rewritten in Linux 3.4.
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001961 // Must use backslashes.
1962 // If /dir1/dir2 is present, also add "prefixpath=dir1/dir2"
Martin Santesson406ea152013-01-16 00:47:19 +01001963 {
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001964 char *unc = xasprintf(
1965 share[len] != '\0' /* "/dir1/dir2" exists? */
1966 ? "unc=\\\\%s\\%.*s,prefixpath=%s"
1967 : "unc=\\\\%s\\%.*s",
1968 hostname,
1969 len, share,
1970 share + len + 1 /* "dir1/dir2" */
1971 );
Denys Vlasenko9b7ebfe2013-01-22 11:00:45 +01001972 parse_mount_options(unc, &filteropts);
1973 if (ENABLE_FEATURE_CLEAN_UP) free(unc);
Martin Santesson406ea152013-01-16 00:47:19 +01001974 }
1975
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001976 lsa = host2sockaddr(hostname, 0);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001977 share[-1] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001978 if (!lsa)
1979 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001980
Denys Vlasenkob09ab442016-09-27 21:02:35 +02001981 // If there is no "ip=..." option yet
1982 if (!is_prefixed_with(filteropts, ",ip="+1)
1983 && !strstr(filteropts, ",ip=")
1984 ) {
1985 char *dotted, *ip;
1986 // Insert "ip=..." option into options
1987 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1988 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1989 ip = xasprintf("ip=%s", dotted);
1990 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denys Vlasenko5093c8c2016-09-26 20:36:30 +02001991// Note: IPv6 scoped addresses ("host%iface", see RFC 4007) should be
Denys Vlasenko3c18e302016-09-26 19:53:04 +02001992// handled by libc in getnameinfo() (inside xmalloc_sockaddr2dotted_noport()).
1993// Currently, glibc does not support that (has no NI_NUMERICSCOPE),
1994// musl apparently does. This results in "ip=numericIPv6%iface_name"
1995// (instead of _numeric_ iface_id) with glibc.
Denys Vlasenko5093c8c2016-09-26 20:36:30 +02001996// This probably should be fixed in glibc, not here.
Denys Vlasenkob09ab442016-09-27 21:02:35 +02001997// The workaround is to manually specify correct "ip=ADDR%n" option.
1998 parse_mount_options(ip, &filteropts);
1999 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
2000 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002001
Denis Vlasenko06c0a712007-01-29 22:51:44 +00002002 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002003 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002004
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002005 goto report_error;
2006 }
2007
2008 // Might this be an NFS filesystem?
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01002009 if ((!mp->mnt_type || is_prefixed_with(mp->mnt_type, "nfs"))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002010 && strchr(mp->mnt_fsname, ':') != NULL
2011 ) {
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01002012 if (!mp->mnt_type)
2013 mp->mnt_type = (char*)"nfs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002014 rc = nfsmount(mp, vfsflags, filteropts);
2015 goto report_error;
2016 }
2017
2018 // Look at the file. (Not found isn't a failure for remount, or for
2019 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00002020 // (We use stat, not lstat, in order to allow
2021 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00002022 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002023 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
2024 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002025 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002026 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
2027 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002028 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002029 if (set_loop(&mp->mnt_fsname, loopFile, 0, /*ro:*/ (vfsflags & MS_RDONLY)) < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002030 if (errno == EPERM || errno == EACCES)
2031 bb_error_msg(bb_msg_perm_denied_are_you_root);
2032 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01002033 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00002034 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002035 }
2036
2037 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002038 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
2039 vfsflags |= MS_BIND;
2040 }
2041
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002042 // If we know the fstype (or don't need to), jump straight
2043 // to the actual mount.
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002044 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002045 char *next;
2046 for (;;) {
2047 next = mp->mnt_type ? strchr(mp->mnt_type, ',') : NULL;
2048 if (next)
2049 *next = '\0';
2050 rc = mount_it_now(mp, vfsflags, filteropts);
2051 if (rc == 0 || !next)
2052 break;
2053 mp->mnt_type = next + 1;
2054 }
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002055 } else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002056 // Loop through filesystem types until mount succeeds
2057 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002058
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01002059 // Initialize list of block backed filesystems.
2060 // This has to be done here so that during "mount -a",
2061 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002062 if (!fslist) {
2063 fslist = get_block_backed_filesystems();
2064 if (ENABLE_FEATURE_CLEAN_UP && fslist)
2065 atexit(delete_block_backed_filesystems);
2066 }
2067
2068 for (fl = fslist; fl; fl = fl->link) {
2069 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00002070 rc = mount_it_now(mp, vfsflags, filteropts);
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002071 if (rc == 0)
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02002072 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002073 }
2074 }
2075
2076 // If mount failed, clean up loop file (if any).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002077 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
2078 del_loop(mp->mnt_fsname);
2079 if (ENABLE_FEATURE_CLEAN_UP) {
2080 free(loopFile);
Denys Vlasenkoecf25cb2016-06-20 11:04:04 +02002081 /* No, "rc != 0" needs it: free(mp->mnt_fsname); */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002082 }
2083 }
2084
Denis Vlasenko5870ad92007-02-04 02:39:55 +00002085 report_error:
2086 if (ENABLE_FEATURE_CLEAN_UP)
2087 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002088
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00002089 if (errno == EBUSY && ignore_busy)
2090 return 0;
Denys Vlasenko911d2652015-12-30 20:11:34 +01002091 if (errno == ENOENT && (vfsflags & MOUNT_NOFAIL))
2092 return 0;
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002093 if (rc != 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002094 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002095 return rc;
2096}
2097
Michael Abbott6b5accb2009-12-04 03:33:07 +01002098// -O support
2099// -O interprets a list of filter options which select whether a mount
2100// point will be mounted: only mounts with options matching *all* filtering
2101// options will be selected.
2102// By default each -O filter option must be present in the list of mount
2103// options, but if it is prefixed by "no" then it must be absent.
2104// For example,
2105// -O a,nob,c matches -o a,c but fails to match -o a,b,c
2106// (and also fails to match -o a because -o c is absent).
2107//
2108// It is different from -t in that each option is matched exactly; a leading
2109// "no" at the beginning of one option does not negate the rest.
2110static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002111{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002112 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01002113 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002114
Michael Abbott6b5accb2009-12-04 03:33:07 +01002115 while (*O_opt) {
2116 const char *fs_opt = fs_opt_in;
2117 int O_len;
2118 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002119
Michael Abbott6b5accb2009-12-04 03:33:07 +01002120 // If option begins with "no" then treat as an inverted match:
2121 // matching is a failure
2122 match = 0;
2123 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
2124 match = 1;
2125 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002126 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002127 // Isolate the current O option
2128 O_len = strchrnul(O_opt, ',') - O_opt;
2129 // Check for a match against existing options
2130 while (1) {
2131 if (strncmp(fs_opt, O_opt, O_len) == 0
2132 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
2133 ) {
2134 if (match)
2135 return 0; // "no" prefix, but option found
2136 match = 1; // current O option found, go check next one
2137 break;
2138 }
2139 fs_opt = strchr(fs_opt, ',');
2140 if (!fs_opt)
2141 break;
2142 fs_opt++;
2143 }
2144 if (match == 0)
2145 return 0; // match wanted but not found
2146 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002147 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01002148 // Step to the next O option
2149 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002150 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002151 // If we get here then everything matched
2152 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002153}
2154
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002155// Parse options, if necessary parse fstab/mtab, and call singlemount for
2156// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002157int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002158int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002159{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002160 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002161 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002162 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002163 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002164 llist_t *lst_o = NULL;
Isaac Dunham7b434a62015-03-11 16:07:24 +01002165 const char *fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002166 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002167 int i, j;
2168 int rc = EXIT_SUCCESS;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002169 unsigned long cmdopt_flags;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002170 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002171 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002172 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002173
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002174 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00002175
Denys Vlasenko16714242011-09-21 01:59:15 +02002176 INIT_G();
2177
Denis Vlasenkof732e962008-02-18 12:07:49 +00002178 // Parse long options, like --bind and --move. Note that -o option
2179 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002180 for (i = j = 1; argv[i]; i++) {
2181 if (argv[i][0] == '-' && argv[i][1] == '-')
2182 append_mount_options(&cmdopts, argv[i] + 2);
2183 else
2184 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002185 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002186 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002187
2188 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002189 // Max 2 params; -o is a list, -v is a counter
Denys Vlasenko237bedd2016-07-06 21:58:02 +02002190 opt_complementary = "?2" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002191 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Isaac Dunham7b434a62015-03-11 16:07:24 +01002192 IF_FEATURE_MOUNT_OTHERTAB(, &fstabname)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002193 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002194 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00002195 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
2196 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00002197 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002198
2199 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002200 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00002201 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002202 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
2203
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002204 if (!mountTable)
2205 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002206
Denis Vlasenko2535f122007-09-15 13:28:30 +00002207 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002208 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002209 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002210 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00002211 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002212 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002213
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002214 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002215 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
2216 mtpair->mnt_dir, mtpair->mnt_type,
2217 mtpair->mnt_opts);
2218 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002219 if (ENABLE_FEATURE_CLEAN_UP)
2220 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002221 return EXIT_SUCCESS;
2222 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002223 storage_path = NULL;
2224 } else {
2225 // When we have two arguments, the second is the directory and we can
2226 // skip looking at fstab entirely. We can always abspath() the directory
2227 // argument when we get it.
2228 if (argv[1]) {
2229 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002230 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002231 mtpair->mnt_fsname = argv[0];
2232 mtpair->mnt_dir = argv[1];
2233 mtpair->mnt_type = fstype;
2234 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002235 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002236 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002237 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00002238 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002239 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002240 }
2241
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002242 // Past this point, we are handling either "mount -a [opts]"
2243 // or "mount [opts] single_param"
2244
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002245 cmdopt_flags = parse_mount_options(cmdopts, NULL);
2246 if (nonroot && (cmdopt_flags & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002247 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00002248
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002249 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002250 if (ENABLE_FEATURE_MOUNT_FLAGS
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002251 && (cmdopt_flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002252 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002253 // verbose_mount(source, target, type, flags, data)
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002254 rc = verbose_mount("", argv[0], "", cmdopt_flags, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002255 if (rc)
2256 bb_simple_perror_msg_and_die(argv[0]);
2257 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002258 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002259
Isaac Dunham7b434a62015-03-11 16:07:24 +01002260 // A malicious user could overmount /usr without this.
2261 if (ENABLE_FEATURE_MOUNT_OTHERTAB && nonroot)
2262 fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002263 // Open either fstab or mtab
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002264 if (cmdopt_flags & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002265 // WARNING. I am not sure this matches util-linux's
2266 // behavior. It's possible util-linux does not
2267 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002268 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002269 }
2270 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00002271 if (!fstab)
Denys Vlasenko651a2692010-03-23 16:25:17 +01002272 bb_perror_msg_and_die("can't read '%s'", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002273
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002274 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00002275 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002276 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002277 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002278
2279 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00002280 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002281 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002282 GETMNTENT_BUFSIZE/2)
2283 ) { // End of fstab/mtab is reached
2284 mtcur = mtother; // the thing we found last time
2285 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002286 }
2287
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002288 // If we're trying to mount something specific and this isn't it,
2289 // skip it. Note we must match the exact text in fstab (ala
2290 // "proc") or a full path from root
2291 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002292
2293 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002294 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
2295 && strcmp(storage_path, mtcur->mnt_fsname) != 0
2296 && strcmp(argv[0], mtcur->mnt_dir) != 0
2297 && strcmp(storage_path, mtcur->mnt_dir) != 0
2298 ) {
2299 continue; // no
2300 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002301
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002302 // Remember this entry. Something later may have
2303 // overmounted it, and we want the _last_ match.
2304 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002305
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002306 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002307 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002308 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002309 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002310 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002311 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002312 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002313
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002314 // Does type match? (NULL matches always)
2315 if (!match_fstype(mtcur, fstype))
2316 continue;
2317
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002318 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002319 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
2320 // swap is bogus "fstype", parse_mount_options can't check fstypes
2321 || strcasecmp(mtcur->mnt_type, "swap") == 0
2322 ) {
2323 continue;
2324 }
2325
2326 // Does (at least one) option match?
2327 // (NULL matches always)
2328 if (!match_opt(mtcur->mnt_opts, O_optmatch))
2329 continue;
2330
2331 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002332
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002333 // NFS mounts want this to be xrealloc-able
2334 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002335
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002336 // If nothing is mounted on this directory...
2337 // (otherwise repeated "mount -a" mounts everything again)
2338 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2339 // We do not check fsname match of found mount point -
2340 // "/" may have fsname of "/dev/root" while fstab
2341 // says "/dev/something_else".
2342 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01002343 if (verbose) {
2344 bb_error_msg("according to %s, "
2345 "%s is already mounted on %s",
2346 bb_path_mtab_file,
2347 mp->mnt_fsname, mp->mnt_dir);
2348 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002349 } else {
2350 // ...mount this thing
2351 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2352 // Count number of failed mounts
2353 rc++;
2354 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002355 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002356 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002357 }
2358 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002359
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002360 // End of fstab/mtab is reached.
2361 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002362 if (argv[0]) { // yes
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002363 unsigned long l;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002364
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002365 // If we didn't find anything, complain
2366 if (!mtcur->mnt_fsname)
2367 bb_error_msg_and_die("can't find %s in %s",
2368 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002369
2370 // What happens when we try to "mount swap_partition"?
2371 // (fstab containts "swap_partition swap swap defaults 0 0")
2372 // util-linux-ng 2.13.1 does this:
2373 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2374 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2375 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2376 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2377 // exit_group(32) = ?
2378#if 0
2379 // In case we want to simply skip swap partitions:
2380 l = parse_mount_options(mtcur->mnt_opts, NULL);
2381 if ((l & MOUNT_SWAP)
2382 // swap is bogus "fstype", parse_mount_options can't check fstypes
2383 || strcasecmp(mtcur->mnt_type, "swap") == 0
2384 ) {
2385 goto ret;
2386 }
2387#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002388 if (nonroot) {
2389 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002390 l = parse_mount_options(mtcur->mnt_opts, NULL);
2391 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002392 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002393 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002394
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002395 //util-linux-2.12 does not do this check.
2396 //// If nothing is mounted on this directory...
2397 //// (otherwise repeated "mount FOO" mounts FOO again)
2398 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2399 //if (mp) {
2400 // bb_error_msg("according to %s, "
2401 // "%s is already mounted on %s",
2402 // bb_path_mtab_file,
2403 // mp->mnt_fsname, mp->mnt_dir);
2404 //} else {
2405 // ...mount the last thing we found
2406 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2407 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2408 resolve_mount_spec(&mtpair->mnt_fsname);
2409 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2410 if (ENABLE_FEATURE_CLEAN_UP)
2411 free(mtcur->mnt_opts);
2412 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002413 }
2414
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002415 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002416 if (ENABLE_FEATURE_CLEAN_UP)
2417 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002418 if (ENABLE_FEATURE_CLEAN_UP) {
2419 free(storage_path);
2420 free(cmdopts);
2421 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002422
2423//TODO: exitcode should be ORed mask of (from "man mount"):
2424// 0 success
2425// 1 incorrect invocation or permissions
2426// 2 system error (out of memory, cannot fork, no more loop devices)
2427// 4 internal mount bug or missing nfs support in mount
2428// 8 user interrupt
2429//16 problems writing or locking /etc/mtab
2430//32 mount failure
2431//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002432 return rc;
2433}