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