1 /* $NetBSD: autofs_solaris_v2_v3.c,v 1.1.1.3 2015/01/17 16:34:16 christos Exp $ */
2
3 /*
4 * Copyright (c) 1999-2003 Ion Badulescu
5 * Copyright (c) 1997-2014 Erez Zadok
6 * Copyright (c) 1990 Jan-Simon Pendry
7 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
8 * Copyright (c) 1990 The Regents of the University of California.
9 * All rights reserved.
10 *
11 * This code is derived from software contributed to Berkeley by
12 * Jan-Simon Pendry at Imperial College, London.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *
39 * File: am-utils/conf/autofs/autofs_solaris_v2_v3.c
40 *
41 */
42
43 /*
44 * Automounter filesystem
45 */
46
47 #ifdef HAVE_CONFIG_H
48 # include <config.h>
49 #endif /* HAVE_CONFIG_H */
50 #include <am_defs.h>
51 #include <amd.h>
52
53 /*
54 * MACROS:
55 */
56 #ifndef AUTOFS_NULL
57 # define AUTOFS_NULL NULLPROC
58 #endif /* not AUTOFS_NULL */
59
60 /*
61 * STRUCTURES:
62 */
63
64 struct amd_rddirres {
65 enum autofs_res rd_status;
66 u_long rd_bufsize;
67 nfsdirlist rd_dl;
68 };
69 typedef struct amd_rddirres amd_rddirres;
70
71 /*
72 * VARIABLES:
73 */
74
75 SVCXPRT *autofs_xprt = NULL;
76
77 /* forward declarations */
78 bool_t xdr_umntrequest(XDR *xdrs, umntrequest *objp);
79 bool_t xdr_umntres(XDR *xdrs, umntres *objp);
80 bool_t xdr_autofs_lookupargs(XDR *xdrs, autofs_lookupargs *objp);
81 bool_t xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp);
82 bool_t xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp);
83 bool_t xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp);
84 static bool_t xdr_amd_rddirres(XDR *xdrs, amd_rddirres *objp);
85
86 /*
87 * These exist only in the AutoFS V2 protocol.
88 */
89 #ifdef AUTOFS_POSTUNMOUNT
90 bool_t xdr_postumntreq(XDR *xdrs, postumntreq *objp);
91 bool_t xdr_postumntres(XDR *xdrs, postumntres *objp);
92 bool_t xdr_postmountreq(XDR *xdrs, postmountreq *objp);
93 bool_t xdr_postmountres(XDR *xdrs, postmountres *objp);
94 #endif /* AUTOFS_POSTUMOUNT */
95
96 /*
97 * AUTOFS XDR FUNCTIONS:
98 */
99
100 bool_t
xdr_autofs_stat(XDR * xdrs,autofs_stat * objp)101 xdr_autofs_stat(XDR *xdrs, autofs_stat *objp)
102 {
103 if (!xdr_enum(xdrs, (enum_t *)objp))
104 return (FALSE);
105 return (TRUE);
106 }
107
108
109 bool_t
xdr_autofs_action(XDR * xdrs,autofs_action * objp)110 xdr_autofs_action(XDR *xdrs, autofs_action *objp)
111 {
112 if (!xdr_enum(xdrs, (enum_t *)objp))
113 return (FALSE);
114 return (TRUE);
115 }
116
117
118 bool_t
xdr_linka(XDR * xdrs,linka * objp)119 xdr_linka(XDR *xdrs, linka *objp)
120 {
121 if (!xdr_string(xdrs, &objp->dir, AUTOFS_MAXPATHLEN))
122 return (FALSE);
123 if (!xdr_string(xdrs, &objp->link, AUTOFS_MAXPATHLEN))
124 return (FALSE);
125 return (TRUE);
126 }
127
128
129 bool_t
xdr_autofs_netbuf(XDR * xdrs,struct netbuf * objp)130 xdr_autofs_netbuf(XDR *xdrs, struct netbuf *objp)
131 {
132 bool_t dummy;
133
134 if (!xdr_u_long(xdrs, (u_long *) &objp->maxlen))
135 return (FALSE);
136 dummy = xdr_bytes(xdrs, (char **)&(objp->buf),
137 (u_int *)&(objp->len), objp->maxlen);
138 return (dummy);
139 }
140
141
142 bool_t
xdr_autofs_args(XDR * xdrs,autofs_args * objp)143 xdr_autofs_args(XDR *xdrs, autofs_args *objp)
144 {
145 if (!xdr_autofs_netbuf(xdrs, &objp->addr))
146 return (FALSE);
147 if (!xdr_string(xdrs, &objp->path, AUTOFS_MAXPATHLEN))
148 return (FALSE);
149 if (!xdr_string(xdrs, &objp->opts, AUTOFS_MAXOPTSLEN))
150 return (FALSE);
151 if (!xdr_string(xdrs, &objp->map, AUTOFS_MAXPATHLEN))
152 return (FALSE);
153 if (!xdr_string(xdrs, &objp->subdir, AUTOFS_MAXPATHLEN))
154 return (FALSE);
155 if (!xdr_string(xdrs, &objp->key, AUTOFS_MAXCOMPONENTLEN))
156 return (FALSE);
157 if (!xdr_int(xdrs, &objp->mount_to))
158 return (FALSE);
159 if (!xdr_int(xdrs, &objp->rpc_to))
160 return (FALSE);
161 if (!xdr_int(xdrs, &objp->direct))
162 return (FALSE);
163 return (TRUE);
164 }
165
166
167 bool_t
xdr_mounta(XDR * xdrs,struct mounta * objp)168 xdr_mounta(XDR *xdrs, struct mounta *objp)
169 {
170 if (!xdr_string(xdrs, &objp->spec, AUTOFS_MAXPATHLEN))
171 return (FALSE);
172 if (!xdr_string(xdrs, &objp->dir, AUTOFS_MAXPATHLEN))
173 return (FALSE);
174 if (!xdr_int(xdrs, &objp->flags))
175 return (FALSE);
176 if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN))
177 return (FALSE);
178 if (!xdr_pointer(xdrs, (char **)&objp->dataptr, sizeof(autofs_args),
179 (XDRPROC_T_TYPE) xdr_autofs_args))
180 return (FALSE);
181 if (!xdr_int(xdrs, &objp->datalen))
182 return (FALSE);
183 return (TRUE);
184 }
185
186
187 bool_t
xdr_action_list_entry(XDR * xdrs,action_list_entry * objp)188 xdr_action_list_entry(XDR *xdrs, action_list_entry *objp)
189 {
190 if (!xdr_autofs_action(xdrs, &objp->action))
191 return (FALSE);
192 switch (objp->action) {
193 case AUTOFS_MOUNT_RQ:
194 if (!xdr_mounta(xdrs, &objp->action_list_entry_u.mounta))
195 return (FALSE);
196 break;
197 case AUTOFS_LINK_RQ:
198 if (!xdr_linka(xdrs, &objp->action_list_entry_u.linka))
199 return (FALSE);
200 break;
201 default:
202 break;
203 }
204 return (TRUE);
205 }
206
207
208 bool_t
xdr_action_list(XDR * xdrs,action_list * objp)209 xdr_action_list(XDR *xdrs, action_list *objp)
210 {
211 if (!xdr_action_list_entry(xdrs, &objp->action))
212 return (FALSE);
213 if (!xdr_pointer(xdrs, (char **)&objp->next, sizeof(action_list),
214 (XDRPROC_T_TYPE) xdr_action_list))
215 return (FALSE);
216 return (TRUE);
217 }
218
219
220 bool_t
xdr_umntrequest(XDR * xdrs,umntrequest * objp)221 xdr_umntrequest(XDR *xdrs, umntrequest *objp)
222 {
223 if (amuDebug(D_XDRTRACE))
224 plog(XLOG_DEBUG, "xdr_umntrequest:");
225
226 if (!xdr_bool_t(xdrs, &objp->isdirect))
227 return (FALSE);
228 #ifdef HAVE_STRUCT_UMNTREQUEST_DEVID
229 if (!xdr_dev_t(xdrs, &objp->devid))
230 return (FALSE);
231 if (!xdr_dev_t(xdrs, &objp->rdevid))
232 return (FALSE);
233 #else /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
234 if (!xdr_string(xdrs, &objp->mntresource, AUTOFS_MAXPATHLEN))
235 return (FALSE);
236 if (!xdr_string(xdrs, &objp->mntpnt, AUTOFS_MAXPATHLEN))
237 return (FALSE);
238 if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN))
239 return (FALSE);
240 if (!xdr_string(xdrs, &objp->mntopts, AUTOFS_MAXOPTSLEN))
241 return (FALSE);
242 #endif /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
243 if (!xdr_pointer(xdrs, (char **) &objp->next, sizeof(umntrequest),
244 (XDRPROC_T_TYPE) xdr_umntrequest))
245 return (FALSE);
246
247 return (TRUE);
248 }
249
250
251 bool_t
xdr_umntres(XDR * xdrs,umntres * objp)252 xdr_umntres(XDR *xdrs, umntres *objp)
253 {
254 if (amuDebug(D_XDRTRACE))
255 plog(XLOG_DEBUG, "xdr_mntres:");
256
257 if (!xdr_int(xdrs, &objp->status))
258 return (FALSE);
259 return (TRUE);
260 }
261
262
263 /*
264 * These exist only in the AutoFS V2 protocol.
265 */
266 #ifdef AUTOFS_POSTUNMOUNT
267 bool_t
xdr_postumntreq(XDR * xdrs,postumntreq * objp)268 xdr_postumntreq(XDR *xdrs, postumntreq *objp)
269 {
270 if (!xdr_dev_t(xdrs, &objp->devid))
271 return (FALSE);
272 if (!xdr_dev_t(xdrs, &objp->rdevid))
273 return (FALSE);
274 if (!xdr_pointer(xdrs, (char **)&objp->next,
275 sizeof(struct postumntreq),
276 (XDRPROC_T_TYPE) xdr_postumntreq))
277 return (FALSE);
278 return (TRUE);
279 }
280
281
282 bool_t
xdr_postumntres(XDR * xdrs,postumntres * objp)283 xdr_postumntres(XDR *xdrs, postumntres *objp)
284 {
285 if (!xdr_int(xdrs, &objp->status))
286 return (FALSE);
287 return (TRUE);
288 }
289
290
291 bool_t
xdr_postmountreq(XDR * xdrs,postmountreq * objp)292 xdr_postmountreq(XDR *xdrs, postmountreq *objp)
293 {
294 if (!xdr_string(xdrs, &objp->special, AUTOFS_MAXPATHLEN))
295 return (FALSE);
296 if (!xdr_string(xdrs, &objp->mountp, AUTOFS_MAXPATHLEN))
297 return (FALSE);
298 if (!xdr_string(xdrs, &objp->fstype, AUTOFS_MAXCOMPONENTLEN))
299 return (FALSE);
300 if (!xdr_string(xdrs, &objp->mntopts, AUTOFS_MAXOPTSLEN))
301 return (FALSE);
302 if (!xdr_dev_t(xdrs, &objp->devid))
303 return (FALSE);
304 return (TRUE);
305 }
306
307
308 bool_t
xdr_postmountres(XDR * xdrs,postmountres * objp)309 xdr_postmountres(XDR *xdrs, postmountres *objp)
310 {
311 if (!xdr_int(xdrs, &objp->status))
312 return (FALSE);
313 return (TRUE);
314 }
315 #endif /* AUTOFS_POSTUNMOUNT */
316
317
318 bool_t
xdr_autofs_res(XDR * xdrs,autofs_res * objp)319 xdr_autofs_res(XDR *xdrs, autofs_res *objp)
320 {
321 if (!xdr_enum(xdrs, (enum_t *)objp))
322 return (FALSE);
323 return (TRUE);
324 }
325
326
327 bool_t
xdr_autofs_lookupargs(XDR * xdrs,autofs_lookupargs * objp)328 xdr_autofs_lookupargs(XDR *xdrs, autofs_lookupargs *objp)
329 {
330 if (amuDebug(D_XDRTRACE))
331 plog(XLOG_DEBUG, "xdr_autofs_lookupargs:");
332
333 if (!xdr_string(xdrs, &objp->map, AUTOFS_MAXPATHLEN))
334 return (FALSE);
335 if (!xdr_string(xdrs, &objp->path, AUTOFS_MAXPATHLEN))
336 return (FALSE);
337 if (!xdr_string(xdrs, &objp->name, AUTOFS_MAXCOMPONENTLEN))
338 return (FALSE);
339 if (!xdr_string(xdrs, &objp->subdir, AUTOFS_MAXPATHLEN))
340 return (FALSE);
341 if (!xdr_string(xdrs, &objp->opts, AUTOFS_MAXOPTSLEN))
342 return (FALSE);
343 if (!xdr_bool_t(xdrs, &objp->isdirect))
344 return (FALSE);
345 return (TRUE);
346 }
347
348
349 bool_t
xdr_mount_result_type(XDR * xdrs,mount_result_type * objp)350 xdr_mount_result_type(XDR *xdrs, mount_result_type *objp)
351 {
352 if (!xdr_autofs_stat(xdrs, &objp->status))
353 return (FALSE);
354 switch (objp->status) {
355 case AUTOFS_ACTION:
356 if (!xdr_pointer(xdrs,
357 (char **)&objp->mount_result_type_u.list,
358 sizeof(action_list), (XDRPROC_T_TYPE) xdr_action_list))
359 return (FALSE);
360 break;
361 case AUTOFS_DONE:
362 if (!xdr_int(xdrs, &objp->mount_result_type_u.error))
363 return (FALSE);
364 break;
365 }
366 return (TRUE);
367 }
368
369
370 bool_t
xdr_autofs_mountres(XDR * xdrs,autofs_mountres * objp)371 xdr_autofs_mountres(XDR *xdrs, autofs_mountres *objp)
372 {
373 if (amuDebug(D_XDRTRACE))
374 plog(XLOG_DEBUG, "xdr_mntres:");
375
376 if (!xdr_mount_result_type(xdrs, &objp->mr_type))
377 return (FALSE);
378 if (!xdr_int(xdrs, &objp->mr_verbose))
379 return (FALSE);
380
381 return (TRUE);
382 }
383
384
385 bool_t
xdr_lookup_result_type(XDR * xdrs,lookup_result_type * objp)386 xdr_lookup_result_type(XDR *xdrs, lookup_result_type *objp)
387 {
388 if (!xdr_autofs_action(xdrs, &objp->action))
389 return (FALSE);
390 switch (objp->action) {
391 case AUTOFS_LINK_RQ:
392 if (!xdr_linka(xdrs, &objp->lookup_result_type_u.lt_linka))
393 return (FALSE);
394 break;
395 default:
396 break;
397 }
398 return (TRUE);
399 }
400
401
402 bool_t
xdr_autofs_lookupres(XDR * xdrs,autofs_lookupres * objp)403 xdr_autofs_lookupres(XDR *xdrs, autofs_lookupres *objp)
404 {
405 if (!xdr_autofs_res(xdrs, &objp->lu_res))
406 return (FALSE);
407 if (!xdr_lookup_result_type(xdrs, &objp->lu_type))
408 return (FALSE);
409 if (!xdr_int(xdrs, &objp->lu_verbose))
410 return (FALSE);
411 return (TRUE);
412 }
413
414
415 bool_t
xdr_autofs_rddirargs(XDR * xdrs,autofs_rddirargs * objp)416 xdr_autofs_rddirargs(XDR *xdrs, autofs_rddirargs *objp)
417 {
418 if (!xdr_string(xdrs, &objp->rda_map, AUTOFS_MAXPATHLEN))
419 return (FALSE);
420 if (!xdr_u_int(xdrs, (u_int *) &objp->rda_offset))
421 return (FALSE);
422 if (!xdr_u_int(xdrs, (u_int *) &objp->rda_count))
423 return (FALSE);
424 return (TRUE);
425 }
426
427
428 /*
429 * ENCODE ONLY
430 *
431 * Solaris automountd uses struct autofsrddir to pass the results.
432 * We use the traditional nfsreaddirres and do the conversion ourselves.
433 */
434 static bool_t
xdr_amd_putrddirres(XDR * xdrs,nfsdirlist * dp,ulong reqsize)435 xdr_amd_putrddirres(XDR *xdrs, nfsdirlist *dp, ulong reqsize)
436 {
437 nfsentry *ep;
438 char *name;
439 u_int namlen;
440 bool_t true = TRUE;
441 bool_t false = FALSE;
442 int entrysz;
443 int tofit;
444 int bufsize;
445 u_long ino, off;
446
447 bufsize = 1 * BYTES_PER_XDR_UNIT;
448 for (ep = dp->dl_entries; ep; ep = ep->ne_nextentry) {
449 name = ep->ne_name;
450 namlen = strlen(name);
451 ino = (u_long) ep->ne_fileid;
452 off = (u_long) ep->ne_cookie + AUTOFS_DAEMONCOOKIE;
453 entrysz = (1 + 1 + 1 + 1) * BYTES_PER_XDR_UNIT +
454 roundup(namlen, BYTES_PER_XDR_UNIT);
455 tofit = entrysz + 2 * BYTES_PER_XDR_UNIT;
456 if (bufsize + tofit > reqsize) {
457 dp->dl_eof = FALSE;
458 break;
459 }
460 if (!xdr_bool(xdrs, &true) ||
461 !xdr_u_long(xdrs, &ino) ||
462 !xdr_bytes(xdrs, &name, &namlen, AUTOFS_MAXPATHLEN) ||
463 !xdr_u_long(xdrs, &off)) {
464 return (FALSE);
465 }
466 bufsize += entrysz;
467 }
468 if (!xdr_bool(xdrs, &false)) {
469 return (FALSE);
470 }
471 if (!xdr_bool(xdrs, &dp->dl_eof)) {
472 return (FALSE);
473 }
474 return (TRUE);
475 }
476
477
478 static bool_t
xdr_amd_rddirres(XDR * xdrs,amd_rddirres * objp)479 xdr_amd_rddirres(XDR *xdrs, amd_rddirres *objp)
480 {
481 if (!xdr_enum(xdrs, (enum_t *)&objp->rd_status))
482 return (FALSE);
483 if (objp->rd_status != AUTOFS_OK)
484 return (TRUE);
485 return (xdr_amd_putrddirres(xdrs, &objp->rd_dl, objp->rd_bufsize));
486 }
487
488
489 /*
490 * AUTOFS RPC methods
491 */
492
493 static int
autofs_lookup_2_req(autofs_lookupargs * m,autofs_lookupres * res,struct authunix_parms * cred,SVCXPRT * transp)494 autofs_lookup_2_req(autofs_lookupargs *m,
495 autofs_lookupres *res,
496 struct authunix_parms *cred,
497 SVCXPRT *transp)
498 {
499 int err;
500 am_node *mp, *new_mp;
501 mntfs *mf;
502
503 dlog("LOOKUP REQUEST: name=%s[%s] map=%s opts=%s path=%s direct=%d",
504 m->name, m->subdir, m->map, m->opts,
505 m->path, m->isdirect);
506
507 /* find the effective uid/gid from RPC request */
508 xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) cred->aup_uid);
509 xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) cred->aup_gid);
510
511 mp = find_ap(m->path);
512 if (!mp) {
513 plog(XLOG_ERROR, "map %s not found", m->path);
514 err = AUTOFS_NOENT;
515 goto out;
516 }
517
518 mf = mp->am_al->al_mnt;
519 new_mp = mf->mf_ops->lookup_child(mp, m->name, &err, VLOOK_LOOKUP);
520 if (!new_mp) {
521 err = AUTOFS_NOENT;
522 goto out;
523 }
524
525 if (err == 0) {
526 plog(XLOG_ERROR, "autofs requests to mount an already mounted node???");
527 } else {
528 free_map(new_mp);
529 }
530 err = AUTOFS_OK;
531 res->lu_type.action = AUTOFS_NONE;
532
533 out:
534 res->lu_res = err;
535 res->lu_verbose = 1;
536
537 dlog("LOOKUP REPLY: status=%d", res->lu_res);
538 return 0;
539 }
540
541
542 static void
autofs_lookup_2_free(autofs_lookupres * res)543 autofs_lookup_2_free(autofs_lookupres *res)
544 {
545 struct linka link;
546
547 if ((res->lu_res == AUTOFS_OK) &&
548 (res->lu_type.action == AUTOFS_LINK_RQ)) {
549 /*
550 * Free link information
551 */
552 link = res->lu_type.lookup_result_type_u.lt_linka;
553 if (link.dir)
554 XFREE(link.dir);
555 if (link.link)
556 XFREE(link.link);
557 }
558 }
559
560
561 static int
autofs_mount_2_req(autofs_lookupargs * m,autofs_mountres * res,struct authunix_parms * cred,SVCXPRT * transp)562 autofs_mount_2_req(autofs_lookupargs *m,
563 autofs_mountres *res,
564 struct authunix_parms *cred,
565 SVCXPRT *transp)
566 {
567 int err = AUTOFS_OK;
568 am_node *mp, *new_mp;
569 mntfs *mf;
570
571 dlog("MOUNT REQUEST: name=%s[%s] map=%s opts=%s path=%s direct=%d",
572 m->name, m->subdir, m->map, m->opts,
573 m->path, m->isdirect);
574
575 /* find the effective uid/gid from RPC request */
576 xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) cred->aup_uid);
577 xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) cred->aup_gid);
578
579 mp = find_ap(m->path);
580 if (!mp) {
581 plog(XLOG_ERROR, "map %s not found", m->path);
582 res->mr_type.status = AUTOFS_DONE;
583 res->mr_type.mount_result_type_u.error = AUTOFS_NOENT;
584 goto out;
585 }
586
587 mf = mp->am_al->al_mnt;
588 new_mp = mf->mf_ops->lookup_child(mp, m->name + m->isdirect, &err, VLOOK_CREATE);
589 if (new_mp && err < 0) {
590 /* new_mp->am_transp = transp; */
591 new_mp = mf->mf_ops->mount_child(new_mp, &err);
592 }
593 if (new_mp == NULL) {
594 if (err < 0) {
595 /* we're working on it */
596 amd_stats.d_drops++;
597 return 1;
598 }
599 res->mr_type.status = AUTOFS_DONE;
600 res->mr_type.mount_result_type_u.error = AUTOFS_NOENT;
601 goto out;
602 }
603
604 if (gopt.flags & CFM_AUTOFS_USE_LOFS ||
605 new_mp->am_al->al_mnt->mf_flags & MFF_ON_AUTOFS) {
606 res->mr_type.status = AUTOFS_DONE;
607 res->mr_type.mount_result_type_u.error = AUTOFS_OK;
608 } else {
609 struct action_list *list = malloc(sizeof(struct action_list));
610 char *target;
611 if (new_mp->am_link)
612 target = new_mp->am_link;
613 else
614 target = new_mp->am_al->al_mnt->mf_mount;
615 list->action.action = AUTOFS_LINK_RQ;
616 list->action.action_list_entry_u.linka.dir = xstrdup(new_mp->am_name);
617 list->action.action_list_entry_u.linka.link = xstrdup(target);
618 list->next = NULL;
619 res->mr_type.status = AUTOFS_ACTION;
620 res->mr_type.mount_result_type_u.list = list;
621 }
622
623 out:
624 res->mr_verbose = 1;
625
626 switch (res->mr_type.status) {
627 case AUTOFS_ACTION:
628 dlog("MOUNT REPLY: status=%d, AUTOFS_ACTION", err);
629 break;
630 case AUTOFS_DONE:
631 dlog("MOUNT REPLY: status=%d, AUTOFS_DONE", err);
632 break;
633 default:
634 dlog("MOUNT REPLY: status=%d, UNKNOWN(%d)", err, res->mr_type.status);
635 }
636
637 if (err) {
638 if (m->isdirect) {
639 /* direct mount */
640 plog(XLOG_ERROR, "mount of %s failed", m->path);
641 } else {
642 /* indirect mount */
643 plog(XLOG_ERROR, "mount of %s/%s failed", m->path, m->name);
644 }
645 }
646 return 0;
647 }
648
649
650 static void
autofs_mount_2_free(struct autofs_mountres * res)651 autofs_mount_2_free(struct autofs_mountres *res)
652 {
653 if (res->mr_type.status == AUTOFS_ACTION &&
654 res->mr_type.mount_result_type_u.list != NULL) {
655 autofs_action action;
656 dlog("freeing action list");
657 action = res->mr_type.mount_result_type_u.list->action.action;
658 if (action == AUTOFS_LINK_RQ) {
659 /*
660 * Free link information
661 */
662 struct linka *link;
663 link = &(res->mr_type.mount_result_type_u.list->action.action_list_entry_u.linka);
664 if (link->dir)
665 XFREE(link->dir);
666 if (link->link)
667 XFREE(link->link);
668 } else if (action == AUTOFS_MOUNT_RQ) {
669 struct mounta *mnt;
670 mnt = &(res->mr_type.mount_result_type_u.list->action.action_list_entry_u.mounta);
671 if (mnt->spec)
672 XFREE(mnt->spec);
673 if (mnt->dir)
674 XFREE(mnt->dir);
675 if (mnt->fstype)
676 XFREE(mnt->fstype);
677 if (mnt->dataptr)
678 XFREE(mnt->dataptr);
679 #ifdef HAVE_MOUNTA_OPTPTR
680 if (mnt->optptr)
681 XFREE(mnt->optptr);
682 #endif /* HAVE_MOUNTA_OPTPTR */
683 }
684 XFREE(res->mr_type.mount_result_type_u.list);
685 }
686 }
687
688
689 static int
autofs_unmount_2_req(umntrequest * ul,umntres * res,struct authunix_parms * cred,SVCXPRT * transp)690 autofs_unmount_2_req(umntrequest *ul,
691 umntres *res,
692 struct authunix_parms *cred,
693 SVCXPRT *transp)
694 {
695 int mapno, err;
696 am_node *mp = NULL;
697
698 #ifdef HAVE_STRUCT_UMNTREQUEST_DEVID
699 dlog("UNMOUNT REQUEST: dev=%lx rdev=%lx %s",
700 (u_long) ul->devid,
701 (u_long) ul->rdevid,
702 ul->isdirect ? "direct" : "indirect");
703 #else /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
704 dlog("UNMOUNT REQUEST: mntresource='%s' mntpnt='%s' fstype='%s' mntopts='%s' %s",
705 ul->mntresource,
706 ul->mntpnt,
707 ul->fstype,
708 ul->mntopts,
709 ul->isdirect ? "direct" : "indirect");
710 #endif /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
711
712 /* by default, and if not found, succeed */
713 res->status = 0;
714
715 #ifdef HAVE_STRUCT_UMNTREQUEST_DEVID
716 for (mp = get_first_exported_ap(&mapno);
717 mp;
718 mp = get_next_exported_ap(&mapno)) {
719 if (mp->am_dev == ul->devid &&
720 mp->am_rdev == ul->rdevid)
721 break;
722 }
723 #else /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
724 mp = find_ap(ul->mntpnt);
725 #endif /* not HAVE_STRUCT_UMNTREQUEST_DEVID */
726
727 if (mp) {
728 /* save RPC context */
729 if (!mp->am_transp && transp) {
730 mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT));
731 *(mp->am_transp) = *transp;
732 }
733
734 mapno = mp->am_mapno;
735 err = unmount_mp(mp);
736
737 if (err)
738 /* backgrounded, don't reply yet */
739 return 1;
740
741 if (get_exported_ap(mapno))
742 /* unmounting failed, tell the kernel */
743 res->status = 1;
744 }
745
746 dlog("UNMOUNT REPLY: status=%d", res->status);
747 return 0;
748 }
749
750
751 /*
752 * These exist only in the AutoFS V2 protocol.
753 */
754 #ifdef AUTOFS_POSTUNMOUNT
755 /* XXX not implemented */
756 static int
autofs_postunmount_2_req(postumntreq * req,postumntres * res,struct authunix_parms * cred,SVCXPRT * transp)757 autofs_postunmount_2_req(postumntreq *req,
758 postumntres *res,
759 struct authunix_parms *cred,
760 SVCXPRT *transp)
761 {
762 postumntreq *ul = req;
763
764 dlog("POSTUNMOUNT REQUEST: dev=%lx rdev=%lx",
765 (u_long) ul->devid,
766 (u_long) ul->rdevid);
767
768 /* succeed unconditionally */
769 res->status = 0;
770
771 dlog("POSTUNMOUNT REPLY: status=%d", res->status);
772 return 0;
773 }
774
775
776 /* XXX not implemented */
777 static int
autofs_postmount_2_req(postmountreq * req,postmountres * res,struct authunix_parms * cred,SVCXPRT * transp)778 autofs_postmount_2_req(postmountreq *req,
779 postmountres *res,
780 struct authunix_parms *cred,
781 SVCXPRT *transp)
782 {
783 dlog("POSTMOUNT REQUEST: %s\tdev=%lx\tspecial=%s %s",
784 req->mountp, (u_long) req->devid, req->special, req->mntopts);
785
786 /* succeed unconditionally */
787 res->status = 0;
788
789 dlog("POSTMOUNT REPLY: status=%d", res->status);
790 return 0;
791 }
792 #endif /* AUTOFS_POSTUNMOUNT */
793
794
795 static int
autofs_readdir_2_req(struct autofs_rddirargs * req,struct amd_rddirres * res,struct authunix_parms * cred,SVCXPRT * transp)796 autofs_readdir_2_req(struct autofs_rddirargs *req,
797 struct amd_rddirres *res,
798 struct authunix_parms *cred,
799 SVCXPRT *transp)
800 {
801 am_node *mp;
802 int err;
803 static nfsentry e_res[MAX_READDIR_ENTRIES];
804
805 dlog("READDIR REQUEST: %s @ %d",
806 req->rda_map, (int) req->rda_offset);
807
808 mp = find_ap(req->rda_map);
809 if (!mp) {
810 plog(XLOG_ERROR, "map %s not found", req->rda_map);
811 res->rd_status = AUTOFS_NOENT;
812 goto out;
813 }
814
815 mp->am_stats.s_readdir++;
816 req->rda_offset -= AUTOFS_DAEMONCOOKIE;
817 err = mp->am_al->al_mnt->mf_ops->readdir(mp, (char *)&req->rda_offset,
818 &res->rd_dl, e_res, req->rda_count);
819 if (err) {
820 res->rd_status = AUTOFS_ECOMM;
821 goto out;
822 }
823
824 res->rd_status = AUTOFS_OK;
825 res->rd_bufsize = req->rda_count;
826
827 out:
828 dlog("READDIR REPLY: status=%d", res->rd_status);
829 return 0;
830 }
831
832
833 /****************************************************************************/
834 /* autofs program dispatcher */
835 static void
autofs_program_2(struct svc_req * rqstp,SVCXPRT * transp)836 autofs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
837 {
838 union {
839 autofs_lookupargs autofs_mount_2_arg;
840 autofs_lookupargs autofs_lookup_2_arg;
841 umntrequest autofs_umount_2_arg;
842 autofs_rddirargs autofs_readdir_2_arg;
843 #ifdef AUTOFS_POSTUNMOUNT
844 postmountreq autofs_postmount_2_arg;
845 postumntreq autofs_postumnt_2_arg;
846 #endif /* AUTOFS_POSTUNMOUNT */
847 } argument;
848
849 union {
850 autofs_mountres mount_res;
851 autofs_lookupres lookup_res;
852 umntres umount_res;
853 amd_rddirres readdir_res;
854 #ifdef AUTOFS_POSTUNMOUNT
855 postumntres postumnt_res;
856 postmountres postmnt_res;
857 #endif /* AUTOFS_POSTUNMOUNT */
858 } result;
859 int ret;
860
861 bool_t (*xdr_argument)();
862 bool_t (*xdr_result)();
863 int (*local)();
864 void (*local_free)() = NULL;
865
866 current_transp = transp;
867
868 switch (rqstp->rq_proc) {
869
870 case AUTOFS_NULL:
871 svc_sendreply(transp,
872 (XDRPROC_T_TYPE) xdr_void,
873 (SVC_IN_ARG_TYPE) NULL);
874 return;
875
876 case AUTOFS_LOOKUP:
877 xdr_argument = xdr_autofs_lookupargs;
878 xdr_result = xdr_autofs_lookupres;
879 local = autofs_lookup_2_req;
880 local_free = autofs_lookup_2_free;
881 break;
882
883 case AUTOFS_MOUNT:
884 xdr_argument = xdr_autofs_lookupargs;
885 xdr_result = xdr_autofs_mountres;
886 local = autofs_mount_2_req;
887 local_free = autofs_mount_2_free;
888 break;
889
890 case AUTOFS_UNMOUNT:
891 xdr_argument = xdr_umntrequest;
892 xdr_result = xdr_umntres;
893 local = autofs_unmount_2_req;
894 break;
895
896 /*
897 * These exist only in the AutoFS V2 protocol.
898 */
899 #ifdef AUTOFS_POSTUNMOUNT
900 case AUTOFS_POSTUNMOUNT:
901 xdr_argument = xdr_postumntreq;
902 xdr_result = xdr_postumntres;
903 local = autofs_postunmount_2_req;
904 break;
905
906 case AUTOFS_POSTMOUNT:
907 xdr_argument = xdr_postmountreq;
908 xdr_result = xdr_postmountres;
909 local = autofs_postmount_2_req;
910 break;
911 #endif /* AUTOFS_POSTUNMOUNT */
912
913 case AUTOFS_READDIR:
914 xdr_argument = xdr_autofs_rddirargs;
915 xdr_result = xdr_amd_rddirres;
916 local = autofs_readdir_2_req;
917 break;
918
919 default:
920 svcerr_noproc(transp);
921 return;
922 }
923
924 memset((char *) &argument, 0, sizeof(argument));
925 if (!svc_getargs(transp,
926 (XDRPROC_T_TYPE) xdr_argument,
927 (SVC_IN_ARG_TYPE) &argument)) {
928 plog(XLOG_ERROR, "AUTOFS xdr decode failed for %d %d %d",
929 (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc);
930 svcerr_decode(transp);
931 return;
932 }
933
934 memset((char *)&result, 0, sizeof(result));
935 ret = (*local) (&argument, &result, rqstp->rq_clntcred, transp);
936
937 current_transp = NULL;
938
939 /* send reply only if the RPC method returned 0 */
940 if (!ret) {
941 if (!svc_sendreply(transp,
942 (XDRPROC_T_TYPE) xdr_result,
943 (SVC_IN_ARG_TYPE) &result)) {
944 svcerr_systemerr(transp);
945 }
946 }
947
948 if (!svc_freeargs(transp,
949 (XDRPROC_T_TYPE) xdr_argument,
950 (SVC_IN_ARG_TYPE) &argument)) {
951 plog(XLOG_FATAL, "unable to free rpc arguments in autofs_program_2");
952 }
953
954 if (local_free)
955 (*local_free)(&result);
956 }
957
958
959 int
autofs_get_fh(am_node * mp)960 autofs_get_fh(am_node *mp)
961 {
962 autofs_fh_t *fh;
963 char buf[MAXHOSTNAMELEN];
964 mntfs *mf = mp->am_al->al_mnt;
965 struct utsname utsname;
966
967 plog(XLOG_DEBUG, "autofs_get_fh for %s", mp->am_path);
968 fh = ALLOC(autofs_fh_t);
969 memset((voidp) fh, 0, sizeof(autofs_fh_t)); /* Paranoid */
970
971 /*
972 * SET MOUNT ARGS
973 */
974 if (uname(&utsname) < 0) {
975 xstrlcpy(buf, "localhost.autofs", sizeof(buf));
976 } else {
977 xstrlcpy(buf, utsname.nodename, sizeof(buf));
978 xstrlcat(buf, ".autofs", sizeof(buf));
979 }
980 #ifdef HAVE_AUTOFS_ARGS_T_ADDR
981 fh->addr.buf = xstrdup(buf);
982 fh->addr.len = fh->addr.maxlen = strlen(buf);
983 #endif /* HAVE_AUTOFS_ARGS_T_ADDR */
984
985 fh->direct = ((mf->mf_ops->autofs_fs_flags & FS_DIRECT) == FS_DIRECT);
986 fh->rpc_to = 1; /* XXX: arbitrary */
987 fh->mount_to = mp->am_timeo;
988 fh->path = mp->am_path;
989 fh->opts = ""; /* XXX: arbitrary */
990 fh->map = mp->am_path; /* this is what we get back in readdir */
991 fh->subdir = "";
992 if (fh->direct)
993 fh->key = mp->am_name;
994 else
995 fh->key = "";
996
997 mp->am_autofs_fh = fh;
998 return 0;
999 }
1000
1001
1002 void
autofs_mounted(am_node * mp)1003 autofs_mounted(am_node *mp)
1004 {
1005 /* We don't want any timeouts on autofs nodes */
1006 mp->am_autofs_ttl = NEVER;
1007 }
1008
1009
1010 void
autofs_release_fh(am_node * mp)1011 autofs_release_fh(am_node *mp)
1012 {
1013 autofs_fh_t *fh = mp->am_autofs_fh;
1014 #ifdef HAVE_AUTOFS_ARGS_T_ADDR
1015 XFREE(fh->addr.buf);
1016 #endif /* HAVE_AUTOFS_ARGS_T_ADDR */
1017 XFREE(fh);
1018 mp->am_autofs_fh = NULL;
1019 }
1020
1021
1022 void
autofs_get_mp(am_node * mp)1023 autofs_get_mp(am_node *mp)
1024 {
1025 /* nothing to do */
1026 }
1027
1028
1029 void
autofs_release_mp(am_node * mp)1030 autofs_release_mp(am_node *mp)
1031 {
1032 /* nothing to do */
1033 }
1034
1035
1036 void
autofs_add_fdset(fd_set * readfds)1037 autofs_add_fdset(fd_set *readfds)
1038 {
1039 /* nothing to do */
1040 }
1041
1042
1043 int
autofs_handle_fdset(fd_set * readfds,int nsel)1044 autofs_handle_fdset(fd_set *readfds, int nsel)
1045 {
1046 /* nothing to do */
1047 return nsel;
1048 }
1049
1050
1051 /*
1052 * Create the autofs service for amd
1053 */
1054 int
create_autofs_service(void)1055 create_autofs_service(void)
1056 {
1057 dlog("creating autofs service listener");
1058 return register_autofs_service(AUTOFS_CONFTYPE, autofs_program_2);
1059 }
1060
1061
1062 int
destroy_autofs_service(void)1063 destroy_autofs_service(void)
1064 {
1065 dlog("destroying autofs service listener");
1066 return unregister_autofs_service(AUTOFS_CONFTYPE);
1067 }
1068
1069
1070 int
autofs_mount_fs(am_node * mp,mntfs * mf)1071 autofs_mount_fs(am_node *mp, mntfs *mf)
1072 {
1073 int err = 0;
1074 char *target, *target2 = NULL;
1075 struct stat buf;
1076
1077 /*
1078 * For sublinks, we could end up here with an already mounted f/s.
1079 * Don't do anything in that case.
1080 */
1081 if (!(mf->mf_flags & MFF_MOUNTED))
1082 err = mf->mf_ops->mount_fs(mp, mf);
1083
1084 if (err || mf->mf_flags & MFF_ON_AUTOFS)
1085 /* Nothing else to do */
1086 return err;
1087
1088 if (!(gopt.flags & CFM_AUTOFS_USE_LOFS))
1089 /* Symlinks will be requested in autofs_mount_succeeded */
1090 return 0;
1091
1092 if (mp->am_link)
1093 target = mp->am_link;
1094 else
1095 target = mf->mf_mount;
1096
1097 if (target[0] != '/')
1098 target2 = str3cat(NULL, mp->am_parent->am_path, "/", target);
1099 else
1100 target2 = xstrdup(target);
1101
1102 plog(XLOG_INFO, "autofs: converting from link to lofs (%s -> %s)", mp->am_path, target2);
1103
1104 /*
1105 * we need to stat() the destination, because the bind mount does not
1106 * follow symlinks and/or allow for non-existent destinations.
1107 * we fall back to symlinks if there are problems.
1108 *
1109 * we need to temporarily change pgrp, otherwise our stat() won't
1110 * trigger whatever cascading mounts are needed.
1111 *
1112 * WARNING: we will deadlock if this function is called from the master
1113 * amd process and it happens to trigger another auto mount. Therefore,
1114 * this function should be called only from a child amd process, or
1115 * at the very least it should not be called from the parent unless we
1116 * know for sure that it won't cause a recursive mount. We refuse to
1117 * cause the recursive mount anyway if called from the parent amd.
1118 */
1119 if (!foreground) {
1120 if ((err = stat(target2, &buf)))
1121 goto out;
1122 }
1123 if ((err = lstat(target2, &buf)))
1124 goto out;
1125
1126 if ((err = mount_lofs(mp->am_path, target2, mf->mf_mopts, 1))) {
1127 errno = err;
1128 goto out;
1129 }
1130
1131 out:
1132 if (target2)
1133 XFREE(target2);
1134
1135 if (err)
1136 return errno;
1137 return 0;
1138 }
1139
1140
1141 int
autofs_umount_fs(am_node * mp,mntfs * mf)1142 autofs_umount_fs(am_node *mp, mntfs *mf)
1143 {
1144 int err = 0;
1145 if (!(mf->mf_flags & MFF_ON_AUTOFS) &&
1146 gopt.flags & CFM_AUTOFS_USE_LOFS) {
1147 err = UMOUNT_FS(mp->am_path, mnttab_file_name, 1);
1148 if (err)
1149 return err;
1150 }
1151
1152 /*
1153 * Multiple sublinks could reference this f/s.
1154 * Don't actually unmount it unless we're holding the last reference.
1155 */
1156 if (mf->mf_refc == 1)
1157 err = mf->mf_ops->umount_fs(mp, mf);
1158 return err;
1159 }
1160
1161
1162 int
autofs_umount_succeeded(am_node * mp)1163 autofs_umount_succeeded(am_node *mp)
1164 {
1165 umntres res;
1166 SVCXPRT *transp = mp->am_transp;
1167
1168 if (transp) {
1169 res.status = 0;
1170
1171 if (!svc_sendreply(transp,
1172 (XDRPROC_T_TYPE) xdr_umntres,
1173 (SVC_IN_ARG_TYPE) &res))
1174 svcerr_systemerr(transp);
1175
1176 dlog("Quick reply sent for %s", mp->am_al->al_mnt->mf_mount);
1177 XFREE(transp);
1178 mp->am_transp = NULL;
1179 }
1180
1181 plog(XLOG_INFO, "autofs: unmounting %s succeeded", mp->am_path);
1182 return 0;
1183 }
1184
1185
1186 int
autofs_umount_failed(am_node * mp)1187 autofs_umount_failed(am_node *mp)
1188 {
1189 umntres res;
1190 SVCXPRT *transp = mp->am_transp;
1191
1192 if (transp) {
1193 res.status = 1;
1194
1195 if (!svc_sendreply(transp,
1196 (XDRPROC_T_TYPE) xdr_umntres,
1197 (SVC_IN_ARG_TYPE) &res))
1198 svcerr_systemerr(transp);
1199
1200 dlog("Quick reply sent for %s", mp->am_al->al_mnt->mf_mount);
1201 XFREE(transp);
1202 mp->am_transp = NULL;
1203 }
1204
1205 plog(XLOG_INFO, "autofs: unmounting %s failed", mp->am_path);
1206 return 0;
1207 }
1208
1209
1210 void
autofs_mount_succeeded(am_node * mp)1211 autofs_mount_succeeded(am_node *mp)
1212 {
1213 SVCXPRT *transp = mp->am_transp;
1214 struct stat stb;
1215
1216 /*
1217 * Store dev and rdev -- but not for symlinks
1218 */
1219 if (gopt.flags & CFM_AUTOFS_USE_LOFS ||
1220 mp->am_al->al_mnt->mf_flags & MFF_ON_AUTOFS) {
1221 if (!lstat(mp->am_path, &stb)) {
1222 mp->am_dev = stb.st_dev;
1223 mp->am_rdev = stb.st_rdev;
1224 }
1225 /* don't expire the entries -- the kernel will do it for us */
1226 mp->am_flags |= AMF_NOTIMEOUT;
1227 }
1228
1229 if (transp) {
1230 autofs_mountres res;
1231 res.mr_type.status = AUTOFS_DONE;
1232 res.mr_type.mount_result_type_u.error = AUTOFS_OK;
1233 res.mr_verbose = 1;
1234
1235 if (!svc_sendreply(transp,
1236 (XDRPROC_T_TYPE) xdr_autofs_mountres,
1237 (SVC_IN_ARG_TYPE) &res))
1238 svcerr_systemerr(transp);
1239
1240 dlog("Quick reply sent for %s", mp->am_al->al_mnt->mf_mount);
1241 XFREE(transp);
1242 mp->am_transp = NULL;
1243 }
1244
1245 plog(XLOG_INFO, "autofs: mounting %s succeeded", mp->am_path);
1246 }
1247
1248
1249 void
autofs_mount_failed(am_node * mp)1250 autofs_mount_failed(am_node *mp)
1251 {
1252 SVCXPRT *transp = mp->am_transp;
1253
1254 if (transp) {
1255 autofs_mountres res;
1256 res.mr_type.status = AUTOFS_DONE;
1257 res.mr_type.mount_result_type_u.error = AUTOFS_NOENT;
1258 res.mr_verbose = 1;
1259
1260 if (!svc_sendreply(transp,
1261 (XDRPROC_T_TYPE) xdr_autofs_mountres,
1262 (SVC_IN_ARG_TYPE) &res))
1263 svcerr_systemerr(transp);
1264
1265 dlog("Quick reply sent for %s", mp->am_al->al_mnt->mf_mount);
1266 XFREE(transp);
1267 mp->am_transp = NULL;
1268 }
1269
1270 plog(XLOG_INFO, "autofs: mounting %s failed", mp->am_path);
1271 }
1272
1273
1274 void
autofs_get_opts(char * opts,size_t l,autofs_fh_t * fh)1275 autofs_get_opts(char *opts, size_t l, autofs_fh_t *fh)
1276 {
1277 xsnprintf(opts, l, "%sdirect",
1278 fh->direct ? "" : "in");
1279 }
1280
1281
1282 int
autofs_compute_mount_flags(mntent_t * mntp)1283 autofs_compute_mount_flags(mntent_t *mntp)
1284 {
1285 /* Must use overlay mounts */
1286 return MNT2_GEN_OPT_OVERLAY;
1287 }
1288
1289
autofs_timeout_mp(am_node * mp)1290 void autofs_timeout_mp(am_node *mp)
1291 {
1292 /* We don't want any timeouts on autofs nodes */
1293 mp->am_autofs_ttl = NEVER;
1294 }
1295