Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/main.c

Parent Directory Parent Directory | Revision Log 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)
-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 }