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