File: | src/usr.sbin/amd/amd/nfs_ops.c |
Warning: | line 472, column 8 Although the value stored to 'colon' is used in the enclosing expression, the value is never actually read from 'colon' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: nfs_ops.c,v 1.27 2021/10/21 10:55:56 deraadt Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1990 Jan-Simon Pendry |
5 | * Copyright (c) 1990 Imperial College of Science, Technology & Medicine |
6 | * Copyright (c) 1990, 1993 |
7 | * The Regents of the University of California. All rights reserved. |
8 | * |
9 | * This code is derived from software contributed to Berkeley by |
10 | * Jan-Simon Pendry at Imperial College, London. |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. |
20 | * 3. Neither the name of the University nor the names of its contributors |
21 | * may be used to endorse or promote products derived from this software |
22 | * without specific prior written permission. |
23 | * |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. |
35 | */ |
36 | |
37 | #include "am.h" |
38 | #include <sys/stat.h> |
39 | |
40 | #ifdef HAS_NFS |
41 | |
42 | #define NFS |
43 | #define NFSCLIENT |
44 | |
45 | #include "mount.h" |
46 | |
47 | /* |
48 | * Network file system |
49 | */ |
50 | |
51 | /* |
52 | * Convert from nfsstat to UN*X error code |
53 | */ |
54 | #define unx_error(e)((int)(e)) ((int)(e)) |
55 | |
56 | /* |
57 | * The NFS layer maintains a cache of file handles. |
58 | * This is *fundamental* to the implementation and |
59 | * also allows quick remounting when a filesystem |
60 | * is accessed soon after timing out. |
61 | * |
62 | * The NFS server layer knows to flush this cache |
63 | * when a server goes down so avoiding stale handles. |
64 | * |
65 | * Each cache entry keeps a hard reference to |
66 | * the corresponding server. This ensures that |
67 | * the server keepalive information is maintained. |
68 | * |
69 | * The copy of the sockaddr_in here is taken so |
70 | * that the port can be twiddled to talk to mountd |
71 | * instead of portmap or the NFS server as used |
72 | * elsewhere. |
73 | * The port# is flushed if a server goes down. |
74 | * The IP address is never flushed - we assume |
75 | * that the address of a mounted machine never |
76 | * changes. If it does, then you have other |
77 | * problems... |
78 | */ |
79 | typedef struct fh_cache fh_cache; |
80 | struct fh_cache { |
81 | qelem fh_q; /* List header */ |
82 | void *fh_wchan; /* Wait channel */ |
83 | int fh_error; /* Valid data? */ |
84 | int fh_id; /* Unique id */ |
85 | int fh_cid; /* Callout id */ |
86 | fhstatus fh_handle; /* Handle on filesystem */ |
87 | struct sockaddr_in fh_sin; /* Address of mountd */ |
88 | fserver *fh_fs; /* Server holding filesystem */ |
89 | char *fh_path; /* Filesystem on host */ |
90 | }; |
91 | |
92 | /* |
93 | * FH_TTL is the time a file handle will remain in the cache since |
94 | * last being used. If the file handle becomes invalid, then it |
95 | * will be flushed anyway. |
96 | */ |
97 | #define FH_TTL(5 * 60) (5 * 60) /* five minutes */ |
98 | #define FH_TTL_ERROR(30) (30) /* 30 seconds */ |
99 | |
100 | static int fh_id = 0; |
101 | #define FHID_ALLOC()(++fh_id) (++fh_id) |
102 | extern qelem fh_head; |
103 | qelem fh_head = { &fh_head, &fh_head }; |
104 | |
105 | static int call_mountd(fh_cache*, unsigned long, fwd_fun, void *); |
106 | |
107 | AUTH *nfs_auth; |
108 | |
109 | static fh_cache * |
110 | find_nfs_fhandle_cache(void *idv, int done) |
111 | { |
112 | fh_cache *fp, *fp2 = 0; |
113 | /* XXX EVIL XXX */ |
114 | int id = (int) ((long)idv); |
115 | |
116 | ITER(fp, fh_cache, &fh_head)for ((fp) = ((fh_cache *) (((&fh_head))->q_forw)); (fp ) != ((fh_cache *) (&fh_head)); (fp) = ((fh_cache *) (((qelem *) (fp))->q_forw))) { |
117 | if (fp->fh_id == id) { |
118 | fp2 = fp; |
119 | break; |
120 | } |
121 | } |
122 | |
123 | #ifdef DEBUG |
124 | if (fp2) { |
125 | dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path); |
126 | } else { |
127 | dlog("fh cache search failed"); |
128 | } |
129 | #endif /* DEBUG */ |
130 | |
131 | if (fp2 && !done) { |
132 | fp2->fh_error = ETIMEDOUT60; |
133 | return 0; |
134 | } |
135 | |
136 | return fp2; |
137 | } |
138 | |
139 | /* |
140 | * Called when a filehandle appears |
141 | */ |
142 | static void |
143 | got_nfs_fh(void *pkt, int len, struct sockaddr_in *sa, |
144 | struct sockaddr_in *ia, void *idv, int done) |
145 | { |
146 | fh_cache *fp = find_nfs_fhandle_cache(idv, done); |
147 | if (fp) { |
148 | fp->fh_handle.fhs_vers = MOUNTVERS((u_long)1); |
149 | fp->fh_error = pickup_rpc_reply(pkt, len, &fp->fh_handle, |
150 | xdr_fhstatus); |
151 | if (!fp->fh_error) { |
152 | #ifdef DEBUG |
153 | dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); |
154 | #endif /* DEBUG */ |
155 | /* |
156 | * Wakeup anything sleeping on this filehandle |
157 | */ |
158 | if (fp->fh_wchan) { |
159 | #ifdef DEBUG |
160 | dlog("Calling wakeup on %#x", fp->fh_wchan); |
161 | #endif /* DEBUG */ |
162 | wakeup(fp->fh_wchan); |
163 | } |
164 | } |
165 | } |
166 | } |
167 | |
168 | void |
169 | flush_nfs_fhandle_cache(fserver *fs) |
170 | { |
171 | fh_cache *fp; |
172 | ITER(fp, fh_cache, &fh_head)for ((fp) = ((fh_cache *) (((&fh_head))->q_forw)); (fp ) != ((fh_cache *) (&fh_head)); (fp) = ((fh_cache *) (((qelem *) (fp))->q_forw))) { |
173 | if (fp->fh_fs == fs || fs == 0) { |
174 | fp->fh_sin.sin_port = (u_short) 0; |
175 | fp->fh_error = -1; |
176 | } |
177 | } |
178 | } |
179 | |
180 | static void |
181 | discard_fh(void *arg) |
182 | { |
183 | fh_cache *fp = arg; |
184 | |
185 | rem_que(&fp->fh_q); |
186 | #ifdef DEBUG |
187 | dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); |
188 | #endif /* DEBUG */ |
189 | free_srvr(fp->fh_fs); |
190 | free(fp->fh_path); |
191 | free(fp); |
192 | } |
193 | |
194 | /* |
195 | * Determine the file handle for a node |
196 | */ |
197 | static int |
198 | prime_nfs_fhandle_cache(char *path, fserver *fs, fhstatus *fhbuf, void *wchan) |
199 | { |
200 | fh_cache *fp, *fp_save = 0; |
201 | int error; |
202 | int reuse_id = FALSE(0); |
203 | |
204 | #ifdef DEBUG |
205 | dlog("Searching cache for %s:%s", fs->fs_host, path); |
206 | #endif /* DEBUG */ |
207 | |
208 | /* |
209 | * First search the cache |
210 | */ |
211 | ITER(fp, fh_cache, &fh_head)for ((fp) = ((fh_cache *) (((&fh_head))->q_forw)); (fp ) != ((fh_cache *) (&fh_head)); (fp) = ((fh_cache *) (((qelem *) (fp))->q_forw))) { |
212 | if (fs == fp->fh_fs && strcmp(path, fp->fh_path) == 0) { |
213 | switch (fp->fh_error) { |
214 | case 0: |
215 | error = fp->fh_error = unx_error(fp->fh_handle.fhs_stat)((int)(fp->fh_handle.fhs_stat)); |
216 | if (error == 0) { |
217 | if (fhbuf) |
218 | bcopy(&fp->fh_handle, fhbuf, |
219 | sizeof(fp->fh_handle)); |
220 | if (fp->fh_cid) |
221 | untimeout(fp->fh_cid); |
222 | fp->fh_cid = timeout(FH_TTL(5 * 60), |
223 | discard_fh, fp); |
224 | } else if (error == EACCES13) { |
225 | /* |
226 | * Now decode the file handle return code. |
227 | */ |
228 | plog(XLOG_INFO0x0010, "Filehandle denied for \"%s:%s\"", |
229 | fs->fs_host, path); |
230 | } else { |
231 | errno(*__errno()) = error; /* XXX */ |
232 | plog(XLOG_INFO0x0010, "Filehandle error for \"%s:%s\": %m", |
233 | fs->fs_host, path); |
234 | } |
235 | |
236 | /* |
237 | * The error was returned from the remote mount daemon. |
238 | * Policy: this error will be cached for now... |
239 | */ |
240 | return error; |
241 | |
242 | case -1: |
243 | /* |
244 | * Still thinking about it, but we can re-use. |
245 | */ |
246 | fp_save = fp; |
247 | reuse_id = TRUE(1); |
248 | break; |
249 | |
250 | default: |
251 | /* |
252 | * Return the error. |
253 | * Policy: make sure we recompute if required again |
254 | * in case this was caused by a network failure. |
255 | * This can thrash mountd's though... If you find |
256 | * your mountd going slowly then: |
257 | * 1. Add a fork() loop to main. |
258 | * 2. Remove the call to innetgr() and don't use |
259 | * netgroups, especially if you don't use YP. |
260 | */ |
261 | error = fp->fh_error; |
262 | fp->fh_error = -1; |
263 | return error; |
264 | } |
265 | break; |
266 | } |
267 | } |
268 | |
269 | /* |
270 | * Not in cache |
271 | */ |
272 | if (fp_save) { |
273 | fp = fp_save; |
274 | /* |
275 | * Re-use existing slot |
276 | */ |
277 | untimeout(fp->fh_cid); |
278 | free_srvr(fp->fh_fs); |
279 | free(fp->fh_path); |
280 | } else { |
281 | fp = ALLOC(fh_cache)((struct fh_cache *) xmalloc(sizeof(struct fh_cache))); |
282 | bzero(fp, sizeof(*fp)); |
283 | ins_que(&fp->fh_q, &fh_head); |
284 | } |
285 | if (!reuse_id) |
286 | fp->fh_id = FHID_ALLOC()(++fh_id); |
287 | fp->fh_wchan = wchan; |
288 | fp->fh_error = -1; |
289 | fp->fh_cid = timeout(FH_TTL(5 * 60), discard_fh, fp); |
290 | |
291 | /* |
292 | * If the address has changed then don't try to re-use the |
293 | * port information |
294 | */ |
295 | if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) { |
296 | fp->fh_sin = *fs->fs_ip; |
297 | fp->fh_sin.sin_port = 0; |
298 | } |
299 | fp->fh_fs = dup_srvr(fs); |
300 | fp->fh_path = strdup(path); |
301 | |
302 | error = call_mountd(fp, MOUNTPROC_MNT((u_long)1), got_nfs_fh, wchan); |
303 | if (error) { |
304 | /* |
305 | * Local error - cache for a short period |
306 | * just to prevent thrashing. |
307 | */ |
308 | untimeout(fp->fh_cid); |
309 | fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME40 : FH_TTL_ERROR(30), |
310 | discard_fh, fp); |
311 | fp->fh_error = error; |
312 | } else { |
313 | error = fp->fh_error; |
314 | } |
315 | return error; |
316 | } |
317 | |
318 | int |
319 | make_nfs_auth(void) |
320 | { |
321 | /* |
322 | * From: Chris Metcalf <metcalf@masala.lcs.mit.edu> |
323 | * Use hostd, not just hostname. Note that uids |
324 | * and gids and the gidlist are type *int* and not the |
325 | * system uid_t and gid_t types. |
326 | */ |
327 | static int group_wheel = 0; |
328 | nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel); |
329 | if (!nfs_auth) |
330 | return ENOBUFS55; |
331 | return 0; |
332 | } |
333 | |
334 | static int |
335 | call_mountd(fh_cache *fp, u_long proc, fwd_fun f, void *wchan) |
336 | { |
337 | struct rpc_msg mnt_msg; |
338 | int len; |
339 | char iobuf[8192]; |
340 | int error; |
341 | |
342 | if (!nfs_auth) { |
343 | error = make_nfs_auth(); |
344 | if (error) |
345 | return error; |
346 | } |
347 | |
348 | if (fp->fh_sin.sin_port == 0) { |
349 | u_short port; |
350 | error = nfs_srvr_port(fp->fh_fs, &port, wchan); |
351 | if (error) |
352 | return error; |
353 | fp->fh_sin.sin_port = port; |
354 | } |
355 | |
356 | rpc_msg_init(&mnt_msg, MOUNTPROG((u_long)100005), MOUNTVERS((u_long)1), (unsigned long) 0); |
357 | len = make_rpc_packet(iobuf, sizeof(iobuf), proc, |
358 | &mnt_msg, &fp->fh_path, xdr_nfspath, nfs_auth); |
359 | |
360 | /* |
361 | * XXX EVIL! We cast fh_id to a pointer, then back to an int |
362 | * XXX later. |
363 | */ |
364 | if (len > 0) { |
365 | error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id)((1) | ((fp->fh_id) << 4)), |
366 | iobuf, len, &fp->fh_sin, &fp->fh_sin, |
367 | (void *)((long)fp->fh_id), f); |
368 | } else { |
369 | error = -len; |
370 | } |
371 | /* |
372 | * It may be the case that we're sending to the wrong MOUNTD port. This |
373 | * occurs if mountd is restarted on the server after the port has been |
374 | * looked up and stored in the filehandle cache somewhere. The correct |
375 | * solution, if we're going to cache port numbers is to catch the ICMP |
376 | * port unreachable reply from the server and cause the portmap request |
377 | * to be redone. The quick solution here is to invalidate the MOUNTD |
378 | * port. |
379 | */ |
380 | fp->fh_sin.sin_port = 0; |
381 | |
382 | return error; |
383 | } |
384 | |
385 | /*-------------------------------------------------------------------------*/ |
386 | |
387 | /* |
388 | * NFS needs the local filesystem, remote filesystem |
389 | * remote hostname. |
390 | * Local filesystem defaults to remote and vice-versa. |
391 | */ |
392 | static char * |
393 | nfs_match(am_opts *fo) |
394 | { |
395 | char *xmtab; |
396 | if (fo->opt_fs && !fo->opt_rfs) |
397 | fo->opt_rfs = fo->opt_fs; |
398 | if (!fo->opt_rfs) { |
399 | plog(XLOG_USER0x0004, "nfs: no remote filesystem specified"); |
400 | return FALSE(0); |
401 | } |
402 | if (!fo->opt_rhost) { |
403 | plog(XLOG_USER0x0004, "nfs: no remote host specified"); |
404 | return FALSE(0); |
405 | } |
406 | /* |
407 | * Determine magic cookie to put in mtab |
408 | */ |
409 | xmtab = xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2); |
410 | snprintf(xmtab, strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2, |
411 | "%s:%s", fo->opt_rhost, fo->opt_rfs); |
412 | #ifdef DEBUG |
413 | dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"", |
414 | fo->opt_rhost, fo->opt_rfs, fo->opt_fs); |
415 | #endif /* DEBUG */ |
416 | |
417 | return xmtab; |
418 | } |
419 | |
420 | /* |
421 | * Initialise am structure for nfs |
422 | */ |
423 | static int |
424 | nfs_init(mntfs *mf) |
425 | { |
426 | if (!mf->mf_private) { |
427 | int error; |
428 | fhstatus fhs; |
429 | |
430 | char *colon = strchr(mf->mf_info, ':'); |
431 | if (colon == 0) |
432 | return ENOENT2; |
433 | |
434 | error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, |
435 | &fhs, mf); |
436 | if (!error) { |
437 | mf->mf_private = ALLOC(fhstatus)((struct fhstatus *) xmalloc(sizeof(struct fhstatus))); |
438 | mf->mf_prfree = free; |
439 | bcopy(&fhs, mf->mf_private, sizeof(fhs)); |
440 | } |
441 | return error; |
442 | } |
443 | |
444 | return 0; |
445 | } |
446 | |
447 | int |
448 | mount_nfs_fh(fhstatus *fhp, char *dir, char *fs_name, char *opts, |
449 | mntfs *mf) |
450 | { |
451 | struct nfs_args nfs_args; |
452 | struct mntent mnt; |
453 | int retry; |
454 | char *colon; |
455 | /*char *path;*/ |
456 | char host[HOST_NAME_MAX255+1 + PATH_MAX1024+2]; |
457 | fserver *fs = mf->mf_server; |
458 | int flags; |
459 | char *xopts; |
460 | int error; |
461 | #ifdef notdef |
462 | unsigned short port; |
463 | #endif /* notdef */ |
464 | |
465 | const char *type = MOUNT_NFS"nfs"; |
466 | |
467 | bzero(&nfs_args, sizeof(nfs_args)); /* Paranoid */ |
468 | |
469 | /* |
470 | * Extract host name to give to kernel |
471 | */ |
472 | if (!(colon = strchr(fs_name, ':'))) |
Although the value stored to 'colon' is used in the enclosing expression, the value is never actually read from 'colon' | |
473 | return ENOENT2; |
474 | strlcpy(host, fs_name, sizeof(host)); |
475 | /*path = colon + 1;*/ |
476 | |
477 | if (mf->mf_remopts && *mf->mf_remopts && !islocalnet(fs->fs_ip->sin_addr.s_addr)) |
478 | xopts = strdup(mf->mf_remopts); |
479 | else |
480 | xopts = strdup(opts); |
481 | |
482 | bzero(&nfs_args, sizeof(nfs_args)); |
483 | |
484 | mnt.mnt_dir = dir; |
485 | mnt.mnt_fsname = fs_name; |
486 | mnt.mnt_type = "nfs"; |
487 | mnt.mnt_opts = xopts; |
488 | mnt.mnt_freq = 0; |
489 | mnt.mnt_passno = 0; |
490 | |
491 | retry = hasmntval(&mnt, "retry"); |
492 | if (retry <= 0) |
493 | retry = 1; /* XXX */ |
494 | |
495 | /*again:*/ |
496 | |
497 | /* |
498 | * set mount args |
499 | */ |
500 | nfs_args.fh = (void *)fhp->fhs_fhandle; |
501 | nfs_args.fhsize = fhp->fhs_size; |
502 | nfs_args.version = NFS_ARGSVERSION4; |
503 | |
504 | nfs_args.hostname = host; |
505 | #ifdef HOSTNAMESZ |
506 | /* |
507 | * Most kernels have a name length restriction. |
508 | */ |
509 | if (strlen(host) >= HOSTNAMESZ) |
510 | strlcpy(host + HOSTNAMESZ - 3, "..", sizeof host - HOSTNAMESZ + 3); |
511 | #endif /* HOSTNAMESZ */ |
512 | |
513 | if ((nfs_args.rsize = hasmntval(&mnt, "rsize"))) |
514 | nfs_args.flags |= NFSMNT_RSIZE0x00000004; |
515 | |
516 | #ifdef NFSMNT_READDIRSIZE0x00020000 |
517 | if ((nfs_args.readdirsize = hasmntval(&mnt, "readdirsize"))) { |
518 | nfs_args.flags |= NFSMNT_READDIRSIZE0x00020000; |
519 | } else if (nfs_args.rsize) { |
520 | nfs_args.readdirsize = nfs_args.rsize; |
521 | nfs_args.flags |= NFSMNT_READDIRSIZE0x00020000; |
522 | } |
523 | #endif |
524 | |
525 | if ((nfs_args.wsize = hasmntval(&mnt, "wsize"))) |
526 | nfs_args.flags |= NFSMNT_WSIZE0x00000002; |
527 | |
528 | if ((nfs_args.timeo = hasmntval(&mnt, "timeo"))) |
529 | nfs_args.flags |= NFSMNT_TIMEO0x00000008; |
530 | |
531 | if ((nfs_args.retrans = hasmntval(&mnt, "retrans"))) |
532 | nfs_args.flags |= NFSMNT_RETRANS0x00000010; |
533 | |
534 | #ifdef NFSMNT_BIODS |
535 | if ((nfs_args.biods = hasmntval(&mnt, "biods"))) |
536 | nfs_args.flags |= NFSMNT_BIODS; |
537 | |
538 | #endif /* NFSMNT_BIODS */ |
539 | |
540 | #ifdef NFSMNT_MAXGRPS0x00000020 |
541 | if ((nfs_args.maxgrouplist = hasmntval(&mnt, "maxgroups"))) |
542 | nfs_args.flags |= NFSMNT_MAXGRPS0x00000020; |
543 | #endif /* NFSMNT_MAXGRPS */ |
544 | |
545 | #ifdef NFSMNT_READAHEAD0x00002000 |
546 | if ((nfs_args.readahead = hasmntval(&mnt, "readahead"))) |
547 | nfs_args.flags |= NFSMNT_READAHEAD0x00002000; |
548 | #endif /* NFSMNT_READAHEAD */ |
549 | |
550 | #ifdef notdef |
551 | /* |
552 | * This isn't supported by the ping algorithm yet. |
553 | * In any case, it is all done in nfs_init(). |
554 | */ |
555 | if ((port = hasmntval(&mnt, "port"))) |
556 | sin.sin_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t )(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U ) >> 8) : __swap16md(port)); |
557 | else |
558 | sin.sin_port = htons(NFS_PORT)(__uint16_t)(__builtin_constant_p(2049) ? (__uint16_t)(((__uint16_t )(2049) & 0xffU) << 8 | ((__uint16_t)(2049) & 0xff00U ) >> 8) : __swap16md(2049)); /* XXX should use portmapper */ |
559 | #endif /* notdef */ |
560 | |
561 | if (hasmntopt(&mnt, "soft") != NULL((void *)0)) |
562 | nfs_args.flags |= NFSMNT_SOFT0x00000001; |
563 | |
564 | #ifdef NFSMNT_SPONGY |
565 | if (hasmntopt(&mnt, "spongy") != NULL((void *)0)) { |
566 | nfs_args.flags |= NFSMNT_SPONGY; |
567 | if (nfs_args.flags & NFSMNT_SOFT0x00000001) { |
568 | plog(XLOG_USER0x0004, "Mount opts soft and spongy are incompatible - soft ignored"); |
569 | nfs_args.flags &= ~NFSMNT_SOFT0x00000001; |
570 | } |
571 | } |
572 | #endif /* MNTOPT_SPONGY */ |
573 | |
574 | if (hasmntopt(&mnt, "intr") != NULL((void *)0)) |
575 | nfs_args.flags |= NFSMNT_INT0x00000040; |
576 | |
577 | #ifdef MNTOPT_NODEVS |
578 | if (hasmntopt(&mnt, MNTOPT_NODEVS) != NULL((void *)0)) |
579 | nfs_args.flags |= NFSMNT_NODEVS; |
580 | #endif /* MNTOPT_NODEVS */ |
581 | |
582 | |
583 | if (hasmntopt(&mnt, "noconn") != NULL((void *)0)) |
584 | nfs_args.flags |= NFSMNT_NOCONN0x00000080; |
585 | |
586 | if (hasmntopt(&mnt, "resvport") != NULL((void *)0)) |
587 | nfs_args.flags |= NFSMNT_RESVPORT0x00000000; |
588 | |
589 | #ifdef NFSMNT_PGTHRESH |
590 | if ((nfs_args.pg_thresh = hasmntval(&mnt, "pgthresh"))) |
591 | nfs_args.flags |= NFSMNT_PGTHRESH; |
592 | #endif /* NFSMNT_PGTHRESH */ |
593 | |
594 | nfs_args.addr = (struct sockaddr *)fs->fs_ip; |
595 | nfs_args.addrlen = sizeof(*fs->fs_ip); |
596 | nfs_args.sotype = SOCK_DGRAM2; |
597 | nfs_args.proto = 0; |
598 | |
599 | flags = compute_mount_flags(&mnt); |
600 | |
601 | #ifdef NFSMNT_NOCTO |
602 | if (hasmntopt(&mnt, "nocto") != NULL((void *)0)) |
603 | nfs_args.flags |= NFSMNT_NOCTO; |
604 | #endif /* NFSMNT_NOCTO */ |
605 | |
606 | if (hasmntopt(&mnt, "tcp") != NULL((void *)0)) |
607 | nfs_args.sotype = SOCK_STREAM1; |
608 | |
609 | |
610 | |
611 | error = mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type); |
612 | free(xopts); |
613 | return error; |
614 | } |
615 | |
616 | static int |
617 | mount_nfs(char *dir, char *fs_name, char *opts, mntfs *mf) |
618 | { |
619 | #ifdef notdef |
620 | int error; |
621 | fhstatus fhs; |
622 | char *colon; |
623 | |
624 | if (!(colon = strchr(fs_name, ':'))) |
625 | return ENOENT2; |
626 | |
627 | #ifdef DEBUG |
628 | dlog("locating fhandle for %s", fs_name); |
629 | #endif /* DEBUG */ |
630 | error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, NULL((void *)0)); |
631 | |
632 | if (error) |
633 | return error; |
634 | |
635 | return mount_nfs_fh(&fhs, dir, fs_name, opts, mf); |
636 | #endif |
637 | if (!mf->mf_private) { |
638 | plog(XLOG_ERROR0x0002, "Missing filehandle for %s", fs_name); |
639 | return EINVAL22; |
640 | } |
641 | |
642 | return mount_nfs_fh((fhstatus *) mf->mf_private, dir, fs_name, opts, mf); |
643 | } |
644 | |
645 | static int |
646 | nfs_fmount(mntfs *mf) |
647 | { |
648 | int error; |
649 | |
650 | error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf); |
651 | |
652 | #ifdef DEBUG |
653 | if (error) { |
654 | errno(*__errno()) = error; |
655 | dlog("mount_nfs: %m"); |
656 | } |
657 | #endif /* DEBUG */ |
658 | return error; |
659 | } |
660 | |
661 | static int |
662 | nfs_fumount(mntfs *mf) |
663 | { |
664 | return (umount_fs(mf->mf_mount)); |
665 | } |
666 | |
667 | static void |
668 | nfs_umounted(am_node *mp) |
669 | { |
670 | |
671 | #ifdef KICK_KERNEL |
672 | /* This should go into the mainline code, not in nfs_ops... */ |
673 | |
674 | /* |
675 | * Run lstat over the underlying directory in |
676 | * case this was a direct mount. This will |
677 | * get the kernel back in sync with reality. |
678 | */ |
679 | if (mp->am_parent && mp->am_parent->am_path && |
680 | STREQ(mp->am_parent->am_mnt->mf_ops->fs_type, "direct")(strcmp((mp->am_parent->am_mnt->mf_ops->fs_type), ("direct")) == 0)) { |
681 | struct stat stb; |
682 | pid_t pid; |
683 | if ((pid = background()) == 0) { |
684 | if (lstat(mp->am_parent->am_path, &stb) < 0) { |
685 | plog(XLOG_ERROR0x0002, "lstat(%s) after unmount: %m", mp->am_parent->am_path); |
686 | #ifdef DEBUG |
687 | } else { |
688 | dlog("hack lstat(%s): ok", mp->am_parent->am_path); |
689 | #endif /* DEBUG */ |
690 | } |
691 | _exit(0); |
692 | } |
693 | } |
694 | #endif /* KICK_KERNEL */ |
695 | } |
696 | |
697 | /* |
698 | * Network file system |
699 | */ |
700 | am_ops nfs_ops = { |
701 | "nfs", |
702 | nfs_match, |
703 | nfs_init, |
704 | auto_fmount, |
705 | nfs_fmount, |
706 | auto_fumount, |
707 | nfs_fumount, |
708 | efs_lookuppn, |
709 | efs_readdir, |
710 | 0, /* nfs_readlink */ |
711 | 0, /* nfs_mounted */ |
712 | nfs_umounted, |
713 | find_nfs_srvr, |
714 | FS_MKMNT0x0008|FS_BACKGROUND(0x0002|0x0010)|FS_AMQINFO0x0040 |
715 | }; |
716 | |
717 | #endif /* HAS_NFS */ |