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