blob: 13590ceb41909202a05db8ffafca4ae1c686bc6b [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002/*
Eric Andersen596e5461999-10-07 08:30:23 +00003 * Mini mount implementation for busybox
4 *
Eric Andersenc4996011999-10-20 22:08:37 +00005 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00006 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Rob Landleydc0955b2006-03-14 18:16:25 +00007 * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
Eric Andersen596e5461999-10-07 08:30:23 +00008 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02009 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Erik Andersenb7cc49d2000-01-13 06:38:14 +000010 */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +000011// Design notes: There is no spec for mount. Remind me to write one.
12//
13// mount_main() calls singlemount() which calls mount_it_now().
14//
15// mount_main() can loop through /etc/fstab for mount -a
16// singlemount() can loop through /etc/filesystems for fstype detection.
17// mount_it_now() does the actual mount.
18//
Pere Orga5bc8c002011-04-11 03:29:49 +020019
Isaac Dunham7b434a62015-03-11 16:07:24 +010020//config:config MOUNT
21//config: bool "mount"
22//config: default y
23//config: select PLATFORM_LINUX
24//config: help
25//config: All files and filesystems in Unix are arranged into one big directory
26//config: tree. The 'mount' utility is used to graft a filesystem onto a
27//config: particular part of the tree. A filesystem can either live on a block
28//config: device, or it can be accessible over the network, as is the case with
29//config: NFS filesystems. Most people using BusyBox will also want to enable
30//config: the 'mount' utility.
31//config:
32//config:config FEATURE_MOUNT_FAKE
33//config: bool "Support option -f"
34//config: default y
35//config: depends on MOUNT
36//config: help
37//config: Enable support for faking a file system mount.
38//config:
39//config:config FEATURE_MOUNT_VERBOSE
40//config: bool "Support option -v"
41//config: default y
42//config: depends on MOUNT
43//config: help
44//config: Enable multi-level -v[vv...] verbose messages. Useful if you
45//config: debug mount problems and want to see what is exactly passed
46//config: to the kernel.
47//config:
48//config:config FEATURE_MOUNT_HELPERS
49//config: bool "Support mount helpers"
50//config: default n
51//config: depends on MOUNT
52//config: help
53//config: Enable mounting of virtual file systems via external helpers.
54//config: E.g. "mount obexfs#-b00.11.22.33.44.55 /mnt" will in effect call
55//config: "obexfs -b00.11.22.33.44.55 /mnt"
56//config: Also "mount -t sometype [-o opts] fs /mnt" will try
57//config: "sometype [-o opts] fs /mnt" if simple mount syscall fails.
58//config: The idea is to use such virtual filesystems in /etc/fstab.
59//config:
60//config:config FEATURE_MOUNT_LABEL
61//config: bool "Support specifying devices by label or UUID"
62//config: default y
63//config: depends on MOUNT
64//config: select VOLUMEID
65//config: help
66//config: This allows for specifying a device by label or uuid, rather than by
67//config: name. This feature utilizes the same functionality as blkid/findfs.
68//config: This also enables label or uuid support for swapon.
69//config:
70//config:config FEATURE_MOUNT_NFS
71//config: bool "Support mounting NFS file systems on Linux < 2.6.23"
72//config: default n
73//config: depends on MOUNT
74//config: select FEATURE_HAVE_RPC
75//config: select FEATURE_SYSLOG
76//config: help
77//config: Enable mounting of NFS file systems on Linux kernels prior
78//config: to version 2.6.23. Note that in this case mounting of NFS
79//config: over IPv6 will not be possible.
80//config:
81//config: Note that this option links in RPC support from libc,
82//config: which is rather large (~10 kbytes on uclibc).
83//config:
84//config:config FEATURE_MOUNT_CIFS
85//config: bool "Support mounting CIFS/SMB file systems"
86//config: default y
87//config: depends on MOUNT
88//config: help
89//config: Enable support for samba mounts.
90//config:
91//config:config FEATURE_MOUNT_FLAGS
92//config: depends on MOUNT
93//config: bool "Support lots of -o flags in mount"
94//config: default y
95//config: help
96//config: Without this, mount only supports ro/rw/remount. With this, it
97//config: supports nosuid, suid, dev, nodev, exec, noexec, sync, async, atime,
98//config: noatime, diratime, nodiratime, loud, bind, move, shared, slave,
99//config: private, unbindable, rshared, rslave, rprivate, and runbindable.
100//config:
101//config:config FEATURE_MOUNT_FSTAB
102//config: depends on MOUNT
103//config: bool "Support /etc/fstab and -a"
104//config: default y
105//config: help
106//config: Support mount all and looking for files in /etc/fstab.
107//config:
108//config:config FEATURE_MOUNT_OTHERTAB
109//config: depends on FEATURE_MOUNT_FSTAB
110//config: bool "Support -T <alt_fstab>"
111//config: default y
112//config: help
113//config: Support mount -T (specifying an alternate fstab)
114
Pere Orga5bc8c002011-04-11 03:29:49 +0200115//usage:#define mount_trivial_usage
Isaac Dunham7b434a62015-03-11 16:07:24 +0100116//usage: "[OPTIONS] [-o OPT] DEVICE NODE"
Pere Orga5bc8c002011-04-11 03:29:49 +0200117//usage:#define mount_full_usage "\n\n"
118//usage: "Mount a filesystem. Filesystem autodetection requires /proc.\n"
Pere Orga5bc8c002011-04-11 03:29:49 +0200119//usage: "\n -a Mount all filesystems in fstab"
120//usage: IF_FEATURE_MOUNT_FAKE(
121//usage: IF_FEATURE_MTAB_SUPPORT(
122//usage: "\n -f Update /etc/mtab, but don't mount"
123//usage: )
124//usage: IF_NOT_FEATURE_MTAB_SUPPORT(
125//usage: "\n -f Dry run"
126//usage: )
127//usage: )
128//usage: IF_FEATURE_MOUNT_HELPERS(
129//usage: "\n -i Don't run mount helper"
130//usage: )
131//usage: IF_FEATURE_MTAB_SUPPORT(
132//usage: "\n -n Don't update /etc/mtab"
133//usage: )
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100134//usage: IF_FEATURE_MOUNT_VERBOSE(
135//usage: "\n -v Verbose"
136//usage: )
137////usage: "\n -s Sloppy (ignored)"
Pere Orga5bc8c002011-04-11 03:29:49 +0200138//usage: "\n -r Read-only mount"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100139////usage: "\n -w Read-write mount (default)"
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +0100140//usage: "\n -t FSTYPE[,...] Filesystem type(s)"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100141//usage: IF_FEATURE_MOUNT_OTHERTAB(
142//usage: "\n -T FILE Read FILE instead of /etc/fstab"
143//usage: )
Pere Orga5bc8c002011-04-11 03:29:49 +0200144//usage: "\n -O OPT Mount only filesystems with option OPT (-a only)"
145//usage: "\n-o OPT:"
146//usage: IF_FEATURE_MOUNT_LOOP(
147//usage: "\n loop Ignored (loop devices are autodetected)"
148//usage: )
149//usage: IF_FEATURE_MOUNT_FLAGS(
150//usage: "\n [a]sync Writes are [a]synchronous"
151//usage: "\n [no]atime Disable/enable updates to inode access times"
152//usage: "\n [no]diratime Disable/enable atime updates to directories"
153//usage: "\n [no]relatime Disable/enable atime updates relative to modification time"
154//usage: "\n [no]dev (Dis)allow use of special device files"
155//usage: "\n [no]exec (Dis)allow use of executable files"
156//usage: "\n [no]suid (Dis)allow set-user-id-root programs"
157//usage: "\n [r]shared Convert [recursively] to a shared subtree"
158//usage: "\n [r]slave Convert [recursively] to a slave subtree"
159//usage: "\n [r]private Convert [recursively] to a private subtree"
160//usage: "\n [un]bindable Make mount point [un]able to be bind mounted"
161//usage: "\n [r]bind Bind a file or directory [recursively] to another location"
162//usage: "\n move Relocate an existing mount point"
163//usage: )
164//usage: "\n remount Remount a mounted filesystem, changing flags"
Isaac Dunham7b434a62015-03-11 16:07:24 +0100165//usage: "\n ro Same as -r"
Pere Orga5bc8c002011-04-11 03:29:49 +0200166//usage: "\n"
167//usage: "\nThere are filesystem-specific -o flags."
168//usage:
169//usage:#define mount_example_usage
170//usage: "$ mount\n"
171//usage: "/dev/hda3 on / type minix (rw)\n"
172//usage: "proc on /proc type proc (rw)\n"
173//usage: "devpts on /dev/pts type devpts (rw)\n"
174//usage: "$ mount /dev/fd0 /mnt -t msdos -o ro\n"
175//usage: "$ mount /tmp/diskimage /opt -t ext2 -o loop\n"
176//usage: "$ mount cd_image.iso mydir\n"
177//usage:#define mount_notes_usage
178//usage: "Returns 0 for success, number of failed mounts for -a, or errno for one mount."
179
Eric Andersencc8ed391999-10-05 16:24:54 +0000180#include <mntent.h>
Bernhard Reutner-Fischerf4701962008-01-27 12:50:12 +0000181#include <syslog.h>
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200182#include <sys/mount.h>
Denys Vlasenko102ff762009-11-21 17:14:08 +0100183// Grab more as needed from util-linux's mount/mount_constants.h
184#ifndef MS_DIRSYNC
185# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
186#endif
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200187#ifndef MS_UNION
188# define MS_UNION (1 << 8)
189#endif
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200190#ifndef MS_BIND
191# define MS_BIND (1 << 12)
192#endif
193#ifndef MS_MOVE
194# define MS_MOVE (1 << 13)
195#endif
196#ifndef MS_RECURSIVE
197# define MS_RECURSIVE (1 << 14)
198#endif
199#ifndef MS_SILENT
200# define MS_SILENT (1 << 15)
201#endif
Denys Vlasenko102ff762009-11-21 17:14:08 +0100202// The shared subtree stuff, which went in around 2.6.15
Denys Vlasenkoda49f582009-07-08 02:58:38 +0200203#ifndef MS_UNBINDABLE
204# define MS_UNBINDABLE (1 << 17)
205#endif
206#ifndef MS_PRIVATE
207# define MS_PRIVATE (1 << 18)
208#endif
209#ifndef MS_SLAVE
210# define MS_SLAVE (1 << 19)
211#endif
212#ifndef MS_SHARED
213# define MS_SHARED (1 << 20)
214#endif
215#ifndef MS_RELATIME
216# define MS_RELATIME (1 << 21)
217#endif
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200218#ifndef MS_STRICTATIME
219# define MS_STRICTATIME (1 << 24)
220#endif
221
222/* Any ~MS_FOO value has this bit set: */
223#define BB_MS_INVERTED_VALUE (1u << 31)
Eric Andersenbd22ed82000-07-08 18:55:24 +0000224
Denys Vlasenko102ff762009-11-21 17:14:08 +0100225#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200226#include "common_bufsiz.h"
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000227#if ENABLE_FEATURE_MOUNT_LABEL
Natanael Copa9aff2992009-09-20 04:28:22 +0200228# include "volume_id.h"
229#else
230# define resolve_mount_spec(fsname) ((void)0)
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000231#endif
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000232
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000233// Needed for nfs support only
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000234#include <sys/utsname.h>
235#undef TRUE
236#undef FALSE
Denys Vlasenkocc428142009-12-16 02:06:56 +0100237#if ENABLE_FEATURE_MOUNT_NFS
238/* This is just a warning of a common mistake. Possibly this should be a
239 * uclibc faq entry rather than in busybox... */
240# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
241# error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
242# endif
243# include <rpc/rpc.h>
244# include <rpc/pmap_prot.h>
245# include <rpc/pmap_clnt.h>
246#endif
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000247
248
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000249#if defined(__dietlibc__)
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000250// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
251// dietlibc-0.30 does not have implementation of getmntent_r()
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000252static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000253 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000254{
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000255 struct mntent* ment = getmntent(stream);
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000256 return memcpy(result, ment, sizeof(*ment));
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000257}
258#endif
259
260
Rob Landleydc0955b2006-03-14 18:16:25 +0000261// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000262enum {
Denys Vlasenko911d2652015-12-30 20:11:34 +0100263 MOUNT_USERS = (1 << 27) * ENABLE_DESKTOP,
264 MOUNT_NOFAIL = (1 << 28) * ENABLE_DESKTOP,
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000265 MOUNT_NOAUTO = (1 << 29),
266 MOUNT_SWAP = (1 << 30),
Denys Vlasenko911d2652015-12-30 20:11:34 +0100267 MOUNT_FAKEFLAGS = MOUNT_USERS | MOUNT_NOFAIL | MOUNT_NOAUTO | MOUNT_SWAP
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000268};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000269
270
Denys Vlasenko237bedd2016-07-06 21:58:02 +0200271#define OPTION_STR "o:*t:rwanfvsiO:" IF_FEATURE_MOUNT_OTHERTAB("T:")
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000272enum {
273 OPT_o = (1 << 0),
274 OPT_t = (1 << 1),
275 OPT_r = (1 << 2),
276 OPT_w = (1 << 3),
277 OPT_a = (1 << 4),
278 OPT_n = (1 << 5),
279 OPT_f = (1 << 6),
280 OPT_v = (1 << 7),
281 OPT_s = (1 << 8),
282 OPT_i = (1 << 9),
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000283 OPT_O = (1 << 10),
Isaac Dunham7b434a62015-03-11 16:07:24 +0100284 OPT_T = (1 << 11),
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000285};
286
287#if ENABLE_FEATURE_MTAB_SUPPORT
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200288#define USE_MTAB (!(option_mask32 & OPT_n))
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000289#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200290#define USE_MTAB 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000291#endif
292
293#if ENABLE_FEATURE_MOUNT_FAKE
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200294#define FAKE_IT (option_mask32 & OPT_f)
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000295#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200296#define FAKE_IT 0
297#endif
298
299#if ENABLE_FEATURE_MOUNT_HELPERS
300#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
301#else
302#define HELPERS_ALLOWED 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000303#endif
304
305
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000306// TODO: more "user" flag compatibility.
307// "user" option (from mount manpage):
308// Only the user that mounted a filesystem can unmount it again.
309// If any user should be able to unmount, then use users instead of user
310// in the fstab line. The owner option is similar to the user option,
311// with the restriction that the user must be the owner of the special file.
312// This may be useful e.g. for /dev/fd if a login script makes
313// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000314
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000315// Standard mount options (from -o options or --options),
316// with corresponding flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000317static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000318 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000319
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000320 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000321 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000322 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000323
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000324 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000325 /* "defaults" */ 0,
326 /* "quiet" 0 - do not filter out, vfat wants to see it */
327 /* "noauto" */ MOUNT_NOAUTO,
328 /* "sw" */ MOUNT_SWAP,
329 /* "swap" */ MOUNT_SWAP,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000330 IF_DESKTOP(/* "user" */ MOUNT_USERS,)
331 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
Denys Vlasenko911d2652015-12-30 20:11:34 +0100332 IF_DESKTOP(/* "nofail" */ MOUNT_NOFAIL,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000333 /* "_netdev" */ 0,
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100334 IF_DESKTOP(/* "comment=" */ 0,) /* systemd uses this in fstab */
Rob Landleye3781b72006-08-08 01:39:49 +0000335 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000336
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000337 IF_FEATURE_MOUNT_FLAGS(
Rob Landleye3781b72006-08-08 01:39:49 +0000338 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000339 /* "nosuid" */ MS_NOSUID,
340 /* "suid" */ ~MS_NOSUID,
341 /* "dev" */ ~MS_NODEV,
342 /* "nodev" */ MS_NODEV,
343 /* "exec" */ ~MS_NOEXEC,
344 /* "noexec" */ MS_NOEXEC,
345 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000346 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000347 /* "async" */ ~MS_SYNCHRONOUS,
348 /* "atime" */ ~MS_NOATIME,
349 /* "noatime" */ MS_NOATIME,
350 /* "diratime" */ ~MS_NODIRATIME,
351 /* "nodiratime" */ MS_NODIRATIME,
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000352 /* "mand" */ MS_MANDLOCK,
353 /* "nomand" */ ~MS_MANDLOCK,
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000354 /* "relatime" */ MS_RELATIME,
355 /* "norelatime" */ ~MS_RELATIME,
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200356 /* "strictatime" */ MS_STRICTATIME,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000357 /* "loud" */ ~MS_SILENT,
Roman Borisov19311bf2011-03-24 15:08:43 +0300358 /* "rbind" */ MS_BIND|MS_RECURSIVE,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000359
Rob Landleye3781b72006-08-08 01:39:49 +0000360 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200361 /* "union" */ MS_UNION,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000362 /* "bind" */ MS_BIND,
363 /* "move" */ MS_MOVE,
364 /* "shared" */ MS_SHARED,
365 /* "slave" */ MS_SLAVE,
366 /* "private" */ MS_PRIVATE,
367 /* "unbindable" */ MS_UNBINDABLE,
368 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
369 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
Roman Borisovd3679d22011-03-23 11:20:25 +0300370 /* "rprivate" */ MS_PRIVATE|MS_RECURSIVE,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000371 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000372 )
373
374 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000375 /* "ro" */ MS_RDONLY, // vfs flag
376 /* "rw" */ ~MS_RDONLY, // vfs flag
377 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000378};
379
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200380static const char mount_option_str[] ALIGN1 =
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000381 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000382 "loop\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000383 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000384 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000385 "defaults\0"
386 // "quiet\0" - do not filter out, vfat wants to see it
387 "noauto\0"
388 "sw\0"
389 "swap\0"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000390 IF_DESKTOP("user\0")
391 IF_DESKTOP("users\0")
Denys Vlasenko911d2652015-12-30 20:11:34 +0100392 IF_DESKTOP("nofail\0")
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000393 "_netdev\0"
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100394 IF_DESKTOP("comment=\0") /* systemd uses this in fstab */
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000395 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000396 IF_FEATURE_MOUNT_FLAGS(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000397 // vfs flags
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000398 "nosuid\0"
399 "suid\0"
400 "dev\0"
401 "nodev\0"
402 "exec\0"
403 "noexec\0"
404 "sync\0"
405 "dirsync\0"
406 "async\0"
407 "atime\0"
408 "noatime\0"
409 "diratime\0"
410 "nodiratime\0"
411 "mand\0"
412 "nomand\0"
413 "relatime\0"
414 "norelatime\0"
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200415 "strictatime\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000416 "loud\0"
Roman Borisov19311bf2011-03-24 15:08:43 +0300417 "rbind\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000418
419 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200420 "union\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000421 "bind\0"
422 "move\0"
Roman Borisov945fd172011-02-25 14:50:39 +0300423 "make-shared\0"
424 "make-slave\0"
425 "make-private\0"
426 "make-unbindable\0"
427 "make-rshared\0"
428 "make-rslave\0"
429 "make-rprivate\0"
430 "make-runbindable\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000431 )
432
433 // Always understood.
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000434 "ro\0" // vfs flag
435 "rw\0" // vfs flag
436 "remount\0" // action flag
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000437;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000438
Denis Vlasenkof732e962008-02-18 12:07:49 +0000439
440struct globals {
441#if ENABLE_FEATURE_MOUNT_NFS
442 smalluint nfs_mount_version;
443#endif
444#if ENABLE_FEATURE_MOUNT_VERBOSE
445 unsigned verbose;
446#endif
447 llist_t *fslist;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000448 char getmntent_buf[1];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100449} FIX_ALIASING;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000450enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200451#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenkof732e962008-02-18 12:07:49 +0000452#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000453#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000454#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000455#else
456#define verbose 0
457#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000458#define fslist (G.fslist )
459#define getmntent_buf (G.getmntent_buf )
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200460#define INIT_G() do { setup_common_bufsiz(); } while (0)
Denis Vlasenkof732e962008-02-18 12:07:49 +0000461
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100462#if ENABLE_FEATURE_MTAB_SUPPORT
463/*
464 * update_mtab_entry_on_move() is used to update entry in case of mount --move.
465 * we are looking for existing entries mnt_dir which is equal to mnt_fsname of
466 * input mntent and replace it by new one.
467 */
468static void FAST_FUNC update_mtab_entry_on_move(const struct mntent *mp)
469{
470 struct mntent *entries, *m;
471 int i, count;
472 FILE *mountTable;
473
474 mountTable = setmntent(bb_path_mtab_file, "r");
475 if (!mountTable) {
476 bb_perror_msg(bb_path_mtab_file);
477 return;
478 }
479
480 entries = NULL;
481 count = 0;
482 while ((m = getmntent(mountTable)) != NULL) {
483 entries = xrealloc_vector(entries, 3, count);
484 entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
485 entries[count].mnt_dir = xstrdup(m->mnt_dir);
486 entries[count].mnt_type = xstrdup(m->mnt_type);
487 entries[count].mnt_opts = xstrdup(m->mnt_opts);
488 entries[count].mnt_freq = m->mnt_freq;
489 entries[count].mnt_passno = m->mnt_passno;
490 count++;
491 }
492 endmntent(mountTable);
493
494 mountTable = setmntent(bb_path_mtab_file, "w");
495 if (mountTable) {
496 for (i = 0; i < count; i++) {
497 if (strcmp(entries[i].mnt_dir, mp->mnt_fsname) != 0)
498 addmntent(mountTable, &entries[i]);
499 else
500 addmntent(mountTable, mp);
501 }
502 endmntent(mountTable);
503 } else if (errno != EROFS)
504 bb_perror_msg(bb_path_mtab_file);
505
506 if (ENABLE_FEATURE_CLEAN_UP) {
507 for (i = 0; i < count; i++) {
508 free(entries[i].mnt_fsname);
509 free(entries[i].mnt_dir);
510 free(entries[i].mnt_type);
511 free(entries[i].mnt_opts);
512 }
513 free(entries);
514 }
515}
516#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000517
518#if ENABLE_FEATURE_MOUNT_VERBOSE
519static int verbose_mount(const char *source, const char *target,
520 const char *filesystemtype,
521 unsigned long mountflags, const void *data)
522{
523 int rc;
524
525 errno = 0;
526 rc = mount(source, target, filesystemtype, mountflags, data);
527 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000528 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000529 source, target, filesystemtype,
530 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000531 return rc;
532}
533#else
534#define verbose_mount(...) mount(__VA_ARGS__)
535#endif
536
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000537// Append mount options to string
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000538static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000539{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000540 if (*oldopts && **oldopts) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000541 // Do not insert options which are already there
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000542 while (newopts[0]) {
543 char *p;
544 int len = strlen(newopts);
545 p = strchr(newopts, ',');
546 if (p) len = p - newopts;
547 p = *oldopts;
548 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000549 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000550 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000551 goto skip;
552 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000553 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000554 p++;
555 }
556 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
557 free(*oldopts);
558 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000559 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000560 newopts += len;
561 while (newopts[0] == ',') newopts++;
562 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000563 } else {
564 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000565 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000566 }
567}
568
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000569// Use the mount_options list to parse options into flags.
Alexander Shishkin77650952010-10-28 06:10:03 +0200570// Also update list of unrecognized options if unrecognized != NULL
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200571static unsigned long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000572{
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200573 unsigned long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000574
Rob Landley6a6798b2005-08-10 20:35:54 +0000575 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000576 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000577 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000578 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000579 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000580
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000581 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000582
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000583// FIXME: use hasmntopt()
Rob Landley6a6798b2005-08-10 20:35:54 +0000584 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000585 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200586 unsigned opt_len = strlen(option_str);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100587
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200588 if (strncasecmp(option_str, options, opt_len) == 0
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100589 && (options[opt_len] == '\0'
590 /* or is it "comment=" thingy in fstab? */
591 IF_FEATURE_MOUNT_FSTAB(IF_DESKTOP( || option_str[opt_len-1] == '=' ))
592 )
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200593 ) {
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200594 unsigned long fl = mount_options[i];
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200595 if (fl & BB_MS_INVERTED_VALUE)
Alexander Shishkin77650952010-10-28 06:10:03 +0200596 flags &= fl;
597 else
598 flags |= fl;
599 goto found;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000600 }
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200601 option_str += opt_len + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000602 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200603 // We did not recognize this option.
604 // If "unrecognized" is not NULL, append option there.
605 // Note that we should not append *empty* option -
606 // in this case we want to pass NULL, not "", to "data"
607 // parameter of mount(2) syscall.
608 // This is crucial for filesystems that don't accept
609 // any arbitrary mount options, like cgroup fs:
610 // "mount -t cgroup none /mnt"
611 if (options[0] && unrecognized) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000612 // Add it to strflags, to pass on to kernel
Alexander Shishkin77650952010-10-28 06:10:03 +0200613 char *p = *unrecognized;
614 unsigned len = p ? strlen(p) : 0;
615 *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000616
Rob Landley6a6798b2005-08-10 20:35:54 +0000617 // Comma separated if it's not the first one
Alexander Shishkin77650952010-10-28 06:10:03 +0200618 if (len) p[len++] = ',';
619 strcpy(p + len, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000620 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200621 found:
Denis Vlasenko2535f122007-09-15 13:28:30 +0000622 if (!comma)
623 break;
624 // Advance to next option
625 *comma = ',';
626 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000627 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000628
Rob Landleydc0955b2006-03-14 18:16:25 +0000629 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000630}
631
Rob Landleydc0955b2006-03-14 18:16:25 +0000632// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000633static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000634{
Denis Vlasenko87468852007-04-13 23:22:00 +0000635 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000636 "/etc/filesystems",
637 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000638 };
639 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200640 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000641 int i;
642 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000643
Denis Vlasenko87468852007-04-13 23:22:00 +0000644 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000645 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000646 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000647
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000648 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100649 if (is_prefixed_with(buf, "nodev") && isspace(buf[5]))
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100650 goto next;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000651 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200652 if (*fs == '#' || *fs == '*' || !*fs)
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100653 goto next;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000654
Denis Vlasenko372686b2006-10-12 22:42:33 +0000655 llist_add_to_end(&list, xstrdup(fs));
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100656 next:
Denis Vlasenko372686b2006-10-12 22:42:33 +0000657 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000658 }
659 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
660 }
661
662 return list;
663}
664
Rob Landleydc0955b2006-03-14 18:16:25 +0000665#if ENABLE_FEATURE_CLEAN_UP
666static void delete_block_backed_filesystems(void)
667{
Rob Landleya6b5b602006-05-08 19:03:07 +0000668 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000669}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000670#else
671void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000672#endif
673
Rob Landleydc0955b2006-03-14 18:16:25 +0000674// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000675// NB: mp->xxx fields may be trashed on exit
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200676static int mount_it_now(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000677{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000678 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000679
Denys Vlasenko911d2652015-12-30 20:11:34 +0100680 vfsflags &= ~(unsigned long)MOUNT_FAKEFLAGS;
681
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200682 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000683 if (verbose >= 2)
684 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
685 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
686 vfsflags, filteropts);
687 goto mtab;
688 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000689
Rob Landleydc0955b2006-03-14 18:16:25 +0000690 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000691 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000692 errno = 0;
693 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000694 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000695
696 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000697 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200698 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200699 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000700 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000701 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000702 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200703 if (FAKE_IT)
704 args[rc++] = (char *)"-f";
705 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
706 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000707 args[rc++] = mp->mnt_fsname;
708 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000709 if (filteropts) {
710 args[rc++] = (char *)"-o";
711 args[rc++] = filteropts;
712 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000713 args[rc] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +0100714 rc = spawn_and_wait(args);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000715 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000716 if (!rc)
717 break;
718 errno = errno_save;
719 }
720
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000721 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000722 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000723 if (!(vfsflags & MS_SILENT))
724 bb_error_msg("%s is write-protected, mounting read-only",
725 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000726 vfsflags |= MS_RDONLY;
727 }
728
Rob Landleydc0955b2006-03-14 18:16:25 +0000729 // Abort entirely if permission denied.
730
731 if (rc && errno == EPERM)
732 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
733
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000734 // If the mount was successful, and we're maintaining an old-style
735 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000736 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200737 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000738 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000739 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000740 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000741 int i;
742
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000743 if (!mountTable) {
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100744 bb_perror_msg(bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000745 goto ret;
746 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000747
748 // Add vfs string flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000749 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
750 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
751 append_mount_options(&(mp->mnt_opts), option_str);
752 option_str += strlen(option_str) + 1;
753 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000754
755 // Remove trailing / (if any) from directory we mounted on
Denis Vlasenko727ef942006-09-14 13:19:19 +0000756 i = strlen(mp->mnt_dir) - 1;
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100757 while (i > 0 && mp->mnt_dir[i] == '/')
Denys Vlasenkoc6450c92011-02-28 11:09:49 +0100758 mp->mnt_dir[i--] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000759
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000760 // Convert to canonical pathnames as needed
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000761 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100762 fsname = NULL;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000763 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000764 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000765 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000766 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000767 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000768
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100769 // Write and close
770#if ENABLE_FEATURE_MTAB_SUPPORT
771 if (vfsflags & MS_MOVE)
772 update_mtab_entry_on_move(mp);
773 else
774#endif
775 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000776 endmntent(mountTable);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100777
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000778 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000779 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000780 free(fsname);
781 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000782 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000783 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000784 return rc;
785}
786
Denis Vlasenko25098f72006-09-14 15:46:33 +0000787#if ENABLE_FEATURE_MOUNT_NFS
788
789/*
790 * Linux NFS mount
791 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
792 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +0200793 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko25098f72006-09-14 15:46:33 +0000794 *
795 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
796 * numbers to be specified on the command line.
797 *
798 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
799 * Omit the call to connect() for Linux version 1.3.11 or later.
800 *
801 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
802 * Implemented the "bg", "fg" and "retry" mount options for NFS.
803 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000804 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000805 * - added Native Language Support
806 *
807 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
808 * plus NFSv3 stuff.
809 */
810
Denis Vlasenko25098f72006-09-14 15:46:33 +0000811#define MOUNTPORT 635
812#define MNTPATHLEN 1024
813#define MNTNAMLEN 255
814#define FHSIZE 32
815#define FHSIZE3 64
816
817typedef char fhandle[FHSIZE];
818
819typedef struct {
820 unsigned int fhandle3_len;
821 char *fhandle3_val;
822} fhandle3;
823
824enum mountstat3 {
825 MNT_OK = 0,
826 MNT3ERR_PERM = 1,
827 MNT3ERR_NOENT = 2,
828 MNT3ERR_IO = 5,
829 MNT3ERR_ACCES = 13,
830 MNT3ERR_NOTDIR = 20,
831 MNT3ERR_INVAL = 22,
832 MNT3ERR_NAMETOOLONG = 63,
833 MNT3ERR_NOTSUPP = 10004,
834 MNT3ERR_SERVERFAULT = 10006,
835};
836typedef enum mountstat3 mountstat3;
837
838struct fhstatus {
839 unsigned int fhs_status;
840 union {
841 fhandle fhs_fhandle;
842 } fhstatus_u;
843};
844typedef struct fhstatus fhstatus;
845
846struct mountres3_ok {
847 fhandle3 fhandle;
848 struct {
849 unsigned int auth_flavours_len;
850 char *auth_flavours_val;
851 } auth_flavours;
852};
853typedef struct mountres3_ok mountres3_ok;
854
855struct mountres3 {
856 mountstat3 fhs_status;
857 union {
858 mountres3_ok mountinfo;
859 } mountres3_u;
860};
861typedef struct mountres3 mountres3;
862
863typedef char *dirpath;
864
865typedef char *name;
866
867typedef struct mountbody *mountlist;
868
869struct mountbody {
870 name ml_hostname;
871 dirpath ml_directory;
872 mountlist ml_next;
873};
874typedef struct mountbody mountbody;
875
876typedef struct groupnode *groups;
877
878struct groupnode {
879 name gr_name;
880 groups gr_next;
881};
882typedef struct groupnode groupnode;
883
884typedef struct exportnode *exports;
885
886struct exportnode {
887 dirpath ex_dir;
888 groups ex_groups;
889 exports ex_next;
890};
891typedef struct exportnode exportnode;
892
893struct ppathcnf {
894 int pc_link_max;
895 short pc_max_canon;
896 short pc_max_input;
897 short pc_name_max;
898 short pc_path_max;
899 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000900 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000901 char pc_xxx;
902 short pc_mask[2];
903};
904typedef struct ppathcnf ppathcnf;
905
906#define MOUNTPROG 100005
907#define MOUNTVERS 1
908
909#define MOUNTPROC_NULL 0
910#define MOUNTPROC_MNT 1
911#define MOUNTPROC_DUMP 2
912#define MOUNTPROC_UMNT 3
913#define MOUNTPROC_UMNTALL 4
914#define MOUNTPROC_EXPORT 5
915#define MOUNTPROC_EXPORTALL 6
916
917#define MOUNTVERS_POSIX 2
918
919#define MOUNTPROC_PATHCONF 7
920
921#define MOUNT_V3 3
922
923#define MOUNTPROC3_NULL 0
924#define MOUNTPROC3_MNT 1
925#define MOUNTPROC3_DUMP 2
926#define MOUNTPROC3_UMNT 3
927#define MOUNTPROC3_UMNTALL 4
928#define MOUNTPROC3_EXPORT 5
929
930enum {
931#ifndef NFS_FHSIZE
932 NFS_FHSIZE = 32,
933#endif
934#ifndef NFS_PORT
935 NFS_PORT = 2049
936#endif
937};
938
Denis Vlasenko25098f72006-09-14 15:46:33 +0000939/*
940 * We want to be able to compile mount on old kernels in such a way
941 * that the binary will work well on more recent kernels.
942 * Thus, if necessary we teach nfsmount.c the structure of new fields
943 * that will come later.
944 *
945 * Moreover, the new kernel includes conflict with glibc includes
946 * so it is easiest to ignore the kernel altogether (at compile time).
947 */
948
949struct nfs2_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100950 char data[32];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000951};
952struct nfs3_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100953 unsigned short size;
954 unsigned char data[64];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000955};
956
957struct nfs_mount_data {
Dave Lovefae473c2011-11-10 15:19:25 +0100958 int version; /* 1 */
959 int fd; /* 1 */
960 struct nfs2_fh old_root; /* 1 */
961 int flags; /* 1 */
962 int rsize; /* 1 */
963 int wsize; /* 1 */
964 int timeo; /* 1 */
965 int retrans; /* 1 */
966 int acregmin; /* 1 */
967 int acregmax; /* 1 */
968 int acdirmin; /* 1 */
969 int acdirmax; /* 1 */
970 struct sockaddr_in addr; /* 1 */
971 char hostname[256]; /* 1 */
972 int namlen; /* 2 */
973 unsigned int bsize; /* 3 */
974 struct nfs3_fh root; /* 4 */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000975};
976
977/* bits in the flags field */
978enum {
979 NFS_MOUNT_SOFT = 0x0001, /* 1 */
980 NFS_MOUNT_INTR = 0x0002, /* 1 */
981 NFS_MOUNT_SECURE = 0x0004, /* 1 */
982 NFS_MOUNT_POSIX = 0x0008, /* 1 */
983 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
984 NFS_MOUNT_NOAC = 0x0020, /* 1 */
985 NFS_MOUNT_TCP = 0x0040, /* 2 */
986 NFS_MOUNT_VER3 = 0x0080, /* 3 */
987 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000988 NFS_MOUNT_NONLM = 0x0200, /* 3 */
Dave Lovefae473c2011-11-10 15:19:25 +0100989 NFS_MOUNT_NOACL = 0x0800, /* 4 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000990 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +0000991};
992
993
994/*
995 * We need to translate between nfs status return values and
996 * the local errno values which may not be the same.
997 *
998 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
999 * "after #include <errno.h> the symbol errno is reserved for any use,
1000 * it cannot even be used as a struct tag or field name".
1001 */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001002#ifndef EDQUOT
Denys Vlasenkocc428142009-12-16 02:06:56 +01001003# define EDQUOT ENOSPC
Denis Vlasenko25098f72006-09-14 15:46:33 +00001004#endif
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001005/* Convert each NFSERR_BLAH into EBLAH */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02001006static const uint8_t nfs_err_stat[] ALIGN1 = {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001007 1, 2, 5, 6, 13, 17,
1008 19, 20, 21, 22, 27, 28,
1009 30, 63, 66, 69, 70, 71
1010};
Denys Vlasenkodc1fd2e2010-05-19 17:01:29 +02001011#if ( \
1012 EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
1013 ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
1014 EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
1015typedef uint8_t nfs_err_type;
1016#else
1017typedef uint16_t nfs_err_type;
1018#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02001019static const nfs_err_type nfs_err_errnum[] ALIGN2 = {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001020 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
1021 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
1022 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
Denis Vlasenko25098f72006-09-14 15:46:33 +00001023};
Denis Vlasenko25098f72006-09-14 15:46:33 +00001024static char *nfs_strerror(int status)
1025{
1026 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001027
Denys Vlasenkocc428142009-12-16 02:06:56 +01001028 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
1029 if (nfs_err_stat[i] == status)
1030 return strerror(nfs_err_errnum[i]);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001031 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001032 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001033}
1034
1035static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
1036{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001037 return xdr_opaque(xdrs, objp, FHSIZE);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001038}
1039
1040static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
1041{
1042 if (!xdr_u_int(xdrs, &objp->fhs_status))
Denys Vlasenko69675782013-01-14 01:34:48 +01001043 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001044 if (objp->fhs_status == 0)
1045 return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001046 return TRUE;
1047}
1048
1049static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
1050{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001051 return xdr_string(xdrs, objp, MNTPATHLEN);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001052}
1053
1054static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
1055{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001056 return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
Denys Vlasenko69675782013-01-14 01:34:48 +01001057 (unsigned int *) &objp->fhandle3_len,
1058 FHSIZE3);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001059}
1060
1061static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
1062{
1063 if (!xdr_fhandle3(xdrs, &objp->fhandle))
1064 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001065 return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
Denys Vlasenko69675782013-01-14 01:34:48 +01001066 &(objp->auth_flavours.auth_flavours_len),
1067 ~0,
1068 sizeof(int),
1069 (xdrproc_t) xdr_int);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001070}
1071
1072static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
1073{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001074 return xdr_enum(xdrs, (enum_t *) objp);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001075}
1076
1077static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
1078{
1079 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
1080 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001081 if (objp->fhs_status == MNT_OK)
1082 return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001083 return TRUE;
1084}
1085
1086#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
1087
Denis Vlasenko25098f72006-09-14 15:46:33 +00001088/*
1089 * Unfortunately, the kernel prints annoying console messages
1090 * in case of an unexpected nfs mount version (instead of
1091 * just returning some error). Therefore we'll have to try
1092 * and figure out what version the kernel expects.
1093 *
1094 * Variables:
1095 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
1096 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
1097 * nfs_mount_version: version this source and running kernel can handle
1098 */
1099static void
1100find_kernel_nfs_mount_version(void)
1101{
Denis Vlasenkob9256052007-09-28 10:29:17 +00001102 int kernel_version;
1103
1104 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001105 return;
1106
1107 nfs_mount_version = 4; /* default */
1108
1109 kernel_version = get_linux_version_code();
1110 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001111 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +00001112 nfs_mount_version = 3;
1113 /* else v4 since 2.3.99pre4 */
1114 }
1115}
1116
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +00001117static void
Denis Vlasenkob9256052007-09-28 10:29:17 +00001118get_mountport(struct pmap *pm_mnt,
1119 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001120 long unsigned prog,
1121 long unsigned version,
1122 long unsigned proto,
1123 long unsigned port)
1124{
1125 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001126
1127 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001128/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
1129 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001130 pmap = pmap_getmaps(server_addr);
1131
1132 if (version > MAX_NFSPROT)
1133 version = MAX_NFSPROT;
1134 if (!prog)
1135 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001136 pm_mnt->pm_prog = prog;
1137 pm_mnt->pm_vers = version;
1138 pm_mnt->pm_prot = proto;
1139 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001140
Denis Vlasenko25098f72006-09-14 15:46:33 +00001141 while (pmap) {
1142 if (pmap->pml_map.pm_prog != prog)
1143 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001144 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001145 goto next;
1146 if (version > 2 && pmap->pml_map.pm_vers != version)
1147 goto next;
1148 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
1149 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001150 if (pmap->pml_map.pm_vers > MAX_NFSPROT
1151 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
1152 || (port && pmap->pml_map.pm_port != port)
1153 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001154 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001155 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001156 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
1157 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001158 pmap = pmap->pml_next;
1159 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001160 if (!pm_mnt->pm_vers)
1161 pm_mnt->pm_vers = MOUNTVERS;
1162 if (!pm_mnt->pm_port)
1163 pm_mnt->pm_port = MOUNTPORT;
1164 if (!pm_mnt->pm_prot)
1165 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001166}
1167
Denis Vlasenkof0000652007-09-04 18:30:26 +00001168#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001169static int daemonize(void)
1170{
Denis Vlasenko25098f72006-09-14 15:46:33 +00001171 int pid = fork();
1172 if (pid < 0) /* error */
1173 return -errno;
1174 if (pid > 0) /* parent */
1175 return 0;
1176 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001177 close(0);
1178 xopen(bb_dev_null, O_RDWR);
1179 xdup2(0, 1);
1180 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001181 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +00001182 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001183 logmode = LOGMODE_SYSLOG;
1184 return 1;
1185}
Denis Vlasenkof0000652007-09-04 18:30:26 +00001186#else
1187static inline int daemonize(void) { return -ENOSYS; }
1188#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001189
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001190/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001191static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001192{
1193 return 0;
1194}
1195
1196/* RPC strerror analogs are terminally idiotic:
1197 * *mandatory* prefix and \n at end.
1198 * This hopefully helps. Usage:
1199 * error_msg_rpc(clnt_*error*(" ")) */
1200static void error_msg_rpc(const char *msg)
1201{
Denis Vlasenko23514fe2006-09-19 14:07:52 +00001202 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001203 while (msg[0] == ' ' || msg[0] == ':') msg++;
1204 len = strlen(msg);
1205 while (len && msg[len-1] == '\n') len--;
1206 bb_error_msg("%.*s", len, msg);
1207}
1208
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001209/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001210static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001211{
1212 CLIENT *mclient;
1213 char *hostname;
1214 char *pathname;
1215 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001216 /* prior to 2.6.23, kernel took NFS options in a form of this struct
1217 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
1218 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001219 struct nfs_mount_data data;
1220 char *opt;
1221 struct hostent *hp;
1222 struct sockaddr_in server_addr;
1223 struct sockaddr_in mount_server_addr;
1224 int msock, fsock;
1225 union {
1226 struct fhstatus nfsv2;
1227 struct mountres3 nfsv3;
1228 } status;
1229 int daemonized;
1230 char *s;
1231 int port;
1232 int mountport;
1233 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001234#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001235 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001236#else
1237 enum { bg = 0 };
1238#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001239 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001240 int mountprog;
1241 int mountvers;
1242 int nfsprog;
1243 int nfsvers;
1244 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001245 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001246 smallint tcp;
1247 smallint soft;
1248 int intr;
1249 int posix;
1250 int nocto;
1251 int noac;
1252 int nordirplus;
1253 int nolock;
Dave Lovefae473c2011-11-10 15:19:25 +01001254 int noacl;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001255
1256 find_kernel_nfs_mount_version();
1257
1258 daemonized = 0;
1259 mounthost = NULL;
1260 retval = ETIMEDOUT;
1261 msock = fsock = -1;
1262 mclient = NULL;
1263
1264 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1265
1266 filteropts = xstrdup(filteropts); /* going to trash it later... */
1267
1268 hostname = xstrdup(mp->mnt_fsname);
1269 /* mount_main() guarantees that ':' is there */
1270 s = strchr(hostname, ':');
1271 pathname = s + 1;
1272 *s = '\0';
1273 /* Ignore all but first hostname in replicated mounts
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001274 * until they can be fully supported. (mack@sgi.com) */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001275 s = strchr(hostname, ',');
1276 if (s) {
1277 *s = '\0';
1278 bb_error_msg("warning: multiple hostnames not supported");
1279 }
1280
1281 server_addr.sin_family = AF_INET;
1282 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1283 hp = gethostbyname(hostname);
1284 if (hp == NULL) {
1285 bb_herror_msg("%s", hostname);
1286 goto fail;
1287 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001288 if (hp->h_length != (int)sizeof(struct in_addr)) {
1289 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001290 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001291 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001292 }
1293
1294 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1295
1296 /* add IP address to mtab options for use when unmounting */
1297
1298 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1299 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1300 } else {
1301 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1302 mp->mnt_opts[0] ? "," : "",
1303 inet_ntoa(server_addr.sin_addr));
1304 free(mp->mnt_opts);
1305 mp->mnt_opts = tmp;
1306 }
1307
1308 /* Set default options.
1309 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1310 * let the kernel decide.
1311 * timeo is filled in after we know whether it'll be TCP or UDP. */
1312 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001313 data.retrans = 3;
1314 data.acregmin = 3;
1315 data.acregmax = 60;
1316 data.acdirmin = 30;
1317 data.acdirmax = 60;
1318 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001319
Denis Vlasenko25098f72006-09-14 15:46:33 +00001320 soft = 0;
1321 intr = 0;
1322 posix = 0;
1323 nocto = 0;
1324 nolock = 0;
1325 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001326 nordirplus = 0;
Dave Lovefae473c2011-11-10 15:19:25 +01001327 noacl = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001328 retry = 10000; /* 10000 minutes ~ 1 week */
Bernhard Reutner-Fischer88206292011-05-04 19:03:30 +02001329 tcp = 1; /* nfs-utils uses tcp per default */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001330
1331 mountprog = MOUNTPROG;
1332 mountvers = 0;
1333 port = 0;
1334 mountport = 0;
1335 nfsprog = 100003;
1336 nfsvers = 0;
1337
1338 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001339 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001340 char *opteq = strchr(opt, '=');
1341 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001342 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001343 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001344 /* 0 */ "rsize\0"
1345 /* 1 */ "wsize\0"
1346 /* 2 */ "timeo\0"
1347 /* 3 */ "retrans\0"
1348 /* 4 */ "acregmin\0"
1349 /* 5 */ "acregmax\0"
1350 /* 6 */ "acdirmin\0"
1351 /* 7 */ "acdirmax\0"
1352 /* 8 */ "actimeo\0"
1353 /* 9 */ "retry\0"
1354 /* 10 */ "port\0"
1355 /* 11 */ "mountport\0"
1356 /* 12 */ "mounthost\0"
1357 /* 13 */ "mountprog\0"
1358 /* 14 */ "mountvers\0"
1359 /* 15 */ "nfsprog\0"
1360 /* 16 */ "nfsvers\0"
1361 /* 17 */ "vers\0"
1362 /* 18 */ "proto\0"
1363 /* 19 */ "namlen\0"
1364 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001365
1366 *opteq++ = '\0';
1367 idx = index_in_strings(options, opt);
1368 switch (idx) {
1369 case 12: // "mounthost"
1370 mounthost = xstrndup(opteq,
1371 strcspn(opteq, " \t\n\r,"));
1372 continue;
1373 case 18: // "proto"
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001374 if (is_prefixed_with(opteq, "tcp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001375 tcp = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001376 else if (is_prefixed_with(opteq, "udp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001377 tcp = 0;
1378 else
1379 bb_error_msg("warning: unrecognized proto= option");
1380 continue;
1381 case 20: // "addr" - ignore
1382 continue;
Peter Korsgaard301fe502011-02-21 17:52:13 +01001383 case -1: // unknown
1384 if (vfsflags & MS_REMOUNT)
1385 continue;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001386 }
1387
Denys Vlasenko77832482010-08-12 14:14:45 +02001388 val = xatoi_positive(opteq);
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001389 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001390 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001391 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001392 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001393 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001394 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001395 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001396 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001397 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001398 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001399 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001400 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001401 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001402 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001403 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001404 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001405 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001406 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001407 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001408 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001409 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001410 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001411 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001412 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001413 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001414 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001415 data.acregmin = val;
1416 data.acregmax = val;
1417 data.acdirmin = val;
1418 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001419 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001420 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001421 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001422 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001423 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001424 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001425 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001426 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001427 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001428 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001429 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001430 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001431 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001432 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001433 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001434 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001435 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001436 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001437 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001438 case 16: // "nfsvers"
1439 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001440 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001441 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001442 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001443 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001444 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001445 //else
1446 // bb_error_msg("warning: option namlen is not supported\n");
1447 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001448 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001449 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1450 goto fail;
1451 }
1452 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001453 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001454 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001455 "bg\0"
1456 "fg\0"
1457 "soft\0"
1458 "hard\0"
1459 "intr\0"
1460 "posix\0"
1461 "cto\0"
1462 "ac\0"
1463 "tcp\0"
1464 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001465 "lock\0"
Dave Lovefae473c2011-11-10 15:19:25 +01001466 "rdirplus\0"
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001467 "acl\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001468 int val = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001469 if (is_prefixed_with(opt, "no")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001470 val = 0;
1471 opt += 2;
1472 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001473 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001474 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001475#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001476 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001477#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001478 break;
1479 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001480#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001481 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001482#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001483 break;
1484 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001485 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001486 break;
1487 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001488 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001489 break;
1490 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001491 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001492 break;
1493 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001494 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001495 break;
1496 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001497 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001498 break;
1499 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001500 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001501 break;
1502 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001503 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001504 break;
1505 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001506 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001507 break;
1508 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001509 if (nfs_mount_version >= 3)
1510 nolock = !val;
1511 else
1512 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001513 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001514 case 11: //rdirplus
1515 nordirplus = !val;
1516 break;
Dave Lovefae473c2011-11-10 15:19:25 +01001517 case 12: // acl
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001518 noacl = !val;
Dave Lovefae473c2011-11-10 15:19:25 +01001519 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001520 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001521 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1522 goto fail;
1523 }
1524 }
1525 }
1526 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1527
1528 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1529 | (intr ? NFS_MOUNT_INTR : 0)
1530 | (posix ? NFS_MOUNT_POSIX : 0)
1531 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001532 | (noac ? NFS_MOUNT_NOAC : 0)
Dave Lovefae473c2011-11-10 15:19:25 +01001533 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0)
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001534 | (noacl ? NFS_MOUNT_NOACL : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001535 if (nfs_mount_version >= 2)
1536 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1537 if (nfs_mount_version >= 3)
1538 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1539 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1540 bb_error_msg("NFSv%d not supported", nfsvers);
1541 goto fail;
1542 }
1543 if (nfsvers && !mountvers)
1544 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1545 if (nfsvers && nfsvers < mountvers) {
1546 mountvers = nfsvers;
1547 }
1548
1549 /* Adjust options if none specified */
1550 if (!data.timeo)
1551 data.timeo = tcp ? 70 : 7;
1552
Denis Vlasenko25098f72006-09-14 15:46:33 +00001553 data.version = nfs_mount_version;
1554
1555 if (vfsflags & MS_REMOUNT)
1556 goto do_mount;
1557
1558 /*
1559 * If the previous mount operation on the same host was
1560 * backgrounded, and the "bg" for this mount is also set,
1561 * give up immediately, to avoid the initial timeout.
1562 */
1563 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001564 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001565 if (daemonized <= 0) { /* parent or error */
1566 retval = -daemonized;
1567 goto ret;
1568 }
1569 }
1570
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001571 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001572 /* See if the nfs host = mount host. */
1573 if (mounthost) {
1574 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1575 mount_server_addr.sin_family = AF_INET;
1576 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1577 } else {
1578 hp = gethostbyname(mounthost);
1579 if (hp == NULL) {
1580 bb_herror_msg("%s", mounthost);
1581 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001582 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001583 if (hp->h_length != (int)sizeof(struct in_addr)) {
1584 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001585 }
1586 mount_server_addr.sin_family = AF_INET;
Denys Vlasenko99069332010-02-27 19:38:19 +01001587 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001588 }
1589 }
1590
1591 /*
1592 * The following loop implements the mount retries. When the mount
1593 * times out, and the "bg" option is set, we background ourself
1594 * and continue trying.
1595 *
1596 * The case where the mount point is not present and the "bg"
1597 * option is set, is treated as a timeout. This is done to
1598 * support nested mounts.
1599 *
1600 * The "retry" count specified by the user is the number of
1601 * minutes to retry before giving up.
1602 */
1603 {
1604 struct timeval total_timeout;
1605 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001606 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001607 time_t t;
1608 time_t prevt;
1609 time_t timeout;
1610
1611 retry_timeout.tv_sec = 3;
1612 retry_timeout.tv_usec = 0;
1613 total_timeout.tv_sec = 20;
1614 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001615/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001616 timeout = time(NULL) + 60 * retry;
1617 prevt = 0;
1618 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001619 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001620 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001621 if (t - prevt < 30)
1622 sleep(30);
1623
Denis Vlasenkob9256052007-09-28 10:29:17 +00001624 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001625 mountprog,
1626 mountvers,
1627 proto,
1628 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001629 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001630
1631 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001632 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001633 msock = RPC_ANYSOCK;
1634
Denis Vlasenkob9256052007-09-28 10:29:17 +00001635 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001636 case IPPROTO_UDP:
1637 mclient = clntudp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001638 pm_mnt.pm_prog,
1639 pm_mnt.pm_vers,
1640 retry_timeout,
1641 &msock);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001642 if (mclient)
1643 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001644 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001645 msock = RPC_ANYSOCK;
1646 case IPPROTO_TCP:
1647 mclient = clnttcp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001648 pm_mnt.pm_prog,
1649 pm_mnt.pm_vers,
1650 &msock, 0, 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001651 break;
1652 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001653 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001654 }
1655 if (!mclient) {
1656 if (!daemonized && prevt == 0)
1657 error_msg_rpc(clnt_spcreateerror(" "));
1658 } else {
1659 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001660
1661 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001662 mclient->cl_auth = authunix_create_default();
1663
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001664 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001665 * that xdr_array allocates memory for us
1666 */
1667 memset(&status, 0, sizeof(status));
1668
Denis Vlasenkob9256052007-09-28 10:29:17 +00001669 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001670 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001671 (xdrproc_t) xdr_dirpath,
1672 (caddr_t) &pathname,
1673 (xdrproc_t) xdr_mountres3,
1674 (caddr_t) &status,
1675 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001676 else
1677 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001678 (xdrproc_t) xdr_dirpath,
1679 (caddr_t) &pathname,
1680 (xdrproc_t) xdr_fhstatus,
1681 (caddr_t) &status,
1682 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001683
1684 if (clnt_stat == RPC_SUCCESS)
1685 goto prepare_kernel_data; /* we're done */
1686 if (errno != ECONNREFUSED) {
1687 error_msg_rpc(clnt_sperror(mclient, " "));
1688 goto fail; /* don't retry */
1689 }
1690 /* Connection refused */
1691 if (!daemonized && prevt == 0) /* print just once */
1692 error_msg_rpc(clnt_sperror(mclient, " "));
1693 auth_destroy(mclient->cl_auth);
1694 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001695 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001696 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001697 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001698 }
1699
1700 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001701 if (!bg)
1702 goto fail;
1703 if (!daemonized) {
1704 daemonized = daemonize();
1705 if (daemonized <= 0) { /* parent or error */
1706 retval = -daemonized;
1707 goto ret;
1708 }
1709 }
1710 prevt = t;
1711 t = time(NULL);
1712 if (t >= timeout)
1713 /* TODO error message */
1714 goto fail;
1715
1716 goto retry;
1717 }
1718
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001719 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001720
1721 if (nfsvers == 2) {
1722 if (status.nfsv2.fhs_status != 0) {
1723 bb_error_msg("%s:%s failed, reason given by server: %s",
1724 hostname, pathname,
1725 nfs_strerror(status.nfsv2.fhs_status));
1726 goto fail;
1727 }
1728 memcpy(data.root.data,
1729 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1730 NFS_FHSIZE);
1731 data.root.size = NFS_FHSIZE;
1732 memcpy(data.old_root.data,
1733 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1734 NFS_FHSIZE);
1735 } else {
1736 fhandle3 *my_fhandle;
1737 if (status.nfsv3.fhs_status != 0) {
1738 bb_error_msg("%s:%s failed, reason given by server: %s",
1739 hostname, pathname,
1740 nfs_strerror(status.nfsv3.fhs_status));
1741 goto fail;
1742 }
1743 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1744 memset(data.old_root.data, 0, NFS_FHSIZE);
1745 memset(&data.root, 0, sizeof(data.root));
1746 data.root.size = my_fhandle->fhandle3_len;
1747 memcpy(data.root.data,
1748 (char *) my_fhandle->fhandle3_val,
1749 my_fhandle->fhandle3_len);
1750
1751 data.flags |= NFS_MOUNT_VER3;
1752 }
1753
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001754 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001755 if (tcp) {
1756 if (nfs_mount_version < 3) {
1757 bb_error_msg("NFS over TCP is not supported");
1758 goto fail;
1759 }
1760 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1761 } else
1762 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1763 if (fsock < 0) {
1764 bb_perror_msg("nfs socket");
1765 goto fail;
1766 }
1767 if (bindresvport(fsock, 0) < 0) {
1768 bb_perror_msg("nfs bindresvport");
1769 goto fail;
1770 }
1771 if (port == 0) {
1772 server_addr.sin_port = PMAPPORT;
1773 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1774 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1775 if (port == 0)
1776 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001777 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001778 server_addr.sin_port = htons(port);
1779
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001780 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001781 data.fd = fsock;
1782 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1783 strncpy(data.hostname, hostname, sizeof(data.hostname));
1784
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001785 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001786 auth_destroy(mclient->cl_auth);
1787 clnt_destroy(mclient);
1788 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001789 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001790
1791 if (bg) {
1792 /* We must wait until mount directory is available */
1793 struct stat statbuf;
1794 int delay = 1;
1795 while (stat(mp->mnt_dir, &statbuf) == -1) {
1796 if (!daemonized) {
1797 daemonized = daemonize();
1798 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001799/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001800 retval = -daemonized;
1801 goto ret;
1802 }
1803 }
1804 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1805 delay *= 2;
1806 if (delay > 30)
1807 delay = 30;
1808 }
1809 }
1810
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001811 /* Perform actual mount */
1812 do_mount:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001813 retval = mount_it_now(mp, vfsflags, (char*)&data);
1814 goto ret;
1815
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001816 /* Abort */
1817 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001818 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001819 if (mclient) {
1820 auth_destroy(mclient->cl_auth);
1821 clnt_destroy(mclient);
1822 }
1823 close(msock);
1824 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001825 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001826 close(fsock);
1827
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001828 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001829 free(hostname);
1830 free(mounthost);
1831 free(filteropts);
1832 return retval;
1833}
1834
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001835#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001836
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001837/* Linux 2.6.23+ supports nfs mounts with options passed as a string.
1838 * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS.
1839 * (However, note that then you lose any chances that NFS over IPv6 would work).
1840 */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001841static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001842{
1843 len_and_sockaddr *lsa;
1844 char *opts;
1845 char *end;
1846 char *dotted;
1847 int ret;
1848
1849# if ENABLE_FEATURE_IPV6
1850 end = strchr(mp->mnt_fsname, ']');
1851 if (end && end[1] == ':')
1852 end++;
1853 else
1854# endif
1855 /* mount_main() guarantees that ':' is there */
1856 end = strchr(mp->mnt_fsname, ':');
1857
1858 *end = '\0';
Denys Vlasenko39b23312011-11-10 17:01:39 +01001859 lsa = xhost2sockaddr(mp->mnt_fsname, /*port:*/ 0);
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001860 *end = ':';
1861 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1862 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1863 opts = xasprintf("%s%saddr=%s",
1864 filteropts ? filteropts : "",
1865 filteropts ? "," : "",
1866 dotted
1867 );
1868 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
1869 ret = mount_it_now(mp, vfsflags, opts);
1870 if (ENABLE_FEATURE_CLEAN_UP) free(opts);
1871
1872 return ret;
1873}
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001874
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001875#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001876
1877// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1878// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001879// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001880static int singlemount(struct mntent *mp, int ignore_busy)
1881{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001882 int rc = -1;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001883 unsigned long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001884 char *loopFile = NULL, *filteropts = NULL;
1885 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001886 struct stat st;
1887
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001888 errno = 0;
1889
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001890 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1891
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001892 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001893 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1894 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001895
Denis Vlasenko2535f122007-09-15 13:28:30 +00001896 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001897 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1898 char *args[35];
1899 char *s;
1900 int n;
1901 // fsname: "cmd#arg1#arg2..."
1902 // WARNING: allows execution of arbitrary commands!
1903 // Try "mount 'sh#-c#sh' bogus_dir".
1904 // It is safe ONLY because non-root
1905 // cannot use two-argument mount command
1906 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1907 // "mount: can't find sh#-c#sh in /etc/fstab"
1908 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1909
1910 s = mp->mnt_fsname;
1911 n = 0;
1912 args[n++] = s;
1913 while (*s && n < 35 - 2) {
1914 if (*s++ == '#' && *s != '#') {
1915 s[-1] = '\0';
1916 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001917 }
1918 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001919 args[n++] = mp->mnt_dir;
1920 args[n] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +01001921 rc = spawn_and_wait(args);
Denis Vlasenko2535f122007-09-15 13:28:30 +00001922 goto report_error;
1923 }
1924
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001925 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001926 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001927 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1928 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1929 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001930 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001931 int len;
1932 char c;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001933 char *hostname, *share;
1934 char *dotted, *ip;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001935 len_and_sockaddr *lsa;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001936
1937 // Parse mp->mnt_fsname of the form "//hostname/share[/dir1/dir2]"
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001938
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001939 hostname = mp->mnt_fsname + 2;
1940 len = strcspn(hostname, "/\\");
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001941 share = hostname + len + 1;
1942 if (len == 0 // 3rd char is a [back]slash (IOW: empty hostname)
1943 || share[-1] == '\0' // no [back]slash after hostname
1944 || share[0] == '\0' // empty share name
Martin Santesson406ea152013-01-16 00:47:19 +01001945 ) {
Denis Vlasenko5c329932009-04-12 12:16:21 +00001946 goto report_error;
Martin Santesson406ea152013-01-16 00:47:19 +01001947 }
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001948 c = share[-1];
1949 share[-1] = '\0';
1950 len = strcspn(share, "/\\");
Martin Santesson406ea152013-01-16 00:47:19 +01001951
1952 // "unc=\\hostname\share" option is mandatory
1953 // after CIFS option parsing was rewritten in Linux 3.4.
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001954 // Must use backslashes.
1955 // If /dir1/dir2 is present, also add "prefixpath=dir1/dir2"
Martin Santesson406ea152013-01-16 00:47:19 +01001956 {
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001957 char *unc = xasprintf(
1958 share[len] != '\0' /* "/dir1/dir2" exists? */
1959 ? "unc=\\\\%s\\%.*s,prefixpath=%s"
1960 : "unc=\\\\%s\\%.*s",
1961 hostname,
1962 len, share,
1963 share + len + 1 /* "dir1/dir2" */
1964 );
Denys Vlasenko9b7ebfe2013-01-22 11:00:45 +01001965 parse_mount_options(unc, &filteropts);
1966 if (ENABLE_FEATURE_CLEAN_UP) free(unc);
Martin Santesson406ea152013-01-16 00:47:19 +01001967 }
1968
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001969 lsa = host2sockaddr(hostname, 0);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001970 share[-1] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001971 if (!lsa)
1972 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001973
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001974 // Insert "ip=..." option into options
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001975 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001976 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001977 ip = xasprintf("ip=%s", dotted);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001978 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001979 parse_mount_options(ip, &filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001980 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001981
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001982 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001983 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001984
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001985 goto report_error;
1986 }
1987
1988 // Might this be an NFS filesystem?
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001989 if ((!mp->mnt_type || is_prefixed_with(mp->mnt_type, "nfs"))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001990 && strchr(mp->mnt_fsname, ':') != NULL
1991 ) {
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001992 if (!mp->mnt_type)
1993 mp->mnt_type = (char*)"nfs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001994 rc = nfsmount(mp, vfsflags, filteropts);
1995 goto report_error;
1996 }
1997
1998 // Look at the file. (Not found isn't a failure for remount, or for
1999 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00002000 // (We use stat, not lstat, in order to allow
2001 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00002002 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002003 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
2004 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002005 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002006 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
2007 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002008 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002009 if (set_loop(&mp->mnt_fsname, loopFile, 0, /*ro:*/ (vfsflags & MS_RDONLY)) < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002010 if (errno == EPERM || errno == EACCES)
2011 bb_error_msg(bb_msg_perm_denied_are_you_root);
2012 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01002013 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00002014 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002015 }
2016
2017 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002018 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
2019 vfsflags |= MS_BIND;
2020 }
2021
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002022 // If we know the fstype (or don't need to), jump straight
2023 // to the actual mount.
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002024 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002025 char *next;
2026 for (;;) {
2027 next = mp->mnt_type ? strchr(mp->mnt_type, ',') : NULL;
2028 if (next)
2029 *next = '\0';
2030 rc = mount_it_now(mp, vfsflags, filteropts);
2031 if (rc == 0 || !next)
2032 break;
2033 mp->mnt_type = next + 1;
2034 }
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002035 } else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002036 // Loop through filesystem types until mount succeeds
2037 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002038
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01002039 // Initialize list of block backed filesystems.
2040 // This has to be done here so that during "mount -a",
2041 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002042 if (!fslist) {
2043 fslist = get_block_backed_filesystems();
2044 if (ENABLE_FEATURE_CLEAN_UP && fslist)
2045 atexit(delete_block_backed_filesystems);
2046 }
2047
2048 for (fl = fslist; fl; fl = fl->link) {
2049 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00002050 rc = mount_it_now(mp, vfsflags, filteropts);
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002051 if (rc == 0)
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02002052 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002053 }
2054 }
2055
2056 // If mount failed, clean up loop file (if any).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002057 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
2058 del_loop(mp->mnt_fsname);
2059 if (ENABLE_FEATURE_CLEAN_UP) {
2060 free(loopFile);
Denys Vlasenkoecf25cb2016-06-20 11:04:04 +02002061 /* No, "rc != 0" needs it: free(mp->mnt_fsname); */
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002062 }
2063 }
2064
Denis Vlasenko5870ad92007-02-04 02:39:55 +00002065 report_error:
2066 if (ENABLE_FEATURE_CLEAN_UP)
2067 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002068
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00002069 if (errno == EBUSY && ignore_busy)
2070 return 0;
Denys Vlasenko911d2652015-12-30 20:11:34 +01002071 if (errno == ENOENT && (vfsflags & MOUNT_NOFAIL))
2072 return 0;
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002073 if (rc != 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002074 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002075 return rc;
2076}
2077
Michael Abbott6b5accb2009-12-04 03:33:07 +01002078// -O support
2079// -O interprets a list of filter options which select whether a mount
2080// point will be mounted: only mounts with options matching *all* filtering
2081// options will be selected.
2082// By default each -O filter option must be present in the list of mount
2083// options, but if it is prefixed by "no" then it must be absent.
2084// For example,
2085// -O a,nob,c matches -o a,c but fails to match -o a,b,c
2086// (and also fails to match -o a because -o c is absent).
2087//
2088// It is different from -t in that each option is matched exactly; a leading
2089// "no" at the beginning of one option does not negate the rest.
2090static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002091{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002092 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01002093 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002094
Michael Abbott6b5accb2009-12-04 03:33:07 +01002095 while (*O_opt) {
2096 const char *fs_opt = fs_opt_in;
2097 int O_len;
2098 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002099
Michael Abbott6b5accb2009-12-04 03:33:07 +01002100 // If option begins with "no" then treat as an inverted match:
2101 // matching is a failure
2102 match = 0;
2103 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
2104 match = 1;
2105 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002106 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002107 // Isolate the current O option
2108 O_len = strchrnul(O_opt, ',') - O_opt;
2109 // Check for a match against existing options
2110 while (1) {
2111 if (strncmp(fs_opt, O_opt, O_len) == 0
2112 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
2113 ) {
2114 if (match)
2115 return 0; // "no" prefix, but option found
2116 match = 1; // current O option found, go check next one
2117 break;
2118 }
2119 fs_opt = strchr(fs_opt, ',');
2120 if (!fs_opt)
2121 break;
2122 fs_opt++;
2123 }
2124 if (match == 0)
2125 return 0; // match wanted but not found
2126 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002127 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01002128 // Step to the next O option
2129 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002130 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002131 // If we get here then everything matched
2132 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002133}
2134
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002135// Parse options, if necessary parse fstab/mtab, and call singlemount for
2136// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002137int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002138int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002139{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002140 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002141 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002142 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002143 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002144 llist_t *lst_o = NULL;
Isaac Dunham7b434a62015-03-11 16:07:24 +01002145 const char *fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002146 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002147 int i, j;
2148 int rc = EXIT_SUCCESS;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002149 unsigned long cmdopt_flags;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002150 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002151 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002152 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002153
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002154 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00002155
Denys Vlasenko16714242011-09-21 01:59:15 +02002156 INIT_G();
2157
Denis Vlasenkof732e962008-02-18 12:07:49 +00002158 // Parse long options, like --bind and --move. Note that -o option
2159 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002160 for (i = j = 1; argv[i]; i++) {
2161 if (argv[i][0] == '-' && argv[i][1] == '-')
2162 append_mount_options(&cmdopts, argv[i] + 2);
2163 else
2164 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002165 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002166 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002167
2168 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002169 // Max 2 params; -o is a list, -v is a counter
Denys Vlasenko237bedd2016-07-06 21:58:02 +02002170 opt_complementary = "?2" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002171 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Isaac Dunham7b434a62015-03-11 16:07:24 +01002172 IF_FEATURE_MOUNT_OTHERTAB(, &fstabname)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002173 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002174 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00002175 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
2176 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00002177 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002178
2179 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002180 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00002181 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002182 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
2183
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002184 if (!mountTable)
2185 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002186
Denis Vlasenko2535f122007-09-15 13:28:30 +00002187 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002188 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002189 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002190 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00002191 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002192 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002193
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002194 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002195 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
2196 mtpair->mnt_dir, mtpair->mnt_type,
2197 mtpair->mnt_opts);
2198 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002199 if (ENABLE_FEATURE_CLEAN_UP)
2200 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002201 return EXIT_SUCCESS;
2202 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002203 storage_path = NULL;
2204 } else {
2205 // When we have two arguments, the second is the directory and we can
2206 // skip looking at fstab entirely. We can always abspath() the directory
2207 // argument when we get it.
2208 if (argv[1]) {
2209 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002210 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002211 mtpair->mnt_fsname = argv[0];
2212 mtpair->mnt_dir = argv[1];
2213 mtpair->mnt_type = fstype;
2214 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002215 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002216 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002217 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00002218 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002219 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002220 }
2221
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002222 // Past this point, we are handling either "mount -a [opts]"
2223 // or "mount [opts] single_param"
2224
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002225 cmdopt_flags = parse_mount_options(cmdopts, NULL);
2226 if (nonroot && (cmdopt_flags & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002227 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00002228
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002229 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002230 if (ENABLE_FEATURE_MOUNT_FLAGS
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002231 && (cmdopt_flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002232 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002233 // verbose_mount(source, target, type, flags, data)
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002234 rc = verbose_mount("", argv[0], "", cmdopt_flags, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002235 if (rc)
2236 bb_simple_perror_msg_and_die(argv[0]);
2237 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002238 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002239
Isaac Dunham7b434a62015-03-11 16:07:24 +01002240 // A malicious user could overmount /usr without this.
2241 if (ENABLE_FEATURE_MOUNT_OTHERTAB && nonroot)
2242 fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002243 // Open either fstab or mtab
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002244 if (cmdopt_flags & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002245 // WARNING. I am not sure this matches util-linux's
2246 // behavior. It's possible util-linux does not
2247 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002248 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002249 }
2250 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00002251 if (!fstab)
Denys Vlasenko651a2692010-03-23 16:25:17 +01002252 bb_perror_msg_and_die("can't read '%s'", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002253
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002254 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00002255 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002256 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002257 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002258
2259 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00002260 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002261 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002262 GETMNTENT_BUFSIZE/2)
2263 ) { // End of fstab/mtab is reached
2264 mtcur = mtother; // the thing we found last time
2265 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002266 }
2267
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002268 // If we're trying to mount something specific and this isn't it,
2269 // skip it. Note we must match the exact text in fstab (ala
2270 // "proc") or a full path from root
2271 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002272
2273 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002274 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
2275 && strcmp(storage_path, mtcur->mnt_fsname) != 0
2276 && strcmp(argv[0], mtcur->mnt_dir) != 0
2277 && strcmp(storage_path, mtcur->mnt_dir) != 0
2278 ) {
2279 continue; // no
2280 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002281
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002282 // Remember this entry. Something later may have
2283 // overmounted it, and we want the _last_ match.
2284 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002285
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002286 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002287 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002288 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002289 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002290 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002291 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002292 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002293
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002294 // Does type match? (NULL matches always)
2295 if (!match_fstype(mtcur, fstype))
2296 continue;
2297
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002298 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002299 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
2300 // swap is bogus "fstype", parse_mount_options can't check fstypes
2301 || strcasecmp(mtcur->mnt_type, "swap") == 0
2302 ) {
2303 continue;
2304 }
2305
2306 // Does (at least one) option match?
2307 // (NULL matches always)
2308 if (!match_opt(mtcur->mnt_opts, O_optmatch))
2309 continue;
2310
2311 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002312
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002313 // NFS mounts want this to be xrealloc-able
2314 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002315
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002316 // If nothing is mounted on this directory...
2317 // (otherwise repeated "mount -a" mounts everything again)
2318 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2319 // We do not check fsname match of found mount point -
2320 // "/" may have fsname of "/dev/root" while fstab
2321 // says "/dev/something_else".
2322 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01002323 if (verbose) {
2324 bb_error_msg("according to %s, "
2325 "%s is already mounted on %s",
2326 bb_path_mtab_file,
2327 mp->mnt_fsname, mp->mnt_dir);
2328 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002329 } else {
2330 // ...mount this thing
2331 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2332 // Count number of failed mounts
2333 rc++;
2334 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002335 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002336 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002337 }
2338 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002339
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002340 // End of fstab/mtab is reached.
2341 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002342 if (argv[0]) { // yes
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002343 unsigned long l;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002344
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002345 // If we didn't find anything, complain
2346 if (!mtcur->mnt_fsname)
2347 bb_error_msg_and_die("can't find %s in %s",
2348 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002349
2350 // What happens when we try to "mount swap_partition"?
2351 // (fstab containts "swap_partition swap swap defaults 0 0")
2352 // util-linux-ng 2.13.1 does this:
2353 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2354 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2355 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2356 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2357 // exit_group(32) = ?
2358#if 0
2359 // In case we want to simply skip swap partitions:
2360 l = parse_mount_options(mtcur->mnt_opts, NULL);
2361 if ((l & MOUNT_SWAP)
2362 // swap is bogus "fstype", parse_mount_options can't check fstypes
2363 || strcasecmp(mtcur->mnt_type, "swap") == 0
2364 ) {
2365 goto ret;
2366 }
2367#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002368 if (nonroot) {
2369 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002370 l = parse_mount_options(mtcur->mnt_opts, NULL);
2371 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002372 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002373 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002374
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002375 //util-linux-2.12 does not do this check.
2376 //// If nothing is mounted on this directory...
2377 //// (otherwise repeated "mount FOO" mounts FOO again)
2378 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2379 //if (mp) {
2380 // bb_error_msg("according to %s, "
2381 // "%s is already mounted on %s",
2382 // bb_path_mtab_file,
2383 // mp->mnt_fsname, mp->mnt_dir);
2384 //} else {
2385 // ...mount the last thing we found
2386 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2387 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2388 resolve_mount_spec(&mtpair->mnt_fsname);
2389 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2390 if (ENABLE_FEATURE_CLEAN_UP)
2391 free(mtcur->mnt_opts);
2392 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002393 }
2394
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002395 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002396 if (ENABLE_FEATURE_CLEAN_UP)
2397 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002398 if (ENABLE_FEATURE_CLEAN_UP) {
2399 free(storage_path);
2400 free(cmdopts);
2401 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002402
2403//TODO: exitcode should be ORed mask of (from "man mount"):
2404// 0 success
2405// 1 incorrect invocation or permissions
2406// 2 system error (out of memory, cannot fork, no more loop devices)
2407// 4 internal mount bug or missing nfs support in mount
2408// 8 user interrupt
2409//16 problems writing or locking /etc/mtab
2410//32 mount failure
2411//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002412 return rc;
2413}