blob: 423e89d5bf409570192b18c28d73ae84fe88dd79 [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
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020021//config: bool "mount (30 kb)"
Isaac Dunham7b434a62015-03-11 16:07:24 +010022//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__)
Denys Vlasenkoce552842017-07-10 14:43:22 +0200249# warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support"
250 /* not #error, since user may be using e.g. libtirpc instead */
Denys Vlasenkocc428142009-12-16 02:06:56 +0100251# endif
252# include <rpc/rpc.h>
253# include <rpc/pmap_prot.h>
254# include <rpc/pmap_clnt.h>
255#endif
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000256
257
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000258#if defined(__dietlibc__)
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000259// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
260// dietlibc-0.30 does not have implementation of getmntent_r()
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000261static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000262 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000263{
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000264 struct mntent* ment = getmntent(stream);
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000265 return memcpy(result, ment, sizeof(*ment));
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000266}
267#endif
268
269
Rob Landleydc0955b2006-03-14 18:16:25 +0000270// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000271enum {
Denys Vlasenko911d2652015-12-30 20:11:34 +0100272 MOUNT_USERS = (1 << 27) * ENABLE_DESKTOP,
273 MOUNT_NOFAIL = (1 << 28) * ENABLE_DESKTOP,
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000274 MOUNT_NOAUTO = (1 << 29),
275 MOUNT_SWAP = (1 << 30),
Denys Vlasenko911d2652015-12-30 20:11:34 +0100276 MOUNT_FAKEFLAGS = MOUNT_USERS | MOUNT_NOFAIL | MOUNT_NOAUTO | MOUNT_SWAP
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000277};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000278
279
Denys Vlasenko237bedd2016-07-06 21:58:02 +0200280#define OPTION_STR "o:*t:rwanfvsiO:" IF_FEATURE_MOUNT_OTHERTAB("T:")
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000281enum {
282 OPT_o = (1 << 0),
283 OPT_t = (1 << 1),
284 OPT_r = (1 << 2),
285 OPT_w = (1 << 3),
286 OPT_a = (1 << 4),
287 OPT_n = (1 << 5),
288 OPT_f = (1 << 6),
289 OPT_v = (1 << 7),
290 OPT_s = (1 << 8),
291 OPT_i = (1 << 9),
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000292 OPT_O = (1 << 10),
Isaac Dunham7b434a62015-03-11 16:07:24 +0100293 OPT_T = (1 << 11),
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000294};
295
296#if ENABLE_FEATURE_MTAB_SUPPORT
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200297#define USE_MTAB (!(option_mask32 & OPT_n))
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000298#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200299#define USE_MTAB 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000300#endif
301
302#if ENABLE_FEATURE_MOUNT_FAKE
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200303#define FAKE_IT (option_mask32 & OPT_f)
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000304#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200305#define FAKE_IT 0
306#endif
307
308#if ENABLE_FEATURE_MOUNT_HELPERS
309#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
310#else
311#define HELPERS_ALLOWED 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000312#endif
313
314
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000315// TODO: more "user" flag compatibility.
316// "user" option (from mount manpage):
317// Only the user that mounted a filesystem can unmount it again.
318// If any user should be able to unmount, then use users instead of user
319// in the fstab line. The owner option is similar to the user option,
320// with the restriction that the user must be the owner of the special file.
321// This may be useful e.g. for /dev/fd if a login script makes
322// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000323
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000324// Standard mount options (from -o options or --options),
325// with corresponding flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000326static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000327 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000328
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000329 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000330 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000331 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000332
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000333 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000334 /* "defaults" */ 0,
335 /* "quiet" 0 - do not filter out, vfat wants to see it */
336 /* "noauto" */ MOUNT_NOAUTO,
337 /* "sw" */ MOUNT_SWAP,
338 /* "swap" */ MOUNT_SWAP,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000339 IF_DESKTOP(/* "user" */ MOUNT_USERS,)
340 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
Denys Vlasenko911d2652015-12-30 20:11:34 +0100341 IF_DESKTOP(/* "nofail" */ MOUNT_NOFAIL,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000342 /* "_netdev" */ 0,
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100343 IF_DESKTOP(/* "comment=" */ 0,) /* systemd uses this in fstab */
Rob Landleye3781b72006-08-08 01:39:49 +0000344 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000345
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000346 IF_FEATURE_MOUNT_FLAGS(
Rob Landleye3781b72006-08-08 01:39:49 +0000347 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000348 /* "nosuid" */ MS_NOSUID,
349 /* "suid" */ ~MS_NOSUID,
350 /* "dev" */ ~MS_NODEV,
351 /* "nodev" */ MS_NODEV,
352 /* "exec" */ ~MS_NOEXEC,
353 /* "noexec" */ MS_NOEXEC,
354 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000355 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000356 /* "async" */ ~MS_SYNCHRONOUS,
357 /* "atime" */ ~MS_NOATIME,
358 /* "noatime" */ MS_NOATIME,
359 /* "diratime" */ ~MS_NODIRATIME,
360 /* "nodiratime" */ MS_NODIRATIME,
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000361 /* "mand" */ MS_MANDLOCK,
362 /* "nomand" */ ~MS_MANDLOCK,
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000363 /* "relatime" */ MS_RELATIME,
364 /* "norelatime" */ ~MS_RELATIME,
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200365 /* "strictatime" */ MS_STRICTATIME,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000366 /* "loud" */ ~MS_SILENT,
Roman Borisov19311bf2011-03-24 15:08:43 +0300367 /* "rbind" */ MS_BIND|MS_RECURSIVE,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000368
Rob Landleye3781b72006-08-08 01:39:49 +0000369 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200370 /* "union" */ MS_UNION,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000371 /* "bind" */ MS_BIND,
372 /* "move" */ MS_MOVE,
373 /* "shared" */ MS_SHARED,
374 /* "slave" */ MS_SLAVE,
375 /* "private" */ MS_PRIVATE,
376 /* "unbindable" */ MS_UNBINDABLE,
377 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
378 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
Roman Borisovd3679d22011-03-23 11:20:25 +0300379 /* "rprivate" */ MS_PRIVATE|MS_RECURSIVE,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000380 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000381 )
382
383 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000384 /* "ro" */ MS_RDONLY, // vfs flag
385 /* "rw" */ ~MS_RDONLY, // vfs flag
386 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000387};
388
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200389static const char mount_option_str[] ALIGN1 =
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000390 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000391 "loop\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000392 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000393 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000394 "defaults\0"
395 // "quiet\0" - do not filter out, vfat wants to see it
396 "noauto\0"
397 "sw\0"
398 "swap\0"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000399 IF_DESKTOP("user\0")
400 IF_DESKTOP("users\0")
Denys Vlasenko911d2652015-12-30 20:11:34 +0100401 IF_DESKTOP("nofail\0")
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000402 "_netdev\0"
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100403 IF_DESKTOP("comment=\0") /* systemd uses this in fstab */
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000404 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000405 IF_FEATURE_MOUNT_FLAGS(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000406 // vfs flags
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000407 "nosuid\0"
408 "suid\0"
409 "dev\0"
410 "nodev\0"
411 "exec\0"
412 "noexec\0"
413 "sync\0"
414 "dirsync\0"
415 "async\0"
416 "atime\0"
417 "noatime\0"
418 "diratime\0"
419 "nodiratime\0"
420 "mand\0"
421 "nomand\0"
422 "relatime\0"
423 "norelatime\0"
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200424 "strictatime\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000425 "loud\0"
Roman Borisov19311bf2011-03-24 15:08:43 +0300426 "rbind\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000427
428 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200429 "union\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000430 "bind\0"
431 "move\0"
Roman Borisov945fd172011-02-25 14:50:39 +0300432 "make-shared\0"
433 "make-slave\0"
434 "make-private\0"
435 "make-unbindable\0"
436 "make-rshared\0"
437 "make-rslave\0"
438 "make-rprivate\0"
439 "make-runbindable\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000440 )
441
442 // Always understood.
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000443 "ro\0" // vfs flag
444 "rw\0" // vfs flag
445 "remount\0" // action flag
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000446;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000447
Denis Vlasenkof732e962008-02-18 12:07:49 +0000448
449struct globals {
450#if ENABLE_FEATURE_MOUNT_NFS
451 smalluint nfs_mount_version;
452#endif
453#if ENABLE_FEATURE_MOUNT_VERBOSE
454 unsigned verbose;
455#endif
456 llist_t *fslist;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000457 char getmntent_buf[1];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100458} FIX_ALIASING;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000459enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200460#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenkof732e962008-02-18 12:07:49 +0000461#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000462#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000463#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000464#else
465#define verbose 0
466#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000467#define fslist (G.fslist )
468#define getmntent_buf (G.getmntent_buf )
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200469#define INIT_G() do { setup_common_bufsiz(); } while (0)
Denis Vlasenkof732e962008-02-18 12:07:49 +0000470
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100471#if ENABLE_FEATURE_MTAB_SUPPORT
472/*
473 * update_mtab_entry_on_move() is used to update entry in case of mount --move.
474 * we are looking for existing entries mnt_dir which is equal to mnt_fsname of
475 * input mntent and replace it by new one.
476 */
477static void FAST_FUNC update_mtab_entry_on_move(const struct mntent *mp)
478{
479 struct mntent *entries, *m;
480 int i, count;
481 FILE *mountTable;
482
483 mountTable = setmntent(bb_path_mtab_file, "r");
484 if (!mountTable) {
485 bb_perror_msg(bb_path_mtab_file);
486 return;
487 }
488
489 entries = NULL;
490 count = 0;
491 while ((m = getmntent(mountTable)) != NULL) {
492 entries = xrealloc_vector(entries, 3, count);
493 entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
494 entries[count].mnt_dir = xstrdup(m->mnt_dir);
495 entries[count].mnt_type = xstrdup(m->mnt_type);
496 entries[count].mnt_opts = xstrdup(m->mnt_opts);
497 entries[count].mnt_freq = m->mnt_freq;
498 entries[count].mnt_passno = m->mnt_passno;
499 count++;
500 }
501 endmntent(mountTable);
502
503 mountTable = setmntent(bb_path_mtab_file, "w");
504 if (mountTable) {
505 for (i = 0; i < count; i++) {
506 if (strcmp(entries[i].mnt_dir, mp->mnt_fsname) != 0)
507 addmntent(mountTable, &entries[i]);
508 else
509 addmntent(mountTable, mp);
510 }
511 endmntent(mountTable);
512 } else if (errno != EROFS)
513 bb_perror_msg(bb_path_mtab_file);
514
515 if (ENABLE_FEATURE_CLEAN_UP) {
516 for (i = 0; i < count; i++) {
517 free(entries[i].mnt_fsname);
518 free(entries[i].mnt_dir);
519 free(entries[i].mnt_type);
520 free(entries[i].mnt_opts);
521 }
522 free(entries);
523 }
524}
525#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000526
527#if ENABLE_FEATURE_MOUNT_VERBOSE
528static int verbose_mount(const char *source, const char *target,
529 const char *filesystemtype,
530 unsigned long mountflags, const void *data)
531{
532 int rc;
533
534 errno = 0;
535 rc = mount(source, target, filesystemtype, mountflags, data);
536 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000537 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000538 source, target, filesystemtype,
539 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000540 return rc;
541}
542#else
543#define verbose_mount(...) mount(__VA_ARGS__)
544#endif
545
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000546// Append mount options to string
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000547static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000548{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000549 if (*oldopts && **oldopts) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000550 // Do not insert options which are already there
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000551 while (newopts[0]) {
552 char *p;
553 int len = strlen(newopts);
554 p = strchr(newopts, ',');
555 if (p) len = p - newopts;
556 p = *oldopts;
557 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000558 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000559 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000560 goto skip;
561 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000562 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000563 p++;
564 }
565 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
566 free(*oldopts);
567 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000568 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000569 newopts += len;
570 while (newopts[0] == ',') newopts++;
571 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000572 } else {
573 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000574 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000575 }
576}
577
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000578// Use the mount_options list to parse options into flags.
Alexander Shishkin77650952010-10-28 06:10:03 +0200579// Also update list of unrecognized options if unrecognized != NULL
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200580static unsigned long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000581{
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200582 unsigned long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000583
Rob Landley6a6798b2005-08-10 20:35:54 +0000584 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000585 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000586 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000587 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000588 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000589
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000590 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000591
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000592// FIXME: use hasmntopt()
Rob Landley6a6798b2005-08-10 20:35:54 +0000593 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000594 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200595 unsigned opt_len = strlen(option_str);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100596
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200597 if (strncasecmp(option_str, options, opt_len) == 0
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100598 && (options[opt_len] == '\0'
599 /* or is it "comment=" thingy in fstab? */
600 IF_FEATURE_MOUNT_FSTAB(IF_DESKTOP( || option_str[opt_len-1] == '=' ))
601 )
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200602 ) {
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200603 unsigned long fl = mount_options[i];
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200604 if (fl & BB_MS_INVERTED_VALUE)
Alexander Shishkin77650952010-10-28 06:10:03 +0200605 flags &= fl;
606 else
607 flags |= fl;
608 goto found;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000609 }
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200610 option_str += opt_len + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000611 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200612 // We did not recognize this option.
613 // If "unrecognized" is not NULL, append option there.
614 // Note that we should not append *empty* option -
615 // in this case we want to pass NULL, not "", to "data"
616 // parameter of mount(2) syscall.
617 // This is crucial for filesystems that don't accept
618 // any arbitrary mount options, like cgroup fs:
619 // "mount -t cgroup none /mnt"
620 if (options[0] && unrecognized) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000621 // Add it to strflags, to pass on to kernel
Alexander Shishkin77650952010-10-28 06:10:03 +0200622 char *p = *unrecognized;
623 unsigned len = p ? strlen(p) : 0;
624 *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000625
Rob Landley6a6798b2005-08-10 20:35:54 +0000626 // Comma separated if it's not the first one
Alexander Shishkin77650952010-10-28 06:10:03 +0200627 if (len) p[len++] = ',';
628 strcpy(p + len, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000629 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200630 found:
Denis Vlasenko2535f122007-09-15 13:28:30 +0000631 if (!comma)
632 break;
633 // Advance to next option
634 *comma = ',';
635 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000636 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000637
Rob Landleydc0955b2006-03-14 18:16:25 +0000638 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000639}
640
Rob Landleydc0955b2006-03-14 18:16:25 +0000641// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000642static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000643{
Denis Vlasenko87468852007-04-13 23:22:00 +0000644 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000645 "/etc/filesystems",
646 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000647 };
648 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200649 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000650 int i;
651 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000652
Denis Vlasenko87468852007-04-13 23:22:00 +0000653 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000654 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000655 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000656
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000657 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100658 if (is_prefixed_with(buf, "nodev") && isspace(buf[5]))
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100659 goto next;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000660 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200661 if (*fs == '#' || *fs == '*' || !*fs)
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100662 goto next;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000663
Denis Vlasenko372686b2006-10-12 22:42:33 +0000664 llist_add_to_end(&list, xstrdup(fs));
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100665 next:
Denis Vlasenko372686b2006-10-12 22:42:33 +0000666 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000667 }
668 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
669 }
670
671 return list;
672}
673
Rob Landleydc0955b2006-03-14 18:16:25 +0000674#if ENABLE_FEATURE_CLEAN_UP
675static void delete_block_backed_filesystems(void)
676{
Rob Landleya6b5b602006-05-08 19:03:07 +0000677 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000678}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000679#else
680void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000681#endif
682
Rob Landleydc0955b2006-03-14 18:16:25 +0000683// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000684// NB: mp->xxx fields may be trashed on exit
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200685static int mount_it_now(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000686{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000687 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000688
Denys Vlasenko911d2652015-12-30 20:11:34 +0100689 vfsflags &= ~(unsigned long)MOUNT_FAKEFLAGS;
690
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200691 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000692 if (verbose >= 2)
693 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
694 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
695 vfsflags, filteropts);
696 goto mtab;
697 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000698
Rob Landleydc0955b2006-03-14 18:16:25 +0000699 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000700 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000701 errno = 0;
702 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000703 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000704
705 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000706 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200707 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200708 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000709 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000710 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000711 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200712 if (FAKE_IT)
713 args[rc++] = (char *)"-f";
714 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
715 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000716 args[rc++] = mp->mnt_fsname;
717 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000718 if (filteropts) {
719 args[rc++] = (char *)"-o";
720 args[rc++] = filteropts;
721 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000722 args[rc] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +0100723 rc = spawn_and_wait(args);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000724 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000725 if (!rc)
726 break;
727 errno = errno_save;
728 }
729
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000730 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000731 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000732 if (!(vfsflags & MS_SILENT))
733 bb_error_msg("%s is write-protected, mounting read-only",
734 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000735 vfsflags |= MS_RDONLY;
736 }
737
Rob Landleydc0955b2006-03-14 18:16:25 +0000738 // Abort entirely if permission denied.
739
740 if (rc && errno == EPERM)
741 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
742
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000743 // If the mount was successful, and we're maintaining an old-style
744 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000745 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200746 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000747 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000748 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000749 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000750 int i;
751
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000752 if (!mountTable) {
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100753 bb_perror_msg(bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000754 goto ret;
755 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000756
757 // Add vfs string flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000758 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
759 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
760 append_mount_options(&(mp->mnt_opts), option_str);
761 option_str += strlen(option_str) + 1;
762 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000763
764 // Remove trailing / (if any) from directory we mounted on
Denis Vlasenko727ef942006-09-14 13:19:19 +0000765 i = strlen(mp->mnt_dir) - 1;
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100766 while (i > 0 && mp->mnt_dir[i] == '/')
Denys Vlasenkoc6450c92011-02-28 11:09:49 +0100767 mp->mnt_dir[i--] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000768
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000769 // Convert to canonical pathnames as needed
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000770 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100771 fsname = NULL;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000772 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000773 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000774 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000775 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000776 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000777
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100778 // Write and close
779#if ENABLE_FEATURE_MTAB_SUPPORT
780 if (vfsflags & MS_MOVE)
781 update_mtab_entry_on_move(mp);
782 else
783#endif
784 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000785 endmntent(mountTable);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100786
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000787 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000788 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000789 free(fsname);
790 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000791 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000792 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000793 return rc;
794}
795
Denis Vlasenko25098f72006-09-14 15:46:33 +0000796#if ENABLE_FEATURE_MOUNT_NFS
797
798/*
799 * Linux NFS mount
800 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
801 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +0200802 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko25098f72006-09-14 15:46:33 +0000803 *
804 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
805 * numbers to be specified on the command line.
806 *
807 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
808 * Omit the call to connect() for Linux version 1.3.11 or later.
809 *
810 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
811 * Implemented the "bg", "fg" and "retry" mount options for NFS.
812 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000813 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000814 * - added Native Language Support
815 *
816 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
817 * plus NFSv3 stuff.
818 */
819
Denis Vlasenko25098f72006-09-14 15:46:33 +0000820#define MOUNTPORT 635
821#define MNTPATHLEN 1024
822#define MNTNAMLEN 255
823#define FHSIZE 32
824#define FHSIZE3 64
825
826typedef char fhandle[FHSIZE];
827
828typedef struct {
829 unsigned int fhandle3_len;
830 char *fhandle3_val;
831} fhandle3;
832
833enum mountstat3 {
834 MNT_OK = 0,
835 MNT3ERR_PERM = 1,
836 MNT3ERR_NOENT = 2,
837 MNT3ERR_IO = 5,
838 MNT3ERR_ACCES = 13,
839 MNT3ERR_NOTDIR = 20,
840 MNT3ERR_INVAL = 22,
841 MNT3ERR_NAMETOOLONG = 63,
842 MNT3ERR_NOTSUPP = 10004,
843 MNT3ERR_SERVERFAULT = 10006,
844};
845typedef enum mountstat3 mountstat3;
846
847struct fhstatus {
848 unsigned int fhs_status;
849 union {
850 fhandle fhs_fhandle;
851 } fhstatus_u;
852};
853typedef struct fhstatus fhstatus;
854
855struct mountres3_ok {
856 fhandle3 fhandle;
857 struct {
858 unsigned int auth_flavours_len;
859 char *auth_flavours_val;
860 } auth_flavours;
861};
862typedef struct mountres3_ok mountres3_ok;
863
864struct mountres3 {
865 mountstat3 fhs_status;
866 union {
867 mountres3_ok mountinfo;
868 } mountres3_u;
869};
870typedef struct mountres3 mountres3;
871
872typedef char *dirpath;
873
874typedef char *name;
875
876typedef struct mountbody *mountlist;
877
878struct mountbody {
879 name ml_hostname;
880 dirpath ml_directory;
881 mountlist ml_next;
882};
883typedef struct mountbody mountbody;
884
885typedef struct groupnode *groups;
886
887struct groupnode {
888 name gr_name;
889 groups gr_next;
890};
891typedef struct groupnode groupnode;
892
893typedef struct exportnode *exports;
894
895struct exportnode {
896 dirpath ex_dir;
897 groups ex_groups;
898 exports ex_next;
899};
900typedef struct exportnode exportnode;
901
902struct ppathcnf {
903 int pc_link_max;
904 short pc_max_canon;
905 short pc_max_input;
906 short pc_name_max;
907 short pc_path_max;
908 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000909 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000910 char pc_xxx;
911 short pc_mask[2];
912};
913typedef struct ppathcnf ppathcnf;
914
915#define MOUNTPROG 100005
916#define MOUNTVERS 1
917
918#define MOUNTPROC_NULL 0
919#define MOUNTPROC_MNT 1
920#define MOUNTPROC_DUMP 2
921#define MOUNTPROC_UMNT 3
922#define MOUNTPROC_UMNTALL 4
923#define MOUNTPROC_EXPORT 5
924#define MOUNTPROC_EXPORTALL 6
925
926#define MOUNTVERS_POSIX 2
927
928#define MOUNTPROC_PATHCONF 7
929
930#define MOUNT_V3 3
931
932#define MOUNTPROC3_NULL 0
933#define MOUNTPROC3_MNT 1
934#define MOUNTPROC3_DUMP 2
935#define MOUNTPROC3_UMNT 3
936#define MOUNTPROC3_UMNTALL 4
937#define MOUNTPROC3_EXPORT 5
938
939enum {
940#ifndef NFS_FHSIZE
941 NFS_FHSIZE = 32,
942#endif
943#ifndef NFS_PORT
944 NFS_PORT = 2049
945#endif
946};
947
Denis Vlasenko25098f72006-09-14 15:46:33 +0000948/*
949 * We want to be able to compile mount on old kernels in such a way
950 * that the binary will work well on more recent kernels.
951 * Thus, if necessary we teach nfsmount.c the structure of new fields
952 * that will come later.
953 *
954 * Moreover, the new kernel includes conflict with glibc includes
955 * so it is easiest to ignore the kernel altogether (at compile time).
956 */
957
958struct nfs2_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100959 char data[32];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000960};
961struct nfs3_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100962 unsigned short size;
963 unsigned char data[64];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000964};
965
966struct nfs_mount_data {
Dave Lovefae473c2011-11-10 15:19:25 +0100967 int version; /* 1 */
968 int fd; /* 1 */
969 struct nfs2_fh old_root; /* 1 */
970 int flags; /* 1 */
971 int rsize; /* 1 */
972 int wsize; /* 1 */
973 int timeo; /* 1 */
974 int retrans; /* 1 */
975 int acregmin; /* 1 */
976 int acregmax; /* 1 */
977 int acdirmin; /* 1 */
978 int acdirmax; /* 1 */
979 struct sockaddr_in addr; /* 1 */
980 char hostname[256]; /* 1 */
981 int namlen; /* 2 */
982 unsigned int bsize; /* 3 */
983 struct nfs3_fh root; /* 4 */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000984};
985
986/* bits in the flags field */
987enum {
988 NFS_MOUNT_SOFT = 0x0001, /* 1 */
989 NFS_MOUNT_INTR = 0x0002, /* 1 */
990 NFS_MOUNT_SECURE = 0x0004, /* 1 */
991 NFS_MOUNT_POSIX = 0x0008, /* 1 */
992 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
993 NFS_MOUNT_NOAC = 0x0020, /* 1 */
994 NFS_MOUNT_TCP = 0x0040, /* 2 */
995 NFS_MOUNT_VER3 = 0x0080, /* 3 */
996 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000997 NFS_MOUNT_NONLM = 0x0200, /* 3 */
Dave Lovefae473c2011-11-10 15:19:25 +0100998 NFS_MOUNT_NOACL = 0x0800, /* 4 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000999 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +00001000};
1001
1002
1003/*
1004 * We need to translate between nfs status return values and
1005 * the local errno values which may not be the same.
1006 *
1007 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
1008 * "after #include <errno.h> the symbol errno is reserved for any use,
1009 * it cannot even be used as a struct tag or field name".
1010 */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001011#ifndef EDQUOT
Denys Vlasenkocc428142009-12-16 02:06:56 +01001012# define EDQUOT ENOSPC
Denis Vlasenko25098f72006-09-14 15:46:33 +00001013#endif
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001014/* Convert each NFSERR_BLAH into EBLAH */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02001015static const uint8_t nfs_err_stat[] ALIGN1 = {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001016 1, 2, 5, 6, 13, 17,
1017 19, 20, 21, 22, 27, 28,
1018 30, 63, 66, 69, 70, 71
1019};
Denys Vlasenkodc1fd2e2010-05-19 17:01:29 +02001020#if ( \
1021 EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
1022 ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
1023 EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
1024typedef uint8_t nfs_err_type;
1025#else
1026typedef uint16_t nfs_err_type;
1027#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02001028static const nfs_err_type nfs_err_errnum[] ALIGN2 = {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001029 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
1030 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
1031 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
Denis Vlasenko25098f72006-09-14 15:46:33 +00001032};
Denis Vlasenko25098f72006-09-14 15:46:33 +00001033static char *nfs_strerror(int status)
1034{
1035 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001036
Denys Vlasenkocc428142009-12-16 02:06:56 +01001037 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
1038 if (nfs_err_stat[i] == status)
1039 return strerror(nfs_err_errnum[i]);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001040 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001041 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001042}
1043
1044static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
1045{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001046 return xdr_opaque(xdrs, objp, FHSIZE);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001047}
1048
1049static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
1050{
1051 if (!xdr_u_int(xdrs, &objp->fhs_status))
Denys Vlasenko69675782013-01-14 01:34:48 +01001052 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001053 if (objp->fhs_status == 0)
1054 return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001055 return TRUE;
1056}
1057
1058static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
1059{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001060 return xdr_string(xdrs, objp, MNTPATHLEN);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001061}
1062
1063static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
1064{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001065 return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
Denys Vlasenko69675782013-01-14 01:34:48 +01001066 (unsigned int *) &objp->fhandle3_len,
1067 FHSIZE3);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001068}
1069
1070static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
1071{
1072 if (!xdr_fhandle3(xdrs, &objp->fhandle))
1073 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001074 return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
Denys Vlasenko69675782013-01-14 01:34:48 +01001075 &(objp->auth_flavours.auth_flavours_len),
1076 ~0,
1077 sizeof(int),
1078 (xdrproc_t) xdr_int);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001079}
1080
1081static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
1082{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001083 return xdr_enum(xdrs, (enum_t *) objp);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001084}
1085
1086static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
1087{
1088 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
1089 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001090 if (objp->fhs_status == MNT_OK)
1091 return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001092 return TRUE;
1093}
1094
1095#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
1096
Denis Vlasenko25098f72006-09-14 15:46:33 +00001097/*
1098 * Unfortunately, the kernel prints annoying console messages
1099 * in case of an unexpected nfs mount version (instead of
1100 * just returning some error). Therefore we'll have to try
1101 * and figure out what version the kernel expects.
1102 *
1103 * Variables:
1104 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
1105 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
1106 * nfs_mount_version: version this source and running kernel can handle
1107 */
1108static void
1109find_kernel_nfs_mount_version(void)
1110{
Denis Vlasenkob9256052007-09-28 10:29:17 +00001111 int kernel_version;
1112
1113 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001114 return;
1115
1116 nfs_mount_version = 4; /* default */
1117
1118 kernel_version = get_linux_version_code();
1119 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001120 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +00001121 nfs_mount_version = 3;
1122 /* else v4 since 2.3.99pre4 */
1123 }
1124}
1125
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +00001126static void
Denis Vlasenkob9256052007-09-28 10:29:17 +00001127get_mountport(struct pmap *pm_mnt,
1128 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001129 long unsigned prog,
1130 long unsigned version,
1131 long unsigned proto,
1132 long unsigned port)
1133{
1134 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001135
1136 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001137/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
1138 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001139 pmap = pmap_getmaps(server_addr);
1140
1141 if (version > MAX_NFSPROT)
1142 version = MAX_NFSPROT;
1143 if (!prog)
1144 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001145 pm_mnt->pm_prog = prog;
1146 pm_mnt->pm_vers = version;
1147 pm_mnt->pm_prot = proto;
1148 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001149
Denis Vlasenko25098f72006-09-14 15:46:33 +00001150 while (pmap) {
1151 if (pmap->pml_map.pm_prog != prog)
1152 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001153 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001154 goto next;
1155 if (version > 2 && pmap->pml_map.pm_vers != version)
1156 goto next;
1157 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
1158 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001159 if (pmap->pml_map.pm_vers > MAX_NFSPROT
1160 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
1161 || (port && pmap->pml_map.pm_port != port)
1162 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001163 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001164 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001165 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
1166 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001167 pmap = pmap->pml_next;
1168 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001169 if (!pm_mnt->pm_vers)
1170 pm_mnt->pm_vers = MOUNTVERS;
1171 if (!pm_mnt->pm_port)
1172 pm_mnt->pm_port = MOUNTPORT;
1173 if (!pm_mnt->pm_prot)
1174 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001175}
1176
Denis Vlasenkof0000652007-09-04 18:30:26 +00001177#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001178static int daemonize(void)
1179{
Denis Vlasenko25098f72006-09-14 15:46:33 +00001180 int pid = fork();
1181 if (pid < 0) /* error */
1182 return -errno;
1183 if (pid > 0) /* parent */
1184 return 0;
1185 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001186 close(0);
1187 xopen(bb_dev_null, O_RDWR);
1188 xdup2(0, 1);
1189 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001190 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +00001191 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001192 logmode = LOGMODE_SYSLOG;
1193 return 1;
1194}
Denis Vlasenkof0000652007-09-04 18:30:26 +00001195#else
1196static inline int daemonize(void) { return -ENOSYS; }
1197#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001198
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001199/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001200static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001201{
1202 return 0;
1203}
1204
1205/* RPC strerror analogs are terminally idiotic:
1206 * *mandatory* prefix and \n at end.
1207 * This hopefully helps. Usage:
1208 * error_msg_rpc(clnt_*error*(" ")) */
1209static void error_msg_rpc(const char *msg)
1210{
Denis Vlasenko23514fe2006-09-19 14:07:52 +00001211 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001212 while (msg[0] == ' ' || msg[0] == ':') msg++;
1213 len = strlen(msg);
1214 while (len && msg[len-1] == '\n') len--;
1215 bb_error_msg("%.*s", len, msg);
1216}
1217
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001218/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001219static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001220{
1221 CLIENT *mclient;
1222 char *hostname;
1223 char *pathname;
1224 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001225 /* prior to 2.6.23, kernel took NFS options in a form of this struct
1226 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
1227 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001228 struct nfs_mount_data data;
1229 char *opt;
1230 struct hostent *hp;
1231 struct sockaddr_in server_addr;
1232 struct sockaddr_in mount_server_addr;
1233 int msock, fsock;
1234 union {
1235 struct fhstatus nfsv2;
1236 struct mountres3 nfsv3;
1237 } status;
1238 int daemonized;
1239 char *s;
1240 int port;
1241 int mountport;
1242 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001243#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001244 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001245#else
1246 enum { bg = 0 };
1247#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001248 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001249 int mountprog;
1250 int mountvers;
1251 int nfsprog;
1252 int nfsvers;
1253 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001254 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001255 smallint tcp;
1256 smallint soft;
1257 int intr;
1258 int posix;
1259 int nocto;
1260 int noac;
1261 int nordirplus;
1262 int nolock;
Dave Lovefae473c2011-11-10 15:19:25 +01001263 int noacl;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001264
1265 find_kernel_nfs_mount_version();
1266
1267 daemonized = 0;
1268 mounthost = NULL;
1269 retval = ETIMEDOUT;
1270 msock = fsock = -1;
1271 mclient = NULL;
1272
1273 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1274
1275 filteropts = xstrdup(filteropts); /* going to trash it later... */
1276
1277 hostname = xstrdup(mp->mnt_fsname);
1278 /* mount_main() guarantees that ':' is there */
1279 s = strchr(hostname, ':');
1280 pathname = s + 1;
1281 *s = '\0';
1282 /* Ignore all but first hostname in replicated mounts
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001283 * until they can be fully supported. (mack@sgi.com) */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001284 s = strchr(hostname, ',');
1285 if (s) {
1286 *s = '\0';
1287 bb_error_msg("warning: multiple hostnames not supported");
1288 }
1289
1290 server_addr.sin_family = AF_INET;
1291 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1292 hp = gethostbyname(hostname);
1293 if (hp == NULL) {
1294 bb_herror_msg("%s", hostname);
1295 goto fail;
1296 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001297 if (hp->h_length != (int)sizeof(struct in_addr)) {
1298 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001299 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001300 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001301 }
1302
1303 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1304
1305 /* add IP address to mtab options for use when unmounting */
1306
1307 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1308 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1309 } else {
1310 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1311 mp->mnt_opts[0] ? "," : "",
1312 inet_ntoa(server_addr.sin_addr));
1313 free(mp->mnt_opts);
1314 mp->mnt_opts = tmp;
1315 }
1316
1317 /* Set default options.
1318 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1319 * let the kernel decide.
1320 * timeo is filled in after we know whether it'll be TCP or UDP. */
1321 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001322 data.retrans = 3;
1323 data.acregmin = 3;
1324 data.acregmax = 60;
1325 data.acdirmin = 30;
1326 data.acdirmax = 60;
1327 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001328
Denis Vlasenko25098f72006-09-14 15:46:33 +00001329 soft = 0;
1330 intr = 0;
1331 posix = 0;
1332 nocto = 0;
1333 nolock = 0;
1334 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001335 nordirplus = 0;
Dave Lovefae473c2011-11-10 15:19:25 +01001336 noacl = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001337 retry = 10000; /* 10000 minutes ~ 1 week */
Bernhard Reutner-Fischer88206292011-05-04 19:03:30 +02001338 tcp = 1; /* nfs-utils uses tcp per default */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001339
1340 mountprog = MOUNTPROG;
1341 mountvers = 0;
1342 port = 0;
1343 mountport = 0;
1344 nfsprog = 100003;
1345 nfsvers = 0;
1346
1347 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001348 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001349 char *opteq = strchr(opt, '=');
1350 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001351 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001352 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001353 /* 0 */ "rsize\0"
1354 /* 1 */ "wsize\0"
1355 /* 2 */ "timeo\0"
1356 /* 3 */ "retrans\0"
1357 /* 4 */ "acregmin\0"
1358 /* 5 */ "acregmax\0"
1359 /* 6 */ "acdirmin\0"
1360 /* 7 */ "acdirmax\0"
1361 /* 8 */ "actimeo\0"
1362 /* 9 */ "retry\0"
1363 /* 10 */ "port\0"
1364 /* 11 */ "mountport\0"
1365 /* 12 */ "mounthost\0"
1366 /* 13 */ "mountprog\0"
1367 /* 14 */ "mountvers\0"
1368 /* 15 */ "nfsprog\0"
1369 /* 16 */ "nfsvers\0"
1370 /* 17 */ "vers\0"
1371 /* 18 */ "proto\0"
1372 /* 19 */ "namlen\0"
1373 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001374
1375 *opteq++ = '\0';
1376 idx = index_in_strings(options, opt);
1377 switch (idx) {
1378 case 12: // "mounthost"
1379 mounthost = xstrndup(opteq,
1380 strcspn(opteq, " \t\n\r,"));
1381 continue;
1382 case 18: // "proto"
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001383 if (is_prefixed_with(opteq, "tcp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001384 tcp = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001385 else if (is_prefixed_with(opteq, "udp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001386 tcp = 0;
1387 else
1388 bb_error_msg("warning: unrecognized proto= option");
1389 continue;
1390 case 20: // "addr" - ignore
1391 continue;
Peter Korsgaard301fe502011-02-21 17:52:13 +01001392 case -1: // unknown
1393 if (vfsflags & MS_REMOUNT)
1394 continue;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001395 }
1396
Denys Vlasenko77832482010-08-12 14:14:45 +02001397 val = xatoi_positive(opteq);
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001398 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001399 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001400 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001401 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001402 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001403 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001404 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001405 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001406 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001407 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001408 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001409 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001410 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001411 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001412 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001413 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001414 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001415 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001416 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001417 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001418 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001419 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001420 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001421 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001422 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001423 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001424 data.acregmin = val;
1425 data.acregmax = val;
1426 data.acdirmin = val;
1427 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001428 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001429 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001430 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001431 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001432 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001433 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001434 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001435 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001436 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001437 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001438 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001439 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001440 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001441 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001442 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001443 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001444 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001445 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001446 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001447 case 16: // "nfsvers"
1448 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001449 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001450 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001451 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001452 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001453 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001454 //else
1455 // bb_error_msg("warning: option namlen is not supported\n");
1456 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001457 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001458 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1459 goto fail;
1460 }
1461 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001462 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001463 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001464 "bg\0"
1465 "fg\0"
1466 "soft\0"
1467 "hard\0"
1468 "intr\0"
1469 "posix\0"
1470 "cto\0"
1471 "ac\0"
1472 "tcp\0"
1473 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001474 "lock\0"
Dave Lovefae473c2011-11-10 15:19:25 +01001475 "rdirplus\0"
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001476 "acl\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001477 int val = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001478 if (is_prefixed_with(opt, "no")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001479 val = 0;
1480 opt += 2;
1481 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001482 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001483 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001484#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001485 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001486#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001487 break;
1488 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001489#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001490 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001491#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001492 break;
1493 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001494 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001495 break;
1496 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001497 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001498 break;
1499 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001500 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001501 break;
1502 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001503 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001504 break;
1505 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001506 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001507 break;
1508 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001509 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001510 break;
1511 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001512 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001513 break;
1514 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001515 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001516 break;
1517 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001518 if (nfs_mount_version >= 3)
1519 nolock = !val;
1520 else
1521 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001522 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001523 case 11: //rdirplus
1524 nordirplus = !val;
1525 break;
Dave Lovefae473c2011-11-10 15:19:25 +01001526 case 12: // acl
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001527 noacl = !val;
Dave Lovefae473c2011-11-10 15:19:25 +01001528 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001529 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001530 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1531 goto fail;
1532 }
1533 }
1534 }
1535 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1536
1537 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1538 | (intr ? NFS_MOUNT_INTR : 0)
1539 | (posix ? NFS_MOUNT_POSIX : 0)
1540 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001541 | (noac ? NFS_MOUNT_NOAC : 0)
Dave Lovefae473c2011-11-10 15:19:25 +01001542 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0)
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001543 | (noacl ? NFS_MOUNT_NOACL : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001544 if (nfs_mount_version >= 2)
1545 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1546 if (nfs_mount_version >= 3)
1547 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1548 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1549 bb_error_msg("NFSv%d not supported", nfsvers);
1550 goto fail;
1551 }
1552 if (nfsvers && !mountvers)
1553 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1554 if (nfsvers && nfsvers < mountvers) {
1555 mountvers = nfsvers;
1556 }
1557
1558 /* Adjust options if none specified */
1559 if (!data.timeo)
1560 data.timeo = tcp ? 70 : 7;
1561
Denis Vlasenko25098f72006-09-14 15:46:33 +00001562 data.version = nfs_mount_version;
1563
1564 if (vfsflags & MS_REMOUNT)
1565 goto do_mount;
1566
1567 /*
1568 * If the previous mount operation on the same host was
1569 * backgrounded, and the "bg" for this mount is also set,
1570 * give up immediately, to avoid the initial timeout.
1571 */
1572 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001573 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001574 if (daemonized <= 0) { /* parent or error */
1575 retval = -daemonized;
1576 goto ret;
1577 }
1578 }
1579
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001580 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001581 /* See if the nfs host = mount host. */
1582 if (mounthost) {
1583 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1584 mount_server_addr.sin_family = AF_INET;
1585 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1586 } else {
1587 hp = gethostbyname(mounthost);
1588 if (hp == NULL) {
1589 bb_herror_msg("%s", mounthost);
1590 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001591 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001592 if (hp->h_length != (int)sizeof(struct in_addr)) {
1593 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001594 }
1595 mount_server_addr.sin_family = AF_INET;
Denys Vlasenko99069332010-02-27 19:38:19 +01001596 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001597 }
1598 }
1599
1600 /*
1601 * The following loop implements the mount retries. When the mount
1602 * times out, and the "bg" option is set, we background ourself
1603 * and continue trying.
1604 *
1605 * The case where the mount point is not present and the "bg"
1606 * option is set, is treated as a timeout. This is done to
1607 * support nested mounts.
1608 *
1609 * The "retry" count specified by the user is the number of
1610 * minutes to retry before giving up.
1611 */
1612 {
1613 struct timeval total_timeout;
1614 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001615 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001616 time_t t;
1617 time_t prevt;
1618 time_t timeout;
1619
1620 retry_timeout.tv_sec = 3;
1621 retry_timeout.tv_usec = 0;
1622 total_timeout.tv_sec = 20;
1623 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001624/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001625 timeout = time(NULL) + 60 * retry;
1626 prevt = 0;
1627 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001628 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001629 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001630 if (t - prevt < 30)
1631 sleep(30);
1632
Denis Vlasenkob9256052007-09-28 10:29:17 +00001633 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001634 mountprog,
1635 mountvers,
1636 proto,
1637 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001638 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001639
1640 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001641 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001642 msock = RPC_ANYSOCK;
1643
Denis Vlasenkob9256052007-09-28 10:29:17 +00001644 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001645 case IPPROTO_UDP:
1646 mclient = clntudp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001647 pm_mnt.pm_prog,
1648 pm_mnt.pm_vers,
1649 retry_timeout,
1650 &msock);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001651 if (mclient)
1652 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001653 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001654 msock = RPC_ANYSOCK;
1655 case IPPROTO_TCP:
1656 mclient = clnttcp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001657 pm_mnt.pm_prog,
1658 pm_mnt.pm_vers,
1659 &msock, 0, 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001660 break;
1661 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001662 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001663 }
1664 if (!mclient) {
1665 if (!daemonized && prevt == 0)
1666 error_msg_rpc(clnt_spcreateerror(" "));
1667 } else {
1668 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001669
1670 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001671 mclient->cl_auth = authunix_create_default();
1672
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001673 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001674 * that xdr_array allocates memory for us
1675 */
1676 memset(&status, 0, sizeof(status));
1677
Denis Vlasenkob9256052007-09-28 10:29:17 +00001678 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001679 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001680 (xdrproc_t) xdr_dirpath,
1681 (caddr_t) &pathname,
1682 (xdrproc_t) xdr_mountres3,
1683 (caddr_t) &status,
1684 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001685 else
1686 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001687 (xdrproc_t) xdr_dirpath,
1688 (caddr_t) &pathname,
1689 (xdrproc_t) xdr_fhstatus,
1690 (caddr_t) &status,
1691 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001692
1693 if (clnt_stat == RPC_SUCCESS)
1694 goto prepare_kernel_data; /* we're done */
1695 if (errno != ECONNREFUSED) {
1696 error_msg_rpc(clnt_sperror(mclient, " "));
1697 goto fail; /* don't retry */
1698 }
1699 /* Connection refused */
1700 if (!daemonized && prevt == 0) /* print just once */
1701 error_msg_rpc(clnt_sperror(mclient, " "));
1702 auth_destroy(mclient->cl_auth);
1703 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001704 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001705 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001706 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001707 }
1708
1709 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001710 if (!bg)
1711 goto fail;
1712 if (!daemonized) {
1713 daemonized = daemonize();
1714 if (daemonized <= 0) { /* parent or error */
1715 retval = -daemonized;
1716 goto ret;
1717 }
1718 }
1719 prevt = t;
1720 t = time(NULL);
1721 if (t >= timeout)
1722 /* TODO error message */
1723 goto fail;
1724
1725 goto retry;
1726 }
1727
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001728 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001729
1730 if (nfsvers == 2) {
1731 if (status.nfsv2.fhs_status != 0) {
1732 bb_error_msg("%s:%s failed, reason given by server: %s",
1733 hostname, pathname,
1734 nfs_strerror(status.nfsv2.fhs_status));
1735 goto fail;
1736 }
1737 memcpy(data.root.data,
1738 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1739 NFS_FHSIZE);
1740 data.root.size = NFS_FHSIZE;
1741 memcpy(data.old_root.data,
1742 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1743 NFS_FHSIZE);
1744 } else {
1745 fhandle3 *my_fhandle;
1746 if (status.nfsv3.fhs_status != 0) {
1747 bb_error_msg("%s:%s failed, reason given by server: %s",
1748 hostname, pathname,
1749 nfs_strerror(status.nfsv3.fhs_status));
1750 goto fail;
1751 }
1752 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1753 memset(data.old_root.data, 0, NFS_FHSIZE);
1754 memset(&data.root, 0, sizeof(data.root));
1755 data.root.size = my_fhandle->fhandle3_len;
1756 memcpy(data.root.data,
1757 (char *) my_fhandle->fhandle3_val,
1758 my_fhandle->fhandle3_len);
1759
1760 data.flags |= NFS_MOUNT_VER3;
1761 }
1762
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001763 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001764 if (tcp) {
1765 if (nfs_mount_version < 3) {
1766 bb_error_msg("NFS over TCP is not supported");
1767 goto fail;
1768 }
1769 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1770 } else
1771 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1772 if (fsock < 0) {
1773 bb_perror_msg("nfs socket");
1774 goto fail;
1775 }
1776 if (bindresvport(fsock, 0) < 0) {
1777 bb_perror_msg("nfs bindresvport");
1778 goto fail;
1779 }
1780 if (port == 0) {
1781 server_addr.sin_port = PMAPPORT;
1782 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1783 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1784 if (port == 0)
1785 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001786 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001787 server_addr.sin_port = htons(port);
1788
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001789 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001790 data.fd = fsock;
1791 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1792 strncpy(data.hostname, hostname, sizeof(data.hostname));
1793
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001794 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001795 auth_destroy(mclient->cl_auth);
1796 clnt_destroy(mclient);
1797 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001798 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001799
1800 if (bg) {
1801 /* We must wait until mount directory is available */
1802 struct stat statbuf;
1803 int delay = 1;
1804 while (stat(mp->mnt_dir, &statbuf) == -1) {
1805 if (!daemonized) {
1806 daemonized = daemonize();
1807 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001808/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001809 retval = -daemonized;
1810 goto ret;
1811 }
1812 }
1813 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1814 delay *= 2;
1815 if (delay > 30)
1816 delay = 30;
1817 }
1818 }
1819
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001820 /* Perform actual mount */
1821 do_mount:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001822 retval = mount_it_now(mp, vfsflags, (char*)&data);
1823 goto ret;
1824
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001825 /* Abort */
1826 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001827 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001828 if (mclient) {
1829 auth_destroy(mclient->cl_auth);
1830 clnt_destroy(mclient);
1831 }
1832 close(msock);
1833 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001834 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001835 close(fsock);
1836
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001837 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001838 free(hostname);
1839 free(mounthost);
1840 free(filteropts);
1841 return retval;
1842}
1843
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001844#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001845
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001846/* Linux 2.6.23+ supports nfs mounts with options passed as a string.
1847 * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS.
1848 * (However, note that then you lose any chances that NFS over IPv6 would work).
1849 */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001850static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001851{
1852 len_and_sockaddr *lsa;
1853 char *opts;
1854 char *end;
1855 char *dotted;
1856 int ret;
1857
1858# if ENABLE_FEATURE_IPV6
1859 end = strchr(mp->mnt_fsname, ']');
1860 if (end && end[1] == ':')
1861 end++;
1862 else
1863# endif
1864 /* mount_main() guarantees that ':' is there */
1865 end = strchr(mp->mnt_fsname, ':');
1866
1867 *end = '\0';
Denys Vlasenko39b23312011-11-10 17:01:39 +01001868 lsa = xhost2sockaddr(mp->mnt_fsname, /*port:*/ 0);
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001869 *end = ':';
1870 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1871 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1872 opts = xasprintf("%s%saddr=%s",
1873 filteropts ? filteropts : "",
1874 filteropts ? "," : "",
1875 dotted
1876 );
1877 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
1878 ret = mount_it_now(mp, vfsflags, opts);
1879 if (ENABLE_FEATURE_CLEAN_UP) free(opts);
1880
1881 return ret;
1882}
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001883
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001884#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001885
1886// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1887// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001888// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001889static int singlemount(struct mntent *mp, int ignore_busy)
1890{
Denys Vlasenkoab518ee2017-03-16 16:49:37 +01001891 int loopfd = -1;
Denis Vlasenkob4133682008-02-18 13:05:38 +00001892 int rc = -1;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001893 unsigned long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001894 char *loopFile = NULL, *filteropts = NULL;
1895 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001896 struct stat st;
1897
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001898 errno = 0;
1899
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001900 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1901
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001902 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001903 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1904 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001905
Denis Vlasenko2535f122007-09-15 13:28:30 +00001906 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001907 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1908 char *args[35];
1909 char *s;
1910 int n;
1911 // fsname: "cmd#arg1#arg2..."
1912 // WARNING: allows execution of arbitrary commands!
1913 // Try "mount 'sh#-c#sh' bogus_dir".
1914 // It is safe ONLY because non-root
1915 // cannot use two-argument mount command
1916 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1917 // "mount: can't find sh#-c#sh in /etc/fstab"
1918 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1919
1920 s = mp->mnt_fsname;
1921 n = 0;
1922 args[n++] = s;
1923 while (*s && n < 35 - 2) {
1924 if (*s++ == '#' && *s != '#') {
1925 s[-1] = '\0';
1926 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001927 }
1928 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001929 args[n++] = mp->mnt_dir;
1930 args[n] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +01001931 rc = spawn_and_wait(args);
Denis Vlasenko2535f122007-09-15 13:28:30 +00001932 goto report_error;
1933 }
1934
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001935 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001936 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001937 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1938 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1939 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001940 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001941 int len;
1942 char c;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001943 char *hostname, *share;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001944 len_and_sockaddr *lsa;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001945
1946 // Parse mp->mnt_fsname of the form "//hostname/share[/dir1/dir2]"
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001947
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001948 hostname = mp->mnt_fsname + 2;
1949 len = strcspn(hostname, "/\\");
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001950 share = hostname + len + 1;
1951 if (len == 0 // 3rd char is a [back]slash (IOW: empty hostname)
1952 || share[-1] == '\0' // no [back]slash after hostname
1953 || share[0] == '\0' // empty share name
Martin Santesson406ea152013-01-16 00:47:19 +01001954 ) {
Denis Vlasenko5c329932009-04-12 12:16:21 +00001955 goto report_error;
Martin Santesson406ea152013-01-16 00:47:19 +01001956 }
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001957 c = share[-1];
1958 share[-1] = '\0';
1959 len = strcspn(share, "/\\");
Martin Santesson406ea152013-01-16 00:47:19 +01001960
1961 // "unc=\\hostname\share" option is mandatory
1962 // after CIFS option parsing was rewritten in Linux 3.4.
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001963 // Must use backslashes.
1964 // If /dir1/dir2 is present, also add "prefixpath=dir1/dir2"
Martin Santesson406ea152013-01-16 00:47:19 +01001965 {
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001966 char *unc = xasprintf(
1967 share[len] != '\0' /* "/dir1/dir2" exists? */
1968 ? "unc=\\\\%s\\%.*s,prefixpath=%s"
1969 : "unc=\\\\%s\\%.*s",
1970 hostname,
1971 len, share,
1972 share + len + 1 /* "dir1/dir2" */
1973 );
Denys Vlasenko9b7ebfe2013-01-22 11:00:45 +01001974 parse_mount_options(unc, &filteropts);
1975 if (ENABLE_FEATURE_CLEAN_UP) free(unc);
Martin Santesson406ea152013-01-16 00:47:19 +01001976 }
1977
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001978 lsa = host2sockaddr(hostname, 0);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001979 share[-1] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001980 if (!lsa)
1981 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001982
Denys Vlasenkob09ab442016-09-27 21:02:35 +02001983 // If there is no "ip=..." option yet
1984 if (!is_prefixed_with(filteropts, ",ip="+1)
1985 && !strstr(filteropts, ",ip=")
1986 ) {
1987 char *dotted, *ip;
1988 // Insert "ip=..." option into options
1989 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1990 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1991 ip = xasprintf("ip=%s", dotted);
1992 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denys Vlasenko5093c8c2016-09-26 20:36:30 +02001993// Note: IPv6 scoped addresses ("host%iface", see RFC 4007) should be
Denys Vlasenko3c18e302016-09-26 19:53:04 +02001994// handled by libc in getnameinfo() (inside xmalloc_sockaddr2dotted_noport()).
1995// Currently, glibc does not support that (has no NI_NUMERICSCOPE),
1996// musl apparently does. This results in "ip=numericIPv6%iface_name"
1997// (instead of _numeric_ iface_id) with glibc.
Denys Vlasenko5093c8c2016-09-26 20:36:30 +02001998// This probably should be fixed in glibc, not here.
Denys Vlasenkob09ab442016-09-27 21:02:35 +02001999// The workaround is to manually specify correct "ip=ADDR%n" option.
2000 parse_mount_options(ip, &filteropts);
2001 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
2002 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002003
Denis Vlasenko06c0a712007-01-29 22:51:44 +00002004 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002005 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002006
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002007 goto report_error;
2008 }
2009
2010 // Might this be an NFS filesystem?
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01002011 if ((!mp->mnt_type || is_prefixed_with(mp->mnt_type, "nfs"))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002012 && strchr(mp->mnt_fsname, ':') != NULL
2013 ) {
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01002014 if (!mp->mnt_type)
2015 mp->mnt_type = (char*)"nfs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002016 rc = nfsmount(mp, vfsflags, filteropts);
2017 goto report_error;
2018 }
2019
2020 // Look at the file. (Not found isn't a failure for remount, or for
2021 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00002022 // (We use stat, not lstat, in order to allow
2023 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00002024 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002025 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
2026 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002027 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002028 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
2029 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002030 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenkoab518ee2017-03-16 16:49:37 +01002031
2032 // mount always creates AUTOCLEARed loopdevs, so that umounting
2033 // drops them without any code in the userspace.
2034 // This happens since circa linux-2.6.25:
2035 // commit 96c5865559cee0f9cbc5173f3c949f6ce3525581
2036 // Date: Wed Feb 6 01:36:27 2008 -0800
2037 // Subject: Allow auto-destruction of loop devices
2038 loopfd = set_loop(&mp->mnt_fsname,
2039 loopFile,
2040 0,
2041 ((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0)
2042 | BB_LO_FLAGS_AUTOCLEAR
2043 );
2044 if (loopfd < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002045 if (errno == EPERM || errno == EACCES)
2046 bb_error_msg(bb_msg_perm_denied_are_you_root);
2047 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01002048 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00002049 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002050 }
2051
2052 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002053 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
2054 vfsflags |= MS_BIND;
2055 }
2056
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002057 // If we know the fstype (or don't need to), jump straight
2058 // to the actual mount.
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002059 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002060 char *next;
2061 for (;;) {
2062 next = mp->mnt_type ? strchr(mp->mnt_type, ',') : NULL;
2063 if (next)
2064 *next = '\0';
2065 rc = mount_it_now(mp, vfsflags, filteropts);
2066 if (rc == 0 || !next)
2067 break;
2068 mp->mnt_type = next + 1;
2069 }
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002070 } else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002071 // Loop through filesystem types until mount succeeds
2072 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002073
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01002074 // Initialize list of block backed filesystems.
2075 // This has to be done here so that during "mount -a",
2076 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002077 if (!fslist) {
2078 fslist = get_block_backed_filesystems();
2079 if (ENABLE_FEATURE_CLEAN_UP && fslist)
2080 atexit(delete_block_backed_filesystems);
2081 }
2082
2083 for (fl = fslist; fl; fl = fl->link) {
2084 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00002085 rc = mount_it_now(mp, vfsflags, filteropts);
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002086 if (rc == 0)
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02002087 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002088 }
2089 }
2090
2091 // If mount failed, clean up loop file (if any).
Denys Vlasenkoab518ee2017-03-16 16:49:37 +01002092 // (Newer kernels which support LO_FLAGS_AUTOCLEAR should not need this,
2093 // merely "close(loopfd)" should do it?)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002094 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
2095 del_loop(mp->mnt_fsname);
2096 if (ENABLE_FEATURE_CLEAN_UP) {
2097 free(loopFile);
Denys Vlasenkoecf25cb2016-06-20 11:04:04 +02002098 /* No, "rc != 0" needs it: free(mp->mnt_fsname); */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002099 }
2100 }
2101
Denis Vlasenko5870ad92007-02-04 02:39:55 +00002102 report_error:
2103 if (ENABLE_FEATURE_CLEAN_UP)
2104 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002105
Denys Vlasenkoab518ee2017-03-16 16:49:37 +01002106 if (loopfd >= 0)
2107 close(loopfd);
2108
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00002109 if (errno == EBUSY && ignore_busy)
2110 return 0;
Denys Vlasenko911d2652015-12-30 20:11:34 +01002111 if (errno == ENOENT && (vfsflags & MOUNT_NOFAIL))
2112 return 0;
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002113 if (rc != 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002114 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002115 return rc;
2116}
2117
Michael Abbott6b5accb2009-12-04 03:33:07 +01002118// -O support
2119// -O interprets a list of filter options which select whether a mount
2120// point will be mounted: only mounts with options matching *all* filtering
2121// options will be selected.
2122// By default each -O filter option must be present in the list of mount
2123// options, but if it is prefixed by "no" then it must be absent.
2124// For example,
2125// -O a,nob,c matches -o a,c but fails to match -o a,b,c
2126// (and also fails to match -o a because -o c is absent).
2127//
2128// It is different from -t in that each option is matched exactly; a leading
2129// "no" at the beginning of one option does not negate the rest.
2130static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002131{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002132 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01002133 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002134
Michael Abbott6b5accb2009-12-04 03:33:07 +01002135 while (*O_opt) {
2136 const char *fs_opt = fs_opt_in;
2137 int O_len;
2138 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002139
Michael Abbott6b5accb2009-12-04 03:33:07 +01002140 // If option begins with "no" then treat as an inverted match:
2141 // matching is a failure
2142 match = 0;
2143 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
2144 match = 1;
2145 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002146 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002147 // Isolate the current O option
2148 O_len = strchrnul(O_opt, ',') - O_opt;
2149 // Check for a match against existing options
2150 while (1) {
2151 if (strncmp(fs_opt, O_opt, O_len) == 0
2152 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
2153 ) {
2154 if (match)
2155 return 0; // "no" prefix, but option found
2156 match = 1; // current O option found, go check next one
2157 break;
2158 }
2159 fs_opt = strchr(fs_opt, ',');
2160 if (!fs_opt)
2161 break;
2162 fs_opt++;
2163 }
2164 if (match == 0)
2165 return 0; // match wanted but not found
2166 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002167 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01002168 // Step to the next O option
2169 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002170 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002171 // If we get here then everything matched
2172 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002173}
2174
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002175// Parse options, if necessary parse fstab/mtab, and call singlemount for
2176// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002177int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002178int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002179{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002180 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002181 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002182 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002183 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002184 llist_t *lst_o = NULL;
Isaac Dunham7b434a62015-03-11 16:07:24 +01002185 const char *fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002186 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002187 int i, j;
2188 int rc = EXIT_SUCCESS;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002189 unsigned long cmdopt_flags;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002190 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002191 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002192 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002193
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002194 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00002195
Denys Vlasenko16714242011-09-21 01:59:15 +02002196 INIT_G();
2197
Denis Vlasenkof732e962008-02-18 12:07:49 +00002198 // Parse long options, like --bind and --move. Note that -o option
2199 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002200 for (i = j = 1; argv[i]; i++) {
2201 if (argv[i][0] == '-' && argv[i][1] == '-')
2202 append_mount_options(&cmdopts, argv[i] + 2);
2203 else
2204 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002205 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002206 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002207
2208 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002209 // Max 2 params; -o is a list, -v is a counter
Denys Vlasenko237bedd2016-07-06 21:58:02 +02002210 opt_complementary = "?2" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002211 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Isaac Dunham7b434a62015-03-11 16:07:24 +01002212 IF_FEATURE_MOUNT_OTHERTAB(, &fstabname)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002213 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002214 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00002215 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
2216 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00002217 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002218
2219 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002220 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00002221 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002222 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
2223
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002224 if (!mountTable)
2225 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002226
Denis Vlasenko2535f122007-09-15 13:28:30 +00002227 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002228 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002229 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002230 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00002231 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002232 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002233
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002234 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002235 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
2236 mtpair->mnt_dir, mtpair->mnt_type,
2237 mtpair->mnt_opts);
2238 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002239 if (ENABLE_FEATURE_CLEAN_UP)
2240 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002241 return EXIT_SUCCESS;
2242 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002243 storage_path = NULL;
2244 } else {
2245 // When we have two arguments, the second is the directory and we can
2246 // skip looking at fstab entirely. We can always abspath() the directory
2247 // argument when we get it.
2248 if (argv[1]) {
2249 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002250 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002251 mtpair->mnt_fsname = argv[0];
2252 mtpair->mnt_dir = argv[1];
2253 mtpair->mnt_type = fstype;
2254 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002255 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002256 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002257 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00002258 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002259 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002260 }
2261
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002262 // Past this point, we are handling either "mount -a [opts]"
2263 // or "mount [opts] single_param"
2264
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002265 cmdopt_flags = parse_mount_options(cmdopts, NULL);
2266 if (nonroot && (cmdopt_flags & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002267 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00002268
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002269 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002270 if (ENABLE_FEATURE_MOUNT_FLAGS
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002271 && (cmdopt_flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002272 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002273 // verbose_mount(source, target, type, flags, data)
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002274 rc = verbose_mount("", argv[0], "", cmdopt_flags, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002275 if (rc)
2276 bb_simple_perror_msg_and_die(argv[0]);
2277 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002278 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002279
Isaac Dunham7b434a62015-03-11 16:07:24 +01002280 // A malicious user could overmount /usr without this.
2281 if (ENABLE_FEATURE_MOUNT_OTHERTAB && nonroot)
2282 fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002283 // Open either fstab or mtab
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002284 if (cmdopt_flags & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002285 // WARNING. I am not sure this matches util-linux's
2286 // behavior. It's possible util-linux does not
2287 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002288 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002289 }
2290 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00002291 if (!fstab)
Denys Vlasenko651a2692010-03-23 16:25:17 +01002292 bb_perror_msg_and_die("can't read '%s'", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002293
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002294 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00002295 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002296 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002297 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002298
2299 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00002300 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002301 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002302 GETMNTENT_BUFSIZE/2)
2303 ) { // End of fstab/mtab is reached
2304 mtcur = mtother; // the thing we found last time
2305 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002306 }
2307
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002308 // If we're trying to mount something specific and this isn't it,
2309 // skip it. Note we must match the exact text in fstab (ala
2310 // "proc") or a full path from root
2311 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002312
2313 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002314 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
2315 && strcmp(storage_path, mtcur->mnt_fsname) != 0
2316 && strcmp(argv[0], mtcur->mnt_dir) != 0
2317 && strcmp(storage_path, mtcur->mnt_dir) != 0
2318 ) {
2319 continue; // no
2320 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002321
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002322 // Remember this entry. Something later may have
2323 // overmounted it, and we want the _last_ match.
2324 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002325
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002326 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002327 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002328 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002329 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002330 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002331 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002332 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002333
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002334 // Does type match? (NULL matches always)
Denys Vlasenko35b54a32017-01-30 00:45:05 +01002335 if (!fstype_matches(mtcur->mnt_type, fstype))
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002336 continue;
2337
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002338 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002339 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
2340 // swap is bogus "fstype", parse_mount_options can't check fstypes
2341 || strcasecmp(mtcur->mnt_type, "swap") == 0
2342 ) {
2343 continue;
2344 }
2345
2346 // Does (at least one) option match?
2347 // (NULL matches always)
2348 if (!match_opt(mtcur->mnt_opts, O_optmatch))
2349 continue;
2350
2351 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002352
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002353 // NFS mounts want this to be xrealloc-able
2354 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002355
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002356 // If nothing is mounted on this directory...
2357 // (otherwise repeated "mount -a" mounts everything again)
2358 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2359 // We do not check fsname match of found mount point -
2360 // "/" may have fsname of "/dev/root" while fstab
2361 // says "/dev/something_else".
2362 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01002363 if (verbose) {
2364 bb_error_msg("according to %s, "
2365 "%s is already mounted on %s",
2366 bb_path_mtab_file,
2367 mp->mnt_fsname, mp->mnt_dir);
2368 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002369 } else {
2370 // ...mount this thing
2371 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2372 // Count number of failed mounts
2373 rc++;
2374 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002375 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002376 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002377 }
2378 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002379
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002380 // End of fstab/mtab is reached.
2381 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002382 if (argv[0]) { // yes
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002383 unsigned long l;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002384
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002385 // If we didn't find anything, complain
2386 if (!mtcur->mnt_fsname)
2387 bb_error_msg_and_die("can't find %s in %s",
2388 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002389
2390 // What happens when we try to "mount swap_partition"?
2391 // (fstab containts "swap_partition swap swap defaults 0 0")
2392 // util-linux-ng 2.13.1 does this:
2393 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2394 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2395 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2396 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2397 // exit_group(32) = ?
2398#if 0
2399 // In case we want to simply skip swap partitions:
2400 l = parse_mount_options(mtcur->mnt_opts, NULL);
2401 if ((l & MOUNT_SWAP)
2402 // swap is bogus "fstype", parse_mount_options can't check fstypes
2403 || strcasecmp(mtcur->mnt_type, "swap") == 0
2404 ) {
2405 goto ret;
2406 }
2407#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002408 if (nonroot) {
2409 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002410 l = parse_mount_options(mtcur->mnt_opts, NULL);
2411 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002412 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002413 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002414
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002415 //util-linux-2.12 does not do this check.
2416 //// If nothing is mounted on this directory...
2417 //// (otherwise repeated "mount FOO" mounts FOO again)
2418 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2419 //if (mp) {
2420 // bb_error_msg("according to %s, "
2421 // "%s is already mounted on %s",
2422 // bb_path_mtab_file,
2423 // mp->mnt_fsname, mp->mnt_dir);
2424 //} else {
2425 // ...mount the last thing we found
2426 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2427 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2428 resolve_mount_spec(&mtpair->mnt_fsname);
2429 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2430 if (ENABLE_FEATURE_CLEAN_UP)
2431 free(mtcur->mnt_opts);
2432 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002433 }
2434
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002435 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002436 if (ENABLE_FEATURE_CLEAN_UP)
2437 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002438 if (ENABLE_FEATURE_CLEAN_UP) {
2439 free(storage_path);
2440 free(cmdopts);
2441 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002442
2443//TODO: exitcode should be ORed mask of (from "man mount"):
2444// 0 success
2445// 1 incorrect invocation or permissions
2446// 2 system error (out of memory, cannot fork, no more loop devices)
2447// 4 internal mount bug or missing nfs support in mount
2448// 8 user interrupt
2449//16 problems writing or locking /etc/mtab
2450//32 mount failure
2451//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002452 return rc;
2453}