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