1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <mntent.h>
22#include <syslog.h>
23#include "libbb.h"
24
25#if ENABLE_FEATURE_MOUNT_LABEL
26#include "volume_id.h"
27#endif
28
29
30#include <sys/utsname.h>
31#undef TRUE
32#undef FALSE
33#include <rpc/rpc.h>
34#include <rpc/pmap_prot.h>
35#include <rpc/pmap_clnt.h>
36
37#ifndef MS_SILENT
38#define MS_SILENT (1 << 15)
39#endif
40
41#ifndef MS_DIRSYNC
42#define MS_DIRSYNC 128
43#endif
44
45
46#if defined(__dietlibc__)
47
48
49static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
50 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
51{
52 struct mntent* ment = getmntent(stream);
53 return memcpy(result, ment, sizeof(*ment));
54}
55#endif
56
57
58
59enum {
60 MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
61 MOUNT_NOAUTO = (1 << 29),
62 MOUNT_SWAP = (1 << 30),
63};
64
65
66#define OPTION_STR "o:t:rwanfvsi"
67enum {
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
94
95
96
97
98
99
100
101
102
103
104
105static const int32_t mount_options[] = {
106
107
108 USE_FEATURE_MOUNT_LOOP(
109 0,
110 )
111
112 USE_FEATURE_MOUNT_FSTAB(
113 0,
114
115 MOUNT_NOAUTO,
116 MOUNT_SWAP,
117 MOUNT_SWAP,
118 USE_DESKTOP( MOUNT_USERS,)
119 USE_DESKTOP( MOUNT_USERS,)
120 0,
121 )
122
123 USE_FEATURE_MOUNT_FLAGS(
124
125 MS_NOSUID,
126 ~MS_NOSUID,
127 ~MS_NODEV,
128 MS_NODEV,
129 ~MS_NOEXEC,
130 MS_NOEXEC,
131 MS_SYNCHRONOUS,
132 MS_DIRSYNC,
133 ~MS_SYNCHRONOUS,
134 ~MS_NOATIME,
135 MS_NOATIME,
136 ~MS_NODIRATIME,
137 MS_NODIRATIME,
138 MS_MANDLOCK,
139 ~MS_MANDLOCK,
140 MS_RELATIME,
141 ~MS_RELATIME,
142 ~MS_SILENT,
143
144
145 MS_BIND,
146 MS_MOVE,
147 MS_SHARED,
148 MS_SLAVE,
149 MS_PRIVATE,
150 MS_UNBINDABLE,
151 MS_SHARED|MS_RECURSIVE,
152 MS_SLAVE|MS_RECURSIVE,
153 MS_SLAVE|MS_RECURSIVE,
154 MS_UNBINDABLE|MS_RECURSIVE,
155 )
156
157
158 MS_RDONLY,
159 ~MS_RDONLY,
160 MS_REMOUNT
161};
162
163static const char mount_option_str[] =
164 USE_FEATURE_MOUNT_LOOP(
165 "loop" "\0"
166 )
167 USE_FEATURE_MOUNT_FSTAB(
168 "defaults" "\0"
169
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
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
198
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
212 "ro" "\0"
213 "rw" "\0"
214 "remount" "\0"
215;
216
217
218struct 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};
229enum { 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
240
241#if ENABLE_FEATURE_MOUNT_VERBOSE
242static 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
260static 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
279static void append_mount_options(char **oldopts, const char *newopts)
280{
281 if (*oldopts && **oldopts) {
282
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 && (p[len] == ',' || p[len] == '\0'))
292 goto skip;
293 p = strchr(p,',');
294 if (!p) break;
295 p++;
296 }
297 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
298 free(*oldopts);
299 *oldopts = p;
300 skip:
301 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
311
312static long parse_mount_options(char *options, char **unrecognized)
313{
314 long flags = MS_SILENT;
315
316
317 for (;;) {
318 unsigned i;
319 char *comma = strchr(options, ',');
320 const char *option_str = mount_option_str;
321
322 if (comma) *comma = '\0';
323
324
325
326 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
327 if (!strcasecmp(option_str, options)) {
328 long fl = mount_options[i];
329 if (fl < 0) flags &= fl;
330 else flags |= fl;
331 break;
332 }
333 option_str += strlen(option_str) + 1;
334 }
335
336 if (unrecognized && i == ARRAY_SIZE(mount_options)) {
337
338 i = *unrecognized ? strlen(*unrecognized) : 0;
339 *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2);
340
341
342 if (i) (*unrecognized)[i++] = ',';
343 strcpy((*unrecognized)+i, options);
344 }
345
346 if (!comma)
347 break;
348
349 *comma = ',';
350 options = ++comma;
351 }
352
353 return flags;
354}
355
356
357
358static llist_t *get_block_backed_filesystems(void)
359{
360 static const char filesystems[2][sizeof("/proc/filesystems")] = {
361 "/etc/filesystems",
362 "/proc/filesystems",
363 };
364 char *fs, *buf;
365 llist_t *list = 0;
366 int i;
367 FILE *f;
368
369 for (i = 0; i < 2; i++) {
370 f = fopen_for_read(filesystems[i]);
371 if (!f) continue;
372
373 while ((buf = xmalloc_fgetline(f)) != NULL) {
374 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
389static void delete_block_backed_filesystems(void)
390{
391 llist_free(fslist, free);
392}
393#else
394void delete_block_backed_filesystems(void);
395#endif
396
397
398
399static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
400{
401 int rc = 0;
402
403 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
411
412 for (;;) {
413 errno = 0;
414 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
415 vfsflags, filteropts);
416
417
418
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 break;
440 if (!(vfsflags & MS_SILENT))
441 bb_error_msg("%s is write-protected, mounting read-only",
442 mp->mnt_fsname);
443 vfsflags |= MS_RDONLY;
444 }
445
446
447
448 if (rc && errno == EPERM)
449 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
450
451
452
453 mtab:
454 if (useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
455 char *fsname;
456 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
457 const char *option_str = mount_option_str;
458 int i;
459
460 if (!mountTable) {
461 bb_error_msg("no %s", bb_path_mtab_file);
462 goto ret;
463 }
464
465
466
467 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
473
474
475 i = strlen(mp->mnt_dir) - 1;
476 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
477
478
479
480 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
481 fsname = 0;
482 if (!mp->mnt_type || !*mp->mnt_type) {
483 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
484 mp->mnt_type = (char*)"bind";
485 }
486 mp->mnt_freq = mp->mnt_passno = 0;
487
488
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
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
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
537typedef char fhandle[FHSIZE];
538
539typedef struct {
540 unsigned int fhandle3_len;
541 char *fhandle3_val;
542} fhandle3;
543
544enum 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};
556typedef enum mountstat3 mountstat3;
557
558struct fhstatus {
559 unsigned int fhs_status;
560 union {
561 fhandle fhs_fhandle;
562 } fhstatus_u;
563};
564typedef struct fhstatus fhstatus;
565
566struct mountres3_ok {
567 fhandle3 fhandle;
568 struct {
569 unsigned int auth_flavours_len;
570 char *auth_flavours_val;
571 } auth_flavours;
572};
573typedef struct mountres3_ok mountres3_ok;
574
575struct mountres3 {
576 mountstat3 fhs_status;
577 union {
578 mountres3_ok mountinfo;
579 } mountres3_u;
580};
581typedef struct mountres3 mountres3;
582
583typedef char *dirpath;
584
585typedef char *name;
586
587typedef struct mountbody *mountlist;
588
589struct mountbody {
590 name ml_hostname;
591 dirpath ml_directory;
592 mountlist ml_next;
593};
594typedef struct mountbody mountbody;
595
596typedef struct groupnode *groups;
597
598struct groupnode {
599 name gr_name;
600 groups gr_next;
601};
602typedef struct groupnode groupnode;
603
604typedef struct exportnode *exports;
605
606struct exportnode {
607 dirpath ex_dir;
608 groups ex_groups;
609 exports ex_next;
610};
611typedef struct exportnode exportnode;
612
613struct 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};
624typedef 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
650enum {
651#ifndef NFS_FHSIZE
652 NFS_FHSIZE = 32,
653#endif
654#ifndef NFS_PORT
655 NFS_PORT = 2049
656#endif
657};
658
659
660
661
662
663
664
665
666
667
668
669struct nfs2_fh {
670 char data[32];
671};
672struct nfs3_fh {
673 unsigned short size;
674 unsigned char data[64];
675};
676
677struct nfs_mount_data {
678 int version;
679 int fd;
680 struct nfs2_fh old_root;
681 int flags;
682 int rsize;
683 int wsize;
684 int timeo;
685 int retrans;
686 int acregmin;
687 int acregmax;
688 int acdirmin;
689 int acdirmax;
690 struct sockaddr_in addr;
691 char hostname[256];
692 int namlen;
693 unsigned int bsize;
694 struct nfs3_fh root;
695};
696
697
698enum {
699 NFS_MOUNT_SOFT = 0x0001,
700 NFS_MOUNT_INTR = 0x0002,
701 NFS_MOUNT_SECURE = 0x0004,
702 NFS_MOUNT_POSIX = 0x0008,
703 NFS_MOUNT_NOCTO = 0x0010,
704 NFS_MOUNT_NOAC = 0x0020,
705 NFS_MOUNT_TCP = 0x0040,
706 NFS_MOUNT_VER3 = 0x0080,
707 NFS_MOUNT_KERBEROS = 0x0100,
708 NFS_MOUNT_NONLM = 0x0200,
709 NFS_MOUNT_NORDIRPLUS = 0x4000
710};
711
712
713
714
715
716
717
718
719
720
721
722#ifndef EDQUOT
723#define EDQUOT ENOSPC
724#endif
725
726
727
728static const struct {
729 short stat;
730 short errnum;
731} 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
738static 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 return xasprintf("unknown nfs status return value: %d", status);
747}
748
749static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
750{
751 if (!xdr_opaque(xdrs, objp, FHSIZE))
752 return FALSE;
753 return TRUE;
754}
755
756static 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
771static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
772{
773 if (!xdr_string(xdrs, objp, MNTPATHLEN))
774 return FALSE;
775 return TRUE;
776}
777
778static 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
785static 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
795static 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
802static 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
821
822
823
824
825
826
827
828
829
830static void
831find_kernel_nfs_mount_version(void)
832{
833 int kernel_version;
834
835 if (nfs_mount_version)
836 return;
837
838 nfs_mount_version = 4;
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
849 }
850}
851
852static void
853get_mountport(struct pmap *pm_mnt,
854 struct sockaddr_in *server_addr,
855 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
864
865 pmap = pmap_getmaps(server_addr);
866
867 if (version > MAX_NFSPROT)
868 version = MAX_NFSPROT;
869 if (!prog)
870 prog = MOUNTPROG;
871 pm_mnt->pm_prog = prog;
872 pm_mnt->pm_vers = version;
873 pm_mnt->pm_prot = proto;
874 pm_mnt->pm_port = port;
875
876 while (pmap) {
877 if (pmap->pml_map.pm_prog != prog)
878 goto next;
879 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
880 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 (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
887 (port && pmap->pml_map.pm_port != port))
888 goto next;
889 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
890 next:
891 pmap = pmap->pml_next;
892 }
893 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}
900
901#if BB_MMU
902static int daemonize(void)
903{
904 int pid = fork();
905 if (pid < 0)
906 return -errno;
907 if (pid > 0)
908 return 0;
909
910 close(0);
911 xopen(bb_dev_null, O_RDWR);
912 xdup2(0, 1);
913 xdup2(0, 2);
914 setsid();
915 openlog(applet_name, LOG_PID, LOG_DAEMON);
916 logmode = LOGMODE_SYSLOG;
917 return 1;
918}
919#else
920static inline int daemonize(void) { return -ENOSYS; }
921#endif
922
923
924static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
925{
926 return 0;
927}
928
929
930
931
932
933static 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
943static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
944{
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#if BB_MMU
965 smallint bg = 0;
966#else
967 enum { bg = 0 };
968#endif
969 int retry;
970 int mountprog;
971 int mountvers;
972 int nfsprog;
973 int nfsvers;
974 int retval;
975
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
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
994
995 filteropts = xstrdup(filteropts);
996
997 hostname = xstrdup(mp->mnt_fsname);
998
999 s = strchr(hostname, ':');
1000 pathname = s + 1;
1001 *s = '\0';
1002
1003
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 if ((size_t)hp->h_length > sizeof(struct in_addr)) {
1018 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
1028
1029 if (!mp->mnt_opts) {
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
1040
1041
1042
1043 memset(&data, 0, sizeof(data));
1044 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
1051 soft = 0;
1052 intr = 0;
1053 posix = 0;
1054 nocto = 0;
1055 nolock = 0;
1056 noac = 0;
1057 nordirplus = 0;
1058 retry = 10000;
1059 tcp = 0;
1060
1061 mountprog = MOUNTPROG;
1062 mountvers = 0;
1063 port = 0;
1064 mountport = 0;
1065 nfsprog = 100003;
1066 nfsvers = 0;
1067
1068
1069 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
1070 char *opteq = strchr(opt, '=');
1071 if (opteq) {
1072 int val, idx;
1073 static const char options[] ALIGN1 =
1074 "rsize\0"
1075 "wsize\0"
1076 "timeo\0"
1077 "retrans\0"
1078 "acregmin\0"
1079 "acregmax\0"
1080 "acdirmin\0"
1081 "acdirmax\0"
1082 "actimeo\0"
1083 "retry\0"
1084 "port\0"
1085 "mountport\0"
1086 "mounthost\0"
1087 "mountprog\0"
1088 "mountvers\0"
1089 "nfsprog\0"
1090 "nfsvers\0"
1091 "vers\0"
1092 "proto\0"
1093 "namlen\0"
1094 "addr\0";
1095
1096 *opteq++ = '\0';
1097 idx = index_in_strings(options, opt);
1098 switch (idx) {
1099 case 12:
1100 mounthost = xstrndup(opteq,
1101 strcspn(opteq, " \t\n\r,"));
1102 continue;
1103 case 18:
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:
1112 continue;
1113 }
1114
1115 val = xatoi_u(opteq);
1116 switch (idx) {
1117 case 0:
1118 data.rsize = val;
1119 continue;
1120 case 1:
1121 data.wsize = val;
1122 continue;
1123 case 2:
1124 data.timeo = val;
1125 continue;
1126 case 3:
1127 data.retrans = val;
1128 continue;
1129 case 4:
1130 data.acregmin = val;
1131 continue;
1132 case 5:
1133 data.acregmax = val;
1134 continue;
1135 case 6:
1136 data.acdirmin = val;
1137 continue;
1138 case 7:
1139 data.acdirmax = val;
1140 continue;
1141 case 8:
1142 data.acregmin = val;
1143 data.acregmax = val;
1144 data.acdirmin = val;
1145 data.acdirmax = val;
1146 continue;
1147 case 9:
1148 retry = val;
1149 continue;
1150 case 10:
1151 port = val;
1152 continue;
1153 case 11:
1154 mountport = val;
1155 continue;
1156 case 13:
1157 mountprog = val;
1158 continue;
1159 case 14:
1160 mountvers = val;
1161 continue;
1162 case 15:
1163 nfsprog = val;
1164 continue;
1165 case 16:
1166 case 17:
1167 nfsvers = val;
1168 continue;
1169 case 19:
1170
1171 data.namlen = val;
1172
1173
1174 continue;
1175 default:
1176 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1177 goto fail;
1178 }
1179 }
1180 else {
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 int val = 1;
1195 if (!strncmp(opt, "no", 2)) {
1196 val = 0;
1197 opt += 2;
1198 }
1199 switch (index_in_strings(options, opt)) {
1200 case 0:
1201#if BB_MMU
1202 bg = val;
1203#endif
1204 break;
1205 case 1:
1206#if BB_MMU
1207 bg = !val;
1208#endif
1209 break;
1210 case 2:
1211 soft = val;
1212 break;
1213 case 3:
1214 soft = !val;
1215 break;
1216 case 4:
1217 intr = val;
1218 break;
1219 case 5:
1220 posix = val;
1221 break;
1222 case 6:
1223 nocto = !val;
1224 break;
1225 case 7:
1226 noac = !val;
1227 break;
1228 case 8:
1229 tcp = val;
1230 break;
1231 case 9:
1232 tcp = !val;
1233 break;
1234 case 10:
1235 if (nfs_mount_version >= 3)
1236 nolock = !val;
1237 else
1238 bb_error_msg("warning: option nolock is not supported");
1239 break;
1240 case 11:
1241 nordirplus = !val;
1242 break;
1243 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 | (noac ? NFS_MOUNT_NOAC : 0)
1256 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
1257 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
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
1282
1283
1284
1285 if (bg && we_saw_this_host_before(hostname)) {
1286 daemonized = daemonize();
1287 if (daemonized <= 0) {
1288 retval = -daemonized;
1289 goto ret;
1290 }
1291 }
1292
1293
1294
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 }
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 hp->h_addr, hp->h_length);
1312 }
1313 }
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327 {
1328 struct timeval total_timeout;
1329 struct timeval retry_timeout;
1330 struct pmap pm_mnt;
1331 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
1340 timeout = time(NULL) + 60 * retry;
1341 prevt = 0;
1342 t = 30;
1343 retry:
1344
1345 if (t - prevt < 30)
1346 sleep(30);
1347
1348 get_mountport(&pm_mnt, &mount_server_addr,
1349 mountprog,
1350 mountvers,
1351 proto,
1352 mountport);
1353 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
1354
1355
1356 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
1357 msock = RPC_ANYSOCK;
1358
1359 switch (pm_mnt.pm_prot) {
1360 case IPPROTO_UDP:
1361 mclient = clntudp_create(&mount_server_addr,
1362 pm_mnt.pm_prog,
1363 pm_mnt.pm_vers,
1364 retry_timeout,
1365 &msock);
1366 if (mclient)
1367 break;
1368 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
1369 msock = RPC_ANYSOCK;
1370 case IPPROTO_TCP:
1371 mclient = clnttcp_create(&mount_server_addr,
1372 pm_mnt.pm_prog,
1373 pm_mnt.pm_vers,
1374 &msock, 0, 0);
1375 break;
1376 default:
1377 mclient = NULL;
1378 }
1379 if (!mclient) {
1380 if (!daemonized && prevt == 0)
1381 error_msg_rpc(clnt_spcreateerror(" "));
1382 } else {
1383 enum clnt_stat clnt_stat;
1384
1385 mclient->cl_auth = authunix_create_default();
1386
1387
1388
1389
1390 memset(&status, 0, sizeof(status));
1391
1392 if (pm_mnt.pm_vers == 3)
1393 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;
1409 if (errno != ECONNREFUSED) {
1410 error_msg_rpc(clnt_sperror(mclient, " "));
1411 goto fail;
1412 }
1413
1414 if (!daemonized && prevt == 0)
1415 error_msg_rpc(clnt_sperror(mclient, " "));
1416 auth_destroy(mclient->cl_auth);
1417 clnt_destroy(mclient);
1418 mclient = NULL;
1419 close(msock);
1420 msock = -1;
1421 }
1422
1423
1424
1425 if (!bg)
1426 goto fail;
1427 if (!daemonized) {
1428 daemonized = daemonize();
1429 if (daemonized <= 0) {
1430 retval = -daemonized;
1431 goto ret;
1432 }
1433 }
1434 prevt = t;
1435 t = time(NULL);
1436 if (t >= timeout)
1437
1438 goto fail;
1439
1440 goto retry;
1441 }
1442
1443 prepare_kernel_data:
1444
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
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
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
1512
1513 auth_destroy(mclient->cl_auth);
1514 clnt_destroy(mclient);
1515 close(msock);
1516 msock = -1;
1517
1518 if (bg) {
1519
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) {
1526
1527 retval = -daemonized;
1528 goto ret;
1529 }
1530 }
1531 sleep(delay);
1532 delay *= 2;
1533 if (delay > 30)
1534 delay = 30;
1535 }
1536 }
1537
1538 do_mount:
1539
1540 mp->mnt_type = (char*)"nfs";
1541 retval = mount_it_now(mp, vfsflags, (char*)&data);
1542 goto ret;
1543
1544 fail:
1545
1546 if (msock >= 0) {
1547 if (mclient) {
1548 auth_destroy(mclient->cl_auth);
1549 clnt_destroy(mclient);
1550 }
1551 close(msock);
1552 }
1553 if (fsock >= 0)
1554 close(fsock);
1555
1556 ret:
1557 free(hostname);
1558 free(mounthost);
1559 free(filteropts);
1560 return retval;
1561}
1562
1563#else
1564
1565
1566int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
1567
1568#endif
1569
1570
1571
1572
1573static int singlemount(struct mntent *mp, int ignore_busy)
1574{
1575 int rc = -1;
1576 long vfsflags;
1577 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
1584
1585 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1586 mp->mnt_type = NULL;
1587
1588
1589
1590 if (ENABLE_FEATURE_MOUNT_HELPERS
1591 && (strchr(mp->mnt_fsname, '#'))
1592 ) {
1593 char *s, *p, *args[35];
1594 int n = 0;
1595
1596
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
1612
1613 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
1622 rc = 1;
1623
1624
1625 for (s = mp->mnt_fsname; *s; ++s)
1626 if (*s == '/') *s = '\\';
1627
1628
1629
1630 s = strrchr(mp->mnt_fsname, '\\');
1631 if (s <= mp->mnt_fsname+1) goto report_error;
1632 *s = '\0';
1633 lsa = host2sockaddr(mp->mnt_fsname+2, 0);
1634 *s = '\\';
1635 if (!lsa) goto report_error;
1636
1637
1638
1639 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1640 ip = xasprintf("ip=%s", dotted);
1641 parse_mount_options(ip, &filteropts);
1642
1643
1644
1645
1646 mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s);
1647
1648
1649 vfsflags |= MS_MANDLOCK;
1650
1651 mp->mnt_type = (char*)"cifs";
1652 rc = mount_it_now(mp, vfsflags, filteropts);
1653 if (ENABLE_FEATURE_CLEAN_UP) {
1654 free(mp->mnt_fsname);
1655 free(ip);
1656 free(dotted);
1657 free(lsa);
1658 }
1659 goto report_error;
1660 }
1661
1662
1663
1664 if (ENABLE_FEATURE_MOUNT_NFS
1665 && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))
1666 && strchr(mp->mnt_fsname, ':') != NULL
1667 ) {
1668 rc = nfsmount(mp, vfsflags, filteropts);
1669 goto report_error;
1670 }
1671
1672
1673
1674
1675
1676
1677 if (!stat(mp->mnt_fsname, &st)
1678 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1679 ) {
1680
1681
1682 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1683 loopFile = bb_simplify_path(mp->mnt_fsname);
1684 mp->mnt_fsname = NULL;
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 return errno;
1691 }
1692
1693
1694
1695 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1696 vfsflags |= MS_BIND;
1697 }
1698
1699
1700
1701
1702 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1703 rc = mount_it_now(mp, vfsflags, filteropts);
1704 else {
1705
1706
1707
1708
1709
1710
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
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 report_error:
1736 if (ENABLE_FEATURE_CLEAN_UP)
1737 free(filteropts);
1738
1739 if (errno == EBUSY && ignore_busy)
1740 return 0;
1741 if (rc < 0)
1742 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
1743 return rc;
1744}
1745
1746
1747
1748
1749static const char must_be_root[] ALIGN1 = "you must be root";
1750
1751int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1752int mount_main(int argc UNUSED_PARAM, char **argv)
1753{
1754 char *cmdopts = xstrdup("");
1755 char *fstype = NULL;
1756 char *storage_path;
1757 llist_t *lst_o = NULL;
1758 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 USE_DESKTOP(int nonroot = ) sanitize_env_if_suid();
1766
1767
1768
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 }
1775 argv[j] = NULL;
1776
1777
1778
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));
1783 if (opt & OPT_r) append_mount_options(&cmdopts, "ro");
1784 if (opt & OPT_w) append_mount_options(&cmdopts, "rw");
1785 argv += optind;
1786
1787
1788 if (!argv[0]) {
1789 if (!(opt & OPT_a)) {
1790 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1791
1792 if (!mountTable)
1793 bb_error_msg_and_die("no %s", bb_path_mtab_file);
1794
1795 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
1796 GETMNTENT_BUFSIZE))
1797 {
1798
1799
1800
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 if (ENABLE_FEATURE_CLEAN_UP)
1808 endmntent(mountTable);
1809 return EXIT_SUCCESS;
1810 }
1811 storage_path = NULL;
1812 } else {
1813
1814
1815
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]);
1830 }
1831
1832
1833
1834
1835 i = parse_mount_options(cmdopts, 0);
1836 if (nonroot && (i & ~MS_SILENT))
1837 bb_error_msg_and_die(must_be_root);
1838
1839
1840 if (ENABLE_FEATURE_MOUNT_FLAGS
1841 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1842 ) {
1843 rc = verbose_mount( "", argv[0],
1844 "", i, "");
1845 if (rc)
1846 bb_simple_perror_msg_and_die(argv[0]);
1847 return rc;
1848 }
1849
1850
1851 fstabname = "/etc/fstab";
1852 if (i & MS_REMOUNT) {
1853
1854
1855
1856 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
1863 memset(mtpair, 0, sizeof(mtpair));
1864 for (;;) {
1865 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
1866
1867
1868 if (!getmntent_r(fstab, mtcur, getmntent_buf
1869 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
1870 GETMNTENT_BUFSIZE/2)
1871 ) {
1872 mtcur = mtother;
1873 break;
1874 }
1875
1876
1877
1878
1879 if (argv[0]) {
1880
1881
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
1888
1889 mtcur = mtother;
1890
1891
1892 } else {
1893
1894 if (fstype && match_fstype(mtcur, fstype))
1895 continue;
1896
1897
1898 if (parse_mount_options(mtcur->mnt_opts, 0) & (MOUNT_NOAUTO | MOUNT_SWAP))
1899 continue;
1900
1901
1902
1903 if (nonroot)
1904 bb_error_msg_and_die(must_be_root);
1905
1906
1907 if (ENABLE_FEATURE_MOUNT_LABEL)
1908 resolve_mount_spec(&mtpair->mnt_fsname);
1909
1910
1911 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
1912 if (singlemount(mtcur, 1)) {
1913
1914 rc++;
1915 }
1916 free(mtcur->mnt_opts);
1917 }
1918 }
1919
1920
1921
1922 if (argv[0]) {
1923
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
1929 if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))
1930 bb_error_msg_and_die(must_be_root);
1931 }
1932
1933
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 if (ENABLE_FEATURE_CLEAN_UP) {
1947 free(storage_path);
1948 free(cmdopts);
1949 }
1950 return rc;
1951}
1952