1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * autod_parse.c 23 * 24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include <stdio.h> 29 #include <ctype.h> 30 #include <string.h> 31 #include <syslog.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <sys/param.h> 35 #include <errno.h> 36 #include <pwd.h> 37 #include <netinet/in.h> 38 #include <netdb.h> 39 #include <sys/tiuser.h> 40 #include <locale.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 #include <thread.h> 44 #include <rpc/rpc.h> 45 #include <rpcsvc/mount.h> 46 #include <fcntl.h> 47 #include <limits.h> 48 #include "automount.h" 49 50 /* 51 * This structure is used to determine the hierarchical 52 * relationship between directories 53 */ 54 typedef struct _hiernode { 55 char dirname[MAXFILENAMELEN+1]; 56 struct _hiernode *subdir; 57 struct _hiernode *leveldir; 58 struct mapent *mapent; 59 } hiernode; 60 61 void free_mapent(struct mapent *); 62 63 static int mapline_to_mapent(struct mapent **, struct mapline *, char *, char *, 64 char *, char *, uint_t); 65 static int hierarchical_sort(struct mapent *, hiernode **, char *, char *); 66 static int push_options(hiernode *, char *, char *, int); 67 static int set_mapent_opts(struct mapent *, char *, char *, char *); 68 static void get_opts(char *, char *, char *, bool_t *); 69 static int fstype_opts(struct mapent *, char *, char *, char *); 70 static int modify_mapents(struct mapent **, char *, char *, char *, hiernode *, 71 char *, uint_t, bool_t); 72 static int set_and_fake_mapent_mntlevel(hiernode *, char *, char *, char *, 73 struct mapent **, uint_t, char *, bool_t); 74 static int mark_level1_root(hiernode *, char *); 75 static int mark_and_fake_level1_noroot(hiernode *, char *, char *, char *, 76 struct mapent **, uint_t i, char *); 77 static int convert_mapent_to_automount(struct mapent *, char *, char *); 78 static int automount_opts(char **, char *); 79 static int parse_fsinfo(char *, struct mapent *); 80 static int parse_nfs(char *, struct mapent *, char *, char *, char **, char **, 81 int); 82 static int parse_special(struct mapent *, char *, char *, char **, char **, 83 int); 84 static int get_dir_from_path(char *, char **, int); 85 static int alloc_hiernode(hiernode **, char *); 86 static void free_hiernode(hiernode *); 87 static void trace_mapents(char *, struct mapent *); 88 static void trace_hierarchy(hiernode *, int); 89 static struct mapent *do_mapent_hosts(char *, char *, uint_t); 90 static void freeex_ent(struct exportnode *); 91 static void freeex(struct exportnode *); 92 static void dump_mapent_err(struct mapent *, char *, char *); 93 94 #define PARSE_OK 0 95 #define PARSE_ERROR -1 96 #define MAX_FSLEN 32 97 98 /* 99 * mapentry error type defininitions 100 */ 101 #define MAPENT_NOERR 0 102 #define MAPENT_UATFS 1 103 104 /* 105 * parse_entry(char *key, char *mapname, char *mapopts, struct mapline *ml, 106 * char *subdir, uint_t isdirect, bool_t mount_access) 107 * Parses the data in ml to build a mapentry list containing the information 108 * for the mounts/lookups to be performed. Builds an intermediate mapentry list 109 * by processing ml, hierarchically sorts (builds a tree of) the list according 110 * to mountpoint. Then pushes options down the hierarchy, and fills in the mount 111 * file system. Finally, modifies the intermediate list depending on how far 112 * in the hierarchy the current request is (uses subdir). Deals with special 113 * case of /net map parsing. 114 * Returns a pointer to the head of the mapentry list. 115 */ 116 struct mapent * 117 parse_entry(char *key, char *mapname, char *mapopts, struct mapline *ml, 118 char *subdir, uint_t isdirect, bool_t mount_access) 119 { 120 char *p; 121 char defaultopts[AUTOFS_MAXOPTSLEN]; 122 123 struct mapent *mapents = NULL; 124 hiernode *rootnode = NULL; 125 char *lp = ml->linebuf; 126 127 if (trace > 1) 128 trace_prt(1, " mapline: %s\n", ml->linebuf); 129 130 /* 131 * Assure the key is only one token long. 132 * This prevents options from sneaking in through the 133 * command line or corruption of /etc/mnttab. 134 */ 135 for (p = key; *p != '\0'; p++) { 136 if (isspace(*p)) { 137 syslog(LOG_ERR, 138 "parse_entry: bad key in map %s: %s", mapname, key); 139 return ((struct mapent *)NULL); 140 } 141 } 142 143 /* 144 * select the appropriate parser, and build the mapentry list 145 */ 146 if (strcmp(lp, "-hosts") == 0) { 147 /* 148 * the /net parser - uses do_mapent_hosts to build mapents. 149 * The mapopts are considered default for every entry, so we 150 * don't push options down hierarchies. 151 */ 152 mapents = do_mapent_hosts(mapopts, key, isdirect); 153 if (mapents == NULL) /* nothing to free */ 154 return (mapents); 155 156 if (trace > 3) 157 trace_mapents("do_mapent_hosts:(return)", mapents); 158 159 if (hierarchical_sort(mapents, &rootnode, key, mapname) 160 != PARSE_OK) 161 goto parse_error; 162 } else { 163 /* 164 * all other parsing 165 */ 166 if (mapline_to_mapent(&mapents, ml, key, mapname, 167 mapopts, defaultopts, isdirect) != PARSE_OK) 168 goto parse_error; 169 170 if (mapents == NULL) 171 return (mapents); 172 173 if (hierarchical_sort(mapents, &rootnode, key, mapname) 174 != PARSE_OK) 175 goto parse_error; 176 177 if (push_options(rootnode, defaultopts, mapopts, 178 MAPENT_NOERR) != PARSE_OK) 179 goto parse_error; 180 181 if (trace > 3) { 182 trace_prt(1, "\n\tpush_options (return)\n"); 183 trace_prt(0, "\tdefault options=%s\n", defaultopts); 184 trace_hierarchy(rootnode, 0); 185 }; 186 187 if (parse_fsinfo(mapname, mapents) != PARSE_OK) 188 goto parse_error; 189 } 190 191 /* 192 * Modify the mapentry list. We *must* do this only after 193 * the mapentry list is completely built (since we need to 194 * have parse_fsinfo called first). 195 */ 196 if (modify_mapents(&mapents, mapname, mapopts, subdir, 197 rootnode, key, isdirect, mount_access) != PARSE_OK) 198 goto parse_error; 199 200 /* 201 * XXX: its dangerous to use rootnode after modify mapents as 202 * it may be pointing to mapents that have been freed 203 */ 204 if (rootnode != NULL) 205 free_hiernode(rootnode); 206 207 return (mapents); 208 209 parse_error: 210 syslog(LOG_ERR, "parse_entry: mapentry parse error: map=%s key=%s", 211 mapname, key); 212 free_mapent(mapents); 213 if (rootnode != NULL) 214 free_hiernode(rootnode); 215 return ((struct mapent *)NULL); 216 } 217 218 219 /* 220 * mapline_to_mapent(struct mapent **mapents, struct mapline *ml, 221 * char *key, char *mapname, char *mapopts, char *defaultopts, 222 * uint_t isdirect) 223 * Parses the mapline information in ml word by word to build an intermediate 224 * mapentry list, which is passed back to the caller. The mapentries may have 225 * holes (example no options), as they are completed only later. The logic is 226 * awkward, but needed to provide the supported flexibility in the map entries. 227 * (especially the first line). Note that the key is the full pathname of the 228 * directory to be mounted in a direct map, and ml is the mapentry beyond key. 229 * Returns PARSE_OK or an appropriate error value. 230 */ 231 static int 232 mapline_to_mapent(struct mapent **mapents, struct mapline *ml, char *key, 233 char *mapname, char *mapopts, char *defaultopts, 234 uint_t isdirect) 235 { 236 struct mapent *me = NULL; 237 struct mapent *mp; 238 char w[MAXPATHLEN]; 239 char wq[MAXPATHLEN]; 240 char w1[MAXPATHLEN]; 241 int implied; 242 243 char *lp = ml->linebuf; 244 char *lq = ml->lineqbuf; 245 246 /* do any macro expansions that are required to complete ml */ 247 if (macro_expand(key, lp, lq, LINESZ)) { 248 syslog(LOG_ERR, 249 "mapline_to_mapent: map %s: line too long (max %d chars)", 250 mapname, LINESZ - 1); 251 return (PARSE_ERROR); 252 } 253 if (trace > 3 && (strcmp(ml->linebuf, lp) != 0)) 254 trace_prt(1, 255 " mapline_to_mapent: (expanded) mapline (%s,%s)\n", 256 ml->linebuf, ml->lineqbuf); 257 258 /* init the head of mapentry list to null */ 259 *mapents = NULL; 260 261 /* 262 * Get the first word - its either a '-' if default options provided, 263 * a '/', if the mountroot is implicitly provided, or a mount filesystem 264 * if the mountroot is implicit. Note that if the first word begins with 265 * a '-' then the second must be read and it must be a mountpoint or a 266 * mount filesystem. Use mapopts if no default opts are provided. 267 */ 268 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 269 return (PARSE_ERROR); 270 if (*w == '-') { 271 strcpy(defaultopts, w); 272 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 273 return (PARSE_ERROR); 274 } else 275 strcpy(defaultopts, mapopts); 276 277 /* 278 * implied is true if there is no '/' 279 * We need the same code path if we have an smbfs mount. 280 */ 281 implied = (*w != '/') || (strstr(defaultopts, "fstype=smbfs") != NULL); 282 while (*w == '/' || implied) { 283 mp = me; 284 if ((me = (struct mapent *)malloc(sizeof (*me))) == NULL) 285 goto alloc_failed; 286 (void) memset((char *)me, 0, sizeof (*me)); 287 if (*mapents == NULL) /* special case of head */ 288 *mapents = me; 289 else 290 mp->map_next = me; 291 292 /* 293 * direct maps get an empty string as root - to be filled 294 * by the entire path later. Indirect maps get /key as the 295 * map root. Note that xfn maps don't care about the root 296 * - they override it in getmapent_fn(). 297 */ 298 if (isdirect) { 299 *w1 = '\0'; 300 } else { 301 strcpy(w1, "/"); 302 strcat(w1, key); 303 } 304 if ((me->map_root = strdup(w1)) == NULL) 305 goto alloc_failed; 306 307 /* mntpnt is empty for the mount root */ 308 if (strcmp(w, "/") == 0 || implied) 309 me->map_mntpnt = strdup(""); 310 else 311 me->map_mntpnt = strdup(w); 312 if (me->map_mntpnt == NULL) 313 goto alloc_failed; 314 315 /* 316 * If implied, the word must be a mount filesystem, 317 * and its already read in; also turn off implied - its 318 * not applicable except for the mount root. Else, 319 * read another (or two) words depending on if there's 320 * an option. 321 */ 322 if (implied) /* must be a mount filesystem */ 323 implied = 0; 324 else { 325 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 326 return (PARSE_ERROR); 327 if (w[0] == '-') { 328 /* mount options */ 329 if ((me->map_mntopts = strdup(w)) == NULL) 330 goto alloc_failed; 331 if (getword(w, wq, &lp, &lq, ' ', 332 sizeof (w)) == -1) 333 return (PARSE_ERROR); 334 } 335 } 336 337 /* 338 * must be a mount filesystem or a set of filesystems at 339 * this point. 340 */ 341 if (w[0] == '\0' || w[0] == '-') { 342 syslog(LOG_ERR, 343 "mapline_to_mapent: bad location=%s map=%s key=%s", 344 w, mapname, key); 345 return (PARSE_ERROR); 346 } 347 348 /* 349 * map_fsw and map_fswq hold information which will be 350 * used to determine filesystem information at a later 351 * point. This is required since we can only find out 352 * about the mount file system after the directories 353 * are hierarchically sorted and options have been pushed 354 * down the hierarchies. 355 */ 356 if (((me->map_fsw = strdup(w)) == NULL) || 357 ((me->map_fswq = strdup(wq)) == NULL)) 358 goto alloc_failed; 359 360 /* 361 * the next word, if any, is either another mount point or a 362 * mount filesystem if more than one server is listed. 363 */ 364 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 365 return (PARSE_ERROR); 366 while (*w && *w != '/') { /* more than 1 server listed */ 367 int len; 368 char *fsw, *fswq; 369 len = strlen(me->map_fsw) + strlen(w) + 4; 370 if ((fsw = (char *)malloc(len)) == NULL) 371 goto alloc_failed; 372 sprintf(fsw, "%s %s", me->map_fsw, w); 373 free(me->map_fsw); 374 me->map_fsw = fsw; 375 len = strlen(me->map_fswq) + strlen(wq) + 4; 376 if ((fswq = (char *)malloc(len)) == NULL) 377 goto alloc_failed; 378 sprintf(fswq, "%s %s", me->map_fswq, wq); 379 free(me->map_fswq); 380 me->map_fswq = fswq; 381 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 382 return (PARSE_ERROR); 383 } 384 385 /* initialize flags */ 386 me->map_mntlevel = -1; 387 me->map_modified = FALSE; 388 me->map_faked = FALSE; 389 me->map_err = MAPENT_NOERR; 390 391 me->map_next = NULL; 392 } 393 394 if (*mapents == NULL || w[0] != '\0') { /* sanity check */ 395 if (verbose) { 396 if (*mapents == NULL) 397 syslog(LOG_ERR, 398 "mapline_to_mapent: parsed with null mapents"); 399 else 400 syslog(LOG_ERR, 401 "mapline_to_mapent: parsed nononempty w=%s", w); 402 } 403 return (PARSE_ERROR); 404 } 405 406 if (trace > 3) 407 trace_mapents("mapline_to_mapent:", *mapents); 408 409 return (PARSE_OK); 410 411 alloc_failed: 412 syslog(LOG_ERR, "mapline_to_mapent: Memory allocation failed"); 413 return (ENOMEM); 414 } 415 416 /* 417 * hierarchical_sort(struct mapent *mapents, hiernode **rootnode, char *key 418 * char *mapname) 419 * sorts the mntpnts in each mapent to build a hierarchy of nodes, with 420 * with the rootnode being the mount root. The hierarchy is setup as 421 * levels, and subdirs below each level. Provides a link from node to 422 * the relevant mapentry. 423 * Returns PARSE_OK or appropriate error value 424 */ 425 static int 426 hierarchical_sort(struct mapent *mapents, hiernode **rootnode, char *key, 427 char *mapname) 428 { 429 hiernode *prevnode, *currnode, *newnode; 430 char *path; 431 char dirname[MAXFILENAMELEN]; 432 433 int rc = PARSE_OK; 434 struct mapent *me = mapents; 435 436 /* allocate the rootnode with a default path of "" */ 437 *rootnode = NULL; 438 if ((rc = alloc_hiernode(rootnode, "")) != PARSE_OK) 439 return (rc); 440 441 /* 442 * walk through mapents - for each mapent, locate the position 443 * within the hierarchy by walking across leveldirs, and 444 * subdirs of matched leveldirs. Starts one level below 445 * the root (assumes an implicit match with rootnode). 446 * XXX - this could probably be done more cleanly using recursion. 447 */ 448 while (me != NULL) { 449 450 path = me->map_mntpnt; 451 452 if ((rc = get_dir_from_path(dirname, &path, 453 sizeof (dirname))) != PARSE_OK) 454 return (rc); 455 456 prevnode = *rootnode; 457 currnode = (*rootnode)->subdir; 458 459 while (dirname[0] != '\0') { 460 if (currnode != NULL) { 461 if (strcmp(currnode->dirname, dirname) == 0) { 462 /* 463 * match found - mntpnt is a child of 464 * this node 465 */ 466 prevnode = currnode; 467 currnode = currnode->subdir; 468 } else { 469 prevnode = currnode; 470 currnode = currnode->leveldir; 471 472 if (currnode == NULL) { 473 /* 474 * No more leveldirs to match. 475 * Add a new one 476 */ 477 if ((rc = alloc_hiernode 478 (&newnode, dirname)) 479 != PARSE_OK) 480 return (rc); 481 prevnode->leveldir = newnode; 482 prevnode = newnode; 483 currnode = newnode->subdir; 484 } else { 485 /* try this leveldir */ 486 continue; 487 } 488 } 489 } else { 490 /* no more subdirs to match. Add a new one */ 491 if ((rc = alloc_hiernode(&newnode, 492 dirname)) != PARSE_OK) 493 return (rc); 494 prevnode->subdir = newnode; 495 prevnode = newnode; 496 currnode = newnode->subdir; 497 } 498 if ((rc = get_dir_from_path(dirname, &path, 499 sizeof (dirname))) != PARSE_OK) 500 return (rc); 501 } 502 503 if (prevnode->mapent != NULL) { 504 /* duplicate mntpoint found */ 505 syslog(LOG_ERR, 506 "hierarchical_sort: duplicate mntpnt map=%s key=%s", 507 mapname, key); 508 return (PARSE_ERROR); 509 } 510 511 /* provide a pointer from node to mapent */ 512 prevnode->mapent = me; 513 me = me->map_next; 514 } 515 516 if (trace > 3) { 517 trace_prt(1, "\n\thierarchical_sort:\n"); 518 trace_hierarchy(*rootnode, 0); /* 0 is rootnode's level */ 519 } 520 521 return (rc); 522 } 523 524 /* 525 * push_options(hiernode *node, char *opts, char *mapopts, int err) 526 * Pushes the options down a hierarchical structure. Works recursively from the 527 * root, which is passed in on the first call. Uses a replacement policy. 528 * If a node points to a mapentry, and it has an option, then thats the option 529 * for that mapentry. Else, the node's mapent inherits the option from the 530 * default (which may be the global option for the entry or mapopts). 531 * err is useful in flagging entries with errors in pushing options. 532 * returns PARSE_OK or appropriate error value. 533 */ 534 static int 535 push_options(hiernode *node, char *defaultopts, char *mapopts, int err) 536 { 537 int rc = PARSE_OK; 538 struct mapent *me = NULL; 539 540 /* ensure that all the dirs at a level are passed the default options */ 541 while (node != NULL) { 542 me = node->mapent; 543 if (me != NULL) { /* not all nodes point to a mapentry */ 544 me->map_err = err; 545 if ((rc = set_mapent_opts(me, me->map_mntopts, 546 defaultopts, mapopts)) != PARSE_OK) 547 return (rc); 548 } 549 550 /* push the options to subdirs */ 551 if (node->subdir != NULL) { 552 if (node->mapent && strcmp(node->mapent->map_fstype, 553 MNTTYPE_AUTOFS) == 0) 554 err = MAPENT_UATFS; 555 if ((rc = push_options(node->subdir, defaultopts, 556 mapopts, err)) != PARSE_OK) 557 return (rc); 558 } 559 node = node->leveldir; 560 } 561 return (rc); 562 } 563 564 #define BACKFSTYPE "backfstype" /* used in cachefs options */ 565 #define BACKFSTYPE_EQ "backfstype=" 566 #define FSTYPE "fstype" 567 #define FSTYPE_EQ "fstype=" 568 #define NO_OPTS "" 569 570 /* 571 * set_mapent_opts(struct mapent *me, char *opts, char *defaultopts, 572 * char *mapopts) 573 * sets the mapentry's options, fstype and mounter fields by separating 574 * out the fstype part from the opts. Use default options if opts is NULL. 575 * Note taht defaultopts may be the same as mapopts. 576 * Returns PARSE_OK or appropriate error value. 577 */ 578 static int 579 set_mapent_opts(struct mapent *me, char *opts, char *defaultopts, 580 char *mapopts) 581 { 582 char entryopts[AUTOFS_MAXOPTSLEN]; 583 char fstype[MAX_FSLEN], mounter[MAX_FSLEN]; 584 int rc = PARSE_OK; 585 bool_t fstype_opt = FALSE; 586 587 strcpy(fstype, MNTTYPE_NFS); /* default */ 588 589 /* set options to default options, if none exist for this entry */ 590 if (opts == NULL) { 591 opts = defaultopts; 592 if (defaultopts == NULL) { /* NULL opts for entry */ 593 strcpy(mounter, fstype); 594 goto done; 595 } 596 } 597 if (*opts == '-') 598 opts++; 599 600 /* separate opts into fstype and (other) entrypopts */ 601 get_opts(opts, entryopts, fstype, &fstype_opt); 602 603 /* replace any existing opts */ 604 if (me->map_mntopts != NULL) 605 free(me->map_mntopts); 606 if ((me->map_mntopts = strdup(entryopts)) == NULL) 607 return (ENOMEM); 608 strcpy(mounter, fstype); 609 610 /* 611 * The following ugly chunk of code crept in as a result of 612 * cachefs. If it's a cachefs mount of an nfs filesystem, then 613 * it's important to parse the nfs special field. Otherwise, 614 * just hand the special field to the fs-specific mount 615 */ 616 if (strcmp(fstype, MNTTYPE_CACHEFS) == 0) { 617 struct mnttab m; 618 char *p; 619 620 m.mnt_mntopts = entryopts; 621 if ((p = hasmntopt(&m, BACKFSTYPE)) != NULL) { 622 int len = strlen(MNTTYPE_NFS); 623 624 p += strlen(BACKFSTYPE_EQ); 625 626 if (strncmp(p, MNTTYPE_NFS, len) == 0 && 627 (p[len] == '\0' || p[len] == ',')) { 628 /* 629 * Cached nfs mount 630 */ 631 (void) strcpy(fstype, MNTTYPE_NFS); 632 (void) strcpy(mounter, MNTTYPE_CACHEFS); 633 } 634 } 635 } 636 637 /* 638 * child options are exactly fstype = somefs, we need to do some 639 * more option pushing work. 640 */ 641 if (fstype_opt == TRUE && 642 (strcmp(me->map_mntopts, NO_OPTS) == 0)) { 643 free(me->map_mntopts); 644 if ((rc = fstype_opts(me, opts, defaultopts, 645 mapopts)) != PARSE_OK) 646 return (rc); 647 } 648 649 done: 650 if (((me->map_fstype = strdup(fstype)) == NULL) || 651 ((me->map_mounter = strdup(mounter)) == NULL)) { 652 if (me->map_fstype != NULL) 653 free(me->map_fstype); 654 syslog(LOG_ERR, "set_mapent_opts: No memory"); 655 return (ENOMEM); 656 } 657 658 return (rc); 659 } 660 661 /* 662 * Check the option string for an "fstype" 663 * option. If found, return the fstype 664 * and the option string with the fstype 665 * option removed, e.g. 666 * 667 * input: "fstype=cachefs,ro,nosuid" 668 * opts: "ro,nosuid" 669 * fstype: "cachefs" 670 * 671 * Also indicates if the fstype option was present 672 * by setting a flag, if the pointer to the flag 673 * is not NULL. 674 */ 675 static void 676 get_opts(input, opts, fstype, fstype_opt) 677 char *input; 678 char *opts; /* output */ 679 char *fstype; /* output */ 680 bool_t *fstype_opt; 681 { 682 char *p, *pb; 683 char buf[MAXOPTSLEN]; 684 char *placeholder; 685 686 *opts = '\0'; 687 (void) strcpy(buf, input); 688 pb = buf; 689 while (p = (char *)strtok_r(pb, ",", &placeholder)) { 690 pb = NULL; 691 if (strncmp(p, FSTYPE_EQ, 7) == 0) { 692 if (fstype_opt != NULL) 693 *fstype_opt = TRUE; 694 (void) strcpy(fstype, p + 7); 695 } else { 696 if (*opts) 697 (void) strcat(opts, ","); 698 (void) strcat(opts, p); 699 } 700 } 701 } 702 703 /* 704 * fstype_opts(struct mapent *me, char *opts, char *defaultopts, 705 * char *mapopts) 706 * We need to push global options to the child entry if it is exactly 707 * fstype=somefs. 708 */ 709 static int 710 fstype_opts(struct mapent *me, char *opts, char *defaultopts, 711 char *mapopts) 712 { 713 char pushopts[AUTOFS_MAXOPTSLEN]; 714 char pushentryopts[AUTOFS_MAXOPTSLEN]; 715 char pushfstype[MAX_FSLEN]; 716 717 if (defaultopts && *defaultopts == '-') 718 defaultopts++; 719 720 /* 721 * the options to push are the global defaults for the entry, 722 * if they exist, or mapopts, if the global defaults for the 723 * entry does not exist. 724 */ 725 if (strcmp(defaultopts, opts) == 0) { 726 if (*mapopts == '-') 727 mapopts++; 728 get_opts(mapopts, pushentryopts, pushfstype, NULL); 729 strcpy(pushopts, mapopts); 730 } else { 731 get_opts(defaultopts, pushentryopts, pushfstype, NULL); 732 strcpy(pushopts, defaultopts); 733 } 734 735 if (strcmp(pushfstype, MNTTYPE_CACHEFS) == 0) 736 me->map_mntopts = strdup(pushopts); 737 else 738 me->map_mntopts = strdup(pushentryopts); 739 740 if (!me->map_mntopts) { 741 syslog(LOG_ERR, "fstype_opts: No memory"); 742 return (ENOMEM); 743 } 744 745 return (PARSE_OK); 746 } 747 748 /* 749 * modify_mapents(struct mapent **mapents, char *mapname, 750 * char *mapopts, char *subdir, hiernode *rootnode, 751 * char *key, uint_t isdirect, bool_t mount_access) 752 * modifies the intermediate mapentry list into the final one, and passes 753 * back a pointer to it. The final list may contain faked mapentries for 754 * hiernodes that do not point to a mapentry, or converted mapentries, if 755 * hiernodes that point to a mapentry need to be converted from nfs to autofs. 756 * mounts. Entries that are not directly 1 level below the subdir are removed. 757 * Returns PARSE_OK or PARSE_ERROR 758 */ 759 static int 760 modify_mapents(struct mapent **mapents, char *mapname, 761 char *mapopts, char *subdir, hiernode *rootnode, 762 char *key, uint_t isdirect, bool_t mount_access) 763 { 764 struct mapent *mp = NULL; 765 char w[MAXPATHLEN]; 766 767 struct mapent *me; 768 int rc = PARSE_OK; 769 struct mapent *faked_mapents = NULL; 770 771 /* 772 * correct the mapentry mntlevel from default -1 to level depending on 773 * position in hierarchy, and build any faked mapentries, if required 774 * at one level below the rootnode given by subdir. 775 */ 776 if ((rc = set_and_fake_mapent_mntlevel(rootnode, subdir, key, mapname, 777 &faked_mapents, isdirect, mapopts, mount_access)) != PARSE_OK) 778 return (rc); 779 780 /* 781 * attaches faked mapents to real mapents list. Assumes mapents 782 * is not NULL. 783 */ 784 me = *mapents; 785 while (me->map_next != NULL) 786 me = me->map_next; 787 me->map_next = faked_mapents; 788 789 /* 790 * get rid of nodes marked at level -1 791 */ 792 me = *mapents; 793 while (me != NULL) { 794 if ((me->map_mntlevel == -1) || (me->map_err) || 795 (mount_access == FALSE && me->map_mntlevel == 0)) { 796 /* 797 * syslog any errors and free entry 798 */ 799 if (me->map_err) 800 dump_mapent_err(me, key, mapname); 801 802 if (me == (*mapents)) { 803 /* special case when head has to be freed */ 804 *mapents = me->map_next; 805 if ((*mapents) == NULL) { 806 /* something wierd happened */ 807 if (verbose) 808 syslog(LOG_ERR, 809 "modify_mapents: level error"); 810 return (PARSE_ERROR); 811 } 812 813 /* separate out the node */ 814 me->map_next = NULL; 815 free_mapent(me); 816 me = *mapents; 817 } else { 818 mp->map_next = me->map_next; 819 me->map_next = NULL; 820 free_mapent(me); 821 me = mp->map_next; 822 } 823 continue; 824 } 825 826 /* 827 * convert level 1 mapents that are not already autonodes 828 * to autonodes 829 */ 830 if (me->map_mntlevel == 1 && 831 (strcmp(me->map_fstype, MNTTYPE_AUTOFS) != 0) && 832 (me->map_faked != TRUE)) { 833 if ((rc = convert_mapent_to_automount(me, mapname, 834 mapopts)) != PARSE_OK) 835 return (rc); 836 } 837 strcpy(w, (me->map_mntpnt+strlen(subdir))); 838 strcpy(me->map_mntpnt, w); 839 mp = me; 840 me = me->map_next; 841 } 842 843 if (trace > 3) 844 trace_mapents("modify_mapents:", *mapents); 845 846 return (PARSE_OK); 847 } 848 849 /* 850 * set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key, 851 * char *mapname, struct mapent **faked_mapents, 852 * uint_t isdirect, char *mapopts, bool_t mount_access) 853 * sets the mapentry mount levels (depths) with respect to the subdir. 854 * Assigns a value of 0 to the new root. Finds the level1 directories by 855 * calling mark_*_level1_*(). Also cleans off extra /'s in level0 and 856 * level1 map_mntpnts. Note that one level below the new root is an existing 857 * mapentry if there's a mapentry (nfs mount) corresponding to the root, 858 * and the direct subdir set for the root, if there's no mapentry corresponding 859 * to the root (we install autodirs). Returns PARSE_OK or error value. 860 */ 861 static int 862 set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key, 863 char *mapname, struct mapent **faked_mapents, 864 uint_t isdirect, char *mapopts, bool_t mount_access) 865 { 866 char dirname[MAXFILENAMELEN]; 867 char traversed_path[MAXPATHLEN]; /* used in building fake mapentries */ 868 869 char *subdir_child = subdir; 870 hiernode *prevnode = rootnode; 871 hiernode *currnode = rootnode->subdir; 872 int rc = PARSE_OK; 873 traversed_path[0] = '\0'; 874 875 /* 876 * find and mark the root by tracing down subdir. Use traversed_path 877 * to keep track of how far we go, while guaranteeing that it 878 * contains no '/' at the end. Took some mucking to get that right. 879 */ 880 if ((rc = get_dir_from_path(dirname, &subdir_child, sizeof (dirname))) 881 != PARSE_OK) 882 return (rc); 883 884 if (dirname[0] != '\0') 885 sprintf(traversed_path, "%s/%s", traversed_path, dirname); 886 887 prevnode = rootnode; 888 currnode = rootnode->subdir; 889 while (dirname[0] != '\0' && currnode != NULL) { 890 if (strcmp(currnode->dirname, dirname) == 0) { 891 892 /* subdir is a child of currnode */ 893 prevnode = currnode; 894 currnode = currnode->subdir; 895 896 if ((rc = get_dir_from_path(dirname, &subdir_child, 897 sizeof (dirname))) != PARSE_OK) 898 return (rc); 899 if (dirname[0] != '\0') 900 sprintf(traversed_path, "%s/%s", 901 traversed_path, dirname); 902 903 } else { 904 /* try next leveldir */ 905 prevnode = currnode; 906 currnode = currnode->leveldir; 907 } 908 } 909 910 if (dirname[0] != '\0') { 911 if (verbose) 912 syslog(LOG_ERR, 913 "set_and_fake_mapent_mntlevel: subdir=%s error: map=%s", 914 subdir, mapname); 915 return (PARSE_ERROR); 916 } 917 918 /* 919 * see if level of root really points to a mapent and if 920 * have access to that filessystem - call appropriate 921 * routine to mark level 1 nodes, and build faked entries 922 */ 923 if (prevnode->mapent != NULL && mount_access == TRUE) { 924 if (trace > 3) 925 trace_prt(1, " node mountpoint %s\t travpath=%s\n", 926 prevnode->mapent->map_mntpnt, traversed_path); 927 928 /* 929 * Copy traversed path map_mntpnt to get rid of any extra 930 * '/' the map entry may contain. 931 */ 932 if (strlen(prevnode->mapent->map_mntpnt) < 933 strlen(traversed_path)) { /* sanity check */ 934 if (verbose) 935 syslog(LOG_ERR, 936 "set_and_fake_mapent_mntlevel: path=%s error", 937 traversed_path); 938 return (PARSE_ERROR); 939 } 940 if (strcmp(prevnode->mapent->map_mntpnt, traversed_path) != 0) 941 strcpy(prevnode->mapent->map_mntpnt, traversed_path); 942 943 prevnode->mapent->map_mntlevel = 0; /* root level is 0 */ 944 if (currnode != NULL) { 945 if ((rc = mark_level1_root(currnode, 946 traversed_path)) != PARSE_OK) 947 return (rc); 948 } 949 } else if (currnode != NULL) { 950 if (trace > 3) 951 trace_prt(1, " No rootnode, travpath=%s\n", 952 traversed_path); 953 if ((rc = mark_and_fake_level1_noroot(currnode, 954 traversed_path, key, mapname, faked_mapents, isdirect, 955 mapopts)) != PARSE_OK) 956 return (rc); 957 } 958 959 if (trace > 3) { 960 trace_prt(1, "\n\tset_and_fake_mapent_mntlevel\n"); 961 trace_hierarchy(rootnode, 0); 962 } 963 964 return (rc); 965 } 966 967 968 /* 969 * mark_level1_root(hiernode *node, char *traversed_path) 970 * marks nodes upto one level below the rootnode given by subdir 971 * recursively. Called if rootnode points to a mapent. 972 * In this routine, a level 1 node is considered to be the 1st existing 973 * mapentry below the root node, so there's no faking involved. 974 * Returns PARSE_OK or error value 975 */ 976 static int 977 mark_level1_root(hiernode *node, char *traversed_path) 978 { 979 /* ensure we touch all leveldirs */ 980 while (node) { 981 /* 982 * mark node level as 1, if one exists - else walk down 983 * subdirs until we find one. 984 */ 985 if (node->mapent == NULL) { 986 char w[MAXPATHLEN]; 987 988 if (node->subdir != NULL) { 989 sprintf(w, "%s/%s", traversed_path, 990 node->dirname); 991 if (mark_level1_root(node->subdir, w) 992 == PARSE_ERROR) 993 return (PARSE_ERROR); 994 } else { 995 if (verbose) { 996 syslog(LOG_ERR, 997 "mark_level1_root: hierarchy error"); 998 } 999 return (PARSE_ERROR); 1000 } 1001 } else { 1002 char w[MAXPATHLEN]; 1003 1004 sprintf(w, "%s/%s", traversed_path, node->dirname); 1005 if (trace > 3) 1006 trace_prt(1, " node mntpnt %s\t travpath %s\n", 1007 node->mapent->map_mntpnt, w); 1008 1009 /* replace mntpnt with travpath to clean extra '/' */ 1010 if (strlen(node->mapent->map_mntpnt) < strlen(w)) { 1011 if (verbose) { 1012 syslog(LOG_ERR, 1013 "mark_level1_root: path=%s error", 1014 traversed_path); 1015 } 1016 return (PARSE_ERROR); 1017 } 1018 if (strcmp(node->mapent->map_mntpnt, w) != 0) 1019 strcpy(node->mapent->map_mntpnt, w); 1020 node->mapent->map_mntlevel = 1; 1021 } 1022 node = node->leveldir; 1023 } 1024 return (PARSE_OK); 1025 } 1026 1027 /* 1028 * mark_and_fake_level1_noroot(hiernode *node, char *traversed_path, 1029 * char *key,char *mapname, struct mapent **faked_mapents, 1030 * uint_t isdirect, char *mapopts) 1031 * Called if the root of the hierarchy does not point to a mapent. marks nodes 1032 * upto one physical level below the rootnode given by subdir. checks if 1033 * there's a real mapentry. If not, it builds a faked one (autonode) at that 1034 * point. The faked autonode is direct, with the map being the same as the 1035 * original one from which the call originated. Options are same as that of 1036 * the map and assigned in automount_opts(). Returns PARSE_OK or error value. 1037 */ 1038 static int 1039 mark_and_fake_level1_noroot(hiernode *node, char *traversed_path, 1040 char *key, char *mapname, struct mapent **faked_mapents, 1041 uint_t isdirect, char *mapopts) 1042 { 1043 struct mapent *me; 1044 int rc = 0; 1045 char faked_map_mntpnt[MAXPATHLEN]; 1046 char w1[MAXPATHLEN]; 1047 char w[MAXPATHLEN]; 1048 1049 while (node != NULL) { 1050 if (node->mapent != NULL) { 1051 /* 1052 * existing mapentry at level 1 - copy travpath to 1053 * get rid of extra '/' in mntpnt 1054 */ 1055 sprintf(w, "%s/%s", traversed_path, node->dirname); 1056 if (trace > 3) 1057 trace_prt(1, " node mntpnt=%s\t travpath=%s\n", 1058 node->mapent->map_mntpnt, w); 1059 if (strlen(node->mapent->map_mntpnt) < strlen(w)) { 1060 /* sanity check */ 1061 if (verbose) 1062 syslog(LOG_ERR, 1063 "mark_fake_level1_noroot:path=%s error", 1064 traversed_path); 1065 return (PARSE_ERROR); 1066 } 1067 if (strcmp(node->mapent->map_mntpnt, w) != 0) 1068 strcpy(node->mapent->map_mntpnt, w); 1069 node->mapent->map_mntlevel = 1; 1070 } else { 1071 /* 1072 * build the faked autonode 1073 */ 1074 if ((me = (struct mapent *)malloc(sizeof (*me))) 1075 == NULL) { 1076 syslog(LOG_ERR, 1077 "mark_and_fake_level1_noroot: out of memory"); 1078 return (ENOMEM); 1079 } 1080 (void) memset((char *)me, 0, sizeof (*me)); 1081 1082 if ((me->map_fs = (struct mapfs *) 1083 malloc(sizeof (struct mapfs))) == NULL) 1084 return (ENOMEM); 1085 (void) memset(me->map_fs, 0, sizeof (struct mapfs)); 1086 1087 if (isdirect) { 1088 *w1 = '\0'; 1089 } else { 1090 strcpy(w1, "/"); 1091 strcat(w1, key); 1092 } 1093 me->map_root = strdup(w1); 1094 1095 sprintf(faked_map_mntpnt, "%s/%s", traversed_path, 1096 node->dirname); 1097 me->map_mntpnt = strdup(faked_map_mntpnt); 1098 me->map_fstype = strdup(MNTTYPE_AUTOFS); 1099 me->map_mounter = strdup(MNTTYPE_AUTOFS); 1100 1101 /* set options */ 1102 if ((rc = automount_opts(&me->map_mntopts, mapopts)) 1103 != PARSE_OK) 1104 return (rc); 1105 me->map_fs->mfs_dir = strdup(mapname); 1106 me->map_mntlevel = 1; 1107 me->map_modified = FALSE; 1108 me->map_faked = TRUE; /* mark as faked */ 1109 if (me->map_root == NULL || 1110 me->map_mntpnt == NULL || 1111 me->map_fstype == NULL || 1112 me->map_mounter == NULL || 1113 me->map_mntopts == NULL || 1114 me->map_fs->mfs_dir == NULL) { 1115 syslog(LOG_ERR, 1116 "mark_and_fake_level1_noroot: out of memory"); 1117 free_mapent(*faked_mapents); 1118 return (ENOMEM); 1119 } 1120 1121 if (*faked_mapents == NULL) 1122 *faked_mapents = me; 1123 else { /* attach to the head */ 1124 me->map_next = *faked_mapents; 1125 *faked_mapents = me; 1126 } 1127 node->mapent = me; 1128 } 1129 node = node->leveldir; 1130 } 1131 return (rc); 1132 } 1133 1134 /* 1135 * convert_mapent_to_automount(struct mapent *me, char *mapname, 1136 * char *mapopts) 1137 * change the mapentry me to an automount - free fields first and NULL them 1138 * to avoid freeing again, while freeing the mapentry at a later stage. 1139 * Could have avoided freeing entries here as we don't really look at them. 1140 * Give the converted mapent entry the options that came with the map using 1141 * automount_opts(). Returns PARSE_OK or appropriate error value. 1142 */ 1143 static int 1144 convert_mapent_to_automount(struct mapent *me, char *mapname, 1145 char *mapopts) 1146 { 1147 struct mapfs *mfs = me->map_fs; /* assumes it exists */ 1148 int rc = PARSE_OK; 1149 1150 /* free relevant entries */ 1151 if (mfs->mfs_host) { 1152 free(mfs->mfs_host); 1153 mfs->mfs_host = NULL; 1154 } 1155 while (me->map_fs->mfs_next != NULL) { 1156 mfs = me->map_fs->mfs_next; 1157 if (mfs->mfs_host) 1158 free(mfs->mfs_host); 1159 if (mfs->mfs_dir) 1160 free(mfs->mfs_dir); 1161 me->map_fs->mfs_next = mfs->mfs_next; /* nulls eventually */ 1162 free((void*)mfs); 1163 } 1164 1165 /* replace relevant entries */ 1166 if (me->map_fstype) 1167 free(me->map_fstype); 1168 if ((me->map_fstype = strdup(MNTTYPE_AUTOFS)) == NULL) 1169 goto alloc_failed; 1170 1171 if (me->map_mounter) 1172 free(me->map_mounter); 1173 if ((me->map_mounter = strdup(me->map_fstype)) == NULL) 1174 goto alloc_failed; 1175 1176 if (me->map_fs->mfs_dir) 1177 free(me->map_fs->mfs_dir); 1178 if ((me->map_fs->mfs_dir = strdup(mapname)) == NULL) 1179 goto alloc_failed; 1180 1181 /* set options */ 1182 if (me->map_mntopts) 1183 free(me->map_mntopts); 1184 if ((rc = automount_opts(&me->map_mntopts, mapopts)) != PARSE_OK) 1185 return (rc); 1186 1187 /* mucked with this entry, set the map_modified field to TRUE */ 1188 me->map_modified = TRUE; 1189 1190 return (rc); 1191 1192 alloc_failed: 1193 syslog(LOG_ERR, 1194 "convert_mapent_to_automount: Memory allocation failed"); 1195 return (ENOMEM); 1196 } 1197 1198 /* 1199 * automount_opts(char **map_mntopts, char *mapopts) 1200 * modifies automount opts - gets rid of all "indirect" and "direct" strings 1201 * if they exist, and then adds a direct string to force a direct automount. 1202 * Rest of the mapopts stay intact. Returns PARSE_OK or appropriate error. 1203 */ 1204 static int 1205 automount_opts(char **map_mntopts, char *mapopts) 1206 { 1207 char *opts; 1208 char *opt; 1209 int len; 1210 char *placeholder; 1211 char buf[AUTOFS_MAXOPTSLEN]; 1212 1213 char *addopt = "direct"; 1214 1215 len = strlen(mapopts)+ strlen(addopt)+2; /* +2 for ",", '\0' */ 1216 if (len > AUTOFS_MAXOPTSLEN) { 1217 syslog(LOG_ERR, 1218 "option string %s too long (max=%d)", mapopts, 1219 AUTOFS_MAXOPTSLEN-8); 1220 return (PARSE_ERROR); 1221 } 1222 1223 if (((*map_mntopts) = ((char *)malloc(len))) == NULL) { 1224 syslog(LOG_ERR, "automount_opts: Memory allocation failed"); 1225 return (ENOMEM); 1226 } 1227 memset(*map_mntopts, 0, len); 1228 1229 strcpy(buf, mapopts); 1230 opts = buf; 1231 while ((opt = strtok_r(opts, ",", &placeholder)) != NULL) { 1232 opts = NULL; 1233 1234 /* remove trailing and leading spaces */ 1235 while (isspace(*opt)) 1236 opt++; 1237 len = strlen(opt)-1; 1238 while (isspace(opt[len])) 1239 opt[len--] = '\0'; 1240 1241 /* 1242 * if direct or indirect found, get rid of it, else put it 1243 * back 1244 */ 1245 if ((strcmp(opt, "indirect") == 0) || 1246 (strcmp(opt, "direct") == 0)) 1247 continue; 1248 if (*map_mntopts[0] != '\0') 1249 strcat(*map_mntopts, ","); 1250 strcat(*map_mntopts, opt); 1251 } 1252 1253 /* add the direct string at the end */ 1254 if (*map_mntopts[0] != '\0') 1255 strcat(*map_mntopts, ","); 1256 strcat(*map_mntopts, addopt); 1257 1258 return (PARSE_OK); 1259 } 1260 1261 /* 1262 * parse_fsinfo(char *mapname, struct mapent *mapents) 1263 * parses the filesystem information stored in me->map_fsw and me->map_fswq 1264 * and calls appropriate filesystem parser. 1265 * Returns PARSE_OK or an appropriate error value. 1266 */ 1267 static int 1268 parse_fsinfo(char *mapname, struct mapent *mapents) 1269 { 1270 struct mapent *me = mapents; 1271 char *bufp; 1272 char *bufq; 1273 int wordsz = MAXPATHLEN; 1274 int err = 0; 1275 1276 while (me != NULL) { 1277 bufp = ""; 1278 bufq = ""; 1279 if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) { 1280 err = parse_nfs(mapname, me, me->map_fsw, 1281 me->map_fswq, &bufp, &bufq, wordsz); 1282 } else { 1283 err = parse_special(me, me->map_fsw, me->map_fswq, 1284 &bufp, &bufq, wordsz); 1285 } 1286 1287 if (err != PARSE_OK || *me->map_fsw != '\0' || 1288 *me->map_fswq != '\0') { 1289 /* sanity check */ 1290 if (verbose) 1291 syslog(LOG_ERR, 1292 "parse_fsinfo: mount location error %s", 1293 me->map_fsw); 1294 return (PARSE_ERROR); 1295 } 1296 1297 me = me->map_next; 1298 } 1299 1300 if (trace > 3) { 1301 trace_mapents("parse_fsinfo:", mapents); 1302 } 1303 1304 return (PARSE_OK); 1305 } 1306 1307 /* 1308 * This function parses the map entry for a nfs type file system 1309 * The input is the string lp (and lq) which can be one of the 1310 * following forms: 1311 * a) host[(penalty)][,host[(penalty)]]... :/directory 1312 * b) host[(penalty)]:/directory[ host[(penalty)]:/directory]... 1313 * This routine constructs a mapfs link-list for each of 1314 * the hosts and the corresponding file system. The list 1315 * is then attatched to the mapent struct passed in. 1316 */ 1317 int 1318 parse_nfs(mapname, me, fsw, fswq, lp, lq, wsize) 1319 struct mapent *me; 1320 char *mapname, *fsw, *fswq, **lp, **lq; 1321 int wsize; 1322 { 1323 struct mapfs *mfs, **mfsp; 1324 char *wlp, *wlq; 1325 char *hl, hostlist[1024], *hlq, hostlistq[1024]; 1326 char hostname_and_penalty[MXHOSTNAMELEN+5]; 1327 char *hn, *hnq, hostname[MXHOSTNAMELEN+1]; 1328 char dirname[MAXPATHLEN+1], subdir[MAXPATHLEN+1]; 1329 char qbuff[MAXPATHLEN+1], qbuff1[MAXPATHLEN+1]; 1330 char pbuff[10], pbuffq[10]; 1331 int penalty; 1332 char w[MAXPATHLEN]; 1333 char wq[MAXPATHLEN]; 1334 int host_cnt; 1335 1336 mfsp = &me->map_fs; 1337 *mfsp = NULL; 1338 1339 /* 1340 * there may be more than one entry in the map list. Get the 1341 * first one. Use temps to handle the word information and 1342 * copy back into fsw and fswq fields when done. 1343 */ 1344 *lp = fsw; 1345 *lq = fswq; 1346 if (getword(w, wq, lp, lq, ' ', wsize) == -1) 1347 return (PARSE_ERROR); 1348 while (*w && *w != '/') { 1349 bool_t maybe_url; 1350 1351 maybe_url = TRUE; 1352 1353 wlp = w; wlq = wq; 1354 if (getword(hostlist, hostlistq, &wlp, &wlq, ':', 1355 sizeof (hostlist)) == -1) 1356 return (PARSE_ERROR); 1357 if (!*hostlist) 1358 goto bad_entry; 1359 1360 if (strcmp(hostlist, "nfs") != 0) 1361 maybe_url = FALSE; 1362 1363 if (getword(dirname, qbuff, &wlp, &wlq, ':', 1364 sizeof (dirname)) == -1) 1365 return (PARSE_ERROR); 1366 if (*dirname == '\0') 1367 goto bad_entry; 1368 1369 if (maybe_url == TRUE && strncmp(dirname, "//", 2) != 0) 1370 maybe_url = FALSE; 1371 1372 /* 1373 * See the next block comment ("Once upon a time ...") to 1374 * understand this. It turns the deprecated concept 1375 * of "subdir mounts" produced some useful code for handling 1376 * the possibility of a ":port#" in the URL. 1377 */ 1378 if (maybe_url == FALSE) 1379 *subdir = '/'; 1380 else 1381 *subdir = ':'; 1382 1383 *qbuff = ' '; 1384 1385 /* 1386 * Once upon time, before autofs, there was support for 1387 * "subdir mounts". The idea was to "economize" the 1388 * number of mounts, so if you had a number of entries 1389 * all referring to a common subdirectory, e.g. 1390 * 1391 * carol seasons:/export/home11/carol 1392 * ted seasons:/export/home11/ted 1393 * alice seasons:/export/home11/alice 1394 * 1395 * then you could tell the automounter to mount a 1396 * common mountpoint which was delimited by the second 1397 * colon: 1398 * 1399 * carol seasons:/export/home11:carol 1400 * ted seasons:/export/home11:ted 1401 * alice seasons:/export/home11:alice 1402 * 1403 * The automounter would mount seasons:/export/home11 1404 * then for any other map entry that referenced the same 1405 * directory it would build a symbolic link that 1406 * appended the remainder of the path after the second 1407 * colon, i.e. once the common subdir was mounted, then 1408 * other directories could be accessed just by link 1409 * building - no further mounts required. 1410 * 1411 * In theory the "mount saving" idea sounded good. In 1412 * practice the saving didn't amount to much and the 1413 * symbolic links confused people because the common 1414 * mountpoint had to have a pseudonym. 1415 * 1416 * To remain backward compatible with the existing 1417 * maps, we interpret a second colon as a slash. 1418 */ 1419 if (getword(subdir+1, qbuff+1, &wlp, &wlq, ':', 1420 sizeof (subdir)) == -1) 1421 return (PARSE_ERROR); 1422 1423 if (*(subdir+1)) 1424 (void) strcat(dirname, subdir); 1425 1426 hl = hostlist; hlq = hostlistq; 1427 1428 host_cnt = 0; 1429 for (;;) { 1430 1431 if (getword(hostname_and_penalty, qbuff, &hl, &hlq, ',', 1432 sizeof (hostname_and_penalty)) == -1) 1433 return (PARSE_ERROR); 1434 if (!*hostname_and_penalty) 1435 break; 1436 1437 host_cnt++; 1438 if (host_cnt > 1) 1439 maybe_url = FALSE; 1440 1441 hn = hostname_and_penalty; 1442 hnq = qbuff; 1443 if (getword(hostname, qbuff1, &hn, &hnq, '(', 1444 sizeof (hostname)) == -1) 1445 return (PARSE_ERROR); 1446 if (hostname[0] == '\0') 1447 goto bad_entry; 1448 1449 if (strcmp(hostname, hostname_and_penalty) == 0) { 1450 penalty = 0; 1451 } else { 1452 maybe_url = FALSE; 1453 hn++; hnq++; 1454 if (getword(pbuff, pbuffq, &hn, &hnq, ')', 1455 sizeof (pbuff)) == -1) 1456 return (PARSE_ERROR); 1457 if (!*pbuff) 1458 penalty = 0; 1459 else 1460 penalty = atoi(pbuff); 1461 } 1462 mfs = (struct mapfs *)malloc(sizeof (*mfs)); 1463 if (mfs == NULL) { 1464 syslog(LOG_ERR, 1465 "parse_nfs: Memory allocation failed"); 1466 return (PARSE_ERROR); 1467 } 1468 (void) memset(mfs, 0, sizeof (*mfs)); 1469 *mfsp = mfs; 1470 mfsp = &mfs->mfs_next; 1471 1472 if (maybe_url == TRUE) { 1473 char *host; 1474 char *path; 1475 char *sport; 1476 1477 host = dirname+2; 1478 path = strchr(host, '/'); 1479 if (path == NULL) { 1480 syslog(LOG_ERR, 1481 "parse_nfs: illegal nfs url syntax: %s", 1482 host); 1483 1484 return (PARSE_ERROR); 1485 } 1486 *path = '\0'; 1487 sport = strchr(host, ':'); 1488 1489 if (sport != NULL && sport < path) { 1490 *sport = '\0'; 1491 mfs->mfs_port = atoi(sport+1); 1492 1493 if (mfs->mfs_port > USHRT_MAX) { 1494 syslog(LOG_ERR, 1495 "parse_nfs: invalid " 1496 "port number (%d) in " 1497 "NFS URL", 1498 mfs->mfs_port); 1499 1500 return (PARSE_ERROR); 1501 } 1502 1503 } 1504 1505 path++; 1506 if (*path == '\0') 1507 path = "."; 1508 1509 mfs->mfs_flags |= MFS_URL; 1510 1511 mfs->mfs_host = strdup(host); 1512 mfs->mfs_dir = strdup(path); 1513 } else { 1514 mfs->mfs_host = strdup(hostname); 1515 mfs->mfs_dir = strdup(dirname); 1516 } 1517 1518 mfs->mfs_penalty = penalty; 1519 if (mfs->mfs_host == NULL || mfs->mfs_dir == NULL) { 1520 syslog(LOG_ERR, 1521 "parse_nfs: Memory allocation failed"); 1522 return (PARSE_ERROR); 1523 } 1524 } 1525 /* 1526 * We check host_cnt to make sure we haven't parsed an entry 1527 * with no host information. 1528 */ 1529 if (host_cnt == 0) { 1530 syslog(LOG_ERR, 1531 "parse_nfs: invalid host specified - bad entry " 1532 "in map %s \"%s\"", 1533 mapname, w); 1534 return (PARSE_ERROR); 1535 } 1536 if (getword(w, wq, lp, lq, ' ', wsize) == -1) 1537 return (PARSE_ERROR); 1538 } 1539 1540 strcpy(fsw, w); 1541 strcpy(fswq, wq); 1542 1543 return (PARSE_OK); 1544 1545 bad_entry: 1546 syslog(LOG_ERR, "parse_nfs: bad entry in map %s \"%s\"", mapname, w); 1547 return (PARSE_ERROR); 1548 } 1549 1550 static int 1551 parse_special(me, w, wq, lp, lq, wsize) 1552 struct mapent *me; 1553 char *w, *wq, **lp, **lq; 1554 int wsize; 1555 { 1556 char devname[MAXPATHLEN + 1], qbuf[MAXPATHLEN + 1]; 1557 char *wlp, *wlq; 1558 struct mapfs *mfs; 1559 1560 wlp = w; 1561 wlq = wq; 1562 if (getword(devname, qbuf, &wlp, &wlq, ' ', sizeof (devname)) == -1) 1563 return (PARSE_ERROR); 1564 if (devname[0] == '\0') 1565 return (PARSE_ERROR); 1566 1567 mfs = (struct mapfs *)malloc(sizeof (struct mapfs)); 1568 if (mfs == NULL) 1569 return (PARSE_ERROR); 1570 (void) memset(mfs, 0, sizeof (*mfs)); 1571 1572 /* 1573 * A device name that begins with a slash could 1574 * be confused with a mountpoint path, hence use 1575 * a colon to escape a device string that begins 1576 * with a slash, e.g. 1577 * 1578 * foo -ro /bar foo:/bar 1579 * and 1580 * foo -ro /dev/sr0 1581 * 1582 * would confuse the parser. The second instance 1583 * must use a colon: 1584 * 1585 * foo -ro :/dev/sr0 1586 */ 1587 mfs->mfs_dir = strdup(&devname[devname[0] == ':']); 1588 if (mfs->mfs_dir == NULL) 1589 return (PARSE_ERROR); 1590 me->map_fs = mfs; 1591 if (getword(w, wq, lp, lq, ' ', wsize) == -1) 1592 return (PARSE_ERROR); 1593 return (0); 1594 } 1595 1596 /* 1597 * get_dir_from_path(char *dir, char **path, int dirsz) 1598 * gets the directory name dir from path for max string of length dirsz. 1599 * A modification of the getword routine. Assumes the delimiter is '/' 1600 * and that excess /'s are redundant. 1601 * Returns PARSE_OK or PARSE_ERROR 1602 */ 1603 static int 1604 get_dir_from_path(char *dir, char **path, int dirsz) 1605 { 1606 char *tmp = dir; 1607 int count = dirsz; 1608 1609 if (dirsz <= 0) { 1610 if (verbose) 1611 syslog(LOG_ERR, 1612 "get_dir_from_path: invalid directory size %d", dirsz); 1613 return (PARSE_ERROR); 1614 } 1615 1616 /* get rid of leading /'s in path */ 1617 while (**path == '/') 1618 (*path)++; 1619 1620 /* now at a word or at the end of path */ 1621 while ((**path) && ((**path) != '/')) { 1622 if (--count <= 0) { 1623 *tmp = '\0'; 1624 syslog(LOG_ERR, 1625 "get_dir_from_path: max pathlength exceeded %d", dirsz); 1626 return (PARSE_ERROR); 1627 } 1628 *dir++ = *(*path)++; 1629 } 1630 1631 *dir = '\0'; 1632 1633 /* get rid of trailing /'s in path */ 1634 while (**path == '/') 1635 (*path)++; 1636 1637 return (PARSE_OK); 1638 } 1639 1640 /* 1641 * alloc_hiernode(hiernode **newnode, char *dirname) 1642 * allocates a new hiernode corresponding to a new directory entry 1643 * in the hierarchical structure, and passes a pointer to it back 1644 * to the calling program. 1645 * Returns PARSE_OK or appropriate error value. 1646 */ 1647 static int 1648 alloc_hiernode(hiernode **newnode, char *dirname) 1649 { 1650 if ((*newnode = (hiernode *)malloc(sizeof (hiernode))) == NULL) { 1651 syslog(LOG_ERR, "alloc_hiernode: Memory allocation failed"); 1652 return (ENOMEM); 1653 } 1654 1655 memset(((char *)*newnode), 0, sizeof (hiernode)); 1656 strcpy(((*newnode)->dirname), dirname); 1657 return (PARSE_OK); 1658 } 1659 1660 /* 1661 * free_hiernode(hiernode *node) 1662 * frees the allocated hiernode given the head of the structure 1663 * recursively calls itself until it frees entire structure. 1664 * Returns nothing. 1665 */ 1666 static void 1667 free_hiernode(hiernode *node) 1668 { 1669 hiernode *currnode = node; 1670 hiernode *prevnode = NULL; 1671 1672 while (currnode != NULL) { 1673 if (currnode->subdir != NULL) 1674 free_hiernode(currnode->subdir); 1675 prevnode = currnode; 1676 currnode = currnode->leveldir; 1677 free((void*)prevnode); 1678 } 1679 } 1680 1681 /* 1682 * free_mapent(struct mapent *) 1683 * free the mapentry and its fields 1684 */ 1685 void 1686 free_mapent(me) 1687 struct mapent *me; 1688 { 1689 struct mapfs *mfs; 1690 struct mapent *m; 1691 1692 while (me) { 1693 while (me->map_fs) { 1694 mfs = me->map_fs; 1695 if (mfs->mfs_host) 1696 free(mfs->mfs_host); 1697 if (mfs->mfs_dir) 1698 free(mfs->mfs_dir); 1699 if (mfs->mfs_args) 1700 free(mfs->mfs_args); 1701 if (mfs->mfs_nconf) 1702 freenetconfigent(mfs->mfs_nconf); 1703 me->map_fs = mfs->mfs_next; 1704 free((char *)mfs); 1705 } 1706 1707 if (me->map_root) 1708 free(me->map_root); 1709 if (me->map_mntpnt) 1710 free(me->map_mntpnt); 1711 if (me->map_mntopts) 1712 free(me->map_mntopts); 1713 if (me->map_fstype) 1714 free(me->map_fstype); 1715 if (me->map_mounter) 1716 free(me->map_mounter); 1717 if (me->map_fsw) 1718 free(me->map_fsw); 1719 if (me->map_fswq) 1720 free(me->map_fswq); 1721 1722 m = me; 1723 me = me->map_next; 1724 free((char *)m); 1725 } 1726 } 1727 1728 /* 1729 * trace_mapents(struct mapent *mapents) 1730 * traces through the mapentry structure and prints it element by element 1731 * returns nothing 1732 */ 1733 static void 1734 trace_mapents(char *s, struct mapent *mapents) 1735 { 1736 struct mapfs *mfs; 1737 struct mapent *me; 1738 1739 trace_prt(1, "\n\t%s\n", s); 1740 for (me = mapents; me; me = me->map_next) { 1741 trace_prt(1, " (%s,%s)\t %s%s -%s\n", 1742 me->map_fstype ? me->map_fstype : "", 1743 me->map_mounter ? me->map_mounter : "", 1744 me->map_root ? me->map_root : "", 1745 me->map_mntpnt ? me->map_mntpnt : "", 1746 me->map_mntopts ? me->map_mntopts : ""); 1747 for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next) 1748 trace_prt(0, "\t\t%s:%s\n", 1749 mfs->mfs_host ? mfs->mfs_host: "", 1750 mfs->mfs_dir ? mfs->mfs_dir : ""); 1751 1752 trace_prt(1, "\tme->map_fsw=%s\n", 1753 me->map_fsw ? me->map_fsw:"", 1754 me->map_fswq ? me->map_fsw:""); 1755 trace_prt(1, "\t mntlevel=%d\t%s\t%s err=%d\n", 1756 me->map_mntlevel, 1757 me->map_modified ? "modify=TRUE":"modify=FALSE", 1758 me->map_faked ? "faked=TRUE":"faked=FALSE", 1759 me->map_err); 1760 } 1761 } 1762 1763 /* 1764 * trace_hierarchy(hiernode *node) 1765 * traces the allocated hiernode given the head of the structure 1766 * recursively calls itself until it traces entire structure. 1767 * the first call made at the root is made with a zero level. 1768 * nodelevel is simply used to print tab and make the tracing clean. 1769 * Returns nothing. 1770 */ 1771 static void 1772 trace_hierarchy(hiernode *node, int nodelevel) 1773 { 1774 hiernode *currnode = node; 1775 int i; 1776 1777 while (currnode != NULL) { 1778 if (currnode->subdir != NULL) { 1779 for (i = 0; i < nodelevel; i++) 1780 trace_prt(0, "\t"); 1781 trace_prt(0, "\t(%s, ", 1782 currnode->dirname ? currnode->dirname :""); 1783 if (currnode->mapent) { 1784 trace_prt(0, "%d, %s)\n", 1785 currnode->mapent->map_mntlevel, 1786 currnode->mapent->map_mntopts ? 1787 currnode->mapent->map_mntopts:""); 1788 } 1789 else 1790 trace_prt(0, " ,)\n"); 1791 nodelevel++; 1792 trace_hierarchy(currnode->subdir, nodelevel); 1793 } else { 1794 for (i = 0; i < nodelevel; i++) 1795 trace_prt(0, "\t"); 1796 trace_prt(0, "\t(%s, ", 1797 currnode->dirname ? currnode->dirname :""); 1798 if (currnode->mapent) { 1799 trace_prt(0, "%d, %s)\n", 1800 currnode->mapent->map_mntlevel, 1801 currnode->mapent->map_mntopts ? 1802 currnode->mapent->map_mntopts:""); 1803 } 1804 else 1805 trace_prt(0, ", )\n"); 1806 } 1807 currnode = currnode->leveldir; 1808 } 1809 } 1810 1811 struct mapent * 1812 do_mapent_hosts(mapopts, host, isdirect) 1813 char *mapopts, *host; 1814 uint_t isdirect; 1815 { 1816 CLIENT *cl; 1817 struct mapent *me, *ms, *mp; 1818 struct mapfs *mfs; 1819 struct exportnode *ex = NULL; 1820 struct exportnode *exlist, *texlist, **texp, *exnext; 1821 struct timeval timeout; 1822 enum clnt_stat clnt_stat; 1823 char name[MAXPATHLEN]; 1824 char entryopts[MAXOPTSLEN]; 1825 char fstype[32], mounter[32]; 1826 int exlen, duplicate; 1827 struct mnttab mb; /* needed for hasmntopt() to get nfs version */ 1828 rpcvers_t nfsvers; /* version in map options, 0 if not there */ 1829 rpcvers_t vers, versmin; /* used to negotiate nfs vers in pingnfs() */ 1830 int retries, delay; 1831 int foundvers; 1832 1833 if (trace > 1) 1834 trace_prt(1, " do_mapent_hosts: host %s\n", host); 1835 1836 /* check for special case: host is me */ 1837 1838 if (self_check(host)) { 1839 ms = (struct mapent *)malloc(sizeof (*ms)); 1840 if (ms == NULL) 1841 goto alloc_failed; 1842 (void) memset((char *)ms, 0, sizeof (*ms)); 1843 (void) strcpy(fstype, MNTTYPE_NFS); 1844 get_opts(mapopts, entryopts, fstype, NULL); 1845 ms->map_mntopts = strdup(entryopts); 1846 if (ms->map_mntopts == NULL) 1847 goto alloc_failed; 1848 ms->map_mounter = strdup(fstype); 1849 if (ms->map_mounter == NULL) 1850 goto alloc_failed; 1851 ms->map_fstype = strdup(MNTTYPE_NFS); 1852 if (ms->map_fstype == NULL) 1853 goto alloc_failed; 1854 1855 if (isdirect) 1856 name[0] = '\0'; 1857 else { 1858 (void) strcpy(name, "/"); 1859 (void) strcat(name, host); 1860 } 1861 ms->map_root = strdup(name); 1862 if (ms->map_root == NULL) 1863 goto alloc_failed; 1864 ms->map_mntpnt = strdup(""); 1865 if (ms->map_mntpnt == NULL) 1866 goto alloc_failed; 1867 mfs = (struct mapfs *)malloc(sizeof (*mfs)); 1868 if (mfs == NULL) 1869 goto alloc_failed; 1870 (void) memset((char *)mfs, 0, sizeof (*mfs)); 1871 ms->map_fs = mfs; 1872 mfs->mfs_host = strdup(host); 1873 if (mfs->mfs_host == NULL) 1874 goto alloc_failed; 1875 mfs->mfs_dir = strdup("/"); 1876 if (mfs->mfs_dir == NULL) 1877 goto alloc_failed; 1878 1879 /* initialize mntlevel and modify */ 1880 ms->map_mntlevel = -1; 1881 ms->map_modified = FALSE; 1882 ms->map_faked = FALSE; 1883 1884 if (trace > 1) 1885 trace_prt(1, 1886 " do_mapent_hosts: self-host %s OK\n", host); 1887 1888 return (ms); 1889 } 1890 1891 /* 1892 * Call pingnfs. Note that we can't have replicated hosts in /net. 1893 * XXX - we would like to avoid duplicating the across the wire calls 1894 * made here in nfsmount(). The pingnfs cache should help avoid it. 1895 */ 1896 mb.mnt_mntopts = mapopts; 1897 foundvers = nopt(&mb, MNTOPT_VERS, (int *)&nfsvers); 1898 if (!foundvers) 1899 nfsvers = 0; 1900 if (set_versrange(nfsvers, &vers, &versmin) != 0) { 1901 syslog(LOG_ERR, "Incorrect NFS version specified for %s", host); 1902 return ((struct mapent *)NULL); 1903 } 1904 if (pingnfs(host, get_retry(mapopts) + 1, &vers, versmin, 0, FALSE, 1905 NULL, NULL) != RPC_SUCCESS) 1906 return ((struct mapent *)NULL); 1907 1908 retries = get_retry(mapopts); 1909 delay = INITDELAY; 1910 retry: 1911 /* get export list of host */ 1912 cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "circuit_v"); 1913 if (cl == NULL) { 1914 cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "datagram_v"); 1915 if (cl == NULL) { 1916 syslog(LOG_ERR, 1917 "do_mapent_hosts: %s %s", host, clnt_spcreateerror("")); 1918 return ((struct mapent *)NULL); 1919 } 1920 1921 } 1922 #ifdef MALLOC_DEBUG 1923 add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__); 1924 add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 1925 __FILE__, __LINE__); 1926 #endif 1927 1928 timeout.tv_usec = 0; 1929 timeout.tv_sec = 25; 1930 if (clnt_stat = clnt_call(cl, MOUNTPROC_EXPORT, xdr_void, 0, 1931 xdr_exports, (caddr_t)&ex, timeout)) { 1932 1933 if (retries-- > 0) { 1934 clnt_destroy(cl); 1935 DELAY(delay); 1936 goto retry; 1937 } 1938 1939 syslog(LOG_ERR, 1940 "do_mapent_hosts: %s: export list: %s", 1941 host, clnt_sperrno(clnt_stat)); 1942 #ifdef MALLOC_DEBUG 1943 drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__); 1944 drop_alloc("AUTH_HANDLE", cl->cl_auth, 1945 __FILE__, __LINE__); 1946 #endif 1947 clnt_destroy(cl); 1948 return ((struct mapent *)NULL); 1949 } 1950 1951 #ifdef MALLOC_DEBUG 1952 drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__); 1953 drop_alloc("AUTH_HANDLE", cl->cl_auth, 1954 __FILE__, __LINE__); 1955 #endif 1956 clnt_destroy(cl); 1957 1958 if (ex == NULL) { 1959 if (trace > 1) 1960 trace_prt(1, 1961 gettext(" getmapent_hosts: null export list\n")); 1962 return ((struct mapent *)NULL); 1963 } 1964 1965 /* now sort by length of names - to get mount order right */ 1966 exlist = ex; 1967 texlist = NULL; 1968 #ifdef lint 1969 exnext = NULL; 1970 #endif 1971 for (; ex; ex = exnext) { 1972 exnext = ex->ex_next; 1973 exlen = strlen(ex->ex_dir); 1974 duplicate = 0; 1975 for (texp = &texlist; *texp; texp = &((*texp)->ex_next)) { 1976 if (exlen < (int)strlen((*texp)->ex_dir)) 1977 break; 1978 duplicate = (strcmp(ex->ex_dir, (*texp)->ex_dir) == 0); 1979 if (duplicate) { 1980 /* disregard duplicate entry */ 1981 freeex_ent(ex); 1982 break; 1983 } 1984 } 1985 if (!duplicate) { 1986 ex->ex_next = *texp; 1987 *texp = ex; 1988 } 1989 } 1990 exlist = texlist; 1991 1992 /* 1993 * The following ugly chunk of code crept in as 1994 * a result of cachefs. If it's a cachefs mount 1995 * of an nfs filesystem, then have it handled as 1996 * an nfs mount but have cachefs do the mount. 1997 */ 1998 (void) strcpy(fstype, MNTTYPE_NFS); 1999 get_opts(mapopts, entryopts, fstype, NULL); 2000 (void) strcpy(mounter, fstype); 2001 if (strcmp(fstype, MNTTYPE_CACHEFS) == 0) { 2002 struct mnttab m; 2003 char *p; 2004 2005 m.mnt_mntopts = entryopts; 2006 if ((p = hasmntopt(&m, "backfstype")) != NULL) { 2007 int len = strlen(MNTTYPE_NFS); 2008 2009 p += 11; 2010 if (strncmp(p, MNTTYPE_NFS, len) == 0 && 2011 (p[len] == '\0' || p[len] == ',')) { 2012 /* 2013 * Cached nfs mount 2014 */ 2015 (void) strcpy(fstype, MNTTYPE_NFS); 2016 (void) strcpy(mounter, MNTTYPE_CACHEFS); 2017 } 2018 } 2019 } 2020 2021 /* Now create a mapent from the export list */ 2022 ms = NULL; 2023 me = NULL; 2024 2025 for (ex = exlist; ex; ex = ex->ex_next) { 2026 mp = me; 2027 me = (struct mapent *)malloc(sizeof (*me)); 2028 if (me == NULL) 2029 goto alloc_failed; 2030 (void) memset((char *)me, 0, sizeof (*me)); 2031 2032 if (ms == NULL) 2033 ms = me; 2034 else 2035 mp->map_next = me; 2036 2037 if (isdirect) 2038 name[0] = '\0'; 2039 else { 2040 (void) strcpy(name, "/"); 2041 (void) strcat(name, host); 2042 } 2043 me->map_root = strdup(name); 2044 if (me->map_root == NULL) 2045 goto alloc_failed; 2046 2047 *name = '\0'; 2048 if (strcmp(ex->ex_dir, "/") != 0) { 2049 if (*(ex->ex_dir) != '/') 2050 (void) strcpy(name, "/"); 2051 (void) strcat(name, ex->ex_dir); 2052 } 2053 me->map_mntpnt = strdup(name); 2054 if (me->map_mntpnt == NULL) 2055 goto alloc_failed; 2056 2057 me->map_fstype = strdup(fstype); 2058 if (me->map_fstype == NULL) 2059 goto alloc_failed; 2060 me->map_mounter = strdup(mounter); 2061 if (me->map_mounter == NULL) 2062 goto alloc_failed; 2063 me->map_mntopts = strdup(entryopts); 2064 if (me->map_mntopts == NULL) 2065 goto alloc_failed; 2066 2067 mfs = (struct mapfs *)malloc(sizeof (*mfs)); 2068 if (mfs == NULL) 2069 goto alloc_failed; 2070 (void) memset((char *)mfs, 0, sizeof (*mfs)); 2071 me->map_fs = mfs; 2072 mfs->mfs_host = strdup(host); 2073 if (mfs->mfs_host == NULL) 2074 goto alloc_failed; 2075 mfs->mfs_dir = strdup(ex->ex_dir); 2076 if (mfs->mfs_dir == NULL) 2077 goto alloc_failed; 2078 2079 /* initialize mntlevel and modify values */ 2080 me->map_mntlevel = -1; 2081 me->map_modified = FALSE; 2082 me->map_faked = FALSE; 2083 } 2084 freeex(exlist); 2085 2086 if (trace > 1) 2087 trace_prt(1, " do_mapent_hosts: host %s OK\n", host); 2088 2089 return (ms); 2090 2091 alloc_failed: 2092 syslog(LOG_ERR, "do_mapent_hosts: Memory allocation failed"); 2093 free_mapent(ms); 2094 freeex(exlist); 2095 return ((struct mapent *)NULL); 2096 } 2097 2098 2099 static void 2100 freeex_ent(ex) 2101 struct exportnode *ex; 2102 { 2103 struct groupnode *groups, *tmpgroups; 2104 2105 free(ex->ex_dir); 2106 groups = ex->ex_groups; 2107 while (groups) { 2108 free(groups->gr_name); 2109 tmpgroups = groups->gr_next; 2110 free((char *)groups); 2111 groups = tmpgroups; 2112 } 2113 free((char *)ex); 2114 } 2115 2116 static void 2117 freeex(ex) 2118 struct exportnode *ex; 2119 { 2120 struct exportnode *tmpex; 2121 2122 while (ex) { 2123 tmpex = ex->ex_next; 2124 freeex_ent(ex); 2125 ex = tmpex; 2126 } 2127 } 2128 2129 static const char uatfs_err[] = "submount under fstype=autofs not supported"; 2130 /* 2131 * dump_mapent_err(struct mapent *me, char *key, char *mapname) 2132 * syslog appropriate error in mapentries. 2133 */ 2134 static void dump_mapent_err(struct mapent *me, char *key, char *mapname) 2135 { 2136 switch (me->map_err) { 2137 case MAPENT_NOERR: 2138 if (verbose) 2139 syslog(LOG_ERR, 2140 "map=%s key=%s mntpnt=%s: no error"); 2141 break; 2142 case MAPENT_UATFS: 2143 syslog(LOG_ERR, 2144 "mountpoint %s in map %s key %s not mounted: %s", 2145 me->map_mntpnt, mapname, key, uatfs_err); 2146 break; 2147 default: 2148 if (verbose) 2149 syslog(LOG_ERR, 2150 "map=%s key=%s mntpnt=%s: unknown mapentry error"); 2151 } 2152 }