Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/main.c
Parent Directory | Revision Log
Revision 815 -
(show annotations)
(download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 5692 byte(s)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 5692 byte(s)
-updated to klibc-1.5.15
1 | #include <errno.h> |
2 | #include <sys/types.h> |
3 | #include <sys/stat.h> |
4 | #include <arpa/inet.h> |
5 | #include <limits.h> |
6 | #include <stdio.h> |
7 | #include <stdlib.h> |
8 | #include <string.h> |
9 | #include <signal.h> |
10 | #include <setjmp.h> |
11 | #include <sys/wait.h> |
12 | #include <unistd.h> |
13 | #include <klibc/sysconfig.h> /* For _KLIBC_NO_MMU */ |
14 | |
15 | #include <linux/nfs_mount.h> |
16 | |
17 | #include "nfsmount.h" |
18 | #include "sunrpc.h" |
19 | #include "dummypmap.h" |
20 | |
21 | const char *progname; |
22 | static jmp_buf abort_buf; |
23 | |
24 | static struct nfs_mount_data mount_data = { |
25 | .version = NFS_MOUNT_VERSION, |
26 | .flags = NFS_MOUNT_NONLM | NFS_MOUNT_VER3 | NFS_MOUNT_TCP, |
27 | .rsize = 0, /* Server's choice */ |
28 | .wsize = 0, /* Server's choice */ |
29 | .timeo = 7, |
30 | .retrans = 3, |
31 | .acregmin = 3, |
32 | .acregmax = 60, |
33 | .acdirmin = 30, |
34 | .acdirmax = 60, |
35 | .namlen = NAME_MAX, |
36 | }; |
37 | |
38 | int nfs_port; |
39 | |
40 | static struct int_opts { |
41 | char *name; |
42 | int *val; |
43 | } int_opts[] = { |
44 | {"port", &nfs_port}, |
45 | {"rsize", &mount_data.rsize}, |
46 | {"wsize", &mount_data.wsize}, |
47 | {"timeo", &mount_data.timeo}, |
48 | {"retrans", &mount_data.retrans}, |
49 | {"acregmin", &mount_data.acregmin}, |
50 | {"acregmax", &mount_data.acregmax}, |
51 | {"acdirmin", &mount_data.acdirmin}, |
52 | {"acdirmax", &mount_data.acdirmax}, |
53 | {NULL, NULL} |
54 | }; |
55 | |
56 | static struct bool_opts { |
57 | char *name; |
58 | int and_mask; |
59 | int or_mask; |
60 | } bool_opts[] = { |
61 | {"soft", ~NFS_MOUNT_SOFT, NFS_MOUNT_SOFT}, |
62 | {"hard", ~NFS_MOUNT_SOFT, 0}, |
63 | {"intr", ~NFS_MOUNT_INTR, NFS_MOUNT_INTR}, |
64 | {"nointr", ~NFS_MOUNT_INTR, 0}, |
65 | {"posix", ~NFS_MOUNT_POSIX, NFS_MOUNT_POSIX}, |
66 | {"noposix", ~NFS_MOUNT_POSIX, 0}, |
67 | {"cto", ~NFS_MOUNT_NOCTO, 0}, |
68 | {"nocto", ~NFS_MOUNT_NOCTO, NFS_MOUNT_NOCTO}, |
69 | {"ac", ~NFS_MOUNT_NOAC, 0}, |
70 | {"noac", ~NFS_MOUNT_NOAC, NFS_MOUNT_NOAC}, |
71 | {"lock", ~NFS_MOUNT_NONLM, 0}, |
72 | {"nolock", ~NFS_MOUNT_NONLM, NFS_MOUNT_NONLM}, |
73 | {"acl", ~NFS_MOUNT_NOACL, 0}, |
74 | {"noacl", ~NFS_MOUNT_NOACL, NFS_MOUNT_NOACL}, |
75 | {"v2", ~NFS_MOUNT_VER3, 0}, |
76 | {"v3", ~NFS_MOUNT_VER3, NFS_MOUNT_VER3}, |
77 | {"udp", ~NFS_MOUNT_TCP, 0}, |
78 | {"tcp", ~NFS_MOUNT_TCP, NFS_MOUNT_TCP}, |
79 | {"broken_suid", ~NFS_MOUNT_BROKEN_SUID, NFS_MOUNT_BROKEN_SUID}, |
80 | {"ro", ~NFS_MOUNT_KLIBC_RONLY, NFS_MOUNT_KLIBC_RONLY}, |
81 | {"rw", ~NFS_MOUNT_KLIBC_RONLY, 0}, |
82 | {NULL, 0, 0} |
83 | }; |
84 | |
85 | static int parse_int(const char *val, const char *ctx) |
86 | { |
87 | char *end; |
88 | int ret; |
89 | |
90 | ret = (int)strtoul(val, &end, 0); |
91 | if (*val == '\0' || *end != '\0') { |
92 | fprintf(stderr, "%s: invalid value for %s\n", val, ctx); |
93 | longjmp(abort_buf, 1); |
94 | } |
95 | return ret; |
96 | } |
97 | |
98 | static void parse_opts(char *opts) |
99 | { |
100 | char *cp, *val; |
101 | |
102 | while ((cp = strsep(&opts, ",")) != NULL) { |
103 | if (*cp == '\0') |
104 | continue; |
105 | if ((val = strchr(cp, '=')) != NULL) { |
106 | struct int_opts *opts = int_opts; |
107 | *val++ = '\0'; |
108 | while (opts->name && strcmp(opts->name, cp) != 0) |
109 | opts++; |
110 | if (opts->name) |
111 | *(opts->val) = parse_int(val, opts->name); |
112 | else { |
113 | fprintf(stderr, "%s: bad option '%s'\n", |
114 | progname, cp); |
115 | longjmp(abort_buf, 1); |
116 | } |
117 | } else { |
118 | struct bool_opts *opts = bool_opts; |
119 | while (opts->name && strcmp(opts->name, cp) != 0) |
120 | opts++; |
121 | if (opts->name) { |
122 | mount_data.flags &= opts->and_mask; |
123 | mount_data.flags |= opts->or_mask; |
124 | } else { |
125 | fprintf(stderr, "%s: bad option '%s'\n", |
126 | progname, cp); |
127 | longjmp(abort_buf, 1); |
128 | } |
129 | } |
130 | } |
131 | } |
132 | |
133 | static uint32_t parse_addr(const char *ip) |
134 | { |
135 | struct in_addr in; |
136 | if (inet_aton(ip, &in) == 0) { |
137 | fprintf(stderr, "%s: can't parse IP address '%s'\n", |
138 | progname, ip); |
139 | longjmp(abort_buf, 1); |
140 | } |
141 | return in.s_addr; |
142 | } |
143 | |
144 | static void check_path(const char *path) |
145 | { |
146 | struct stat st; |
147 | |
148 | if (stat(path, &st) == -1) { |
149 | perror("stat"); |
150 | longjmp(abort_buf, 1); |
151 | } else if (!S_ISDIR(st.st_mode)) { |
152 | fprintf(stderr, "%s: '%s' not a directory\n", progname, path); |
153 | longjmp(abort_buf, 1); |
154 | } |
155 | } |
156 | |
157 | int main(int argc, char *argv[]) |
158 | __attribute__ ((weak, alias("nfsmount_main"))); |
159 | |
160 | int nfsmount_main(int argc, char *argv[]) |
161 | { |
162 | uint32_t server; |
163 | char *rem_name; |
164 | char *rem_path; |
165 | char *hostname; |
166 | char *path; |
167 | int c; |
168 | const char *portmap_file; |
169 | pid_t spoof_portmap; |
170 | int err, ret; |
171 | |
172 | if ((err = setjmp(abort_buf))) |
173 | return err; |
174 | |
175 | /* Set these here to avoid longjmp warning */ |
176 | portmap_file = NULL; |
177 | spoof_portmap = 0; |
178 | server = 0; |
179 | |
180 | /* If progname is set we're invoked from another program */ |
181 | if (!progname) { |
182 | struct timeval now; |
183 | progname = argv[0]; |
184 | gettimeofday(&now, NULL); |
185 | srand48(now.tv_usec ^ (now.tv_sec << 24)); |
186 | } |
187 | |
188 | while ((c = getopt(argc, argv, "o:p:")) != EOF) { |
189 | switch (c) { |
190 | case 'o': |
191 | parse_opts(optarg); |
192 | break; |
193 | case 'p': |
194 | portmap_file = optarg; |
195 | break; |
196 | case '?': |
197 | fprintf(stderr, "%s: invalid option -%c\n", |
198 | progname, optopt); |
199 | return 1; |
200 | } |
201 | } |
202 | |
203 | if (optind == argc) { |
204 | fprintf(stderr, "%s: need a path\n", progname); |
205 | return 1; |
206 | } |
207 | |
208 | hostname = rem_path = argv[optind]; |
209 | |
210 | if ((rem_name = strdup(rem_path)) == NULL) { |
211 | perror("strdup"); |
212 | return 1; |
213 | } |
214 | |
215 | if ((rem_path = strchr(rem_path, ':')) == NULL) { |
216 | fprintf(stderr, "%s: need a server\n", progname); |
217 | return 1; |
218 | } |
219 | |
220 | *rem_path++ = '\0'; |
221 | |
222 | if (*rem_path != '/') { |
223 | fprintf(stderr, "%s: need a path\n", progname); |
224 | return 1; |
225 | } |
226 | |
227 | server = parse_addr(hostname); |
228 | |
229 | if (optind <= argc - 2) |
230 | path = argv[optind + 1]; |
231 | else |
232 | path = "/nfs_root"; |
233 | |
234 | check_path(path); |
235 | |
236 | #if! _KLIBC_NO_MMU |
237 | /* Note: uClinux can't fork(), so the spoof portmapper is not |
238 | available on uClinux. */ |
239 | if (portmap_file) |
240 | spoof_portmap = start_dummy_portmap(portmap_file); |
241 | |
242 | if (spoof_portmap == -1) |
243 | return 1; |
244 | #endif |
245 | |
246 | ret = 0; |
247 | if (nfs_mount(rem_name, hostname, server, rem_path, path, |
248 | &mount_data) != 0) |
249 | ret = 1; |
250 | |
251 | /* If we set up the spoofer, tear it down now */ |
252 | if (spoof_portmap) { |
253 | kill(spoof_portmap, SIGTERM); |
254 | while (waitpid(spoof_portmap, NULL, 0) == -1 && |
255 | errno == EINTR) |
256 | ; |
257 | } |
258 | |
259 | free(rem_name); |
260 | |
261 | return ret; |
262 | } |