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