blob: 84c85c0578ea1bb10ec755b14aa529f6a670784a [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 Vlasenkob097a842018-12-28 03:20:17 +010021//config: bool "mount (23 kb)"
Isaac Dunham7b434a62015-03-11 16:07:24 +010022//config: default y
23//config: select PLATFORM_LINUX
24//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020025//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
Denys Vlasenko68b653b2017-07-27 10:53:09 +020029//config: NFS filesystems.
Isaac Dunham7b434a62015-03-11 16:07:24 +010030//config:
31//config:config FEATURE_MOUNT_FAKE
Denys Vlasenko5b3cbe32017-07-27 14:45:25 +020032//config: bool "Support -f (fake mount)"
Isaac Dunham7b434a62015-03-11 16:07:24 +010033//config: default y
34//config: depends on MOUNT
35//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020036//config: Enable support for faking a file system mount.
Isaac Dunham7b434a62015-03-11 16:07:24 +010037//config:
38//config:config FEATURE_MOUNT_VERBOSE
Denys Vlasenko5b3cbe32017-07-27 14:45:25 +020039//config: bool "Support -v (verbose)"
Isaac Dunham7b434a62015-03-11 16:07:24 +010040//config: default y
41//config: depends on MOUNT
42//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020043//config: Enable multi-level -v[vv...] verbose messages. Useful if you
44//config: debug mount problems and want to see what is exactly passed
45//config: to the kernel.
Isaac Dunham7b434a62015-03-11 16:07:24 +010046//config:
47//config:config FEATURE_MOUNT_HELPERS
48//config: bool "Support mount helpers"
49//config: default n
50//config: depends on MOUNT
51//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020052//config: Enable mounting of virtual file systems via external helpers.
53//config: E.g. "mount obexfs#-b00.11.22.33.44.55 /mnt" will in effect call
54//config: "obexfs -b00.11.22.33.44.55 /mnt"
55//config: Also "mount -t sometype [-o opts] fs /mnt" will try
56//config: "sometype [-o opts] fs /mnt" if simple mount syscall fails.
57//config: The idea is to use such virtual filesystems in /etc/fstab.
Isaac Dunham7b434a62015-03-11 16:07:24 +010058//config:
59//config:config FEATURE_MOUNT_LABEL
60//config: bool "Support specifying devices by label or UUID"
61//config: default y
62//config: depends on MOUNT
63//config: select VOLUMEID
64//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020065//config: This allows for specifying a device by label or uuid, rather than by
66//config: name. This feature utilizes the same functionality as blkid/findfs.
Isaac Dunham7b434a62015-03-11 16:07:24 +010067//config:
68//config:config FEATURE_MOUNT_NFS
69//config: bool "Support mounting NFS file systems on Linux < 2.6.23"
70//config: default n
71//config: depends on MOUNT
Isaac Dunham7b434a62015-03-11 16:07:24 +010072//config: select FEATURE_SYSLOG
73//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020074//config: Enable mounting of NFS file systems on Linux kernels prior
75//config: to version 2.6.23. Note that in this case mounting of NFS
76//config: over IPv6 will not be possible.
Isaac Dunham7b434a62015-03-11 16:07:24 +010077//config:
Denys Vlasenko72089cf2017-07-21 09:50:55 +020078//config: Note that this option links in RPC support from libc,
79//config: which is rather large (~10 kbytes on uclibc).
Isaac Dunham7b434a62015-03-11 16:07:24 +010080//config:
81//config:config FEATURE_MOUNT_CIFS
82//config: bool "Support mounting CIFS/SMB file systems"
83//config: default y
84//config: depends on MOUNT
85//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020086//config: Enable support for samba mounts.
Isaac Dunham7b434a62015-03-11 16:07:24 +010087//config:
88//config:config FEATURE_MOUNT_FLAGS
89//config: depends on MOUNT
Denys Vlasenkof5604222017-01-10 14:58:54 +010090//config: bool "Support lots of -o flags"
Isaac Dunham7b434a62015-03-11 16:07:24 +010091//config: default y
92//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020093//config: Without this, mount only supports ro/rw/remount. With this, it
94//config: supports nosuid, suid, dev, nodev, exec, noexec, sync, async, atime,
95//config: noatime, diratime, nodiratime, loud, bind, move, shared, slave,
96//config: private, unbindable, rshared, rslave, rprivate, and runbindable.
Isaac Dunham7b434a62015-03-11 16:07:24 +010097//config:
98//config:config FEATURE_MOUNT_FSTAB
99//config: depends on MOUNT
Denys Vlasenko5b3cbe32017-07-27 14:45:25 +0200100//config: bool "Support /etc/fstab and -a (mount all)"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100101//config: default y
102//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200103//config: Support mount all and looking for files in /etc/fstab.
Isaac Dunham7b434a62015-03-11 16:07:24 +0100104//config:
105//config:config FEATURE_MOUNT_OTHERTAB
106//config: depends on FEATURE_MOUNT_FSTAB
107//config: bool "Support -T <alt_fstab>"
108//config: default y
109//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +0200110//config: Support mount -T (specifying an alternate fstab)
Isaac Dunham7b434a62015-03-11 16:07:24 +0100111
Denys Vlasenkodd898c92016-11-23 11:46:32 +0100112/* On full-blown systems, requires suid for user mounts.
113 * But it's not unthinkable to have it available in non-suid flavor on some systems,
114 * for viewing mount table.
115 * Therefore we use BB_SUID_MAYBE instead of BB_SUID_REQUIRE: */
116//applet:IF_MOUNT(APPLET(mount, BB_DIR_BIN, IF_DESKTOP(BB_SUID_MAYBE) IF_NOT_DESKTOP(BB_SUID_DROP)))
117
118//kbuild:lib-$(CONFIG_MOUNT) += mount.o
119
Pere Orga5bc8c002011-04-11 03:29:49 +0200120//usage:#define mount_trivial_usage
Isaac Dunham7b434a62015-03-11 16:07:24 +0100121//usage: "[OPTIONS] [-o OPT] DEVICE NODE"
Pere Orga5bc8c002011-04-11 03:29:49 +0200122//usage:#define mount_full_usage "\n\n"
123//usage: "Mount a filesystem. Filesystem autodetection requires /proc.\n"
Pere Orga5bc8c002011-04-11 03:29:49 +0200124//usage: "\n -a Mount all filesystems in fstab"
125//usage: IF_FEATURE_MOUNT_FAKE(
126//usage: IF_FEATURE_MTAB_SUPPORT(
127//usage: "\n -f Update /etc/mtab, but don't mount"
128//usage: )
129//usage: IF_NOT_FEATURE_MTAB_SUPPORT(
130//usage: "\n -f Dry run"
131//usage: )
132//usage: )
133//usage: IF_FEATURE_MOUNT_HELPERS(
134//usage: "\n -i Don't run mount helper"
135//usage: )
136//usage: IF_FEATURE_MTAB_SUPPORT(
137//usage: "\n -n Don't update /etc/mtab"
138//usage: )
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100139//usage: IF_FEATURE_MOUNT_VERBOSE(
140//usage: "\n -v Verbose"
141//usage: )
142////usage: "\n -s Sloppy (ignored)"
Pere Orga5bc8c002011-04-11 03:29:49 +0200143//usage: "\n -r Read-only mount"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100144////usage: "\n -w Read-write mount (default)"
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +0100145//usage: "\n -t FSTYPE[,...] Filesystem type(s)"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100146//usage: IF_FEATURE_MOUNT_OTHERTAB(
147//usage: "\n -T FILE Read FILE instead of /etc/fstab"
148//usage: )
Pere Orga5bc8c002011-04-11 03:29:49 +0200149//usage: "\n -O OPT Mount only filesystems with option OPT (-a only)"
150//usage: "\n-o OPT:"
151//usage: IF_FEATURE_MOUNT_LOOP(
152//usage: "\n loop Ignored (loop devices are autodetected)"
153//usage: )
154//usage: IF_FEATURE_MOUNT_FLAGS(
155//usage: "\n [a]sync Writes are [a]synchronous"
156//usage: "\n [no]atime Disable/enable updates to inode access times"
157//usage: "\n [no]diratime Disable/enable atime updates to directories"
158//usage: "\n [no]relatime Disable/enable atime updates relative to modification time"
159//usage: "\n [no]dev (Dis)allow use of special device files"
160//usage: "\n [no]exec (Dis)allow use of executable files"
161//usage: "\n [no]suid (Dis)allow set-user-id-root programs"
162//usage: "\n [r]shared Convert [recursively] to a shared subtree"
163//usage: "\n [r]slave Convert [recursively] to a slave subtree"
164//usage: "\n [r]private Convert [recursively] to a private subtree"
165//usage: "\n [un]bindable Make mount point [un]able to be bind mounted"
166//usage: "\n [r]bind Bind a file or directory [recursively] to another location"
167//usage: "\n move Relocate an existing mount point"
168//usage: )
169//usage: "\n remount Remount a mounted filesystem, changing flags"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100170//usage: "\n ro Same as -r"
Pere Orga5bc8c002011-04-11 03:29:49 +0200171//usage: "\n"
172//usage: "\nThere are filesystem-specific -o flags."
173//usage:
174//usage:#define mount_example_usage
175//usage: "$ mount\n"
176//usage: "/dev/hda3 on / type minix (rw)\n"
177//usage: "proc on /proc type proc (rw)\n"
178//usage: "devpts on /dev/pts type devpts (rw)\n"
179//usage: "$ mount /dev/fd0 /mnt -t msdos -o ro\n"
180//usage: "$ mount /tmp/diskimage /opt -t ext2 -o loop\n"
181//usage: "$ mount cd_image.iso mydir\n"
182//usage:#define mount_notes_usage
183//usage: "Returns 0 for success, number of failed mounts for -a, or errno for one mount."
184
Eric Andersencc8ed391999-10-05 16:24:54 +0000185#include <mntent.h>
Bernhard Reutner-Fischerf4701962008-01-27 12:50:12 +0000186#include <syslog.h>
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200187#include <sys/mount.h>
Denys Vlasenko102ff762009-11-21 17:14:08 +0100188// Grab more as needed from util-linux's mount/mount_constants.h
189#ifndef MS_DIRSYNC
190# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
191#endif
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200192#ifndef MS_UNION
193# define MS_UNION (1 << 8)
194#endif
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200195#ifndef MS_BIND
196# define MS_BIND (1 << 12)
197#endif
198#ifndef MS_MOVE
199# define MS_MOVE (1 << 13)
200#endif
201#ifndef MS_RECURSIVE
202# define MS_RECURSIVE (1 << 14)
203#endif
204#ifndef MS_SILENT
205# define MS_SILENT (1 << 15)
206#endif
Denys Vlasenko102ff762009-11-21 17:14:08 +0100207// The shared subtree stuff, which went in around 2.6.15
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200208#ifndef MS_UNBINDABLE
209# define MS_UNBINDABLE (1 << 17)
210#endif
211#ifndef MS_PRIVATE
212# define MS_PRIVATE (1 << 18)
213#endif
214#ifndef MS_SLAVE
215# define MS_SLAVE (1 << 19)
216#endif
217#ifndef MS_SHARED
218# define MS_SHARED (1 << 20)
219#endif
220#ifndef MS_RELATIME
221# define MS_RELATIME (1 << 21)
222#endif
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200223#ifndef MS_STRICTATIME
224# define MS_STRICTATIME (1 << 24)
225#endif
226
227/* Any ~MS_FOO value has this bit set: */
228#define BB_MS_INVERTED_VALUE (1u << 31)
Eric Andersenbd22ed82000-07-08 18:55:24 +0000229
Denys Vlasenko102ff762009-11-21 17:14:08 +0100230#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200231#include "common_bufsiz.h"
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000232#if ENABLE_FEATURE_MOUNT_LABEL
Natanael Copa9aff2992009-09-20 04:28:22 +0200233# include "volume_id.h"
234#else
235# define resolve_mount_spec(fsname) ((void)0)
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000236#endif
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000237
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000238// Needed for nfs support only
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000239#include <sys/utsname.h>
240#undef TRUE
241#undef FALSE
Denys Vlasenkocc428142009-12-16 02:06:56 +0100242#if ENABLE_FEATURE_MOUNT_NFS
243/* This is just a warning of a common mistake. Possibly this should be a
244 * uclibc faq entry rather than in busybox... */
245# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
Denys Vlasenkoce552842017-07-10 14:43:22 +0200246# warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support"
Denys Vlasenko4892f3a2018-02-13 18:20:28 +0100247 /* not #error, since user may be using e.g. libtirpc instead.
248 * This might work:
249 * CONFIG_EXTRA_CFLAGS="-I/usr/include/tirpc"
250 * CONFIG_EXTRA_LDLIBS="tirpc"
251 */
Denys Vlasenkocc428142009-12-16 02:06:56 +0100252# endif
253# include <rpc/rpc.h>
254# include <rpc/pmap_prot.h>
255# include <rpc/pmap_clnt.h>
256#endif
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000257
258
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000259#if defined(__dietlibc__)
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000260// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
261// dietlibc-0.30 does not have implementation of getmntent_r()
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000262static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000263 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000264{
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000265 struct mntent* ment = getmntent(stream);
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000266 return memcpy(result, ment, sizeof(*ment));
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000267}
268#endif
269
270
Rob Landleydc0955b2006-03-14 18:16:25 +0000271// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000272enum {
Denys Vlasenko911d2652015-12-30 20:11:34 +0100273 MOUNT_USERS = (1 << 27) * ENABLE_DESKTOP,
274 MOUNT_NOFAIL = (1 << 28) * ENABLE_DESKTOP,
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000275 MOUNT_NOAUTO = (1 << 29),
276 MOUNT_SWAP = (1 << 30),
Denys Vlasenko911d2652015-12-30 20:11:34 +0100277 MOUNT_FAKEFLAGS = MOUNT_USERS | MOUNT_NOFAIL | MOUNT_NOAUTO | MOUNT_SWAP
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000278};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000279
280
Denys Vlasenko237bedd2016-07-06 21:58:02 +0200281#define OPTION_STR "o:*t:rwanfvsiO:" IF_FEATURE_MOUNT_OTHERTAB("T:")
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000282enum {
283 OPT_o = (1 << 0),
284 OPT_t = (1 << 1),
285 OPT_r = (1 << 2),
286 OPT_w = (1 << 3),
287 OPT_a = (1 << 4),
288 OPT_n = (1 << 5),
289 OPT_f = (1 << 6),
290 OPT_v = (1 << 7),
291 OPT_s = (1 << 8),
292 OPT_i = (1 << 9),
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000293 OPT_O = (1 << 10),
Isaac Dunham7b434a62015-03-11 16:07:24 +0100294 OPT_T = (1 << 11),
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000295};
296
297#if ENABLE_FEATURE_MTAB_SUPPORT
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200298#define USE_MTAB (!(option_mask32 & OPT_n))
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000299#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200300#define USE_MTAB 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000301#endif
302
303#if ENABLE_FEATURE_MOUNT_FAKE
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200304#define FAKE_IT (option_mask32 & OPT_f)
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000305#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200306#define FAKE_IT 0
307#endif
308
309#if ENABLE_FEATURE_MOUNT_HELPERS
310#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
311#else
312#define HELPERS_ALLOWED 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000313#endif
314
315
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000316// TODO: more "user" flag compatibility.
317// "user" option (from mount manpage):
318// Only the user that mounted a filesystem can unmount it again.
319// If any user should be able to unmount, then use users instead of user
320// in the fstab line. The owner option is similar to the user option,
321// with the restriction that the user must be the owner of the special file.
322// This may be useful e.g. for /dev/fd if a login script makes
323// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000324
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000325// Standard mount options (from -o options or --options),
326// with corresponding flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000327static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000328 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000329
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000330 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000331 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000332 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000333
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000334 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000335 /* "defaults" */ 0,
336 /* "quiet" 0 - do not filter out, vfat wants to see it */
337 /* "noauto" */ MOUNT_NOAUTO,
338 /* "sw" */ MOUNT_SWAP,
339 /* "swap" */ MOUNT_SWAP,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000340 IF_DESKTOP(/* "user" */ MOUNT_USERS,)
341 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
Denys Vlasenko911d2652015-12-30 20:11:34 +0100342 IF_DESKTOP(/* "nofail" */ MOUNT_NOFAIL,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000343 /* "_netdev" */ 0,
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100344 IF_DESKTOP(/* "comment=" */ 0,) /* systemd uses this in fstab */
Rob Landleye3781b72006-08-08 01:39:49 +0000345 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000346
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000347 IF_FEATURE_MOUNT_FLAGS(
Rob Landleye3781b72006-08-08 01:39:49 +0000348 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000349 /* "nosuid" */ MS_NOSUID,
350 /* "suid" */ ~MS_NOSUID,
351 /* "dev" */ ~MS_NODEV,
352 /* "nodev" */ MS_NODEV,
353 /* "exec" */ ~MS_NOEXEC,
354 /* "noexec" */ MS_NOEXEC,
355 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000356 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000357 /* "async" */ ~MS_SYNCHRONOUS,
358 /* "atime" */ ~MS_NOATIME,
359 /* "noatime" */ MS_NOATIME,
360 /* "diratime" */ ~MS_NODIRATIME,
361 /* "nodiratime" */ MS_NODIRATIME,
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000362 /* "mand" */ MS_MANDLOCK,
363 /* "nomand" */ ~MS_MANDLOCK,
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000364 /* "relatime" */ MS_RELATIME,
365 /* "norelatime" */ ~MS_RELATIME,
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200366 /* "strictatime" */ MS_STRICTATIME,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000367 /* "loud" */ ~MS_SILENT,
Roman Borisov19311bf2011-03-24 15:08:43 +0300368 /* "rbind" */ MS_BIND|MS_RECURSIVE,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000369
Rob Landleye3781b72006-08-08 01:39:49 +0000370 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200371 /* "union" */ MS_UNION,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000372 /* "bind" */ MS_BIND,
373 /* "move" */ MS_MOVE,
374 /* "shared" */ MS_SHARED,
375 /* "slave" */ MS_SLAVE,
376 /* "private" */ MS_PRIVATE,
377 /* "unbindable" */ MS_UNBINDABLE,
378 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
379 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
Roman Borisovd3679d22011-03-23 11:20:25 +0300380 /* "rprivate" */ MS_PRIVATE|MS_RECURSIVE,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000381 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000382 )
383
384 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000385 /* "ro" */ MS_RDONLY, // vfs flag
386 /* "rw" */ ~MS_RDONLY, // vfs flag
387 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000388};
389
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200390static const char mount_option_str[] ALIGN1 =
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000391 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000392 "loop\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000393 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000394 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000395 "defaults\0"
396 // "quiet\0" - do not filter out, vfat wants to see it
397 "noauto\0"
398 "sw\0"
399 "swap\0"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000400 IF_DESKTOP("user\0")
401 IF_DESKTOP("users\0")
Denys Vlasenko911d2652015-12-30 20:11:34 +0100402 IF_DESKTOP("nofail\0")
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000403 "_netdev\0"
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100404 IF_DESKTOP("comment=\0") /* systemd uses this in fstab */
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000405 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000406 IF_FEATURE_MOUNT_FLAGS(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000407 // vfs flags
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000408 "nosuid\0"
409 "suid\0"
410 "dev\0"
411 "nodev\0"
412 "exec\0"
413 "noexec\0"
414 "sync\0"
415 "dirsync\0"
416 "async\0"
417 "atime\0"
418 "noatime\0"
419 "diratime\0"
420 "nodiratime\0"
421 "mand\0"
422 "nomand\0"
423 "relatime\0"
424 "norelatime\0"
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200425 "strictatime\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000426 "loud\0"
Roman Borisov19311bf2011-03-24 15:08:43 +0300427 "rbind\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000428
429 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200430 "union\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000431 "bind\0"
432 "move\0"
Roman Borisov945fd172011-02-25 14:50:39 +0300433 "make-shared\0"
434 "make-slave\0"
435 "make-private\0"
436 "make-unbindable\0"
437 "make-rshared\0"
438 "make-rslave\0"
439 "make-rprivate\0"
440 "make-runbindable\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000441 )
442
443 // Always understood.
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000444 "ro\0" // vfs flag
445 "rw\0" // vfs flag
446 "remount\0" // action flag
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000447;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000448
Denis Vlasenkof732e962008-02-18 12:07:49 +0000449
450struct globals {
451#if ENABLE_FEATURE_MOUNT_NFS
452 smalluint nfs_mount_version;
453#endif
454#if ENABLE_FEATURE_MOUNT_VERBOSE
455 unsigned verbose;
456#endif
457 llist_t *fslist;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000458 char getmntent_buf[1];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100459} FIX_ALIASING;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000460enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200461#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenkof732e962008-02-18 12:07:49 +0000462#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000463#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000464#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000465#else
466#define verbose 0
467#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000468#define fslist (G.fslist )
469#define getmntent_buf (G.getmntent_buf )
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200470#define INIT_G() do { setup_common_bufsiz(); } while (0)
Denis Vlasenkof732e962008-02-18 12:07:49 +0000471
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100472#if ENABLE_FEATURE_MTAB_SUPPORT
473/*
474 * update_mtab_entry_on_move() is used to update entry in case of mount --move.
475 * we are looking for existing entries mnt_dir which is equal to mnt_fsname of
476 * input mntent and replace it by new one.
477 */
478static void FAST_FUNC update_mtab_entry_on_move(const struct mntent *mp)
479{
480 struct mntent *entries, *m;
481 int i, count;
482 FILE *mountTable;
483
484 mountTable = setmntent(bb_path_mtab_file, "r");
485 if (!mountTable) {
James Byrne69374872019-07-02 11:35:03 +0200486 bb_simple_perror_msg(bb_path_mtab_file);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100487 return;
488 }
489
490 entries = NULL;
491 count = 0;
492 while ((m = getmntent(mountTable)) != NULL) {
493 entries = xrealloc_vector(entries, 3, count);
494 entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
495 entries[count].mnt_dir = xstrdup(m->mnt_dir);
496 entries[count].mnt_type = xstrdup(m->mnt_type);
497 entries[count].mnt_opts = xstrdup(m->mnt_opts);
498 entries[count].mnt_freq = m->mnt_freq;
499 entries[count].mnt_passno = m->mnt_passno;
500 count++;
501 }
502 endmntent(mountTable);
503
504 mountTable = setmntent(bb_path_mtab_file, "w");
505 if (mountTable) {
506 for (i = 0; i < count; i++) {
507 if (strcmp(entries[i].mnt_dir, mp->mnt_fsname) != 0)
508 addmntent(mountTable, &entries[i]);
509 else
510 addmntent(mountTable, mp);
511 }
512 endmntent(mountTable);
513 } else if (errno != EROFS)
James Byrne69374872019-07-02 11:35:03 +0200514 bb_simple_perror_msg(bb_path_mtab_file);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100515
516 if (ENABLE_FEATURE_CLEAN_UP) {
517 for (i = 0; i < count; i++) {
518 free(entries[i].mnt_fsname);
519 free(entries[i].mnt_dir);
520 free(entries[i].mnt_type);
521 free(entries[i].mnt_opts);
522 }
523 free(entries);
524 }
525}
526#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000527
528#if ENABLE_FEATURE_MOUNT_VERBOSE
529static int verbose_mount(const char *source, const char *target,
530 const char *filesystemtype,
531 unsigned long mountflags, const void *data)
532{
533 int rc;
534
535 errno = 0;
536 rc = mount(source, target, filesystemtype, mountflags, data);
537 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000538 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000539 source, target, filesystemtype,
540 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000541 return rc;
542}
543#else
544#define verbose_mount(...) mount(__VA_ARGS__)
545#endif
546
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000547// Append mount options to string
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000548static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000549{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000550 if (*oldopts && **oldopts) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000551 // Do not insert options which are already there
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000552 while (newopts[0]) {
553 char *p;
554 int len = strlen(newopts);
555 p = strchr(newopts, ',');
556 if (p) len = p - newopts;
557 p = *oldopts;
558 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000559 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000560 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000561 goto skip;
562 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000563 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000564 p++;
565 }
566 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
567 free(*oldopts);
568 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000569 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000570 newopts += len;
571 while (newopts[0] == ',') newopts++;
572 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000573 } else {
574 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000575 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000576 }
577}
578
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000579// Use the mount_options list to parse options into flags.
Alexander Shishkin77650952010-10-28 06:10:03 +0200580// Also update list of unrecognized options if unrecognized != NULL
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200581static unsigned long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000582{
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200583 unsigned long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000584
Rob Landley6a6798b2005-08-10 20:35:54 +0000585 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000586 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000587 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000588 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000589 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000590
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000591 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000592
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000593// FIXME: use hasmntopt()
Rob Landley6a6798b2005-08-10 20:35:54 +0000594 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000595 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200596 unsigned opt_len = strlen(option_str);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100597
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200598 if (strncasecmp(option_str, options, opt_len) == 0
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100599 && (options[opt_len] == '\0'
600 /* or is it "comment=" thingy in fstab? */
601 IF_FEATURE_MOUNT_FSTAB(IF_DESKTOP( || option_str[opt_len-1] == '=' ))
602 )
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200603 ) {
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200604 unsigned long fl = mount_options[i];
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200605 if (fl & BB_MS_INVERTED_VALUE)
Alexander Shishkin77650952010-10-28 06:10:03 +0200606 flags &= fl;
607 else
608 flags |= fl;
609 goto found;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000610 }
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200611 option_str += opt_len + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000612 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200613 // We did not recognize this option.
614 // If "unrecognized" is not NULL, append option there.
615 // Note that we should not append *empty* option -
616 // in this case we want to pass NULL, not "", to "data"
617 // parameter of mount(2) syscall.
618 // This is crucial for filesystems that don't accept
619 // any arbitrary mount options, like cgroup fs:
620 // "mount -t cgroup none /mnt"
621 if (options[0] && unrecognized) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000622 // Add it to strflags, to pass on to kernel
Alexander Shishkin77650952010-10-28 06:10:03 +0200623 char *p = *unrecognized;
624 unsigned len = p ? strlen(p) : 0;
625 *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000626
Rob Landley6a6798b2005-08-10 20:35:54 +0000627 // Comma separated if it's not the first one
Alexander Shishkin77650952010-10-28 06:10:03 +0200628 if (len) p[len++] = ',';
629 strcpy(p + len, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000630 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200631 found:
Denis Vlasenko2535f122007-09-15 13:28:30 +0000632 if (!comma)
633 break;
634 // Advance to next option
635 *comma = ',';
636 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000637 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000638
Rob Landleydc0955b2006-03-14 18:16:25 +0000639 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000640}
641
Rob Landleydc0955b2006-03-14 18:16:25 +0000642// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000643static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000644{
Denis Vlasenko87468852007-04-13 23:22:00 +0000645 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000646 "/etc/filesystems",
647 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000648 };
649 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200650 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000651 int i;
652 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000653
Denis Vlasenko87468852007-04-13 23:22:00 +0000654 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000655 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000656 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000657
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000658 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100659 if (is_prefixed_with(buf, "nodev") && isspace(buf[5]))
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100660 goto next;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000661 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200662 if (*fs == '#' || *fs == '*' || !*fs)
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100663 goto next;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000664
Denis Vlasenko372686b2006-10-12 22:42:33 +0000665 llist_add_to_end(&list, xstrdup(fs));
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100666 next:
Denis Vlasenko372686b2006-10-12 22:42:33 +0000667 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000668 }
669 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
670 }
671
672 return list;
673}
674
Rob Landleydc0955b2006-03-14 18:16:25 +0000675#if ENABLE_FEATURE_CLEAN_UP
676static void delete_block_backed_filesystems(void)
677{
Rob Landleya6b5b602006-05-08 19:03:07 +0000678 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000679}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000680#else
681void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000682#endif
683
Rob Landleydc0955b2006-03-14 18:16:25 +0000684// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000685// NB: mp->xxx fields may be trashed on exit
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200686static int mount_it_now(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000687{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000688 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000689
Denys Vlasenko911d2652015-12-30 20:11:34 +0100690 vfsflags &= ~(unsigned long)MOUNT_FAKEFLAGS;
691
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200692 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000693 if (verbose >= 2)
694 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
695 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
696 vfsflags, filteropts);
697 goto mtab;
698 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000699
Rob Landleydc0955b2006-03-14 18:16:25 +0000700 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000701 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000702 errno = 0;
703 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000704 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000705
706 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000707 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200708 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200709 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000710 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000711 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000712 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200713 if (FAKE_IT)
714 args[rc++] = (char *)"-f";
715 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
716 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000717 args[rc++] = mp->mnt_fsname;
718 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000719 if (filteropts) {
720 args[rc++] = (char *)"-o";
721 args[rc++] = filteropts;
722 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000723 args[rc] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +0100724 rc = spawn_and_wait(args);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000725 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000726 if (!rc)
727 break;
728 errno = errno_save;
729 }
730
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000731 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000732 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000733 if (!(vfsflags & MS_SILENT))
734 bb_error_msg("%s is write-protected, mounting read-only",
735 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000736 vfsflags |= MS_RDONLY;
737 }
738
Rob Landleydc0955b2006-03-14 18:16:25 +0000739 // Abort entirely if permission denied.
740
741 if (rc && errno == EPERM)
James Byrne69374872019-07-02 11:35:03 +0200742 bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root);
Rob Landleydc0955b2006-03-14 18:16:25 +0000743
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000744 // If the mount was successful, and we're maintaining an old-style
745 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000746 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200747 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000748 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000749 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000750 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000751 int i;
752
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000753 if (!mountTable) {
James Byrne69374872019-07-02 11:35:03 +0200754 bb_simple_perror_msg(bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000755 goto ret;
756 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000757
758 // Add vfs string flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000759 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
760 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
761 append_mount_options(&(mp->mnt_opts), option_str);
762 option_str += strlen(option_str) + 1;
763 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000764
765 // Remove trailing / (if any) from directory we mounted on
Denis Vlasenko727ef942006-09-14 13:19:19 +0000766 i = strlen(mp->mnt_dir) - 1;
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100767 while (i > 0 && mp->mnt_dir[i] == '/')
Denys Vlasenkoc6450c92011-02-28 11:09:49 +0100768 mp->mnt_dir[i--] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000769
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000770 // Convert to canonical pathnames as needed
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000771 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100772 fsname = NULL;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000773 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000774 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000775 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000776 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000777 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000778
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100779 // Write and close
780#if ENABLE_FEATURE_MTAB_SUPPORT
781 if (vfsflags & MS_MOVE)
782 update_mtab_entry_on_move(mp);
783 else
784#endif
785 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000786 endmntent(mountTable);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100787
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000788 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000789 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000790 free(fsname);
791 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000792 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000793 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000794 return rc;
795}
796
Denis Vlasenko25098f72006-09-14 15:46:33 +0000797#if ENABLE_FEATURE_MOUNT_NFS
798
799/*
800 * Linux NFS mount
801 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
802 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +0200803 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko25098f72006-09-14 15:46:33 +0000804 *
805 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
806 * numbers to be specified on the command line.
807 *
808 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
809 * Omit the call to connect() for Linux version 1.3.11 or later.
810 *
811 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
812 * Implemented the "bg", "fg" and "retry" mount options for NFS.
813 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000814 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000815 * - added Native Language Support
816 *
817 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
818 * plus NFSv3 stuff.
819 */
820
Denis Vlasenko25098f72006-09-14 15:46:33 +0000821#define MOUNTPORT 635
822#define MNTPATHLEN 1024
823#define MNTNAMLEN 255
824#define FHSIZE 32
825#define FHSIZE3 64
826
827typedef char fhandle[FHSIZE];
828
829typedef struct {
830 unsigned int fhandle3_len;
831 char *fhandle3_val;
832} fhandle3;
833
834enum mountstat3 {
835 MNT_OK = 0,
836 MNT3ERR_PERM = 1,
837 MNT3ERR_NOENT = 2,
838 MNT3ERR_IO = 5,
839 MNT3ERR_ACCES = 13,
840 MNT3ERR_NOTDIR = 20,
841 MNT3ERR_INVAL = 22,
842 MNT3ERR_NAMETOOLONG = 63,
843 MNT3ERR_NOTSUPP = 10004,
844 MNT3ERR_SERVERFAULT = 10006,
845};
846typedef enum mountstat3 mountstat3;
847
848struct fhstatus {
849 unsigned int fhs_status;
850 union {
851 fhandle fhs_fhandle;
852 } fhstatus_u;
853};
854typedef struct fhstatus fhstatus;
855
856struct mountres3_ok {
857 fhandle3 fhandle;
858 struct {
859 unsigned int auth_flavours_len;
860 char *auth_flavours_val;
861 } auth_flavours;
862};
863typedef struct mountres3_ok mountres3_ok;
864
865struct mountres3 {
866 mountstat3 fhs_status;
867 union {
868 mountres3_ok mountinfo;
869 } mountres3_u;
870};
871typedef struct mountres3 mountres3;
872
873typedef char *dirpath;
874
875typedef char *name;
876
877typedef struct mountbody *mountlist;
878
879struct mountbody {
880 name ml_hostname;
881 dirpath ml_directory;
882 mountlist ml_next;
883};
884typedef struct mountbody mountbody;
885
886typedef struct groupnode *groups;
887
888struct groupnode {
889 name gr_name;
890 groups gr_next;
891};
892typedef struct groupnode groupnode;
893
894typedef struct exportnode *exports;
895
896struct exportnode {
897 dirpath ex_dir;
898 groups ex_groups;
899 exports ex_next;
900};
901typedef struct exportnode exportnode;
902
903struct ppathcnf {
904 int pc_link_max;
905 short pc_max_canon;
906 short pc_max_input;
907 short pc_name_max;
908 short pc_path_max;
909 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000910 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000911 char pc_xxx;
912 short pc_mask[2];
913};
914typedef struct ppathcnf ppathcnf;
915
916#define MOUNTPROG 100005
917#define MOUNTVERS 1
918
919#define MOUNTPROC_NULL 0
920#define MOUNTPROC_MNT 1
921#define MOUNTPROC_DUMP 2
922#define MOUNTPROC_UMNT 3
923#define MOUNTPROC_UMNTALL 4
924#define MOUNTPROC_EXPORT 5
925#define MOUNTPROC_EXPORTALL 6
926
927#define MOUNTVERS_POSIX 2
928
929#define MOUNTPROC_PATHCONF 7
930
931#define MOUNT_V3 3
932
933#define MOUNTPROC3_NULL 0
934#define MOUNTPROC3_MNT 1
935#define MOUNTPROC3_DUMP 2
936#define MOUNTPROC3_UMNT 3
937#define MOUNTPROC3_UMNTALL 4
938#define MOUNTPROC3_EXPORT 5
939
940enum {
941#ifndef NFS_FHSIZE
942 NFS_FHSIZE = 32,
943#endif
944#ifndef NFS_PORT
945 NFS_PORT = 2049
946#endif
947};
948
Denis Vlasenko25098f72006-09-14 15:46:33 +0000949/*
950 * We want to be able to compile mount on old kernels in such a way
951 * that the binary will work well on more recent kernels.
952 * Thus, if necessary we teach nfsmount.c the structure of new fields
953 * that will come later.
954 *
955 * Moreover, the new kernel includes conflict with glibc includes
956 * so it is easiest to ignore the kernel altogether (at compile time).
957 */
958
959struct nfs2_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100960 char data[32];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000961};
962struct nfs3_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100963 unsigned short size;
964 unsigned char data[64];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000965};
966
967struct nfs_mount_data {
Dave Lovefae473c2011-11-10 15:19:25 +0100968 int version; /* 1 */
969 int fd; /* 1 */
970 struct nfs2_fh old_root; /* 1 */
971 int flags; /* 1 */
972 int rsize; /* 1 */
973 int wsize; /* 1 */
974 int timeo; /* 1 */
975 int retrans; /* 1 */
976 int acregmin; /* 1 */
977 int acregmax; /* 1 */
978 int acdirmin; /* 1 */
979 int acdirmax; /* 1 */
980 struct sockaddr_in addr; /* 1 */
981 char hostname[256]; /* 1 */
982 int namlen; /* 2 */
983 unsigned int bsize; /* 3 */
984 struct nfs3_fh root; /* 4 */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000985};
986
987/* bits in the flags field */
988enum {
989 NFS_MOUNT_SOFT = 0x0001, /* 1 */
990 NFS_MOUNT_INTR = 0x0002, /* 1 */
991 NFS_MOUNT_SECURE = 0x0004, /* 1 */
992 NFS_MOUNT_POSIX = 0x0008, /* 1 */
993 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
994 NFS_MOUNT_NOAC = 0x0020, /* 1 */
995 NFS_MOUNT_TCP = 0x0040, /* 2 */
996 NFS_MOUNT_VER3 = 0x0080, /* 3 */
997 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000998 NFS_MOUNT_NONLM = 0x0200, /* 3 */
Dave Lovefae473c2011-11-10 15:19:25 +0100999 NFS_MOUNT_NOACL = 0x0800, /* 4 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001000 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +00001001};
1002
1003
1004/*
1005 * We need to translate between nfs status return values and
1006 * the local errno values which may not be the same.
1007 *
1008 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
1009 * "after #include <errno.h> the symbol errno is reserved for any use,
1010 * it cannot even be used as a struct tag or field name".
1011 */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001012#ifndef EDQUOT
Denys Vlasenkocc428142009-12-16 02:06:56 +01001013# define EDQUOT ENOSPC
Denis Vlasenko25098f72006-09-14 15:46:33 +00001014#endif
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001015/* Convert each NFSERR_BLAH into EBLAH */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02001016static const uint8_t nfs_err_stat[] ALIGN1 = {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001017 1, 2, 5, 6, 13, 17,
1018 19, 20, 21, 22, 27, 28,
1019 30, 63, 66, 69, 70, 71
1020};
Denys Vlasenkodc1fd2e2010-05-19 17:01:29 +02001021#if ( \
1022 EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
1023 ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
1024 EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
1025typedef uint8_t nfs_err_type;
1026#else
1027typedef uint16_t nfs_err_type;
1028#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02001029static const nfs_err_type nfs_err_errnum[] ALIGN2 = {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001030 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
1031 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
1032 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
Denis Vlasenko25098f72006-09-14 15:46:33 +00001033};
Denis Vlasenko25098f72006-09-14 15:46:33 +00001034static char *nfs_strerror(int status)
1035{
1036 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001037
Denys Vlasenkocc428142009-12-16 02:06:56 +01001038 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
1039 if (nfs_err_stat[i] == status)
1040 return strerror(nfs_err_errnum[i]);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001041 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001042 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001043}
1044
1045static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
1046{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001047 return xdr_opaque(xdrs, objp, FHSIZE);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001048}
1049
1050static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
1051{
1052 if (!xdr_u_int(xdrs, &objp->fhs_status))
Denys Vlasenko69675782013-01-14 01:34:48 +01001053 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001054 if (objp->fhs_status == 0)
1055 return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001056 return TRUE;
1057}
1058
1059static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
1060{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001061 return xdr_string(xdrs, objp, MNTPATHLEN);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001062}
1063
1064static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
1065{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001066 return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
Denys Vlasenko69675782013-01-14 01:34:48 +01001067 (unsigned int *) &objp->fhandle3_len,
1068 FHSIZE3);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001069}
1070
1071static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
1072{
1073 if (!xdr_fhandle3(xdrs, &objp->fhandle))
1074 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001075 return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
Denys Vlasenko69675782013-01-14 01:34:48 +01001076 &(objp->auth_flavours.auth_flavours_len),
1077 ~0,
1078 sizeof(int),
1079 (xdrproc_t) xdr_int);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001080}
1081
1082static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
1083{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001084 return xdr_enum(xdrs, (enum_t *) objp);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001085}
1086
1087static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
1088{
1089 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
1090 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001091 if (objp->fhs_status == MNT_OK)
1092 return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001093 return TRUE;
1094}
1095
1096#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
1097
Denis Vlasenko25098f72006-09-14 15:46:33 +00001098/*
1099 * Unfortunately, the kernel prints annoying console messages
1100 * in case of an unexpected nfs mount version (instead of
1101 * just returning some error). Therefore we'll have to try
1102 * and figure out what version the kernel expects.
1103 *
1104 * Variables:
1105 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
1106 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
1107 * nfs_mount_version: version this source and running kernel can handle
1108 */
1109static void
1110find_kernel_nfs_mount_version(void)
1111{
Denis Vlasenkob9256052007-09-28 10:29:17 +00001112 int kernel_version;
1113
1114 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001115 return;
1116
1117 nfs_mount_version = 4; /* default */
1118
1119 kernel_version = get_linux_version_code();
1120 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001121 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +00001122 nfs_mount_version = 3;
1123 /* else v4 since 2.3.99pre4 */
1124 }
1125}
1126
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +00001127static void
Denis Vlasenkob9256052007-09-28 10:29:17 +00001128get_mountport(struct pmap *pm_mnt,
1129 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001130 long unsigned prog,
1131 long unsigned version,
1132 long unsigned proto,
1133 long unsigned port)
1134{
1135 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001136
1137 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001138/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
1139 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001140 pmap = pmap_getmaps(server_addr);
1141
1142 if (version > MAX_NFSPROT)
1143 version = MAX_NFSPROT;
1144 if (!prog)
1145 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001146 pm_mnt->pm_prog = prog;
1147 pm_mnt->pm_vers = version;
1148 pm_mnt->pm_prot = proto;
1149 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001150
Denis Vlasenko25098f72006-09-14 15:46:33 +00001151 while (pmap) {
1152 if (pmap->pml_map.pm_prog != prog)
1153 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001154 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001155 goto next;
1156 if (version > 2 && pmap->pml_map.pm_vers != version)
1157 goto next;
1158 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
1159 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001160 if (pmap->pml_map.pm_vers > MAX_NFSPROT
1161 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
1162 || (port && pmap->pml_map.pm_port != port)
1163 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001164 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001165 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001166 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
1167 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001168 pmap = pmap->pml_next;
1169 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001170 if (!pm_mnt->pm_vers)
1171 pm_mnt->pm_vers = MOUNTVERS;
1172 if (!pm_mnt->pm_port)
1173 pm_mnt->pm_port = MOUNTPORT;
1174 if (!pm_mnt->pm_prot)
1175 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001176}
1177
Denis Vlasenkof0000652007-09-04 18:30:26 +00001178#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001179static int daemonize(void)
1180{
Denis Vlasenko25098f72006-09-14 15:46:33 +00001181 int pid = fork();
1182 if (pid < 0) /* error */
1183 return -errno;
1184 if (pid > 0) /* parent */
1185 return 0;
1186 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001187 close(0);
1188 xopen(bb_dev_null, O_RDWR);
1189 xdup2(0, 1);
1190 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001191 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +00001192 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001193 logmode = LOGMODE_SYSLOG;
1194 return 1;
1195}
Denis Vlasenkof0000652007-09-04 18:30:26 +00001196#else
Denys Vlasenko8c317f02019-05-14 17:26:47 +02001197static inline int daemonize(void)
1198{
1199 return -ENOSYS;
1200}
Denis Vlasenkof0000652007-09-04 18:30:26 +00001201#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001202
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001203/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001204static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001205{
1206 return 0;
1207}
1208
1209/* RPC strerror analogs are terminally idiotic:
1210 * *mandatory* prefix and \n at end.
1211 * This hopefully helps. Usage:
1212 * error_msg_rpc(clnt_*error*(" ")) */
1213static void error_msg_rpc(const char *msg)
1214{
Denis Vlasenko23514fe2006-09-19 14:07:52 +00001215 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001216 while (msg[0] == ' ' || msg[0] == ':') msg++;
1217 len = strlen(msg);
1218 while (len && msg[len-1] == '\n') len--;
1219 bb_error_msg("%.*s", len, msg);
1220}
1221
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001222/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001223static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001224{
1225 CLIENT *mclient;
1226 char *hostname;
1227 char *pathname;
1228 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001229 /* prior to 2.6.23, kernel took NFS options in a form of this struct
1230 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
1231 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001232 struct nfs_mount_data data;
1233 char *opt;
1234 struct hostent *hp;
1235 struct sockaddr_in server_addr;
1236 struct sockaddr_in mount_server_addr;
1237 int msock, fsock;
1238 union {
1239 struct fhstatus nfsv2;
1240 struct mountres3 nfsv3;
1241 } status;
1242 int daemonized;
1243 char *s;
1244 int port;
1245 int mountport;
1246 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001247#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001248 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001249#else
1250 enum { bg = 0 };
1251#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001252 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001253 int mountprog;
1254 int mountvers;
1255 int nfsprog;
1256 int nfsvers;
1257 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001258 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001259 smallint tcp;
1260 smallint soft;
1261 int intr;
1262 int posix;
1263 int nocto;
1264 int noac;
1265 int nordirplus;
1266 int nolock;
Dave Lovefae473c2011-11-10 15:19:25 +01001267 int noacl;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001268
1269 find_kernel_nfs_mount_version();
1270
1271 daemonized = 0;
1272 mounthost = NULL;
1273 retval = ETIMEDOUT;
1274 msock = fsock = -1;
1275 mclient = NULL;
1276
1277 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1278
1279 filteropts = xstrdup(filteropts); /* going to trash it later... */
1280
1281 hostname = xstrdup(mp->mnt_fsname);
1282 /* mount_main() guarantees that ':' is there */
1283 s = strchr(hostname, ':');
1284 pathname = s + 1;
1285 *s = '\0';
1286 /* Ignore all but first hostname in replicated mounts
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001287 * until they can be fully supported. (mack@sgi.com) */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001288 s = strchr(hostname, ',');
1289 if (s) {
1290 *s = '\0';
James Byrne69374872019-07-02 11:35:03 +02001291 bb_simple_error_msg("warning: multiple hostnames not supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001292 }
1293
1294 server_addr.sin_family = AF_INET;
1295 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1296 hp = gethostbyname(hostname);
1297 if (hp == NULL) {
James Byrne69374872019-07-02 11:35:03 +02001298 bb_simple_herror_msg(hostname);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001299 goto fail;
1300 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001301 if (hp->h_length != (int)sizeof(struct in_addr)) {
James Byrne69374872019-07-02 11:35:03 +02001302 bb_simple_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001303 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001304 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001305 }
1306
1307 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1308
1309 /* add IP address to mtab options for use when unmounting */
1310
1311 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1312 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1313 } else {
1314 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1315 mp->mnt_opts[0] ? "," : "",
1316 inet_ntoa(server_addr.sin_addr));
1317 free(mp->mnt_opts);
1318 mp->mnt_opts = tmp;
1319 }
1320
1321 /* Set default options.
1322 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1323 * let the kernel decide.
1324 * timeo is filled in after we know whether it'll be TCP or UDP. */
1325 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001326 data.retrans = 3;
1327 data.acregmin = 3;
1328 data.acregmax = 60;
1329 data.acdirmin = 30;
1330 data.acdirmax = 60;
1331 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001332
Denis Vlasenko25098f72006-09-14 15:46:33 +00001333 soft = 0;
1334 intr = 0;
1335 posix = 0;
1336 nocto = 0;
1337 nolock = 0;
1338 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001339 nordirplus = 0;
Dave Lovefae473c2011-11-10 15:19:25 +01001340 noacl = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001341 retry = 10000; /* 10000 minutes ~ 1 week */
Bernhard Reutner-Fischer88206292011-05-04 19:03:30 +02001342 tcp = 1; /* nfs-utils uses tcp per default */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001343
1344 mountprog = MOUNTPROG;
1345 mountvers = 0;
1346 port = 0;
1347 mountport = 0;
1348 nfsprog = 100003;
1349 nfsvers = 0;
1350
1351 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001352 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001353 char *opteq = strchr(opt, '=');
1354 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001355 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001356 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001357 /* 0 */ "rsize\0"
1358 /* 1 */ "wsize\0"
1359 /* 2 */ "timeo\0"
1360 /* 3 */ "retrans\0"
1361 /* 4 */ "acregmin\0"
1362 /* 5 */ "acregmax\0"
1363 /* 6 */ "acdirmin\0"
1364 /* 7 */ "acdirmax\0"
1365 /* 8 */ "actimeo\0"
1366 /* 9 */ "retry\0"
1367 /* 10 */ "port\0"
1368 /* 11 */ "mountport\0"
1369 /* 12 */ "mounthost\0"
1370 /* 13 */ "mountprog\0"
1371 /* 14 */ "mountvers\0"
1372 /* 15 */ "nfsprog\0"
1373 /* 16 */ "nfsvers\0"
1374 /* 17 */ "vers\0"
1375 /* 18 */ "proto\0"
1376 /* 19 */ "namlen\0"
1377 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001378
1379 *opteq++ = '\0';
1380 idx = index_in_strings(options, opt);
1381 switch (idx) {
1382 case 12: // "mounthost"
1383 mounthost = xstrndup(opteq,
1384 strcspn(opteq, " \t\n\r,"));
1385 continue;
1386 case 18: // "proto"
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001387 if (is_prefixed_with(opteq, "tcp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001388 tcp = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001389 else if (is_prefixed_with(opteq, "udp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001390 tcp = 0;
1391 else
James Byrne69374872019-07-02 11:35:03 +02001392 bb_simple_error_msg("warning: unrecognized proto= option");
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001393 continue;
1394 case 20: // "addr" - ignore
1395 continue;
Peter Korsgaard301fe502011-02-21 17:52:13 +01001396 case -1: // unknown
1397 if (vfsflags & MS_REMOUNT)
1398 continue;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001399 }
1400
Denys Vlasenko77832482010-08-12 14:14:45 +02001401 val = xatoi_positive(opteq);
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001402 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001403 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001404 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001405 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001406 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001407 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001408 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001409 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001410 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001411 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001412 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001413 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001414 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001415 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001416 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001417 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001418 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001419 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001420 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001421 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001422 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001423 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001424 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001425 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001426 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001427 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001428 data.acregmin = val;
1429 data.acregmax = val;
1430 data.acdirmin = val;
1431 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001432 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001433 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001434 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001435 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001436 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001437 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001438 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001439 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001440 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001441 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001442 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001443 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001444 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001445 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001446 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001447 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001448 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001449 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001450 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001451 case 16: // "nfsvers"
1452 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001453 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001454 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001455 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001456 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001457 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001458 //else
1459 // bb_error_msg("warning: option namlen is not supported\n");
1460 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001461 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001462 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1463 goto fail;
1464 }
1465 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001466 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001467 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001468 "bg\0"
1469 "fg\0"
1470 "soft\0"
1471 "hard\0"
1472 "intr\0"
1473 "posix\0"
1474 "cto\0"
1475 "ac\0"
1476 "tcp\0"
1477 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001478 "lock\0"
Dave Lovefae473c2011-11-10 15:19:25 +01001479 "rdirplus\0"
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001480 "acl\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001481 int val = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001482 if (is_prefixed_with(opt, "no")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001483 val = 0;
1484 opt += 2;
1485 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001486 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001487 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001488#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001489 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001490#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001491 break;
1492 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001493#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001494 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001495#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001496 break;
1497 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001498 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001499 break;
1500 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001501 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001502 break;
1503 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001504 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001505 break;
1506 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001507 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001508 break;
1509 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001510 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001511 break;
1512 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001513 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001514 break;
1515 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001516 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001517 break;
1518 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001519 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001520 break;
1521 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001522 if (nfs_mount_version >= 3)
1523 nolock = !val;
1524 else
James Byrne69374872019-07-02 11:35:03 +02001525 bb_simple_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001526 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001527 case 11: //rdirplus
1528 nordirplus = !val;
1529 break;
Dave Lovefae473c2011-11-10 15:19:25 +01001530 case 12: // acl
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001531 noacl = !val;
Dave Lovefae473c2011-11-10 15:19:25 +01001532 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001533 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001534 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1535 goto fail;
1536 }
1537 }
1538 }
1539 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1540
1541 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1542 | (intr ? NFS_MOUNT_INTR : 0)
1543 | (posix ? NFS_MOUNT_POSIX : 0)
1544 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001545 | (noac ? NFS_MOUNT_NOAC : 0)
Dave Lovefae473c2011-11-10 15:19:25 +01001546 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0)
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001547 | (noacl ? NFS_MOUNT_NOACL : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001548 if (nfs_mount_version >= 2)
1549 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1550 if (nfs_mount_version >= 3)
1551 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1552 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1553 bb_error_msg("NFSv%d not supported", nfsvers);
1554 goto fail;
1555 }
1556 if (nfsvers && !mountvers)
1557 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1558 if (nfsvers && nfsvers < mountvers) {
1559 mountvers = nfsvers;
1560 }
1561
1562 /* Adjust options if none specified */
1563 if (!data.timeo)
1564 data.timeo = tcp ? 70 : 7;
1565
Denis Vlasenko25098f72006-09-14 15:46:33 +00001566 data.version = nfs_mount_version;
1567
1568 if (vfsflags & MS_REMOUNT)
1569 goto do_mount;
1570
1571 /*
1572 * If the previous mount operation on the same host was
1573 * backgrounded, and the "bg" for this mount is also set,
1574 * give up immediately, to avoid the initial timeout.
1575 */
1576 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001577 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001578 if (daemonized <= 0) { /* parent or error */
1579 retval = -daemonized;
1580 goto ret;
1581 }
1582 }
1583
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001584 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001585 /* See if the nfs host = mount host. */
1586 if (mounthost) {
1587 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1588 mount_server_addr.sin_family = AF_INET;
1589 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1590 } else {
1591 hp = gethostbyname(mounthost);
1592 if (hp == NULL) {
James Byrne69374872019-07-02 11:35:03 +02001593 bb_simple_herror_msg(mounthost);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001594 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001595 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001596 if (hp->h_length != (int)sizeof(struct in_addr)) {
James Byrne69374872019-07-02 11:35:03 +02001597 bb_simple_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001598 }
1599 mount_server_addr.sin_family = AF_INET;
Denys Vlasenko99069332010-02-27 19:38:19 +01001600 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001601 }
1602 }
1603
1604 /*
1605 * The following loop implements the mount retries. When the mount
1606 * times out, and the "bg" option is set, we background ourself
1607 * and continue trying.
1608 *
1609 * The case where the mount point is not present and the "bg"
1610 * option is set, is treated as a timeout. This is done to
1611 * support nested mounts.
1612 *
1613 * The "retry" count specified by the user is the number of
1614 * minutes to retry before giving up.
1615 */
1616 {
1617 struct timeval total_timeout;
1618 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001619 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001620 time_t t;
1621 time_t prevt;
1622 time_t timeout;
1623
1624 retry_timeout.tv_sec = 3;
1625 retry_timeout.tv_usec = 0;
1626 total_timeout.tv_sec = 20;
1627 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001628/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001629 timeout = time(NULL) + 60 * retry;
1630 prevt = 0;
1631 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001632 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001633 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001634 if (t - prevt < 30)
1635 sleep(30);
1636
Denis Vlasenkob9256052007-09-28 10:29:17 +00001637 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001638 mountprog,
1639 mountvers,
1640 proto,
1641 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001642 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001643
1644 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001645 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001646 msock = RPC_ANYSOCK;
1647
Denis Vlasenkob9256052007-09-28 10:29:17 +00001648 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001649 case IPPROTO_UDP:
1650 mclient = clntudp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001651 pm_mnt.pm_prog,
1652 pm_mnt.pm_vers,
1653 retry_timeout,
1654 &msock);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001655 if (mclient)
1656 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001657 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001658 msock = RPC_ANYSOCK;
1659 case IPPROTO_TCP:
1660 mclient = clnttcp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001661 pm_mnt.pm_prog,
1662 pm_mnt.pm_vers,
1663 &msock, 0, 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001664 break;
1665 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001666 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001667 }
1668 if (!mclient) {
1669 if (!daemonized && prevt == 0)
1670 error_msg_rpc(clnt_spcreateerror(" "));
1671 } else {
1672 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001673
1674 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001675 mclient->cl_auth = authunix_create_default();
1676
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001677 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001678 * that xdr_array allocates memory for us
1679 */
1680 memset(&status, 0, sizeof(status));
1681
Denis Vlasenkob9256052007-09-28 10:29:17 +00001682 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001683 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001684 (xdrproc_t) xdr_dirpath,
1685 (caddr_t) &pathname,
1686 (xdrproc_t) xdr_mountres3,
1687 (caddr_t) &status,
1688 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001689 else
1690 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001691 (xdrproc_t) xdr_dirpath,
1692 (caddr_t) &pathname,
1693 (xdrproc_t) xdr_fhstatus,
1694 (caddr_t) &status,
1695 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001696
1697 if (clnt_stat == RPC_SUCCESS)
1698 goto prepare_kernel_data; /* we're done */
1699 if (errno != ECONNREFUSED) {
1700 error_msg_rpc(clnt_sperror(mclient, " "));
1701 goto fail; /* don't retry */
1702 }
1703 /* Connection refused */
1704 if (!daemonized && prevt == 0) /* print just once */
1705 error_msg_rpc(clnt_sperror(mclient, " "));
1706 auth_destroy(mclient->cl_auth);
1707 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001708 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001709 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001710 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001711 }
1712
1713 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001714 if (!bg)
1715 goto fail;
1716 if (!daemonized) {
1717 daemonized = daemonize();
1718 if (daemonized <= 0) { /* parent or error */
1719 retval = -daemonized;
1720 goto ret;
1721 }
1722 }
1723 prevt = t;
1724 t = time(NULL);
1725 if (t >= timeout)
1726 /* TODO error message */
1727 goto fail;
1728
1729 goto retry;
1730 }
1731
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001732 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001733
1734 if (nfsvers == 2) {
1735 if (status.nfsv2.fhs_status != 0) {
1736 bb_error_msg("%s:%s failed, reason given by server: %s",
1737 hostname, pathname,
1738 nfs_strerror(status.nfsv2.fhs_status));
1739 goto fail;
1740 }
1741 memcpy(data.root.data,
1742 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1743 NFS_FHSIZE);
1744 data.root.size = NFS_FHSIZE;
1745 memcpy(data.old_root.data,
1746 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1747 NFS_FHSIZE);
1748 } else {
1749 fhandle3 *my_fhandle;
1750 if (status.nfsv3.fhs_status != 0) {
1751 bb_error_msg("%s:%s failed, reason given by server: %s",
1752 hostname, pathname,
1753 nfs_strerror(status.nfsv3.fhs_status));
1754 goto fail;
1755 }
1756 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1757 memset(data.old_root.data, 0, NFS_FHSIZE);
1758 memset(&data.root, 0, sizeof(data.root));
1759 data.root.size = my_fhandle->fhandle3_len;
1760 memcpy(data.root.data,
1761 (char *) my_fhandle->fhandle3_val,
1762 my_fhandle->fhandle3_len);
1763
1764 data.flags |= NFS_MOUNT_VER3;
1765 }
1766
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001767 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001768 if (tcp) {
1769 if (nfs_mount_version < 3) {
James Byrne69374872019-07-02 11:35:03 +02001770 bb_simple_error_msg("NFS over TCP is not supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001771 goto fail;
1772 }
1773 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1774 } else
1775 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1776 if (fsock < 0) {
James Byrne69374872019-07-02 11:35:03 +02001777 bb_simple_perror_msg("nfs socket");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001778 goto fail;
1779 }
1780 if (bindresvport(fsock, 0) < 0) {
James Byrne69374872019-07-02 11:35:03 +02001781 bb_simple_perror_msg("nfs bindresvport");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001782 goto fail;
1783 }
1784 if (port == 0) {
1785 server_addr.sin_port = PMAPPORT;
1786 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1787 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1788 if (port == 0)
1789 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001790 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001791 server_addr.sin_port = htons(port);
1792
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001793 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001794 data.fd = fsock;
1795 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1796 strncpy(data.hostname, hostname, sizeof(data.hostname));
1797
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001798 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001799 auth_destroy(mclient->cl_auth);
1800 clnt_destroy(mclient);
1801 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001802 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001803
1804 if (bg) {
1805 /* We must wait until mount directory is available */
1806 struct stat statbuf;
1807 int delay = 1;
1808 while (stat(mp->mnt_dir, &statbuf) == -1) {
1809 if (!daemonized) {
1810 daemonized = daemonize();
1811 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001812/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001813 retval = -daemonized;
1814 goto ret;
1815 }
1816 }
1817 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1818 delay *= 2;
1819 if (delay > 30)
1820 delay = 30;
1821 }
1822 }
1823
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001824 /* Perform actual mount */
1825 do_mount:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001826 retval = mount_it_now(mp, vfsflags, (char*)&data);
1827 goto ret;
1828
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001829 /* Abort */
1830 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001831 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001832 if (mclient) {
1833 auth_destroy(mclient->cl_auth);
1834 clnt_destroy(mclient);
1835 }
1836 close(msock);
1837 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001838 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001839 close(fsock);
1840
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001841 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001842 free(hostname);
1843 free(mounthost);
1844 free(filteropts);
1845 return retval;
1846}
1847
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001848#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001849
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001850/* Linux 2.6.23+ supports nfs mounts with options passed as a string.
1851 * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS.
1852 * (However, note that then you lose any chances that NFS over IPv6 would work).
1853 */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001854static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001855{
1856 len_and_sockaddr *lsa;
1857 char *opts;
1858 char *end;
1859 char *dotted;
1860 int ret;
1861
1862# if ENABLE_FEATURE_IPV6
1863 end = strchr(mp->mnt_fsname, ']');
1864 if (end && end[1] == ':')
1865 end++;
1866 else
1867# endif
1868 /* mount_main() guarantees that ':' is there */
1869 end = strchr(mp->mnt_fsname, ':');
1870
1871 *end = '\0';
Denys Vlasenko39b23312011-11-10 17:01:39 +01001872 lsa = xhost2sockaddr(mp->mnt_fsname, /*port:*/ 0);
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001873 *end = ':';
1874 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1875 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1876 opts = xasprintf("%s%saddr=%s",
1877 filteropts ? filteropts : "",
1878 filteropts ? "," : "",
1879 dotted
1880 );
1881 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
1882 ret = mount_it_now(mp, vfsflags, opts);
1883 if (ENABLE_FEATURE_CLEAN_UP) free(opts);
1884
1885 return ret;
1886}
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001887
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001888#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001889
1890// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1891// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001892// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001893static int singlemount(struct mntent *mp, int ignore_busy)
1894{
Denys Vlasenkoab518ee2017-03-16 16:49:37 +01001895 int loopfd = -1;
Denis Vlasenkob4133682008-02-18 13:05:38 +00001896 int rc = -1;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001897 unsigned long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001898 char *loopFile = NULL, *filteropts = NULL;
1899 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001900 struct stat st;
1901
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001902 errno = 0;
1903
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001904 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1905
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001906 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001907 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1908 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001909
Denis Vlasenko2535f122007-09-15 13:28:30 +00001910 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001911 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1912 char *args[35];
1913 char *s;
1914 int n;
1915 // fsname: "cmd#arg1#arg2..."
1916 // WARNING: allows execution of arbitrary commands!
1917 // Try "mount 'sh#-c#sh' bogus_dir".
1918 // It is safe ONLY because non-root
1919 // cannot use two-argument mount command
1920 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1921 // "mount: can't find sh#-c#sh in /etc/fstab"
1922 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1923
1924 s = mp->mnt_fsname;
1925 n = 0;
1926 args[n++] = s;
1927 while (*s && n < 35 - 2) {
1928 if (*s++ == '#' && *s != '#') {
1929 s[-1] = '\0';
1930 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001931 }
1932 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001933 args[n++] = mp->mnt_dir;
1934 args[n] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +01001935 rc = spawn_and_wait(args);
Denis Vlasenko2535f122007-09-15 13:28:30 +00001936 goto report_error;
1937 }
1938
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001939 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001940 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001941 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1942 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1943 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001944 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001945 int len;
1946 char c;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001947 char *hostname, *share;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001948 len_and_sockaddr *lsa;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001949
1950 // Parse mp->mnt_fsname of the form "//hostname/share[/dir1/dir2]"
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001951
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001952 hostname = mp->mnt_fsname + 2;
1953 len = strcspn(hostname, "/\\");
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001954 share = hostname + len + 1;
1955 if (len == 0 // 3rd char is a [back]slash (IOW: empty hostname)
1956 || share[-1] == '\0' // no [back]slash after hostname
1957 || share[0] == '\0' // empty share name
Martin Santesson406ea152013-01-16 00:47:19 +01001958 ) {
Denis Vlasenko5c329932009-04-12 12:16:21 +00001959 goto report_error;
Martin Santesson406ea152013-01-16 00:47:19 +01001960 }
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001961 c = share[-1];
1962 share[-1] = '\0';
1963 len = strcspn(share, "/\\");
Martin Santesson406ea152013-01-16 00:47:19 +01001964
1965 // "unc=\\hostname\share" option is mandatory
1966 // after CIFS option parsing was rewritten in Linux 3.4.
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001967 // Must use backslashes.
1968 // If /dir1/dir2 is present, also add "prefixpath=dir1/dir2"
Martin Santesson406ea152013-01-16 00:47:19 +01001969 {
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001970 char *unc = xasprintf(
1971 share[len] != '\0' /* "/dir1/dir2" exists? */
1972 ? "unc=\\\\%s\\%.*s,prefixpath=%s"
1973 : "unc=\\\\%s\\%.*s",
1974 hostname,
1975 len, share,
1976 share + len + 1 /* "dir1/dir2" */
1977 );
Denys Vlasenko9b7ebfe2013-01-22 11:00:45 +01001978 parse_mount_options(unc, &filteropts);
1979 if (ENABLE_FEATURE_CLEAN_UP) free(unc);
Martin Santesson406ea152013-01-16 00:47:19 +01001980 }
1981
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001982 lsa = host2sockaddr(hostname, 0);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001983 share[-1] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001984 if (!lsa)
1985 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001986
Denys Vlasenkob09ab442016-09-27 21:02:35 +02001987 // If there is no "ip=..." option yet
1988 if (!is_prefixed_with(filteropts, ",ip="+1)
1989 && !strstr(filteropts, ",ip=")
1990 ) {
1991 char *dotted, *ip;
1992 // Insert "ip=..." option into options
1993 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1994 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1995 ip = xasprintf("ip=%s", dotted);
1996 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denys Vlasenko5093c8c2016-09-26 20:36:30 +02001997// Note: IPv6 scoped addresses ("host%iface", see RFC 4007) should be
Denys Vlasenko3c18e302016-09-26 19:53:04 +02001998// handled by libc in getnameinfo() (inside xmalloc_sockaddr2dotted_noport()).
1999// Currently, glibc does not support that (has no NI_NUMERICSCOPE),
2000// musl apparently does. This results in "ip=numericIPv6%iface_name"
2001// (instead of _numeric_ iface_id) with glibc.
Denys Vlasenko5093c8c2016-09-26 20:36:30 +02002002// This probably should be fixed in glibc, not here.
Denys Vlasenkob09ab442016-09-27 21:02:35 +02002003// The workaround is to manually specify correct "ip=ADDR%n" option.
2004 parse_mount_options(ip, &filteropts);
2005 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
2006 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002007
Denis Vlasenko06c0a712007-01-29 22:51:44 +00002008 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002009 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002010
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002011 goto report_error;
2012 }
2013
2014 // Might this be an NFS filesystem?
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01002015 if ((!mp->mnt_type || is_prefixed_with(mp->mnt_type, "nfs"))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002016 && strchr(mp->mnt_fsname, ':') != NULL
2017 ) {
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01002018 if (!mp->mnt_type)
2019 mp->mnt_type = (char*)"nfs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002020 rc = nfsmount(mp, vfsflags, filteropts);
2021 goto report_error;
2022 }
2023
2024 // Look at the file. (Not found isn't a failure for remount, or for
2025 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00002026 // (We use stat, not lstat, in order to allow
2027 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00002028 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002029 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
2030 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002031 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002032 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
2033 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002034 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenkoab518ee2017-03-16 16:49:37 +01002035
2036 // mount always creates AUTOCLEARed loopdevs, so that umounting
2037 // drops them without any code in the userspace.
2038 // This happens since circa linux-2.6.25:
2039 // commit 96c5865559cee0f9cbc5173f3c949f6ce3525581
2040 // Date: Wed Feb 6 01:36:27 2008 -0800
2041 // Subject: Allow auto-destruction of loop devices
2042 loopfd = set_loop(&mp->mnt_fsname,
2043 loopFile,
2044 0,
2045 ((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0)
2046 | BB_LO_FLAGS_AUTOCLEAR
2047 );
2048 if (loopfd < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002049 if (errno == EPERM || errno == EACCES)
James Byrne69374872019-07-02 11:35:03 +02002050 bb_simple_error_msg(bb_msg_perm_denied_are_you_root);
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002051 else
James Byrne69374872019-07-02 11:35:03 +02002052 bb_simple_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00002053 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002054 }
2055
2056 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002057 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
2058 vfsflags |= MS_BIND;
2059 }
2060
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002061 // If we know the fstype (or don't need to), jump straight
2062 // to the actual mount.
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002063 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002064 char *next;
2065 for (;;) {
2066 next = mp->mnt_type ? strchr(mp->mnt_type, ',') : NULL;
2067 if (next)
2068 *next = '\0';
2069 rc = mount_it_now(mp, vfsflags, filteropts);
2070 if (rc == 0 || !next)
2071 break;
2072 mp->mnt_type = next + 1;
2073 }
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002074 } else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002075 // Loop through filesystem types until mount succeeds
2076 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002077
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01002078 // Initialize list of block backed filesystems.
2079 // This has to be done here so that during "mount -a",
2080 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002081 if (!fslist) {
2082 fslist = get_block_backed_filesystems();
2083 if (ENABLE_FEATURE_CLEAN_UP && fslist)
2084 atexit(delete_block_backed_filesystems);
2085 }
2086
2087 for (fl = fslist; fl; fl = fl->link) {
2088 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00002089 rc = mount_it_now(mp, vfsflags, filteropts);
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002090 if (rc == 0)
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02002091 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002092 }
2093 }
2094
2095 // If mount failed, clean up loop file (if any).
Denys Vlasenkoab518ee2017-03-16 16:49:37 +01002096 // (Newer kernels which support LO_FLAGS_AUTOCLEAR should not need this,
2097 // merely "close(loopfd)" should do it?)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002098 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
2099 del_loop(mp->mnt_fsname);
2100 if (ENABLE_FEATURE_CLEAN_UP) {
2101 free(loopFile);
Denys Vlasenkoecf25cb2016-06-20 11:04:04 +02002102 /* No, "rc != 0" needs it: free(mp->mnt_fsname); */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002103 }
2104 }
2105
Denis Vlasenko5870ad92007-02-04 02:39:55 +00002106 report_error:
2107 if (ENABLE_FEATURE_CLEAN_UP)
2108 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002109
Denys Vlasenkoab518ee2017-03-16 16:49:37 +01002110 if (loopfd >= 0)
2111 close(loopfd);
2112
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00002113 if (errno == EBUSY && ignore_busy)
2114 return 0;
Denys Vlasenko911d2652015-12-30 20:11:34 +01002115 if (errno == ENOENT && (vfsflags & MOUNT_NOFAIL))
2116 return 0;
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002117 if (rc != 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002118 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002119 return rc;
2120}
2121
Michael Abbott6b5accb2009-12-04 03:33:07 +01002122// -O support
2123// -O interprets a list of filter options which select whether a mount
2124// point will be mounted: only mounts with options matching *all* filtering
2125// options will be selected.
2126// By default each -O filter option must be present in the list of mount
2127// options, but if it is prefixed by "no" then it must be absent.
2128// For example,
2129// -O a,nob,c matches -o a,c but fails to match -o a,b,c
2130// (and also fails to match -o a because -o c is absent).
2131//
2132// It is different from -t in that each option is matched exactly; a leading
2133// "no" at the beginning of one option does not negate the rest.
2134static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002135{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002136 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01002137 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002138
Michael Abbott6b5accb2009-12-04 03:33:07 +01002139 while (*O_opt) {
2140 const char *fs_opt = fs_opt_in;
2141 int O_len;
2142 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002143
Michael Abbott6b5accb2009-12-04 03:33:07 +01002144 // If option begins with "no" then treat as an inverted match:
2145 // matching is a failure
2146 match = 0;
2147 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
2148 match = 1;
2149 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002150 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002151 // Isolate the current O option
2152 O_len = strchrnul(O_opt, ',') - O_opt;
2153 // Check for a match against existing options
2154 while (1) {
2155 if (strncmp(fs_opt, O_opt, O_len) == 0
2156 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
2157 ) {
2158 if (match)
2159 return 0; // "no" prefix, but option found
2160 match = 1; // current O option found, go check next one
2161 break;
2162 }
2163 fs_opt = strchr(fs_opt, ',');
2164 if (!fs_opt)
2165 break;
2166 fs_opt++;
2167 }
2168 if (match == 0)
2169 return 0; // match wanted but not found
2170 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002171 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01002172 // Step to the next O option
2173 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002174 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002175 // If we get here then everything matched
2176 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002177}
2178
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002179// Parse options, if necessary parse fstab/mtab, and call singlemount for
2180// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002181int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002182int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002183{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002184 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002185 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002186 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002187 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002188 llist_t *lst_o = NULL;
Isaac Dunham7b434a62015-03-11 16:07:24 +01002189 const char *fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002190 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002191 int i, j;
2192 int rc = EXIT_SUCCESS;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002193 unsigned long cmdopt_flags;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002194 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002195 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002196 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002197
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002198 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00002199
Denys Vlasenko16714242011-09-21 01:59:15 +02002200 INIT_G();
2201
Denis Vlasenkof732e962008-02-18 12:07:49 +00002202 // Parse long options, like --bind and --move. Note that -o option
2203 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002204 for (i = j = 1; argv[i]; i++) {
2205 if (argv[i][0] == '-' && argv[i][1] == '-')
2206 append_mount_options(&cmdopts, argv[i] + 2);
2207 else
2208 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002209 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002210 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002211
2212 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002213 // Max 2 params; -o is a list, -v is a counter
Denys Vlasenko22542ec2017-08-08 21:55:02 +02002214 opt = getopt32(argv, "^"
2215 OPTION_STR
2216 "\0" "?2"IF_FEATURE_MOUNT_VERBOSE("vv"),
2217 &lst_o, &fstype, &O_optmatch
2218 IF_FEATURE_MOUNT_OTHERTAB(, &fstabname)
2219 IF_FEATURE_MOUNT_VERBOSE(, &verbose)
2220 );
2221
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002222 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00002223 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
2224 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00002225 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002226
2227 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002228 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00002229 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002230 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
2231
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002232 if (!mountTable)
2233 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002234
Denis Vlasenko2535f122007-09-15 13:28:30 +00002235 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002236 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002237 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002238 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00002239 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002240 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002241
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002242 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002243 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
2244 mtpair->mnt_dir, mtpair->mnt_type,
2245 mtpair->mnt_opts);
2246 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002247 if (ENABLE_FEATURE_CLEAN_UP)
2248 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002249 return EXIT_SUCCESS;
2250 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002251 storage_path = NULL;
2252 } else {
2253 // When we have two arguments, the second is the directory and we can
2254 // skip looking at fstab entirely. We can always abspath() the directory
2255 // argument when we get it.
2256 if (argv[1]) {
2257 if (nonroot)
James Byrne69374872019-07-02 11:35:03 +02002258 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002259 mtpair->mnt_fsname = argv[0];
2260 mtpair->mnt_dir = argv[1];
2261 mtpair->mnt_type = fstype;
2262 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002263 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002264 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002265 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00002266 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002267 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002268 }
2269
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002270 // Past this point, we are handling either "mount -a [opts]"
2271 // or "mount [opts] single_param"
2272
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002273 cmdopt_flags = parse_mount_options(cmdopts, NULL);
2274 if (nonroot && (cmdopt_flags & ~MS_SILENT)) // Non-root users cannot specify flags
James Byrne69374872019-07-02 11:35:03 +02002275 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00002276
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002277 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002278 if (ENABLE_FEATURE_MOUNT_FLAGS
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002279 && (cmdopt_flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002280 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002281 // verbose_mount(source, target, type, flags, data)
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002282 rc = verbose_mount("", argv[0], "", cmdopt_flags, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002283 if (rc)
2284 bb_simple_perror_msg_and_die(argv[0]);
2285 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002286 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002287
Isaac Dunham7b434a62015-03-11 16:07:24 +01002288 // A malicious user could overmount /usr without this.
2289 if (ENABLE_FEATURE_MOUNT_OTHERTAB && nonroot)
2290 fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002291 // Open either fstab or mtab
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002292 if (cmdopt_flags & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002293 // WARNING. I am not sure this matches util-linux's
2294 // behavior. It's possible util-linux does not
2295 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002296 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002297 }
2298 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00002299 if (!fstab)
Denys Vlasenko651a2692010-03-23 16:25:17 +01002300 bb_perror_msg_and_die("can't read '%s'", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002301
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002302 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00002303 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002304 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002305 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002306
2307 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00002308 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002309 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002310 GETMNTENT_BUFSIZE/2)
2311 ) { // End of fstab/mtab is reached
2312 mtcur = mtother; // the thing we found last time
2313 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002314 }
2315
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002316 // If we're trying to mount something specific and this isn't it,
2317 // skip it. Note we must match the exact text in fstab (ala
2318 // "proc") or a full path from root
2319 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002320
2321 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002322 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
2323 && strcmp(storage_path, mtcur->mnt_fsname) != 0
2324 && strcmp(argv[0], mtcur->mnt_dir) != 0
2325 && strcmp(storage_path, mtcur->mnt_dir) != 0
2326 ) {
2327 continue; // no
2328 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002329
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002330 // Remember this entry. Something later may have
2331 // overmounted it, and we want the _last_ match.
2332 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002333
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002334 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002335 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002336 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002337 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002338 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002339 if (nonroot)
James Byrne69374872019-07-02 11:35:03 +02002340 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002341
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002342 // Does type match? (NULL matches always)
Denys Vlasenko35b54a32017-01-30 00:45:05 +01002343 if (!fstype_matches(mtcur->mnt_type, fstype))
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002344 continue;
2345
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002346 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002347 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
2348 // swap is bogus "fstype", parse_mount_options can't check fstypes
2349 || strcasecmp(mtcur->mnt_type, "swap") == 0
2350 ) {
2351 continue;
2352 }
2353
2354 // Does (at least one) option match?
2355 // (NULL matches always)
2356 if (!match_opt(mtcur->mnt_opts, O_optmatch))
2357 continue;
2358
2359 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002360
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002361 // NFS mounts want this to be xrealloc-able
2362 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002363
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002364 // If nothing is mounted on this directory...
2365 // (otherwise repeated "mount -a" mounts everything again)
2366 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2367 // We do not check fsname match of found mount point -
2368 // "/" may have fsname of "/dev/root" while fstab
2369 // says "/dev/something_else".
2370 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01002371 if (verbose) {
2372 bb_error_msg("according to %s, "
2373 "%s is already mounted on %s",
2374 bb_path_mtab_file,
2375 mp->mnt_fsname, mp->mnt_dir);
2376 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002377 } else {
2378 // ...mount this thing
2379 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2380 // Count number of failed mounts
2381 rc++;
2382 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002383 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002384 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002385 }
2386 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002387
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002388 // End of fstab/mtab is reached.
2389 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002390 if (argv[0]) { // yes
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002391 unsigned long l;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002392
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002393 // If we didn't find anything, complain
2394 if (!mtcur->mnt_fsname)
2395 bb_error_msg_and_die("can't find %s in %s",
2396 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002397
2398 // What happens when we try to "mount swap_partition"?
2399 // (fstab containts "swap_partition swap swap defaults 0 0")
2400 // util-linux-ng 2.13.1 does this:
2401 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2402 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2403 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2404 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2405 // exit_group(32) = ?
2406#if 0
2407 // In case we want to simply skip swap partitions:
2408 l = parse_mount_options(mtcur->mnt_opts, NULL);
2409 if ((l & MOUNT_SWAP)
2410 // swap is bogus "fstype", parse_mount_options can't check fstypes
2411 || strcasecmp(mtcur->mnt_type, "swap") == 0
2412 ) {
2413 goto ret;
2414 }
2415#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002416 if (nonroot) {
2417 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002418 l = parse_mount_options(mtcur->mnt_opts, NULL);
2419 if (!(l & MOUNT_USERS))
James Byrne69374872019-07-02 11:35:03 +02002420 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002421 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002422
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002423 //util-linux-2.12 does not do this check.
2424 //// If nothing is mounted on this directory...
2425 //// (otherwise repeated "mount FOO" mounts FOO again)
2426 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2427 //if (mp) {
2428 // bb_error_msg("according to %s, "
2429 // "%s is already mounted on %s",
2430 // bb_path_mtab_file,
2431 // mp->mnt_fsname, mp->mnt_dir);
2432 //} else {
2433 // ...mount the last thing we found
2434 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2435 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2436 resolve_mount_spec(&mtpair->mnt_fsname);
2437 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2438 if (ENABLE_FEATURE_CLEAN_UP)
2439 free(mtcur->mnt_opts);
2440 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002441 }
2442
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002443 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002444 if (ENABLE_FEATURE_CLEAN_UP)
2445 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002446 if (ENABLE_FEATURE_CLEAN_UP) {
2447 free(storage_path);
2448 free(cmdopts);
2449 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002450
2451//TODO: exitcode should be ORed mask of (from "man mount"):
2452// 0 success
2453// 1 incorrect invocation or permissions
2454// 2 system error (out of memory, cannot fork, no more loop devices)
2455// 4 internal mount bug or missing nfs support in mount
2456// 8 user interrupt
2457//16 problems writing or locking /etc/mtab
2458//32 mount failure
2459//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002460 return rc;
2461}