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