mount: handle EDQUOT > 255 properly. closes bug 1579
[oweals/busybox.git] / util-linux / mount.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini mount implementation for busybox
4  *
5  * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7  * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
8  *
9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10  */
11 // 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 //
19 #include <mntent.h>
20 #include <syslog.h>
21 #include <sys/mount.h>
22 // Grab more as needed from util-linux's mount/mount_constants.h
23 #ifndef MS_DIRSYNC
24 # define MS_DIRSYNC     (1 << 7) // Directory modifications are synchronous
25 #endif
26 #ifndef MS_UNION
27 # define MS_UNION       (1 << 8)
28 #endif
29 #ifndef MS_BIND
30 # define MS_BIND        (1 << 12)
31 #endif
32 #ifndef MS_MOVE
33 # define MS_MOVE        (1 << 13)
34 #endif
35 #ifndef MS_RECURSIVE
36 # define MS_RECURSIVE   (1 << 14)
37 #endif
38 #ifndef MS_SILENT
39 # define MS_SILENT      (1 << 15)
40 #endif
41 // The shared subtree stuff, which went in around 2.6.15
42 #ifndef MS_UNBINDABLE
43 # define MS_UNBINDABLE  (1 << 17)
44 #endif
45 #ifndef MS_PRIVATE
46 # define MS_PRIVATE     (1 << 18)
47 #endif
48 #ifndef MS_SLAVE
49 # define MS_SLAVE       (1 << 19)
50 #endif
51 #ifndef MS_SHARED
52 # define MS_SHARED      (1 << 20)
53 #endif
54 #ifndef MS_RELATIME
55 # define MS_RELATIME    (1 << 21)
56 #endif
57
58 #include "libbb.h"
59 #if ENABLE_FEATURE_MOUNT_LABEL
60 # include "volume_id.h"
61 #else
62 # define resolve_mount_spec(fsname) ((void)0)
63 #endif
64
65 // Needed for nfs support only
66 #include <sys/utsname.h>
67 #undef TRUE
68 #undef FALSE
69 #if ENABLE_FEATURE_MOUNT_NFS
70 /* This is just a warning of a common mistake.  Possibly this should be a
71  * uclibc faq entry rather than in busybox... */
72 # if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
73 #  error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
74 # endif
75 # include <rpc/rpc.h>
76 # include <rpc/pmap_prot.h>
77 # include <rpc/pmap_clnt.h>
78 #endif
79
80
81 #if defined(__dietlibc__)
82 // 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
83 // dietlibc-0.30 does not have implementation of getmntent_r()
84 static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
85                 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
86 {
87         struct mntent* ment = getmntent(stream);
88         return memcpy(result, ment, sizeof(*ment));
89 }
90 #endif
91
92
93 // Not real flags, but we want to be able to check for this.
94 enum {
95         MOUNT_USERS  = (1 << 28) * ENABLE_DESKTOP,
96         MOUNT_NOAUTO = (1 << 29),
97         MOUNT_SWAP   = (1 << 30),
98 };
99
100
101 #define OPTION_STR "o:t:rwanfvsiO:"
102 enum {
103         OPT_o = (1 << 0),
104         OPT_t = (1 << 1),
105         OPT_r = (1 << 2),
106         OPT_w = (1 << 3),
107         OPT_a = (1 << 4),
108         OPT_n = (1 << 5),
109         OPT_f = (1 << 6),
110         OPT_v = (1 << 7),
111         OPT_s = (1 << 8),
112         OPT_i = (1 << 9),
113         OPT_O = (1 << 10),
114 };
115
116 #if ENABLE_FEATURE_MTAB_SUPPORT
117 #define USE_MTAB (!(option_mask32 & OPT_n))
118 #else
119 #define USE_MTAB 0
120 #endif
121
122 #if ENABLE_FEATURE_MOUNT_FAKE
123 #define FAKE_IT (option_mask32 & OPT_f)
124 #else
125 #define FAKE_IT 0
126 #endif
127
128 #if ENABLE_FEATURE_MOUNT_HELPERS
129 #define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
130 #else
131 #define HELPERS_ALLOWED 0
132 #endif
133
134
135 // TODO: more "user" flag compatibility.
136 // "user" option (from mount manpage):
137 // Only the user that mounted a filesystem can unmount it again.
138 // If any user should be able to unmount, then use users instead of user
139 // in the fstab line.  The owner option is similar to the user option,
140 // with the restriction that the user must be the owner of the special file.
141 // This may be useful e.g. for /dev/fd if a login script makes
142 // the console user owner of this device.
143
144 // Standard mount options (from -o options or --options),
145 // with corresponding flags
146 static const int32_t mount_options[] = {
147         // MS_FLAGS set a bit.  ~MS_FLAGS disable that bit.  0 flags are NOPs.
148
149         IF_FEATURE_MOUNT_LOOP(
150                 /* "loop" */ 0,
151         )
152
153         IF_FEATURE_MOUNT_FSTAB(
154                 /* "defaults" */ 0,
155                 /* "quiet" 0 - do not filter out, vfat wants to see it */
156                 /* "noauto" */ MOUNT_NOAUTO,
157                 /* "sw"     */ MOUNT_SWAP,
158                 /* "swap"   */ MOUNT_SWAP,
159                 IF_DESKTOP(/* "user"  */ MOUNT_USERS,)
160                 IF_DESKTOP(/* "users" */ MOUNT_USERS,)
161                 /* "_netdev" */ 0,
162         )
163
164         IF_FEATURE_MOUNT_FLAGS(
165                 // vfs flags
166                 /* "nosuid"      */ MS_NOSUID,
167                 /* "suid"        */ ~MS_NOSUID,
168                 /* "dev"         */ ~MS_NODEV,
169                 /* "nodev"       */ MS_NODEV,
170                 /* "exec"        */ ~MS_NOEXEC,
171                 /* "noexec"      */ MS_NOEXEC,
172                 /* "sync"        */ MS_SYNCHRONOUS,
173                 /* "dirsync"     */ MS_DIRSYNC,
174                 /* "async"       */ ~MS_SYNCHRONOUS,
175                 /* "atime"       */ ~MS_NOATIME,
176                 /* "noatime"     */ MS_NOATIME,
177                 /* "diratime"    */ ~MS_NODIRATIME,
178                 /* "nodiratime"  */ MS_NODIRATIME,
179                 /* "mand"        */ MS_MANDLOCK,
180                 /* "nomand"      */ ~MS_MANDLOCK,
181                 /* "relatime"    */ MS_RELATIME,
182                 /* "norelatime"  */ ~MS_RELATIME,
183                 /* "loud"        */ ~MS_SILENT,
184
185                 // action flags
186                 /* "union"       */ MS_UNION,
187                 /* "bind"        */ MS_BIND,
188                 /* "move"        */ MS_MOVE,
189                 /* "shared"      */ MS_SHARED,
190                 /* "slave"       */ MS_SLAVE,
191                 /* "private"     */ MS_PRIVATE,
192                 /* "unbindable"  */ MS_UNBINDABLE,
193                 /* "rshared"     */ MS_SHARED|MS_RECURSIVE,
194                 /* "rslave"      */ MS_SLAVE|MS_RECURSIVE,
195                 /* "rprivate"    */ MS_SLAVE|MS_RECURSIVE,
196                 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
197         )
198
199         // Always understood.
200         /* "ro"      */ MS_RDONLY,  // vfs flag
201         /* "rw"      */ ~MS_RDONLY, // vfs flag
202         /* "remount" */ MS_REMOUNT  // action flag
203 };
204
205 static const char mount_option_str[] =
206         IF_FEATURE_MOUNT_LOOP(
207                 "loop\0"
208         )
209         IF_FEATURE_MOUNT_FSTAB(
210                 "defaults\0"
211                 // "quiet\0" - do not filter out, vfat wants to see it
212                 "noauto\0"
213                 "sw\0"
214                 "swap\0"
215                 IF_DESKTOP("user\0")
216                 IF_DESKTOP("users\0")
217                 "_netdev\0"
218         )
219         IF_FEATURE_MOUNT_FLAGS(
220                 // vfs flags
221                 "nosuid\0"
222                 "suid\0"
223                 "dev\0"
224                 "nodev\0"
225                 "exec\0"
226                 "noexec\0"
227                 "sync\0"
228                 "dirsync\0"
229                 "async\0"
230                 "atime\0"
231                 "noatime\0"
232                 "diratime\0"
233                 "nodiratime\0"
234                 "mand\0"
235                 "nomand\0"
236                 "relatime\0"
237                 "norelatime\0"
238                 "loud\0"
239
240                 // action flags
241                 "union\0"
242                 "bind\0"
243                 "move\0"
244                 "shared\0"
245                 "slave\0"
246                 "private\0"
247                 "unbindable\0"
248                 "rshared\0"
249                 "rslave\0"
250                 "rprivate\0"
251                 "runbindable\0"
252         )
253
254         // Always understood.
255         "ro\0"        // vfs flag
256         "rw\0"        // vfs flag
257         "remount\0"   // action flag
258 ;
259
260
261 struct globals {
262 #if ENABLE_FEATURE_MOUNT_NFS
263         smalluint nfs_mount_version;
264 #endif
265 #if ENABLE_FEATURE_MOUNT_VERBOSE
266         unsigned verbose;
267 #endif
268         llist_t *fslist;
269         char getmntent_buf[1];
270 } FIX_ALIASING;
271 enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
272 #define G (*(struct globals*)&bb_common_bufsiz1)
273 #define nfs_mount_version (G.nfs_mount_version)
274 #if ENABLE_FEATURE_MOUNT_VERBOSE
275 #define verbose           (G.verbose          )
276 #else
277 #define verbose           0
278 #endif
279 #define fslist            (G.fslist           )
280 #define getmntent_buf     (G.getmntent_buf    )
281
282
283 #if ENABLE_FEATURE_MOUNT_VERBOSE
284 static int verbose_mount(const char *source, const char *target,
285                 const char *filesystemtype,
286                 unsigned long mountflags, const void *data)
287 {
288         int rc;
289
290         errno = 0;
291         rc = mount(source, target, filesystemtype, mountflags, data);
292         if (verbose >= 2)
293                 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
294                         source, target, filesystemtype,
295                         mountflags, (char*)data, rc);
296         return rc;
297 }
298 #else
299 #define verbose_mount(...) mount(__VA_ARGS__)
300 #endif
301
302 // Append mount options to string
303 static void append_mount_options(char **oldopts, const char *newopts)
304 {
305         if (*oldopts && **oldopts) {
306                 // Do not insert options which are already there
307                 while (newopts[0]) {
308                         char *p;
309                         int len = strlen(newopts);
310                         p = strchr(newopts, ',');
311                         if (p) len = p - newopts;
312                         p = *oldopts;
313                         while (1) {
314                                 if (!strncmp(p, newopts, len)
315                                  && (p[len] == ',' || p[len] == '\0'))
316                                         goto skip;
317                                 p = strchr(p,',');
318                                 if (!p) break;
319                                 p++;
320                         }
321                         p = xasprintf("%s,%.*s", *oldopts, len, newopts);
322                         free(*oldopts);
323                         *oldopts = p;
324  skip:
325                         newopts += len;
326                         while (newopts[0] == ',') newopts++;
327                 }
328         } else {
329                 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
330                 *oldopts = xstrdup(newopts);
331         }
332 }
333
334 // Use the mount_options list to parse options into flags.
335 // Also return list of unrecognized options if unrecognized != NULL
336 static long parse_mount_options(char *options, char **unrecognized)
337 {
338         long flags = MS_SILENT;
339
340         // Loop through options
341         for (;;) {
342                 unsigned i;
343                 char *comma = strchr(options, ',');
344                 const char *option_str = mount_option_str;
345
346                 if (comma) *comma = '\0';
347
348 // FIXME: use hasmntopt()
349                 // Find this option in mount_options
350                 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
351                         if (!strcasecmp(option_str, options)) {
352                                 long fl = mount_options[i];
353                                 if (fl < 0) flags &= fl;
354                                 else flags |= fl;
355                                 break;
356                         }
357                         option_str += strlen(option_str) + 1;
358                 }
359                 // If unrecognized not NULL, append unrecognized mount options
360                 if (unrecognized && i == ARRAY_SIZE(mount_options)) {
361                         // Add it to strflags, to pass on to kernel
362                         i = *unrecognized ? strlen(*unrecognized) : 0;
363                         *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2);
364
365                         // Comma separated if it's not the first one
366                         if (i) (*unrecognized)[i++] = ',';
367                         strcpy((*unrecognized)+i, options);
368                 }
369
370                 if (!comma)
371                         break;
372                 // Advance to next option
373                 *comma = ',';
374                 options = ++comma;
375         }
376
377         return flags;
378 }
379
380 // Return a list of all block device backed filesystems
381 static llist_t *get_block_backed_filesystems(void)
382 {
383         static const char filesystems[2][sizeof("/proc/filesystems")] = {
384                 "/etc/filesystems",
385                 "/proc/filesystems",
386         };
387         char *fs, *buf;
388         llist_t *list = NULL;
389         int i;
390         FILE *f;
391
392         for (i = 0; i < 2; i++) {
393                 f = fopen_for_read(filesystems[i]);
394                 if (!f) continue;
395
396                 while ((buf = xmalloc_fgetline(f)) != NULL) {
397                         if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
398                                 continue;
399                         fs = skip_whitespace(buf);
400                         if (*fs == '#' || *fs == '*' || !*fs)
401                                 continue;
402
403                         llist_add_to_end(&list, xstrdup(fs));
404                         free(buf);
405                 }
406                 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
407         }
408
409         return list;
410 }
411
412 #if ENABLE_FEATURE_CLEAN_UP
413 static void delete_block_backed_filesystems(void)
414 {
415         llist_free(fslist, free);
416 }
417 #else
418 void delete_block_backed_filesystems(void);
419 #endif
420
421 // Perform actual mount of specific filesystem at specific location.
422 // NB: mp->xxx fields may be trashed on exit
423 static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
424 {
425         int rc = 0;
426
427         if (FAKE_IT) {
428                 if (verbose >= 2)
429                         bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
430                                 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
431                                 vfsflags, filteropts);
432                 goto mtab;
433         }
434
435         // Mount, with fallback to read-only if necessary.
436         for (;;) {
437                 errno = 0;
438                 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
439                                 vfsflags, filteropts);
440
441                 // If mount failed, try
442                 // helper program mount.<mnt_type>
443                 if (HELPERS_ALLOWED && rc && mp->mnt_type) {
444                         char *args[8];
445                         int errno_save = errno;
446                         args[0] = xasprintf("mount.%s", mp->mnt_type);
447                         rc = 1;
448                         if (FAKE_IT)
449                                 args[rc++] = (char *)"-f";
450                         if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
451                                 args[rc++] = (char *)"-n";
452                         args[rc++] = mp->mnt_fsname;
453                         args[rc++] = mp->mnt_dir;
454                         if (filteropts) {
455                                 args[rc++] = (char *)"-o";
456                                 args[rc++] = filteropts;
457                         }
458                         args[rc] = NULL;
459                         rc = spawn_and_wait(args);
460                         free(args[0]);
461                         if (!rc)
462                                 break;
463                         errno = errno_save;
464                 }
465
466                 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
467                         break;
468                 if (!(vfsflags & MS_SILENT))
469                         bb_error_msg("%s is write-protected, mounting read-only",
470                                                 mp->mnt_fsname);
471                 vfsflags |= MS_RDONLY;
472         }
473
474         // Abort entirely if permission denied.
475
476         if (rc && errno == EPERM)
477                 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
478
479         // If the mount was successful, and we're maintaining an old-style
480         // mtab file by hand, add the new entry to it now.
481  mtab:
482         if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
483                 char *fsname;
484                 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
485                 const char *option_str = mount_option_str;
486                 int i;
487
488                 if (!mountTable) {
489                         bb_error_msg("no %s", bb_path_mtab_file);
490                         goto ret;
491                 }
492
493                 // Add vfs string flags
494
495                 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
496                         if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
497                                 append_mount_options(&(mp->mnt_opts), option_str);
498                         option_str += strlen(option_str) + 1;
499                 }
500
501                 // Remove trailing / (if any) from directory we mounted on
502
503                 i = strlen(mp->mnt_dir) - 1;
504                 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
505
506                 // Convert to canonical pathnames as needed
507
508                 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
509                 fsname = 0;
510                 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
511                         mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
512                         mp->mnt_type = (char*)"bind";
513                 }
514                 mp->mnt_freq = mp->mnt_passno = 0;
515
516                 // Write and close.
517
518                 addmntent(mountTable, mp);
519                 endmntent(mountTable);
520                 if (ENABLE_FEATURE_CLEAN_UP) {
521                         free(mp->mnt_dir);
522                         free(fsname);
523                 }
524         }
525  ret:
526         return rc;
527 }
528
529 #if ENABLE_FEATURE_MOUNT_NFS
530
531 /*
532  * Linux NFS mount
533  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
534  *
535  * Licensed under GPLv2, see file LICENSE in this tarball for details.
536  *
537  * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
538  * numbers to be specified on the command line.
539  *
540  * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
541  * Omit the call to connect() for Linux version 1.3.11 or later.
542  *
543  * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
544  * Implemented the "bg", "fg" and "retry" mount options for NFS.
545  *
546  * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
547  * - added Native Language Support
548  *
549  * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
550  * plus NFSv3 stuff.
551  */
552
553 #define MOUNTPORT 635
554 #define MNTPATHLEN 1024
555 #define MNTNAMLEN 255
556 #define FHSIZE 32
557 #define FHSIZE3 64
558
559 typedef char fhandle[FHSIZE];
560
561 typedef struct {
562         unsigned int fhandle3_len;
563         char *fhandle3_val;
564 } fhandle3;
565
566 enum mountstat3 {
567         MNT_OK = 0,
568         MNT3ERR_PERM = 1,
569         MNT3ERR_NOENT = 2,
570         MNT3ERR_IO = 5,
571         MNT3ERR_ACCES = 13,
572         MNT3ERR_NOTDIR = 20,
573         MNT3ERR_INVAL = 22,
574         MNT3ERR_NAMETOOLONG = 63,
575         MNT3ERR_NOTSUPP = 10004,
576         MNT3ERR_SERVERFAULT = 10006,
577 };
578 typedef enum mountstat3 mountstat3;
579
580 struct fhstatus {
581         unsigned int fhs_status;
582         union {
583                 fhandle fhs_fhandle;
584         } fhstatus_u;
585 };
586 typedef struct fhstatus fhstatus;
587
588 struct mountres3_ok {
589         fhandle3 fhandle;
590         struct {
591                 unsigned int auth_flavours_len;
592                 char *auth_flavours_val;
593         } auth_flavours;
594 };
595 typedef struct mountres3_ok mountres3_ok;
596
597 struct mountres3 {
598         mountstat3 fhs_status;
599         union {
600                 mountres3_ok mountinfo;
601         } mountres3_u;
602 };
603 typedef struct mountres3 mountres3;
604
605 typedef char *dirpath;
606
607 typedef char *name;
608
609 typedef struct mountbody *mountlist;
610
611 struct mountbody {
612         name ml_hostname;
613         dirpath ml_directory;
614         mountlist ml_next;
615 };
616 typedef struct mountbody mountbody;
617
618 typedef struct groupnode *groups;
619
620 struct groupnode {
621         name gr_name;
622         groups gr_next;
623 };
624 typedef struct groupnode groupnode;
625
626 typedef struct exportnode *exports;
627
628 struct exportnode {
629         dirpath ex_dir;
630         groups ex_groups;
631         exports ex_next;
632 };
633 typedef struct exportnode exportnode;
634
635 struct ppathcnf {
636         int pc_link_max;
637         short pc_max_canon;
638         short pc_max_input;
639         short pc_name_max;
640         short pc_path_max;
641         short pc_pipe_buf;
642         uint8_t pc_vdisable;
643         char pc_xxx;
644         short pc_mask[2];
645 };
646 typedef struct ppathcnf ppathcnf;
647
648 #define MOUNTPROG 100005
649 #define MOUNTVERS 1
650
651 #define MOUNTPROC_NULL 0
652 #define MOUNTPROC_MNT 1
653 #define MOUNTPROC_DUMP 2
654 #define MOUNTPROC_UMNT 3
655 #define MOUNTPROC_UMNTALL 4
656 #define MOUNTPROC_EXPORT 5
657 #define MOUNTPROC_EXPORTALL 6
658
659 #define MOUNTVERS_POSIX 2
660
661 #define MOUNTPROC_PATHCONF 7
662
663 #define MOUNT_V3 3
664
665 #define MOUNTPROC3_NULL 0
666 #define MOUNTPROC3_MNT 1
667 #define MOUNTPROC3_DUMP 2
668 #define MOUNTPROC3_UMNT 3
669 #define MOUNTPROC3_UMNTALL 4
670 #define MOUNTPROC3_EXPORT 5
671
672 enum {
673 #ifndef NFS_FHSIZE
674         NFS_FHSIZE = 32,
675 #endif
676 #ifndef NFS_PORT
677         NFS_PORT = 2049
678 #endif
679 };
680
681 /*
682  * We want to be able to compile mount on old kernels in such a way
683  * that the binary will work well on more recent kernels.
684  * Thus, if necessary we teach nfsmount.c the structure of new fields
685  * that will come later.
686  *
687  * Moreover, the new kernel includes conflict with glibc includes
688  * so it is easiest to ignore the kernel altogether (at compile time).
689  */
690
691 struct nfs2_fh {
692         char                    data[32];
693 };
694 struct nfs3_fh {
695         unsigned short          size;
696         unsigned char           data[64];
697 };
698
699 struct nfs_mount_data {
700         int             version;                /* 1 */
701         int             fd;                     /* 1 */
702         struct nfs2_fh  old_root;               /* 1 */
703         int             flags;                  /* 1 */
704         int             rsize;                  /* 1 */
705         int             wsize;                  /* 1 */
706         int             timeo;                  /* 1 */
707         int             retrans;                /* 1 */
708         int             acregmin;               /* 1 */
709         int             acregmax;               /* 1 */
710         int             acdirmin;               /* 1 */
711         int             acdirmax;               /* 1 */
712         struct sockaddr_in addr;                /* 1 */
713         char            hostname[256];          /* 1 */
714         int             namlen;                 /* 2 */
715         unsigned int    bsize;                  /* 3 */
716         struct nfs3_fh  root;                   /* 4 */
717 };
718
719 /* bits in the flags field */
720 enum {
721         NFS_MOUNT_SOFT = 0x0001,        /* 1 */
722         NFS_MOUNT_INTR = 0x0002,        /* 1 */
723         NFS_MOUNT_SECURE = 0x0004,      /* 1 */
724         NFS_MOUNT_POSIX = 0x0008,       /* 1 */
725         NFS_MOUNT_NOCTO = 0x0010,       /* 1 */
726         NFS_MOUNT_NOAC = 0x0020,        /* 1 */
727         NFS_MOUNT_TCP = 0x0040,         /* 2 */
728         NFS_MOUNT_VER3 = 0x0080,        /* 3 */
729         NFS_MOUNT_KERBEROS = 0x0100,    /* 3 */
730         NFS_MOUNT_NONLM = 0x0200,       /* 3 */
731         NFS_MOUNT_NORDIRPLUS = 0x4000
732 };
733
734
735 /*
736  * We need to translate between nfs status return values and
737  * the local errno values which may not be the same.
738  *
739  * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
740  * "after #include <errno.h> the symbol errno is reserved for any use,
741  *  it cannot even be used as a struct tag or field name".
742  */
743 #ifndef EDQUOT
744 # define EDQUOT ENOSPC
745 #endif
746 /* Convert each NFSERR_BLAH into EBLAH */
747 static const uint8_t nfs_err_stat[] = {
748          1,  2,  5,  6, 13, 17,
749         19, 20, 21, 22, 27, 28,
750         30, 63, 66, 69, 70, 71
751 };
752 #if ( \
753         EPERM | ENOENT      | EIO      | ENXIO | EACCES| EEXIST | \
754         ENODEV| ENOTDIR     | EISDIR   | EINVAL| EFBIG | ENOSPC | \
755         EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
756 typedef uint8_t nfs_err_type;
757 #else
758 typedef uint16_t nfs_err_type;
759 #endif
760 static const nfs_err_type nfs_err_errnum[] = {
761         EPERM , ENOENT      , EIO      , ENXIO , EACCES, EEXIST,
762         ENODEV, ENOTDIR     , EISDIR   , EINVAL, EFBIG , ENOSPC,
763         EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
764 };
765 static char *nfs_strerror(int status)
766 {
767         int i;
768
769         for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
770                 if (nfs_err_stat[i] == status)
771                         return strerror(nfs_err_errnum[i]);
772         }
773         return xasprintf("unknown nfs status return value: %d", status);
774 }
775
776 static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
777 {
778         if (!xdr_opaque(xdrs, objp, FHSIZE))
779                  return FALSE;
780         return TRUE;
781 }
782
783 static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
784 {
785         if (!xdr_u_int(xdrs, &objp->fhs_status))
786                  return FALSE;
787         switch (objp->fhs_status) {
788         case 0:
789                 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
790                          return FALSE;
791                 break;
792         default:
793                 break;
794         }
795         return TRUE;
796 }
797
798 static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
799 {
800         if (!xdr_string(xdrs, objp, MNTPATHLEN))
801                  return FALSE;
802         return TRUE;
803 }
804
805 static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
806 {
807         if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
808                                 (unsigned int *) &objp->fhandle3_len,
809                                 FHSIZE3)
810         ) {
811                  return FALSE;
812         }
813         return TRUE;
814 }
815
816 static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
817 {
818         if (!xdr_fhandle3(xdrs, &objp->fhandle))
819                 return FALSE;
820         if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
821                                 &(objp->auth_flavours.auth_flavours_len),
822                                 ~0,
823                                 sizeof(int),
824                                 (xdrproc_t) xdr_int)
825         ) {
826                 return FALSE;
827         }
828         return TRUE;
829 }
830
831 static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
832 {
833         if (!xdr_enum(xdrs, (enum_t *) objp))
834                  return FALSE;
835         return TRUE;
836 }
837
838 static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
839 {
840         if (!xdr_mountstat3(xdrs, &objp->fhs_status))
841                 return FALSE;
842         switch (objp->fhs_status) {
843         case MNT_OK:
844                 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
845                          return FALSE;
846                 break;
847         default:
848                 break;
849         }
850         return TRUE;
851 }
852
853 #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
854
855 /*
856  * Unfortunately, the kernel prints annoying console messages
857  * in case of an unexpected nfs mount version (instead of
858  * just returning some error).  Therefore we'll have to try
859  * and figure out what version the kernel expects.
860  *
861  * Variables:
862  *      KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
863  *      NFS_MOUNT_VERSION: these nfsmount sources at compile time
864  *      nfs_mount_version: version this source and running kernel can handle
865  */
866 static void
867 find_kernel_nfs_mount_version(void)
868 {
869         int kernel_version;
870
871         if (nfs_mount_version)
872                 return;
873
874         nfs_mount_version = 4; /* default */
875
876         kernel_version = get_linux_version_code();
877         if (kernel_version) {
878                 if (kernel_version < KERNEL_VERSION(2,2,18))
879                         nfs_mount_version = 3;
880                 /* else v4 since 2.3.99pre4 */
881         }
882 }
883
884 static void
885 get_mountport(struct pmap *pm_mnt,
886         struct sockaddr_in *server_addr,
887         long unsigned prog,
888         long unsigned version,
889         long unsigned proto,
890         long unsigned port)
891 {
892         struct pmaplist *pmap;
893
894         server_addr->sin_port = PMAPPORT;
895 /* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
896  * I understand it like "IPv6 for this is not 100% ready" */
897         pmap = pmap_getmaps(server_addr);
898
899         if (version > MAX_NFSPROT)
900                 version = MAX_NFSPROT;
901         if (!prog)
902                 prog = MOUNTPROG;
903         pm_mnt->pm_prog = prog;
904         pm_mnt->pm_vers = version;
905         pm_mnt->pm_prot = proto;
906         pm_mnt->pm_port = port;
907
908         while (pmap) {
909                 if (pmap->pml_map.pm_prog != prog)
910                         goto next;
911                 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
912                         goto next;
913                 if (version > 2 && pmap->pml_map.pm_vers != version)
914                         goto next;
915                 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
916                         goto next;
917                 if (pmap->pml_map.pm_vers > MAX_NFSPROT
918                  || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
919                  || (port && pmap->pml_map.pm_port != port)
920                 ) {
921                         goto next;
922                 }
923                 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
924  next:
925                 pmap = pmap->pml_next;
926         }
927         if (!pm_mnt->pm_vers)
928                 pm_mnt->pm_vers = MOUNTVERS;
929         if (!pm_mnt->pm_port)
930                 pm_mnt->pm_port = MOUNTPORT;
931         if (!pm_mnt->pm_prot)
932                 pm_mnt->pm_prot = IPPROTO_TCP;
933 }
934
935 #if BB_MMU
936 static int daemonize(void)
937 {
938         int pid = fork();
939         if (pid < 0) /* error */
940                 return -errno;
941         if (pid > 0) /* parent */
942                 return 0;
943         /* child */
944         close(0);
945         xopen(bb_dev_null, O_RDWR);
946         xdup2(0, 1);
947         xdup2(0, 2);
948         setsid();
949         openlog(applet_name, LOG_PID, LOG_DAEMON);
950         logmode = LOGMODE_SYSLOG;
951         return 1;
952 }
953 #else
954 static inline int daemonize(void) { return -ENOSYS; }
955 #endif
956
957 /* TODO */
958 static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
959 {
960         return 0;
961 }
962
963 /* RPC strerror analogs are terminally idiotic:
964  * *mandatory* prefix and \n at end.
965  * This hopefully helps. Usage:
966  * error_msg_rpc(clnt_*error*(" ")) */
967 static void error_msg_rpc(const char *msg)
968 {
969         int len;
970         while (msg[0] == ' ' || msg[0] == ':') msg++;
971         len = strlen(msg);
972         while (len && msg[len-1] == '\n') len--;
973         bb_error_msg("%.*s", len, msg);
974 }
975
976 /* NB: mp->xxx fields may be trashed on exit */
977 static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
978 {
979         CLIENT *mclient;
980         char *hostname;
981         char *pathname;
982         char *mounthost;
983         /* prior to 2.6.23, kernel took NFS options in a form of this struct
984          * only. 2.6.23+ looks at data->version, and if it's not 1..6,
985          * then data pointer is interpreted as a string. */
986         struct nfs_mount_data data;
987         char *opt;
988         struct hostent *hp;
989         struct sockaddr_in server_addr;
990         struct sockaddr_in mount_server_addr;
991         int msock, fsock;
992         union {
993                 struct fhstatus nfsv2;
994                 struct mountres3 nfsv3;
995         } status;
996         int daemonized;
997         char *s;
998         int port;
999         int mountport;
1000         int proto;
1001 #if BB_MMU
1002         smallint bg = 0;
1003 #else
1004         enum { bg = 0 };
1005 #endif
1006         int retry;
1007         int mountprog;
1008         int mountvers;
1009         int nfsprog;
1010         int nfsvers;
1011         int retval;
1012         /* these all are one-bit really. gcc 4.3.1 likes this combination: */
1013         smallint tcp;
1014         smallint soft;
1015         int intr;
1016         int posix;
1017         int nocto;
1018         int noac;
1019         int nordirplus;
1020         int nolock;
1021
1022         find_kernel_nfs_mount_version();
1023
1024         daemonized = 0;
1025         mounthost = NULL;
1026         retval = ETIMEDOUT;
1027         msock = fsock = -1;
1028         mclient = NULL;
1029
1030         /* NB: hostname, mounthost, filteropts must be free()d prior to return */
1031
1032         filteropts = xstrdup(filteropts); /* going to trash it later... */
1033
1034         hostname = xstrdup(mp->mnt_fsname);
1035         /* mount_main() guarantees that ':' is there */
1036         s = strchr(hostname, ':');
1037         pathname = s + 1;
1038         *s = '\0';
1039         /* Ignore all but first hostname in replicated mounts
1040            until they can be fully supported. (mack@sgi.com) */
1041         s = strchr(hostname, ',');
1042         if (s) {
1043                 *s = '\0';
1044                 bb_error_msg("warning: multiple hostnames not supported");
1045         }
1046
1047         server_addr.sin_family = AF_INET;
1048         if (!inet_aton(hostname, &server_addr.sin_addr)) {
1049                 hp = gethostbyname(hostname);
1050                 if (hp == NULL) {
1051                         bb_herror_msg("%s", hostname);
1052                         goto fail;
1053                 }
1054                 if (hp->h_length != (int)sizeof(struct in_addr)) {
1055                         bb_error_msg_and_die("only IPv4 is supported");
1056                 }
1057                 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
1058         }
1059
1060         memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1061
1062         /* add IP address to mtab options for use when unmounting */
1063
1064         if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
1065                 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1066         } else {
1067                 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1068                                         mp->mnt_opts[0] ? "," : "",
1069                                         inet_ntoa(server_addr.sin_addr));
1070                 free(mp->mnt_opts);
1071                 mp->mnt_opts = tmp;
1072         }
1073
1074         /* Set default options.
1075          * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
1076          * let the kernel decide.
1077          * timeo is filled in after we know whether it'll be TCP or UDP. */
1078         memset(&data, 0, sizeof(data));
1079         data.retrans  = 3;
1080         data.acregmin = 3;
1081         data.acregmax = 60;
1082         data.acdirmin = 30;
1083         data.acdirmax = 60;
1084         data.namlen   = NAME_MAX;
1085
1086         soft = 0;
1087         intr = 0;
1088         posix = 0;
1089         nocto = 0;
1090         nolock = 0;
1091         noac = 0;
1092         nordirplus = 0;
1093         retry = 10000;          /* 10000 minutes ~ 1 week */
1094         tcp = 0;
1095
1096         mountprog = MOUNTPROG;
1097         mountvers = 0;
1098         port = 0;
1099         mountport = 0;
1100         nfsprog = 100003;
1101         nfsvers = 0;
1102
1103         /* parse options */
1104         if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
1105                 char *opteq = strchr(opt, '=');
1106                 if (opteq) {
1107                         int val, idx;
1108                         static const char options[] ALIGN1 =
1109                                 /* 0 */ "rsize\0"
1110                                 /* 1 */ "wsize\0"
1111                                 /* 2 */ "timeo\0"
1112                                 /* 3 */ "retrans\0"
1113                                 /* 4 */ "acregmin\0"
1114                                 /* 5 */ "acregmax\0"
1115                                 /* 6 */ "acdirmin\0"
1116                                 /* 7 */ "acdirmax\0"
1117                                 /* 8 */ "actimeo\0"
1118                                 /* 9 */ "retry\0"
1119                                 /* 10 */ "port\0"
1120                                 /* 11 */ "mountport\0"
1121                                 /* 12 */ "mounthost\0"
1122                                 /* 13 */ "mountprog\0"
1123                                 /* 14 */ "mountvers\0"
1124                                 /* 15 */ "nfsprog\0"
1125                                 /* 16 */ "nfsvers\0"
1126                                 /* 17 */ "vers\0"
1127                                 /* 18 */ "proto\0"
1128                                 /* 19 */ "namlen\0"
1129                                 /* 20 */ "addr\0";
1130
1131                         *opteq++ = '\0';
1132                         idx = index_in_strings(options, opt);
1133                         switch (idx) {
1134                         case 12: // "mounthost"
1135                                 mounthost = xstrndup(opteq,
1136                                                 strcspn(opteq, " \t\n\r,"));
1137                                 continue;
1138                         case 18: // "proto"
1139                                 if (!strncmp(opteq, "tcp", 3))
1140                                         tcp = 1;
1141                                 else if (!strncmp(opteq, "udp", 3))
1142                                         tcp = 0;
1143                                 else
1144                                         bb_error_msg("warning: unrecognized proto= option");
1145                                 continue;
1146                         case 20: // "addr" - ignore
1147                                 continue;
1148                         }
1149
1150                         val = xatoi_u(opteq);
1151                         switch (idx) {
1152                         case 0: // "rsize"
1153                                 data.rsize = val;
1154                                 continue;
1155                         case 1: // "wsize"
1156                                 data.wsize = val;
1157                                 continue;
1158                         case 2: // "timeo"
1159                                 data.timeo = val;
1160                                 continue;
1161                         case 3: // "retrans"
1162                                 data.retrans = val;
1163                                 continue;
1164                         case 4: // "acregmin"
1165                                 data.acregmin = val;
1166                                 continue;
1167                         case 5: // "acregmax"
1168                                 data.acregmax = val;
1169                                 continue;
1170                         case 6: // "acdirmin"
1171                                 data.acdirmin = val;
1172                                 continue;
1173                         case 7: // "acdirmax"
1174                                 data.acdirmax = val;
1175                                 continue;
1176                         case 8: // "actimeo"
1177                                 data.acregmin = val;
1178                                 data.acregmax = val;
1179                                 data.acdirmin = val;
1180                                 data.acdirmax = val;
1181                                 continue;
1182                         case 9: // "retry"
1183                                 retry = val;
1184                                 continue;
1185                         case 10: // "port"
1186                                 port = val;
1187                                 continue;
1188                         case 11: // "mountport"
1189                                 mountport = val;
1190                                 continue;
1191                         case 13: // "mountprog"
1192                                 mountprog = val;
1193                                 continue;
1194                         case 14: // "mountvers"
1195                                 mountvers = val;
1196                                 continue;
1197                         case 15: // "nfsprog"
1198                                 nfsprog = val;
1199                                 continue;
1200                         case 16: // "nfsvers"
1201                         case 17: // "vers"
1202                                 nfsvers = val;
1203                                 continue;
1204                         case 19: // "namlen"
1205                                 //if (nfs_mount_version >= 2)
1206                                         data.namlen = val;
1207                                 //else
1208                                 //      bb_error_msg("warning: option namlen is not supported\n");
1209                                 continue;
1210                         default:
1211                                 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1212                                 goto fail;
1213                         }
1214                 }
1215                 else { /* not of the form opt=val */
1216                         static const char options[] ALIGN1 =
1217                                 "bg\0"
1218                                 "fg\0"
1219                                 "soft\0"
1220                                 "hard\0"
1221                                 "intr\0"
1222                                 "posix\0"
1223                                 "cto\0"
1224                                 "ac\0"
1225                                 "tcp\0"
1226                                 "udp\0"
1227                                 "lock\0"
1228                                 "rdirplus\0";
1229                         int val = 1;
1230                         if (!strncmp(opt, "no", 2)) {
1231                                 val = 0;
1232                                 opt += 2;
1233                         }
1234                         switch (index_in_strings(options, opt)) {
1235                         case 0: // "bg"
1236 #if BB_MMU
1237                                 bg = val;
1238 #endif
1239                                 break;
1240                         case 1: // "fg"
1241 #if BB_MMU
1242                                 bg = !val;
1243 #endif
1244                                 break;
1245                         case 2: // "soft"
1246                                 soft = val;
1247                                 break;
1248                         case 3: // "hard"
1249                                 soft = !val;
1250                                 break;
1251                         case 4: // "intr"
1252                                 intr = val;
1253                                 break;
1254                         case 5: // "posix"
1255                                 posix = val;
1256                                 break;
1257                         case 6: // "cto"
1258                                 nocto = !val;
1259                                 break;
1260                         case 7: // "ac"
1261                                 noac = !val;
1262                                 break;
1263                         case 8: // "tcp"
1264                                 tcp = val;
1265                                 break;
1266                         case 9: // "udp"
1267                                 tcp = !val;
1268                                 break;
1269                         case 10: // "lock"
1270                                 if (nfs_mount_version >= 3)
1271                                         nolock = !val;
1272                                 else
1273                                         bb_error_msg("warning: option nolock is not supported");
1274                                 break;
1275                         case 11: //rdirplus
1276                                 nordirplus = !val;
1277                                 break;
1278                         default:
1279                                 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1280                                 goto fail;
1281                         }
1282                 }
1283         }
1284         proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1285
1286         data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1287                 | (intr ? NFS_MOUNT_INTR : 0)
1288                 | (posix ? NFS_MOUNT_POSIX : 0)
1289                 | (nocto ? NFS_MOUNT_NOCTO : 0)
1290                 | (noac ? NFS_MOUNT_NOAC : 0)
1291                 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
1292         if (nfs_mount_version >= 2)
1293                 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1294         if (nfs_mount_version >= 3)
1295                 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1296         if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1297                 bb_error_msg("NFSv%d not supported", nfsvers);
1298                 goto fail;
1299         }
1300         if (nfsvers && !mountvers)
1301                 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1302         if (nfsvers && nfsvers < mountvers) {
1303                 mountvers = nfsvers;
1304         }
1305
1306         /* Adjust options if none specified */
1307         if (!data.timeo)
1308                 data.timeo = tcp ? 70 : 7;
1309
1310         data.version = nfs_mount_version;
1311
1312         if (vfsflags & MS_REMOUNT)
1313                 goto do_mount;
1314
1315         /*
1316          * If the previous mount operation on the same host was
1317          * backgrounded, and the "bg" for this mount is also set,
1318          * give up immediately, to avoid the initial timeout.
1319          */
1320         if (bg && we_saw_this_host_before(hostname)) {
1321                 daemonized = daemonize();
1322                 if (daemonized <= 0) { /* parent or error */
1323                         retval = -daemonized;
1324                         goto ret;
1325                 }
1326         }
1327
1328         /* Create mount daemon client */
1329         /* See if the nfs host = mount host. */
1330         if (mounthost) {
1331                 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1332                         mount_server_addr.sin_family = AF_INET;
1333                         mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1334                 } else {
1335                         hp = gethostbyname(mounthost);
1336                         if (hp == NULL) {
1337                                 bb_herror_msg("%s", mounthost);
1338                                 goto fail;
1339                         }
1340                         if (hp->h_length != (int)sizeof(struct in_addr)) {
1341                                 bb_error_msg_and_die("only IPv4 is supported");
1342                         }
1343                         mount_server_addr.sin_family = AF_INET;
1344                         memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
1345                 }
1346         }
1347
1348         /*
1349          * The following loop implements the mount retries. When the mount
1350          * times out, and the "bg" option is set, we background ourself
1351          * and continue trying.
1352          *
1353          * The case where the mount point is not present and the "bg"
1354          * option is set, is treated as a timeout. This is done to
1355          * support nested mounts.
1356          *
1357          * The "retry" count specified by the user is the number of
1358          * minutes to retry before giving up.
1359          */
1360         {
1361                 struct timeval total_timeout;
1362                 struct timeval retry_timeout;
1363                 struct pmap pm_mnt;
1364                 time_t t;
1365                 time_t prevt;
1366                 time_t timeout;
1367
1368                 retry_timeout.tv_sec = 3;
1369                 retry_timeout.tv_usec = 0;
1370                 total_timeout.tv_sec = 20;
1371                 total_timeout.tv_usec = 0;
1372 /* FIXME: use monotonic()? */
1373                 timeout = time(NULL) + 60 * retry;
1374                 prevt = 0;
1375                 t = 30;
1376  retry:
1377                 /* Be careful not to use too many CPU cycles */
1378                 if (t - prevt < 30)
1379                         sleep(30);
1380
1381                 get_mountport(&pm_mnt, &mount_server_addr,
1382                                 mountprog,
1383                                 mountvers,
1384                                 proto,
1385                                 mountport);
1386                 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
1387
1388                 /* contact the mount daemon via TCP */
1389                 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
1390                 msock = RPC_ANYSOCK;
1391
1392                 switch (pm_mnt.pm_prot) {
1393                 case IPPROTO_UDP:
1394                         mclient = clntudp_create(&mount_server_addr,
1395                                                  pm_mnt.pm_prog,
1396                                                  pm_mnt.pm_vers,
1397                                                  retry_timeout,
1398                                                  &msock);
1399                         if (mclient)
1400                                 break;
1401                         mount_server_addr.sin_port = htons(pm_mnt.pm_port);
1402                         msock = RPC_ANYSOCK;
1403                 case IPPROTO_TCP:
1404                         mclient = clnttcp_create(&mount_server_addr,
1405                                                  pm_mnt.pm_prog,
1406                                                  pm_mnt.pm_vers,
1407                                                  &msock, 0, 0);
1408                         break;
1409                 default:
1410                         mclient = NULL;
1411                 }
1412                 if (!mclient) {
1413                         if (!daemonized && prevt == 0)
1414                                 error_msg_rpc(clnt_spcreateerror(" "));
1415                 } else {
1416                         enum clnt_stat clnt_stat;
1417
1418                         /* Try to mount hostname:pathname */
1419                         mclient->cl_auth = authunix_create_default();
1420
1421                         /* Make pointers in xdr_mountres3 NULL so
1422                          * that xdr_array allocates memory for us
1423                          */
1424                         memset(&status, 0, sizeof(status));
1425
1426                         if (pm_mnt.pm_vers == 3)
1427                                 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1428                                               (xdrproc_t) xdr_dirpath,
1429                                               (caddr_t) &pathname,
1430                                               (xdrproc_t) xdr_mountres3,
1431                                               (caddr_t) &status,
1432                                               total_timeout);
1433                         else
1434                                 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1435                                               (xdrproc_t) xdr_dirpath,
1436                                               (caddr_t) &pathname,
1437                                               (xdrproc_t) xdr_fhstatus,
1438                                               (caddr_t) &status,
1439                                               total_timeout);
1440
1441                         if (clnt_stat == RPC_SUCCESS)
1442                                 goto prepare_kernel_data; /* we're done */
1443                         if (errno != ECONNREFUSED) {
1444                                 error_msg_rpc(clnt_sperror(mclient, " "));
1445                                 goto fail;      /* don't retry */
1446                         }
1447                         /* Connection refused */
1448                         if (!daemonized && prevt == 0) /* print just once */
1449                                 error_msg_rpc(clnt_sperror(mclient, " "));
1450                         auth_destroy(mclient->cl_auth);
1451                         clnt_destroy(mclient);
1452                         mclient = NULL;
1453                         close(msock);
1454                         msock = -1;
1455                 }
1456
1457                 /* Timeout. We are going to retry... maybe */
1458                 if (!bg)
1459                         goto fail;
1460                 if (!daemonized) {
1461                         daemonized = daemonize();
1462                         if (daemonized <= 0) { /* parent or error */
1463                                 retval = -daemonized;
1464                                 goto ret;
1465                         }
1466                 }
1467                 prevt = t;
1468                 t = time(NULL);
1469                 if (t >= timeout)
1470                         /* TODO error message */
1471                         goto fail;
1472
1473                 goto retry;
1474         }
1475
1476  prepare_kernel_data:
1477
1478         if (nfsvers == 2) {
1479                 if (status.nfsv2.fhs_status != 0) {
1480                         bb_error_msg("%s:%s failed, reason given by server: %s",
1481                                 hostname, pathname,
1482                                 nfs_strerror(status.nfsv2.fhs_status));
1483                         goto fail;
1484                 }
1485                 memcpy(data.root.data,
1486                                 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1487                                 NFS_FHSIZE);
1488                 data.root.size = NFS_FHSIZE;
1489                 memcpy(data.old_root.data,
1490                                 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1491                                 NFS_FHSIZE);
1492         } else {
1493                 fhandle3 *my_fhandle;
1494                 if (status.nfsv3.fhs_status != 0) {
1495                         bb_error_msg("%s:%s failed, reason given by server: %s",
1496                                 hostname, pathname,
1497                                 nfs_strerror(status.nfsv3.fhs_status));
1498                         goto fail;
1499                 }
1500                 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1501                 memset(data.old_root.data, 0, NFS_FHSIZE);
1502                 memset(&data.root, 0, sizeof(data.root));
1503                 data.root.size = my_fhandle->fhandle3_len;
1504                 memcpy(data.root.data,
1505                                 (char *) my_fhandle->fhandle3_val,
1506                                 my_fhandle->fhandle3_len);
1507
1508                 data.flags |= NFS_MOUNT_VER3;
1509         }
1510
1511         /* Create nfs socket for kernel */
1512         if (tcp) {
1513                 if (nfs_mount_version < 3) {
1514                         bb_error_msg("NFS over TCP is not supported");
1515                         goto fail;
1516                 }
1517                 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1518         } else
1519                 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1520         if (fsock < 0) {
1521                 bb_perror_msg("nfs socket");
1522                 goto fail;
1523         }
1524         if (bindresvport(fsock, 0) < 0) {
1525                 bb_perror_msg("nfs bindresvport");
1526                 goto fail;
1527         }
1528         if (port == 0) {
1529                 server_addr.sin_port = PMAPPORT;
1530                 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1531                                         tcp ? IPPROTO_TCP : IPPROTO_UDP);
1532                 if (port == 0)
1533                         port = NFS_PORT;
1534         }
1535         server_addr.sin_port = htons(port);
1536
1537         /* Prepare data structure for kernel */
1538         data.fd = fsock;
1539         memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1540         strncpy(data.hostname, hostname, sizeof(data.hostname));
1541
1542         /* Clean up */
1543         auth_destroy(mclient->cl_auth);
1544         clnt_destroy(mclient);
1545         close(msock);
1546         msock = -1;
1547
1548         if (bg) {
1549                 /* We must wait until mount directory is available */
1550                 struct stat statbuf;
1551                 int delay = 1;
1552                 while (stat(mp->mnt_dir, &statbuf) == -1) {
1553                         if (!daemonized) {
1554                                 daemonized = daemonize();
1555                                 if (daemonized <= 0) { /* parent or error */
1556 /* FIXME: parent doesn't close fsock - ??! */
1557                                         retval = -daemonized;
1558                                         goto ret;
1559                                 }
1560                         }
1561                         sleep(delay);   /* 1, 2, 4, 8, 16, 30, ... */
1562                         delay *= 2;
1563                         if (delay > 30)
1564                                 delay = 30;
1565                 }
1566         }
1567
1568         /* Perform actual mount */
1569  do_mount:
1570         mp->mnt_type = (char*)"nfs";
1571         retval = mount_it_now(mp, vfsflags, (char*)&data);
1572         goto ret;
1573
1574         /* Abort */
1575  fail:
1576         if (msock >= 0) {
1577                 if (mclient) {
1578                         auth_destroy(mclient->cl_auth);
1579                         clnt_destroy(mclient);
1580                 }
1581                 close(msock);
1582         }
1583         if (fsock >= 0)
1584                 close(fsock);
1585
1586  ret:
1587         free(hostname);
1588         free(mounthost);
1589         free(filteropts);
1590         return retval;
1591 }
1592
1593 #else // !ENABLE_FEATURE_MOUNT_NFS
1594
1595 // Never called. Call should be optimized out.
1596 int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
1597
1598 #endif // !ENABLE_FEATURE_MOUNT_NFS
1599
1600 // Mount one directory.  Handles CIFS, NFS, loopback, autobind, and filesystem
1601 // type detection.  Returns 0 for success, nonzero for failure.
1602 // NB: mp->xxx fields may be trashed on exit
1603 static int singlemount(struct mntent *mp, int ignore_busy)
1604 {
1605         int rc = -1;
1606         long vfsflags;
1607         char *loopFile = NULL, *filteropts = NULL;
1608         llist_t *fl = NULL;
1609         struct stat st;
1610
1611         errno = 0;
1612
1613         vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1614
1615         // Treat fstype "auto" as unspecified
1616         if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1617                 mp->mnt_type = NULL;
1618
1619         // Might this be a virtual filesystem?
1620         if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1621                 char *args[35];
1622                 char *s;
1623                 int n;
1624                 // fsname: "cmd#arg1#arg2..."
1625                 // WARNING: allows execution of arbitrary commands!
1626                 // Try "mount 'sh#-c#sh' bogus_dir".
1627                 // It is safe ONLY because non-root
1628                 // cannot use two-argument mount command
1629                 // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1630                 // "mount: can't find sh#-c#sh in /etc/fstab"
1631                 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1632
1633                 s = mp->mnt_fsname;
1634                 n = 0;
1635                 args[n++] = s;
1636                 while (*s && n < 35 - 2) {
1637                         if (*s++ == '#' && *s != '#') {
1638                                 s[-1] = '\0';
1639                                 args[n++] = s;
1640                         }
1641                 }
1642                 args[n++] = mp->mnt_dir;
1643                 args[n] = NULL;
1644                 rc = spawn_and_wait(args);
1645                 goto report_error;
1646         }
1647
1648         // Might this be an CIFS filesystem?
1649         if (ENABLE_FEATURE_MOUNT_CIFS
1650          && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1651          && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1652          && mp->mnt_fsname[0] == mp->mnt_fsname[1]
1653         ) {
1654                 int len;
1655                 char c;
1656                 len_and_sockaddr *lsa;
1657                 char *hostname, *dotted, *ip;
1658
1659                 hostname = mp->mnt_fsname + 2;
1660                 len = strcspn(hostname, "/\\");
1661                 if (len == 0 || hostname[len] == '\0')
1662                         goto report_error;
1663                 c = hostname[len];
1664                 hostname[len] = '\0';
1665                 lsa = host2sockaddr(hostname, 0);
1666                 hostname[len] = c;
1667                 if (!lsa)
1668                         goto report_error;
1669
1670                 // Insert "ip=..." option into options
1671                 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1672                 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1673                 ip = xasprintf("ip=%s", dotted);
1674                 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
1675                 parse_mount_options(ip, &filteropts);
1676                 if (ENABLE_FEATURE_CLEAN_UP) free(ip);
1677
1678                 // "-o mand" is required [why?]
1679                 vfsflags |= MS_MANDLOCK;
1680                 mp->mnt_type = (char*)"cifs";
1681                 rc = mount_it_now(mp, vfsflags, filteropts);
1682
1683                 goto report_error;
1684         }
1685
1686         // Might this be an NFS filesystem?
1687         if (ENABLE_FEATURE_MOUNT_NFS
1688          && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
1689          && strchr(mp->mnt_fsname, ':') != NULL
1690         ) {
1691                 rc = nfsmount(mp, vfsflags, filteropts);
1692                 goto report_error;
1693         }
1694
1695         // Look at the file.  (Not found isn't a failure for remount, or for
1696         // a synthetic filesystem like proc or sysfs.)
1697         // (We use stat, not lstat, in order to allow
1698         // mount symlink_to_file_or_blkdev dir)
1699         if (!stat(mp->mnt_fsname, &st)
1700          && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1701         ) {
1702                 // Do we need to allocate a loopback device for it?
1703                 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1704                         loopFile = bb_simplify_path(mp->mnt_fsname);
1705                         mp->mnt_fsname = NULL; // will receive malloced loop dev name
1706                         if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
1707                                 if (errno == EPERM || errno == EACCES)
1708                                         bb_error_msg(bb_msg_perm_denied_are_you_root);
1709                                 else
1710                                         bb_perror_msg("can't setup loop device");
1711                                 return errno;
1712                         }
1713
1714                 // Autodetect bind mounts
1715                 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1716                         vfsflags |= MS_BIND;
1717         }
1718
1719         // If we know the fstype (or don't need to), jump straight
1720         // to the actual mount.
1721         if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1722                 rc = mount_it_now(mp, vfsflags, filteropts);
1723         else {
1724                 // Loop through filesystem types until mount succeeds
1725                 // or we run out
1726
1727                 // Initialize list of block backed filesystems.
1728                 // This has to be done here so that during "mount -a",
1729                 // mounts after /proc shows up can autodetect.
1730                 if (!fslist) {
1731                         fslist = get_block_backed_filesystems();
1732                         if (ENABLE_FEATURE_CLEAN_UP && fslist)
1733                                 atexit(delete_block_backed_filesystems);
1734                 }
1735
1736                 for (fl = fslist; fl; fl = fl->link) {
1737                         mp->mnt_type = fl->data;
1738                         rc = mount_it_now(mp, vfsflags, filteropts);
1739                         if (!rc)
1740                                 break;
1741                 }
1742         }
1743
1744         // If mount failed, clean up loop file (if any).
1745         if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1746                 del_loop(mp->mnt_fsname);
1747                 if (ENABLE_FEATURE_CLEAN_UP) {
1748                         free(loopFile);
1749                         free(mp->mnt_fsname);
1750                 }
1751         }
1752
1753  report_error:
1754         if (ENABLE_FEATURE_CLEAN_UP)
1755                 free(filteropts);
1756
1757         if (errno == EBUSY && ignore_busy)
1758                 return 0;
1759         if (rc < 0)
1760                 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
1761         return rc;
1762 }
1763
1764 // -O support
1765 //    -O interprets a list of filter options which select whether a mount
1766 // point will be mounted: only mounts with options matching *all* filtering
1767 // options will be selected.
1768 //    By default each -O filter option must be present in the list of mount
1769 // options, but if it is prefixed by "no" then it must be absent.
1770 // For example,
1771 //  -O a,nob,c  matches  -o a,c  but fails to match  -o a,b,c
1772 //              (and also fails to match  -o a  because  -o c  is absent).
1773 //
1774 // It is different from -t in that each option is matched exactly; a leading
1775 // "no" at the beginning of one option does not negate the rest.
1776 static int match_opt(const char *fs_opt_in, const char *O_opt)
1777 {
1778         if (!O_opt)
1779                 return 1;
1780
1781         while (*O_opt) {
1782                 const char *fs_opt = fs_opt_in;
1783                 int O_len;
1784                 int match;
1785
1786                 // If option begins with "no" then treat as an inverted match:
1787                 // matching is a failure
1788                 match = 0;
1789                 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
1790                         match = 1;
1791                         O_opt += 2;
1792                 }
1793                 // Isolate the current O option
1794                 O_len = strchrnul(O_opt, ',') - O_opt;
1795                 // Check for a match against existing options
1796                 while (1) {
1797                         if (strncmp(fs_opt, O_opt, O_len) == 0
1798                          && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
1799                         ) {
1800                                 if (match)
1801                                         return 0;  // "no" prefix, but option found
1802                                 match = 1;  // current O option found, go check next one
1803                                 break;
1804                         }
1805                         fs_opt = strchr(fs_opt, ',');
1806                         if (!fs_opt)
1807                                 break;
1808                         fs_opt++;
1809                 }
1810                 if (match == 0)
1811                         return 0;     // match wanted but not found
1812                 if (O_opt[O_len] == '\0') // end?
1813                         break;
1814                 // Step to the next O option
1815                 O_opt += O_len + 1;
1816         }
1817         // If we get here then everything matched
1818         return 1;
1819 }
1820
1821 // Parse options, if necessary parse fstab/mtab, and call singlemount for
1822 // each directory to be mounted.
1823 int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1824 int mount_main(int argc UNUSED_PARAM, char **argv)
1825 {
1826         char *cmdopts = xzalloc(1);
1827         char *fstype = NULL;
1828         char *O_optmatch = NULL;
1829         char *storage_path;
1830         llist_t *lst_o = NULL;
1831         const char *fstabname;
1832         FILE *fstab;
1833         int i, j;
1834         int rc = EXIT_SUCCESS;
1835         unsigned opt;
1836         struct mntent mtpair[2], *mtcur = mtpair;
1837         IF_NOT_DESKTOP(const int nonroot = 0;)
1838
1839         IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
1840
1841         // Parse long options, like --bind and --move.  Note that -o option
1842         // and --option are synonymous.  Yes, this means --remount,rw works.
1843         for (i = j = 1; argv[i]; i++) {
1844                 if (argv[i][0] == '-' && argv[i][1] == '-')
1845                         append_mount_options(&cmdopts, argv[i] + 2);
1846                 else
1847                         argv[j++] = argv[i];
1848         }
1849         argv[j] = NULL;
1850
1851         // Parse remaining options
1852         // Max 2 params; -o is a list, -v is a counter
1853         opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
1854         opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
1855                         IF_FEATURE_MOUNT_VERBOSE(, &verbose));
1856         while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
1857         if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1858         if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
1859         argv += optind;
1860
1861         // If we have no arguments, show currently mounted filesystems
1862         if (!argv[0]) {
1863                 if (!(opt & OPT_a)) {
1864                         FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1865
1866                         if (!mountTable)
1867                                 bb_error_msg_and_die("no %s", bb_path_mtab_file);
1868
1869                         while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
1870                                                                 GETMNTENT_BUFSIZE))
1871                         {
1872                                 // Don't show rootfs. FIXME: why??
1873                                 // util-linux 2.12a happily shows rootfs...
1874                                 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
1875
1876                                 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
1877                                         printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1878                                                         mtpair->mnt_dir, mtpair->mnt_type,
1879                                                         mtpair->mnt_opts);
1880                         }
1881                         if (ENABLE_FEATURE_CLEAN_UP)
1882                                 endmntent(mountTable);
1883                         return EXIT_SUCCESS;
1884                 }
1885                 storage_path = NULL;
1886         } else {
1887                 // When we have two arguments, the second is the directory and we can
1888                 // skip looking at fstab entirely.  We can always abspath() the directory
1889                 // argument when we get it.
1890                 if (argv[1]) {
1891                         if (nonroot)
1892                                 bb_error_msg_and_die(bb_msg_you_must_be_root);
1893                         mtpair->mnt_fsname = argv[0];
1894                         mtpair->mnt_dir = argv[1];
1895                         mtpair->mnt_type = fstype;
1896                         mtpair->mnt_opts = cmdopts;
1897                         resolve_mount_spec(&mtpair->mnt_fsname);
1898                         rc = singlemount(mtpair, /*ignore_busy:*/ 0);
1899                         return rc;
1900                 }
1901                 storage_path = bb_simplify_path(argv[0]); // malloced
1902         }
1903
1904         // Past this point, we are handling either "mount -a [opts]"
1905         // or "mount [opts] single_param"
1906
1907         i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
1908         if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
1909                 bb_error_msg_and_die(bb_msg_you_must_be_root);
1910
1911         // If we have a shared subtree flag, don't worry about fstab or mtab.
1912         if (ENABLE_FEATURE_MOUNT_FLAGS
1913          && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1914         ) {
1915                 // verbose_mount(source, target, type, flags, data)
1916                 rc = verbose_mount("", argv[0], "", i, "");
1917                 if (rc)
1918                         bb_simple_perror_msg_and_die(argv[0]);
1919                 return rc;
1920         }
1921
1922         // Open either fstab or mtab
1923         fstabname = "/etc/fstab";
1924         if (i & MS_REMOUNT) {
1925                 // WARNING. I am not sure this matches util-linux's
1926                 // behavior. It's possible util-linux does not
1927                 // take -o opts from mtab (takes only mount source).
1928                 fstabname = bb_path_mtab_file;
1929         }
1930         fstab = setmntent(fstabname, "r");
1931         if (!fstab)
1932                 bb_perror_msg_and_die("can't read '%s'", fstabname);
1933
1934         // Loop through entries until we find what we're looking for
1935         memset(mtpair, 0, sizeof(mtpair));
1936         for (;;) {
1937                 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
1938
1939                 // Get next fstab entry
1940                 if (!getmntent_r(fstab, mtcur, getmntent_buf
1941                                         + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
1942                                 GETMNTENT_BUFSIZE/2)
1943                 ) { // End of fstab/mtab is reached
1944                         mtcur = mtother; // the thing we found last time
1945                         break;
1946                 }
1947
1948                 // If we're trying to mount something specific and this isn't it,
1949                 // skip it.  Note we must match the exact text in fstab (ala
1950                 // "proc") or a full path from root
1951                 if (argv[0]) {
1952
1953                         // Is this what we're looking for?
1954                         if (strcmp(argv[0], mtcur->mnt_fsname) != 0
1955                          && strcmp(storage_path, mtcur->mnt_fsname) != 0
1956                          && strcmp(argv[0], mtcur->mnt_dir) != 0
1957                          && strcmp(storage_path, mtcur->mnt_dir) != 0
1958                         ) {
1959                                 continue; // no
1960                         }
1961
1962                         // Remember this entry.  Something later may have
1963                         // overmounted it, and we want the _last_ match.
1964                         mtcur = mtother;
1965
1966                 // If we're mounting all
1967                 } else {
1968                         struct mntent *mp;
1969                         // No, mount -a won't mount anything,
1970                         // even user mounts, for mere humans
1971                         if (nonroot)
1972                                 bb_error_msg_and_die(bb_msg_you_must_be_root);
1973
1974                         // Does type match? (NULL matches always)
1975                         if (!match_fstype(mtcur, fstype))
1976                                 continue;
1977
1978                         // Skip noauto and swap anyway
1979                         if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
1980                         // swap is bogus "fstype", parse_mount_options can't check fstypes
1981                          || strcasecmp(mtcur->mnt_type, "swap") == 0
1982                         ) {
1983                                 continue;
1984                         }
1985
1986                         // Does (at least one) option match?
1987                         // (NULL matches always)
1988                         if (!match_opt(mtcur->mnt_opts, O_optmatch))
1989                                 continue;
1990
1991                         resolve_mount_spec(&mtcur->mnt_fsname);
1992
1993                         // NFS mounts want this to be xrealloc-able
1994                         mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
1995
1996                         // If nothing is mounted on this directory...
1997                         // (otherwise repeated "mount -a" mounts everything again)
1998                         mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
1999                         // We do not check fsname match of found mount point -
2000                         // "/" may have fsname of "/dev/root" while fstab
2001                         // says "/dev/something_else".
2002                         if (mp) {
2003                                 if (verbose) {
2004                                         bb_error_msg("according to %s, "
2005                                                 "%s is already mounted on %s",
2006                                                 bb_path_mtab_file,
2007                                                 mp->mnt_fsname, mp->mnt_dir);
2008                                 }
2009                         } else {
2010                                 // ...mount this thing
2011                                 if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2012                                         // Count number of failed mounts
2013                                         rc++;
2014                                 }
2015                         }
2016                         free(mtcur->mnt_opts);
2017                 }
2018         }
2019
2020         // End of fstab/mtab is reached.
2021         // Were we looking for something specific?
2022         if (argv[0]) { // yes
2023                 long l;
2024
2025                 // If we didn't find anything, complain
2026                 if (!mtcur->mnt_fsname)
2027                         bb_error_msg_and_die("can't find %s in %s",
2028                                 argv[0], fstabname);
2029
2030                 // What happens when we try to "mount swap_partition"?
2031                 // (fstab containts "swap_partition swap swap defaults 0 0")
2032                 // util-linux-ng 2.13.1 does this:
2033                 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2034                 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2035                 // lstat("swap", 0x7fff62a3a640)           = -1 ENOENT (No such file or directory)
2036                 // write(2, "mount: mount point swap does not exist\n", 39) = 39
2037                 // exit_group(32)                          = ?
2038 #if 0
2039                 // In case we want to simply skip swap partitions:
2040                 l = parse_mount_options(mtcur->mnt_opts, NULL);
2041                 if ((l & MOUNT_SWAP)
2042                 // swap is bogus "fstype", parse_mount_options can't check fstypes
2043                  || strcasecmp(mtcur->mnt_type, "swap") == 0
2044                 ) {
2045                         goto ret;
2046                 }
2047 #endif
2048                 if (nonroot) {
2049                         // fstab must have "users" or "user"
2050                         l = parse_mount_options(mtcur->mnt_opts, NULL);
2051                         if (!(l & MOUNT_USERS))
2052                                 bb_error_msg_and_die(bb_msg_you_must_be_root);
2053                 }
2054
2055                 //util-linux-2.12 does not do this check.
2056                 //// If nothing is mounted on this directory...
2057                 //// (otherwise repeated "mount FOO" mounts FOO again)
2058                 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2059                 //if (mp) {
2060                 //      bb_error_msg("according to %s, "
2061                 //              "%s is already mounted on %s",
2062                 //              bb_path_mtab_file,
2063                 //              mp->mnt_fsname, mp->mnt_dir);
2064                 //} else {
2065                         // ...mount the last thing we found
2066                         mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2067                         append_mount_options(&(mtcur->mnt_opts), cmdopts);
2068                         resolve_mount_spec(&mtpair->mnt_fsname);
2069                         rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2070                         if (ENABLE_FEATURE_CLEAN_UP)
2071                                 free(mtcur->mnt_opts);
2072                 //}
2073         }
2074
2075  //ret:
2076         if (ENABLE_FEATURE_CLEAN_UP)
2077                 endmntent(fstab);
2078         if (ENABLE_FEATURE_CLEAN_UP) {
2079                 free(storage_path);
2080                 free(cmdopts);
2081         }
2082
2083 //TODO: exitcode should be ORed mask of (from "man mount"):
2084 // 0 success
2085 // 1 incorrect invocation or permissions
2086 // 2 system error (out of memory, cannot fork, no more loop devices)
2087 // 4 internal mount bug or missing nfs support in mount
2088 // 8 user interrupt
2089 //16 problems writing or locking /etc/mtab
2090 //32 mount failure
2091 //64 some mount succeeded
2092         return rc;
2093 }