Magellan Linux

Annotation of /tags/mkinitrd-6_1_12/busybox/util-linux/mount.c

Parent Directory Parent Directory | Revision Log Revision Log


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