1 /* vi: set sw=4 ts=4: */
3 * Mini mount implementation for busybox
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>
9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
12 /* Design notes: There is no spec for mount. Remind me to write one.
14 mount_main() calls singlemount() which calls mount_it_now().
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.
24 /* Needed for nfs support only... */
26 #include <sys/utsname.h>
30 #include <rpc/pmap_prot.h>
31 #include <rpc/pmap_clnt.h>
34 #define MS_SILENT (1 << 15)
37 #if defined(__dietlibc__)
38 /* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
39 * dietlibc-0.30 does not have implementation of getmntent_r() */
40 struct mntent
*getmntent_r(FILE* stream
, struct mntent
* result
, char* buffer
, int bufsize
)
42 struct mntent
* ment
= getmntent(stream
);
43 memcpy(result
, ment
, sizeof(struct mntent
));
48 #define getmntent_buf bb_common_bufsiz1
51 // Not real flags, but we want to be able to check for this.
53 MOUNT_USERS
= (1<<28)*ENABLE_DESKTOP
,
54 MOUNT_NOAUTO
= (1<<29),
57 // TODO: more "user" flag compatibility.
58 // "user" option (from mount manpage):
59 // Only the user that mounted a filesystem can unmount it again.
60 // If any user should be able to unmount, then use users instead of user
61 // in the fstab line. The owner option is similar to the user option,
62 // with the restriction that the user must be the owner of the special file.
63 // This may be useful e.g. for /dev/fd if a login script makes
64 // the console user owner of this device.
66 /* Standard mount options (from -o options or --options), with corresponding
73 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
75 USE_FEATURE_MOUNT_LOOP(
79 USE_FEATURE_MOUNT_FSTAB(
81 /* {"quiet", 0}, - do not filter out, vfat wants to see it */
82 {"noauto", MOUNT_NOAUTO
},
85 USE_DESKTOP({"user", MOUNT_USERS
},)
86 USE_DESKTOP({"users", MOUNT_USERS
},)
89 USE_FEATURE_MOUNT_FLAGS(
91 {"nosuid", MS_NOSUID
},
96 {"noexec", MS_NOEXEC
},
97 {"sync", MS_SYNCHRONOUS
},
98 {"async", ~MS_SYNCHRONOUS
},
99 {"atime", ~MS_NOATIME
},
100 {"noatime", MS_NOATIME
},
101 {"diratime", ~MS_NODIRATIME
},
102 {"nodiratime", MS_NODIRATIME
},
103 {"loud", ~MS_SILENT
},
109 {"shared", MS_SHARED
},
111 {"private", MS_PRIVATE
},
112 {"unbindable", MS_UNBINDABLE
},
113 {"rshared", MS_SHARED
|MS_RECURSIVE
},
114 {"rslave", MS_SLAVE
|MS_RECURSIVE
},
115 {"rprivate", MS_SLAVE
|MS_RECURSIVE
},
116 {"runbindable", MS_UNBINDABLE
|MS_RECURSIVE
},
119 // Always understood.
121 {"ro", MS_RDONLY
}, // vfs flag
122 {"rw", ~MS_RDONLY
}, // vfs flag
123 {"remount", MS_REMOUNT
}, // action flag
127 /* Append mount options to string */
128 static void append_mount_options(char **oldopts
, const char *newopts
)
130 if (*oldopts
&& **oldopts
) {
131 /* do not insert options which are already there */
134 int len
= strlen(newopts
);
135 p
= strchr(newopts
, ',');
136 if (p
) len
= p
- newopts
;
139 if (!strncmp(p
, newopts
, len
)
140 && (p
[len
]==',' || p
[len
]==0))
146 p
= xasprintf("%s,%.*s", *oldopts
, len
, newopts
);
151 while (newopts
[0] == ',') newopts
++;
154 if (ENABLE_FEATURE_CLEAN_UP
) free(*oldopts
);
155 *oldopts
= xstrdup(newopts
);
159 /* Use the mount_options list to parse options into flags.
160 * Also return list of unrecognized options if unrecognized!=NULL */
161 static int parse_mount_options(char *options
, char **unrecognized
)
163 int flags
= MS_SILENT
;
165 // Loop through options
168 char *comma
= strchr(options
, ',');
170 if (comma
) *comma
= 0;
172 // Find this option in mount_options
173 for (i
= 0; i
< ARRAY_SIZE(mount_options
); i
++) {
174 if (!strcasecmp(mount_options
[i
].name
, options
)) {
175 long fl
= mount_options
[i
].flags
;
176 if (fl
< 0) flags
&= fl
;
181 // If unrecognized not NULL, append unrecognized mount options */
182 if (unrecognized
&& i
== ARRAY_SIZE(mount_options
)) {
183 // Add it to strflags, to pass on to kernel
184 i
= *unrecognized
? strlen(*unrecognized
) : 0;
185 *unrecognized
= xrealloc(*unrecognized
, i
+strlen(options
)+2);
187 // Comma separated if it's not the first one
188 if (i
) (*unrecognized
)[i
++] = ',';
189 strcpy((*unrecognized
)+i
, options
);
194 // Advance to next option
202 // Return a list of all block device backed filesystems
204 static llist_t
*get_block_backed_filesystems(void)
206 static const char filesystems
[2][sizeof("/proc/filesystems")] = {
215 for (i
= 0; i
< 2; i
++) {
216 f
= fopen(filesystems
[i
], "r");
219 while ((buf
= xmalloc_getline(f
)) != 0) {
220 if (!strncmp(buf
, "nodev", 5) && isspace(buf
[5]))
222 fs
= skip_whitespace(buf
);
223 if (*fs
=='#' || *fs
=='*' || !*fs
) continue;
225 llist_add_to_end(&list
, xstrdup(fs
));
228 if (ENABLE_FEATURE_CLEAN_UP
) fclose(f
);
234 static llist_t
*fslist
;
236 #if ENABLE_FEATURE_CLEAN_UP
237 static void delete_block_backed_filesystems(void)
239 llist_free(fslist
, free
);
242 void delete_block_backed_filesystems(void);
245 #if ENABLE_FEATURE_MTAB_SUPPORT
246 static int useMtab
= 1;
253 // Perform actual mount of specific filesystem at specific location.
254 // NB: mp->xxx fields may be trashed on exit
255 static int mount_it_now(struct mntent
*mp
, int vfsflags
, char *filteropts
)
259 if (fakeIt
) goto mtab
;
261 // Mount, with fallback to read-only if necessary.
264 rc
= mount(mp
->mnt_fsname
, mp
->mnt_dir
, mp
->mnt_type
,
265 vfsflags
, filteropts
);
266 if (!rc
|| (vfsflags
&MS_RDONLY
) || (errno
!=EACCES
&& errno
!=EROFS
))
268 if (!(vfsflags
& MS_SILENT
))
269 bb_error_msg("%s is write-protected, mounting read-only",
271 vfsflags
|= MS_RDONLY
;
274 // Abort entirely if permission denied.
276 if (rc
&& errno
== EPERM
)
277 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root
);
279 /* If the mount was successful, and we're maintaining an old-style
280 * mtab file by hand, add the new entry to it now. */
282 if (ENABLE_FEATURE_MTAB_SUPPORT
&& useMtab
&& !rc
&& !(vfsflags
& MS_REMOUNT
)) {
284 FILE *mountTable
= setmntent(bb_path_mtab_file
, "a+");
288 bb_error_msg("no %s",bb_path_mtab_file
);
292 // Add vfs string flags
294 for (i
=0; mount_options
[i
].flags
!= MS_REMOUNT
; i
++)
295 if (mount_options
[i
].flags
> 0 && (mount_options
[i
].flags
& vfsflags
))
296 append_mount_options(&(mp
->mnt_opts
), mount_options
[i
].name
);
298 // Remove trailing / (if any) from directory we mounted on
300 i
= strlen(mp
->mnt_dir
) - 1;
301 if (i
> 0 && mp
->mnt_dir
[i
] == '/') mp
->mnt_dir
[i
] = 0;
303 // Convert to canonical pathnames as needed
305 mp
->mnt_dir
= bb_simplify_path(mp
->mnt_dir
);
307 if (!mp
->mnt_type
|| !*mp
->mnt_type
) { /* bind mount */
308 mp
->mnt_fsname
= fsname
= bb_simplify_path(mp
->mnt_fsname
);
309 mp
->mnt_type
= (char*)"bind";
311 mp
->mnt_freq
= mp
->mnt_passno
= 0;
315 addmntent(mountTable
, mp
);
316 endmntent(mountTable
);
317 if (ENABLE_FEATURE_CLEAN_UP
) {
326 #if ENABLE_FEATURE_MOUNT_NFS
330 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
332 * Licensed under GPLv2, see file LICENSE in this tarball for details.
334 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
335 * numbers to be specified on the command line.
337 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
338 * Omit the call to connect() for Linux version 1.3.11 or later.
340 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
341 * Implemented the "bg", "fg" and "retry" mount options for NFS.
343 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
344 * - added Native Language Support
346 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
350 /* This is just a warning of a common mistake. Possibly this should be a
351 * uclibc faq entry rather than in busybox... */
352 #if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
353 #error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
356 #define MOUNTPORT 635
357 #define MNTPATHLEN 1024
358 #define MNTNAMLEN 255
362 typedef char fhandle
[FHSIZE
];
365 unsigned int fhandle3_len
;
377 MNT3ERR_NAMETOOLONG
= 63,
378 MNT3ERR_NOTSUPP
= 10004,
379 MNT3ERR_SERVERFAULT
= 10006,
381 typedef enum mountstat3 mountstat3
;
384 unsigned int fhs_status
;
389 typedef struct fhstatus fhstatus
;
391 struct mountres3_ok
{
394 unsigned int auth_flavours_len
;
395 char *auth_flavours_val
;
398 typedef struct mountres3_ok mountres3_ok
;
401 mountstat3 fhs_status
;
403 mountres3_ok mountinfo
;
406 typedef struct mountres3 mountres3
;
408 typedef char *dirpath
;
412 typedef struct mountbody
*mountlist
;
416 dirpath ml_directory
;
419 typedef struct mountbody mountbody
;
421 typedef struct groupnode
*groups
;
427 typedef struct groupnode groupnode
;
429 typedef struct exportnode
*exports
;
436 typedef struct exportnode exportnode
;
449 typedef struct ppathcnf ppathcnf
;
451 #define MOUNTPROG 100005
454 #define MOUNTPROC_NULL 0
455 #define MOUNTPROC_MNT 1
456 #define MOUNTPROC_DUMP 2
457 #define MOUNTPROC_UMNT 3
458 #define MOUNTPROC_UMNTALL 4
459 #define MOUNTPROC_EXPORT 5
460 #define MOUNTPROC_EXPORTALL 6
462 #define MOUNTVERS_POSIX 2
464 #define MOUNTPROC_PATHCONF 7
468 #define MOUNTPROC3_NULL 0
469 #define MOUNTPROC3_MNT 1
470 #define MOUNTPROC3_DUMP 2
471 #define MOUNTPROC3_UMNT 3
472 #define MOUNTPROC3_UMNTALL 4
473 #define MOUNTPROC3_EXPORT 5
485 * We want to be able to compile mount on old kernels in such a way
486 * that the binary will work well on more recent kernels.
487 * Thus, if necessary we teach nfsmount.c the structure of new fields
488 * that will come later.
490 * Moreover, the new kernel includes conflict with glibc includes
491 * so it is easiest to ignore the kernel altogether (at compile time).
499 unsigned char data
[64];
502 struct nfs_mount_data
{
505 struct nfs2_fh old_root
; /* 1 */
511 int acregmin
; /* 1 */
512 int acregmax
; /* 1 */
513 int acdirmin
; /* 1 */
514 int acdirmax
; /* 1 */
515 struct sockaddr_in addr
; /* 1 */
516 char hostname
[256]; /* 1 */
518 unsigned int bsize
; /* 3 */
519 struct nfs3_fh root
; /* 4 */
522 /* bits in the flags field */
524 NFS_MOUNT_SOFT
= 0x0001, /* 1 */
525 NFS_MOUNT_INTR
= 0x0002, /* 1 */
526 NFS_MOUNT_SECURE
= 0x0004, /* 1 */
527 NFS_MOUNT_POSIX
= 0x0008, /* 1 */
528 NFS_MOUNT_NOCTO
= 0x0010, /* 1 */
529 NFS_MOUNT_NOAC
= 0x0020, /* 1 */
530 NFS_MOUNT_TCP
= 0x0040, /* 2 */
531 NFS_MOUNT_VER3
= 0x0080, /* 3 */
532 NFS_MOUNT_KERBEROS
= 0x0100, /* 3 */
533 NFS_MOUNT_NONLM
= 0x0200 /* 3 */
538 * We need to translate between nfs status return values and
539 * the local errno values which may not be the same.
541 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
542 * "after #include <errno.h> the symbol errno is reserved for any use,
543 * it cannot even be used as a struct tag or field name".
547 #define EDQUOT ENOSPC
550 // Convert each NFSERR_BLAH into EBLAH
552 static const struct {
556 {0,0}, {1,EPERM
}, {2,ENOENT
}, {5,EIO
}, {6,ENXIO
}, {13,EACCES
}, {17,EEXIST
},
557 {19,ENODEV
}, {20,ENOTDIR
}, {21,EISDIR
}, {22,EINVAL
}, {27,EFBIG
},
558 {28,ENOSPC
}, {30,EROFS
}, {63,ENAMETOOLONG
}, {66,ENOTEMPTY
}, {69,EDQUOT
},
559 {70,ESTALE
}, {71,EREMOTE
}, {-1,EIO
}
562 static char *nfs_strerror(int status
)
566 for (i
= 0; nfs_errtbl
[i
].stat
!= -1; i
++) {
567 if (nfs_errtbl
[i
].stat
== status
)
568 return strerror(nfs_errtbl
[i
].errnum
);
570 return xasprintf("unknown nfs status return value: %d", status
);
573 static bool_t
xdr_fhandle(XDR
*xdrs
, fhandle objp
)
575 if (!xdr_opaque(xdrs
, objp
, FHSIZE
))
580 static bool_t
xdr_fhstatus(XDR
*xdrs
, fhstatus
*objp
)
582 if (!xdr_u_int(xdrs
, &objp
->fhs_status
))
584 switch (objp
->fhs_status
) {
586 if (!xdr_fhandle(xdrs
, objp
->fhstatus_u
.fhs_fhandle
))
595 static bool_t
xdr_dirpath(XDR
*xdrs
, dirpath
*objp
)
597 if (!xdr_string(xdrs
, objp
, MNTPATHLEN
))
602 static bool_t
xdr_fhandle3(XDR
*xdrs
, fhandle3
*objp
)
604 if (!xdr_bytes(xdrs
, (char **)&objp
->fhandle3_val
, (unsigned int *) &objp
->fhandle3_len
, FHSIZE3
))
609 static bool_t
xdr_mountres3_ok(XDR
*xdrs
, mountres3_ok
*objp
)
611 if (!xdr_fhandle3(xdrs
, &objp
->fhandle
))
613 if (!xdr_array(xdrs
, &(objp
->auth_flavours
.auth_flavours_val
), &(objp
->auth_flavours
.auth_flavours_len
), ~0,
614 sizeof (int), (xdrproc_t
) xdr_int
))
619 static bool_t
xdr_mountstat3(XDR
*xdrs
, mountstat3
*objp
)
621 if (!xdr_enum(xdrs
, (enum_t
*) objp
))
626 static bool_t
xdr_mountres3(XDR
*xdrs
, mountres3
*objp
)
628 if (!xdr_mountstat3(xdrs
, &objp
->fhs_status
))
630 switch (objp
->fhs_status
) {
632 if (!xdr_mountres3_ok(xdrs
, &objp
->mountres3_u
.mountinfo
))
641 #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
643 static smalluint nfs_mount_version
;
646 * Unfortunately, the kernel prints annoying console messages
647 * in case of an unexpected nfs mount version (instead of
648 * just returning some error). Therefore we'll have to try
649 * and figure out what version the kernel expects.
652 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
653 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
654 * nfs_mount_version: version this source and running kernel can handle
657 find_kernel_nfs_mount_version(void)
661 if (nfs_mount_version
)
664 nfs_mount_version
= 4; /* default */
666 kernel_version
= get_linux_version_code();
667 if (kernel_version
) {
668 if (kernel_version
< KERNEL_VERSION(2,1,32))
669 nfs_mount_version
= 1;
670 else if (kernel_version
< KERNEL_VERSION(2,2,18) ||
671 (kernel_version
>= KERNEL_VERSION(2,3,0) &&
672 kernel_version
< KERNEL_VERSION(2,3,99)))
673 nfs_mount_version
= 3;
674 /* else v4 since 2.3.99pre4 */
679 get_mountport(struct pmap
*pm_mnt
,
680 struct sockaddr_in
*server_addr
,
682 long unsigned version
,
686 struct pmaplist
*pmap
;
688 server_addr
->sin_port
= PMAPPORT
;
689 /* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
690 * I understand it like "IPv6 for this is not 100% ready" */
691 pmap
= pmap_getmaps(server_addr
);
693 if (version
> MAX_NFSPROT
)
694 version
= MAX_NFSPROT
;
697 pm_mnt
->pm_prog
= prog
;
698 pm_mnt
->pm_vers
= version
;
699 pm_mnt
->pm_prot
= proto
;
700 pm_mnt
->pm_port
= port
;
703 if (pmap
->pml_map
.pm_prog
!= prog
)
705 if (!version
&& pm_mnt
->pm_vers
> pmap
->pml_map
.pm_vers
)
707 if (version
> 2 && pmap
->pml_map
.pm_vers
!= version
)
709 if (version
&& version
<= 2 && pmap
->pml_map
.pm_vers
> 2)
711 if (pmap
->pml_map
.pm_vers
> MAX_NFSPROT
||
712 (proto
&& pm_mnt
->pm_prot
&& pmap
->pml_map
.pm_prot
!= proto
) ||
713 (port
&& pmap
->pml_map
.pm_port
!= port
))
715 memcpy(pm_mnt
, &pmap
->pml_map
, sizeof(*pm_mnt
));
717 pmap
= pmap
->pml_next
;
719 if (!pm_mnt
->pm_vers
)
720 pm_mnt
->pm_vers
= MOUNTVERS
;
721 if (!pm_mnt
->pm_port
)
722 pm_mnt
->pm_port
= MOUNTPORT
;
723 if (!pm_mnt
->pm_prot
)
724 pm_mnt
->pm_prot
= IPPROTO_TCP
;
728 static int daemonize(void)
732 if (pid
< 0) /* error */
734 if (pid
> 0) /* parent */
737 fd
= xopen(bb_dev_null
, O_RDWR
);
741 while (fd
> 2) close(fd
--);
743 openlog(applet_name
, LOG_PID
, LOG_DAEMON
);
744 logmode
= LOGMODE_SYSLOG
;
748 static inline int daemonize(void) { return -ENOSYS
; }
752 static inline int we_saw_this_host_before(const char *hostname
)
757 /* RPC strerror analogs are terminally idiotic:
758 * *mandatory* prefix and \n at end.
759 * This hopefully helps. Usage:
760 * error_msg_rpc(clnt_*error*(" ")) */
761 static void error_msg_rpc(const char *msg
)
764 while (msg
[0] == ' ' || msg
[0] == ':') msg
++;
766 while (len
&& msg
[len
-1] == '\n') len
--;
767 bb_error_msg("%.*s", len
, msg
);
770 // NB: mp->xxx fields may be trashed on exit
771 static int nfsmount(struct mntent
*mp
, int vfsflags
, char *filteropts
)
777 struct nfs_mount_data data
;
780 struct sockaddr_in server_addr
;
781 struct sockaddr_in mount_server_addr
;
784 struct fhstatus nfsv2
;
785 struct mountres3 nfsv3
;
811 find_kernel_nfs_mount_version();
819 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
821 filteropts
= xstrdup(filteropts
); /* going to trash it later... */
823 hostname
= xstrdup(mp
->mnt_fsname
);
824 /* mount_main() guarantees that ':' is there */
825 s
= strchr(hostname
, ':');
828 /* Ignore all but first hostname in replicated mounts
829 until they can be fully supported. (mack@sgi.com) */
830 s
= strchr(hostname
, ',');
833 bb_error_msg("warning: multiple hostnames not supported");
836 server_addr
.sin_family
= AF_INET
;
837 if (!inet_aton(hostname
, &server_addr
.sin_addr
)) {
838 hp
= gethostbyname(hostname
);
840 bb_herror_msg("%s", hostname
);
843 if (hp
->h_length
> sizeof(struct in_addr
)) {
844 bb_error_msg("got bad hp->h_length");
845 hp
->h_length
= sizeof(struct in_addr
);
847 memcpy(&server_addr
.sin_addr
,
848 hp
->h_addr
, hp
->h_length
);
851 memcpy(&mount_server_addr
, &server_addr
, sizeof(mount_server_addr
));
853 /* add IP address to mtab options for use when unmounting */
855 if (!mp
->mnt_opts
) { /* TODO: actually mp->mnt_opts is never NULL */
856 mp
->mnt_opts
= xasprintf("addr=%s", inet_ntoa(server_addr
.sin_addr
));
858 char *tmp
= xasprintf("%s%saddr=%s", mp
->mnt_opts
,
859 mp
->mnt_opts
[0] ? "," : "",
860 inet_ntoa(server_addr
.sin_addr
));
865 /* Set default options.
866 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
867 * let the kernel decide.
868 * timeo is filled in after we know whether it'll be TCP or UDP. */
869 memset(&data
, 0, sizeof(data
));
875 data
.namlen
= NAME_MAX
;
883 retry
= 10000; /* 10000 minutes ~ 1 week */
886 mountprog
= MOUNTPROG
;
894 if (filteropts
) for (opt
= strtok(filteropts
, ","); opt
; opt
= strtok(NULL
, ",")) {
895 char *opteq
= strchr(opt
, '=');
897 static const char options
[] ALIGN1
=
909 /* 11 */ "mountport\0"
910 /* 12 */ "mounthost\0"
911 /* 13 */ "mountprog\0"
912 /* 14 */ "mountvers\0"
919 int val
= xatoi_u(opteq
+ 1);
921 switch (index_in_strings(options
, opt
)) {
934 case 4: // "acregmin"
937 case 5: // "acregmax"
940 case 6: // "acdirmin"
943 case 7: // "acdirmax"
958 case 11: // "mountport"
961 case 12: // "mounthost"
962 mounthost
= xstrndup(opteq
+1,
963 strcspn(opteq
+1," \t\n\r,"));
965 case 13: // "mountprog"
968 case 14: // "mountvers"
971 case 15: // "nfsprog"
974 case 16: // "nfsvers"
979 if (!strncmp(opteq
+1, "tcp", 3))
981 else if (!strncmp(opteq
+1, "udp", 3))
984 bb_error_msg("warning: unrecognized proto= option");
987 if (nfs_mount_version
>= 2)
990 bb_error_msg("warning: option namlen is not supported\n");
992 case 20: // "addr" - ignore
995 bb_error_msg("unknown nfs mount parameter: %s=%d", opt
, val
);
1000 static const char options
[] ALIGN1
=
1013 if (!strncmp(opt
, "no", 2)) {
1017 switch (index_in_strings(options
, opt
)) {
1053 if (nfs_mount_version
>= 3)
1056 bb_error_msg("warning: option nolock is not supported");
1059 bb_error_msg("unknown nfs mount option: %s%s", val
? "" : "no", opt
);
1064 proto
= (tcp
) ? IPPROTO_TCP
: IPPROTO_UDP
;
1066 data
.flags
= (soft
? NFS_MOUNT_SOFT
: 0)
1067 | (intr
? NFS_MOUNT_INTR
: 0)
1068 | (posix
? NFS_MOUNT_POSIX
: 0)
1069 | (nocto
? NFS_MOUNT_NOCTO
: 0)
1070 | (noac
? NFS_MOUNT_NOAC
: 0);
1071 if (nfs_mount_version
>= 2)
1072 data
.flags
|= (tcp
? NFS_MOUNT_TCP
: 0);
1073 if (nfs_mount_version
>= 3)
1074 data
.flags
|= (nolock
? NFS_MOUNT_NONLM
: 0);
1075 if (nfsvers
> MAX_NFSPROT
|| mountvers
> MAX_NFSPROT
) {
1076 bb_error_msg("NFSv%d not supported", nfsvers
);
1079 if (nfsvers
&& !mountvers
)
1080 mountvers
= (nfsvers
< 3) ? 1 : nfsvers
;
1081 if (nfsvers
&& nfsvers
< mountvers
) {
1082 mountvers
= nfsvers
;
1085 /* Adjust options if none specified */
1087 data
.timeo
= tcp
? 70 : 7;
1089 data
.version
= nfs_mount_version
;
1091 if (vfsflags
& MS_REMOUNT
)
1095 * If the previous mount operation on the same host was
1096 * backgrounded, and the "bg" for this mount is also set,
1097 * give up immediately, to avoid the initial timeout.
1099 if (bg
&& we_saw_this_host_before(hostname
)) {
1100 daemonized
= daemonize();
1101 if (daemonized
<= 0) { /* parent or error */
1102 retval
= -daemonized
;
1107 /* create mount daemon client */
1108 /* See if the nfs host = mount host. */
1110 if (mounthost
[0] >= '0' && mounthost
[0] <= '9') {
1111 mount_server_addr
.sin_family
= AF_INET
;
1112 mount_server_addr
.sin_addr
.s_addr
= inet_addr(hostname
);
1114 hp
= gethostbyname(mounthost
);
1116 bb_herror_msg("%s", mounthost
);
1119 if (hp
->h_length
> sizeof(struct in_addr
)) {
1120 bb_error_msg("got bad hp->h_length?");
1121 hp
->h_length
= sizeof(struct in_addr
);
1123 mount_server_addr
.sin_family
= AF_INET
;
1124 memcpy(&mount_server_addr
.sin_addr
,
1125 hp
->h_addr
, hp
->h_length
);
1131 * The following loop implements the mount retries. When the mount
1132 * times out, and the "bg" option is set, we background ourself
1133 * and continue trying.
1135 * The case where the mount point is not present and the "bg"
1136 * option is set, is treated as a timeout. This is done to
1137 * support nested mounts.
1139 * The "retry" count specified by the user is the number of
1140 * minutes to retry before giving up.
1143 struct timeval total_timeout
;
1144 struct timeval retry_timeout
;
1150 retry_timeout
.tv_sec
= 3;
1151 retry_timeout
.tv_usec
= 0;
1152 total_timeout
.tv_sec
= 20;
1153 total_timeout
.tv_usec
= 0;
1154 timeout
= time(NULL
) + 60 * retry
;
1158 /* be careful not to use too many CPU cycles */
1162 get_mountport(&pm_mnt
, &mount_server_addr
,
1167 nfsvers
= (pm_mnt
.pm_vers
< 2) ? 2 : pm_mnt
.pm_vers
;
1169 /* contact the mount daemon via TCP */
1170 mount_server_addr
.sin_port
= htons(pm_mnt
.pm_port
);
1171 msock
= RPC_ANYSOCK
;
1173 switch (pm_mnt
.pm_prot
) {
1175 mclient
= clntudp_create(&mount_server_addr
,
1182 mount_server_addr
.sin_port
= htons(pm_mnt
.pm_port
);
1183 msock
= RPC_ANYSOCK
;
1185 mclient
= clnttcp_create(&mount_server_addr
,
1194 if (!daemonized
&& prevt
== 0)
1195 error_msg_rpc(clnt_spcreateerror(" "));
1197 enum clnt_stat clnt_stat
;
1198 /* try to mount hostname:pathname */
1199 mclient
->cl_auth
= authunix_create_default();
1201 /* make pointers in xdr_mountres3 NULL so
1202 * that xdr_array allocates memory for us
1204 memset(&status
, 0, sizeof(status
));
1206 if (pm_mnt
.pm_vers
== 3)
1207 clnt_stat
= clnt_call(mclient
, MOUNTPROC3_MNT
,
1208 (xdrproc_t
) xdr_dirpath
,
1209 (caddr_t
) &pathname
,
1210 (xdrproc_t
) xdr_mountres3
,
1214 clnt_stat
= clnt_call(mclient
, MOUNTPROC_MNT
,
1215 (xdrproc_t
) xdr_dirpath
,
1216 (caddr_t
) &pathname
,
1217 (xdrproc_t
) xdr_fhstatus
,
1221 if (clnt_stat
== RPC_SUCCESS
)
1222 goto prepare_kernel_data
; /* we're done */
1223 if (errno
!= ECONNREFUSED
) {
1224 error_msg_rpc(clnt_sperror(mclient
, " "));
1225 goto fail
; /* don't retry */
1227 /* Connection refused */
1228 if (!daemonized
&& prevt
== 0) /* print just once */
1229 error_msg_rpc(clnt_sperror(mclient
, " "));
1230 auth_destroy(mclient
->cl_auth
);
1231 clnt_destroy(mclient
);
1237 /* Timeout. We are going to retry... maybe */
1242 daemonized
= daemonize();
1243 if (daemonized
<= 0) { /* parent or error */
1244 retval
= -daemonized
;
1251 /* TODO error message */
1257 prepare_kernel_data
:
1260 if (status
.nfsv2
.fhs_status
!= 0) {
1261 bb_error_msg("%s:%s failed, reason given by server: %s",
1263 nfs_strerror(status
.nfsv2
.fhs_status
));
1266 memcpy(data
.root
.data
,
1267 (char *) status
.nfsv2
.fhstatus_u
.fhs_fhandle
,
1269 data
.root
.size
= NFS_FHSIZE
;
1270 memcpy(data
.old_root
.data
,
1271 (char *) status
.nfsv2
.fhstatus_u
.fhs_fhandle
,
1274 fhandle3
*my_fhandle
;
1275 if (status
.nfsv3
.fhs_status
!= 0) {
1276 bb_error_msg("%s:%s failed, reason given by server: %s",
1278 nfs_strerror(status
.nfsv3
.fhs_status
));
1281 my_fhandle
= &status
.nfsv3
.mountres3_u
.mountinfo
.fhandle
;
1282 memset(data
.old_root
.data
, 0, NFS_FHSIZE
);
1283 memset(&data
.root
, 0, sizeof(data
.root
));
1284 data
.root
.size
= my_fhandle
->fhandle3_len
;
1285 memcpy(data
.root
.data
,
1286 (char *) my_fhandle
->fhandle3_val
,
1287 my_fhandle
->fhandle3_len
);
1289 data
.flags
|= NFS_MOUNT_VER3
;
1292 /* create nfs socket for kernel */
1295 if (nfs_mount_version
< 3) {
1296 bb_error_msg("NFS over TCP is not supported");
1299 fsock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
1301 fsock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
1303 bb_perror_msg("nfs socket");
1306 if (bindresvport(fsock
, 0) < 0) {
1307 bb_perror_msg("nfs bindresvport");
1311 server_addr
.sin_port
= PMAPPORT
;
1312 port
= pmap_getport(&server_addr
, nfsprog
, nfsvers
,
1313 tcp
? IPPROTO_TCP
: IPPROTO_UDP
);
1317 server_addr
.sin_port
= htons(port
);
1319 /* prepare data structure for kernel */
1322 memcpy((char *) &data
.addr
, (char *) &server_addr
, sizeof(data
.addr
));
1323 strncpy(data
.hostname
, hostname
, sizeof(data
.hostname
));
1327 auth_destroy(mclient
->cl_auth
);
1328 clnt_destroy(mclient
);
1333 /* We must wait until mount directory is available */
1334 struct stat statbuf
;
1336 while (stat(mp
->mnt_dir
, &statbuf
) == -1) {
1338 daemonized
= daemonize();
1339 if (daemonized
<= 0) { /* parent or error */
1340 // FIXME: parent doesn't close fsock - ??!
1341 retval
= -daemonized
;
1345 sleep(delay
); /* 1, 2, 4, 8, 16, 30, ... */
1352 do_mount
: /* perform actual mount */
1354 mp
->mnt_type
= (char*)"nfs";
1355 retval
= mount_it_now(mp
, vfsflags
, (char*)&data
);
1362 auth_destroy(mclient
->cl_auth
);
1363 clnt_destroy(mclient
);
1377 #else /* !ENABLE_FEATURE_MOUNT_NFS */
1379 /* Never called. Call should be optimized out. */
1380 int nfsmount(struct mntent
*mp
, int vfsflags
, char *filteropts
);
1382 #endif /* !ENABLE_FEATURE_MOUNT_NFS */
1384 // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1385 // type detection. Returns 0 for success, nonzero for failure.
1386 // NB: mp->xxx fields may be trashed on exit
1387 static int singlemount(struct mntent
*mp
, int ignore_busy
)
1389 int rc
= -1, vfsflags
;
1390 char *loopFile
= 0, *filteropts
= 0;
1394 vfsflags
= parse_mount_options(mp
->mnt_opts
, &filteropts
);
1396 // Treat fstype "auto" as unspecified.
1398 if (mp
->mnt_type
&& strcmp(mp
->mnt_type
,"auto") == 0)
1401 // Might this be a virtual filesystem?
1403 if (ENABLE_FEATURE_MOUNT_HELPERS
1404 && (strchr(mp
->mnt_fsname
,'#'))
1406 char *s
, *p
, *args
[35];
1408 for (s
= p
= mp
->mnt_fsname
; *s
&& n
< 35-3; ++s
) {
1409 if (s
[0] == '#' && s
[1] != '#') {
1416 args
[n
++] = mp
->mnt_dir
;
1418 rc
= wait4pid(xspawn(args
));
1422 // Might this be an CIFS filesystem?
1424 if (ENABLE_FEATURE_MOUNT_CIFS
1425 && (!mp
->mnt_type
|| strcmp(mp
->mnt_type
,"cifs") == 0)
1426 && (mp
->mnt_fsname
[0]=='/' || mp
->mnt_fsname
[0]=='\\')
1427 && mp
->mnt_fsname
[0]==mp
->mnt_fsname
[1]
1429 len_and_sockaddr
*lsa
;
1434 // Replace '/' with '\' and verify that unc points to "//server/share".
1436 for (s
= mp
->mnt_fsname
; *s
; ++s
)
1437 if (*s
== '/') *s
= '\\';
1441 s
= strrchr(mp
->mnt_fsname
, '\\');
1442 if (s
<= mp
->mnt_fsname
+1) goto report_error
;
1444 lsa
= host2sockaddr(mp
->mnt_fsname
+2, 0);
1446 if (!lsa
) goto report_error
;
1448 // insert ip=... option into string flags.
1450 dotted
= xmalloc_sockaddr2dotted_noport(&lsa
->sa
);
1451 ip
= xasprintf("ip=%s", dotted
);
1452 parse_mount_options(ip
, &filteropts
);
1454 // compose new unc '\\server-ip\share'
1455 // (s => slash after hostname)
1457 mp
->mnt_fsname
= xasprintf("\\\\%s%s", dotted
, s
);
1460 vfsflags
|= MS_MANDLOCK
;
1462 mp
->mnt_type
= (char*)"cifs";
1463 rc
= mount_it_now(mp
, vfsflags
, filteropts
);
1464 if (ENABLE_FEATURE_CLEAN_UP
) {
1465 free(mp
->mnt_fsname
);
1473 // Might this be an NFS filesystem?
1475 if (ENABLE_FEATURE_MOUNT_NFS
1476 && (!mp
->mnt_type
|| !strcmp(mp
->mnt_type
, "nfs"))
1477 && strchr(mp
->mnt_fsname
, ':') != NULL
1479 rc
= nfsmount(mp
, vfsflags
, filteropts
);
1483 // Look at the file. (Not found isn't a failure for remount, or for
1484 // a synthetic filesystem like proc or sysfs.)
1485 // (We use stat, not lstat, in order to allow
1486 // mount symlink_to_file_or_blkdev dir)
1488 if (!stat(mp
->mnt_fsname
, &st
)
1489 && !(vfsflags
& (MS_REMOUNT
| MS_BIND
| MS_MOVE
))
1491 // Do we need to allocate a loopback device for it?
1493 if (ENABLE_FEATURE_MOUNT_LOOP
&& S_ISREG(st
.st_mode
)) {
1494 loopFile
= bb_simplify_path(mp
->mnt_fsname
);
1495 mp
->mnt_fsname
= NULL
; /* will receive malloced loop dev name */
1496 if (set_loop(&(mp
->mnt_fsname
), loopFile
, 0) < 0) {
1497 if (errno
== EPERM
|| errno
== EACCES
)
1498 bb_error_msg(bb_msg_perm_denied_are_you_root
);
1500 bb_perror_msg("cannot setup loop device");
1504 // Autodetect bind mounts
1506 } else if (S_ISDIR(st
.st_mode
) && !mp
->mnt_type
)
1507 vfsflags
|= MS_BIND
;
1510 /* If we know the fstype (or don't need to), jump straight
1511 * to the actual mount. */
1513 if (mp
->mnt_type
|| (vfsflags
& (MS_REMOUNT
| MS_BIND
| MS_MOVE
)))
1514 rc
= mount_it_now(mp
, vfsflags
, filteropts
);
1516 // Loop through filesystem types until mount succeeds
1519 /* Initialize list of block backed filesystems. This has to be
1520 * done here so that during "mount -a", mounts after /proc shows up
1521 * can autodetect. */
1524 fslist
= get_block_backed_filesystems();
1525 if (ENABLE_FEATURE_CLEAN_UP
&& fslist
)
1526 atexit(delete_block_backed_filesystems
);
1529 for (fl
= fslist
; fl
; fl
= fl
->link
) {
1530 mp
->mnt_type
= fl
->data
;
1531 rc
= mount_it_now(mp
, vfsflags
, filteropts
);
1536 // If mount failed, clean up loop file (if any).
1538 if (ENABLE_FEATURE_MOUNT_LOOP
&& rc
&& loopFile
) {
1539 del_loop(mp
->mnt_fsname
);
1540 if (ENABLE_FEATURE_CLEAN_UP
) {
1542 free(mp
->mnt_fsname
);
1547 if (ENABLE_FEATURE_CLEAN_UP
)
1550 if (errno
== EBUSY
&& ignore_busy
)
1553 bb_perror_msg("mounting %s on %s failed", mp
->mnt_fsname
, mp
->mnt_dir
);
1557 // Parse options, if necessary parse fstab/mtab, and call singlemount for
1558 // each directory to be mounted.
1560 static const char must_be_root
[] ALIGN1
= "you must be root";
1562 int mount_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
1563 int mount_main(int argc
, char **argv
)
1565 enum { OPT_ALL
= 0x10 };
1567 char *cmdopts
= xstrdup(""), *fstype
=0, *storage_path
=0;
1569 const char *fstabname
;
1573 struct mntent mtpair
[2], *mtcur
= mtpair
;
1574 SKIP_DESKTOP(const int nonroot
= 0;)
1575 USE_DESKTOP( int nonroot
= (getuid() != 0);)
1577 /* parse long options, like --bind and --move. Note that -o option
1578 * and --option are synonymous. Yes, this means --remount,rw works. */
1580 for (i
= j
= 0; i
< argc
; i
++) {
1581 if (argv
[i
][0] == '-' && argv
[i
][1] == '-') {
1582 append_mount_options(&cmdopts
, argv
[i
]+2);
1583 } else argv
[j
++] = argv
[i
];
1588 // Parse remaining options
1590 opt
= getopt32(argv
, "o:t:rwanfvsi", &opt_o
, &fstype
);
1591 if (opt
& 0x1) append_mount_options(&cmdopts
, opt_o
); // -o
1592 //if (opt & 0x2) // -t
1593 if (opt
& 0x4) append_mount_options(&cmdopts
, "ro"); // -r
1594 if (opt
& 0x8) append_mount_options(&cmdopts
, "rw"); // -w
1595 //if (opt & 0x10) // -a
1596 if (opt
& 0x20) USE_FEATURE_MTAB_SUPPORT(useMtab
= 0); // -n
1597 if (opt
& 0x40) USE_FEATURE_MTAB_SUPPORT(fakeIt
= 1); // -f
1598 //if (opt & 0x80) // -v: verbose (ignore)
1599 //if (opt & 0x100) // -s: sloppy (ignore)
1600 //if (opt & 0x200) // -i: don't call mount.<fstype> (ignore)
1604 // Three or more non-option arguments? Die with a usage message.
1606 if (argc
> 2) bb_show_usage();
1608 // If we have no arguments, show currently mounted filesystems
1611 if (!(opt
& OPT_ALL
)) {
1612 FILE *mountTable
= setmntent(bb_path_mtab_file
, "r");
1614 if (!mountTable
) bb_error_msg_and_die("no %s", bb_path_mtab_file
);
1616 while (getmntent_r(mountTable
, &mtpair
[0], getmntent_buf
,
1617 sizeof(getmntent_buf
)))
1619 // Don't show rootfs. FIXME: why??
1620 // util-linux 2.12a happily shows rootfs...
1621 //if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
1623 if (!fstype
|| !strcmp(mtpair
->mnt_type
, fstype
))
1624 printf("%s on %s type %s (%s)\n", mtpair
->mnt_fsname
,
1625 mtpair
->mnt_dir
, mtpair
->mnt_type
,
1628 if (ENABLE_FEATURE_CLEAN_UP
) endmntent(mountTable
);
1629 return EXIT_SUCCESS
;
1631 } else storage_path
= bb_simplify_path(argv
[0]);
1633 // When we have two arguments, the second is the directory and we can
1634 // skip looking at fstab entirely. We can always abspath() the directory
1635 // argument when we get it.
1639 bb_error_msg_and_die(must_be_root
);
1640 mtpair
->mnt_fsname
= argv
[0];
1641 mtpair
->mnt_dir
= argv
[1];
1642 mtpair
->mnt_type
= fstype
;
1643 mtpair
->mnt_opts
= cmdopts
;
1644 rc
= singlemount(mtpair
, 0);
1648 i
= parse_mount_options(cmdopts
, 0);
1649 if (nonroot
&& (i
& ~MS_SILENT
)) // Non-root users cannot specify flags
1650 bb_error_msg_and_die(must_be_root
);
1652 // If we have a shared subtree flag, don't worry about fstab or mtab.
1654 if (ENABLE_FEATURE_MOUNT_FLAGS
1655 && (i
& (MS_SHARED
| MS_PRIVATE
| MS_SLAVE
| MS_UNBINDABLE
))
1657 rc
= mount("", argv
[0], "", i
, "");
1658 if (rc
) bb_simple_perror_msg_and_die(argv
[0]);
1662 // Open either fstab or mtab
1664 fstabname
= "/etc/fstab";
1665 if (i
& MS_REMOUNT
) {
1666 fstabname
= bb_path_mtab_file
;
1668 fstab
= setmntent(fstabname
, "r");
1670 bb_perror_msg_and_die("cannot read %s", fstabname
);
1672 // Loop through entries until we find what we're looking for.
1674 memset(mtpair
, 0, sizeof(mtpair
));
1676 struct mntent
*mtnext
= (mtcur
==mtpair
? mtpair
+1 : mtpair
);
1678 // Get next fstab entry
1680 if (!getmntent_r(fstab
, mtcur
, getmntent_buf
1681 + (mtcur
==mtpair
? sizeof(getmntent_buf
)/2 : 0),
1682 sizeof(getmntent_buf
)/2))
1684 // Were we looking for something specific?
1688 // If we didn't find anything, complain.
1690 if (!mtnext
->mnt_fsname
)
1691 bb_error_msg_and_die("can't find %s in %s",
1692 argv
[0], fstabname
);
1696 // fstab must have "users" or "user"
1697 if (!(parse_mount_options(mtcur
->mnt_opts
, 0) & MOUNT_USERS
))
1698 bb_error_msg_and_die(must_be_root
);
1701 // Mount the last thing we found.
1703 mtcur
->mnt_opts
= xstrdup(mtcur
->mnt_opts
);
1704 append_mount_options(&(mtcur
->mnt_opts
), cmdopts
);
1705 rc
= singlemount(mtcur
, 0);
1706 free(mtcur
->mnt_opts
);
1711 /* If we're trying to mount something specific and this isn't it,
1712 * skip it. Note we must match both the exact text in fstab (ala
1713 * "proc") or a full path from root */
1717 // Is this what we're looking for?
1719 if (strcmp(argv
[0], mtcur
->mnt_fsname
) &&
1720 strcmp(storage_path
, mtcur
->mnt_fsname
) &&
1721 strcmp(argv
[0], mtcur
->mnt_dir
) &&
1722 strcmp(storage_path
, mtcur
->mnt_dir
)) continue;
1724 // Remember this entry. Something later may have overmounted
1725 // it, and we want the _last_ match.
1729 // If we're mounting all.
1732 // Do we need to match a filesystem type?
1733 if (fstype
&& match_fstype(mtcur
, fstype
)) continue;
1735 // Skip noauto and swap anyway.
1737 if (parse_mount_options(mtcur
->mnt_opts
, 0)
1738 & (MOUNT_NOAUTO
| MOUNT_SWAP
)) continue;
1740 // No, mount -a won't mount anything,
1741 // even user mounts, for mere humans.
1744 bb_error_msg_and_die(must_be_root
);
1746 // Mount this thing.
1748 // NFS mounts want this to be xrealloc-able
1749 mtcur
->mnt_opts
= xstrdup(mtcur
->mnt_opts
);
1750 if (singlemount(mtcur
, 1)) {
1751 /* Count number of failed mounts */
1754 free(mtcur
->mnt_opts
);
1757 if (ENABLE_FEATURE_CLEAN_UP
) endmntent(fstab
);
1761 if (ENABLE_FEATURE_CLEAN_UP
) {