]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/amd/libamu/mount_fs.c
MFC r308493, r308619: Update amd from am-utils 6.1.5 to 6.2.
[FreeBSD/stable/10.git] / contrib / amd / libamu / mount_fs.c
1 /*
2  * Copyright (c) 1997-2014 Erez Zadok
3  * Copyright (c) 1990 Jan-Simon Pendry
4  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Jan-Simon Pendry at Imperial College, London.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *
36  * File: am-utils/libamu/mount_fs.c
37  *
38  */
39
40 #ifdef HAVE_CONFIG_H
41 # include <config.h>
42 #endif /* HAVE_CONFIG_H */
43 #include <am_defs.h>
44 #include <amu.h>
45 #include <nfs_common.h>
46
47
48 /* ensure that mount table options are delimited by a comma */
49 #define append_opts(old, l, new) { \
50         if (*(old) != '\0') \
51           xstrlcat(old, ",", l); \
52         xstrlcat(old, new, l); }
53
54 /*
55  * Standard mount flags
56  */
57 struct opt_tab mnt_flags[] =
58 {
59 #if defined(MNT2_GEN_OPT_RDONLY) && defined(MNTTAB_OPT_RO)
60   {MNTTAB_OPT_RO, MNT2_GEN_OPT_RDONLY},
61 #endif /* defined(MNT2_GEN_OPT_RDONLY) && defined(MNTTAB_OPT_RO) */
62
63 #if defined(MNT2_GEN_OPT_NOCACHE) && defined(MNTTAB_OPT_NOCACHE)
64   {MNTTAB_OPT_NOCACHE, MNT2_GEN_OPT_NOCACHE},
65 #endif /* defined(MNT2_GEN_OPT_NOCACHE) && defined(MNTTAB_OPT_NOCACHE) */
66
67   /* the "grpid" mount option can be offered as generic of NFS */
68 #ifdef MNTTAB_OPT_GRPID
69 # ifdef MNT2_GEN_OPT_GRPID
70   {MNTTAB_OPT_GRPID, MNT2_GEN_OPT_GRPID},
71 # endif /* MNT2_GEN_OPT_GRPID */
72 # ifdef MNT2_NFS_OPT_GRPID
73   {MNTTAB_OPT_GRPID, MNT2_NFS_OPT_GRPID},
74 # endif /* MNT2_NFS_OPT_GRPID */
75 #endif /* MNTTAB_OPT_GRPID */
76
77 #if defined(MNT2_GEN_OPT_MULTI) && defined(MNTTAB_OPT_MULTI)
78   {MNTTAB_OPT_MULTI, MNT2_GEN_OPT_MULTI},
79 #endif /* defined(MNT2_GEN_OPT_MULTI) && defined(MNTTAB_OPT_MULTI) */
80
81 #if defined(MNT2_GEN_OPT_NODEV) && defined(MNTTAB_OPT_NODEV)
82   {MNTTAB_OPT_NODEV, MNT2_GEN_OPT_NODEV},
83 #endif /* defined(MNT2_GEN_OPT_NODEV) && defined(MNTTAB_OPT_NODEV) */
84
85 #if defined(MNT2_GEN_OPT_NOEXEC) && defined(MNTTAB_OPT_NOEXEC)
86   {MNTTAB_OPT_NOEXEC, MNT2_GEN_OPT_NOEXEC},
87 #endif /* defined(MNT2_GEN_OPT_NOEXEC) && defined(MNTTAB_OPT_NOEXEC) */
88
89 #if defined(MNT2_GEN_OPT_NOSUB) && defined(MNTTAB_OPT_NOSUB)
90   {MNTTAB_OPT_NOSUB, MNT2_GEN_OPT_NOSUB},
91 #endif /* defined(MNT2_GEN_OPT_NOSUB) && defined(MNTTAB_OPT_NOSUB) */
92
93 #if defined(MNT2_GEN_OPT_NOSUID) && defined(MNTTAB_OPT_NOSUID)
94   {MNTTAB_OPT_NOSUID, MNT2_GEN_OPT_NOSUID},
95 #endif /* defined(MNT2_GEN_OPT_NOSUID) && defined(MNTTAB_OPT_NOSUID) */
96
97 #if defined(MNT2_GEN_OPT_SYNC) && defined(MNTTAB_OPT_SYNC)
98   {MNTTAB_OPT_SYNC, MNT2_GEN_OPT_SYNC},
99 #endif /* defined(MNT2_GEN_OPT_SYNC) && defined(MNTTAB_OPT_SYNC) */
100
101 #if defined(MNT2_GEN_OPT_OVERLAY) && defined(MNTTAB_OPT_OVERLAY)
102   {MNTTAB_OPT_OVERLAY, MNT2_GEN_OPT_OVERLAY},
103 #endif /* defined(MNT2_GEN_OPT_OVERLAY) && defined(MNTTAB_OPT_OVERLAY) */
104
105 #if defined(MNT2_GEN_OPT_LOG) && defined(MNTTAB_OPT_LOG)
106   {MNTTAB_OPT_LOG, MNT2_GEN_OPT_LOG},
107 #endif /* defined(MNT2_GEN_OPT_LOG) && defined(MNTTAB_OPT_LOG) */
108
109 #if defined(MNT2_GEN_OPT_NOATIME) && defined(MNTTAB_OPT_NOATIME)
110   {MNTTAB_OPT_NOATIME, MNT2_GEN_OPT_NOATIME},
111 #endif /* defined(MNT2_GEN_OPT_NOATIME) && defined(MNTTAB_OPT_NOATIME) */
112
113 #if defined(MNT2_GEN_OPT_NODEVMTIME) && defined(MNTTAB_OPT_NODEVMTIME)
114   {MNTTAB_OPT_NODEVMTIME, MNT2_GEN_OPT_NODEVMTIME},
115 #endif /* defined(MNT2_GEN_OPT_NODEVMTIME) && defined(MNTTAB_OPT_NODEVMTIME) */
116
117 #if defined(MNT2_GEN_OPT_SOFTDEP) && defined(MNTTAB_OPT_SOFTDEP)
118   {MNTTAB_OPT_SOFTDEP, MNT2_GEN_OPT_SOFTDEP},
119 #endif /* defined(MNT2_GEN_OPT_SOFTDEP) && defined(MNTTAB_OPT_SOFTDEP) */
120
121 #if defined(MNT2_GEN_OPT_SYMPERM) && defined(MNTTAB_OPT_SYMPERM)
122   {MNTTAB_OPT_SYMPERM, MNT2_GEN_OPT_SYMPERM},
123 #endif /* defined(MNT2_GEN_OPT_SYMPERM) && defined(MNTTAB_OPT_SYMPERM) */
124
125 #if defined(MNT2_GEN_OPT_UNION) && defined(MNTTAB_OPT_UNION)
126   {MNTTAB_OPT_UNION, MNT2_GEN_OPT_UNION},
127 #endif /* defined(MNT2_GEN_OPT_UNION) && defined(MNTTAB_OPT_UNION) */
128
129   /*
130    * Do not define MNT2_NFS_OPT_* entries here!  This is for generic
131    * mount(2) options only, not for NFS mount options.  If you need to put
132    * something here, it's probably not the right place: see
133    * include/am_compat.h.
134    */
135
136   {0, 0}
137 };
138
139
140 /* compute generic mount flags */
141 int
142 compute_mount_flags(mntent_t *mntp)
143 {
144   struct opt_tab *opt;
145   int flags = 0;
146
147 #ifdef MNT2_GEN_OPT_NEWTYPE
148   flags |= MNT2_GEN_OPT_NEWTYPE;
149 #endif /* MNT2_GEN_OPT_NEWTYPE */
150 #ifdef MNT2_GEN_OPT_AUTOMOUNTED
151   flags |= MNT2_GEN_OPT_AUTOMOUNTED;
152 #endif /* not MNT2_GEN_OPT_AUTOMOUNTED */
153
154   /*
155    * Crack basic mount options
156    */
157   for (opt = mnt_flags; opt->opt; opt++) {
158     flags |= amu_hasmntopt(mntp, opt->opt) ? opt->flag : 0;
159   }
160
161   return flags;
162 }
163
164
165 /* compute generic mount flags for automounter mounts */
166 int
167 compute_automounter_mount_flags(mntent_t *mntp)
168 {
169   int flags = 0;
170
171 #ifdef MNT2_GEN_OPT_IGNORE
172   flags |= MNT2_GEN_OPT_IGNORE;
173 #endif /* not MNT2_GEN_OPT_IGNORE */
174 #ifdef MNT2_GEN_OPT_AUTOMNTFS
175   flags |= MNT2_GEN_OPT_AUTOMNTFS;
176 #endif /* not MNT2_GEN_OPT_AUTOMNTFS */
177
178   return flags;
179 }
180
181
182 #if defined(MOUNT_TABLE_ON_FILE) && defined(MNTTAB_OPT_VERS)
183 /*
184  * add the extra vers={2,3} field to the mount table,
185  * unless already specified by user
186  */
187 static void
188 addvers(char *zopts, size_t l, mntent_t *mnt, u_long have_vers,
189   u_long want_vers)
190 {
191   if (have_vers == want_vers &&
192       hasmntval(mnt, MNTTAB_OPT_VERS) != want_vers) {
193     char optsbuf[48];
194     xsnprintf(optsbuf, sizeof(optsbuf),
195               "%s=%d", MNTTAB_OPT_VERS, want_vers);
196     append_opts(zopts, l, optsbuf);
197   }
198 }
199 #endif /* MOUNT_TABLE_ON_FILE && MNTTAB_OPT_VERS */
200
201 int
202 mount_fs(mntent_t *mnt, int flags, caddr_t mnt_data, int retry, MTYPE_TYPE type, u_long nfs_version, const char *nfs_proto, const char *mnttabname, int on_autofs)
203 {
204   int error = 0;
205 #ifdef MOUNT_TABLE_ON_FILE
206   char *zopts = NULL, *xopts = NULL;
207   size_t l;
208 #endif /* MOUNT_TABLE_ON_FILE */
209   char *mnt_dir = NULL;
210
211 #ifdef NEED_AUTOFS_SPACE_HACK
212   char *old_mnt_dir = NULL;
213   /* perform space hack */
214   if (on_autofs) {
215     old_mnt_dir = mnt->mnt_dir;
216     mnt->mnt_dir = mnt_dir = autofs_strdup_space_hack(old_mnt_dir);
217   } else
218 #endif /* NEED_AUTOFS_SPACE_HACK */
219     mnt_dir = xstrdup(mnt->mnt_dir);
220
221   dlog("'%s' fstype " MTYPE_PRINTF_TYPE " (%s) flags %#x (%s)",
222        mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts);
223
224 again:
225   error = MOUNT_TRAP(type, mnt, flags, mnt_data);
226
227   if (error < 0) {
228     plog(XLOG_ERROR, "'%s': mount: %m", mnt_dir);
229     /*
230      * The following code handles conditions which shouldn't
231      * occur.  They are possible either because amd screws up
232      * in preparing for the mount, or because some human
233      * messed with the mount point.  Both have been known to
234      * happen. -- stolcke 2/22/95
235      */
236     if (errno == EBUSY) {
237       /*
238        * Also, sometimes unmount isn't called, e.g., because
239        * our mountlist is garbled.  This leaves old mount
240        * points around which need to be removed before we
241        * can mount something new in their place.
242        */
243       errno = umount_fs(mnt_dir, mnttabname, on_autofs);
244       if (errno != 0)
245         plog(XLOG_ERROR, "'%s': umount: %m", mnt_dir);
246       else {
247         plog(XLOG_WARNING, "extra umount required for '%s'", mnt_dir);
248         error = MOUNT_TRAP(type, mnt, flags, mnt_data);
249       }
250     }
251   }
252
253   if (error < 0 && --retry > 0) {
254     sleep(1);
255     goto again;
256   }
257
258 #ifdef NEED_AUTOFS_SPACE_HACK
259   /* Undo space hack */
260   if (on_autofs)
261     mnt->mnt_dir = old_mnt_dir;
262 #endif /* NEED_AUTOFS_SPACE_HACK */
263
264   if (error < 0) {
265     error = errno;
266     goto out;
267   }
268
269 #ifdef MOUNT_TABLE_ON_FILE
270   /*
271    * Allocate memory for options:
272    *        dev=..., vers={2,3}, proto={tcp,udp}
273    */
274   l = strlen(mnt->mnt_opts) + 48;
275   zopts = (char *) xmalloc(l);
276
277   /* copy standard options */
278   xopts = mnt->mnt_opts;
279
280   xstrlcpy(zopts, xopts, l);
281
282 # ifdef MNTTAB_OPT_DEV
283   {
284     /* add the extra dev= field to the mount table */
285     struct stat stb;
286     if (lstat(mnt_dir, &stb) == 0) {
287       char optsbuf[48];
288       if (sizeof(stb.st_dev) == 2) /* e.g. SunOS 4.1 */
289         xsnprintf(optsbuf, sizeof(optsbuf), "%s=%04lx",
290                   MNTTAB_OPT_DEV, (u_long) stb.st_dev & 0xffff);
291       else                      /* e.g. System Vr4 */
292         xsnprintf(optsbuf, sizeof(optsbuf), "%s=%08lx",
293                   MNTTAB_OPT_DEV, (u_long) stb.st_dev);
294       append_opts(zopts, l, optsbuf);
295     }
296   }
297 # endif /* MNTTAB_OPT_DEV */
298
299 # if defined(HAVE_FS_NFS4) && defined(MNTTAB_OPT_VERS)
300   addvers(zopts, l, mnt, nfs_version, NFS_VERSION4);
301 # endif /* defined(HAVE_FS_NFS4) && defined(MNTTAB_OPT_VERS) */
302 # if defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS)
303   addvers(zopts, l, mnt, nfs_version, NFS_VERSION3);
304 # endif /* defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS) */
305 # ifdef MNTTAB_OPT_VERS
306   addvers(zopts, l, mnt, nfs_version, NFS_VERSION2);
307 # endif /* MNTTAB_OPT_VERS */
308
309 # ifdef MNTTAB_OPT_PROTO
310   /*
311    * add the extra proto={tcp,udp} field to the mount table,
312    * unless already specified by user.
313    */
314   if (nfs_proto && !amu_hasmntopt(mnt, MNTTAB_OPT_PROTO)) {
315     char optsbuf[48];
316     xsnprintf(optsbuf, sizeof(optsbuf), "%s=%s", MNTTAB_OPT_PROTO, nfs_proto);
317     append_opts(zopts, l, optsbuf);
318   }
319 # endif /* MNTTAB_OPT_PROTO */
320
321   /* finally, store the options into the mount table structure */
322   mnt->mnt_opts = zopts;
323
324   /*
325    * Additional fields in mntent_t
326    * are fixed up here
327    */
328 # ifdef HAVE_MNTENT_T_MNT_CNODE
329   mnt->mnt_cnode = 0;
330 # endif /* HAVE_MNTENT_T_MNT_CNODE */
331
332 # ifdef HAVE_MNTENT_T_MNT_RO
333   mnt->mnt_ro = (amu_hasmntopt(mnt, MNTTAB_OPT_RO) != NULL);
334 # endif /* HAVE_MNTENT_T_MNT_RO */
335
336 # ifdef HAVE_MNTENT_T_MNT_TIME
337 #  ifdef HAVE_MNTENT_T_MNT_TIME_STRING
338   {                             /* allocate enough space for a long */
339     size_t l = 13 * sizeof(char);
340     char *str = (char *) xmalloc(l);
341     xsnprintf(str, l, "%ld", time((time_t *) NULL));
342     mnt->mnt_time = str;
343   }
344 #  else /* not HAVE_MNTENT_T_MNT_TIME_STRING */
345   mnt->mnt_time = time((time_t *) NULL);
346 #  endif /* not HAVE_MNTENT_T_MNT_TIME_STRING */
347 # endif /* HAVE_MNTENT_T_MNT_TIME */
348
349   write_mntent(mnt, mnttabname);
350
351 # ifdef MNTTAB_OPT_DEV
352   if (xopts) {
353     XFREE(mnt->mnt_opts);
354     mnt->mnt_opts = xopts;
355   }
356 # endif /* MNTTAB_OPT_DEV */
357 #endif /* MOUNT_TABLE_ON_FILE */
358
359  out:
360   XFREE(mnt_dir);
361   return error;
362 }
363
364
365 /*
366  * Compute all NFS attribute cache related flags separately.  Note that this
367  * function now computes attribute-cache flags for both Amd's automount
368  * points (NFS) as well as any normal NFS mount that Amd performs.  Edit
369  * with caution.
370  */
371 static void
372 compute_nfs_attrcache_flags(struct nfs_common_args *nap, mntent_t *mntp)
373 {
374   int acval = 0;
375   int err_acval = 1;            /* 1 means we found no 'actimeo' value */
376 #if defined(HAVE_NFS_ARGS_T_ACREGMIN) || defined(HAVE_NFS_ARGS_T_ACREGMAX) || defined(HAVE_NFS_ARGS_T_ACDIRMIN) || defined(HAVE_NFS_ARGS_T_ACDIRMAX)
377   int err_acrdmm;               /* for ac{reg,dir}{min,max} */
378 #endif /* HAVE_NFS_ARGS_T_AC{REG,DIR}{MIN,MAX} */
379
380   /************************************************************************/
381   /***  ATTRIBUTE CACHES                                                ***/
382   /************************************************************************/
383   /*
384    * acval is set to 0 at the top of the function.  If actimeo mount option
385    * exists and defined in mntopts, then its acval is set to it.
386    * If the value is non-zero, then we set all attribute cache fields to it.
387    * If acval is zero, it means it was never defined in mntopts or the
388    * actimeo mount option does not exist, in which case we check for
389    * individual mount options per attribute cache.
390    * Regardless of the value of acval, mount flags are set based directly
391    * on the values of the attribute caches.
392    */
393 #ifdef MNTTAB_OPT_ACTIMEO
394   err_acval = hasmntvalerr(mntp, MNTTAB_OPT_ACTIMEO, &acval);   /* attr cache timeout (sec) */
395 #endif /* MNTTAB_OPT_ACTIMEO */
396
397   /*** acregmin ***/
398 #ifdef HAVE_NFS_ARGS_T_ACREGMIN
399   err_acrdmm = 1;               /* 1 means we found no acregmin value */
400   if (!err_acval) {
401     nap->acregmin = acval;      /* min ac timeout for reg files (sec) */
402   } else {
403 # ifdef MNTTAB_OPT_ACREGMIN
404     int tmp;
405     err_acrdmm = hasmntvalerr(mntp, MNTTAB_OPT_ACREGMIN, &tmp);
406     nap->acregmin = tmp;
407 # else /* not MNTTAB_OPT_ACREGMIN */
408     nap->acregmin = 0;
409 # endif /* not MNTTAB_OPT_ACREGMIN */
410   }
411   /* set this flag iff we changed acregmin (possibly to zero) */
412 # ifdef MNT2_NFS_OPT_ACREGMIN
413   if (!err_acval || !err_acrdmm)
414     nap->flags |= MNT2_NFS_OPT_ACREGMIN;
415 # endif /* MNT2_NFS_OPT_ACREGMIN */
416 #endif /* HAVE_NFS_ARGS_T_ACREGMIN */
417
418   /*** acregmax ***/
419 #ifdef HAVE_NFS_ARGS_T_ACREGMAX
420   err_acrdmm = 1;               /* 1 means we found no acregmax value */
421   if (!err_acval) {
422     nap->acregmax = acval;      /* max ac timeout for reg files (sec) */
423   } else {
424 # ifdef MNTTAB_OPT_ACREGMAX
425     int tmp;
426     err_acrdmm = hasmntvalerr(mntp, MNTTAB_OPT_ACREGMAX, &tmp);
427     nap->acregmax = tmp;
428 # else /* not MNTTAB_OPT_ACREGMAX */
429     nap->acregmax = 0;
430 # endif /* not MNTTAB_OPT_ACREGMAX */
431   }
432   /* set this flag iff we changed acregmax (possibly to zero) */
433 # ifdef MNT2_NFS_OPT_ACREGMAX
434   if (!err_acval || !err_acrdmm)
435     nap->flags |= MNT2_NFS_OPT_ACREGMAX;
436 # endif /* MNT2_NFS_OPT_ACREGMAX */
437 #endif /* HAVE_NFS_ARGS_T_ACREGMAX */
438
439   /*** acdirmin ***/
440 #ifdef HAVE_NFS_ARGS_T_ACDIRMIN
441   err_acrdmm = 1;               /* 1 means we found no acdirmin value */
442   if (!err_acval) {
443     nap->acdirmin = acval;      /* min ac timeout for dirs (sec) */
444   } else {
445 # ifdef MNTTAB_OPT_ACDIRMIN
446     int tmp;
447     err_acrdmm = hasmntvalerr(mntp, MNTTAB_OPT_ACDIRMIN, &tmp);
448     nap->acdirmin = tmp;
449 # else /* not MNTTAB_OPT_ACDIRMIN */
450     nap->acdirmin = 0;
451 # endif /* not MNTTAB_OPT_ACDIRMIN */
452   }
453   /* set this flag iff we changed acdirmin (possibly to zero) */
454 # ifdef MNT2_NFS_OPT_ACDIRMIN
455   if (!err_acval || !err_acrdmm)
456     nap->flags |= MNT2_NFS_OPT_ACDIRMIN;
457 # endif /* MNT2_NFS_OPT_ACDIRMIN */
458 #endif /* HAVE_NFS_ARGS_T_ACDIRMIN */
459
460   /*** acdirmax ***/
461 #ifdef HAVE_NFS_ARGS_T_ACDIRMAX
462   err_acrdmm = 1;               /* 1 means we found no acdirmax value */
463   if (!err_acval) {
464     nap->acdirmax = acval;      /* max ac timeout for dirs (sec) */
465   } else {
466 # ifdef MNTTAB_OPT_ACDIRMAX
467     int tmp;
468     err_acrdmm = hasmntvalerr(mntp, MNTTAB_OPT_ACDIRMAX, &tmp);
469     nap->acdirmax = tmp;
470 # else /* not MNTTAB_OPT_ACDIRMAX */
471     nap->acdirmax = 0;
472 # endif /* not MNTTAB_OPT_ACDIRMAX */
473   }
474   /* set this flag iff we changed acdirmax (possibly to zero) */
475 # ifdef MNT2_NFS_OPT_ACDIRMAX
476   if (!err_acval || !err_acrdmm)
477     nap->flags |= MNT2_NFS_OPT_ACDIRMAX;
478 # endif /* MNT2_NFS_OPT_ACDIRMAX */
479 #endif /* HAVE_NFS_ARGS_T_ACDIRMAX */
480
481
482   /* don't cache attributes */
483 #if defined(MNTTAB_OPT_NOAC) && defined(MNT2_NFS_OPT_NOAC)
484   if (amu_hasmntopt(mntp, MNTTAB_OPT_NOAC) != NULL)
485     nap->flags |= MNT2_NFS_OPT_NOAC;
486 #endif /* defined(MNTTAB_OPT_NOAC) && defined(MNT2_NFS_OPT_NOAC) */
487 }
488
489
490
491 static void
492 compute_nfs_common_args(struct nfs_common_args *nap, mntent_t *mntp,
493     const char *nfs_proto, u_long nfs_version)
494 {
495 #ifdef MNT2_NFS_OPT_TCP
496   if (nfs_proto && STREQ(nfs_proto, "tcp"))
497     nap->flags |= MNT2_NFS_OPT_TCP;
498 #endif /* MNT2_NFS_OPT_TCP */
499
500 #ifdef MNT2_NFS_OPT_NOCONN
501   /* check if user specified to use unconnected or connected sockets */
502   if (amu_hasmntopt(mntp, MNTTAB_OPT_NOCONN) != NULL)
503     nap->flags |= MNT2_NFS_OPT_NOCONN;
504   else if (amu_hasmntopt(mntp, MNTTAB_OPT_CONN) != NULL)
505     nap->flags &= ~MNT2_NFS_OPT_NOCONN;
506   else {
507     /*
508      * Some OSs want you to set noconn always.  Some want you to always turn
509      * it off.  Others want you to turn it on/off only if NFS V.3 is used.
510      * And all of that changes from revision to another.  This is
511      * particularly true of OpenBSD, NetBSD, and FreeBSD.  So, rather than
512      * attempt to auto-detect this, I'm forced to "fix" it in the individual
513      * conf/nfs_prot/nfs_prot_*.h files.
514      */
515 # ifdef USE_UNCONNECTED_NFS_SOCKETS
516     if (!(nap->flags & MNT2_NFS_OPT_NOCONN)) {
517       nap->flags |= MNT2_NFS_OPT_NOCONN;
518       plog(XLOG_WARNING, "noconn option not specified, and was just turned ON (OS override)! (May cause NFS hangs on some systems...)");
519     }
520 # endif /* USE_UNCONNECTED_NFS_SOCKETS */
521 # ifdef USE_CONNECTED_NFS_SOCKETS
522     if (nap->flags & MNT2_NFS_OPT_NOCONN) {
523       nap->flags &= ~MNT2_NFS_OPT_NOCONN;
524       plog(XLOG_WARNING, "noconn option specified, and was just turned OFF (OS override)! (May cause NFS hangs on some systems...)");
525     }
526 # endif /* USE_CONNECTED_NFS_SOCKETS */
527   }
528 #endif /* MNT2_NFS_OPT_NOCONN */
529
530 #ifdef MNT2_NFS_OPT_RESVPORT
531 # ifdef MNTTAB_OPT_RESVPORT
532   if (amu_hasmntopt(mntp, MNTTAB_OPT_RESVPORT) != NULL)
533     nap->flags |= MNT2_NFS_OPT_RESVPORT;
534 # else /* not MNTTAB_OPT_RESVPORT */
535   nap->flags |= MNT2_NFS_OPT_RESVPORT;
536 # endif /* not MNTTAB_OPT_RESVPORT */
537 #endif /* MNT2_NFS_OPT_RESVPORT */
538
539   nap->rsize = hasmntval(mntp, MNTTAB_OPT_RSIZE);
540 #ifdef MNT2_NFS_OPT_RSIZE
541   if (nap->rsize)
542     nap->flags |= MNT2_NFS_OPT_RSIZE;
543 #endif /* MNT2_NFS_OPT_RSIZE */
544   if (nfs_version == NFS_VERSION && nap->rsize > 8192)
545     nap->rsize = 8192;
546
547   nap->wsize = hasmntval(mntp, MNTTAB_OPT_WSIZE);
548 #ifdef MNT2_NFS_OPT_WSIZE
549   if (nap->wsize)
550     nap->flags |= MNT2_NFS_OPT_WSIZE;
551 #endif /* MNT2_NFS_OPT_WSIZE */
552   if (nfs_version == NFS_VERSION && nap->wsize > 8192)
553     nap->wsize = 8192;
554
555   nap->timeo = hasmntval(mntp, MNTTAB_OPT_TIMEO);
556 #ifdef MNT2_NFS_OPT_TIMEO
557   if (nap->timeo)
558     nap->flags |= MNT2_NFS_OPT_TIMEO;
559 #endif /* MNT2_NFS_OPT_TIMEO */
560
561   nap->retrans = hasmntval(mntp, MNTTAB_OPT_RETRANS);
562 #ifdef MNT2_NFS_OPT_RETRANS
563   if (nap->retrans)
564     nap->flags |= MNT2_NFS_OPT_RETRANS;
565 #endif /* MNT2_NFS_OPT_RETRANS */
566
567 #ifdef MNT2_NFS_OPT_SOFT
568   if (amu_hasmntopt(mntp, MNTTAB_OPT_SOFT) != NULL)
569     nap->flags |= MNT2_NFS_OPT_SOFT;
570 #endif /* MNT2_NFS_OPT_SOFT */
571
572 #ifdef MNT2_NFS_OPT_SPONGY
573   if (amu_hasmntopt(mntp, MNTTAB_OPT_SPONGY) != NULL) {
574     nap->flags |= MNT2_NFS_OPT_SPONGY;
575     if (*flags & MNT2_NFS_OPT_SOFT) {
576       plog(XLOG_USER, "Mount opts soft and spongy are incompatible - soft ignored");
577       nap->flags &= ~MNT2_NFS_OPT_SOFT;
578     }
579   }
580 #endif /* MNT2_NFS_OPT_SPONGY */
581
582 #if defined(MNT2_GEN_OPT_RONLY) && defined(MNT2_NFS_OPT_RONLY)
583   /* Ultrix has separate generic and NFS ro flags */
584   if (genflags & MNT2_GEN_OPT_RONLY)
585     nap->flags |= MNT2_NFS_OPT_RONLY;
586 #endif /* defined(MNT2_GEN_OPT_RONLY) && defined(MNT2_NFS_OPT_RONLY) */
587
588 #ifdef MNTTAB_OPT_INTR
589   if (amu_hasmntopt(mntp, MNTTAB_OPT_INTR) != NULL)
590     /*
591      * Either turn on the "allow interrupts" option, or
592      * turn off the "disallow interrupts" option"
593      */
594 # ifdef MNT2_NFS_OPT_INTR
595     nap->flags |= MNT2_NFS_OPT_INTR;
596 # endif /* MNT2_NFS_OPT_INTR */
597 # ifdef MNT2_NFS_OPT_NOINTR
598     nap->flags &= ~MNT2_NFS_OPT_NOINTR;
599 # endif /* MNT2_NFS_OPT_NOINTR */
600 # ifdef MNT2_NFS_OPT_INT
601     nap->flags |= MNT2_NFS_OPT_INT;
602 # endif /* MNT2_NFS_OPT_INT */
603 # ifdef MNT2_NFS_OPT_NOINT
604     nap->flags &= ~MNT2_NFS_OPT_NOINT;
605 # endif /* MNT2_NFS_OPT_NOINT */
606 #endif /* MNTTAB_OPT_INTR */
607
608 #ifdef MNT2_NFS_OPT_NOACL
609   if (amu_hasmntopt(mntp, MNTTAB_OPT_NOACL) != NULL)
610     nap->flags |= MNT2_NFS_OPT_NOACL;
611 #endif /* MNT2_NFS_OPT_NOACL */
612
613 #ifdef MNTTAB_OPT_NODEVS
614   if (amu_hasmntopt(mntp, MNTTAB_OPT_NODEVS) != NULL)
615     nap->flags |= MNT2_NFS_OPT_NODEVS;
616 #endif /* MNTTAB_OPT_NODEVS */
617
618 #ifdef MNTTAB_OPT_COMPRESS
619   if (amu_hasmntopt(mntp, MNTTAB_OPT_COMPRESS) != NULL)
620     nap->flags |= MNT2_NFS_OPT_COMPRESS;
621 #endif /* MNTTAB_OPT_COMPRESS */
622
623 #ifdef MNTTAB_OPT_PRIVATE       /* mount private, single-client tree */
624   if (amu_hasmntopt(mntp, MNTTAB_OPT_PRIVATE) != NULL)
625     nap->flags |= MNT2_NFS_OPT_PRIVATE;
626 #endif /* MNTTAB_OPT_PRIVATE */
627
628
629 #if defined(MNT2_NFS_OPT_NOCTO) && defined(MNTTAB_OPT_NOCTO)
630   if (amu_hasmntopt(mntp, MNTTAB_OPT_NOCTO) != NULL)
631     nap->flags |= MNT2_NFS_OPT_NOCTO;
632 #endif /* defined(MNT2_NFS_OPT_NOCTO) && defined(MNTTAB_OPT_NOCTO) */
633
634 #if defined(MNT2_NFS_OPT_PROPLIST) && defined(MNTTAB_OPT_PROPLIST)
635   if (amu_hasmntopt(mntp, MNTTAB_OPT_PROPLIST) != NULL)
636     nap->flags |= MNT2_NFS_OPT_PROPLIST;
637 #endif /* defined(MNT2_NFS_OPT_PROPLIST) && defined(MNTTAB_OPT_PROPLIST) */
638
639 #if defined(MNT2_NFS_OPT_NONLM) && defined(MNTTAB_OPT_NOLOCK)
640   if (amu_hasmntopt(mntp, MNTTAB_OPT_NOLOCK) != NULL)
641     nap->flags |= MNT2_NFS_OPT_NONLM;
642 #endif /* defined(MNT2_NFS_OPT_NONLM) && defined(MNTTAB_OPT_NOLOCK) */
643
644 #if defined(MNT2_NFS_OPT_XLATECOOKIE) && defined(MNTTAB_OPT_XLATECOOKIE)
645   if (amu_hasmntopt(mntp, MNTTAB_OPT_XLATECOOKIE) != NULL)
646     nap->flags |= MNT2_NFS_OPT_XLATECOOKIE;
647 #endif /* defined(MNT2_NFS_OPT_XLATECOOKIE) && defined(MNTTAB_OPT_XLATECOOKIE) */
648 }
649
650 static void
651 print_nfs_common_args(const struct nfs_common_args *a)
652 {
653   plog(XLOG_DEBUG, "NA->flags = 0x%lx", a->flags);
654
655   plog(XLOG_DEBUG, "NA->rsize = %lu", a->rsize);
656   plog(XLOG_DEBUG, "NA->wsize = %lu", a->wsize);
657   plog(XLOG_DEBUG, "NA->timeo = %lu", a->timeo);
658   plog(XLOG_DEBUG, "NA->retrans = %lu", a->retrans);
659
660 #ifdef HAVE_NFS_ARGS_T_ACREGMIN
661   plog(XLOG_DEBUG, "NA->acregmin = %lu", a->acregmin);
662   plog(XLOG_DEBUG, "NA->acregmax = %lu", a->acregmax);
663   plog(XLOG_DEBUG, "NA->acdirmin = %lu", a->acdirmin);
664   plog(XLOG_DEBUG, "NA->acdirmax = %lu", a->acdirmax);
665 #endif /* HAVE_NFS_ARGS_T_ACREGMIN */
666 }
667
668 static void
669 discard_nfs23_args(nfs_args_t *nap)
670 {
671 #ifdef HAVE_TRANSPORT_TYPE_TLI
672   free_knetconfig(nap->knconf);
673   if (nap->addr)
674     XFREE(nap->addr);   /* allocated in compute_nfs_args() */
675 #endif /* HAVE_TRANSPORT_TYPE_TLI */
676 }
677
678 #ifdef DEBUG
679 /* get string version (in hex) of identifier */
680 static char *
681 get_hex_string(u_int len, const char *fhdata)
682 {
683   u_int i;
684   static u_int xlen;
685   static char *buf;
686   static u_short *arr;
687   char str[16];
688
689   if (!fhdata || len == 0 || len > 10240)
690     return NULL;
691   i = len * 4 + 1;
692   if (xlen < i) {
693     buf = xrealloc(buf, i);
694     arr = xrealloc(arr, len * sizeof(*arr));
695     xlen = i;
696   }
697         
698   buf[0] = '\0';
699   memset(arr, 0, len * sizeof(*arr));
700   memcpy(arr, fhdata, len);
701   len /= sizeof(*arr);
702   for (i = 0; i < len; i++) {
703     xsnprintf(str, sizeof(str), "%04x", ntohs(arr[i]));
704     xstrlcat(buf, str, xlen);
705   }
706   return buf;
707 }
708
709 static void
710 print_nfs_sockaddr_in(const char *tag, const struct sockaddr_in *sap)
711 {
712   char name[64];
713   plog(XLOG_DEBUG, "NA->%s.sin_family = %d", tag, sap->sin_family);
714   plog(XLOG_DEBUG, "NA->%s.sin_port = %d", tag, ntohs(sap->sin_port));
715   if (inet_ntop(AF_INET, &sap->sin_addr, name, sizeof(name)) == NULL)
716     return;
717   plog(XLOG_DEBUG, "NA->%s.sin_addr = \"%s\"", tag, name);
718 }
719
720 /*
721  * print a subset of fields from "struct nfs_args" that are otherwise
722  * not being provided anywhere else.
723  */
724 static void
725 print_nfs23_args(const nfs_args_t *nap, u_long nfs_version)
726 {
727   int fhlen = 32;       /* default: NFS V.2 file handle length is 32 */
728 #ifdef HAVE_TRANSPORT_TYPE_TLI
729   struct netbuf *nbp;
730   struct knetconfig *kncp;
731 #else /* not HAVE_TRANSPORT_TYPE_TLI */
732   struct sockaddr_in *sap;
733 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
734   struct nfs_common_args a;
735
736   if (!nap) {
737     plog(XLOG_DEBUG, "NULL nfs_args!");
738     return;
739   }
740
741   /* override default file handle size */
742 #ifdef FHSIZE
743    fhlen = FHSIZE;
744 #endif /* FHSIZE */
745 #ifdef NFS_FHSIZE
746    fhlen = NFS_FHSIZE;
747 #endif /* NFS_FHSIZE */
748
749 #ifdef HAVE_TRANSPORT_TYPE_TLI
750   nbp = nap->addr;
751   plog(XLOG_DEBUG, "NA->addr {netbuf} (maxlen=%d, len=%d) = \"%s\"",
752        nbp->maxlen, nbp->len,
753        get_hex_string(nbp->len, nbp->buf));
754   nbp = nap->syncaddr;
755   plog(XLOG_DEBUG, "NA->syncaddr {netbuf} %p", nbp);
756   kncp = nap->knconf;
757   plog(XLOG_DEBUG, "NA->knconf->semantics %lu", (u_long) kncp->knc_semantics);
758   plog(XLOG_DEBUG, "NA->knconf->protofmly \"%s\"", kncp->knc_protofmly);
759   plog(XLOG_DEBUG, "NA->knconf->proto \"%s\"", kncp->knc_proto);
760   plog(XLOG_DEBUG, "NA->knconf->rdev %lu", (u_long) kncp->knc_rdev);
761   /* don't print knconf->unused field */
762 #else /* not HAVE_TRANSPORT_TYPE_TLI */
763 # ifdef NFS_ARGS_T_ADDR_IS_POINTER
764     sap = (struct sockaddr_in *) nap->addr;
765 # else /* not NFS_ARGS_T_ADDR_IS_POINTER */
766     sap = (struct sockaddr_in *) &nap->addr;
767 # endif /* not NFS_ARGS_T_ADDR_IS_POINTER */
768 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
769   /* as per POSIX, sin_len need not be set (used internally by kernel) */
770   plog(XLOG_DEBUG, "NA->addr.sin_len = %d", sap->sin_len);
771 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
772   print_nfs_sockaddr_in("addr", sap);
773 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
774 #ifdef HAVE_NFS_ARGS_T_ADDRLEN
775   plog(XLOG_DEBUG, "NA->addrlen = %d", nap->addrlen);
776 #endif /* ifdef HAVE_NFS_ARGS_T_ADDRLEN */
777
778   plog(XLOG_DEBUG, "NA->hostname = \"%s\"", nap->hostname ? nap->hostname : "null");
779 #ifdef HAVE_NFS_ARGS_T_NAMLEN
780   plog(XLOG_DEBUG, "NA->namlen = %d", nap->namlen);
781 #endif /* HAVE_NFS_ARGS_T_NAMLEN */
782
783 #ifdef MNT2_NFS_OPT_FSNAME
784   plog(XLOG_DEBUG, "NA->fsname = \"%s\"", nap->fsname ? nap->fsname : "null");
785 #endif /* MNT2_NFS_OPT_FSNAME */
786
787 #ifdef HAVE_NFS_ARGS_T_FHSIZE
788   plog(XLOG_DEBUG, "NA->fhsize = %d", nap->fhsize);
789   fhlen = nap->fhsize;
790 #endif /* HAVE_NFS_ARGS_T_FHSIZE */
791 #ifdef HAVE_NFS_ARGS_T_FH_LEN
792   plog(XLOG_DEBUG, "NA->fh_len = %d", nap->fh_len);
793   fhlen = nap->fh_len;
794 #endif /* HAVE_NFS_ARGS_T_FH_LEN */
795
796   /*
797    * XXX: need to figure out how to correctly print file handles,
798    * since some times they are pointers, and sometimes the real structure
799    * is stored in nfs_args.  Even if it is a pointer, it can be the actual
800    * char[] array, or a structure containing multiple fields.
801    */
802   plog(XLOG_DEBUG, "NA->filehandle = \"%s\"",
803        get_hex_string(fhlen, (const char *) &nap->NFS_FH_FIELD));
804
805 #ifdef HAVE_NFS_ARGS_T_SOTYPE
806   plog(XLOG_DEBUG, "NA->sotype = %d", nap->sotype);
807 #endif /* HAVE_NFS_ARGS_T_SOTYPE */
808 #ifdef HAVE_NFS_ARGS_T_PROTO
809   plog(XLOG_DEBUG, "NA->proto = %d", (int) nap->proto);
810 #endif /* HAVE_NFS_ARGS_T_PROTO */
811 #ifdef HAVE_NFS_ARGS_T_VERSION
812   plog(XLOG_DEBUG, "NA->version = %d", nap->version);
813 #endif /* HAVE_NFS_ARGS_T_VERSION */
814
815   put_nfs_common_args(nap, a);
816   print_nfs_common_args(&a);
817
818 #ifdef HAVE_NFS_ARGS_T_BSIZE
819   plog(XLOG_DEBUG, "NA->bsize = %d", nap->bsize);
820 #endif /* HAVE_NFS_ARGS_T_BSIZE */
821
822 #ifdef MNTTAB_OPT_SYMTTL
823   plog(XLOG_DEBUG, "NA->symttl = %d", nap->symttl);
824 #endif /* MNTTAB_OPT_SYMTTL */
825 #ifdef MNTTAB_OPT_PG_THRESH
826   plog(XLOG_DEBUG, "NA->pg_thresh = %d", nap->pg_thresh);
827 #endif /* MNTTAB_OPT_PG_THRESH */
828
829 #ifdef MNT2_NFS_OPT_BIODS
830   plog(XLOG_DEBUG, "NA->biods = %d", nap->biods);
831 #endif /* MNT2_NFS_OPT_BIODS */
832
833 }
834 #endif /* DEBUG */
835
836 /*
837  * Fill in the many possible fields and flags of struct nfs_args.
838  *
839  * nap:         pre-allocated structure to fill in.
840  * mntp:        mount entry structure (includes options)
841  * genflags:    generic mount flags already determined
842  * nfsncp:      (TLI only) netconfig entry for this NFS mount
843  * ip_addr:     IP address of file server
844  * nfs_version: 2, 3, or 0 if unknown
845  * nfs_proto:   "udp", "tcp", or NULL.
846  * fhp:         file handle structure pointer
847  * host_name:   name of remote NFS host
848  * fs_name:     remote file system name to mount
849  */
850 static void
851 compute_nfs23_args(nfs_args_t *nap,
852                    mntent_t *mntp,
853                    int genflags,
854                    struct netconfig *nfsncp,
855                    struct sockaddr_in *ip_addr,
856                    u_long nfs_version,
857                    char *nfs_proto,
858                    am_nfs_handle_t *fhp,
859                    char *host_name,
860                    char *fs_name)
861 {
862   struct nfs_common_args a;
863   /* initialize just in case */
864   memset((voidp) nap, 0, sizeof(nfs_args_t));
865
866   /* compute all of the NFS attribute-cache flags */
867   memset(&a, 0, sizeof(a));
868   compute_nfs_attrcache_flags(&a, mntp);
869   compute_nfs_common_args(&a, mntp, nfs_proto, nfs_version);
870   get_nfs_common_args(nap, a);
871
872   /************************************************************************/
873   /***  FILEHANDLE DATA AND LENGTH                                      ***/
874   /************************************************************************/
875 #ifdef HAVE_FS_NFS3
876   if (nfs_version == NFS_VERSION3) {
877     if (fhp == NULL) {
878       plog(XLOG_FATAL, "cannot pass NULL fh for NFSv%lu", nfs_version);
879       going_down(1);
880       return;
881     }
882
883 # if defined(HAVE_NFS_ARGS_T_FHSIZE) || defined(HAVE_NFS_ARGS_T_FH_LEN)
884     /*
885      * Some systems (Irix/bsdi3) have a separate field in nfs_args for
886      * the length of the file handle for NFS V3.  They insist that
887      * the file handle set in nfs_args be plain bytes, and not
888      * include the length field.
889      */
890     NFS_FH_DREF(nap->NFS_FH_FIELD, &fhp->v3.am_fh3_data);
891 # else /* not defined(HAVE_NFS_ARGS_T_FHSIZE) || defined(HAVE_NFS_ARGS_T_FH_LEN) */
892     NFS_FH_DREF(nap->NFS_FH_FIELD, &fhp->v3);
893 # endif /* not defined(HAVE_NFS_ARGS_T_FHSIZE) || defined(HAVE_NFS_ARGS_T_FH_LEN) */
894 # ifdef MNT2_NFS_OPT_NFSV3
895     nap->flags |= MNT2_NFS_OPT_NFSV3;
896 # endif /* MNT2_NFS_OPT_NFSV3 */
897 # ifdef MNT2_NFS_OPT_VER3
898     nap->flags |= MNT2_NFS_OPT_VER3;
899 # endif /* MNT2_NFS_OPT_VER3 */
900   } else
901 #endif /* HAVE_FS_NFS3 */
902   {
903     if (fhp == NULL) {
904       plog(XLOG_FATAL, "cannot pass NULL fh for NFSv%lu", nfs_version);
905       going_down(1);
906       return;
907     }
908     NFS_FH_DREF(nap->NFS_FH_FIELD, &fhp->v2);
909   }
910
911 #ifdef HAVE_NFS_ARGS_T_FHSIZE
912 # ifdef HAVE_FS_NFS3
913   if (nfs_version == NFS_VERSION3)
914     nap->fhsize = fhp->v3.am_fh3_length;
915   else
916 # endif /* HAVE_FS_NFS3 */
917     nap->fhsize = FHSIZE;
918 #endif /* HAVE_NFS_ARGS_T_FHSIZE */
919
920   /* this is the version of the nfs_args structure, not of NFS! */
921 #ifdef HAVE_NFS_ARGS_T_FH_LEN
922 # ifdef HAVE_FS_NFS3
923   if (nfs_version == NFS_VERSION3)
924     nap->fh_len = fhp->v3.am_fh3_length;
925   else
926 # endif /* HAVE_FS_NFS3 */
927     nap->fh_len = FHSIZE;
928 #endif /* HAVE_NFS_ARGS_T_FH_LEN */
929
930   /************************************************************************/
931   /***  HOST NAME                                                       ***/
932   /************************************************************************/
933   /*
934    * XXX: warning, using xstrlcpy in NFS_HN_DREF, which may corrupt a
935    * struct nfs_args, or truncate our concocted "hostname:/path"
936    * string prematurely.
937    */
938   NFS_HN_DREF(nap->hostname, host_name);
939 #ifdef MNT2_NFS_OPT_HOSTNAME
940   nap->flags |= MNT2_NFS_OPT_HOSTNAME;
941 #endif /* MNT2_NFS_OPT_HOSTNAME */
942
943   /************************************************************************/
944   /***  IP ADDRESS OF REMOTE HOST                                       ***/
945   /************************************************************************/
946   if (ip_addr) {
947 #ifdef HAVE_TRANSPORT_TYPE_TLI
948     nap->addr = ALLOC(struct netbuf); /* free()'ed at end of mount_nfs_fh() */
949 #endif /* HAVE_TRANSPORT_TYPE_TLI */
950     NFS_SA_DREF(nap, ip_addr);
951   }
952
953   /************************************************************************/
954   /***  NFS PROTOCOL (UDP, TCP) AND VERSION                             ***/
955   /************************************************************************/
956 #ifdef HAVE_NFS_ARGS_T_SOTYPE
957   /* bsdi3 uses this */
958   if (nfs_proto) {
959     if (STREQ(nfs_proto, "tcp"))
960       nap->sotype = SOCK_STREAM;
961     else if (STREQ(nfs_proto, "udp"))
962       nap->sotype = SOCK_DGRAM;
963   }
964 #endif /* HAVE_NFS_ARGS_T_SOTYPE */
965
966 #ifdef HAVE_NFS_ARGS_T_PROTO
967   nap->proto = 0;               /* bsdi3 sets this field to zero  */
968 # ifdef IPPROTO_TCP
969   if (nfs_proto) {
970     if (STREQ(nfs_proto, "tcp"))        /* AIX 4.2.x needs this */
971       nap->proto = IPPROTO_TCP;
972     else if (STREQ(nfs_proto, "udp"))
973       nap->proto = IPPROTO_UDP;
974   }
975 # endif /* IPPROTO_TCP */
976 #endif /* HAVE_NFS_ARGS_T_SOTYPE */
977
978 #ifdef HAVE_NFS_ARGS_T_VERSION
979 # ifdef NFS_ARGSVERSION
980   nap->version = NFS_ARGSVERSION; /* BSDI 3.0 and OpenBSD 2.2 */
981 # endif /* NFS_ARGSVERSION */
982 # ifdef DG_MOUNT_NFS_VERSION
983   nap->version = DG_MOUNT_NFS_VERSION; /* dg-ux */
984 # endif /* DG_MOUNT_NFS_VERSION */
985 #endif /* HAVE_NFS_ARGS_VERSION */
986
987   /************************************************************************/
988   /***  OTHER NFS SOCKET RELATED OPTIONS AND FLAGS                      ***/
989   /************************************************************************/
990
991   /************************************************************************/
992   /***  OTHER FLAGS AND OPTIONS                                         ***/
993   /************************************************************************/
994
995 #ifdef MNT2_NFS_OPT_BIODS
996   if ((nap->biods = hasmntval(mntp, MNTTAB_OPT_BIODS)))
997     nap->flags |= MNT2_NFS_OPT_BIODS;
998 #endif /* MNT2_NFS_OPT_BIODS */
999
1000 #ifdef MNTTAB_OPT_SYMTTL        /* symlink cache time-to-live */
1001   if ((nap->symttl = hasmntval(mntp, MNTTAB_OPT_SYMTTL)))
1002     nap->args.flags |= MNT2_NFS_OPT_SYMTTL;
1003 #endif /* MNTTAB_OPT_SYMTTL */
1004
1005 #ifdef MNT2_NFS_OPT_PGTHRESH    /* paging threshold */
1006   if ((nap->pg_thresh = hasmntval(mntp, MNTTAB_OPT_PGTHRESH)))
1007     nap->args.flags |= MNT2_NFS_OPT_PGTHRESH;
1008 #endif /* MNT2_NFS_OPT_PGTHRESH */
1009
1010 #if defined(MNT2_NFS_OPT_POSIX) && defined(MNTTAB_OPT_POSIX)
1011   if (amu_hasmntopt(mntp, MNTTAB_OPT_POSIX) != NULL) {
1012     nap->flags |= MNT2_NFS_OPT_POSIX;
1013 # ifdef HAVE_NFS_ARGS_T_PATHCONF
1014     nap->pathconf = NULL;
1015 # endif /* HAVE_NFS_ARGS_T_PATHCONF */
1016   }
1017 #endif /* MNT2_NFS_OPT_POSIX && MNTTAB_OPT_POSIX */
1018
1019 #ifdef HAVE_TRANSPORT_TYPE_TLI
1020   /* set up syncaddr field */
1021   nap->syncaddr = (struct netbuf *) NULL;
1022
1023   /* set up knconf field */
1024   if (get_knetconfig(&nap->knconf, nfsncp, nfs_proto) < 0) {
1025     plog(XLOG_FATAL, "cannot fill knetconfig structure for nfs_args");
1026     going_down(1);
1027     return;
1028   }
1029   /* update the flags field for knconf */
1030   nap->args.flags |= MNT2_NFS_OPT_KNCONF;
1031 #endif /* HAVE_TRANSPORT_TYPE_TLI */
1032
1033 #ifdef MNT2_NFS_OPT_FSNAME
1034   nap->fsname = fs_name;
1035   nap->args.flags |= MNT2_NFS_OPT_FSNAME;
1036 #endif /* MNT2_NFS_OPT_FSNAME */
1037
1038
1039 #ifdef HAVE_NFS_ARGS_T_OPTSTR
1040   nap->optstr = mntp->mnt_opts;
1041 #endif /* HAVE_NFS_ARGS_T_OPTSTR */
1042
1043 #if defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS)
1044   nap->maxgrouplist = hasmntval(mntp, MNTTAB_OPT_MAXGROUPS);
1045   if (nap->maxgrouplist != 0)
1046     nap->flags |= MNT2_NFS_OPT_MAXGRPS;
1047 #endif /* defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS) */
1048
1049   /************************************************************************/
1050   /***  FINAL ACTIONS                                                   ***/
1051   /************************************************************************/
1052
1053 #ifdef HAVE_NFS_ARGS_T_GFS_FLAGS
1054   /* Ultrix stores generic flags in nfs_args.gfs_flags. */
1055   nap->gfs_flags = genflags;
1056 #endif /* HAVE_NFS_ARGS_T_FLAGS */
1057
1058   return;                       /* end of compute_nfs_args() function */
1059 }
1060
1061 #ifdef HAVE_FS_NFS4
1062
1063 #define RPC_AUTH_GSS_KRB5       390003
1064 #define RPC_AUTH_GSS_KRB5I      390004
1065 #define RPC_AUTH_GSS_KRB5P      390005
1066 #define RPC_AUTH_GSS_LKEY       390006
1067 #define RPC_AUTH_GSS_LKEYI      390007
1068 #define RPC_AUTH_GSS_LKEYP      390008
1069 #define RPC_AUTH_GSS_SPKM       390009
1070 #define RPC_AUTH_GSS_SPKMI      390010
1071 #define RPC_AUTH_GSS_SPKMP      390011
1072
1073 struct {
1074   const char *name;
1075   int num;
1076 } flavours[] = {
1077   { "unix",     AUTH_UNIX },
1078   { "krb5",     RPC_AUTH_GSS_KRB5 },
1079   { "krb5i",    RPC_AUTH_GSS_KRB5I },
1080   { "krb5p",    RPC_AUTH_GSS_KRB5P },
1081   { "lkey",     RPC_AUTH_GSS_LKEY },
1082   { "lkeyi",    RPC_AUTH_GSS_LKEYI },
1083   { "lkeyp",    RPC_AUTH_GSS_LKEYP },
1084   { "spkm",     RPC_AUTH_GSS_SPKM },
1085   { "spkmi",    RPC_AUTH_GSS_SPKMI },
1086   { "spkmp",    RPC_AUTH_GSS_SPKMP },
1087 };
1088
1089 static char *
1090 set_nfs4_security(nfs4_args_t *nap, mntent_t *mntp)
1091 {
1092   const char *o = hasmnteq(mntp, MNTTAB_OPT_SEC);
1093   char *q, *s, *ss;
1094   size_t l, i;
1095
1096   if (o == NULL)
1097     o = "unix";
1098
1099   for (l = 1, q = strchr(o, ','); q; q = strchr(q + 1, ','))
1100     l++;
1101
1102   nap->auth_flavours = xmalloc(l * sizeof(*nap->auth_flavours));
1103
1104   s = ss = xstrdup(o);
1105   for (;;) {
1106     q = strchr(s, ',');
1107     if (q)
1108         *q = '\0';
1109
1110     for (l = 0, i = 0; i < sizeof(flavours) / sizeof(flavours[0]); i++)
1111       if (strcmp(flavours[i].name, s) == 0) {
1112         nap->auth_flavours[l++] = flavours[i].num;
1113         break;
1114       }
1115
1116     if (i == sizeof(flavours) / sizeof(flavours[0]))
1117       plog(XLOG_ERROR, "Unknown NFSv4 security mechanism %s\n", s);
1118
1119     if (q == NULL)
1120       break;
1121
1122     *q = ':';
1123     s = ++q;
1124   }
1125
1126   nap->auth_flavourlen = l;
1127   return ss;
1128 }
1129
1130 static int
1131 get_my_ipv4addr(struct nfs_string *ns)
1132 {
1133   struct hostent *hp;
1134   char myname[MAXHOSTNAMELEN];
1135
1136   if (gethostname(myname, sizeof(myname)) == -1)
1137     return -1;
1138   if ((hp = gethostbyname(myname)) == NULL)
1139     return -1;
1140   if (inet_ntop(AF_INET, hp->h_addr, myname, sizeof(myname)) == NULL)
1141     return -1;
1142   ns->len = strlen(myname);
1143   ns->data = xmalloc(ns->len + 1);
1144   memcpy(ns->data, myname, ns->len + 1);
1145   return 0;
1146 }
1147
1148 static void
1149 add_nfs4_mntopts(const nfs4_args_t *nap, mntent_t *mntp, char *sec)
1150 {
1151   char *opts = mntp->mnt_opts;
1152   char buf[1024], addr[128];
1153   size_t len = strlen(mntp->mnt_opts);
1154
1155   if (inet_ntop(AF_INET,
1156       &((const struct sockaddr_in *)nap->host_addr)->sin_addr,
1157       addr, sizeof(addr)) == NULL)
1158     return;
1159
1160   xsnprintf(buf, sizeof(buf), ",clientaddr=%s,addr=%s", nap->client_addr.data,
1161             addr);
1162
1163   len += strlen(buf) + 1;
1164
1165   if (sec && strcmp(sec, "unix") != 0) {
1166     len += strlen(sec) + strlen(MNTTAB_OPT_SEC) + 2; /* 2 = ",=" */
1167   } else
1168     sec = NULL;
1169
1170   opts = xrealloc(mntp->mnt_opts, len);
1171   xstrlcat(opts, buf, len);
1172
1173   if (sec) {
1174     xstrlcat(opts, ",", len);
1175     xstrlcat(opts, MNTTAB_OPT_SEC, len);
1176     xstrlcat(opts, "=", len);
1177     xstrlcat(opts, sec, len);
1178   }
1179
1180   mntp->mnt_opts = opts;
1181 }
1182
1183 static void
1184 print_nfs4_security(const nfs4_args_t *nap)
1185 {
1186   char buf[1024];
1187   char num[64];
1188   size_t i, j;
1189
1190   buf[0] = '\0';
1191
1192   for (i = 0; i < nap->auth_flavourlen; i++) {
1193
1194     for (j = 0; j < sizeof(flavours) / sizeof(flavours[0]); j++)
1195       if (flavours[j].num == nap->auth_flavours[i]) {
1196         xstrlcpy(num, flavours[j].name, sizeof(num));
1197         break;
1198       }
1199
1200     if (j == sizeof(flavours) / sizeof(flavours[0])) {
1201       plog(XLOG_ERROR, "Unknown NFSv4 security mechanism %d\n",
1202            nap->auth_flavours[i]);
1203       xsnprintf(num, sizeof(num), "*%d*", nap->auth_flavours[i]);
1204     }
1205
1206     if (buf[0])
1207       xstrlcat(buf, ":", sizeof(buf));
1208
1209     xstrlcat(buf, num, sizeof(buf));
1210   }
1211
1212   plog(XLOG_DEBUG, "NA->auth_flavours \"%s\"\n", buf);
1213 }
1214
1215 static void
1216 discard_nfs4_args(nfs4_args_t *nap)
1217 {
1218   if (nap->client_addr.data)
1219     free(nap->client_addr.data);
1220   if (nap->hostname.data)
1221     free(nap->hostname.data);
1222   if (nap->mnt_path.data)
1223     free(nap->mnt_path.data);
1224   if (nap->host_addr)
1225     free(nap->host_addr);
1226   if (nap->auth_flavours)
1227     free(nap->auth_flavours);
1228 }
1229
1230 /*
1231  * Fill in the many possible fields and flags of struct nfs4_args.
1232  *
1233  * nap:         pre-allocated structure to fill in.
1234  * mntp:        mount entry structure (includes options)
1235  * genflags:    generic mount flags already determined
1236  * nfsncp:      (TLI only) netconfig entry for this NFS mount
1237  * ip_addr:     IP address of file server
1238  * nfs_version: 4, or 0 if unknown
1239  * nfs_proto:   "udp", "tcp", or NULL.
1240  * fhp:         file handle structure pointer
1241  * host_name:   name of remote NFS host
1242  * fs_name:     remote file system name to mount
1243  */
1244 static void
1245 compute_nfs4_args(nfs4_args_t *nap,
1246                   mntent_t *mntp,
1247                   int genflags,
1248                   struct netconfig *nfsncp,
1249                   struct sockaddr_in *ip_addr,
1250                   u_long nfs_version,
1251                   char *nfs_proto,
1252                   am_nfs_handle_t *fhp,
1253                   char *host_name,
1254                   char *fs_name)
1255 {
1256   char *s;
1257   struct nfs_common_args a;
1258   uint16_t nfs_port;
1259
1260   /* initialize just in case */
1261   memset((voidp) nap, 0, sizeof(nfs4_args_t));
1262
1263   /* compute all of the NFS attribute-cache flags */
1264   memset(&a, 0, sizeof(a));
1265   compute_nfs_attrcache_flags(&a, mntp);
1266   compute_nfs_common_args(&a, mntp, nfs_proto, nfs_version);
1267   get_nfs_common_args(nap, a);
1268
1269   get_my_ipv4addr(&nap->client_addr);
1270
1271   /************************************************************************/
1272   /***  HOST NAME                                                       ***/
1273   /************************************************************************/
1274   nap->hostname.len = strlen(host_name);
1275   nap->hostname.data = xmalloc(nap->hostname.len + 1);
1276   memcpy(nap->hostname.data, host_name, nap->hostname.len + 1);
1277
1278   if ((s = strchr(fs_name, ':')) != NULL)
1279     s++;
1280   else
1281     s = fs_name;
1282
1283   nap->mnt_path.len = strlen(s);
1284   nap->mnt_path.data = xmalloc(nap->mnt_path.len + 1);
1285   memcpy(nap->mnt_path.data, s, nap->mnt_path.len + 1);
1286   plog(XLOG_DEBUG, "dir name %s\n", nap->mnt_path.data);
1287
1288   /************************************************************************/
1289   /***  IP ADDRESS OF REMOTE HOST                                       ***/
1290   /************************************************************************/
1291   nap->host_addrlen = sizeof(*ip_addr);
1292   nap->host_addr = xmalloc(nap->host_addrlen);
1293   memcpy(nap->host_addr, ip_addr, nap->host_addrlen);
1294
1295   nfs_port = hasmntval(mntp, MNTTAB_OPT_PORT);
1296   if (nfs_port == 0)
1297     nfs_port = htons(NFS_PORT);
1298   else
1299     nfs_port = htons(nfs_port);
1300
1301   ((struct sockaddr_in *)nap->host_addr)->sin_port = nfs_port;
1302
1303   nap->proto = 0;               /* bsdi3 sets this field to zero  */
1304   if (nfs_proto) {
1305     if (STREQ(nfs_proto, "tcp"))        /* AIX 4.2.x needs this */
1306       nap->proto = IPPROTO_TCP;
1307     else if (STREQ(nfs_proto, "udp"))
1308       nap->proto = IPPROTO_UDP;
1309   }
1310
1311   nap->version = NFS4_MOUNT_VERSION; /* BSDI 3.0 and OpenBSD 2.2 */
1312
1313   /************************************************************************/
1314   /***  OTHER NFS SOCKET RELATED OPTIONS AND FLAGS                      ***/
1315   /************************************************************************/
1316
1317
1318   /************************************************************************/
1319   /***  OTHER FLAGS AND OPTIONS                                         ***/
1320   /************************************************************************/
1321
1322 #if defined(MNT2_NFS_OPT_POSIX) && defined(MNTTAB_OPT_POSIX)
1323   if (amu_hasmntopt(mntp, MNTTAB_OPT_POSIX) != NULL) {
1324     nap->args.flags |= MNT2_NFS_OPT_POSIX;
1325 # ifdef HAVE_NFS_ARGS_T_PATHCONF
1326     nap->pathconf = NULL;
1327 # endif /* HAVE_NFS_ARGS_T_PATHCONF */
1328   }
1329 #endif /* MNT2_NFS_OPT_POSIX && MNTTAB_OPT_POSIX */
1330
1331 #if defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS)
1332   nap->maxgrouplist = hasmntval(mntp, MNTTAB_OPT_MAXGROUPS);
1333   if (nap->maxgrouplist != 0)
1334     nap->args.flags |= MNT2_NFS_OPT_MAXGRPS;
1335 #endif /* defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS) */
1336
1337 #ifdef HAVE_NFS_ARGS_T_OPTSTR
1338   nap->optstr = mntp->mnt_opts;
1339 #endif /* HAVE_NFS_ARGS_T_OPTSTR */
1340
1341   /************************************************************************/
1342   /***  FINAL ACTIONS                                                   ***/
1343   /************************************************************************/
1344
1345 #ifdef HAVE_NFS_ARGS_T_GFS_FLAGS
1346   /* Ultrix stores generic flags in nfs_args.gfs_flags. */
1347   nap->gfs_flags = genflags;
1348 #endif /* HAVE_NFS_ARGS_T_FLAGS */
1349
1350   s = set_nfs4_security(nap, mntp);
1351
1352   /* Add addresses to the mount options */
1353   add_nfs4_mntopts(nap, mntp, s);
1354
1355   return;                       /* end of compute_nfs4_args() function */
1356 }
1357
1358 #ifdef DEBUG
1359 static void
1360 print_nfs4_args(const nfs4_args_t *nap, u_long nfs_version)
1361 {
1362   struct sockaddr_in *sap;
1363   struct nfs_common_args a;
1364
1365   if (!nap) {
1366     plog(XLOG_DEBUG, "NULL nfs_args!");
1367     return;
1368   }
1369
1370   plog(XLOG_DEBUG, "NA->client_addr \"%s\"\n", nap->client_addr.data);
1371   plog(XLOG_DEBUG, "NA->mnt_path = \"%s\"", nap->mnt_path.data);
1372   plog(XLOG_DEBUG, "NA->hostname = \"%s\"", nap->hostname.data);
1373   sap = (struct sockaddr_in *) nap->host_addr;
1374   print_nfs_sockaddr_in("host_addr", sap);
1375   plog(XLOG_DEBUG, "NA->proto = %d", (int) nap->proto);
1376 #ifdef HAVE_NFS_ARGS_T_VERSION
1377   plog(XLOG_DEBUG, "NA->version = %d", nap->version);
1378 #endif /* HAVE_NFS_ARGS_T_VERSION */
1379   print_nfs4_security(nap);
1380
1381   put_nfs_common_args(nap, a);
1382   print_nfs_common_args(&a);
1383 }
1384 #endif
1385 #endif /* HAVE_FS_NFS4 */
1386
1387 void
1388 compute_nfs_args(void *nap,
1389                  mntent_t *mntp,
1390                  int genflags,
1391                  struct netconfig *nfsncp,
1392                  struct sockaddr_in *ip_addr,
1393                  u_long nfs_version,
1394                  char *nfs_proto,
1395                  am_nfs_handle_t *fhp,
1396                  char *host_name,
1397                  char *fs_name)
1398 {
1399 #ifdef HAVE_FS_NFS4
1400   if (nfs_version == NFS_VERSION4)
1401     compute_nfs4_args(nap, mntp, genflags, nfsncp, ip_addr, nfs_version,
1402                       nfs_proto, fhp, host_name, fs_name);
1403   else
1404 #endif /* HAVE_FS_NFS4 */
1405     compute_nfs23_args(nap, mntp, genflags, nfsncp, ip_addr, nfs_version,
1406                        nfs_proto, fhp, host_name, fs_name);
1407 }
1408
1409 void
1410 discard_nfs_args(void *nap, u_long nfs_version)
1411 {
1412 #ifdef HAVE_FS_NFS4
1413   if (nfs_version == NFS_VERSION4)
1414     discard_nfs4_args(nap);
1415   else
1416 #endif /* HAVE_FS_NFS4 */
1417     discard_nfs23_args(nap);
1418 }
1419
1420 #ifdef DEBUG
1421 void
1422 print_nfs_args(const void *nap, u_long nfs_version)
1423 {
1424 #ifdef HAVE_FS_NFS4
1425   if (nfs_version == NFS_VERSION4)
1426     print_nfs4_args(nap, nfs_version);
1427   else
1428 #endif /* HAVE_FS_NFS4 */
1429     print_nfs23_args(nap, nfs_version);
1430 }
1431 #endif
1432
1433
1434 /*
1435  * Fill in special values for flags and fields of nfs_args, for an
1436  * automounter NFS mount.
1437  */
1438 void
1439 compute_automounter_nfs_args(nfs_args_t *nap, mntent_t *mntp)
1440 {
1441   struct nfs_common_args a;
1442
1443 #ifdef MNT2_NFS_OPT_SYMTTL
1444   /*
1445    * Don't let the kernel cache symbolic links we generate, or else lookups
1446    * will bypass amd and fail to remount stuff as needed.
1447    */
1448   plog(XLOG_INFO, "turning on NFS option symttl and setting value to 0");
1449   nap->flags |= MNT2_NFS_OPT_SYMTTL;
1450   nap->symttl = 0;
1451 #endif /* MNT2_NFS_OPT_SYMTTL */
1452
1453   /*
1454    * This completes the flags for the HIDE_MOUNT_TYPE  code in the
1455    * mount_amfs_toplvl() function in amd/amfs_toplvl.c.
1456    * Some systems don't have a mount type, but a mount flag.
1457    */
1458 #ifdef MNT2_NFS_OPT_AUTO
1459   nap->flags |= MNT2_NFS_OPT_AUTO;
1460 #endif /* MNT2_NFS_OPT_AUTO */
1461 #ifdef MNT2_NFS_OPT_IGNORE
1462   nap->flags |= MNT2_NFS_OPT_IGNORE;
1463 #endif /* MNT2_NFS_OPT_IGNORE */
1464 #ifdef MNT2_GEN_OPT_AUTOMNTFS
1465   nap->flags |= MNT2_GEN_OPT_AUTOMNTFS;
1466 #endif /* not MNT2_GEN_OPT_AUTOMNTFS */
1467
1468 #ifdef MNT2_NFS_OPT_DUMBTIMR
1469   /*
1470    * Don't let the kernel start computing throughput of Amd.  The numbers
1471    * will be meaningless because of the way Amd does mount retries.
1472    */
1473   plog(XLOG_INFO, "%s: disabling nfs congestion window", mntp->mnt_dir);
1474   nap->flags |= MNT2_NFS_OPT_DUMBTIMR;
1475 #endif /* MNT2_NFS_OPT_DUMBTIMR */
1476
1477   /* compute all of the NFS attribute-cache flags */
1478   memset(&a, 0, sizeof(a));
1479   a.flags = nap->flags;
1480   compute_nfs_attrcache_flags(&a, mntp);
1481   get_nfs_common_args(nap, a);
1482
1483   /*
1484    * Provide a slight bit more security by requiring the kernel to use
1485    * reserved ports.
1486    */
1487 #ifdef MNT2_NFS_OPT_RESVPORT
1488   nap->flags |= MNT2_NFS_OPT_RESVPORT;
1489 #endif /* MNT2_NFS_OPT_RESVPORT */
1490 }
1491
1492 int
1493 nfs_valid_version(u_long v)
1494 {
1495   return v >= NFS_VERS_MIN && v <= NFS_VERS_MAX;
1496 }