blob: c428f58274d9f6356dd38fef94e480caa24ec338 [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"
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000226#if ENABLE_FEATURE_MOUNT_LABEL
Natanael Copa9aff2992009-09-20 04:28:22 +0200227# include "volume_id.h"
228#else
229# define resolve_mount_spec(fsname) ((void)0)
Denis Vlasenko6aa76962008-03-18 01:44:52 +0000230#endif
Denis Vlasenkode7684a2008-02-18 21:08:49 +0000231
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000232// Needed for nfs support only
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000233#include <sys/utsname.h>
234#undef TRUE
235#undef FALSE
Denys Vlasenkocc428142009-12-16 02:06:56 +0100236#if ENABLE_FEATURE_MOUNT_NFS
237/* This is just a warning of a common mistake. Possibly this should be a
238 * uclibc faq entry rather than in busybox... */
239# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
240# error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
241# endif
242# include <rpc/rpc.h>
243# include <rpc/pmap_prot.h>
244# include <rpc/pmap_clnt.h>
245#endif
Denis Vlasenko30a64cd2006-09-15 15:12:00 +0000246
247
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000248#if defined(__dietlibc__)
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000249// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
250// dietlibc-0.30 does not have implementation of getmntent_r()
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000251static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000252 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000253{
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000254 struct mntent* ment = getmntent(stream);
Denis Vlasenkoa0e17f72008-05-26 01:19:53 +0000255 return memcpy(result, ment, sizeof(*ment));
Denis Vlasenko908d6b72006-12-18 23:07:42 +0000256}
257#endif
258
259
Rob Landleydc0955b2006-03-14 18:16:25 +0000260// Not real flags, but we want to be able to check for this.
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000261enum {
Denys Vlasenko911d2652015-12-30 20:11:34 +0100262 MOUNT_USERS = (1 << 27) * ENABLE_DESKTOP,
263 MOUNT_NOFAIL = (1 << 28) * ENABLE_DESKTOP,
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000264 MOUNT_NOAUTO = (1 << 29),
265 MOUNT_SWAP = (1 << 30),
Denys Vlasenko911d2652015-12-30 20:11:34 +0100266 MOUNT_FAKEFLAGS = MOUNT_USERS | MOUNT_NOFAIL | MOUNT_NOAUTO | MOUNT_SWAP
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000267};
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000268
269
Isaac Dunham7b434a62015-03-11 16:07:24 +0100270#define OPTION_STR "o:t:rwanfvsiO:" IF_FEATURE_MOUNT_OTHERTAB("T:")
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000271enum {
272 OPT_o = (1 << 0),
273 OPT_t = (1 << 1),
274 OPT_r = (1 << 2),
275 OPT_w = (1 << 3),
276 OPT_a = (1 << 4),
277 OPT_n = (1 << 5),
278 OPT_f = (1 << 6),
279 OPT_v = (1 << 7),
280 OPT_s = (1 << 8),
281 OPT_i = (1 << 9),
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +0000282 OPT_O = (1 << 10),
Isaac Dunham7b434a62015-03-11 16:07:24 +0100283 OPT_T = (1 << 11),
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000284};
285
286#if ENABLE_FEATURE_MTAB_SUPPORT
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200287#define USE_MTAB (!(option_mask32 & OPT_n))
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000288#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200289#define USE_MTAB 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000290#endif
291
292#if ENABLE_FEATURE_MOUNT_FAKE
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200293#define FAKE_IT (option_mask32 & OPT_f)
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000294#else
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200295#define FAKE_IT 0
296#endif
297
298#if ENABLE_FEATURE_MOUNT_HELPERS
299#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
300#else
301#define HELPERS_ALLOWED 0
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +0000302#endif
303
304
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000305// TODO: more "user" flag compatibility.
306// "user" option (from mount manpage):
307// Only the user that mounted a filesystem can unmount it again.
308// If any user should be able to unmount, then use users instead of user
309// in the fstab line. The owner option is similar to the user option,
310// with the restriction that the user must be the owner of the special file.
311// This may be useful e.g. for /dev/fd if a login script makes
312// the console user owner of this device.
Rob Landley3ba7bd12006-08-09 19:51:13 +0000313
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000314// Standard mount options (from -o options or --options),
315// with corresponding flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000316static const int32_t mount_options[] = {
Rob Landleye3781b72006-08-08 01:39:49 +0000317 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
Rob Landleydc0955b2006-03-14 18:16:25 +0000318
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000319 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000320 /* "loop" */ 0,
Rob Landleye3781b72006-08-08 01:39:49 +0000321 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000322
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000323 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000324 /* "defaults" */ 0,
325 /* "quiet" 0 - do not filter out, vfat wants to see it */
326 /* "noauto" */ MOUNT_NOAUTO,
327 /* "sw" */ MOUNT_SWAP,
328 /* "swap" */ MOUNT_SWAP,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000329 IF_DESKTOP(/* "user" */ MOUNT_USERS,)
330 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
Denys Vlasenko911d2652015-12-30 20:11:34 +0100331 IF_DESKTOP(/* "nofail" */ MOUNT_NOFAIL,)
Denis Vlasenko8c638cb2008-01-29 09:31:09 +0000332 /* "_netdev" */ 0,
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100333 IF_DESKTOP(/* "comment=" */ 0,) /* systemd uses this in fstab */
Rob Landleye3781b72006-08-08 01:39:49 +0000334 )
Rob Landleydc0955b2006-03-14 18:16:25 +0000335
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000336 IF_FEATURE_MOUNT_FLAGS(
Rob Landleye3781b72006-08-08 01:39:49 +0000337 // vfs flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000338 /* "nosuid" */ MS_NOSUID,
339 /* "suid" */ ~MS_NOSUID,
340 /* "dev" */ ~MS_NODEV,
341 /* "nodev" */ MS_NODEV,
342 /* "exec" */ ~MS_NOEXEC,
343 /* "noexec" */ MS_NOEXEC,
344 /* "sync" */ MS_SYNCHRONOUS,
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +0000345 /* "dirsync" */ MS_DIRSYNC,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000346 /* "async" */ ~MS_SYNCHRONOUS,
347 /* "atime" */ ~MS_NOATIME,
348 /* "noatime" */ MS_NOATIME,
349 /* "diratime" */ ~MS_NODIRATIME,
350 /* "nodiratime" */ MS_NODIRATIME,
Denis Vlasenko580ce2d2008-07-08 02:56:53 +0000351 /* "mand" */ MS_MANDLOCK,
352 /* "nomand" */ ~MS_MANDLOCK,
Bernhard Reutner-Fischerfb5902c2008-08-06 18:14:38 +0000353 /* "relatime" */ MS_RELATIME,
354 /* "norelatime" */ ~MS_RELATIME,
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200355 /* "strictatime" */ MS_STRICTATIME,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000356 /* "loud" */ ~MS_SILENT,
Roman Borisov19311bf2011-03-24 15:08:43 +0300357 /* "rbind" */ MS_BIND|MS_RECURSIVE,
Eric Andersen9601a1c2006-03-20 18:07:50 +0000358
Rob Landleye3781b72006-08-08 01:39:49 +0000359 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200360 /* "union" */ MS_UNION,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000361 /* "bind" */ MS_BIND,
362 /* "move" */ MS_MOVE,
363 /* "shared" */ MS_SHARED,
364 /* "slave" */ MS_SLAVE,
365 /* "private" */ MS_PRIVATE,
366 /* "unbindable" */ MS_UNBINDABLE,
367 /* "rshared" */ MS_SHARED|MS_RECURSIVE,
368 /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
Roman Borisovd3679d22011-03-23 11:20:25 +0300369 /* "rprivate" */ MS_PRIVATE|MS_RECURSIVE,
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000370 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
Rob Landleye3781b72006-08-08 01:39:49 +0000371 )
372
373 // Always understood.
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000374 /* "ro" */ MS_RDONLY, // vfs flag
375 /* "rw" */ ~MS_RDONLY, // vfs flag
376 /* "remount" */ MS_REMOUNT // action flag
Eric Andersencc8ed391999-10-05 16:24:54 +0000377};
378
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000379static const char mount_option_str[] =
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000380 IF_FEATURE_MOUNT_LOOP(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000381 "loop\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000382 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000383 IF_FEATURE_MOUNT_FSTAB(
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000384 "defaults\0"
385 // "quiet\0" - do not filter out, vfat wants to see it
386 "noauto\0"
387 "sw\0"
388 "swap\0"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000389 IF_DESKTOP("user\0")
390 IF_DESKTOP("users\0")
Denys Vlasenko911d2652015-12-30 20:11:34 +0100391 IF_DESKTOP("nofail\0")
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000392 "_netdev\0"
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100393 IF_DESKTOP("comment=\0") /* systemd uses this in fstab */
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000394 )
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000395 IF_FEATURE_MOUNT_FLAGS(
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000396 // vfs flags
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000397 "nosuid\0"
398 "suid\0"
399 "dev\0"
400 "nodev\0"
401 "exec\0"
402 "noexec\0"
403 "sync\0"
404 "dirsync\0"
405 "async\0"
406 "atime\0"
407 "noatime\0"
408 "diratime\0"
409 "nodiratime\0"
410 "mand\0"
411 "nomand\0"
412 "relatime\0"
413 "norelatime\0"
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200414 "strictatime\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000415 "loud\0"
Roman Borisov19311bf2011-03-24 15:08:43 +0300416 "rbind\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000417
418 // action flags
Vladimir Dronnikovbe168b12009-10-05 02:18:01 +0200419 "union\0"
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000420 "bind\0"
421 "move\0"
Roman Borisov945fd172011-02-25 14:50:39 +0300422 "make-shared\0"
423 "make-slave\0"
424 "make-private\0"
425 "make-unbindable\0"
426 "make-rshared\0"
427 "make-rslave\0"
428 "make-rprivate\0"
429 "make-runbindable\0"
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000430 )
431
432 // Always understood.
Denis Vlasenko3f8f4b22008-12-10 11:28:30 +0000433 "ro\0" // vfs flag
434 "rw\0" // vfs flag
435 "remount\0" // action flag
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000436;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000437
Denis Vlasenkof732e962008-02-18 12:07:49 +0000438
439struct globals {
440#if ENABLE_FEATURE_MOUNT_NFS
441 smalluint nfs_mount_version;
442#endif
443#if ENABLE_FEATURE_MOUNT_VERBOSE
444 unsigned verbose;
445#endif
446 llist_t *fslist;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000447 char getmntent_buf[1];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100448} FIX_ALIASING;
Denis Vlasenkod0a071a2008-03-17 09:33:45 +0000449enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
Denis Vlasenkof732e962008-02-18 12:07:49 +0000450#define G (*(struct globals*)&bb_common_bufsiz1)
451#define nfs_mount_version (G.nfs_mount_version)
Denis Vlasenkob4133682008-02-18 13:05:38 +0000452#if ENABLE_FEATURE_MOUNT_VERBOSE
Denis Vlasenkof732e962008-02-18 12:07:49 +0000453#define verbose (G.verbose )
Denis Vlasenkob4133682008-02-18 13:05:38 +0000454#else
455#define verbose 0
456#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000457#define fslist (G.fslist )
458#define getmntent_buf (G.getmntent_buf )
Denys Vlasenko16714242011-09-21 01:59:15 +0200459#define INIT_G() do { } while (0)
Denis Vlasenkof732e962008-02-18 12:07:49 +0000460
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100461#if ENABLE_FEATURE_MTAB_SUPPORT
462/*
463 * update_mtab_entry_on_move() is used to update entry in case of mount --move.
464 * we are looking for existing entries mnt_dir which is equal to mnt_fsname of
465 * input mntent and replace it by new one.
466 */
467static void FAST_FUNC update_mtab_entry_on_move(const struct mntent *mp)
468{
469 struct mntent *entries, *m;
470 int i, count;
471 FILE *mountTable;
472
473 mountTable = setmntent(bb_path_mtab_file, "r");
474 if (!mountTable) {
475 bb_perror_msg(bb_path_mtab_file);
476 return;
477 }
478
479 entries = NULL;
480 count = 0;
481 while ((m = getmntent(mountTable)) != NULL) {
482 entries = xrealloc_vector(entries, 3, count);
483 entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
484 entries[count].mnt_dir = xstrdup(m->mnt_dir);
485 entries[count].mnt_type = xstrdup(m->mnt_type);
486 entries[count].mnt_opts = xstrdup(m->mnt_opts);
487 entries[count].mnt_freq = m->mnt_freq;
488 entries[count].mnt_passno = m->mnt_passno;
489 count++;
490 }
491 endmntent(mountTable);
492
493 mountTable = setmntent(bb_path_mtab_file, "w");
494 if (mountTable) {
495 for (i = 0; i < count; i++) {
496 if (strcmp(entries[i].mnt_dir, mp->mnt_fsname) != 0)
497 addmntent(mountTable, &entries[i]);
498 else
499 addmntent(mountTable, mp);
500 }
501 endmntent(mountTable);
502 } else if (errno != EROFS)
503 bb_perror_msg(bb_path_mtab_file);
504
505 if (ENABLE_FEATURE_CLEAN_UP) {
506 for (i = 0; i < count; i++) {
507 free(entries[i].mnt_fsname);
508 free(entries[i].mnt_dir);
509 free(entries[i].mnt_type);
510 free(entries[i].mnt_opts);
511 }
512 free(entries);
513 }
514}
515#endif
Denis Vlasenkof732e962008-02-18 12:07:49 +0000516
517#if ENABLE_FEATURE_MOUNT_VERBOSE
518static int verbose_mount(const char *source, const char *target,
519 const char *filesystemtype,
520 unsigned long mountflags, const void *data)
521{
522 int rc;
523
524 errno = 0;
525 rc = mount(source, target, filesystemtype, mountflags, data);
526 if (verbose >= 2)
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000527 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
Denis Vlasenkob4133682008-02-18 13:05:38 +0000528 source, target, filesystemtype,
529 mountflags, (char*)data, rc);
Denis Vlasenkof732e962008-02-18 12:07:49 +0000530 return rc;
531}
532#else
533#define verbose_mount(...) mount(__VA_ARGS__)
534#endif
535
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000536// Append mount options to string
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000537static void append_mount_options(char **oldopts, const char *newopts)
Eric Andersencc8ed391999-10-05 16:24:54 +0000538{
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000539 if (*oldopts && **oldopts) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000540 // Do not insert options which are already there
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000541 while (newopts[0]) {
542 char *p;
543 int len = strlen(newopts);
544 p = strchr(newopts, ',');
545 if (p) len = p - newopts;
546 p = *oldopts;
547 while (1) {
Denis Vlasenko13c5a682006-10-16 22:39:51 +0000548 if (!strncmp(p, newopts, len)
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000549 && (p[len] == ',' || p[len] == '\0'))
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000550 goto skip;
551 p = strchr(p,',');
Denis Vlasenko51742f42007-04-12 00:32:05 +0000552 if (!p) break;
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000553 p++;
554 }
555 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
556 free(*oldopts);
557 *oldopts = p;
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000558 skip:
Denis Vlasenkoc889d2b2006-09-17 15:08:12 +0000559 newopts += len;
560 while (newopts[0] == ',') newopts++;
561 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000562 } else {
563 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000564 *oldopts = xstrdup(newopts);
Rob Landleydc0955b2006-03-14 18:16:25 +0000565 }
566}
567
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000568// Use the mount_options list to parse options into flags.
Alexander Shishkin77650952010-10-28 06:10:03 +0200569// Also update list of unrecognized options if unrecognized != NULL
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200570static unsigned long parse_mount_options(char *options, char **unrecognized)
Rob Landleydc0955b2006-03-14 18:16:25 +0000571{
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200572 unsigned long flags = MS_SILENT;
Rob Landleydc0955b2006-03-14 18:16:25 +0000573
Rob Landley6a6798b2005-08-10 20:35:54 +0000574 // Loop through options
Rob Landleydc0955b2006-03-14 18:16:25 +0000575 for (;;) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000576 unsigned i;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000577 char *comma = strchr(options, ',');
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000578 const char *option_str = mount_option_str;
Eric Andersencc8ed391999-10-05 16:24:54 +0000579
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000580 if (comma) *comma = '\0';
Eric Andersen3ae0c781999-11-04 01:13:21 +0000581
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000582// FIXME: use hasmntopt()
Rob Landley6a6798b2005-08-10 20:35:54 +0000583 // Find this option in mount_options
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000584 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200585 unsigned opt_len = strlen(option_str);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100586
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200587 if (strncasecmp(option_str, options, opt_len) == 0
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +0100588 && (options[opt_len] == '\0'
589 /* or is it "comment=" thingy in fstab? */
590 IF_FEATURE_MOUNT_FSTAB(IF_DESKTOP( || option_str[opt_len-1] == '=' ))
591 )
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200592 ) {
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200593 unsigned long fl = mount_options[i];
Denys Vlasenko9ad89792012-06-26 16:09:00 +0200594 if (fl & BB_MS_INVERTED_VALUE)
Alexander Shishkin77650952010-10-28 06:10:03 +0200595 flags &= fl;
596 else
597 flags |= fl;
598 goto found;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000599 }
Denys Vlasenko6ebb2b62012-06-22 15:17:18 +0200600 option_str += opt_len + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000601 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200602 // We did not recognize this option.
603 // If "unrecognized" is not NULL, append option there.
604 // Note that we should not append *empty* option -
605 // in this case we want to pass NULL, not "", to "data"
606 // parameter of mount(2) syscall.
607 // This is crucial for filesystems that don't accept
608 // any arbitrary mount options, like cgroup fs:
609 // "mount -t cgroup none /mnt"
610 if (options[0] && unrecognized) {
Rob Landley6a6798b2005-08-10 20:35:54 +0000611 // Add it to strflags, to pass on to kernel
Alexander Shishkin77650952010-10-28 06:10:03 +0200612 char *p = *unrecognized;
613 unsigned len = p ? strlen(p) : 0;
614 *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
Eric Andersen9601a1c2006-03-20 18:07:50 +0000615
Rob Landley6a6798b2005-08-10 20:35:54 +0000616 // Comma separated if it's not the first one
Alexander Shishkin77650952010-10-28 06:10:03 +0200617 if (len) p[len++] = ',';
618 strcpy(p + len, options);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000619 }
Alexander Shishkin77650952010-10-28 06:10:03 +0200620 found:
Denis Vlasenko2535f122007-09-15 13:28:30 +0000621 if (!comma)
622 break;
623 // Advance to next option
624 *comma = ',';
625 options = ++comma;
Eric Andersencc8ed391999-10-05 16:24:54 +0000626 }
Eric Andersen9601a1c2006-03-20 18:07:50 +0000627
Rob Landleydc0955b2006-03-14 18:16:25 +0000628 return flags;
Eric Andersencc8ed391999-10-05 16:24:54 +0000629}
630
Rob Landleydc0955b2006-03-14 18:16:25 +0000631// Return a list of all block device backed filesystems
Rob Landleydc0955b2006-03-14 18:16:25 +0000632static llist_t *get_block_backed_filesystems(void)
Eric Andersencc8ed391999-10-05 16:24:54 +0000633{
Denis Vlasenko87468852007-04-13 23:22:00 +0000634 static const char filesystems[2][sizeof("/proc/filesystems")] = {
Denis Vlasenko372686b2006-10-12 22:42:33 +0000635 "/etc/filesystems",
636 "/proc/filesystems",
Denis Vlasenko372686b2006-10-12 22:42:33 +0000637 };
638 char *fs, *buf;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200639 llist_t *list = NULL;
Rob Landleydc0955b2006-03-14 18:16:25 +0000640 int i;
641 FILE *f;
Eric Andersencc8ed391999-10-05 16:24:54 +0000642
Denis Vlasenko87468852007-04-13 23:22:00 +0000643 for (i = 0; i < 2; i++) {
Denis Vlasenko5415c852008-07-21 23:05:26 +0000644 f = fopen_for_read(filesystems[i]);
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000645 if (!f) continue;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000646
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000647 while ((buf = xmalloc_fgetline(f)) != NULL) {
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100648 if (is_prefixed_with(buf, "nodev") && isspace(buf[5]))
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100649 goto next;
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000650 fs = skip_whitespace(buf);
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200651 if (*fs == '#' || *fs == '*' || !*fs)
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100652 goto next;
Eric Andersen9601a1c2006-03-20 18:07:50 +0000653
Denis Vlasenko372686b2006-10-12 22:42:33 +0000654 llist_add_to_end(&list, xstrdup(fs));
Denys Vlasenkof85554c2011-11-03 09:54:53 +0100655 next:
Denis Vlasenko372686b2006-10-12 22:42:33 +0000656 free(buf);
Rob Landleydc0955b2006-03-14 18:16:25 +0000657 }
658 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
659 }
660
661 return list;
662}
663
Rob Landleydc0955b2006-03-14 18:16:25 +0000664#if ENABLE_FEATURE_CLEAN_UP
665static void delete_block_backed_filesystems(void)
666{
Rob Landleya6b5b602006-05-08 19:03:07 +0000667 llist_free(fslist, free);
Rob Landleydc0955b2006-03-14 18:16:25 +0000668}
Rob Landleyfe908fd2006-03-29 14:30:49 +0000669#else
670void delete_block_backed_filesystems(void);
Rob Landleydc0955b2006-03-14 18:16:25 +0000671#endif
672
Rob Landleydc0955b2006-03-14 18:16:25 +0000673// Perform actual mount of specific filesystem at specific location.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000674// NB: mp->xxx fields may be trashed on exit
Denys Vlasenko9ee42662012-06-21 12:08:56 +0200675static int mount_it_now(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Rob Landleydc0955b2006-03-14 18:16:25 +0000676{
Denis Vlasenkob1726782006-09-29 14:43:20 +0000677 int rc = 0;
Rob Landleyeaa34ca2006-03-18 02:58:11 +0000678
Denys Vlasenko911d2652015-12-30 20:11:34 +0100679 vfsflags &= ~(unsigned long)MOUNT_FAKEFLAGS;
680
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200681 if (FAKE_IT) {
Denis Vlasenkob4133682008-02-18 13:05:38 +0000682 if (verbose >= 2)
683 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
684 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
685 vfsflags, filteropts);
686 goto mtab;
687 }
Eric Andersen19b5b8f2006-03-20 18:07:13 +0000688
Rob Landleydc0955b2006-03-14 18:16:25 +0000689 // Mount, with fallback to read-only if necessary.
Denis Vlasenko8d474b52006-09-17 15:00:58 +0000690 for (;;) {
Denis Vlasenkof732e962008-02-18 12:07:49 +0000691 errno = 0;
692 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
Rob Landleydc0955b2006-03-14 18:16:25 +0000693 vfsflags, filteropts);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000694
695 // If mount failed, try
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +0000696 // helper program mount.<mnt_type>
Denys Vlasenkoba986032009-09-15 23:00:09 +0200697 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200698 char *args[8];
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000699 int errno_save = errno;
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000700 args[0] = xasprintf("mount.%s", mp->mnt_type);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000701 rc = 1;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200702 if (FAKE_IT)
703 args[rc++] = (char *)"-f";
704 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
705 args[rc++] = (char *)"-n";
Denis Vlasenko5c329932009-04-12 12:16:21 +0000706 args[rc++] = mp->mnt_fsname;
707 args[rc++] = mp->mnt_dir;
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000708 if (filteropts) {
709 args[rc++] = (char *)"-o";
710 args[rc++] = filteropts;
711 }
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000712 args[rc] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +0100713 rc = spawn_and_wait(args);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +0000714 free(args[0]);
Denis Vlasenko32d49bc2008-02-03 23:52:41 +0000715 if (!rc)
716 break;
717 errno = errno_save;
718 }
719
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000720 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
Rob Landleydc0955b2006-03-14 18:16:25 +0000721 break;
Denis Vlasenko2535f122007-09-15 13:28:30 +0000722 if (!(vfsflags & MS_SILENT))
723 bb_error_msg("%s is write-protected, mounting read-only",
724 mp->mnt_fsname);
Rob Landleydc0955b2006-03-14 18:16:25 +0000725 vfsflags |= MS_RDONLY;
726 }
727
Rob Landleydc0955b2006-03-14 18:16:25 +0000728 // Abort entirely if permission denied.
729
730 if (rc && errno == EPERM)
731 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
732
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000733 // If the mount was successful, and we're maintaining an old-style
734 // mtab file by hand, add the new entry to it now.
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000735 mtab:
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +0200736 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000737 char *fsname;
Rob Landleydc0955b2006-03-14 18:16:25 +0000738 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000739 const char *option_str = mount_option_str;
Rob Landleydc0955b2006-03-14 18:16:25 +0000740 int i;
741
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000742 if (!mountTable) {
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100743 bb_perror_msg(bb_path_mtab_file);
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000744 goto ret;
745 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000746
747 // Add vfs string flags
Denis Vlasenko63430ae2007-10-29 19:18:39 +0000748 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
749 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
750 append_mount_options(&(mp->mnt_opts), option_str);
751 option_str += strlen(option_str) + 1;
752 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000753
754 // Remove trailing / (if any) from directory we mounted on
Denis Vlasenko727ef942006-09-14 13:19:19 +0000755 i = strlen(mp->mnt_dir) - 1;
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100756 while (i > 0 && mp->mnt_dir[i] == '/')
Denys Vlasenkoc6450c92011-02-28 11:09:49 +0100757 mp->mnt_dir[i--] = '\0';
Denis Vlasenko727ef942006-09-14 13:19:19 +0000758
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000759 // Convert to canonical pathnames as needed
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000760 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100761 fsname = NULL;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +0000762 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000763 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000764 mp->mnt_type = (char*)"bind";
Denis Vlasenko727ef942006-09-14 13:19:19 +0000765 }
Denis Vlasenko25098f72006-09-14 15:46:33 +0000766 mp->mnt_freq = mp->mnt_passno = 0;
Rob Landleydc0955b2006-03-14 18:16:25 +0000767
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100768 // Write and close
769#if ENABLE_FEATURE_MTAB_SUPPORT
770 if (vfsflags & MS_MOVE)
771 update_mtab_entry_on_move(mp);
772 else
773#endif
774 addmntent(mountTable, mp);
Rob Landleydc0955b2006-03-14 18:16:25 +0000775 endmntent(mountTable);
Roman Borisovc8dc01d2011-02-28 05:06:01 +0100776
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000777 if (ENABLE_FEATURE_CLEAN_UP) {
Denis Vlasenkoa52145a2006-09-17 15:09:48 +0000778 free(mp->mnt_dir);
Denis Vlasenkofc56dd22006-09-17 15:01:53 +0000779 free(fsname);
780 }
Rob Landleydc0955b2006-03-14 18:16:25 +0000781 }
Denis Vlasenko6a353c82006-11-19 17:34:57 +0000782 ret:
Rob Landleydc0955b2006-03-14 18:16:25 +0000783 return rc;
784}
785
Denis Vlasenko25098f72006-09-14 15:46:33 +0000786#if ENABLE_FEATURE_MOUNT_NFS
787
788/*
789 * Linux NFS mount
790 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
791 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +0200792 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko25098f72006-09-14 15:46:33 +0000793 *
794 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
795 * numbers to be specified on the command line.
796 *
797 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
798 * Omit the call to connect() for Linux version 1.3.11 or later.
799 *
800 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
801 * Implemented the "bg", "fg" and "retry" mount options for NFS.
802 *
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000803 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
Denis Vlasenko25098f72006-09-14 15:46:33 +0000804 * - added Native Language Support
805 *
806 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
807 * plus NFSv3 stuff.
808 */
809
Denis Vlasenko25098f72006-09-14 15:46:33 +0000810#define MOUNTPORT 635
811#define MNTPATHLEN 1024
812#define MNTNAMLEN 255
813#define FHSIZE 32
814#define FHSIZE3 64
815
816typedef char fhandle[FHSIZE];
817
818typedef struct {
819 unsigned int fhandle3_len;
820 char *fhandle3_val;
821} fhandle3;
822
823enum mountstat3 {
824 MNT_OK = 0,
825 MNT3ERR_PERM = 1,
826 MNT3ERR_NOENT = 2,
827 MNT3ERR_IO = 5,
828 MNT3ERR_ACCES = 13,
829 MNT3ERR_NOTDIR = 20,
830 MNT3ERR_INVAL = 22,
831 MNT3ERR_NAMETOOLONG = 63,
832 MNT3ERR_NOTSUPP = 10004,
833 MNT3ERR_SERVERFAULT = 10006,
834};
835typedef enum mountstat3 mountstat3;
836
837struct fhstatus {
838 unsigned int fhs_status;
839 union {
840 fhandle fhs_fhandle;
841 } fhstatus_u;
842};
843typedef struct fhstatus fhstatus;
844
845struct mountres3_ok {
846 fhandle3 fhandle;
847 struct {
848 unsigned int auth_flavours_len;
849 char *auth_flavours_val;
850 } auth_flavours;
851};
852typedef struct mountres3_ok mountres3_ok;
853
854struct mountres3 {
855 mountstat3 fhs_status;
856 union {
857 mountres3_ok mountinfo;
858 } mountres3_u;
859};
860typedef struct mountres3 mountres3;
861
862typedef char *dirpath;
863
864typedef char *name;
865
866typedef struct mountbody *mountlist;
867
868struct mountbody {
869 name ml_hostname;
870 dirpath ml_directory;
871 mountlist ml_next;
872};
873typedef struct mountbody mountbody;
874
875typedef struct groupnode *groups;
876
877struct groupnode {
878 name gr_name;
879 groups gr_next;
880};
881typedef struct groupnode groupnode;
882
883typedef struct exportnode *exports;
884
885struct exportnode {
886 dirpath ex_dir;
887 groups ex_groups;
888 exports ex_next;
889};
890typedef struct exportnode exportnode;
891
892struct ppathcnf {
893 int pc_link_max;
894 short pc_max_canon;
895 short pc_max_input;
896 short pc_name_max;
897 short pc_path_max;
898 short pc_pipe_buf;
Denis Vlasenko28703012006-12-19 20:32:02 +0000899 uint8_t pc_vdisable;
Denis Vlasenko25098f72006-09-14 15:46:33 +0000900 char pc_xxx;
901 short pc_mask[2];
902};
903typedef struct ppathcnf ppathcnf;
904
905#define MOUNTPROG 100005
906#define MOUNTVERS 1
907
908#define MOUNTPROC_NULL 0
909#define MOUNTPROC_MNT 1
910#define MOUNTPROC_DUMP 2
911#define MOUNTPROC_UMNT 3
912#define MOUNTPROC_UMNTALL 4
913#define MOUNTPROC_EXPORT 5
914#define MOUNTPROC_EXPORTALL 6
915
916#define MOUNTVERS_POSIX 2
917
918#define MOUNTPROC_PATHCONF 7
919
920#define MOUNT_V3 3
921
922#define MOUNTPROC3_NULL 0
923#define MOUNTPROC3_MNT 1
924#define MOUNTPROC3_DUMP 2
925#define MOUNTPROC3_UMNT 3
926#define MOUNTPROC3_UMNTALL 4
927#define MOUNTPROC3_EXPORT 5
928
929enum {
930#ifndef NFS_FHSIZE
931 NFS_FHSIZE = 32,
932#endif
933#ifndef NFS_PORT
934 NFS_PORT = 2049
935#endif
936};
937
Denis Vlasenko25098f72006-09-14 15:46:33 +0000938/*
939 * We want to be able to compile mount on old kernels in such a way
940 * that the binary will work well on more recent kernels.
941 * Thus, if necessary we teach nfsmount.c the structure of new fields
942 * that will come later.
943 *
944 * Moreover, the new kernel includes conflict with glibc includes
945 * so it is easiest to ignore the kernel altogether (at compile time).
946 */
947
948struct nfs2_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100949 char data[32];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000950};
951struct nfs3_fh {
Dave Lovefae473c2011-11-10 15:19:25 +0100952 unsigned short size;
953 unsigned char data[64];
Denis Vlasenko25098f72006-09-14 15:46:33 +0000954};
955
956struct nfs_mount_data {
Dave Lovefae473c2011-11-10 15:19:25 +0100957 int version; /* 1 */
958 int fd; /* 1 */
959 struct nfs2_fh old_root; /* 1 */
960 int flags; /* 1 */
961 int rsize; /* 1 */
962 int wsize; /* 1 */
963 int timeo; /* 1 */
964 int retrans; /* 1 */
965 int acregmin; /* 1 */
966 int acregmax; /* 1 */
967 int acdirmin; /* 1 */
968 int acdirmax; /* 1 */
969 struct sockaddr_in addr; /* 1 */
970 char hostname[256]; /* 1 */
971 int namlen; /* 2 */
972 unsigned int bsize; /* 3 */
973 struct nfs3_fh root; /* 4 */
Denis Vlasenko25098f72006-09-14 15:46:33 +0000974};
975
976/* bits in the flags field */
977enum {
978 NFS_MOUNT_SOFT = 0x0001, /* 1 */
979 NFS_MOUNT_INTR = 0x0002, /* 1 */
980 NFS_MOUNT_SECURE = 0x0004, /* 1 */
981 NFS_MOUNT_POSIX = 0x0008, /* 1 */
982 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
983 NFS_MOUNT_NOAC = 0x0020, /* 1 */
984 NFS_MOUNT_TCP = 0x0040, /* 2 */
985 NFS_MOUNT_VER3 = 0x0080, /* 3 */
986 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000987 NFS_MOUNT_NONLM = 0x0200, /* 3 */
Dave Lovefae473c2011-11-10 15:19:25 +0100988 NFS_MOUNT_NOACL = 0x0800, /* 4 */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +0000989 NFS_MOUNT_NORDIRPLUS = 0x4000
Denis Vlasenko25098f72006-09-14 15:46:33 +0000990};
991
992
993/*
994 * We need to translate between nfs status return values and
995 * the local errno values which may not be the same.
996 *
997 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
998 * "after #include <errno.h> the symbol errno is reserved for any use,
999 * it cannot even be used as a struct tag or field name".
1000 */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001001#ifndef EDQUOT
Denys Vlasenkocc428142009-12-16 02:06:56 +01001002# define EDQUOT ENOSPC
Denis Vlasenko25098f72006-09-14 15:46:33 +00001003#endif
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001004/* Convert each NFSERR_BLAH into EBLAH */
Denys Vlasenkocc428142009-12-16 02:06:56 +01001005static const uint8_t nfs_err_stat[] = {
1006 1, 2, 5, 6, 13, 17,
1007 19, 20, 21, 22, 27, 28,
1008 30, 63, 66, 69, 70, 71
1009};
Denys Vlasenkodc1fd2e2010-05-19 17:01:29 +02001010#if ( \
1011 EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
1012 ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
1013 EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
1014typedef uint8_t nfs_err_type;
1015#else
1016typedef uint16_t nfs_err_type;
1017#endif
1018static const nfs_err_type nfs_err_errnum[] = {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001019 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
1020 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
1021 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
Denis Vlasenko25098f72006-09-14 15:46:33 +00001022};
Denis Vlasenko25098f72006-09-14 15:46:33 +00001023static char *nfs_strerror(int status)
1024{
1025 int i;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001026
Denys Vlasenkocc428142009-12-16 02:06:56 +01001027 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
1028 if (nfs_err_stat[i] == status)
1029 return strerror(nfs_err_errnum[i]);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001030 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001031 return xasprintf("unknown nfs status return value: %d", status);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001032}
1033
1034static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
1035{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001036 return xdr_opaque(xdrs, objp, FHSIZE);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001037}
1038
1039static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
1040{
1041 if (!xdr_u_int(xdrs, &objp->fhs_status))
Denys Vlasenko69675782013-01-14 01:34:48 +01001042 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001043 if (objp->fhs_status == 0)
1044 return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001045 return TRUE;
1046}
1047
1048static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
1049{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001050 return xdr_string(xdrs, objp, MNTPATHLEN);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001051}
1052
1053static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
1054{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001055 return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
Denys Vlasenko69675782013-01-14 01:34:48 +01001056 (unsigned int *) &objp->fhandle3_len,
1057 FHSIZE3);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001058}
1059
1060static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
1061{
1062 if (!xdr_fhandle3(xdrs, &objp->fhandle))
1063 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001064 return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
Denys Vlasenko69675782013-01-14 01:34:48 +01001065 &(objp->auth_flavours.auth_flavours_len),
1066 ~0,
1067 sizeof(int),
1068 (xdrproc_t) xdr_int);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001069}
1070
1071static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
1072{
Alexander Shishkin54779a42010-10-22 13:35:47 +02001073 return xdr_enum(xdrs, (enum_t *) objp);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001074}
1075
1076static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
1077{
1078 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
1079 return FALSE;
Alexander Shishkin54779a42010-10-22 13:35:47 +02001080 if (objp->fhs_status == MNT_OK)
1081 return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001082 return TRUE;
1083}
1084
1085#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
1086
Denis Vlasenko25098f72006-09-14 15:46:33 +00001087/*
1088 * Unfortunately, the kernel prints annoying console messages
1089 * in case of an unexpected nfs mount version (instead of
1090 * just returning some error). Therefore we'll have to try
1091 * and figure out what version the kernel expects.
1092 *
1093 * Variables:
1094 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
1095 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
1096 * nfs_mount_version: version this source and running kernel can handle
1097 */
1098static void
1099find_kernel_nfs_mount_version(void)
1100{
Denis Vlasenkob9256052007-09-28 10:29:17 +00001101 int kernel_version;
1102
1103 if (nfs_mount_version)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001104 return;
1105
1106 nfs_mount_version = 4; /* default */
1107
1108 kernel_version = get_linux_version_code();
1109 if (kernel_version) {
Denys Vlasenkocc428142009-12-16 02:06:56 +01001110 if (kernel_version < KERNEL_VERSION(2,2,18))
Denis Vlasenko25098f72006-09-14 15:46:33 +00001111 nfs_mount_version = 3;
1112 /* else v4 since 2.3.99pre4 */
1113 }
1114}
1115
Denis Vlasenko3f5fdc72007-10-14 04:55:59 +00001116static void
Denis Vlasenkob9256052007-09-28 10:29:17 +00001117get_mountport(struct pmap *pm_mnt,
1118 struct sockaddr_in *server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001119 long unsigned prog,
1120 long unsigned version,
1121 long unsigned proto,
1122 long unsigned port)
1123{
1124 struct pmaplist *pmap;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001125
1126 server_addr->sin_port = PMAPPORT;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001127/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
1128 * I understand it like "IPv6 for this is not 100% ready" */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001129 pmap = pmap_getmaps(server_addr);
1130
1131 if (version > MAX_NFSPROT)
1132 version = MAX_NFSPROT;
1133 if (!prog)
1134 prog = MOUNTPROG;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001135 pm_mnt->pm_prog = prog;
1136 pm_mnt->pm_vers = version;
1137 pm_mnt->pm_prot = proto;
1138 pm_mnt->pm_port = port;
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00001139
Denis Vlasenko25098f72006-09-14 15:46:33 +00001140 while (pmap) {
1141 if (pmap->pml_map.pm_prog != prog)
1142 goto next;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001143 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001144 goto next;
1145 if (version > 2 && pmap->pml_map.pm_vers != version)
1146 goto next;
1147 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
1148 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001149 if (pmap->pml_map.pm_vers > MAX_NFSPROT
1150 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
1151 || (port && pmap->pml_map.pm_port != port)
1152 ) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001153 goto next;
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01001154 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001155 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
1156 next:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001157 pmap = pmap->pml_next;
1158 }
Denis Vlasenkob9256052007-09-28 10:29:17 +00001159 if (!pm_mnt->pm_vers)
1160 pm_mnt->pm_vers = MOUNTVERS;
1161 if (!pm_mnt->pm_port)
1162 pm_mnt->pm_port = MOUNTPORT;
1163 if (!pm_mnt->pm_prot)
1164 pm_mnt->pm_prot = IPPROTO_TCP;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001165}
1166
Denis Vlasenkof0000652007-09-04 18:30:26 +00001167#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001168static int daemonize(void)
1169{
Denis Vlasenko25098f72006-09-14 15:46:33 +00001170 int pid = fork();
1171 if (pid < 0) /* error */
1172 return -errno;
1173 if (pid > 0) /* parent */
1174 return 0;
1175 /* child */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001176 close(0);
1177 xopen(bb_dev_null, O_RDWR);
1178 xdup2(0, 1);
1179 xdup2(0, 2);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001180 setsid();
Denis Vlasenko8f8f2682006-10-03 21:00:43 +00001181 openlog(applet_name, LOG_PID, LOG_DAEMON);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001182 logmode = LOGMODE_SYSLOG;
1183 return 1;
1184}
Denis Vlasenkof0000652007-09-04 18:30:26 +00001185#else
1186static inline int daemonize(void) { return -ENOSYS; }
1187#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001188
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001189/* TODO */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001190static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001191{
1192 return 0;
1193}
1194
1195/* RPC strerror analogs are terminally idiotic:
1196 * *mandatory* prefix and \n at end.
1197 * This hopefully helps. Usage:
1198 * error_msg_rpc(clnt_*error*(" ")) */
1199static void error_msg_rpc(const char *msg)
1200{
Denis Vlasenko23514fe2006-09-19 14:07:52 +00001201 int len;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001202 while (msg[0] == ' ' || msg[0] == ':') msg++;
1203 len = strlen(msg);
1204 while (len && msg[len-1] == '\n') len--;
1205 bb_error_msg("%.*s", len, msg);
1206}
1207
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001208/* NB: mp->xxx fields may be trashed on exit */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001209static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001210{
1211 CLIENT *mclient;
1212 char *hostname;
1213 char *pathname;
1214 char *mounthost;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001215 /* prior to 2.6.23, kernel took NFS options in a form of this struct
1216 * only. 2.6.23+ looks at data->version, and if it's not 1..6,
1217 * then data pointer is interpreted as a string. */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001218 struct nfs_mount_data data;
1219 char *opt;
1220 struct hostent *hp;
1221 struct sockaddr_in server_addr;
1222 struct sockaddr_in mount_server_addr;
1223 int msock, fsock;
1224 union {
1225 struct fhstatus nfsv2;
1226 struct mountres3 nfsv3;
1227 } status;
1228 int daemonized;
1229 char *s;
1230 int port;
1231 int mountport;
1232 int proto;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001233#if BB_MMU
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001234 smallint bg = 0;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001235#else
1236 enum { bg = 0 };
1237#endif
Denis Vlasenko25098f72006-09-14 15:46:33 +00001238 int retry;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001239 int mountprog;
1240 int mountvers;
1241 int nfsprog;
1242 int nfsvers;
1243 int retval;
Denys Vlasenkoe71dd7c2009-05-13 16:32:32 +02001244 /* these all are one-bit really. gcc 4.3.1 likes this combination: */
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001245 smallint tcp;
1246 smallint soft;
1247 int intr;
1248 int posix;
1249 int nocto;
1250 int noac;
1251 int nordirplus;
1252 int nolock;
Dave Lovefae473c2011-11-10 15:19:25 +01001253 int noacl;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001254
1255 find_kernel_nfs_mount_version();
1256
1257 daemonized = 0;
1258 mounthost = NULL;
1259 retval = ETIMEDOUT;
1260 msock = fsock = -1;
1261 mclient = NULL;
1262
1263 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1264
1265 filteropts = xstrdup(filteropts); /* going to trash it later... */
1266
1267 hostname = xstrdup(mp->mnt_fsname);
1268 /* mount_main() guarantees that ':' is there */
1269 s = strchr(hostname, ':');
1270 pathname = s + 1;
1271 *s = '\0';
1272 /* Ignore all but first hostname in replicated mounts
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001273 * until they can be fully supported. (mack@sgi.com) */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001274 s = strchr(hostname, ',');
1275 if (s) {
1276 *s = '\0';
1277 bb_error_msg("warning: multiple hostnames not supported");
1278 }
1279
1280 server_addr.sin_family = AF_INET;
1281 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1282 hp = gethostbyname(hostname);
1283 if (hp == NULL) {
1284 bb_herror_msg("%s", hostname);
1285 goto fail;
1286 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001287 if (hp->h_length != (int)sizeof(struct in_addr)) {
1288 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko25098f72006-09-14 15:46:33 +00001289 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001290 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001291 }
1292
1293 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1294
1295 /* add IP address to mtab options for use when unmounting */
1296
1297 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1298 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1299 } else {
1300 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1301 mp->mnt_opts[0] ? "," : "",
1302 inet_ntoa(server_addr.sin_addr));
1303 free(mp->mnt_opts);
1304 mp->mnt_opts = tmp;
1305 }
1306
1307 /* Set default options.
1308 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1309 * let the kernel decide.
1310 * timeo is filled in after we know whether it'll be TCP or UDP. */
1311 memset(&data, 0, sizeof(data));
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001312 data.retrans = 3;
1313 data.acregmin = 3;
1314 data.acregmax = 60;
1315 data.acdirmin = 30;
1316 data.acdirmax = 60;
1317 data.namlen = NAME_MAX;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001318
Denis Vlasenko25098f72006-09-14 15:46:33 +00001319 soft = 0;
1320 intr = 0;
1321 posix = 0;
1322 nocto = 0;
1323 nolock = 0;
1324 noac = 0;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001325 nordirplus = 0;
Dave Lovefae473c2011-11-10 15:19:25 +01001326 noacl = 0;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001327 retry = 10000; /* 10000 minutes ~ 1 week */
Bernhard Reutner-Fischer88206292011-05-04 19:03:30 +02001328 tcp = 1; /* nfs-utils uses tcp per default */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001329
1330 mountprog = MOUNTPROG;
1331 mountvers = 0;
1332 port = 0;
1333 mountport = 0;
1334 nfsprog = 100003;
1335 nfsvers = 0;
1336
1337 /* parse options */
Denis Vlasenko68de7202007-05-09 20:38:04 +00001338 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001339 char *opteq = strchr(opt, '=');
1340 if (opteq) {
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001341 int val, idx;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001342 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001343 /* 0 */ "rsize\0"
1344 /* 1 */ "wsize\0"
1345 /* 2 */ "timeo\0"
1346 /* 3 */ "retrans\0"
1347 /* 4 */ "acregmin\0"
1348 /* 5 */ "acregmax\0"
1349 /* 6 */ "acdirmin\0"
1350 /* 7 */ "acdirmax\0"
1351 /* 8 */ "actimeo\0"
1352 /* 9 */ "retry\0"
1353 /* 10 */ "port\0"
1354 /* 11 */ "mountport\0"
1355 /* 12 */ "mounthost\0"
1356 /* 13 */ "mountprog\0"
1357 /* 14 */ "mountvers\0"
1358 /* 15 */ "nfsprog\0"
1359 /* 16 */ "nfsvers\0"
1360 /* 17 */ "vers\0"
1361 /* 18 */ "proto\0"
1362 /* 19 */ "namlen\0"
1363 /* 20 */ "addr\0";
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001364
1365 *opteq++ = '\0';
1366 idx = index_in_strings(options, opt);
1367 switch (idx) {
1368 case 12: // "mounthost"
1369 mounthost = xstrndup(opteq,
1370 strcspn(opteq, " \t\n\r,"));
1371 continue;
1372 case 18: // "proto"
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001373 if (is_prefixed_with(opteq, "tcp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001374 tcp = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001375 else if (is_prefixed_with(opteq, "udp"))
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001376 tcp = 0;
1377 else
1378 bb_error_msg("warning: unrecognized proto= option");
1379 continue;
1380 case 20: // "addr" - ignore
1381 continue;
Peter Korsgaard301fe502011-02-21 17:52:13 +01001382 case -1: // unknown
1383 if (vfsflags & MS_REMOUNT)
1384 continue;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001385 }
1386
Denys Vlasenko77832482010-08-12 14:14:45 +02001387 val = xatoi_positive(opteq);
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001388 switch (idx) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001389 case 0: // "rsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001390 data.rsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001391 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001392 case 1: // "wsize"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001393 data.wsize = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001394 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001395 case 2: // "timeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001396 data.timeo = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001397 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001398 case 3: // "retrans"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001399 data.retrans = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001400 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001401 case 4: // "acregmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001402 data.acregmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001403 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001404 case 5: // "acregmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001405 data.acregmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001406 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001407 case 6: // "acdirmin"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001408 data.acdirmin = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001409 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001410 case 7: // "acdirmax"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001411 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001412 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001413 case 8: // "actimeo"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001414 data.acregmin = val;
1415 data.acregmax = val;
1416 data.acdirmin = val;
1417 data.acdirmax = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001418 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001419 case 9: // "retry"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001420 retry = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001421 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001422 case 10: // "port"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001423 port = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001424 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001425 case 11: // "mountport"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001426 mountport = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001427 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001428 case 13: // "mountprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001429 mountprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001430 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001431 case 14: // "mountvers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001432 mountvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001433 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001434 case 15: // "nfsprog"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001435 nfsprog = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001436 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001437 case 16: // "nfsvers"
1438 case 17: // "vers"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001439 nfsvers = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001440 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001441 case 19: // "namlen"
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001442 //if (nfs_mount_version >= 2)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001443 data.namlen = val;
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001444 //else
1445 // bb_error_msg("warning: option namlen is not supported\n");
1446 continue;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001447 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001448 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1449 goto fail;
1450 }
1451 }
Denis Vlasenkof26e3d22008-06-24 21:39:32 +00001452 else { /* not of the form opt=val */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00001453 static const char options[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001454 "bg\0"
1455 "fg\0"
1456 "soft\0"
1457 "hard\0"
1458 "intr\0"
1459 "posix\0"
1460 "cto\0"
1461 "ac\0"
1462 "tcp\0"
1463 "udp\0"
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001464 "lock\0"
Dave Lovefae473c2011-11-10 15:19:25 +01001465 "rdirplus\0"
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001466 "acl\0";
Denis Vlasenko25098f72006-09-14 15:46:33 +00001467 int val = 1;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001468 if (is_prefixed_with(opt, "no")) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001469 val = 0;
1470 opt += 2;
1471 }
Denis Vlasenko990d0f62007-07-24 15:54:42 +00001472 switch (index_in_strings(options, opt)) {
Denis Vlasenko68f21872006-10-26 01:47:34 +00001473 case 0: // "bg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001474#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001475 bg = val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001476#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001477 break;
1478 case 1: // "fg"
Denis Vlasenkof0000652007-09-04 18:30:26 +00001479#if BB_MMU
Denis Vlasenko25098f72006-09-14 15:46:33 +00001480 bg = !val;
Denis Vlasenkof0000652007-09-04 18:30:26 +00001481#endif
Denis Vlasenko68f21872006-10-26 01:47:34 +00001482 break;
1483 case 2: // "soft"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001484 soft = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001485 break;
1486 case 3: // "hard"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001487 soft = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001488 break;
1489 case 4: // "intr"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001490 intr = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001491 break;
1492 case 5: // "posix"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001493 posix = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001494 break;
1495 case 6: // "cto"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001496 nocto = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001497 break;
1498 case 7: // "ac"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001499 noac = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001500 break;
1501 case 8: // "tcp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001502 tcp = val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001503 break;
1504 case 9: // "udp"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001505 tcp = !val;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001506 break;
1507 case 10: // "lock"
Denis Vlasenko25098f72006-09-14 15:46:33 +00001508 if (nfs_mount_version >= 3)
1509 nolock = !val;
1510 else
1511 bb_error_msg("warning: option nolock is not supported");
Denis Vlasenko68f21872006-10-26 01:47:34 +00001512 break;
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001513 case 11: //rdirplus
1514 nordirplus = !val;
1515 break;
Dave Lovefae473c2011-11-10 15:19:25 +01001516 case 12: // acl
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001517 noacl = !val;
Dave Lovefae473c2011-11-10 15:19:25 +01001518 break;
Denis Vlasenko68f21872006-10-26 01:47:34 +00001519 default:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001520 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1521 goto fail;
1522 }
1523 }
1524 }
1525 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1526
1527 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1528 | (intr ? NFS_MOUNT_INTR : 0)
1529 | (posix ? NFS_MOUNT_POSIX : 0)
1530 | (nocto ? NFS_MOUNT_NOCTO : 0)
Denis Vlasenkoc29684a2008-07-19 22:40:30 +00001531 | (noac ? NFS_MOUNT_NOAC : 0)
Dave Lovefae473c2011-11-10 15:19:25 +01001532 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0)
Denys Vlasenko56443cd2012-04-20 15:07:22 +02001533 | (noacl ? NFS_MOUNT_NOACL : 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001534 if (nfs_mount_version >= 2)
1535 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1536 if (nfs_mount_version >= 3)
1537 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1538 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1539 bb_error_msg("NFSv%d not supported", nfsvers);
1540 goto fail;
1541 }
1542 if (nfsvers && !mountvers)
1543 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1544 if (nfsvers && nfsvers < mountvers) {
1545 mountvers = nfsvers;
1546 }
1547
1548 /* Adjust options if none specified */
1549 if (!data.timeo)
1550 data.timeo = tcp ? 70 : 7;
1551
Denis Vlasenko25098f72006-09-14 15:46:33 +00001552 data.version = nfs_mount_version;
1553
1554 if (vfsflags & MS_REMOUNT)
1555 goto do_mount;
1556
1557 /*
1558 * If the previous mount operation on the same host was
1559 * backgrounded, and the "bg" for this mount is also set,
1560 * give up immediately, to avoid the initial timeout.
1561 */
1562 if (bg && we_saw_this_host_before(hostname)) {
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001563 daemonized = daemonize();
Denis Vlasenko25098f72006-09-14 15:46:33 +00001564 if (daemonized <= 0) { /* parent or error */
1565 retval = -daemonized;
1566 goto ret;
1567 }
1568 }
1569
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001570 /* Create mount daemon client */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001571 /* See if the nfs host = mount host. */
1572 if (mounthost) {
1573 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1574 mount_server_addr.sin_family = AF_INET;
1575 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1576 } else {
1577 hp = gethostbyname(mounthost);
1578 if (hp == NULL) {
1579 bb_herror_msg("%s", mounthost);
1580 goto fail;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001581 }
Denys Vlasenko99069332010-02-27 19:38:19 +01001582 if (hp->h_length != (int)sizeof(struct in_addr)) {
1583 bb_error_msg_and_die("only IPv4 is supported");
Denis Vlasenko77ad97f2008-05-13 02:27:31 +00001584 }
1585 mount_server_addr.sin_family = AF_INET;
Denys Vlasenko99069332010-02-27 19:38:19 +01001586 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
Denis Vlasenko25098f72006-09-14 15:46:33 +00001587 }
1588 }
1589
1590 /*
1591 * The following loop implements the mount retries. When the mount
1592 * times out, and the "bg" option is set, we background ourself
1593 * and continue trying.
1594 *
1595 * The case where the mount point is not present and the "bg"
1596 * option is set, is treated as a timeout. This is done to
1597 * support nested mounts.
1598 *
1599 * The "retry" count specified by the user is the number of
1600 * minutes to retry before giving up.
1601 */
1602 {
1603 struct timeval total_timeout;
1604 struct timeval retry_timeout;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001605 struct pmap pm_mnt;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001606 time_t t;
1607 time_t prevt;
1608 time_t timeout;
1609
1610 retry_timeout.tv_sec = 3;
1611 retry_timeout.tv_usec = 0;
1612 total_timeout.tv_sec = 20;
1613 total_timeout.tv_usec = 0;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001614/* FIXME: use monotonic()? */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001615 timeout = time(NULL) + 60 * retry;
1616 prevt = 0;
1617 t = 30;
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001618 retry:
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001619 /* Be careful not to use too many CPU cycles */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001620 if (t - prevt < 30)
1621 sleep(30);
1622
Denis Vlasenkob9256052007-09-28 10:29:17 +00001623 get_mountport(&pm_mnt, &mount_server_addr,
Denis Vlasenko25098f72006-09-14 15:46:33 +00001624 mountprog,
1625 mountvers,
1626 proto,
1627 mountport);
Denis Vlasenkob9256052007-09-28 10:29:17 +00001628 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001629
1630 /* contact the mount daemon via TCP */
Denis Vlasenkob9256052007-09-28 10:29:17 +00001631 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001632 msock = RPC_ANYSOCK;
1633
Denis Vlasenkob9256052007-09-28 10:29:17 +00001634 switch (pm_mnt.pm_prot) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001635 case IPPROTO_UDP:
1636 mclient = clntudp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001637 pm_mnt.pm_prog,
1638 pm_mnt.pm_vers,
1639 retry_timeout,
1640 &msock);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001641 if (mclient)
1642 break;
Denis Vlasenkob9256052007-09-28 10:29:17 +00001643 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001644 msock = RPC_ANYSOCK;
1645 case IPPROTO_TCP:
1646 mclient = clnttcp_create(&mount_server_addr,
Denys Vlasenko69675782013-01-14 01:34:48 +01001647 pm_mnt.pm_prog,
1648 pm_mnt.pm_vers,
1649 &msock, 0, 0);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001650 break;
1651 default:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001652 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001653 }
1654 if (!mclient) {
1655 if (!daemonized && prevt == 0)
1656 error_msg_rpc(clnt_spcreateerror(" "));
1657 } else {
1658 enum clnt_stat clnt_stat;
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001659
1660 /* Try to mount hostname:pathname */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001661 mclient->cl_auth = authunix_create_default();
1662
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001663 /* Make pointers in xdr_mountres3 NULL so
Denis Vlasenko25098f72006-09-14 15:46:33 +00001664 * that xdr_array allocates memory for us
1665 */
1666 memset(&status, 0, sizeof(status));
1667
Denis Vlasenkob9256052007-09-28 10:29:17 +00001668 if (pm_mnt.pm_vers == 3)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001669 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001670 (xdrproc_t) xdr_dirpath,
1671 (caddr_t) &pathname,
1672 (xdrproc_t) xdr_mountres3,
1673 (caddr_t) &status,
1674 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001675 else
1676 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
Denys Vlasenko69675782013-01-14 01:34:48 +01001677 (xdrproc_t) xdr_dirpath,
1678 (caddr_t) &pathname,
1679 (xdrproc_t) xdr_fhstatus,
1680 (caddr_t) &status,
1681 total_timeout);
Denis Vlasenko25098f72006-09-14 15:46:33 +00001682
1683 if (clnt_stat == RPC_SUCCESS)
1684 goto prepare_kernel_data; /* we're done */
1685 if (errno != ECONNREFUSED) {
1686 error_msg_rpc(clnt_sperror(mclient, " "));
1687 goto fail; /* don't retry */
1688 }
1689 /* Connection refused */
1690 if (!daemonized && prevt == 0) /* print just once */
1691 error_msg_rpc(clnt_sperror(mclient, " "));
1692 auth_destroy(mclient->cl_auth);
1693 clnt_destroy(mclient);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001694 mclient = NULL;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001695 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001696 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001697 }
1698
1699 /* Timeout. We are going to retry... maybe */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001700 if (!bg)
1701 goto fail;
1702 if (!daemonized) {
1703 daemonized = daemonize();
1704 if (daemonized <= 0) { /* parent or error */
1705 retval = -daemonized;
1706 goto ret;
1707 }
1708 }
1709 prevt = t;
1710 t = time(NULL);
1711 if (t >= timeout)
1712 /* TODO error message */
1713 goto fail;
1714
1715 goto retry;
1716 }
1717
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001718 prepare_kernel_data:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001719
1720 if (nfsvers == 2) {
1721 if (status.nfsv2.fhs_status != 0) {
1722 bb_error_msg("%s:%s failed, reason given by server: %s",
1723 hostname, pathname,
1724 nfs_strerror(status.nfsv2.fhs_status));
1725 goto fail;
1726 }
1727 memcpy(data.root.data,
1728 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1729 NFS_FHSIZE);
1730 data.root.size = NFS_FHSIZE;
1731 memcpy(data.old_root.data,
1732 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1733 NFS_FHSIZE);
1734 } else {
1735 fhandle3 *my_fhandle;
1736 if (status.nfsv3.fhs_status != 0) {
1737 bb_error_msg("%s:%s failed, reason given by server: %s",
1738 hostname, pathname,
1739 nfs_strerror(status.nfsv3.fhs_status));
1740 goto fail;
1741 }
1742 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1743 memset(data.old_root.data, 0, NFS_FHSIZE);
1744 memset(&data.root, 0, sizeof(data.root));
1745 data.root.size = my_fhandle->fhandle3_len;
1746 memcpy(data.root.data,
1747 (char *) my_fhandle->fhandle3_val,
1748 my_fhandle->fhandle3_len);
1749
1750 data.flags |= NFS_MOUNT_VER3;
1751 }
1752
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001753 /* Create nfs socket for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001754 if (tcp) {
1755 if (nfs_mount_version < 3) {
1756 bb_error_msg("NFS over TCP is not supported");
1757 goto fail;
1758 }
1759 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1760 } else
1761 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1762 if (fsock < 0) {
1763 bb_perror_msg("nfs socket");
1764 goto fail;
1765 }
1766 if (bindresvport(fsock, 0) < 0) {
1767 bb_perror_msg("nfs bindresvport");
1768 goto fail;
1769 }
1770 if (port == 0) {
1771 server_addr.sin_port = PMAPPORT;
1772 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1773 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1774 if (port == 0)
1775 port = NFS_PORT;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001776 }
Denis Vlasenko25098f72006-09-14 15:46:33 +00001777 server_addr.sin_port = htons(port);
1778
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001779 /* Prepare data structure for kernel */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001780 data.fd = fsock;
1781 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1782 strncpy(data.hostname, hostname, sizeof(data.hostname));
1783
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001784 /* Clean up */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001785 auth_destroy(mclient->cl_auth);
1786 clnt_destroy(mclient);
1787 close(msock);
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001788 msock = -1;
Denis Vlasenko25098f72006-09-14 15:46:33 +00001789
1790 if (bg) {
1791 /* We must wait until mount directory is available */
1792 struct stat statbuf;
1793 int delay = 1;
1794 while (stat(mp->mnt_dir, &statbuf) == -1) {
1795 if (!daemonized) {
1796 daemonized = daemonize();
1797 if (daemonized <= 0) { /* parent or error */
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001798/* FIXME: parent doesn't close fsock - ??! */
Denis Vlasenko25098f72006-09-14 15:46:33 +00001799 retval = -daemonized;
1800 goto ret;
1801 }
1802 }
1803 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1804 delay *= 2;
1805 if (delay > 30)
1806 delay = 30;
1807 }
1808 }
1809
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001810 /* Perform actual mount */
1811 do_mount:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001812 retval = mount_it_now(mp, vfsflags, (char*)&data);
1813 goto ret;
1814
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001815 /* Abort */
1816 fail:
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001817 if (msock >= 0) {
Denis Vlasenko25098f72006-09-14 15:46:33 +00001818 if (mclient) {
1819 auth_destroy(mclient->cl_auth);
1820 clnt_destroy(mclient);
1821 }
1822 close(msock);
1823 }
Denis Vlasenko7d8de4d2007-08-28 11:23:23 +00001824 if (fsock >= 0)
Denis Vlasenko25098f72006-09-14 15:46:33 +00001825 close(fsock);
1826
Denis Vlasenko63430ae2007-10-29 19:18:39 +00001827 ret:
Denis Vlasenko25098f72006-09-14 15:46:33 +00001828 free(hostname);
1829 free(mounthost);
1830 free(filteropts);
1831 return retval;
1832}
1833
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001834#else // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001835
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001836/* Linux 2.6.23+ supports nfs mounts with options passed as a string.
1837 * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS.
1838 * (However, note that then you lose any chances that NFS over IPv6 would work).
1839 */
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001840static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001841{
1842 len_and_sockaddr *lsa;
1843 char *opts;
1844 char *end;
1845 char *dotted;
1846 int ret;
1847
1848# if ENABLE_FEATURE_IPV6
1849 end = strchr(mp->mnt_fsname, ']');
1850 if (end && end[1] == ':')
1851 end++;
1852 else
1853# endif
1854 /* mount_main() guarantees that ':' is there */
1855 end = strchr(mp->mnt_fsname, ':');
1856
1857 *end = '\0';
Denys Vlasenko39b23312011-11-10 17:01:39 +01001858 lsa = xhost2sockaddr(mp->mnt_fsname, /*port:*/ 0);
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001859 *end = ':';
1860 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1861 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1862 opts = xasprintf("%s%saddr=%s",
1863 filteropts ? filteropts : "",
1864 filteropts ? "," : "",
1865 dotted
1866 );
1867 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
1868 ret = mount_it_now(mp, vfsflags, opts);
1869 if (ENABLE_FEATURE_CLEAN_UP) free(opts);
1870
1871 return ret;
1872}
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001873
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001874#endif // !ENABLE_FEATURE_MOUNT_NFS
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001875
1876// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1877// type detection. Returns 0 for success, nonzero for failure.
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00001878// NB: mp->xxx fields may be trashed on exit
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001879static int singlemount(struct mntent *mp, int ignore_busy)
1880{
Denis Vlasenkob4133682008-02-18 13:05:38 +00001881 int rc = -1;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02001882 unsigned long vfsflags;
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001883 char *loopFile = NULL, *filteropts = NULL;
1884 llist_t *fl = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001885 struct stat st;
1886
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001887 errno = 0;
1888
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001889 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1890
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00001891 // Treat fstype "auto" as unspecified
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001892 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1893 mp->mnt_type = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001894
Denis Vlasenko2535f122007-09-15 13:28:30 +00001895 // Might this be a virtual filesystem?
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02001896 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1897 char *args[35];
1898 char *s;
1899 int n;
1900 // fsname: "cmd#arg1#arg2..."
1901 // WARNING: allows execution of arbitrary commands!
1902 // Try "mount 'sh#-c#sh' bogus_dir".
1903 // It is safe ONLY because non-root
1904 // cannot use two-argument mount command
1905 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1906 // "mount: can't find sh#-c#sh in /etc/fstab"
1907 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1908
1909 s = mp->mnt_fsname;
1910 n = 0;
1911 args[n++] = s;
1912 while (*s && n < 35 - 2) {
1913 if (*s++ == '#' && *s != '#') {
1914 s[-1] = '\0';
1915 args[n++] = s;
Denis Vlasenko2535f122007-09-15 13:28:30 +00001916 }
1917 }
Denis Vlasenko2535f122007-09-15 13:28:30 +00001918 args[n++] = mp->mnt_dir;
1919 args[n] = NULL;
Denys Vlasenko8531d762010-03-18 22:44:00 +01001920 rc = spawn_and_wait(args);
Denis Vlasenko2535f122007-09-15 13:28:30 +00001921 goto report_error;
1922 }
1923
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001924 // Might this be an CIFS filesystem?
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001925 if (ENABLE_FEATURE_MOUNT_CIFS
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00001926 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1927 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1928 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001929 ) {
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001930 int len;
1931 char c;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001932 char *hostname, *share;
1933 char *dotted, *ip;
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001934 len_and_sockaddr *lsa;
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001935
1936 // Parse mp->mnt_fsname of the form "//hostname/share[/dir1/dir2]"
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001937
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001938 hostname = mp->mnt_fsname + 2;
1939 len = strcspn(hostname, "/\\");
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001940 share = hostname + len + 1;
1941 if (len == 0 // 3rd char is a [back]slash (IOW: empty hostname)
1942 || share[-1] == '\0' // no [back]slash after hostname
1943 || share[0] == '\0' // empty share name
Martin Santesson406ea152013-01-16 00:47:19 +01001944 ) {
Denis Vlasenko5c329932009-04-12 12:16:21 +00001945 goto report_error;
Martin Santesson406ea152013-01-16 00:47:19 +01001946 }
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001947 c = share[-1];
1948 share[-1] = '\0';
1949 len = strcspn(share, "/\\");
Martin Santesson406ea152013-01-16 00:47:19 +01001950
1951 // "unc=\\hostname\share" option is mandatory
1952 // after CIFS option parsing was rewritten in Linux 3.4.
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001953 // Must use backslashes.
1954 // If /dir1/dir2 is present, also add "prefixpath=dir1/dir2"
Martin Santesson406ea152013-01-16 00:47:19 +01001955 {
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001956 char *unc = xasprintf(
1957 share[len] != '\0' /* "/dir1/dir2" exists? */
1958 ? "unc=\\\\%s\\%.*s,prefixpath=%s"
1959 : "unc=\\\\%s\\%.*s",
1960 hostname,
1961 len, share,
1962 share + len + 1 /* "dir1/dir2" */
1963 );
Denys Vlasenko9b7ebfe2013-01-22 11:00:45 +01001964 parse_mount_options(unc, &filteropts);
1965 if (ENABLE_FEATURE_CLEAN_UP) free(unc);
Martin Santesson406ea152013-01-16 00:47:19 +01001966 }
1967
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01001968 lsa = host2sockaddr(hostname, 0);
Bernhard Reutner-Fischer20c5e5a2013-01-17 02:30:35 +01001969 share[-1] = c;
Denis Vlasenko5c329932009-04-12 12:16:21 +00001970 if (!lsa)
1971 goto report_error;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001972
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001973 // Insert "ip=..." option into options
Bernhard Reutner-Fischer8c69afd2008-01-29 10:33:34 +00001974 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001975 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
Denis Vlasenko5870ad92007-02-04 02:39:55 +00001976 ip = xasprintf("ip=%s", dotted);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001977 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001978 parse_mount_options(ip, &filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001979 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001980
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001981 mp->mnt_type = (char*)"cifs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001982 rc = mount_it_now(mp, vfsflags, filteropts);
Denys Vlasenko4e60f302009-12-15 01:28:59 +01001983
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001984 goto report_error;
1985 }
1986
1987 // Might this be an NFS filesystem?
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001988 if ((!mp->mnt_type || is_prefixed_with(mp->mnt_type, "nfs"))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00001989 && strchr(mp->mnt_fsname, ':') != NULL
1990 ) {
Denys Vlasenkoa86e0242011-11-10 16:53:35 +01001991 if (!mp->mnt_type)
1992 mp->mnt_type = (char*)"nfs";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00001993 rc = nfsmount(mp, vfsflags, filteropts);
1994 goto report_error;
1995 }
1996
1997 // Look at the file. (Not found isn't a failure for remount, or for
1998 // a synthetic filesystem like proc or sysfs.)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00001999 // (We use stat, not lstat, in order to allow
2000 // mount symlink_to_file_or_blkdev dir)
Denis Vlasenko38ec1472007-05-20 12:32:41 +00002001 if (!stat(mp->mnt_fsname, &st)
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002002 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
2003 ) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002004 // Do we need to allocate a loopback device for it?
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002005 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
2006 loopFile = bb_simplify_path(mp->mnt_fsname);
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002007 mp->mnt_fsname = NULL; // will receive malloced loop dev name
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002008 if (set_loop(&mp->mnt_fsname, loopFile, 0, /*ro:*/ (vfsflags & MS_RDONLY)) < 0) {
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002009 if (errno == EPERM || errno == EACCES)
2010 bb_error_msg(bb_msg_perm_denied_are_you_root);
2011 else
Denys Vlasenko6331cf02009-11-13 09:08:27 +01002012 bb_perror_msg("can't setup loop device");
Denis Vlasenko13b49242006-09-17 15:04:35 +00002013 return errno;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002014 }
2015
2016 // Autodetect bind mounts
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002017 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
2018 vfsflags |= MS_BIND;
2019 }
2020
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002021 // If we know the fstype (or don't need to), jump straight
2022 // to the actual mount.
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002023 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002024 char *next;
2025 for (;;) {
2026 next = mp->mnt_type ? strchr(mp->mnt_type, ',') : NULL;
2027 if (next)
2028 *next = '\0';
2029 rc = mount_it_now(mp, vfsflags, filteropts);
2030 if (rc == 0 || !next)
2031 break;
2032 mp->mnt_type = next + 1;
2033 }
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002034 } else {
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002035 // Loop through filesystem types until mount succeeds
2036 // or we run out
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002037
Denys Vlasenkob7a0e132009-12-15 16:36:14 +01002038 // Initialize list of block backed filesystems.
2039 // This has to be done here so that during "mount -a",
2040 // mounts after /proc shows up can autodetect.
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002041 if (!fslist) {
2042 fslist = get_block_backed_filesystems();
2043 if (ENABLE_FEATURE_CLEAN_UP && fslist)
2044 atexit(delete_block_backed_filesystems);
2045 }
2046
2047 for (fl = fslist; fl; fl = fl->link) {
2048 mp->mnt_type = fl->data;
Denis Vlasenko13b49242006-09-17 15:04:35 +00002049 rc = mount_it_now(mp, vfsflags, filteropts);
Karol Lewandowskib5ebe5f2011-11-03 10:02:31 +01002050 if (rc == 0)
Denys Vlasenkoe2e4cc22009-06-19 11:48:29 +02002051 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002052 }
2053 }
2054
2055 // If mount failed, clean up loop file (if any).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002056 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
2057 del_loop(mp->mnt_fsname);
2058 if (ENABLE_FEATURE_CLEAN_UP) {
2059 free(loopFile);
2060 free(mp->mnt_fsname);
2061 }
2062 }
2063
Denis Vlasenko5870ad92007-02-04 02:39:55 +00002064 report_error:
2065 if (ENABLE_FEATURE_CLEAN_UP)
2066 free(filteropts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002067
Denis Vlasenkoc8d4d2f2007-09-07 19:33:56 +00002068 if (errno == EBUSY && ignore_busy)
2069 return 0;
Denys Vlasenko911d2652015-12-30 20:11:34 +01002070 if (errno == ENOENT && (vfsflags & MOUNT_NOFAIL))
2071 return 0;
Denys Vlasenkofa1b3702010-06-27 16:47:40 +02002072 if (rc != 0)
Denis Vlasenko0e2c9fb2007-08-03 14:16:24 +00002073 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002074 return rc;
2075}
2076
Michael Abbott6b5accb2009-12-04 03:33:07 +01002077// -O support
2078// -O interprets a list of filter options which select whether a mount
2079// point will be mounted: only mounts with options matching *all* filtering
2080// options will be selected.
2081// By default each -O filter option must be present in the list of mount
2082// options, but if it is prefixed by "no" then it must be absent.
2083// For example,
2084// -O a,nob,c matches -o a,c but fails to match -o a,b,c
2085// (and also fails to match -o a because -o c is absent).
2086//
2087// It is different from -t in that each option is matched exactly; a leading
2088// "no" at the beginning of one option does not negate the rest.
2089static int match_opt(const char *fs_opt_in, const char *O_opt)
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002090{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002091 if (!O_opt)
Michael Abbott6b5accb2009-12-04 03:33:07 +01002092 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002093
Michael Abbott6b5accb2009-12-04 03:33:07 +01002094 while (*O_opt) {
2095 const char *fs_opt = fs_opt_in;
2096 int O_len;
2097 int match;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002098
Michael Abbott6b5accb2009-12-04 03:33:07 +01002099 // If option begins with "no" then treat as an inverted match:
2100 // matching is a failure
2101 match = 0;
2102 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
2103 match = 1;
2104 O_opt += 2;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002105 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002106 // Isolate the current O option
2107 O_len = strchrnul(O_opt, ',') - O_opt;
2108 // Check for a match against existing options
2109 while (1) {
2110 if (strncmp(fs_opt, O_opt, O_len) == 0
2111 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
2112 ) {
2113 if (match)
2114 return 0; // "no" prefix, but option found
2115 match = 1; // current O option found, go check next one
2116 break;
2117 }
2118 fs_opt = strchr(fs_opt, ',');
2119 if (!fs_opt)
2120 break;
2121 fs_opt++;
2122 }
2123 if (match == 0)
2124 return 0; // match wanted but not found
2125 if (O_opt[O_len] == '\0') // end?
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002126 break;
Michael Abbott6b5accb2009-12-04 03:33:07 +01002127 // Step to the next O option
2128 O_opt += O_len + 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002129 }
Michael Abbott6b5accb2009-12-04 03:33:07 +01002130 // If we get here then everything matched
2131 return 1;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002132}
2133
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002134// Parse options, if necessary parse fstab/mtab, and call singlemount for
2135// each directory to be mounted.
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002136int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002137int mount_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002138{
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002139 char *cmdopts = xzalloc(1);
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002140 char *fstype = NULL;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002141 char *O_optmatch = NULL;
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002142 char *storage_path;
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002143 llist_t *lst_o = NULL;
Isaac Dunham7b434a62015-03-11 16:07:24 +01002144 const char *fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002145 FILE *fstab;
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002146 int i, j;
2147 int rc = EXIT_SUCCESS;
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002148 unsigned long cmdopt_flags;
Denis Vlasenko67b23e62006-10-03 21:00:06 +00002149 unsigned opt;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002150 struct mntent mtpair[2], *mtcur = mtpair;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002151 IF_NOT_DESKTOP(const int nonroot = 0;)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002152
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002153 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
Denis Vlasenkoc9ca0a32008-02-18 11:08:33 +00002154
Denys Vlasenko16714242011-09-21 01:59:15 +02002155 INIT_G();
2156
Denis Vlasenkof732e962008-02-18 12:07:49 +00002157 // Parse long options, like --bind and --move. Note that -o option
2158 // and --option are synonymous. Yes, this means --remount,rw works.
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002159 for (i = j = 1; argv[i]; i++) {
2160 if (argv[i][0] == '-' && argv[i][1] == '-')
2161 append_mount_options(&cmdopts, argv[i] + 2);
2162 else
2163 argv[j++] = argv[i];
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002164 }
Denis Vlasenkoa4522c52008-03-17 08:46:43 +00002165 argv[j] = NULL;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002166
2167 // Parse remaining options
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002168 // Max 2 params; -o is a list, -v is a counter
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002169 opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002170 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
Isaac Dunham7b434a62015-03-11 16:07:24 +01002171 IF_FEATURE_MOUNT_OTHERTAB(, &fstabname)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00002172 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
Denis Vlasenkof9dde912008-10-18 19:15:57 +00002173 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
Denis Vlasenkob1d8e7d2008-02-16 23:28:42 +00002174 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
2175 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Denis Vlasenko3bc59aa2006-09-17 15:04:01 +00002176 argv += optind;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002177
2178 // If we have no arguments, show currently mounted filesystems
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002179 if (!argv[0]) {
Denis Vlasenko397de612008-03-17 08:55:44 +00002180 if (!(opt & OPT_a)) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002181 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
2182
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002183 if (!mountTable)
2184 bb_error_msg_and_die("no %s", bb_path_mtab_file);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002185
Denis Vlasenko2535f122007-09-15 13:28:30 +00002186 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002187 GETMNTENT_BUFSIZE))
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002188 {
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002189 // Don't show rootfs. FIXME: why??
Denis Vlasenko908d6b72006-12-18 23:07:42 +00002190 // util-linux 2.12a happily shows rootfs...
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002191 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002192
Denys Vlasenko4e60f302009-12-15 01:28:59 +01002193 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002194 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
2195 mtpair->mnt_dir, mtpair->mnt_type,
2196 mtpair->mnt_opts);
2197 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002198 if (ENABLE_FEATURE_CLEAN_UP)
2199 endmntent(mountTable);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002200 return EXIT_SUCCESS;
2201 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002202 storage_path = NULL;
2203 } else {
2204 // When we have two arguments, the second is the directory and we can
2205 // skip looking at fstab entirely. We can always abspath() the directory
2206 // argument when we get it.
2207 if (argv[1]) {
2208 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002209 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002210 mtpair->mnt_fsname = argv[0];
2211 mtpair->mnt_dir = argv[1];
2212 mtpair->mnt_type = fstype;
2213 mtpair->mnt_opts = cmdopts;
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002214 resolve_mount_spec(&mtpair->mnt_fsname);
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002215 rc = singlemount(mtpair, /*ignore_busy:*/ 0);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002216 return rc;
Denis Vlasenkode7684a2008-02-18 21:08:49 +00002217 }
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002218 storage_path = bb_simplify_path(argv[0]); // malloced
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002219 }
2220
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002221 // Past this point, we are handling either "mount -a [opts]"
2222 // or "mount [opts] single_param"
2223
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002224 cmdopt_flags = parse_mount_options(cmdopts, NULL);
2225 if (nonroot && (cmdopt_flags & ~MS_SILENT)) // Non-root users cannot specify flags
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002226 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko546cd182006-10-02 18:52:49 +00002227
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002228 // If we have a shared subtree flag, don't worry about fstab or mtab.
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002229 if (ENABLE_FEATURE_MOUNT_FLAGS
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002230 && (cmdopt_flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
Denis Vlasenko6cd2d2b2007-01-22 14:06:03 +00002231 ) {
Denis Vlasenko30e5cf82008-12-05 16:40:36 +00002232 // verbose_mount(source, target, type, flags, data)
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002233 rc = verbose_mount("", argv[0], "", cmdopt_flags, "");
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002234 if (rc)
2235 bb_simple_perror_msg_and_die(argv[0]);
2236 return rc;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002237 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00002238
Isaac Dunham7b434a62015-03-11 16:07:24 +01002239 // A malicious user could overmount /usr without this.
2240 if (ENABLE_FEATURE_MOUNT_OTHERTAB && nonroot)
2241 fstabname = "/etc/fstab";
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002242 // Open either fstab or mtab
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002243 if (cmdopt_flags & MS_REMOUNT) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002244 // WARNING. I am not sure this matches util-linux's
2245 // behavior. It's possible util-linux does not
2246 // take -o opts from mtab (takes only mount source).
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002247 fstabname = bb_path_mtab_file;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002248 }
2249 fstab = setmntent(fstabname, "r");
Denis Vlasenko8d474b52006-09-17 15:00:58 +00002250 if (!fstab)
Denys Vlasenko651a2692010-03-23 16:25:17 +01002251 bb_perror_msg_and_die("can't read '%s'", fstabname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002252
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002253 // Loop through entries until we find what we're looking for
Denis Vlasenko546cd182006-10-02 18:52:49 +00002254 memset(mtpair, 0, sizeof(mtpair));
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002255 for (;;) {
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002256 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002257
2258 // Get next fstab entry
Denis Vlasenko2535f122007-09-15 13:28:30 +00002259 if (!getmntent_r(fstab, mtcur, getmntent_buf
Denis Vlasenkod0a071a2008-03-17 09:33:45 +00002260 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002261 GETMNTENT_BUFSIZE/2)
2262 ) { // End of fstab/mtab is reached
2263 mtcur = mtother; // the thing we found last time
2264 break;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002265 }
2266
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002267 // If we're trying to mount something specific and this isn't it,
2268 // skip it. Note we must match the exact text in fstab (ala
2269 // "proc") or a full path from root
2270 if (argv[0]) {
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002271
2272 // Is this what we're looking for?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002273 if (strcmp(argv[0], mtcur->mnt_fsname) != 0
2274 && strcmp(storage_path, mtcur->mnt_fsname) != 0
2275 && strcmp(argv[0], mtcur->mnt_dir) != 0
2276 && strcmp(storage_path, mtcur->mnt_dir) != 0
2277 ) {
2278 continue; // no
2279 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002280
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002281 // Remember this entry. Something later may have
2282 // overmounted it, and we want the _last_ match.
2283 mtcur = mtother;
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002284
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002285 // If we're mounting all
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002286 } else {
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002287 struct mntent *mp;
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002288 // No, mount -a won't mount anything,
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002289 // even user mounts, for mere humans
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002290 if (nonroot)
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002291 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenko13c5a682006-10-16 22:39:51 +00002292
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002293 // Does type match? (NULL matches always)
2294 if (!match_fstype(mtcur, fstype))
2295 continue;
2296
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002297 // Skip noauto and swap anyway
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002298 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
2299 // swap is bogus "fstype", parse_mount_options can't check fstypes
2300 || strcasecmp(mtcur->mnt_type, "swap") == 0
2301 ) {
2302 continue;
2303 }
2304
2305 // Does (at least one) option match?
2306 // (NULL matches always)
2307 if (!match_opt(mtcur->mnt_opts, O_optmatch))
2308 continue;
2309
2310 resolve_mount_spec(&mtcur->mnt_fsname);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002311
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002312 // NFS mounts want this to be xrealloc-able
2313 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
Denis Vlasenko6a2d0d92008-12-10 11:39:18 +00002314
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002315 // If nothing is mounted on this directory...
2316 // (otherwise repeated "mount -a" mounts everything again)
2317 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2318 // We do not check fsname match of found mount point -
2319 // "/" may have fsname of "/dev/root" while fstab
2320 // says "/dev/something_else".
2321 if (mp) {
Denys Vlasenko86566762009-12-10 21:32:28 +01002322 if (verbose) {
2323 bb_error_msg("according to %s, "
2324 "%s is already mounted on %s",
2325 bb_path_mtab_file,
2326 mp->mnt_fsname, mp->mnt_dir);
2327 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002328 } else {
2329 // ...mount this thing
2330 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2331 // Count number of failed mounts
2332 rc++;
2333 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002334 }
Denis Vlasenko666da5e2006-12-26 18:17:42 +00002335 free(mtcur->mnt_opts);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002336 }
2337 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002338
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002339 // End of fstab/mtab is reached.
2340 // Were we looking for something specific?
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002341 if (argv[0]) { // yes
Denys Vlasenko9ee42662012-06-21 12:08:56 +02002342 unsigned long l;
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002343
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002344 // If we didn't find anything, complain
2345 if (!mtcur->mnt_fsname)
2346 bb_error_msg_and_die("can't find %s in %s",
2347 argv[0], fstabname);
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002348
2349 // What happens when we try to "mount swap_partition"?
2350 // (fstab containts "swap_partition swap swap defaults 0 0")
2351 // util-linux-ng 2.13.1 does this:
2352 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2353 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2354 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
2355 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2356 // exit_group(32) = ?
2357#if 0
2358 // In case we want to simply skip swap partitions:
2359 l = parse_mount_options(mtcur->mnt_opts, NULL);
2360 if ((l & MOUNT_SWAP)
2361 // swap is bogus "fstype", parse_mount_options can't check fstypes
2362 || strcasecmp(mtcur->mnt_type, "swap") == 0
2363 ) {
2364 goto ret;
2365 }
2366#endif
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002367 if (nonroot) {
2368 // fstab must have "users" or "user"
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002369 l = parse_mount_options(mtcur->mnt_opts, NULL);
2370 if (!(l & MOUNT_USERS))
Denys Vlasenkob2e5fc32009-11-25 14:52:47 +01002371 bb_error_msg_and_die(bb_msg_you_must_be_root);
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002372 }
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002373
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002374 //util-linux-2.12 does not do this check.
2375 //// If nothing is mounted on this directory...
2376 //// (otherwise repeated "mount FOO" mounts FOO again)
2377 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2378 //if (mp) {
2379 // bb_error_msg("according to %s, "
2380 // "%s is already mounted on %s",
2381 // bb_path_mtab_file,
2382 // mp->mnt_fsname, mp->mnt_dir);
2383 //} else {
2384 // ...mount the last thing we found
2385 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2386 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2387 resolve_mount_spec(&mtpair->mnt_fsname);
2388 rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2389 if (ENABLE_FEATURE_CLEAN_UP)
2390 free(mtcur->mnt_opts);
2391 //}
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002392 }
2393
Denis Vlasenko7aaedcf2009-03-14 22:57:20 +00002394 //ret:
Denis Vlasenkod0cc3f42008-06-24 18:59:59 +00002395 if (ENABLE_FEATURE_CLEAN_UP)
2396 endmntent(fstab);
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002397 if (ENABLE_FEATURE_CLEAN_UP) {
2398 free(storage_path);
2399 free(cmdopts);
2400 }
Denys Vlasenkoa7329662009-12-05 04:25:19 +01002401
2402//TODO: exitcode should be ORed mask of (from "man mount"):
2403// 0 success
2404// 1 incorrect invocation or permissions
2405// 2 system error (out of memory, cannot fork, no more loop devices)
2406// 4 internal mount bug or missing nfs support in mount
2407// 8 user interrupt
2408//16 problems writing or locking /etc/mtab
2409//32 mount failure
2410//64 some mount succeeded
Denis Vlasenko30a64cd2006-09-15 15:12:00 +00002411 return rc;
2412}