138494Sobrien/* 2174294Sobrien * Copyright (c) 1997-2006 Erez Zadok 338494Sobrien * Copyright (c) 1989 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1989 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1989 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 1938494Sobrien * 3. All advertising materials mentioning features or use of this software 2042629Sobrien * must display the following acknowledgment: 2138494Sobrien * This product includes software developed by the University of 2238494Sobrien * California, Berkeley and its contributors. 2338494Sobrien * 4. Neither the name of the University nor the names of its contributors 2438494Sobrien * may be used to endorse or promote products derived from this software 2538494Sobrien * without specific prior written permission. 2638494Sobrien * 2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3038494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3738494Sobrien * SUCH DAMAGE. 3838494Sobrien * 3938494Sobrien * 40174294Sobrien * File: am-utils/amd/am_ops.c 4138494Sobrien * 4238494Sobrien */ 4338494Sobrien 4438494Sobrien#ifdef HAVE_CONFIG_H 4538494Sobrien# include <config.h> 4638494Sobrien#endif /* HAVE_CONFIG_H */ 4738494Sobrien#include <am_defs.h> 4838494Sobrien#include <amd.h> 4938494Sobrien 5038494Sobrien 5138494Sobrien/* 5238494Sobrien * The order of these entries matters, since lookups in this table are done 5338494Sobrien * on a first-match basis. The entries below are a mixture of native 5438494Sobrien * filesystems supported by the OS (HAVE_FS_FOO), and some meta-filesystems 5582794Sobrien * supported by amd (HAVE_AMU_FS_FOO). The order is set here in expected 5638494Sobrien * match-hit such that more popular filesystems are listed first (nfs is the 5738494Sobrien * most popular, followed by a symlink F/S) 5838494Sobrien */ 5938494Sobrienstatic am_ops *vops[] = 6038494Sobrien{ 6138494Sobrien#ifdef HAVE_FS_NFS 6238494Sobrien &nfs_ops, /* network F/S (version 2) */ 6338494Sobrien#endif /* HAVE_FS_NFS */ 6482794Sobrien#ifdef HAVE_AMU_FS_LINK 6538494Sobrien &amfs_link_ops, /* symlink F/S */ 6682794Sobrien#endif /* HAVE_AMU_FS_LINK */ 6738494Sobrien 6838494Sobrien /* 6938494Sobrien * Other amd-supported meta-filesystems. 7038494Sobrien */ 7182794Sobrien#ifdef HAVE_AMU_FS_NFSX 7238494Sobrien &amfs_nfsx_ops, /* multiple-nfs F/S */ 7382794Sobrien#endif /* HAVE_AMU_FS_NFSX */ 7482794Sobrien#ifdef HAVE_AMU_FS_NFSL 7538494Sobrien &amfs_nfsl_ops, /* NFS with local link existence check */ 7682794Sobrien#endif /* HAVE_AMU_FS_NFSL */ 7782794Sobrien#ifdef HAVE_AMU_FS_HOST 7838494Sobrien &amfs_host_ops, /* multiple exported nfs F/S */ 7982794Sobrien#endif /* HAVE_AMU_FS_HOST */ 8082794Sobrien#ifdef HAVE_AMU_FS_LINKX 8138494Sobrien &amfs_linkx_ops, /* symlink F/S with link target verify */ 8282794Sobrien#endif /* HAVE_AMU_FS_LINKX */ 8382794Sobrien#ifdef HAVE_AMU_FS_PROGRAM 8438494Sobrien &amfs_program_ops, /* program F/S */ 8582794Sobrien#endif /* HAVE_AMU_FS_PROGRAM */ 8682794Sobrien#ifdef HAVE_AMU_FS_UNION 8738494Sobrien &amfs_union_ops, /* union F/S */ 8882794Sobrien#endif /* HAVE_AMU_FS_UNION */ 8938494Sobrien 9038494Sobrien /* 9138494Sobrien * A few more native filesystems. 9238494Sobrien */ 9338494Sobrien#ifdef HAVE_FS_UFS 9438494Sobrien &ufs_ops, /* Unix F/S */ 9538494Sobrien#endif /* HAVE_FS_UFS */ 9638494Sobrien#ifdef HAVE_FS_XFS 9738494Sobrien &xfs_ops, /* Unix (irix) F/S */ 9838494Sobrien#endif /* HAVE_FS_XFS */ 9938494Sobrien#ifdef HAVE_FS_EFS 10038494Sobrien &efs_ops, /* Unix (irix) F/S */ 10138494Sobrien#endif /* HAVE_FS_EFS */ 10238494Sobrien#ifdef HAVE_FS_LOFS 10338494Sobrien &lofs_ops, /* loopback F/S */ 10438494Sobrien#endif /* HAVE_FS_LOFS */ 10538494Sobrien#ifdef HAVE_FS_CDFS 10638494Sobrien &cdfs_ops, /* CDROM/HSFS/ISO9960 F/S */ 10738494Sobrien#endif /* HAVE_FS_CDFS */ 10838494Sobrien#ifdef HAVE_FS_PCFS 10938494Sobrien &pcfs_ops, /* Floppy/MSDOS F/S */ 11038494Sobrien#endif /* HAVE_FS_PCFS */ 11138494Sobrien#ifdef HAVE_FS_CACHEFS 11238494Sobrien &cachefs_ops, /* caching F/S */ 11338494Sobrien#endif /* HAVE_FS_CACHEFS */ 11438494Sobrien#ifdef HAVE_FS_NULLFS 11538494Sobrien/* FILL IN */ /* null (loopback) F/S */ 11638494Sobrien#endif /* HAVE_FS_NULLFS */ 11738494Sobrien#ifdef HAVE_FS_UNIONFS 11838494Sobrien/* FILL IN */ /* union (bsd44) F/S */ 11938494Sobrien#endif /* HAVE_FS_UNIONFS */ 12038494Sobrien#ifdef HAVE_FS_UMAPFS 12138494Sobrien/* FILL IN */ /* uid/gid mapping F/S */ 12238494Sobrien#endif /* HAVE_FS_UMAPFS */ 12338494Sobrien 12438494Sobrien /* 125174294Sobrien * These 4 should be last, in the order: 12638494Sobrien * (1) amfs_auto 12738494Sobrien * (2) amfs_direct 12838494Sobrien * (3) amfs_toplvl 129119679Smbr * (4) amfs_error 13038494Sobrien */ 13182794Sobrien#ifdef HAVE_AMU_FS_AUTO 13238494Sobrien &amfs_auto_ops, /* Automounter F/S */ 13382794Sobrien#endif /* HAVE_AMU_FS_AUTO */ 13482794Sobrien#ifdef HAVE_AMU_FS_DIRECT 13538494Sobrien &amfs_direct_ops, /* direct-mount F/S */ 13682794Sobrien#endif /* HAVE_AMU_FS_DIRECT */ 13782794Sobrien#ifdef HAVE_AMU_FS_TOPLVL 13838494Sobrien &amfs_toplvl_ops, /* top-level mount F/S */ 13982794Sobrien#endif /* HAVE_AMU_FS_TOPLVL */ 14082794Sobrien#ifdef HAVE_AMU_FS_ERROR 14138494Sobrien &amfs_error_ops, /* error F/S */ 14282794Sobrien#endif /* HAVE_AMU_FS_ERROR */ 14338494Sobrien 0 14438494Sobrien}; 14538494Sobrien 14638494Sobrien 14738494Sobrienvoid 148174294Sobrienops_showamfstypes(char *buf, size_t l) 14938494Sobrien{ 15038494Sobrien struct am_ops **ap; 151174294Sobrien int linesize = 0; 15238494Sobrien 15338494Sobrien buf[0] = '\0'; 15438494Sobrien for (ap = vops; *ap; ap++) { 155174294Sobrien xstrlcat(buf, (*ap)->fs_type, l); 15638494Sobrien if (ap[1]) 157174294Sobrien xstrlcat(buf, ", ", l); 158174294Sobrien linesize += strlen((*ap)->fs_type) + 2; 159174294Sobrien if (linesize > 62) { 160174294Sobrien linesize = 0; 161174294Sobrien xstrlcat(buf, "\n ", l); 16238494Sobrien } 16338494Sobrien } 16438494Sobrien} 16538494Sobrien 16638494Sobrien 16738494Sobrienstatic void 168174294Sobrienops_show1(char *buf, size_t l, int *linesizep, const char *name) 16938494Sobrien{ 170174294Sobrien xstrlcat(buf, name, l); 171174294Sobrien xstrlcat(buf, ", ", l); 172174294Sobrien *linesizep += strlen(name) + 2; 173174294Sobrien if (*linesizep > 60) { 174174294Sobrien xstrlcat(buf, "\t\n", l); 175174294Sobrien *linesizep = 0; 17638494Sobrien } 17738494Sobrien} 17838494Sobrien 17938494Sobrien 18038494Sobrienvoid 181174294Sobrienops_showfstypes(char *buf, size_t l) 18238494Sobrien{ 183174294Sobrien int linesize = 0; 18438494Sobrien 18538494Sobrien buf[0] = '\0'; 18638494Sobrien 187174294Sobrien#ifdef MNTTAB_TYPE_AUTOFS 188174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_AUTOFS); 189174294Sobrien#endif /* MNTTAB_TYPE_AUTOFS */ 190174294Sobrien 19138494Sobrien#ifdef MNTTAB_TYPE_CACHEFS 192174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_CACHEFS); 19338494Sobrien#endif /* MNTTAB_TYPE_CACHEFS */ 19438494Sobrien 19538494Sobrien#ifdef MNTTAB_TYPE_CDFS 196174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_CDFS); 19738494Sobrien#endif /* MNTTAB_TYPE_CDFS */ 19838494Sobrien 19938494Sobrien#ifdef MNTTAB_TYPE_CFS 200174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_CFS); 20138494Sobrien#endif /* MNTTAB_TYPE_CFS */ 20238494Sobrien 20338494Sobrien#ifdef MNTTAB_TYPE_LOFS 204174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_LOFS); 20538494Sobrien#endif /* MNTTAB_TYPE_LOFS */ 20638494Sobrien 20738494Sobrien#ifdef MNTTAB_TYPE_EFS 208174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_EFS); 20938494Sobrien#endif /* MNTTAB_TYPE_EFS */ 21038494Sobrien 21138494Sobrien#ifdef MNTTAB_TYPE_MFS 212174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_MFS); 21338494Sobrien#endif /* MNTTAB_TYPE_MFS */ 21438494Sobrien 21538494Sobrien#ifdef MNTTAB_TYPE_NFS 216174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_NFS); 21738494Sobrien#endif /* MNTTAB_TYPE_NFS */ 21838494Sobrien 21938494Sobrien#ifdef MNTTAB_TYPE_NFS3 220174294Sobrien ops_show1(buf, l, &linesize, "nfs3"); /* always hard-code as nfs3 */ 22138494Sobrien#endif /* MNTTAB_TYPE_NFS3 */ 22238494Sobrien 22338494Sobrien#ifdef MNTTAB_TYPE_NULLFS 224174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_NULLFS); 22538494Sobrien#endif /* MNTTAB_TYPE_NULLFS */ 22638494Sobrien 22738494Sobrien#ifdef MNTTAB_TYPE_PCFS 228174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_PCFS); 22938494Sobrien#endif /* MNTTAB_TYPE_PCFS */ 23038494Sobrien 23138494Sobrien#ifdef MNTTAB_TYPE_TFS 232174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_TFS); 23338494Sobrien#endif /* MNTTAB_TYPE_TFS */ 23438494Sobrien 23538494Sobrien#ifdef MNTTAB_TYPE_TMPFS 236174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_TMPFS); 23738494Sobrien#endif /* MNTTAB_TYPE_TMPFS */ 23838494Sobrien 23938494Sobrien#ifdef MNTTAB_TYPE_UFS 240174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_UFS); 24138494Sobrien#endif /* MNTTAB_TYPE_UFS */ 24238494Sobrien 24338494Sobrien#ifdef MNTTAB_TYPE_UMAPFS 244174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_UMAPFS); 24538494Sobrien#endif /* MNTTAB_TYPE_UMAPFS */ 24638494Sobrien 24738494Sobrien#ifdef MNTTAB_TYPE_UNIONFS 248174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_UNIONFS); 24938494Sobrien#endif /* MNTTAB_TYPE_UNIONFS */ 25038494Sobrien 25138494Sobrien#ifdef MNTTAB_TYPE_XFS 252174294Sobrien ops_show1(buf, l, &linesize, MNTTAB_TYPE_XFS); 25338494Sobrien#endif /* MNTTAB_TYPE_XFS */ 25438494Sobrien 25538494Sobrien /* terminate with a period, newline, and NULL */ 25638494Sobrien if (buf[strlen(buf)-1] == '\n') 25738494Sobrien buf[strlen(buf) - 4] = '\0'; 25838494Sobrien else 25938494Sobrien buf[strlen(buf) - 2] = '\0'; 260174294Sobrien xstrlcat(buf, ".\n", l); 26138494Sobrien} 26238494Sobrien 26338494Sobrien 26438494Sobrien/* 26538494Sobrien * return string option which is the reverse of opt. 26638494Sobrien * nosuid -> suid 26738494Sobrien * quota -> noquota 26838494Sobrien * ro -> rw 26938494Sobrien * etc. 27038494Sobrien * may return pointer to static buffer or subpointer within opt. 27138494Sobrien */ 27238494Sobrienstatic char * 27338494Sobrienreverse_option(const char *opt) 27438494Sobrien{ 27538494Sobrien static char buf[80]; 27638494Sobrien 27738494Sobrien /* sanity check */ 27838494Sobrien if (!opt) 27938494Sobrien return NULL; 28038494Sobrien 28138494Sobrien /* check special cases */ 28238494Sobrien /* XXX: if this gets too long, rewrite the code more flexibly */ 28338494Sobrien if (STREQ(opt, "ro")) return "rw"; 28438494Sobrien if (STREQ(opt, "rw")) return "ro"; 28538494Sobrien if (STREQ(opt, "bg")) return "fg"; 28638494Sobrien if (STREQ(opt, "fg")) return "bg"; 28738494Sobrien if (STREQ(opt, "soft")) return "hard"; 28838494Sobrien if (STREQ(opt, "hard")) return "soft"; 28938494Sobrien 29038494Sobrien /* check if string starts with 'no' and chop it */ 29138494Sobrien if (NSTREQ(opt, "no", 2)) { 292174294Sobrien xstrlcpy(buf, &opt[2], sizeof(buf)); 29338494Sobrien } else { 29438494Sobrien /* finally return a string prepended with 'no' */ 295174294Sobrien xstrlcpy(buf, "no", sizeof(buf)); 296174294Sobrien xstrlcat(buf, opt, sizeof(buf)); 29738494Sobrien } 29838494Sobrien return buf; 29938494Sobrien} 30038494Sobrien 30138494Sobrien 30238494Sobrien/* 30338494Sobrien * start with an empty string. for each opts1 option that is not 30438494Sobrien * in opts2, add it to the string (make sure the reverse of it 30538494Sobrien * isn't in either). finally add opts2. return new string. 30638494Sobrien * Both opts1 and opts2 must not be null! 30738494Sobrien * Caller must eventually free the string being returned. 30838494Sobrien */ 30938494Sobrienstatic char * 31042629Sobrienmerge_opts(const char *opts1, const char *opts2) 31138494Sobrien{ 31238494Sobrien mntent_t mnt2; /* place holder for opts2 */ 31338494Sobrien char *newstr; /* new string to return (malloc'ed) */ 31438494Sobrien char *tmpstr; /* temp */ 31582794Sobrien char *eq; /* pointer to whatever follows '=' within temp */ 31638494Sobrien char oneopt[80]; /* one option w/o value if any */ 31738494Sobrien char *revoneopt; /* reverse of oneopt */ 318174294Sobrien size_t len = strlen(opts1) + strlen(opts2) + 2; /* space for "," and NULL */ 31938494Sobrien char *s1 = strdup(opts1); /* copy of opts1 to munge */ 32038494Sobrien 32138494Sobrien /* initialization */ 32242629Sobrien mnt2.mnt_opts = (char *) opts2; 32338494Sobrien newstr = xmalloc(len); 32438494Sobrien newstr[0] = '\0'; 32538494Sobrien 32638494Sobrien for (tmpstr = strtok(s1, ","); 32738494Sobrien tmpstr; 32838494Sobrien tmpstr = strtok(NULL, ",")) { 32938494Sobrien /* copy option to temp buffer */ 330174294Sobrien xstrlcpy(oneopt, tmpstr, 80); 33138494Sobrien /* if option has a value such as rsize=1024, chop the value part */ 33282794Sobrien if ((eq = haseq(oneopt))) 33382794Sobrien *eq = '\0'; 33438494Sobrien /* find reverse option of oneopt */ 33538494Sobrien revoneopt = reverse_option(oneopt); 33638494Sobrien /* if option orits reverse exist in opts2, ignore it */ 337174294Sobrien if (amu_hasmntopt(&mnt2, oneopt) || amu_hasmntopt(&mnt2, revoneopt)) 33838494Sobrien continue; 33938494Sobrien /* add option to returned string */ 340174294Sobrien if (newstr[0]) { 341174294Sobrien xstrlcat(newstr, ",", len); 342174294Sobrien xstrlcat(newstr, tmpstr, len); 34338494Sobrien } else { 344174294Sobrien xstrlcpy(newstr, tmpstr, len); 34538494Sobrien } 34638494Sobrien } 34738494Sobrien 34838494Sobrien /* finally, append opts2 itself */ 349174294Sobrien if (newstr[0]) { 350174294Sobrien xstrlcat(newstr, ",", len); 351174294Sobrien xstrlcat(newstr, opts2, len); 35238494Sobrien } else { 353174294Sobrien xstrlcpy(newstr, opts2, len); 35438494Sobrien } 35538494Sobrien 35638494Sobrien XFREE(s1); 35738494Sobrien return newstr; 35838494Sobrien} 35938494Sobrien 36038494Sobrien 36138494Sobrienam_ops * 362174294Sobrienops_search(char *type) 36338494Sobrien{ 36438494Sobrien am_ops **vp; 36538494Sobrien am_ops *rop = 0; 366174294Sobrien for (vp = vops; (rop = *vp); vp++) 367174294Sobrien if (STREQ(rop->fs_type, type)) 368174294Sobrien break; 369174294Sobrien return rop; 370174294Sobrien} 37138494Sobrien 372174294Sobrien 373174294Sobrienam_ops * 374174294Sobrienops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map) 375174294Sobrien{ 376174294Sobrien am_ops *rop = 0; 377174294Sobrien char *link_dir; 378174294Sobrien 37938494Sobrien /* 38038494Sobrien * First crack the global opts and the local opts 38138494Sobrien */ 38238494Sobrien if (!eval_fs_opts(fo, key, g_key, path, keym, map)) { 38338494Sobrien rop = &amfs_error_ops; 38438494Sobrien } else if (fo->opt_type == 0) { 38538494Sobrien plog(XLOG_USER, "No fs type specified (key = \"%s\", map = \"%s\")", keym, map); 38638494Sobrien rop = &amfs_error_ops; 38738494Sobrien } else { 38838494Sobrien /* 38938494Sobrien * Next find the correct filesystem type 39038494Sobrien */ 391174294Sobrien rop = ops_search(fo->opt_type); 39238494Sobrien if (!rop) { 39338494Sobrien plog(XLOG_USER, "fs type \"%s\" not recognized", fo->opt_type); 39438494Sobrien rop = &amfs_error_ops; 39538494Sobrien } 39638494Sobrien } 39738494Sobrien 39838494Sobrien /* 39938494Sobrien * Make sure we have a default mount option. 40038494Sobrien * Otherwise skip past any leading '-'. 40138494Sobrien */ 40238494Sobrien if (fo->opt_opts == 0) 40338494Sobrien fo->opt_opts = strdup("rw,defaults"); 40438494Sobrien else if (*fo->opt_opts == '-') { 40538494Sobrien /* 40638494Sobrien * We cannot simply do fo->opt_opts++ here since the opts 40738494Sobrien * module will try to free the pointer fo->opt_opts later. 40838494Sobrien * So just reallocate the thing -- stolcke 11/11/94 40938494Sobrien */ 41038494Sobrien char *old = fo->opt_opts; 41138494Sobrien fo->opt_opts = strdup(old + 1); 41238494Sobrien XFREE(old); 41338494Sobrien } 41438494Sobrien 41538494Sobrien /* 41638494Sobrien * If addopts option was used, then append it to the 41751292Sobrien * current options and remote mount options. 41838494Sobrien */ 41938494Sobrien if (fo->opt_addopts) { 42051292Sobrien if (STREQ(fo->opt_opts, fo->opt_remopts)) { 42151292Sobrien /* optimize things for the common case where opts==remopts */ 42251292Sobrien char *mergedstr; 42351292Sobrien mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts); 42482794Sobrien plog(XLOG_INFO, "merge rem/opts \"%s\" add \"%s\" => \"%s\"", 42551292Sobrien fo->opt_opts, fo->opt_addopts, mergedstr); 42651292Sobrien XFREE(fo->opt_opts); 42751292Sobrien XFREE(fo->opt_remopts); 42851292Sobrien fo->opt_opts = mergedstr; 42951292Sobrien fo->opt_remopts = strdup(mergedstr); 43051292Sobrien } else { 43151292Sobrien char *mergedstr, *remmergedstr; 43251292Sobrien mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts); 43382794Sobrien plog(XLOG_INFO, "merge opts \"%s\" add \"%s\" => \"%s\"", 43451292Sobrien fo->opt_opts, fo->opt_addopts, mergedstr); 43551292Sobrien XFREE(fo->opt_opts); 43651292Sobrien fo->opt_opts = mergedstr; 43751292Sobrien remmergedstr = merge_opts(fo->opt_remopts, fo->opt_addopts); 43882794Sobrien plog(XLOG_INFO, "merge remopts \"%s\" add \"%s\" => \"%s\"", 43951292Sobrien fo->opt_remopts, fo->opt_addopts, remmergedstr); 44051292Sobrien XFREE(fo->opt_remopts); 44151292Sobrien fo->opt_remopts = remmergedstr; 44251292Sobrien } 44338494Sobrien } 44438494Sobrien 44538494Sobrien /* 446174294Sobrien * Initialize opt_mount_type to "nfs", if it's not initialized already 447174294Sobrien */ 448174294Sobrien if (!fo->opt_mount_type) 449174294Sobrien fo->opt_mount_type = "nfs"; 450174294Sobrien 451174294Sobrien /* Normalize the sublink and make it absolute */ 452174294Sobrien link_dir = fo->opt_sublink; 453174294Sobrien if (link_dir && link_dir[0] && link_dir[0] != '/') { 454174294Sobrien link_dir = str3cat((char *) 0, fo->opt_fs, "/", link_dir); 455174294Sobrien normalize_slash(link_dir); 456174294Sobrien XFREE(fo->opt_sublink); 457174294Sobrien fo->opt_sublink = link_dir; 458174294Sobrien } 459174294Sobrien 460174294Sobrien /* 46138494Sobrien * Check the filesystem is happy 46238494Sobrien */ 46338494Sobrien if (fo->fs_mtab) 46438494Sobrien XFREE(fo->fs_mtab); 46538494Sobrien 466174294Sobrien fo->fs_mtab = rop->fs_match(fo); 467174294Sobrien if (fo->fs_mtab) 46838494Sobrien return rop; 46938494Sobrien 47038494Sobrien /* 47138494Sobrien * Return error file system 47238494Sobrien */ 473174294Sobrien fo->fs_mtab = amfs_error_ops.fs_match(fo); 47438494Sobrien return &amfs_error_ops; 47538494Sobrien} 476