4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1989 Jan-Simon Pendry
6 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1989 The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * File: am-utils/amd/am_ops.c
48 #endif /* HAVE_CONFIG_H */
54 * The order of these entries matters, since lookups in this table are done
55 * on a first-match basis. The entries below are a mixture of native
56 * filesystems supported by the OS (HAVE_FS_FOO), and some meta-filesystems
57 * supported by amd (HAVE_AMU_FS_FOO). The order is set here in expected
58 * match-hit such that more popular filesystems are listed first (nfs is the
59 * most popular, followed by a symlink F/S)
61 static am_ops
*vops
[] =
64 &nfs_ops
, /* network F/S (version 2) */
65 #endif /* HAVE_FS_NFS */
66 #ifdef HAVE_AMU_FS_LINK
67 &amfs_link_ops
, /* symlink F/S */
68 #endif /* HAVE_AMU_FS_LINK */
71 * Other amd-supported meta-filesystems.
73 #ifdef HAVE_AMU_FS_NFSX
74 &amfs_nfsx_ops
, /* multiple-nfs F/S */
75 #endif /* HAVE_AMU_FS_NFSX */
76 #ifdef HAVE_AMU_FS_NFSL
77 &amfs_nfsl_ops
, /* NFS with local link existence check */
78 #endif /* HAVE_AMU_FS_NFSL */
79 #ifdef HAVE_AMU_FS_HOST
80 &amfs_host_ops
, /* multiple exported nfs F/S */
81 #endif /* HAVE_AMU_FS_HOST */
82 #ifdef HAVE_AMU_FS_LINKX
83 &amfs_linkx_ops
, /* symlink F/S with link target verify */
84 #endif /* HAVE_AMU_FS_LINKX */
85 #ifdef HAVE_AMU_FS_PROGRAM
86 &amfs_program_ops
, /* program F/S */
87 #endif /* HAVE_AMU_FS_PROGRAM */
88 #ifdef HAVE_AMU_FS_UNION
89 &amfs_union_ops
, /* union F/S */
90 #endif /* HAVE_AMU_FS_UNION */
93 * A few more native filesystems.
96 &ufs_ops
, /* Unix F/S */
97 #endif /* HAVE_FS_UFS */
99 &xfs_ops
, /* Unix (irix) F/S */
100 #endif /* HAVE_FS_XFS */
102 &efs_ops
, /* Unix (irix) F/S */
103 #endif /* HAVE_FS_EFS */
105 &lofs_ops
, /* loopback F/S */
106 #endif /* HAVE_FS_LOFS */
108 &cdfs_ops
, /* CDROM/HSFS/ISO9960 F/S */
109 #endif /* HAVE_FS_CDFS */
111 &pcfs_ops
, /* Floppy/MSDOS F/S */
112 #endif /* HAVE_FS_PCFS */
113 #ifdef HAVE_FS_CACHEFS
114 &cachefs_ops
, /* caching F/S */
115 #endif /* HAVE_FS_CACHEFS */
117 &tmpfs_ops
, /* /tmp (in memory) F/S */
118 #endif /* HAVE_FS_TMPFS */
119 #ifdef HAVE_FS_NULLFS
120 /* FILL IN */ /* null (loopback) F/S */
121 #endif /* HAVE_FS_NULLFS */
122 #ifdef HAVE_FS_UNIONFS
123 /* FILL IN */ /* union (bsd44) F/S */
124 #endif /* HAVE_FS_UNIONFS */
125 #ifdef HAVE_FS_UMAPFS
126 /* FILL IN */ /* uid/gid mapping F/S */
127 #endif /* HAVE_FS_UMAPFS */
129 &udf_ops
, /* UDF F/S */
130 #endif /* HAVE_FS_UDF */
133 * These 4 should be last, in the order:
139 #ifdef HAVE_AMU_FS_AUTO
140 &amfs_auto_ops
, /* Automounter F/S */
141 #endif /* HAVE_AMU_FS_AUTO */
142 #ifdef HAVE_AMU_FS_DIRECT
143 &amfs_direct_ops
, /* direct-mount F/S */
144 #endif /* HAVE_AMU_FS_DIRECT */
145 #ifdef HAVE_AMU_FS_TOPLVL
146 &amfs_toplvl_ops
, /* top-level mount F/S */
147 #endif /* HAVE_AMU_FS_TOPLVL */
148 #ifdef HAVE_AMU_FS_ERROR
149 &amfs_error_ops
, /* error F/S */
150 #endif /* HAVE_AMU_FS_ERROR */
156 ops_showamfstypes(char *buf
, size_t l
)
162 for (ap
= vops
; *ap
; ap
++) {
163 xstrlcat(buf
, (*ap
)->fs_type
, l
);
165 xstrlcat(buf
, ", ", l
);
166 linesize
+= strlen((*ap
)->fs_type
) + 2;
169 xstrlcat(buf
, "\n ", l
);
176 ops_show1(char *buf
, size_t l
, int *linesizep
, const char *name
)
178 xstrlcat(buf
, name
, l
);
179 xstrlcat(buf
, ", ", l
);
180 *linesizep
+= strlen(name
) + 2;
181 if (*linesizep
> 60) {
182 xstrlcat(buf
, "\t\n", l
);
189 ops_showfstypes(char *buf
, size_t l
)
195 #ifdef MNTTAB_TYPE_AUTOFS
196 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_AUTOFS
);
197 #endif /* MNTTAB_TYPE_AUTOFS */
199 #ifdef MNTTAB_TYPE_CACHEFS
200 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_CACHEFS
);
201 #endif /* MNTTAB_TYPE_CACHEFS */
203 #ifdef MNTTAB_TYPE_CDFS
204 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_CDFS
);
205 #endif /* MNTTAB_TYPE_CDFS */
207 #ifdef MNTTAB_TYPE_CFS
208 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_CFS
);
209 #endif /* MNTTAB_TYPE_CFS */
211 #ifdef MNTTAB_TYPE_LOFS
212 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_LOFS
);
213 #endif /* MNTTAB_TYPE_LOFS */
215 #ifdef MNTTAB_TYPE_EFS
216 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_EFS
);
217 #endif /* MNTTAB_TYPE_EFS */
219 #ifdef MNTTAB_TYPE_MFS
220 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_MFS
);
221 #endif /* MNTTAB_TYPE_MFS */
223 #ifdef MNTTAB_TYPE_NFS
224 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_NFS
);
225 #endif /* MNTTAB_TYPE_NFS */
227 #ifdef MNTTAB_TYPE_NFS3
228 ops_show1(buf
, l
, &linesize
, "nfs3"); /* always hard-code as nfs3 */
229 #endif /* MNTTAB_TYPE_NFS3 */
231 #ifdef MNTTAB_TYPE_NULLFS
232 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_NULLFS
);
233 #endif /* MNTTAB_TYPE_NULLFS */
235 #ifdef MNTTAB_TYPE_PCFS
236 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_PCFS
);
237 #endif /* MNTTAB_TYPE_PCFS */
239 #ifdef MNTTAB_TYPE_TFS
240 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_TFS
);
241 #endif /* MNTTAB_TYPE_TFS */
243 #ifdef MNTTAB_TYPE_TMPFS
244 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_TMPFS
);
245 #endif /* MNTTAB_TYPE_TMPFS */
247 #ifdef MNTTAB_TYPE_UFS
248 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_UFS
);
249 #endif /* MNTTAB_TYPE_UFS */
251 #ifdef MNTTAB_TYPE_UMAPFS
252 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_UMAPFS
);
253 #endif /* MNTTAB_TYPE_UMAPFS */
255 #ifdef MNTTAB_TYPE_UNIONFS
256 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_UNIONFS
);
257 #endif /* MNTTAB_TYPE_UNIONFS */
259 #ifdef MNTTAB_TYPE_XFS
260 ops_show1(buf
, l
, &linesize
, MNTTAB_TYPE_XFS
);
261 #endif /* MNTTAB_TYPE_XFS */
263 /* terminate with a period, newline, and NULL */
264 if (buf
[strlen(buf
)-1] == '\n')
265 buf
[strlen(buf
) - 4] = '\0';
267 buf
[strlen(buf
) - 2] = '\0';
268 xstrlcat(buf
, ".\n", l
);
273 * return string option which is the reverse of opt.
278 * may return pointer to static buffer or subpointer within opt.
281 reverse_option(const char *opt
)
289 /* check special cases */
290 /* XXX: if this gets too long, rewrite the code more flexibly */
291 if (STREQ(opt
, "ro")) return "rw";
292 if (STREQ(opt
, "rw")) return "ro";
293 if (STREQ(opt
, "bg")) return "fg";
294 if (STREQ(opt
, "fg")) return "bg";
295 if (STREQ(opt
, "soft")) return "hard";
296 if (STREQ(opt
, "hard")) return "soft";
298 /* check if string starts with 'no' and chop it */
299 if (NSTREQ(opt
, "no", 2)) {
300 xstrlcpy(buf
, &opt
[2], sizeof(buf
));
302 /* finally return a string prepended with 'no' */
303 xstrlcpy(buf
, "no", sizeof(buf
));
304 xstrlcat(buf
, opt
, sizeof(buf
));
311 * start with an empty string. for each opts1 option that is not
312 * in opts2, add it to the string (make sure the reverse of it
313 * isn't in either). finally add opts2. return new string.
314 * Both opts1 and opts2 must not be null!
315 * Caller must eventually free the string being returned.
318 merge_opts(const char *opts1
, const char *opts2
)
320 mntent_t mnt2
; /* place holder for opts2 */
321 char *newstr
; /* new string to return (malloc'ed) */
322 char *tmpstr
; /* temp */
323 char *eq
; /* pointer to whatever follows '=' within temp */
324 char oneopt
[80]; /* one option w/o value if any */
325 char *revoneopt
; /* reverse of oneopt */
326 size_t len
= strlen(opts1
) + strlen(opts2
) + 2; /* space for "," and NULL */
327 char *s1
= strdup(opts1
); /* copy of opts1 to munge */
330 mnt2
.mnt_opts
= (char *) opts2
;
331 newstr
= xmalloc(len
);
334 for (tmpstr
= strtok(s1
, ",");
336 tmpstr
= strtok(NULL
, ",")) {
337 /* copy option to temp buffer */
338 xstrlcpy(oneopt
, tmpstr
, sizeof(oneopt
));
339 /* if option has a value such as rsize=1024, chop the value part */
340 if ((eq
= haseq(oneopt
)))
342 /* find reverse option of oneopt */
343 revoneopt
= reverse_option(oneopt
);
344 /* if option orits reverse exist in opts2, ignore it */
345 if (amu_hasmntopt(&mnt2
, oneopt
) || amu_hasmntopt(&mnt2
, revoneopt
))
347 /* add option to returned string */
349 xstrlcat(newstr
, ",", len
);
350 xstrlcat(newstr
, tmpstr
, len
);
352 xstrlcpy(newstr
, tmpstr
, len
);
356 /* finally, append opts2 itself */
358 xstrlcat(newstr
, ",", len
);
359 xstrlcat(newstr
, opts2
, len
);
361 xstrlcpy(newstr
, opts2
, len
);
370 ops_search(char *type
)
374 for (vp
= vops
; (rop
= *vp
); vp
++)
375 if (STREQ(rop
->fs_type
, type
))
382 ops_match(am_opts
*fo
, char *key
, char *g_key
, char *path
, char *keym
, char *map
)
388 * First crack the global opts and the local opts
390 if (!eval_fs_opts(fo
, key
, g_key
, path
, keym
, map
)) {
391 rop
= &amfs_error_ops
;
392 } else if (fo
->opt_type
== 0) {
393 plog(XLOG_USER
, "No fs type specified (key = \"%s\", map = \"%s\")", keym
, map
);
394 rop
= &amfs_error_ops
;
397 * Next find the correct filesystem type
399 rop
= ops_search(fo
->opt_type
);
401 plog(XLOG_USER
, "fs type \"%s\" not recognized", fo
->opt_type
);
402 rop
= &amfs_error_ops
;
407 * Make sure we have a default mount option.
408 * Otherwise skip past any leading '-'.
410 if (fo
->opt_opts
== 0)
411 fo
->opt_opts
= strdup("rw,defaults");
412 else if (*fo
->opt_opts
== '-') {
414 * We cannot simply do fo->opt_opts++ here since the opts
415 * module will try to free the pointer fo->opt_opts later.
416 * So just reallocate the thing -- stolcke 11/11/94
418 char *old
= fo
->opt_opts
;
419 fo
->opt_opts
= strdup(old
+ 1);
424 * If addopts option was used, then append it to the
425 * current options and remote mount options.
427 if (fo
->opt_addopts
) {
428 if (STREQ(fo
->opt_opts
, fo
->opt_remopts
)) {
429 /* optimize things for the common case where opts==remopts */
431 mergedstr
= merge_opts(fo
->opt_opts
, fo
->opt_addopts
);
432 plog(XLOG_INFO
, "merge rem/opts \"%s\" add \"%s\" => \"%s\"",
433 fo
->opt_opts
, fo
->opt_addopts
, mergedstr
);
435 XFREE(fo
->opt_remopts
);
436 fo
->opt_opts
= mergedstr
;
437 fo
->opt_remopts
= strdup(mergedstr
);
439 char *mergedstr
, *remmergedstr
;
440 mergedstr
= merge_opts(fo
->opt_opts
, fo
->opt_addopts
);
441 plog(XLOG_INFO
, "merge opts \"%s\" add \"%s\" => \"%s\"",
442 fo
->opt_opts
, fo
->opt_addopts
, mergedstr
);
444 fo
->opt_opts
= mergedstr
;
445 remmergedstr
= merge_opts(fo
->opt_remopts
, fo
->opt_addopts
);
446 plog(XLOG_INFO
, "merge remopts \"%s\" add \"%s\" => \"%s\"",
447 fo
->opt_remopts
, fo
->opt_addopts
, remmergedstr
);
448 XFREE(fo
->opt_remopts
);
449 fo
->opt_remopts
= remmergedstr
;
454 * Initialize opt_mount_type to "nfs", if it's not initialized already
456 if (!fo
->opt_mount_type
)
457 fo
->opt_mount_type
= "nfs";
459 /* Normalize the sublink and make it absolute */
460 link_dir
= fo
->opt_sublink
;
461 if (link_dir
&& link_dir
[0] && link_dir
[0] != '/') {
462 link_dir
= str3cat((char *) NULL
, fo
->opt_fs
, "/", link_dir
);
463 normalize_slash(link_dir
);
464 XFREE(fo
->opt_sublink
);
465 fo
->opt_sublink
= link_dir
;
469 * Check the filesystem is happy
474 fo
->fs_mtab
= rop
->fs_match(fo
);
479 * Return error file system
481 fo
->fs_mtab
= amfs_error_ops
.fs_match(fo
);
482 return &amfs_error_ops
;