1/* $NetBSD: am_ops.c,v 1.1.1.2 2009/03/20 20:26:48 christos Exp $ */ 2 3/* 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. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Jan-Simon Pendry at Imperial College, London. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 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. 28 * 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 39 * SUCH DAMAGE. 40 * 41 * 42 * File: am-utils/amd/am_ops.c 43 * 44 */ 45 46#ifdef HAVE_CONFIG_H 47# include <config.h> 48#endif /* HAVE_CONFIG_H */ 49#include <am_defs.h> 50#include <amd.h> 51 52 53/* 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) 60 */ 61static am_ops *vops[] = 62{ 63#ifdef HAVE_FS_NFS 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 */ 69 70 /* 71 * Other amd-supported meta-filesystems. 72 */ 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 */ 91 92 /* 93 * A few more native filesystems. 94 */ 95#ifdef HAVE_FS_UFS 96 &ufs_ops, /* Unix F/S */ 97#endif /* HAVE_FS_UFS */ 98#ifdef HAVE_FS_XFS 99 &xfs_ops, /* Unix (irix) F/S */ 100#endif /* HAVE_FS_XFS */ 101#ifdef HAVE_FS_EFS 102 &efs_ops, /* Unix (irix) F/S */ 103#endif /* HAVE_FS_EFS */ 104#ifdef HAVE_FS_LOFS 105 &lofs_ops, /* loopback F/S */ 106#endif /* HAVE_FS_LOFS */ 107#ifdef HAVE_FS_CDFS 108 &cdfs_ops, /* CDROM/HSFS/ISO9960 F/S */ 109#endif /* HAVE_FS_CDFS */ 110#ifdef HAVE_FS_PCFS 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 */ 116#ifdef HAVE_FS_TMPFS 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 */ 128#ifdef HAVE_FS_UDF 129 &udf_ops, /* UDF F/S */ 130#endif /* HAVE_FS_UDF */ 131 132 /* 133 * These 4 should be last, in the order: 134 * (1) amfs_auto 135 * (2) amfs_direct 136 * (3) amfs_toplvl 137 * (4) amfs_error 138 */ 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 */ 151 0 152}; 153 154 155void 156ops_showamfstypes(char *buf, size_t l) 157{ 158 struct am_ops **ap; 159 int linesize = 0; 160 161 buf[0] = '\0'; 162 for (ap = vops; *ap; ap++) { 163 xstrlcat(buf, (*ap)->fs_type, l); 164 if (ap[1]) 165 xstrlcat(buf, ", ", l); 166 linesize += strlen((*ap)->fs_type) + 2; 167 if (linesize > 62) { 168 linesize = 0; 169 xstrlcat(buf, "\n ", l); 170 } 171 } 172} 173 174 175static void 176ops_show1(char *buf, size_t l, int *linesizep, const char *name) 177{ 178 xstrlcat(buf, name, l); 179 xstrlcat(buf, ", ", l); 180 *linesizep += strlen(name) + 2; 181 if (*linesizep > 60) { 182 xstrlcat(buf, "\t\n", l); 183 *linesizep = 0; 184 } 185} 186 187 188void 189ops_showfstypes(char *buf, size_t l) 190{ 191 int linesize = 0; 192 193 buf[0] = '\0'; 194 195#ifdef MNTTAB_TYPE_AUTOFS 196 ops_show1(buf, l, &linesize, MNTTAB_TYPE_AUTOFS); 197#endif /* MNTTAB_TYPE_AUTOFS */ 198 199#ifdef MNTTAB_TYPE_CACHEFS 200 ops_show1(buf, l, &linesize, MNTTAB_TYPE_CACHEFS); 201#endif /* MNTTAB_TYPE_CACHEFS */ 202 203#ifdef MNTTAB_TYPE_CDFS 204 ops_show1(buf, l, &linesize, MNTTAB_TYPE_CDFS); 205#endif /* MNTTAB_TYPE_CDFS */ 206 207#ifdef MNTTAB_TYPE_CFS 208 ops_show1(buf, l, &linesize, MNTTAB_TYPE_CFS); 209#endif /* MNTTAB_TYPE_CFS */ 210 211#ifdef MNTTAB_TYPE_LOFS 212 ops_show1(buf, l, &linesize, MNTTAB_TYPE_LOFS); 213#endif /* MNTTAB_TYPE_LOFS */ 214 215#ifdef MNTTAB_TYPE_EFS 216 ops_show1(buf, l, &linesize, MNTTAB_TYPE_EFS); 217#endif /* MNTTAB_TYPE_EFS */ 218 219#ifdef MNTTAB_TYPE_MFS 220 ops_show1(buf, l, &linesize, MNTTAB_TYPE_MFS); 221#endif /* MNTTAB_TYPE_MFS */ 222 223#ifdef MNTTAB_TYPE_NFS 224 ops_show1(buf, l, &linesize, MNTTAB_TYPE_NFS); 225#endif /* MNTTAB_TYPE_NFS */ 226 227#ifdef MNTTAB_TYPE_NFS3 228 ops_show1(buf, l, &linesize, "nfs3"); /* always hard-code as nfs3 */ 229#endif /* MNTTAB_TYPE_NFS3 */ 230 231#ifdef MNTTAB_TYPE_NULLFS 232 ops_show1(buf, l, &linesize, MNTTAB_TYPE_NULLFS); 233#endif /* MNTTAB_TYPE_NULLFS */ 234 235#ifdef MNTTAB_TYPE_PCFS 236 ops_show1(buf, l, &linesize, MNTTAB_TYPE_PCFS); 237#endif /* MNTTAB_TYPE_PCFS */ 238 239#ifdef MNTTAB_TYPE_TFS 240 ops_show1(buf, l, &linesize, MNTTAB_TYPE_TFS); 241#endif /* MNTTAB_TYPE_TFS */ 242 243#ifdef MNTTAB_TYPE_TMPFS 244 ops_show1(buf, l, &linesize, MNTTAB_TYPE_TMPFS); 245#endif /* MNTTAB_TYPE_TMPFS */ 246 247#ifdef MNTTAB_TYPE_UFS 248 ops_show1(buf, l, &linesize, MNTTAB_TYPE_UFS); 249#endif /* MNTTAB_TYPE_UFS */ 250 251#ifdef MNTTAB_TYPE_UMAPFS 252 ops_show1(buf, l, &linesize, MNTTAB_TYPE_UMAPFS); 253#endif /* MNTTAB_TYPE_UMAPFS */ 254 255#ifdef MNTTAB_TYPE_UNIONFS 256 ops_show1(buf, l, &linesize, MNTTAB_TYPE_UNIONFS); 257#endif /* MNTTAB_TYPE_UNIONFS */ 258 259#ifdef MNTTAB_TYPE_XFS 260 ops_show1(buf, l, &linesize, MNTTAB_TYPE_XFS); 261#endif /* MNTTAB_TYPE_XFS */ 262 263 /* terminate with a period, newline, and NULL */ 264 if (buf[strlen(buf)-1] == '\n') 265 buf[strlen(buf) - 4] = '\0'; 266 else 267 buf[strlen(buf) - 2] = '\0'; 268 xstrlcat(buf, ".\n", l); 269} 270 271 272/* 273 * return string option which is the reverse of opt. 274 * nosuid -> suid 275 * quota -> noquota 276 * ro -> rw 277 * etc. 278 * may return pointer to static buffer or subpointer within opt. 279 */ 280static char * 281reverse_option(const char *opt) 282{ 283 static char buf[80]; 284 285 /* sanity check */ 286 if (!opt) 287 return NULL; 288 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"; 297 298 /* check if string starts with 'no' and chop it */ 299 if (NSTREQ(opt, "no", 2)) { 300 xstrlcpy(buf, &opt[2], sizeof(buf)); 301 } else { 302 /* finally return a string prepended with 'no' */ 303 xstrlcpy(buf, "no", sizeof(buf)); 304 xstrlcat(buf, opt, sizeof(buf)); 305 } 306 return buf; 307} 308 309 310/* 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. 316 */ 317static char * 318merge_opts(const char *opts1, const char *opts2) 319{ 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 */ 328 329 /* initialization */ 330 mnt2.mnt_opts = (char *) opts2; 331 newstr = xmalloc(len); 332 newstr[0] = '\0'; 333 334 for (tmpstr = strtok(s1, ","); 335 tmpstr; 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))) 341 *eq = '\0'; 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)) 346 continue; 347 /* add option to returned string */ 348 if (newstr[0]) { 349 xstrlcat(newstr, ",", len); 350 xstrlcat(newstr, tmpstr, len); 351 } else { 352 xstrlcpy(newstr, tmpstr, len); 353 } 354 } 355 356 /* finally, append opts2 itself */ 357 if (newstr[0]) { 358 xstrlcat(newstr, ",", len); 359 xstrlcat(newstr, opts2, len); 360 } else { 361 xstrlcpy(newstr, opts2, len); 362 } 363 364 XFREE(s1); 365 return newstr; 366} 367 368 369am_ops * 370ops_search(char *type) 371{ 372 am_ops **vp; 373 am_ops *rop = NULL; 374 for (vp = vops; (rop = *vp); vp++) 375 if (STREQ(rop->fs_type, type)) 376 break; 377 return rop; 378} 379 380 381am_ops * 382ops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map) 383{ 384 am_ops *rop = NULL; 385 char *link_dir; 386 387 /* 388 * First crack the global opts and the local opts 389 */ 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; 395 } else { 396 /* 397 * Next find the correct filesystem type 398 */ 399 rop = ops_search(fo->opt_type); 400 if (!rop) { 401 plog(XLOG_USER, "fs type \"%s\" not recognized", fo->opt_type); 402 rop = &amfs_error_ops; 403 } 404 } 405 406 /* 407 * Make sure we have a default mount option. 408 * Otherwise skip past any leading '-'. 409 */ 410 if (fo->opt_opts == 0) 411 fo->opt_opts = strdup("rw,defaults"); 412 else if (*fo->opt_opts == '-') { 413 /* 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 417 */ 418 char *old = fo->opt_opts; 419 fo->opt_opts = strdup(old + 1); 420 XFREE(old); 421 } 422 423 /* 424 * If addopts option was used, then append it to the 425 * current options and remote mount options. 426 */ 427 if (fo->opt_addopts) { 428 if (STREQ(fo->opt_opts, fo->opt_remopts)) { 429 /* optimize things for the common case where opts==remopts */ 430 char *mergedstr; 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); 434 XFREE(fo->opt_opts); 435 XFREE(fo->opt_remopts); 436 fo->opt_opts = mergedstr; 437 fo->opt_remopts = strdup(mergedstr); 438 } else { 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); 443 XFREE(fo->opt_opts); 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; 450 } 451 } 452 453 /* 454 * Initialize opt_mount_type to "nfs", if it's not initialized already 455 */ 456 if (!fo->opt_mount_type) 457 fo->opt_mount_type = "nfs"; 458 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; 466 } 467 468 /* 469 * Check the filesystem is happy 470 */ 471 if (fo->fs_mtab) 472 XFREE(fo->fs_mtab); 473 474 fo->fs_mtab = rop->fs_match(fo); 475 if (fo->fs_mtab) 476 return rop; 477 478 /* 479 * Return error file system 480 */ 481 fo->fs_mtab = amfs_error_ops.fs_match(fo); 482 return &amfs_error_ops; 483} 484