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