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