xref: /netbsd-src/external/bsd/am-utils/dist/amd/am_ops.c (revision 8bae5d409deb915cf7c8f0539fae22ff2cb8a313)
1*8bae5d40Schristos /*	$NetBSD: am_ops.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $	*/
2a53f50b9Schristos 
3a53f50b9Schristos /*
4*8bae5d40Schristos  * Copyright (c) 1997-2014 Erez Zadok
5a53f50b9Schristos  * Copyright (c) 1989 Jan-Simon Pendry
6a53f50b9Schristos  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7a53f50b9Schristos  * Copyright (c) 1989 The Regents of the University of California.
8a53f50b9Schristos  * All rights reserved.
9a53f50b9Schristos  *
10a53f50b9Schristos  * This code is derived from software contributed to Berkeley by
11a53f50b9Schristos  * Jan-Simon Pendry at Imperial College, London.
12a53f50b9Schristos  *
13a53f50b9Schristos  * Redistribution and use in source and binary forms, with or without
14a53f50b9Schristos  * modification, are permitted provided that the following conditions
15a53f50b9Schristos  * are met:
16a53f50b9Schristos  * 1. Redistributions of source code must retain the above copyright
17a53f50b9Schristos  *    notice, this list of conditions and the following disclaimer.
18a53f50b9Schristos  * 2. Redistributions in binary form must reproduce the above copyright
19a53f50b9Schristos  *    notice, this list of conditions and the following disclaimer in the
20a53f50b9Schristos  *    documentation and/or other materials provided with the distribution.
21*8bae5d40Schristos  * 3. Neither the name of the University nor the names of its contributors
22a53f50b9Schristos  *    may be used to endorse or promote products derived from this software
23a53f50b9Schristos  *    without specific prior written permission.
24a53f50b9Schristos  *
25a53f50b9Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26a53f50b9Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27a53f50b9Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28a53f50b9Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29a53f50b9Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30a53f50b9Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31a53f50b9Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32a53f50b9Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33a53f50b9Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34a53f50b9Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35a53f50b9Schristos  * SUCH DAMAGE.
36a53f50b9Schristos  *
37a53f50b9Schristos  *
38a53f50b9Schristos  * File: am-utils/amd/am_ops.c
39a53f50b9Schristos  *
40a53f50b9Schristos  */
41a53f50b9Schristos 
42a53f50b9Schristos #ifdef HAVE_CONFIG_H
43a53f50b9Schristos # include <config.h>
44a53f50b9Schristos #endif /* HAVE_CONFIG_H */
45a53f50b9Schristos #include <am_defs.h>
46a53f50b9Schristos #include <amd.h>
47a53f50b9Schristos 
48a53f50b9Schristos 
49a53f50b9Schristos /*
50a53f50b9Schristos  * The order of these entries matters, since lookups in this table are done
51a53f50b9Schristos  * on a first-match basis.  The entries below are a mixture of native
52a53f50b9Schristos  * filesystems supported by the OS (HAVE_FS_FOO), and some meta-filesystems
53a53f50b9Schristos  * supported by amd (HAVE_AMU_FS_FOO).  The order is set here in expected
54a53f50b9Schristos  * match-hit such that more popular filesystems are listed first (nfs is the
55a53f50b9Schristos  * most popular, followed by a symlink F/S)
56a53f50b9Schristos  */
57a53f50b9Schristos static am_ops *vops[] =
58a53f50b9Schristos {
59a53f50b9Schristos #ifdef HAVE_FS_NFS
60a53f50b9Schristos   &nfs_ops,			/* network F/S (version 2) */
61a53f50b9Schristos #endif /* HAVE_FS_NFS */
62a53f50b9Schristos #ifdef HAVE_AMU_FS_LINK
63a53f50b9Schristos   &amfs_link_ops,		/* symlink F/S */
64a53f50b9Schristos #endif /* HAVE_AMU_FS_LINK */
65a53f50b9Schristos 
66a53f50b9Schristos   /*
67a53f50b9Schristos    * Other amd-supported meta-filesystems.
68a53f50b9Schristos    */
69a53f50b9Schristos #ifdef HAVE_AMU_FS_NFSX
70a53f50b9Schristos   &amfs_nfsx_ops,		/* multiple-nfs F/S */
71a53f50b9Schristos #endif /* HAVE_AMU_FS_NFSX */
72a53f50b9Schristos #ifdef HAVE_AMU_FS_NFSL
73a53f50b9Schristos   &amfs_nfsl_ops,		/* NFS with local link existence check */
74a53f50b9Schristos #endif /* HAVE_AMU_FS_NFSL */
75a53f50b9Schristos #ifdef HAVE_AMU_FS_HOST
76a53f50b9Schristos   &amfs_host_ops,		/* multiple exported nfs F/S */
77a53f50b9Schristos #endif /* HAVE_AMU_FS_HOST */
78a53f50b9Schristos #ifdef HAVE_AMU_FS_LINKX
79a53f50b9Schristos   &amfs_linkx_ops,		/* symlink F/S with link target verify */
80a53f50b9Schristos #endif /* HAVE_AMU_FS_LINKX */
81a53f50b9Schristos #ifdef HAVE_AMU_FS_PROGRAM
82a53f50b9Schristos   &amfs_program_ops,		/* program F/S */
83a53f50b9Schristos #endif /* HAVE_AMU_FS_PROGRAM */
84a53f50b9Schristos #ifdef HAVE_AMU_FS_UNION
85a53f50b9Schristos   &amfs_union_ops,		/* union F/S */
86a53f50b9Schristos #endif /* HAVE_AMU_FS_UNION */
87a53f50b9Schristos 
88a53f50b9Schristos   /*
89a53f50b9Schristos    * A few more native filesystems.
90a53f50b9Schristos    */
91a53f50b9Schristos #ifdef HAVE_FS_UFS
92a53f50b9Schristos   &ufs_ops,			/* Unix F/S */
93a53f50b9Schristos #endif /* HAVE_FS_UFS */
94a53f50b9Schristos #ifdef HAVE_FS_XFS
95a53f50b9Schristos   &xfs_ops,			/* Unix (irix) F/S */
96a53f50b9Schristos #endif /* HAVE_FS_XFS */
97*8bae5d40Schristos #ifdef HAVE_FS_EXT
98*8bae5d40Schristos   &ext2_ops,			/* Unix (linux) F/S */
99*8bae5d40Schristos   &ext3_ops,			/* Unix (linux) F/S */
100*8bae5d40Schristos   &ext4_ops,			/* Unix (linux) F/S */
101*8bae5d40Schristos #endif /* HAVE_FS_EXT */
102a53f50b9Schristos #ifdef HAVE_FS_EFS
103a53f50b9Schristos   &efs_ops,			/* Unix (irix) F/S */
104a53f50b9Schristos #endif /* HAVE_FS_EFS */
105a53f50b9Schristos #ifdef HAVE_FS_LOFS
106a53f50b9Schristos   &lofs_ops,			/* loopback F/S */
107a53f50b9Schristos #endif /* HAVE_FS_LOFS */
108a53f50b9Schristos #ifdef HAVE_FS_CDFS
109a53f50b9Schristos   &cdfs_ops,			/* CDROM/HSFS/ISO9960 F/S */
110a53f50b9Schristos #endif /* HAVE_FS_CDFS */
111a53f50b9Schristos #ifdef HAVE_FS_PCFS
112a53f50b9Schristos   &pcfs_ops,			/* Floppy/MSDOS F/S */
113a53f50b9Schristos #endif /* HAVE_FS_PCFS */
114a53f50b9Schristos #ifdef HAVE_FS_CACHEFS
115a53f50b9Schristos   &cachefs_ops,			/* caching F/S */
116a53f50b9Schristos #endif /* HAVE_FS_CACHEFS */
117a53f50b9Schristos #ifdef HAVE_FS_TMPFS
118a53f50b9Schristos   &tmpfs_ops,			/* /tmp (in memory) F/S */
119a53f50b9Schristos #endif /* HAVE_FS_TMPFS */
120a53f50b9Schristos #ifdef HAVE_FS_NULLFS
121a53f50b9Schristos /* FILL IN */			/* null (loopback) F/S */
122a53f50b9Schristos #endif /* HAVE_FS_NULLFS */
123a53f50b9Schristos #ifdef HAVE_FS_UNIONFS
124a53f50b9Schristos /* FILL IN */			/* union (bsd44) F/S */
125a53f50b9Schristos #endif /* HAVE_FS_UNIONFS */
126a53f50b9Schristos #ifdef HAVE_FS_UMAPFS
127a53f50b9Schristos /* FILL IN */			/* uid/gid mapping F/S */
128a53f50b9Schristos #endif /* HAVE_FS_UMAPFS */
1294bcd344eSchristos #ifdef HAVE_FS_UDF
1304bcd344eSchristos   &udf_ops,			/* UDF F/S */
1314bcd344eSchristos #endif /* HAVE_FS_UDF */
132*8bae5d40Schristos #ifdef HAVE_FS_LUSTRE
133*8bae5d40Schristos   &lustre_ops,			/* Lustre */
134*8bae5d40Schristos #endif /* HAVE_FS_LUSTRE */
135a53f50b9Schristos 
136a53f50b9Schristos   /*
137a53f50b9Schristos    * These 4 should be last, in the order:
138a53f50b9Schristos    *	(1) amfs_auto
139a53f50b9Schristos    *	(2) amfs_direct
140a53f50b9Schristos    *	(3) amfs_toplvl
141a53f50b9Schristos    *	(4) amfs_error
142a53f50b9Schristos    */
143a53f50b9Schristos #ifdef HAVE_AMU_FS_AUTO
144a53f50b9Schristos   &amfs_auto_ops,		/* Automounter F/S */
145a53f50b9Schristos #endif /* HAVE_AMU_FS_AUTO */
146a53f50b9Schristos #ifdef HAVE_AMU_FS_DIRECT
147a53f50b9Schristos   &amfs_direct_ops,		/* direct-mount F/S */
148a53f50b9Schristos #endif /* HAVE_AMU_FS_DIRECT */
149a53f50b9Schristos #ifdef HAVE_AMU_FS_TOPLVL
150a53f50b9Schristos   &amfs_toplvl_ops,		/* top-level mount F/S */
151a53f50b9Schristos #endif /* HAVE_AMU_FS_TOPLVL */
152a53f50b9Schristos #ifdef HAVE_AMU_FS_ERROR
153a53f50b9Schristos   &amfs_error_ops,		/* error F/S */
154a53f50b9Schristos #endif /* HAVE_AMU_FS_ERROR */
155a53f50b9Schristos   0
156a53f50b9Schristos };
157a53f50b9Schristos 
158a53f50b9Schristos 
159a53f50b9Schristos void
ops_showamfstypes(char * buf,size_t l)160a53f50b9Schristos ops_showamfstypes(char *buf, size_t l)
161a53f50b9Schristos {
162a53f50b9Schristos   struct am_ops **ap;
163a53f50b9Schristos   int linesize = 0;
164a53f50b9Schristos 
165a53f50b9Schristos   buf[0] = '\0';
166a53f50b9Schristos   for (ap = vops; *ap; ap++) {
167a53f50b9Schristos     xstrlcat(buf, (*ap)->fs_type, l);
168a53f50b9Schristos     if (ap[1])
169a53f50b9Schristos       xstrlcat(buf, ", ", l);
170a53f50b9Schristos     linesize += strlen((*ap)->fs_type) + 2;
171a53f50b9Schristos     if (linesize > 62) {
172a53f50b9Schristos       linesize = 0;
173a53f50b9Schristos       xstrlcat(buf, "\n      ", l);
174a53f50b9Schristos     }
175a53f50b9Schristos   }
176a53f50b9Schristos }
177a53f50b9Schristos 
178a53f50b9Schristos 
179a53f50b9Schristos static void
ops_show1(char * buf,size_t l,int * linesizep,const char * name)180a53f50b9Schristos ops_show1(char *buf, size_t l, int *linesizep, const char *name)
181a53f50b9Schristos {
182a53f50b9Schristos   xstrlcat(buf, name, l);
183a53f50b9Schristos   xstrlcat(buf, ", ", l);
184a53f50b9Schristos   *linesizep += strlen(name) + 2;
185a53f50b9Schristos   if (*linesizep > 60) {
186a53f50b9Schristos     xstrlcat(buf, "\t\n", l);
187a53f50b9Schristos     *linesizep = 0;
188a53f50b9Schristos   }
189a53f50b9Schristos }
190a53f50b9Schristos 
191a53f50b9Schristos 
192a53f50b9Schristos void
ops_showfstypes(char * buf,size_t l)193a53f50b9Schristos ops_showfstypes(char *buf, size_t l)
194a53f50b9Schristos {
195a53f50b9Schristos   int linesize = 0;
196a53f50b9Schristos 
197a53f50b9Schristos   buf[0] = '\0';
198a53f50b9Schristos 
199a53f50b9Schristos #ifdef MNTTAB_TYPE_AUTOFS
200a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_AUTOFS);
201a53f50b9Schristos #endif /* MNTTAB_TYPE_AUTOFS */
202a53f50b9Schristos 
203a53f50b9Schristos #ifdef MNTTAB_TYPE_CACHEFS
204a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_CACHEFS);
205a53f50b9Schristos #endif /* MNTTAB_TYPE_CACHEFS */
206a53f50b9Schristos 
207a53f50b9Schristos #ifdef MNTTAB_TYPE_CDFS
208a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_CDFS);
209a53f50b9Schristos #endif /* MNTTAB_TYPE_CDFS */
210a53f50b9Schristos 
211a53f50b9Schristos #ifdef MNTTAB_TYPE_CFS
212a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_CFS);
213a53f50b9Schristos #endif /* MNTTAB_TYPE_CFS */
214a53f50b9Schristos 
215a53f50b9Schristos #ifdef MNTTAB_TYPE_LOFS
216a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_LOFS);
217a53f50b9Schristos #endif /* MNTTAB_TYPE_LOFS */
218a53f50b9Schristos 
219a53f50b9Schristos #ifdef MNTTAB_TYPE_EFS
220a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_EFS);
221a53f50b9Schristos #endif /* MNTTAB_TYPE_EFS */
222a53f50b9Schristos 
223a53f50b9Schristos #ifdef MNTTAB_TYPE_MFS
224a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_MFS);
225a53f50b9Schristos #endif /* MNTTAB_TYPE_MFS */
226a53f50b9Schristos 
227a53f50b9Schristos #ifdef MNTTAB_TYPE_NFS
228a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_NFS);
229a53f50b9Schristos #endif /* MNTTAB_TYPE_NFS */
230a53f50b9Schristos 
231a53f50b9Schristos #ifdef MNTTAB_TYPE_NFS3
232a53f50b9Schristos   ops_show1(buf, l, &linesize, "nfs3"); /* always hard-code as nfs3 */
233a53f50b9Schristos #endif /* MNTTAB_TYPE_NFS3 */
234a53f50b9Schristos 
235a53f50b9Schristos #ifdef MNTTAB_TYPE_NULLFS
236a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_NULLFS);
237a53f50b9Schristos #endif /* MNTTAB_TYPE_NULLFS */
238a53f50b9Schristos 
239a53f50b9Schristos #ifdef MNTTAB_TYPE_PCFS
240a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_PCFS);
241a53f50b9Schristos #endif /* MNTTAB_TYPE_PCFS */
242a53f50b9Schristos 
243a53f50b9Schristos #ifdef MNTTAB_TYPE_TFS
244a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_TFS);
245a53f50b9Schristos #endif /* MNTTAB_TYPE_TFS */
246a53f50b9Schristos 
247a53f50b9Schristos #ifdef MNTTAB_TYPE_TMPFS
248a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_TMPFS);
249a53f50b9Schristos #endif /* MNTTAB_TYPE_TMPFS */
250a53f50b9Schristos 
251a53f50b9Schristos #ifdef MNTTAB_TYPE_UFS
252a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_UFS);
253a53f50b9Schristos #endif /* MNTTAB_TYPE_UFS */
254a53f50b9Schristos 
255a53f50b9Schristos #ifdef MNTTAB_TYPE_UMAPFS
256a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_UMAPFS);
257a53f50b9Schristos #endif /* MNTTAB_TYPE_UMAPFS */
258a53f50b9Schristos 
259a53f50b9Schristos #ifdef MNTTAB_TYPE_UNIONFS
260a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_UNIONFS);
261a53f50b9Schristos #endif /* MNTTAB_TYPE_UNIONFS */
262a53f50b9Schristos 
263a53f50b9Schristos #ifdef MNTTAB_TYPE_XFS
264a53f50b9Schristos   ops_show1(buf, l, &linesize, MNTTAB_TYPE_XFS);
265a53f50b9Schristos #endif /* MNTTAB_TYPE_XFS */
266a53f50b9Schristos 
267a53f50b9Schristos   /* terminate with a period, newline, and NULL */
268a53f50b9Schristos   if (buf[strlen(buf)-1] == '\n')
269a53f50b9Schristos     buf[strlen(buf) - 4] = '\0';
270a53f50b9Schristos   else
271a53f50b9Schristos     buf[strlen(buf) - 2] = '\0';
272a53f50b9Schristos   xstrlcat(buf, ".\n", l);
273a53f50b9Schristos }
274a53f50b9Schristos 
275a53f50b9Schristos 
276a53f50b9Schristos /*
277a53f50b9Schristos  * return string option which is the reverse of opt.
278a53f50b9Schristos  * nosuid -> suid
279a53f50b9Schristos  * quota -> noquota
280a53f50b9Schristos  * ro -> rw
281a53f50b9Schristos  * etc.
282a53f50b9Schristos  * may return pointer to static buffer or subpointer within opt.
283a53f50b9Schristos  */
284a53f50b9Schristos static char *
reverse_option(const char * opt)285a53f50b9Schristos reverse_option(const char *opt)
286a53f50b9Schristos {
287a53f50b9Schristos   static char buf[80];
288a53f50b9Schristos 
289a53f50b9Schristos   /* sanity check */
290a53f50b9Schristos   if (!opt)
291a53f50b9Schristos     return NULL;
292a53f50b9Schristos 
293a53f50b9Schristos   /* check special cases */
294a53f50b9Schristos   /* XXX: if this gets too long, rewrite the code more flexibly */
295a53f50b9Schristos   if (STREQ(opt, "ro")) return "rw";
296a53f50b9Schristos   if (STREQ(opt, "rw")) return "ro";
297a53f50b9Schristos   if (STREQ(opt, "bg")) return "fg";
298a53f50b9Schristos   if (STREQ(opt, "fg")) return "bg";
299a53f50b9Schristos   if (STREQ(opt, "soft")) return "hard";
300a53f50b9Schristos   if (STREQ(opt, "hard")) return "soft";
301a53f50b9Schristos 
302a53f50b9Schristos   /* check if string starts with 'no' and chop it */
303a53f50b9Schristos   if (NSTREQ(opt, "no", 2)) {
304a53f50b9Schristos     xstrlcpy(buf, &opt[2], sizeof(buf));
305a53f50b9Schristos   } else {
306a53f50b9Schristos     /* finally return a string prepended with 'no' */
307a53f50b9Schristos     xstrlcpy(buf, "no", sizeof(buf));
308a53f50b9Schristos     xstrlcat(buf, opt, sizeof(buf));
309a53f50b9Schristos   }
310a53f50b9Schristos   return buf;
311a53f50b9Schristos }
312a53f50b9Schristos 
313a53f50b9Schristos 
314a53f50b9Schristos /*
315a53f50b9Schristos  * start with an empty string. for each opts1 option that is not
316a53f50b9Schristos  * in opts2, add it to the string (make sure the reverse of it
317a53f50b9Schristos  * isn't in either). finally add opts2. return new string.
318a53f50b9Schristos  * Both opts1 and opts2 must not be null!
319a53f50b9Schristos  * Caller must eventually free the string being returned.
320a53f50b9Schristos  */
321a53f50b9Schristos static char *
merge_opts(const char * opts1,const char * opts2)322a53f50b9Schristos merge_opts(const char *opts1, const char *opts2)
323a53f50b9Schristos {
324a53f50b9Schristos   mntent_t mnt2;		/* place holder for opts2 */
325a53f50b9Schristos   char *newstr;			/* new string to return (malloc'ed) */
326a53f50b9Schristos   char *tmpstr;			/* temp */
327a53f50b9Schristos   char *eq;			/* pointer to whatever follows '=' within temp */
328a53f50b9Schristos   char oneopt[80];		/* one option w/o value if any */
329a53f50b9Schristos   char *revoneopt;		/* reverse of oneopt */
330a53f50b9Schristos   size_t len = strlen(opts1) + strlen(opts2) + 2; /* space for "," and NULL */
331*8bae5d40Schristos   char *s1 = xstrdup(opts1);	/* copy of opts1 to munge */
332a53f50b9Schristos 
333a53f50b9Schristos   /* initialization */
334a53f50b9Schristos   mnt2.mnt_opts = (char *) opts2;
335a53f50b9Schristos   newstr = xmalloc(len);
336a53f50b9Schristos   newstr[0] = '\0';
337a53f50b9Schristos 
338a53f50b9Schristos   for (tmpstr = strtok(s1, ",");
339a53f50b9Schristos        tmpstr;
340a53f50b9Schristos        tmpstr = strtok(NULL, ",")) {
341a53f50b9Schristos     /* copy option to temp buffer */
342a53f50b9Schristos     xstrlcpy(oneopt, tmpstr, sizeof(oneopt));
343a53f50b9Schristos     /* if option has a value such as rsize=1024, chop the value part */
344*8bae5d40Schristos     if ((eq = strchr(oneopt, '=')))
345a53f50b9Schristos       *eq = '\0';
346a53f50b9Schristos     /* find reverse option of oneopt */
347a53f50b9Schristos     revoneopt = reverse_option(oneopt);
348a53f50b9Schristos     /* if option or its reverse exist in opts2, ignore it */
349a53f50b9Schristos     if (amu_hasmntopt(&mnt2, oneopt) || amu_hasmntopt(&mnt2, revoneopt))
350a53f50b9Schristos       continue;
351a53f50b9Schristos     /* add option to returned string */
352a53f50b9Schristos     if (newstr[0]) {
353a53f50b9Schristos       xstrlcat(newstr, ",", len);
354a53f50b9Schristos       xstrlcat(newstr, tmpstr, len);
355a53f50b9Schristos     } else {
356a53f50b9Schristos       xstrlcpy(newstr, tmpstr, len);
357a53f50b9Schristos     }
358a53f50b9Schristos   }
359a53f50b9Schristos 
360a53f50b9Schristos   /* finally, append opts2 itself */
361a53f50b9Schristos   if (newstr[0]) {
362a53f50b9Schristos     xstrlcat(newstr, ",", len);
363a53f50b9Schristos     xstrlcat(newstr, opts2, len);
364a53f50b9Schristos   } else {
365a53f50b9Schristos     xstrlcpy(newstr, opts2, len);
366a53f50b9Schristos   }
367a53f50b9Schristos 
368a53f50b9Schristos   XFREE(s1);
369a53f50b9Schristos   return newstr;
370a53f50b9Schristos }
371a53f50b9Schristos 
372a53f50b9Schristos 
373a53f50b9Schristos am_ops *
ops_search(char * type)374a53f50b9Schristos ops_search(char *type)
375a53f50b9Schristos {
376a53f50b9Schristos   am_ops **vp;
377a53f50b9Schristos   am_ops *rop = NULL;
378a53f50b9Schristos   for (vp = vops; (rop = *vp); vp++)
379a53f50b9Schristos     if (STREQ(rop->fs_type, type))
380a53f50b9Schristos       break;
381a53f50b9Schristos   return rop;
382a53f50b9Schristos }
383a53f50b9Schristos 
384a53f50b9Schristos 
385a53f50b9Schristos am_ops *
ops_match(am_opts * fo,char * key,char * g_key,char * path,char * keym,char * map)386a53f50b9Schristos ops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map)
387a53f50b9Schristos {
388a53f50b9Schristos   am_ops *rop = NULL;
389a53f50b9Schristos   char *link_dir;
390a53f50b9Schristos 
391a53f50b9Schristos   /*
392a53f50b9Schristos    * First crack the global opts and the local opts
393a53f50b9Schristos    */
394a53f50b9Schristos   if (!eval_fs_opts(fo, key, g_key, path, keym, map)) {
395a53f50b9Schristos     rop = &amfs_error_ops;
396a53f50b9Schristos   } else if (fo->opt_type == 0) {
397a53f50b9Schristos     plog(XLOG_USER, "No fs type specified (key = \"%s\", map = \"%s\")", keym, map);
398a53f50b9Schristos     rop = &amfs_error_ops;
399a53f50b9Schristos   } else {
400a53f50b9Schristos     /*
401a53f50b9Schristos      * Next find the correct filesystem type
402a53f50b9Schristos      */
403a53f50b9Schristos     rop = ops_search(fo->opt_type);
404a53f50b9Schristos     if (!rop) {
405a53f50b9Schristos       plog(XLOG_USER, "fs type \"%s\" not recognized", fo->opt_type);
406a53f50b9Schristos       rop = &amfs_error_ops;
407a53f50b9Schristos     }
408a53f50b9Schristos   }
409a53f50b9Schristos 
410a53f50b9Schristos   /*
411a53f50b9Schristos    * Make sure we have a default mount option.
412a53f50b9Schristos    * Otherwise skip past any leading '-'.
413a53f50b9Schristos    */
414a53f50b9Schristos   if (fo->opt_opts == 0)
415*8bae5d40Schristos     fo->opt_opts = xstrdup("rw,defaults");
416a53f50b9Schristos   else if (*fo->opt_opts == '-') {
417a53f50b9Schristos     /*
418a53f50b9Schristos      * We cannot simply do fo->opt_opts++ here since the opts
419a53f50b9Schristos      * module will try to free the pointer fo->opt_opts later.
420a53f50b9Schristos      * So just reallocate the thing -- stolcke 11/11/94
421a53f50b9Schristos      */
422a53f50b9Schristos     char *old = fo->opt_opts;
423*8bae5d40Schristos     fo->opt_opts = xstrdup(old + 1);
424a53f50b9Schristos     XFREE(old);
425a53f50b9Schristos   }
426a53f50b9Schristos 
427a53f50b9Schristos   /*
428a53f50b9Schristos    * If addopts option was used, then append it to the
429a53f50b9Schristos    * current options and remote mount options.
430a53f50b9Schristos    */
431a53f50b9Schristos   if (fo->opt_addopts) {
432a53f50b9Schristos     if (STREQ(fo->opt_opts, fo->opt_remopts)) {
433a53f50b9Schristos       /* optimize things for the common case where opts==remopts */
434a53f50b9Schristos       char *mergedstr;
435a53f50b9Schristos       mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts);
436a53f50b9Schristos       plog(XLOG_INFO, "merge rem/opts \"%s\" add \"%s\" => \"%s\"",
437a53f50b9Schristos 	   fo->opt_opts, fo->opt_addopts, mergedstr);
438a53f50b9Schristos       XFREE(fo->opt_opts);
439a53f50b9Schristos       XFREE(fo->opt_remopts);
440a53f50b9Schristos       fo->opt_opts = mergedstr;
441*8bae5d40Schristos       fo->opt_remopts = xstrdup(mergedstr);
442a53f50b9Schristos     } else {
443a53f50b9Schristos       char *mergedstr, *remmergedstr;
444a53f50b9Schristos       mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts);
445a53f50b9Schristos       plog(XLOG_INFO, "merge opts \"%s\" add \"%s\" => \"%s\"",
446a53f50b9Schristos 	   fo->opt_opts, fo->opt_addopts, mergedstr);
447a53f50b9Schristos       XFREE(fo->opt_opts);
448a53f50b9Schristos       fo->opt_opts = mergedstr;
449a53f50b9Schristos       remmergedstr = merge_opts(fo->opt_remopts, fo->opt_addopts);
450a53f50b9Schristos       plog(XLOG_INFO, "merge remopts \"%s\" add \"%s\" => \"%s\"",
451a53f50b9Schristos 	   fo->opt_remopts, fo->opt_addopts, remmergedstr);
452a53f50b9Schristos       XFREE(fo->opt_remopts);
453a53f50b9Schristos       fo->opt_remopts = remmergedstr;
454a53f50b9Schristos     }
455a53f50b9Schristos   }
456a53f50b9Schristos 
457a53f50b9Schristos   /*
458a53f50b9Schristos    * Initialize opt_mount_type to "nfs", if it's not initialized already
459a53f50b9Schristos    */
460a53f50b9Schristos   if (!fo->opt_mount_type)
461a53f50b9Schristos     fo->opt_mount_type = "nfs";
462a53f50b9Schristos 
463a53f50b9Schristos   /* Normalize the sublink and make it absolute */
464a53f50b9Schristos   link_dir = fo->opt_sublink;
465a53f50b9Schristos   if (link_dir && link_dir[0] && link_dir[0] != '/') {
466a53f50b9Schristos     link_dir = str3cat((char *) NULL, fo->opt_fs, "/", link_dir);
467a53f50b9Schristos     normalize_slash(link_dir);
468a53f50b9Schristos     XFREE(fo->opt_sublink);
469a53f50b9Schristos     fo->opt_sublink = link_dir;
470a53f50b9Schristos   }
471a53f50b9Schristos 
472a53f50b9Schristos   /*
473a53f50b9Schristos    * Check the filesystem is happy
474a53f50b9Schristos    */
475a53f50b9Schristos   XFREE(fo->fs_mtab);
476a53f50b9Schristos 
477a53f50b9Schristos   fo->fs_mtab = rop->fs_match(fo);
478a53f50b9Schristos   if (fo->fs_mtab)
479a53f50b9Schristos     return rop;
480a53f50b9Schristos 
481a53f50b9Schristos   /*
482a53f50b9Schristos    * Return error file system
483a53f50b9Schristos    */
484a53f50b9Schristos   fo->fs_mtab = amfs_error_ops.fs_match(fo);
485a53f50b9Schristos   return &amfs_error_ops;
486a53f50b9Schristos }
487