1 /* $NetBSD: am_ops.c,v 1.1.1.1 2008/09/19 20:07:15 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997-2007 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 */ 61 static 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 129 /* 130 * These 4 should be last, in the order: 131 * (1) amfs_auto 132 * (2) amfs_direct 133 * (3) amfs_toplvl 134 * (4) amfs_error 135 */ 136 #ifdef HAVE_AMU_FS_AUTO 137 &amfs_auto_ops, /* Automounter F/S */ 138 #endif /* HAVE_AMU_FS_AUTO */ 139 #ifdef HAVE_AMU_FS_DIRECT 140 &amfs_direct_ops, /* direct-mount F/S */ 141 #endif /* HAVE_AMU_FS_DIRECT */ 142 #ifdef HAVE_AMU_FS_TOPLVL 143 &amfs_toplvl_ops, /* top-level mount F/S */ 144 #endif /* HAVE_AMU_FS_TOPLVL */ 145 #ifdef HAVE_AMU_FS_ERROR 146 &amfs_error_ops, /* error F/S */ 147 #endif /* HAVE_AMU_FS_ERROR */ 148 0 149 }; 150 151 152 void 153 ops_showamfstypes(char *buf, size_t l) 154 { 155 struct am_ops **ap; 156 int linesize = 0; 157 158 buf[0] = '\0'; 159 for (ap = vops; *ap; ap++) { 160 xstrlcat(buf, (*ap)->fs_type, l); 161 if (ap[1]) 162 xstrlcat(buf, ", ", l); 163 linesize += strlen((*ap)->fs_type) + 2; 164 if (linesize > 62) { 165 linesize = 0; 166 xstrlcat(buf, "\n ", l); 167 } 168 } 169 } 170 171 172 static void 173 ops_show1(char *buf, size_t l, int *linesizep, const char *name) 174 { 175 xstrlcat(buf, name, l); 176 xstrlcat(buf, ", ", l); 177 *linesizep += strlen(name) + 2; 178 if (*linesizep > 60) { 179 xstrlcat(buf, "\t\n", l); 180 *linesizep = 0; 181 } 182 } 183 184 185 void 186 ops_showfstypes(char *buf, size_t l) 187 { 188 int linesize = 0; 189 190 buf[0] = '\0'; 191 192 #ifdef MNTTAB_TYPE_AUTOFS 193 ops_show1(buf, l, &linesize, MNTTAB_TYPE_AUTOFS); 194 #endif /* MNTTAB_TYPE_AUTOFS */ 195 196 #ifdef MNTTAB_TYPE_CACHEFS 197 ops_show1(buf, l, &linesize, MNTTAB_TYPE_CACHEFS); 198 #endif /* MNTTAB_TYPE_CACHEFS */ 199 200 #ifdef MNTTAB_TYPE_CDFS 201 ops_show1(buf, l, &linesize, MNTTAB_TYPE_CDFS); 202 #endif /* MNTTAB_TYPE_CDFS */ 203 204 #ifdef MNTTAB_TYPE_CFS 205 ops_show1(buf, l, &linesize, MNTTAB_TYPE_CFS); 206 #endif /* MNTTAB_TYPE_CFS */ 207 208 #ifdef MNTTAB_TYPE_LOFS 209 ops_show1(buf, l, &linesize, MNTTAB_TYPE_LOFS); 210 #endif /* MNTTAB_TYPE_LOFS */ 211 212 #ifdef MNTTAB_TYPE_EFS 213 ops_show1(buf, l, &linesize, MNTTAB_TYPE_EFS); 214 #endif /* MNTTAB_TYPE_EFS */ 215 216 #ifdef MNTTAB_TYPE_MFS 217 ops_show1(buf, l, &linesize, MNTTAB_TYPE_MFS); 218 #endif /* MNTTAB_TYPE_MFS */ 219 220 #ifdef MNTTAB_TYPE_NFS 221 ops_show1(buf, l, &linesize, MNTTAB_TYPE_NFS); 222 #endif /* MNTTAB_TYPE_NFS */ 223 224 #ifdef MNTTAB_TYPE_NFS3 225 ops_show1(buf, l, &linesize, "nfs3"); /* always hard-code as nfs3 */ 226 #endif /* MNTTAB_TYPE_NFS3 */ 227 228 #ifdef MNTTAB_TYPE_NULLFS 229 ops_show1(buf, l, &linesize, MNTTAB_TYPE_NULLFS); 230 #endif /* MNTTAB_TYPE_NULLFS */ 231 232 #ifdef MNTTAB_TYPE_PCFS 233 ops_show1(buf, l, &linesize, MNTTAB_TYPE_PCFS); 234 #endif /* MNTTAB_TYPE_PCFS */ 235 236 #ifdef MNTTAB_TYPE_TFS 237 ops_show1(buf, l, &linesize, MNTTAB_TYPE_TFS); 238 #endif /* MNTTAB_TYPE_TFS */ 239 240 #ifdef MNTTAB_TYPE_TMPFS 241 ops_show1(buf, l, &linesize, MNTTAB_TYPE_TMPFS); 242 #endif /* MNTTAB_TYPE_TMPFS */ 243 244 #ifdef MNTTAB_TYPE_UFS 245 ops_show1(buf, l, &linesize, MNTTAB_TYPE_UFS); 246 #endif /* MNTTAB_TYPE_UFS */ 247 248 #ifdef MNTTAB_TYPE_UMAPFS 249 ops_show1(buf, l, &linesize, MNTTAB_TYPE_UMAPFS); 250 #endif /* MNTTAB_TYPE_UMAPFS */ 251 252 #ifdef MNTTAB_TYPE_UNIONFS 253 ops_show1(buf, l, &linesize, MNTTAB_TYPE_UNIONFS); 254 #endif /* MNTTAB_TYPE_UNIONFS */ 255 256 #ifdef MNTTAB_TYPE_XFS 257 ops_show1(buf, l, &linesize, MNTTAB_TYPE_XFS); 258 #endif /* MNTTAB_TYPE_XFS */ 259 260 /* terminate with a period, newline, and NULL */ 261 if (buf[strlen(buf)-1] == '\n') 262 buf[strlen(buf) - 4] = '\0'; 263 else 264 buf[strlen(buf) - 2] = '\0'; 265 xstrlcat(buf, ".\n", l); 266 } 267 268 269 /* 270 * return string option which is the reverse of opt. 271 * nosuid -> suid 272 * quota -> noquota 273 * ro -> rw 274 * etc. 275 * may return pointer to static buffer or subpointer within opt. 276 */ 277 static char * 278 reverse_option(const char *opt) 279 { 280 static char buf[80]; 281 282 /* sanity check */ 283 if (!opt) 284 return NULL; 285 286 /* check special cases */ 287 /* XXX: if this gets too long, rewrite the code more flexibly */ 288 if (STREQ(opt, "ro")) return "rw"; 289 if (STREQ(opt, "rw")) return "ro"; 290 if (STREQ(opt, "bg")) return "fg"; 291 if (STREQ(opt, "fg")) return "bg"; 292 if (STREQ(opt, "soft")) return "hard"; 293 if (STREQ(opt, "hard")) return "soft"; 294 295 /* check if string starts with 'no' and chop it */ 296 if (NSTREQ(opt, "no", 2)) { 297 xstrlcpy(buf, &opt[2], sizeof(buf)); 298 } else { 299 /* finally return a string prepended with 'no' */ 300 xstrlcpy(buf, "no", sizeof(buf)); 301 xstrlcat(buf, opt, sizeof(buf)); 302 } 303 return buf; 304 } 305 306 307 /* 308 * start with an empty string. for each opts1 option that is not 309 * in opts2, add it to the string (make sure the reverse of it 310 * isn't in either). finally add opts2. return new string. 311 * Both opts1 and opts2 must not be null! 312 * Caller must eventually free the string being returned. 313 */ 314 static char * 315 merge_opts(const char *opts1, const char *opts2) 316 { 317 mntent_t mnt2; /* place holder for opts2 */ 318 char *newstr; /* new string to return (malloc'ed) */ 319 char *tmpstr; /* temp */ 320 char *eq; /* pointer to whatever follows '=' within temp */ 321 char oneopt[80]; /* one option w/o value if any */ 322 char *revoneopt; /* reverse of oneopt */ 323 size_t len = strlen(opts1) + strlen(opts2) + 2; /* space for "," and NULL */ 324 char *s1 = strdup(opts1); /* copy of opts1 to munge */ 325 326 /* initialization */ 327 mnt2.mnt_opts = (char *) opts2; 328 newstr = xmalloc(len); 329 newstr[0] = '\0'; 330 331 for (tmpstr = strtok(s1, ","); 332 tmpstr; 333 tmpstr = strtok(NULL, ",")) { 334 /* copy option to temp buffer */ 335 xstrlcpy(oneopt, tmpstr, sizeof(oneopt)); 336 /* if option has a value such as rsize=1024, chop the value part */ 337 if ((eq = haseq(oneopt))) 338 *eq = '\0'; 339 /* find reverse option of oneopt */ 340 revoneopt = reverse_option(oneopt); 341 /* if option orits reverse exist in opts2, ignore it */ 342 if (amu_hasmntopt(&mnt2, oneopt) || amu_hasmntopt(&mnt2, revoneopt)) 343 continue; 344 /* add option to returned string */ 345 if (newstr[0]) { 346 xstrlcat(newstr, ",", len); 347 xstrlcat(newstr, tmpstr, len); 348 } else { 349 xstrlcpy(newstr, tmpstr, len); 350 } 351 } 352 353 /* finally, append opts2 itself */ 354 if (newstr[0]) { 355 xstrlcat(newstr, ",", len); 356 xstrlcat(newstr, opts2, len); 357 } else { 358 xstrlcpy(newstr, opts2, len); 359 } 360 361 XFREE(s1); 362 return newstr; 363 } 364 365 366 am_ops * 367 ops_search(char *type) 368 { 369 am_ops **vp; 370 am_ops *rop = NULL; 371 for (vp = vops; (rop = *vp); vp++) 372 if (STREQ(rop->fs_type, type)) 373 break; 374 return rop; 375 } 376 377 378 am_ops * 379 ops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map) 380 { 381 am_ops *rop = NULL; 382 char *link_dir; 383 384 /* 385 * First crack the global opts and the local opts 386 */ 387 if (!eval_fs_opts(fo, key, g_key, path, keym, map)) { 388 rop = &amfs_error_ops; 389 } else if (fo->opt_type == 0) { 390 plog(XLOG_USER, "No fs type specified (key = \"%s\", map = \"%s\")", keym, map); 391 rop = &amfs_error_ops; 392 } else { 393 /* 394 * Next find the correct filesystem type 395 */ 396 rop = ops_search(fo->opt_type); 397 if (!rop) { 398 plog(XLOG_USER, "fs type \"%s\" not recognized", fo->opt_type); 399 rop = &amfs_error_ops; 400 } 401 } 402 403 /* 404 * Make sure we have a default mount option. 405 * Otherwise skip past any leading '-'. 406 */ 407 if (fo->opt_opts == 0) 408 fo->opt_opts = strdup("rw,defaults"); 409 else if (*fo->opt_opts == '-') { 410 /* 411 * We cannot simply do fo->opt_opts++ here since the opts 412 * module will try to free the pointer fo->opt_opts later. 413 * So just reallocate the thing -- stolcke 11/11/94 414 */ 415 char *old = fo->opt_opts; 416 fo->opt_opts = strdup(old + 1); 417 XFREE(old); 418 } 419 420 /* 421 * If addopts option was used, then append it to the 422 * current options and remote mount options. 423 */ 424 if (fo->opt_addopts) { 425 if (STREQ(fo->opt_opts, fo->opt_remopts)) { 426 /* optimize things for the common case where opts==remopts */ 427 char *mergedstr; 428 mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts); 429 plog(XLOG_INFO, "merge rem/opts \"%s\" add \"%s\" => \"%s\"", 430 fo->opt_opts, fo->opt_addopts, mergedstr); 431 XFREE(fo->opt_opts); 432 XFREE(fo->opt_remopts); 433 fo->opt_opts = mergedstr; 434 fo->opt_remopts = strdup(mergedstr); 435 } else { 436 char *mergedstr, *remmergedstr; 437 mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts); 438 plog(XLOG_INFO, "merge opts \"%s\" add \"%s\" => \"%s\"", 439 fo->opt_opts, fo->opt_addopts, mergedstr); 440 XFREE(fo->opt_opts); 441 fo->opt_opts = mergedstr; 442 remmergedstr = merge_opts(fo->opt_remopts, fo->opt_addopts); 443 plog(XLOG_INFO, "merge remopts \"%s\" add \"%s\" => \"%s\"", 444 fo->opt_remopts, fo->opt_addopts, remmergedstr); 445 XFREE(fo->opt_remopts); 446 fo->opt_remopts = remmergedstr; 447 } 448 } 449 450 /* 451 * Initialize opt_mount_type to "nfs", if it's not initialized already 452 */ 453 if (!fo->opt_mount_type) 454 fo->opt_mount_type = "nfs"; 455 456 /* Normalize the sublink and make it absolute */ 457 link_dir = fo->opt_sublink; 458 if (link_dir && link_dir[0] && link_dir[0] != '/') { 459 link_dir = str3cat((char *) NULL, fo->opt_fs, "/", link_dir); 460 normalize_slash(link_dir); 461 XFREE(fo->opt_sublink); 462 fo->opt_sublink = link_dir; 463 } 464 465 /* 466 * Check the filesystem is happy 467 */ 468 if (fo->fs_mtab) 469 XFREE(fo->fs_mtab); 470 471 fo->fs_mtab = rop->fs_match(fo); 472 if (fo->fs_mtab) 473 return rop; 474 475 /* 476 * Return error file system 477 */ 478 fo->fs_mtab = amfs_error_ops.fs_match(fo); 479 return &amfs_error_ops; 480 } 481