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