Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/main.c
Parent Directory
|
Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 5598 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 5598 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
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 | {"v2", ~NFS_MOUNT_VER3, 0}, |
74 | {"v3", ~NFS_MOUNT_VER3, NFS_MOUNT_VER3}, |
75 | {"udp", ~NFS_MOUNT_TCP, 0}, |
76 | {"tcp", ~NFS_MOUNT_TCP, NFS_MOUNT_TCP}, |
77 | {"broken_suid", ~NFS_MOUNT_BROKEN_SUID, NFS_MOUNT_BROKEN_SUID}, |
78 | {"ro", ~NFS_MOUNT_KLIBC_RONLY, NFS_MOUNT_KLIBC_RONLY}, |
79 | {"rw", ~NFS_MOUNT_KLIBC_RONLY, 0}, |
80 | {NULL, 0, 0} |
81 | }; |
82 | |
83 | static int parse_int(const char *val, const char *ctx) |
84 | { |
85 | char *end; |
86 | int ret; |
87 | |
88 | ret = (int)strtoul(val, &end, 0); |
89 | if (*val == '\0' || *end != '\0') { |
90 | fprintf(stderr, "%s: invalid value for %s\n", val, ctx); |
91 | longjmp(abort_buf, 1); |
92 | } |
93 | return ret; |
94 | } |
95 | |
96 | static void parse_opts(char *opts) |
97 | { |
98 | char *cp, *val; |
99 | |
100 | while ((cp = strsep(&opts, ",")) != NULL) { |
101 | if (*cp == '\0') |
102 | continue; |
103 | if ((val = strchr(cp, '=')) != NULL) { |
104 | struct int_opts *opts = int_opts; |
105 | *val++ = '\0'; |
106 | while (opts->name && strcmp(opts->name, cp) != 0) |
107 | opts++; |
108 | if (opts->name) |
109 | *(opts->val) = parse_int(val, opts->name); |
110 | else { |
111 | fprintf(stderr, "%s: bad option '%s'\n", |
112 | progname, cp); |
113 | longjmp(abort_buf, 1); |
114 | } |
115 | } else { |
116 | struct bool_opts *opts = bool_opts; |
117 | while (opts->name && strcmp(opts->name, cp) != 0) |
118 | opts++; |
119 | if (opts->name) { |
120 | mount_data.flags &= opts->and_mask; |
121 | mount_data.flags |= opts->or_mask; |
122 | } else { |
123 | fprintf(stderr, "%s: bad option '%s'\n", |
124 | progname, cp); |
125 | longjmp(abort_buf, 1); |
126 | } |
127 | } |
128 | } |
129 | } |
130 | |
131 | static uint32_t parse_addr(const char *ip) |
132 | { |
133 | struct in_addr in; |
134 | if (inet_aton(ip, &in) == 0) { |
135 | fprintf(stderr, "%s: can't parse IP address '%s'\n", |
136 | progname, ip); |
137 | longjmp(abort_buf, 1); |
138 | } |
139 | return in.s_addr; |
140 | } |
141 | |
142 | static void check_path(const char *path) |
143 | { |
144 | struct stat st; |
145 | |
146 | if (stat(path, &st) == -1) { |
147 | perror("stat"); |
148 | longjmp(abort_buf, 1); |
149 | } else if (!S_ISDIR(st.st_mode)) { |
150 | fprintf(stderr, "%s: '%s' not a directory\n", progname, path); |
151 | longjmp(abort_buf, 1); |
152 | } |
153 | } |
154 | |
155 | int main(int argc, char *argv[]) |
156 | __attribute__ ((weak, alias("nfsmount_main"))); |
157 | |
158 | int nfsmount_main(int argc, char *argv[]) |
159 | { |
160 | uint32_t server; |
161 | char *rem_name; |
162 | char *rem_path; |
163 | char *hostname; |
164 | char *path; |
165 | int c; |
166 | const char *portmap_file; |
167 | pid_t spoof_portmap; |
168 | int err; |
169 | |
170 | if ((err = setjmp(abort_buf))) |
171 | return err; |
172 | |
173 | /* Set these here to avoid longjmp warning */ |
174 | portmap_file = NULL; |
175 | spoof_portmap = 0; |
176 | server = 0; |
177 | |
178 | /* If progname is set we're invoked from another program */ |
179 | if (!progname) { |
180 | struct timeval now; |
181 | progname = argv[0]; |
182 | gettimeofday(&now, NULL); |
183 | srand48(now.tv_usec ^ (now.tv_sec << 24)); |
184 | } |
185 | |
186 | while ((c = getopt(argc, argv, "o:p:")) != EOF) { |
187 | switch (c) { |
188 | case 'o': |
189 | parse_opts(optarg); |
190 | break; |
191 | case 'p': |
192 | portmap_file = optarg; |
193 | break; |
194 | case '?': |
195 | fprintf(stderr, "%s: invalid option -%c\n", |
196 | progname, optopt); |
197 | return 1; |
198 | } |
199 | } |
200 | |
201 | if (optind == argc) { |
202 | fprintf(stderr, "%s: need a path\n", progname); |
203 | return 1; |
204 | } |
205 | |
206 | hostname = rem_path = argv[optind]; |
207 | |
208 | if ((rem_name = strdup(rem_path)) == NULL) { |
209 | perror("strdup"); |
210 | return 1; |
211 | } |
212 | |
213 | if ((rem_path = strchr(rem_path, ':')) == NULL) { |
214 | fprintf(stderr, "%s: need a server\n", progname); |
215 | return 1; |
216 | } |
217 | |
218 | *rem_path++ = '\0'; |
219 | |
220 | if (*rem_path != '/') { |
221 | fprintf(stderr, "%s: need a path\n", progname); |
222 | return 1; |
223 | } |
224 | |
225 | server = parse_addr(hostname); |
226 | |
227 | if (optind <= argc - 2) |
228 | path = argv[optind + 1]; |
229 | else |
230 | path = "/nfs_root"; |
231 | |
232 | check_path(path); |
233 | |
234 | #if! _KLIBC_NO_MMU |
235 | /* Note: uClinux can't fork(), so the spoof portmapper is not |
236 | available on uClinux. */ |
237 | if (portmap_file) |
238 | spoof_portmap = start_dummy_portmap(portmap_file); |
239 | |
240 | if (spoof_portmap == -1) |
241 | return 1; |
242 | #endif |
243 | |
244 | if (nfs_mount(rem_name, hostname, server, rem_path, path, |
245 | &mount_data) != 0) |
246 | return 1; |
247 | |
248 | /* If we set up the spoofer, tear it down now */ |
249 | if (spoof_portmap) { |
250 | kill(SIGTERM, spoof_portmap); |
251 | while (waitpid(spoof_portmap, NULL, 0) == -1 && |
252 | errno == EINTR) |
253 | ; |
254 | } |
255 | |
256 | free(rem_name); |
257 | |
258 | return 0; |
259 | } |