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