1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <mntent.h>
20#include <syslog.h>
21#include <sys/mount.h>
22#ifndef MS_BIND
23# define MS_BIND (1 << 12)
24#endif
25#ifndef MS_MOVE
26# define MS_MOVE (1 << 13)
27#endif
28#ifndef MS_RECURSIVE
29# define MS_RECURSIVE (1 << 14)
30#endif
31#ifndef MS_SILENT
32# define MS_SILENT (1 << 15)
33#endif
34
35#ifndef MS_UNBINDABLE
36# define MS_UNBINDABLE (1 << 17)
37#endif
38#ifndef MS_PRIVATE
39# define MS_PRIVATE (1 << 18)
40#endif
41#ifndef MS_SLAVE
42# define MS_SLAVE (1 << 19)
43#endif
44#ifndef MS_SHARED
45# define MS_SHARED (1 << 20)
46#endif
47#ifndef MS_RELATIME
48# define MS_RELATIME (1 << 21)
49#endif
50#include "libbb.h"
51
52#if ENABLE_FEATURE_MOUNT_LABEL
53#include "volume_id.h"
54#endif
55
56
57#include <sys/utsname.h>
58#undef TRUE
59#undef FALSE
60#include <rpc/rpc.h>
61#include <rpc/pmap_prot.h>
62#include <rpc/pmap_clnt.h>
63
64#ifndef MS_SILENT
65#define MS_SILENT (1 << 15)
66#endif
67
68#ifndef MS_DIRSYNC
69#define MS_DIRSYNC 128
70#endif
71
72
73#if defined(__dietlibc__)
74
75
76static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
77 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
78{
79 struct mntent* ment = getmntent(stream);
80 return memcpy(result, ment, sizeof(*ment));
81}
82#endif
83
84
85
86enum {
87 MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
88 MOUNT_NOAUTO = (1 << 29),
89 MOUNT_SWAP = (1 << 30),
90};
91
92
93#define OPTION_STR "o:t:rwanfvsiO:"
94enum {
95 OPT_o = (1 << 0),
96 OPT_t = (1 << 1),
97 OPT_r = (1 << 2),
98 OPT_w = (1 << 3),
99 OPT_a = (1 << 4),
100 OPT_n = (1 << 5),
101 OPT_f = (1 << 6),
102 OPT_v = (1 << 7),
103 OPT_s = (1 << 8),
104 OPT_i = (1 << 9),
105 OPT_O = (1 << 10),
106};
107
108#if ENABLE_FEATURE_MTAB_SUPPORT
109#define USE_MTAB (!(option_mask32 & OPT_n))
110#else
111#define USE_MTAB 0
112#endif
113
114#if ENABLE_FEATURE_MOUNT_FAKE
115#define FAKE_IT (option_mask32 & OPT_f)
116#else
117#define FAKE_IT 0
118#endif
119
120#if ENABLE_FEATURE_MOUNT_HELPERS
121#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
122#else
123#define HELPERS_ALLOWED 0
124#endif
125
126
127
128
129
130
131
132
133
134
135
136
137
138static const int32_t mount_options[] = {
139
140
141 IF_FEATURE_MOUNT_LOOP(
142 0,
143 )
144
145 IF_FEATURE_MOUNT_FSTAB(
146 0,
147
148 MOUNT_NOAUTO,
149 MOUNT_SWAP,
150 MOUNT_SWAP,
151 IF_DESKTOP( MOUNT_USERS,)
152 IF_DESKTOP( MOUNT_USERS,)
153 0,
154 )
155
156 IF_FEATURE_MOUNT_FLAGS(
157
158 MS_NOSUID,
159 ~MS_NOSUID,
160 ~MS_NODEV,
161 MS_NODEV,
162 ~MS_NOEXEC,
163 MS_NOEXEC,
164 MS_SYNCHRONOUS,
165 MS_DIRSYNC,
166 ~MS_SYNCHRONOUS,
167 ~MS_NOATIME,
168 MS_NOATIME,
169 ~MS_NODIRATIME,
170 MS_NODIRATIME,
171 MS_MANDLOCK,
172 ~MS_MANDLOCK,
173 MS_RELATIME,
174 ~MS_RELATIME,
175 ~MS_SILENT,
176
177
178 MS_BIND,
179 MS_MOVE,
180 MS_SHARED,
181 MS_SLAVE,
182 MS_PRIVATE,
183 MS_UNBINDABLE,
184 MS_SHARED|MS_RECURSIVE,
185 MS_SLAVE|MS_RECURSIVE,
186 MS_SLAVE|MS_RECURSIVE,
187 MS_UNBINDABLE|MS_RECURSIVE,
188 )
189
190
191 MS_RDONLY,
192 ~MS_RDONLY,
193 MS_REMOUNT
194};
195
196static const char mount_option_str[] =
197 IF_FEATURE_MOUNT_LOOP(
198 "loop\0"
199 )
200 IF_FEATURE_MOUNT_FSTAB(
201 "defaults\0"
202
203 "noauto\0"
204 "sw\0"
205 "swap\0"
206 IF_DESKTOP("user\0")
207 IF_DESKTOP("users\0")
208 "_netdev\0"
209 )
210 IF_FEATURE_MOUNT_FLAGS(
211
212 "nosuid\0"
213 "suid\0"
214 "dev\0"
215 "nodev\0"
216 "exec\0"
217 "noexec\0"
218 "sync\0"
219 "dirsync\0"
220 "async\0"
221 "atime\0"
222 "noatime\0"
223 "diratime\0"
224 "nodiratime\0"
225 "mand\0"
226 "nomand\0"
227 "relatime\0"
228 "norelatime\0"
229 "loud\0"
230
231
232 "bind\0"
233 "move\0"
234 "shared\0"
235 "slave\0"
236 "private\0"
237 "unbindable\0"
238 "rshared\0"
239 "rslave\0"
240 "rprivate\0"
241 "runbindable\0"
242 )
243
244
245 "ro\0"
246 "rw\0"
247 "remount\0"
248;
249
250
251struct globals {
252#if ENABLE_FEATURE_MOUNT_NFS
253 smalluint nfs_mount_version;
254#endif
255#if ENABLE_FEATURE_MOUNT_VERBOSE
256 unsigned verbose;
257#endif
258 llist_t *fslist;
259 char getmntent_buf[1];
260
261};
262enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
263#define G (*(struct globals*)&bb_common_bufsiz1)
264#define nfs_mount_version (G.nfs_mount_version)
265#if ENABLE_FEATURE_MOUNT_VERBOSE
266#define verbose (G.verbose )
267#else
268#define verbose 0
269#endif
270#define fslist (G.fslist )
271#define getmntent_buf (G.getmntent_buf )
272
273
274#if ENABLE_FEATURE_MOUNT_VERBOSE
275static int verbose_mount(const char *source, const char *target,
276 const char *filesystemtype,
277 unsigned long mountflags, const void *data)
278{
279 int rc;
280
281 errno = 0;
282 rc = mount(source, target, filesystemtype, mountflags, data);
283 if (verbose >= 2)
284 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
285 source, target, filesystemtype,
286 mountflags, (char*)data, rc);
287 return rc;
288}
289#else
290#define verbose_mount(...) mount(__VA_ARGS__)
291#endif
292
293#if ENABLE_FEATURE_MOUNT_LABEL
294static void resolve_mount_spec(char **fsname)
295{
296 char *tmp = NULL;
297
298 if (!strncmp(*fsname, "UUID=", 5))
299 tmp = get_devname_from_uuid(*fsname + 5);
300 else if (!strncmp(*fsname, "LABEL=", 6))
301 tmp = get_devname_from_label(*fsname + 6);
302
303 if (tmp)
304 *fsname = tmp;
305}
306#else
307#define resolve_mount_spec(fsname) ((void)0)
308#endif
309
310
311static void append_mount_options(char **oldopts, const char *newopts)
312{
313 if (*oldopts && **oldopts) {
314
315 while (newopts[0]) {
316 char *p;
317 int len = strlen(newopts);
318 p = strchr(newopts, ',');
319 if (p) len = p - newopts;
320 p = *oldopts;
321 while (1) {
322 if (!strncmp(p, newopts, len)
323 && (p[len] == ',' || p[len] == '\0'))
324 goto skip;
325 p = strchr(p,',');
326 if (!p) break;
327 p++;
328 }
329 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
330 free(*oldopts);
331 *oldopts = p;
332 skip:
333 newopts += len;
334 while (newopts[0] == ',') newopts++;
335 }
336 } else {
337 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
338 *oldopts = xstrdup(newopts);
339 }
340}
341
342
343
344static long parse_mount_options(char *options, char **unrecognized)
345{
346 long flags = MS_SILENT;
347
348
349 for (;;) {
350 unsigned i;
351 char *comma = strchr(options, ',');
352 const char *option_str = mount_option_str;
353
354 if (comma) *comma = '\0';
355
356
357
358 for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
359 if (!strcasecmp(option_str, options)) {
360 long fl = mount_options[i];
361 if (fl < 0) flags &= fl;
362 else flags |= fl;
363 break;
364 }
365 option_str += strlen(option_str) + 1;
366 }
367
368 if (unrecognized && i == ARRAY_SIZE(mount_options)) {
369
370 i = *unrecognized ? strlen(*unrecognized) : 0;
371 *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2);
372
373
374 if (i) (*unrecognized)[i++] = ',';
375 strcpy((*unrecognized)+i, options);
376 }
377
378 if (!comma)
379 break;
380
381 *comma = ',';
382 options = ++comma;
383 }
384
385 return flags;
386}
387
388
389static llist_t *get_block_backed_filesystems(void)
390{
391 static const char filesystems[2][sizeof("/proc/filesystems")] = {
392 "/etc/filesystems",
393 "/proc/filesystems",
394 };
395 char *fs, *buf;
396 llist_t *list = NULL;
397 int i;
398 FILE *f;
399
400 for (i = 0; i < 2; i++) {
401 f = fopen_for_read(filesystems[i]);
402 if (!f) continue;
403
404 while ((buf = xmalloc_fgetline(f)) != NULL) {
405 if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
406 continue;
407 fs = skip_whitespace(buf);
408 if (*fs == '#' || *fs == '*' || !*fs)
409 continue;
410
411 llist_add_to_end(&list, xstrdup(fs));
412 free(buf);
413 }
414 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
415 }
416
417 return list;
418}
419
420#if ENABLE_FEATURE_CLEAN_UP
421static void delete_block_backed_filesystems(void)
422{
423 llist_free(fslist, free);
424}
425#else
426void delete_block_backed_filesystems(void);
427#endif
428
429
430
431static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
432{
433 int rc = 0;
434
435 if (FAKE_IT) {
436 if (verbose >= 2)
437 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
438 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
439 vfsflags, filteropts);
440 goto mtab;
441 }
442
443
444 for (;;) {
445 errno = 0;
446 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
447 vfsflags, filteropts);
448
449
450
451 if (HELPERS_ALLOWED && rc) {
452 char *args[8];
453 int errno_save = errno;
454 args[0] = xasprintf("mount.%s", mp->mnt_type);
455 rc = 1;
456 if (FAKE_IT)
457 args[rc++] = (char *)"-f";
458 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
459 args[rc++] = (char *)"-n";
460 args[rc++] = mp->mnt_fsname;
461 args[rc++] = mp->mnt_dir;
462 if (filteropts) {
463 args[rc++] = (char *)"-o";
464 args[rc++] = filteropts;
465 }
466 args[rc] = NULL;
467 rc = wait4pid(spawn(args));
468 free(args[0]);
469 if (!rc)
470 break;
471 errno = errno_save;
472 }
473
474 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
475 break;
476 if (!(vfsflags & MS_SILENT))
477 bb_error_msg("%s is write-protected, mounting read-only",
478 mp->mnt_fsname);
479 vfsflags |= MS_RDONLY;
480 }
481
482
483
484 if (rc && errno == EPERM)
485 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
486
487
488
489 mtab:
490 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
491 char *fsname;
492 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
493 const char *option_str = mount_option_str;
494 int i;
495
496 if (!mountTable) {
497 bb_error_msg("no %s", bb_path_mtab_file);
498 goto ret;
499 }
500
501
502
503 for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
504 if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
505 append_mount_options(&(mp->mnt_opts), option_str);
506 option_str += strlen(option_str) + 1;
507 }
508
509
510
511 i = strlen(mp->mnt_dir) - 1;
512 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
513
514
515
516 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
517 fsname = 0;
518 if (!mp->mnt_type || !*mp->mnt_type) {
519 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
520 mp->mnt_type = (char*)"bind";
521 }
522 mp->mnt_freq = mp->mnt_passno = 0;
523
524
525
526 addmntent(mountTable, mp);
527 endmntent(mountTable);
528 if (ENABLE_FEATURE_CLEAN_UP) {
529 free(mp->mnt_dir);
530 free(fsname);
531 }
532 }
533 ret:
534 return rc;
535}
536
537#if ENABLE_FEATURE_MOUNT_NFS
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
564#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
565#endif
566
567#define MOUNTPORT 635
568#define MNTPATHLEN 1024
569#define MNTNAMLEN 255
570#define FHSIZE 32
571#define FHSIZE3 64
572
573typedef char fhandle[FHSIZE];
574
575typedef struct {
576 unsigned int fhandle3_len;
577 char *fhandle3_val;
578} fhandle3;
579
580enum mountstat3 {
581 MNT_OK = 0,
582 MNT3ERR_PERM = 1,
583 MNT3ERR_NOENT = 2,
584 MNT3ERR_IO = 5,
585 MNT3ERR_ACCES = 13,
586 MNT3ERR_NOTDIR = 20,
587 MNT3ERR_INVAL = 22,
588 MNT3ERR_NAMETOOLONG = 63,
589 MNT3ERR_NOTSUPP = 10004,
590 MNT3ERR_SERVERFAULT = 10006,
591};
592typedef enum mountstat3 mountstat3;
593
594struct fhstatus {
595 unsigned int fhs_status;
596 union {
597 fhandle fhs_fhandle;
598 } fhstatus_u;
599};
600typedef struct fhstatus fhstatus;
601
602struct mountres3_ok {
603 fhandle3 fhandle;
604 struct {
605 unsigned int auth_flavours_len;
606 char *auth_flavours_val;
607 } auth_flavours;
608};
609typedef struct mountres3_ok mountres3_ok;
610
611struct mountres3 {
612 mountstat3 fhs_status;
613 union {
614 mountres3_ok mountinfo;
615 } mountres3_u;
616};
617typedef struct mountres3 mountres3;
618
619typedef char *dirpath;
620
621typedef char *name;
622
623typedef struct mountbody *mountlist;
624
625struct mountbody {
626 name ml_hostname;
627 dirpath ml_directory;
628 mountlist ml_next;
629};
630typedef struct mountbody mountbody;
631
632typedef struct groupnode *groups;
633
634struct groupnode {
635 name gr_name;
636 groups gr_next;
637};
638typedef struct groupnode groupnode;
639
640typedef struct exportnode *exports;
641
642struct exportnode {
643 dirpath ex_dir;
644 groups ex_groups;
645 exports ex_next;
646};
647typedef struct exportnode exportnode;
648
649struct ppathcnf {
650 int pc_link_max;
651 short pc_max_canon;
652 short pc_max_input;
653 short pc_name_max;
654 short pc_path_max;
655 short pc_pipe_buf;
656 uint8_t pc_vdisable;
657 char pc_xxx;
658 short pc_mask[2];
659};
660typedef struct ppathcnf ppathcnf;
661
662#define MOUNTPROG 100005
663#define MOUNTVERS 1
664
665#define MOUNTPROC_NULL 0
666#define MOUNTPROC_MNT 1
667#define MOUNTPROC_DUMP 2
668#define MOUNTPROC_UMNT 3
669#define MOUNTPROC_UMNTALL 4
670#define MOUNTPROC_EXPORT 5
671#define MOUNTPROC_EXPORTALL 6
672
673#define MOUNTVERS_POSIX 2
674
675#define MOUNTPROC_PATHCONF 7
676
677#define MOUNT_V3 3
678
679#define MOUNTPROC3_NULL 0
680#define MOUNTPROC3_MNT 1
681#define MOUNTPROC3_DUMP 2
682#define MOUNTPROC3_UMNT 3
683#define MOUNTPROC3_UMNTALL 4
684#define MOUNTPROC3_EXPORT 5
685
686enum {
687#ifndef NFS_FHSIZE
688 NFS_FHSIZE = 32,
689#endif
690#ifndef NFS_PORT
691 NFS_PORT = 2049
692#endif
693};
694
695
696
697
698
699
700
701
702
703
704
705struct nfs2_fh {
706 char data[32];
707};
708struct nfs3_fh {
709 unsigned short size;
710 unsigned char data[64];
711};
712
713struct nfs_mount_data {
714 int version;
715 int fd;
716 struct nfs2_fh old_root;
717 int flags;
718 int rsize;
719 int wsize;
720 int timeo;
721 int retrans;
722 int acregmin;
723 int acregmax;
724 int acdirmin;
725 int acdirmax;
726 struct sockaddr_in addr;
727 char hostname[256];
728 int namlen;
729 unsigned int bsize;
730 struct nfs3_fh root;
731};
732
733
734enum {
735 NFS_MOUNT_SOFT = 0x0001,
736 NFS_MOUNT_INTR = 0x0002,
737 NFS_MOUNT_SECURE = 0x0004,
738 NFS_MOUNT_POSIX = 0x0008,
739 NFS_MOUNT_NOCTO = 0x0010,
740 NFS_MOUNT_NOAC = 0x0020,
741 NFS_MOUNT_TCP = 0x0040,
742 NFS_MOUNT_VER3 = 0x0080,
743 NFS_MOUNT_KERBEROS = 0x0100,
744 NFS_MOUNT_NONLM = 0x0200,
745 NFS_MOUNT_NORDIRPLUS = 0x4000
746};
747
748
749
750
751
752
753
754
755
756
757
758#ifndef EDQUOT
759#define EDQUOT ENOSPC
760#endif
761
762
763static const struct {
764 short stat;
765 short errnum;
766} nfs_errtbl[] = {
767 {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
768 {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
769 {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
770 {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
771};
772static char *nfs_strerror(int status)
773{
774 int i;
775
776 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
777 if (nfs_errtbl[i].stat == status)
778 return strerror(nfs_errtbl[i].errnum);
779 }
780 return xasprintf("unknown nfs status return value: %d", status);
781}
782
783static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
784{
785 if (!xdr_opaque(xdrs, objp, FHSIZE))
786 return FALSE;
787 return TRUE;
788}
789
790static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
791{
792 if (!xdr_u_int(xdrs, &objp->fhs_status))
793 return FALSE;
794 switch (objp->fhs_status) {
795 case 0:
796 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
797 return FALSE;
798 break;
799 default:
800 break;
801 }
802 return TRUE;
803}
804
805static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
806{
807 if (!xdr_string(xdrs, objp, MNTPATHLEN))
808 return FALSE;
809 return TRUE;
810}
811
812static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
813{
814 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
815 return FALSE;
816 return TRUE;
817}
818
819static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
820{
821 if (!xdr_fhandle3(xdrs, &objp->fhandle))
822 return FALSE;
823 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
824 sizeof(int), (xdrproc_t) xdr_int))
825 return FALSE;
826 return TRUE;
827}
828
829static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
830{
831 if (!xdr_enum(xdrs, (enum_t *) objp))
832 return FALSE;
833 return TRUE;
834}
835
836static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
837{
838 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
839 return FALSE;
840 switch (objp->fhs_status) {
841 case MNT_OK:
842 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
843 return FALSE;
844 break;
845 default:
846 break;
847 }
848 return TRUE;
849}
850
851#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
852
853
854
855
856
857
858
859
860
861
862
863
864static void
865find_kernel_nfs_mount_version(void)
866{
867 int kernel_version;
868
869 if (nfs_mount_version)
870 return;
871
872 nfs_mount_version = 4;
873
874 kernel_version = get_linux_version_code();
875 if (kernel_version) {
876 if (kernel_version < KERNEL_VERSION(2,1,32))
877 nfs_mount_version = 1;
878 else if (kernel_version < KERNEL_VERSION(2,2,18) ||
879 (kernel_version >= KERNEL_VERSION(2,3,0) &&
880 kernel_version < KERNEL_VERSION(2,3,99)))
881 nfs_mount_version = 3;
882
883 }
884}
885
886static void
887get_mountport(struct pmap *pm_mnt,
888 struct sockaddr_in *server_addr,
889 long unsigned prog,
890 long unsigned version,
891 long unsigned proto,
892 long unsigned port)
893{
894 struct pmaplist *pmap;
895
896 server_addr->sin_port = PMAPPORT;
897
898
899 pmap = pmap_getmaps(server_addr);
900
901 if (version > MAX_NFSPROT)
902 version = MAX_NFSPROT;
903 if (!prog)
904 prog = MOUNTPROG;
905 pm_mnt->pm_prog = prog;
906 pm_mnt->pm_vers = version;
907 pm_mnt->pm_prot = proto;
908 pm_mnt->pm_port = port;
909
910 while (pmap) {
911 if (pmap->pml_map.pm_prog != prog)
912 goto next;
913 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
914 goto next;
915 if (version > 2 && pmap->pml_map.pm_vers != version)
916 goto next;
917 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
918 goto next;
919 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
920 (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
921 (port && pmap->pml_map.pm_port != port))
922 goto next;
923 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
924 next:
925 pmap = pmap->pml_next;
926 }
927 if (!pm_mnt->pm_vers)
928 pm_mnt->pm_vers = MOUNTVERS;
929 if (!pm_mnt->pm_port)
930 pm_mnt->pm_port = MOUNTPORT;
931 if (!pm_mnt->pm_prot)
932 pm_mnt->pm_prot = IPPROTO_TCP;
933}
934
935#if BB_MMU
936static int daemonize(void)
937{
938 int pid = fork();
939 if (pid < 0)
940 return -errno;
941 if (pid > 0)
942 return 0;
943
944 close(0);
945 xopen(bb_dev_null, O_RDWR);
946 xdup2(0, 1);
947 xdup2(0, 2);
948 setsid();
949 openlog(applet_name, LOG_PID, LOG_DAEMON);
950 logmode = LOGMODE_SYSLOG;
951 return 1;
952}
953#else
954static inline int daemonize(void) { return -ENOSYS; }
955#endif
956
957
958static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
959{
960 return 0;
961}
962
963
964
965
966
967static void error_msg_rpc(const char *msg)
968{
969 int len;
970 while (msg[0] == ' ' || msg[0] == ':') msg++;
971 len = strlen(msg);
972 while (len && msg[len-1] == '\n') len--;
973 bb_error_msg("%.*s", len, msg);
974}
975
976
977static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
978{
979 CLIENT *mclient;
980 char *hostname;
981 char *pathname;
982 char *mounthost;
983
984
985
986 struct nfs_mount_data data;
987 char *opt;
988 struct hostent *hp;
989 struct sockaddr_in server_addr;
990 struct sockaddr_in mount_server_addr;
991 int msock, fsock;
992 union {
993 struct fhstatus nfsv2;
994 struct mountres3 nfsv3;
995 } status;
996 int daemonized;
997 char *s;
998 int port;
999 int mountport;
1000 int proto;
1001#if BB_MMU
1002 smallint bg = 0;
1003#else
1004 enum { bg = 0 };
1005#endif
1006 int retry;
1007 int mountprog;
1008 int mountvers;
1009 int nfsprog;
1010 int nfsvers;
1011 int retval;
1012
1013 smallint tcp;
1014 smallint soft;
1015 int intr;
1016 int posix;
1017 int nocto;
1018 int noac;
1019 int nordirplus;
1020 int nolock;
1021
1022 find_kernel_nfs_mount_version();
1023
1024 daemonized = 0;
1025 mounthost = NULL;
1026 retval = ETIMEDOUT;
1027 msock = fsock = -1;
1028 mclient = NULL;
1029
1030
1031
1032 filteropts = xstrdup(filteropts);
1033
1034 hostname = xstrdup(mp->mnt_fsname);
1035
1036 s = strchr(hostname, ':');
1037 pathname = s + 1;
1038 *s = '\0';
1039
1040
1041 s = strchr(hostname, ',');
1042 if (s) {
1043 *s = '\0';
1044 bb_error_msg("warning: multiple hostnames not supported");
1045 }
1046
1047 server_addr.sin_family = AF_INET;
1048 if (!inet_aton(hostname, &server_addr.sin_addr)) {
1049 hp = gethostbyname(hostname);
1050 if (hp == NULL) {
1051 bb_herror_msg("%s", hostname);
1052 goto fail;
1053 }
1054 if ((size_t)hp->h_length > sizeof(struct in_addr)) {
1055 bb_error_msg("got bad hp->h_length");
1056 hp->h_length = sizeof(struct in_addr);
1057 }
1058 memcpy(&server_addr.sin_addr,
1059 hp->h_addr, hp->h_length);
1060 }
1061
1062 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
1063
1064
1065
1066 if (!mp->mnt_opts) {
1067 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
1068 } else {
1069 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
1070 mp->mnt_opts[0] ? "," : "",
1071 inet_ntoa(server_addr.sin_addr));
1072 free(mp->mnt_opts);
1073 mp->mnt_opts = tmp;
1074 }
1075
1076
1077
1078
1079
1080 memset(&data, 0, sizeof(data));
1081 data.retrans = 3;
1082 data.acregmin = 3;
1083 data.acregmax = 60;
1084 data.acdirmin = 30;
1085 data.acdirmax = 60;
1086 data.namlen = NAME_MAX;
1087
1088 soft = 0;
1089 intr = 0;
1090 posix = 0;
1091 nocto = 0;
1092 nolock = 0;
1093 noac = 0;
1094 nordirplus = 0;
1095 retry = 10000;
1096 tcp = 0;
1097
1098 mountprog = MOUNTPROG;
1099 mountvers = 0;
1100 port = 0;
1101 mountport = 0;
1102 nfsprog = 100003;
1103 nfsvers = 0;
1104
1105
1106 if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
1107 char *opteq = strchr(opt, '=');
1108 if (opteq) {
1109 int val, idx;
1110 static const char options[] ALIGN1 =
1111 "rsize\0"
1112 "wsize\0"
1113 "timeo\0"
1114 "retrans\0"
1115 "acregmin\0"
1116 "acregmax\0"
1117 "acdirmin\0"
1118 "acdirmax\0"
1119 "actimeo\0"
1120 "retry\0"
1121 "port\0"
1122 "mountport\0"
1123 "mounthost\0"
1124 "mountprog\0"
1125 "mountvers\0"
1126 "nfsprog\0"
1127 "nfsvers\0"
1128 "vers\0"
1129 "proto\0"
1130 "namlen\0"
1131 "addr\0";
1132
1133 *opteq++ = '\0';
1134 idx = index_in_strings(options, opt);
1135 switch (idx) {
1136 case 12:
1137 mounthost = xstrndup(opteq,
1138 strcspn(opteq, " \t\n\r,"));
1139 continue;
1140 case 18:
1141 if (!strncmp(opteq, "tcp", 3))
1142 tcp = 1;
1143 else if (!strncmp(opteq, "udp", 3))
1144 tcp = 0;
1145 else
1146 bb_error_msg("warning: unrecognized proto= option");
1147 continue;
1148 case 20:
1149 continue;
1150 }
1151
1152 val = xatoi_u(opteq);
1153 switch (idx) {
1154 case 0:
1155 data.rsize = val;
1156 continue;
1157 case 1:
1158 data.wsize = val;
1159 continue;
1160 case 2:
1161 data.timeo = val;
1162 continue;
1163 case 3:
1164 data.retrans = val;
1165 continue;
1166 case 4:
1167 data.acregmin = val;
1168 continue;
1169 case 5:
1170 data.acregmax = val;
1171 continue;
1172 case 6:
1173 data.acdirmin = val;
1174 continue;
1175 case 7:
1176 data.acdirmax = val;
1177 continue;
1178 case 8:
1179 data.acregmin = val;
1180 data.acregmax = val;
1181 data.acdirmin = val;
1182 data.acdirmax = val;
1183 continue;
1184 case 9:
1185 retry = val;
1186 continue;
1187 case 10:
1188 port = val;
1189 continue;
1190 case 11:
1191 mountport = val;
1192 continue;
1193 case 13:
1194 mountprog = val;
1195 continue;
1196 case 14:
1197 mountvers = val;
1198 continue;
1199 case 15:
1200 nfsprog = val;
1201 continue;
1202 case 16:
1203 case 17:
1204 nfsvers = val;
1205 continue;
1206 case 19:
1207
1208 data.namlen = val;
1209
1210
1211 continue;
1212 default:
1213 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1214 goto fail;
1215 }
1216 }
1217 else {
1218 static const char options[] ALIGN1 =
1219 "bg\0"
1220 "fg\0"
1221 "soft\0"
1222 "hard\0"
1223 "intr\0"
1224 "posix\0"
1225 "cto\0"
1226 "ac\0"
1227 "tcp\0"
1228 "udp\0"
1229 "lock\0"
1230 "rdirplus\0";
1231 int val = 1;
1232 if (!strncmp(opt, "no", 2)) {
1233 val = 0;
1234 opt += 2;
1235 }
1236 switch (index_in_strings(options, opt)) {
1237 case 0:
1238#if BB_MMU
1239 bg = val;
1240#endif
1241 break;
1242 case 1:
1243#if BB_MMU
1244 bg = !val;
1245#endif
1246 break;
1247 case 2:
1248 soft = val;
1249 break;
1250 case 3:
1251 soft = !val;
1252 break;
1253 case 4:
1254 intr = val;
1255 break;
1256 case 5:
1257 posix = val;
1258 break;
1259 case 6:
1260 nocto = !val;
1261 break;
1262 case 7:
1263 noac = !val;
1264 break;
1265 case 8:
1266 tcp = val;
1267 break;
1268 case 9:
1269 tcp = !val;
1270 break;
1271 case 10:
1272 if (nfs_mount_version >= 3)
1273 nolock = !val;
1274 else
1275 bb_error_msg("warning: option nolock is not supported");
1276 break;
1277 case 11:
1278 nordirplus = !val;
1279 break;
1280 default:
1281 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1282 goto fail;
1283 }
1284 }
1285 }
1286 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1287
1288 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1289 | (intr ? NFS_MOUNT_INTR : 0)
1290 | (posix ? NFS_MOUNT_POSIX : 0)
1291 | (nocto ? NFS_MOUNT_NOCTO : 0)
1292 | (noac ? NFS_MOUNT_NOAC : 0)
1293 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
1294 if (nfs_mount_version >= 2)
1295 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1296 if (nfs_mount_version >= 3)
1297 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1298 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1299 bb_error_msg("NFSv%d not supported", nfsvers);
1300 goto fail;
1301 }
1302 if (nfsvers && !mountvers)
1303 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1304 if (nfsvers && nfsvers < mountvers) {
1305 mountvers = nfsvers;
1306 }
1307
1308
1309 if (!data.timeo)
1310 data.timeo = tcp ? 70 : 7;
1311
1312 data.version = nfs_mount_version;
1313
1314 if (vfsflags & MS_REMOUNT)
1315 goto do_mount;
1316
1317
1318
1319
1320
1321
1322 if (bg && we_saw_this_host_before(hostname)) {
1323 daemonized = daemonize();
1324 if (daemonized <= 0) {
1325 retval = -daemonized;
1326 goto ret;
1327 }
1328 }
1329
1330
1331
1332 if (mounthost) {
1333 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1334 mount_server_addr.sin_family = AF_INET;
1335 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1336 } else {
1337 hp = gethostbyname(mounthost);
1338 if (hp == NULL) {
1339 bb_herror_msg("%s", mounthost);
1340 goto fail;
1341 }
1342 if ((size_t)hp->h_length > sizeof(struct in_addr)) {
1343 bb_error_msg("got bad hp->h_length");
1344 hp->h_length = sizeof(struct in_addr);
1345 }
1346 mount_server_addr.sin_family = AF_INET;
1347 memcpy(&mount_server_addr.sin_addr,
1348 hp->h_addr, hp->h_length);
1349 }
1350 }
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364 {
1365 struct timeval total_timeout;
1366 struct timeval retry_timeout;
1367 struct pmap pm_mnt;
1368 time_t t;
1369 time_t prevt;
1370 time_t timeout;
1371
1372 retry_timeout.tv_sec = 3;
1373 retry_timeout.tv_usec = 0;
1374 total_timeout.tv_sec = 20;
1375 total_timeout.tv_usec = 0;
1376
1377 timeout = time(NULL) + 60 * retry;
1378 prevt = 0;
1379 t = 30;
1380 retry:
1381
1382 if (t - prevt < 30)
1383 sleep(30);
1384
1385 get_mountport(&pm_mnt, &mount_server_addr,
1386 mountprog,
1387 mountvers,
1388 proto,
1389 mountport);
1390 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
1391
1392
1393 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
1394 msock = RPC_ANYSOCK;
1395
1396 switch (pm_mnt.pm_prot) {
1397 case IPPROTO_UDP:
1398 mclient = clntudp_create(&mount_server_addr,
1399 pm_mnt.pm_prog,
1400 pm_mnt.pm_vers,
1401 retry_timeout,
1402 &msock);
1403 if (mclient)
1404 break;
1405 mount_server_addr.sin_port = htons(pm_mnt.pm_port);
1406 msock = RPC_ANYSOCK;
1407 case IPPROTO_TCP:
1408 mclient = clnttcp_create(&mount_server_addr,
1409 pm_mnt.pm_prog,
1410 pm_mnt.pm_vers,
1411 &msock, 0, 0);
1412 break;
1413 default:
1414 mclient = NULL;
1415 }
1416 if (!mclient) {
1417 if (!daemonized && prevt == 0)
1418 error_msg_rpc(clnt_spcreateerror(" "));
1419 } else {
1420 enum clnt_stat clnt_stat;
1421
1422
1423 mclient->cl_auth = authunix_create_default();
1424
1425
1426
1427
1428 memset(&status, 0, sizeof(status));
1429
1430 if (pm_mnt.pm_vers == 3)
1431 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1432 (xdrproc_t) xdr_dirpath,
1433 (caddr_t) &pathname,
1434 (xdrproc_t) xdr_mountres3,
1435 (caddr_t) &status,
1436 total_timeout);
1437 else
1438 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1439 (xdrproc_t) xdr_dirpath,
1440 (caddr_t) &pathname,
1441 (xdrproc_t) xdr_fhstatus,
1442 (caddr_t) &status,
1443 total_timeout);
1444
1445 if (clnt_stat == RPC_SUCCESS)
1446 goto prepare_kernel_data;
1447 if (errno != ECONNREFUSED) {
1448 error_msg_rpc(clnt_sperror(mclient, " "));
1449 goto fail;
1450 }
1451
1452 if (!daemonized && prevt == 0)
1453 error_msg_rpc(clnt_sperror(mclient, " "));
1454 auth_destroy(mclient->cl_auth);
1455 clnt_destroy(mclient);
1456 mclient = NULL;
1457 close(msock);
1458 msock = -1;
1459 }
1460
1461
1462 if (!bg)
1463 goto fail;
1464 if (!daemonized) {
1465 daemonized = daemonize();
1466 if (daemonized <= 0) {
1467 retval = -daemonized;
1468 goto ret;
1469 }
1470 }
1471 prevt = t;
1472 t = time(NULL);
1473 if (t >= timeout)
1474
1475 goto fail;
1476
1477 goto retry;
1478 }
1479
1480 prepare_kernel_data:
1481
1482 if (nfsvers == 2) {
1483 if (status.nfsv2.fhs_status != 0) {
1484 bb_error_msg("%s:%s failed, reason given by server: %s",
1485 hostname, pathname,
1486 nfs_strerror(status.nfsv2.fhs_status));
1487 goto fail;
1488 }
1489 memcpy(data.root.data,
1490 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1491 NFS_FHSIZE);
1492 data.root.size = NFS_FHSIZE;
1493 memcpy(data.old_root.data,
1494 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1495 NFS_FHSIZE);
1496 } else {
1497 fhandle3 *my_fhandle;
1498 if (status.nfsv3.fhs_status != 0) {
1499 bb_error_msg("%s:%s failed, reason given by server: %s",
1500 hostname, pathname,
1501 nfs_strerror(status.nfsv3.fhs_status));
1502 goto fail;
1503 }
1504 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1505 memset(data.old_root.data, 0, NFS_FHSIZE);
1506 memset(&data.root, 0, sizeof(data.root));
1507 data.root.size = my_fhandle->fhandle3_len;
1508 memcpy(data.root.data,
1509 (char *) my_fhandle->fhandle3_val,
1510 my_fhandle->fhandle3_len);
1511
1512 data.flags |= NFS_MOUNT_VER3;
1513 }
1514
1515
1516 if (tcp) {
1517 if (nfs_mount_version < 3) {
1518 bb_error_msg("NFS over TCP is not supported");
1519 goto fail;
1520 }
1521 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1522 } else
1523 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1524 if (fsock < 0) {
1525 bb_perror_msg("nfs socket");
1526 goto fail;
1527 }
1528 if (bindresvport(fsock, 0) < 0) {
1529 bb_perror_msg("nfs bindresvport");
1530 goto fail;
1531 }
1532 if (port == 0) {
1533 server_addr.sin_port = PMAPPORT;
1534 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1535 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1536 if (port == 0)
1537 port = NFS_PORT;
1538 }
1539 server_addr.sin_port = htons(port);
1540
1541
1542 data.fd = fsock;
1543 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1544 strncpy(data.hostname, hostname, sizeof(data.hostname));
1545
1546
1547 auth_destroy(mclient->cl_auth);
1548 clnt_destroy(mclient);
1549 close(msock);
1550 msock = -1;
1551
1552 if (bg) {
1553
1554 struct stat statbuf;
1555 int delay = 1;
1556 while (stat(mp->mnt_dir, &statbuf) == -1) {
1557 if (!daemonized) {
1558 daemonized = daemonize();
1559 if (daemonized <= 0) {
1560
1561 retval = -daemonized;
1562 goto ret;
1563 }
1564 }
1565 sleep(delay);
1566 delay *= 2;
1567 if (delay > 30)
1568 delay = 30;
1569 }
1570 }
1571
1572
1573 do_mount:
1574 mp->mnt_type = (char*)"nfs";
1575 retval = mount_it_now(mp, vfsflags, (char*)&data);
1576 goto ret;
1577
1578
1579 fail:
1580 if (msock >= 0) {
1581 if (mclient) {
1582 auth_destroy(mclient->cl_auth);
1583 clnt_destroy(mclient);
1584 }
1585 close(msock);
1586 }
1587 if (fsock >= 0)
1588 close(fsock);
1589
1590 ret:
1591 free(hostname);
1592 free(mounthost);
1593 free(filteropts);
1594 return retval;
1595}
1596
1597#else
1598
1599
1600int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
1601
1602#endif
1603
1604
1605
1606
1607static int singlemount(struct mntent *mp, int ignore_busy)
1608{
1609 int rc = -1;
1610 long vfsflags;
1611 char *loopFile = NULL, *filteropts = NULL;
1612 llist_t *fl = NULL;
1613 struct stat st;
1614
1615 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1616
1617
1618 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1619 mp->mnt_type = NULL;
1620
1621
1622 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1623 char *args[35];
1624 char *s;
1625 int n;
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635 s = mp->mnt_fsname;
1636 n = 0;
1637 args[n++] = s;
1638 while (*s && n < 35 - 2) {
1639 if (*s++ == '#' && *s != '#') {
1640 s[-1] = '\0';
1641 args[n++] = s;
1642 }
1643 }
1644 args[n++] = mp->mnt_dir;
1645 args[n] = NULL;
1646 rc = wait4pid(xspawn(args));
1647 goto report_error;
1648 }
1649
1650
1651 if (ENABLE_FEATURE_MOUNT_CIFS
1652 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1653 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1654 && mp->mnt_fsname[0] == mp->mnt_fsname[1]
1655 ) {
1656#if 0
1657 len_and_sockaddr *lsa;
1658 char *ip, *dotted;
1659 char *s;
1660
1661
1662 for (s = mp->mnt_fsname; *s; ++s)
1663 if (*s == '/') *s = '\\';
1664
1665
1666 s = strrchr(mp->mnt_fsname, '\\');
1667 if (s <= mp->mnt_fsname+1)
1668 goto report_error;
1669 *s = '\0';
1670 lsa = host2sockaddr(mp->mnt_fsname+2, 0);
1671 *s = '\\';
1672 if (!lsa)
1673 goto report_error;
1674
1675
1676 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1677 ip = xasprintf("ip=%s", dotted);
1678 parse_mount_options(ip, &filteropts);
1679
1680
1681
1682 mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s);
1683#endif
1684
1685 vfsflags |= MS_MANDLOCK;
1686 mp->mnt_type = (char*)"cifs";
1687 rc = mount_it_now(mp, vfsflags, filteropts);
1688#if 0
1689 if (ENABLE_FEATURE_CLEAN_UP) {
1690 free(mp->mnt_fsname);
1691 free(ip);
1692 free(dotted);
1693 free(lsa);
1694 }
1695#endif
1696 goto report_error;
1697 }
1698
1699
1700 if (ENABLE_FEATURE_MOUNT_NFS
1701 && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))
1702 && strchr(mp->mnt_fsname, ':') != NULL
1703 ) {
1704 rc = nfsmount(mp, vfsflags, filteropts);
1705 goto report_error;
1706 }
1707
1708
1709
1710
1711
1712 if (!stat(mp->mnt_fsname, &st)
1713 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1714 ) {
1715
1716 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1717 loopFile = bb_simplify_path(mp->mnt_fsname);
1718 mp->mnt_fsname = NULL;
1719 if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) {
1720 if (errno == EPERM || errno == EACCES)
1721 bb_error_msg(bb_msg_perm_denied_are_you_root);
1722 else
1723 bb_perror_msg("cannot setup loop device");
1724 return errno;
1725 }
1726
1727
1728 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1729 vfsflags |= MS_BIND;
1730 }
1731
1732
1733
1734 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1735 rc = mount_it_now(mp, vfsflags, filteropts);
1736 else {
1737
1738
1739
1740
1741
1742
1743 if (!fslist) {
1744 fslist = get_block_backed_filesystems();
1745 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1746 atexit(delete_block_backed_filesystems);
1747 }
1748
1749 for (fl = fslist; fl; fl = fl->link) {
1750 mp->mnt_type = fl->data;
1751 rc = mount_it_now(mp, vfsflags, filteropts);
1752 if (!rc)
1753 break;
1754 }
1755 }
1756
1757
1758 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1759 del_loop(mp->mnt_fsname);
1760 if (ENABLE_FEATURE_CLEAN_UP) {
1761 free(loopFile);
1762 free(mp->mnt_fsname);
1763 }
1764 }
1765
1766 report_error:
1767 if (ENABLE_FEATURE_CLEAN_UP)
1768 free(filteropts);
1769
1770 if (errno == EBUSY && ignore_busy)
1771 return 0;
1772 if (rc < 0)
1773 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
1774 return rc;
1775}
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787static int match_opt(const char *fs_opt, const char *O_opt)
1788{
1789 int match = 1;
1790 int len;
1791
1792 if (!O_opt)
1793 return match;
1794
1795 if (O_opt[0] == 'n' && O_opt[1] == 'o') {
1796 match--;
1797 O_opt += 2;
1798 }
1799
1800 len = strlen(O_opt);
1801 while (1) {
1802 if (strncmp(fs_opt, O_opt, len) == 0
1803 && (fs_opt[len] == '\0' || fs_opt[len] == ',')
1804 ) {
1805 return match;
1806 }
1807 fs_opt = strchr(fs_opt, ',');
1808 if (!fs_opt)
1809 break;
1810 fs_opt++;
1811 }
1812
1813 return !match;
1814}
1815
1816
1817
1818static const char must_be_root[] ALIGN1 = "you must be root";
1819
1820int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1821int mount_main(int argc UNUSED_PARAM, char **argv)
1822{
1823 char *cmdopts = xzalloc(1);
1824 char *fstype = NULL;
1825 char *O_optmatch = NULL;
1826 char *storage_path;
1827 llist_t *lst_o = NULL;
1828 const char *fstabname;
1829 FILE *fstab;
1830 int i, j, rc = 0;
1831 unsigned opt;
1832 struct mntent mtpair[2], *mtcur = mtpair;
1833 IF_NOT_DESKTOP(const int nonroot = 0;)
1834
1835 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
1836
1837
1838
1839 for (i = j = 1; argv[i]; i++) {
1840 if (argv[i][0] == '-' && argv[i][1] == '-')
1841 append_mount_options(&cmdopts, argv[i] + 2);
1842 else
1843 argv[j++] = argv[i];
1844 }
1845 argv[j] = NULL;
1846
1847
1848
1849 opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
1850 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
1851 IF_FEATURE_MOUNT_VERBOSE(, &verbose));
1852 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o));
1853 if (opt & OPT_r) append_mount_options(&cmdopts, "ro");
1854 if (opt & OPT_w) append_mount_options(&cmdopts, "rw");
1855 argv += optind;
1856
1857
1858 if (!argv[0]) {
1859 if (!(opt & OPT_a)) {
1860 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1861
1862 if (!mountTable)
1863 bb_error_msg_and_die("no %s", bb_path_mtab_file);
1864
1865 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
1866 GETMNTENT_BUFSIZE))
1867 {
1868
1869
1870
1871
1872 if (!fstype || !strcmp(mtpair->mnt_type, fstype))
1873 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1874 mtpair->mnt_dir, mtpair->mnt_type,
1875 mtpair->mnt_opts);
1876 }
1877 if (ENABLE_FEATURE_CLEAN_UP)
1878 endmntent(mountTable);
1879 return EXIT_SUCCESS;
1880 }
1881 storage_path = NULL;
1882 } else {
1883
1884
1885
1886 if (argv[1]) {
1887 if (nonroot)
1888 bb_error_msg_and_die(must_be_root);
1889 mtpair->mnt_fsname = argv[0];
1890 mtpair->mnt_dir = argv[1];
1891 mtpair->mnt_type = fstype;
1892 mtpair->mnt_opts = cmdopts;
1893 resolve_mount_spec(&mtpair->mnt_fsname);
1894 rc = singlemount(mtpair, 0);
1895 return rc;
1896 }
1897 storage_path = bb_simplify_path(argv[0]);
1898 }
1899
1900
1901
1902
1903 i = parse_mount_options(cmdopts, NULL);
1904 if (nonroot && (i & ~MS_SILENT))
1905 bb_error_msg_and_die(must_be_root);
1906
1907
1908 if (ENABLE_FEATURE_MOUNT_FLAGS
1909 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1910 ) {
1911
1912 rc = verbose_mount("", argv[0], "", i, "");
1913 if (rc)
1914 bb_simple_perror_msg_and_die(argv[0]);
1915 return rc;
1916 }
1917
1918
1919 fstabname = "/etc/fstab";
1920 if (i & MS_REMOUNT) {
1921
1922
1923
1924 fstabname = bb_path_mtab_file;
1925 }
1926 fstab = setmntent(fstabname, "r");
1927 if (!fstab)
1928 bb_perror_msg_and_die("cannot read %s", fstabname);
1929
1930
1931 memset(mtpair, 0, sizeof(mtpair));
1932 for (;;) {
1933 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
1934
1935
1936 if (!getmntent_r(fstab, mtcur, getmntent_buf
1937 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
1938 GETMNTENT_BUFSIZE/2)
1939 ) {
1940 mtcur = mtother;
1941 break;
1942 }
1943
1944
1945
1946
1947 if (argv[0]) {
1948
1949
1950 if (strcmp(argv[0], mtcur->mnt_fsname) &&
1951 strcmp(storage_path, mtcur->mnt_fsname) &&
1952 strcmp(argv[0], mtcur->mnt_dir) &&
1953 strcmp(storage_path, mtcur->mnt_dir)) continue;
1954
1955
1956
1957 mtcur = mtother;
1958
1959
1960 } else {
1961 struct mntent *mp;
1962
1963
1964 if (nonroot)
1965 bb_error_msg_and_die(must_be_root);
1966
1967
1968 if (!match_fstype(mtcur, fstype))
1969 continue;
1970
1971
1972 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
1973
1974 || strcasecmp(mtcur->mnt_type, "swap") == 0
1975 ) {
1976 continue;
1977 }
1978
1979
1980
1981 if (!match_opt(mtcur->mnt_opts, O_optmatch))
1982 continue;
1983
1984 resolve_mount_spec(&mtcur->mnt_fsname);
1985
1986
1987 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
1988
1989
1990
1991 mp = find_mount_point(mtcur->mnt_dir, 0);
1992
1993
1994
1995 if (mp) {
1996 if (verbose) {
1997 bb_error_msg("according to %s, "
1998 "%s is already mounted on %s",
1999 bb_path_mtab_file,
2000 mp->mnt_fsname, mp->mnt_dir);
2001 }
2002 } else {
2003
2004 if (singlemount(mtcur, 1)) {
2005
2006 rc++;
2007 }
2008 }
2009 free(mtcur->mnt_opts);
2010 }
2011 }
2012
2013
2014
2015 if (argv[0]) {
2016 long l;
2017
2018
2019 if (!mtcur->mnt_fsname)
2020 bb_error_msg_and_die("can't find %s in %s",
2021 argv[0], fstabname);
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031#if 0
2032
2033 l = parse_mount_options(mtcur->mnt_opts, NULL);
2034 if ((l & MOUNT_SWAP)
2035
2036 || strcasecmp(mtcur->mnt_type, "swap") == 0
2037 ) {
2038 goto ret;
2039 }
2040#endif
2041 if (nonroot) {
2042
2043 l = parse_mount_options(mtcur->mnt_opts, NULL);
2044 if (!(l & MOUNT_USERS))
2045 bb_error_msg_and_die(must_be_root);
2046 }
2047
2048
2049 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2050 append_mount_options(&(mtcur->mnt_opts), cmdopts);
2051 resolve_mount_spec(&mtpair->mnt_fsname);
2052 rc = singlemount(mtcur, 0);
2053 if (ENABLE_FEATURE_CLEAN_UP)
2054 free(mtcur->mnt_opts);
2055 }
2056
2057
2058 if (ENABLE_FEATURE_CLEAN_UP)
2059 endmntent(fstab);
2060 if (ENABLE_FEATURE_CLEAN_UP) {
2061 free(storage_path);
2062 free(cmdopts);
2063 }
2064 return rc;
2065}
2066