10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * autod_parse.c 240Sstevel@tonic-gate * 250Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 260Sstevel@tonic-gate * Use is subject to license terms. 270Sstevel@tonic-gate */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 300Sstevel@tonic-gate 310Sstevel@tonic-gate #include <stdio.h> 320Sstevel@tonic-gate #include <ctype.h> 330Sstevel@tonic-gate #include <string.h> 340Sstevel@tonic-gate #include <syslog.h> 350Sstevel@tonic-gate #include <sys/types.h> 360Sstevel@tonic-gate #include <sys/stat.h> 370Sstevel@tonic-gate #include <sys/param.h> 380Sstevel@tonic-gate #include <errno.h> 390Sstevel@tonic-gate #include <pwd.h> 400Sstevel@tonic-gate #include <netinet/in.h> 410Sstevel@tonic-gate #include <netdb.h> 420Sstevel@tonic-gate #include <sys/tiuser.h> 430Sstevel@tonic-gate #include <locale.h> 440Sstevel@tonic-gate #include <stdlib.h> 450Sstevel@tonic-gate #include <unistd.h> 460Sstevel@tonic-gate #include <thread.h> 470Sstevel@tonic-gate #include <rpc/rpc.h> 480Sstevel@tonic-gate #include <rpcsvc/mount.h> 490Sstevel@tonic-gate #include <fcntl.h> 500Sstevel@tonic-gate #include <limits.h> 510Sstevel@tonic-gate #include "automount.h" 520Sstevel@tonic-gate 530Sstevel@tonic-gate /* 540Sstevel@tonic-gate * This structure is used to determine the hierarchical 550Sstevel@tonic-gate * relationship between directories 560Sstevel@tonic-gate */ 57*249Sjwahlig typedef struct _hiernode { 580Sstevel@tonic-gate char dirname[MAXFILENAMELEN+1]; 590Sstevel@tonic-gate struct _hiernode *subdir; 600Sstevel@tonic-gate struct _hiernode *leveldir; 610Sstevel@tonic-gate struct mapent *mapent; 62*249Sjwahlig } hiernode; 630Sstevel@tonic-gate 640Sstevel@tonic-gate void free_mapent(struct mapent *); 650Sstevel@tonic-gate 660Sstevel@tonic-gate static int mapline_to_mapent(struct mapent **, struct mapline *, char *, char *, 670Sstevel@tonic-gate char *, char *, uint_t); 680Sstevel@tonic-gate static int hierarchical_sort(struct mapent *, hiernode **, char *, char *); 690Sstevel@tonic-gate static int push_options(hiernode *, char *, char *, int); 700Sstevel@tonic-gate static int set_mapent_opts(struct mapent *, char *, char *, char *); 710Sstevel@tonic-gate static void get_opts(char *, char *, char *, bool_t *); 720Sstevel@tonic-gate static int fstype_opts(struct mapent *, char *, char *, char *); 730Sstevel@tonic-gate static int modify_mapents(struct mapent **, char *, char *, char *, hiernode *, 740Sstevel@tonic-gate char *, uint_t, bool_t); 750Sstevel@tonic-gate static int set_and_fake_mapent_mntlevel(hiernode *, char *, char *, char *, 760Sstevel@tonic-gate struct mapent **, uint_t, char *, bool_t); 770Sstevel@tonic-gate static int mark_level1_root(hiernode *, char *); 780Sstevel@tonic-gate static int mark_and_fake_level1_noroot(hiernode *, char *, char *, char *, 790Sstevel@tonic-gate struct mapent **, uint_t i, char *); 800Sstevel@tonic-gate static int convert_mapent_to_automount(struct mapent *, char *, char *); 810Sstevel@tonic-gate static int automount_opts(char **, char *); 820Sstevel@tonic-gate static int parse_fsinfo(char *, struct mapent *); 830Sstevel@tonic-gate static int parse_nfs(char *, struct mapent *, char *, char *, char **, char **, 840Sstevel@tonic-gate int); 850Sstevel@tonic-gate static int parse_special(struct mapent *, char *, char *, char **, char **, 860Sstevel@tonic-gate int); 870Sstevel@tonic-gate static int get_dir_from_path(char *, char **, int); 880Sstevel@tonic-gate static int alloc_hiernode(hiernode **, char *); 890Sstevel@tonic-gate static void free_hiernode(hiernode *); 900Sstevel@tonic-gate static void trace_mapents(char *, struct mapent *); 910Sstevel@tonic-gate static void trace_hierarchy(hiernode *, int); 920Sstevel@tonic-gate static struct mapent *do_mapent_hosts(char *, char *, uint_t); 930Sstevel@tonic-gate static void freeex_ent(struct exportnode *); 940Sstevel@tonic-gate static void freeex(struct exportnode *); 950Sstevel@tonic-gate static void dump_mapent_err(struct mapent *, char *, char *); 960Sstevel@tonic-gate 970Sstevel@tonic-gate #define PARSE_OK 0 980Sstevel@tonic-gate #define PARSE_ERROR -1 990Sstevel@tonic-gate #define MAX_FSLEN 32 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate /* 1020Sstevel@tonic-gate * mapentry error type defininitions 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate #define MAPENT_NOERR 0 1050Sstevel@tonic-gate #define MAPENT_UATFS 1 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate /* 1080Sstevel@tonic-gate * parse_entry(char *key, char *mapname, char *mapopts, struct mapline *ml, 1090Sstevel@tonic-gate * char *subdir, uint_t isdirect, bool_t mount_access) 1100Sstevel@tonic-gate * Parses the data in ml to build a mapentry list containing the information 1110Sstevel@tonic-gate * for the mounts/lookups to be performed. Builds an intermediate mapentry list 1120Sstevel@tonic-gate * by processing ml, hierarchically sorts (builds a tree of) the list according 1130Sstevel@tonic-gate * to mountpoint. Then pushes options down the hierarchy, and fills in the mount 1140Sstevel@tonic-gate * file system. Finally, modifies the intermediate list depending on how far 1150Sstevel@tonic-gate * in the hierarchy the current request is (uses subdir). Deals with special 1160Sstevel@tonic-gate * case of /net map parsing. 1170Sstevel@tonic-gate * Returns a pointer to the head of the mapentry list. 1180Sstevel@tonic-gate */ 1190Sstevel@tonic-gate struct mapent * 1200Sstevel@tonic-gate parse_entry(char *key, char *mapname, char *mapopts, struct mapline *ml, 1210Sstevel@tonic-gate char *subdir, uint_t isdirect, bool_t mount_access) 1220Sstevel@tonic-gate { 1230Sstevel@tonic-gate char *p; 1240Sstevel@tonic-gate char defaultopts[AUTOFS_MAXOPTSLEN]; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate struct mapent *mapents = NULL; 1270Sstevel@tonic-gate hiernode *rootnode = NULL; 1280Sstevel@tonic-gate char *lp = ml->linebuf; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate if (trace > 1) 1310Sstevel@tonic-gate trace_prt(1, " mapline: %s\n", ml->linebuf); 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate /* 1340Sstevel@tonic-gate * Assure the key is only one token long. 1350Sstevel@tonic-gate * This prevents options from sneaking in through the 1360Sstevel@tonic-gate * command line or corruption of /etc/mnttab. 1370Sstevel@tonic-gate */ 1380Sstevel@tonic-gate for (p = key; *p != '\0'; p++) { 1390Sstevel@tonic-gate if (isspace(*p)) { 1400Sstevel@tonic-gate syslog(LOG_ERR, 1410Sstevel@tonic-gate "parse_entry: bad key in map %s: %s", mapname, key); 1420Sstevel@tonic-gate return ((struct mapent *)NULL); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate /* 1470Sstevel@tonic-gate * select the appropriate parser, and build the mapentry list 1480Sstevel@tonic-gate */ 1490Sstevel@tonic-gate if (strcmp(lp, "-hosts") == 0) { 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * the /net parser - uses do_mapent_hosts to build mapents. 1520Sstevel@tonic-gate * The mapopts are considered default for every entry, so we 1530Sstevel@tonic-gate * don't push options down hierarchies. 1540Sstevel@tonic-gate */ 1550Sstevel@tonic-gate mapents = do_mapent_hosts(mapopts, key, isdirect); 1560Sstevel@tonic-gate if (mapents == NULL) /* nothing to free */ 1570Sstevel@tonic-gate return (mapents); 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate if (trace > 3) 1600Sstevel@tonic-gate trace_mapents("do_mapent_hosts:(return)", mapents); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate if (hierarchical_sort(mapents, &rootnode, key, mapname) 1630Sstevel@tonic-gate != PARSE_OK) 1640Sstevel@tonic-gate goto parse_error; 1650Sstevel@tonic-gate } else { 1660Sstevel@tonic-gate /* 1670Sstevel@tonic-gate * all other parsing 1680Sstevel@tonic-gate */ 1690Sstevel@tonic-gate if (mapline_to_mapent(&mapents, ml, key, mapname, 1700Sstevel@tonic-gate mapopts, defaultopts, isdirect) != PARSE_OK) 1710Sstevel@tonic-gate goto parse_error; 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate if (mapents == NULL) 1740Sstevel@tonic-gate return (mapents); 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate if (hierarchical_sort(mapents, &rootnode, key, mapname) 1770Sstevel@tonic-gate != PARSE_OK) 1780Sstevel@tonic-gate goto parse_error; 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate if (push_options(rootnode, defaultopts, mapopts, 1810Sstevel@tonic-gate MAPENT_NOERR) != PARSE_OK) 1820Sstevel@tonic-gate goto parse_error; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate if (trace > 3) { 1850Sstevel@tonic-gate trace_prt(1, "\n\tpush_options (return)\n"); 1860Sstevel@tonic-gate trace_prt(0, "\tdefault options=%s\n", defaultopts); 1870Sstevel@tonic-gate trace_hierarchy(rootnode, 0); 1880Sstevel@tonic-gate }; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate if (parse_fsinfo(mapname, mapents) != PARSE_OK) 1910Sstevel@tonic-gate goto parse_error; 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * Modify the mapentry list. We *must* do this only after 1960Sstevel@tonic-gate * the mapentry list is completely built (since we need to 1970Sstevel@tonic-gate * have parse_fsinfo called first). 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate if (modify_mapents(&mapents, mapname, mapopts, subdir, 2000Sstevel@tonic-gate rootnode, key, isdirect, mount_access) != PARSE_OK) 2010Sstevel@tonic-gate goto parse_error; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate /* 2040Sstevel@tonic-gate * XXX: its dangerous to use rootnode after modify mapents as 2050Sstevel@tonic-gate * it may be pointing to mapents that have been freed 2060Sstevel@tonic-gate */ 2070Sstevel@tonic-gate if (rootnode != NULL) 2080Sstevel@tonic-gate free_hiernode(rootnode); 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate return (mapents); 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate parse_error: 2130Sstevel@tonic-gate syslog(LOG_ERR, "parse_entry: mapentry parse error: map=%s key=%s", 2140Sstevel@tonic-gate mapname, key); 2150Sstevel@tonic-gate free_mapent(mapents); 2160Sstevel@tonic-gate if (rootnode != NULL) 2170Sstevel@tonic-gate free_hiernode(rootnode); 2180Sstevel@tonic-gate return ((struct mapent *)NULL); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate /* 2230Sstevel@tonic-gate * mapline_to_mapent(struct mapent **mapents, struct mapline *ml, 2240Sstevel@tonic-gate * char *key, char *mapname, char *mapopts, char *defaultopts, 2250Sstevel@tonic-gate * uint_t isdirect) 2260Sstevel@tonic-gate * Parses the mapline information in ml word by word to build an intermediate 2270Sstevel@tonic-gate * mapentry list, which is passed back to the caller. The mapentries may have 2280Sstevel@tonic-gate * holes (example no options), as they are completed only later. The logic is 2290Sstevel@tonic-gate * awkward, but needed to provide the supported flexibility in the map entries. 2300Sstevel@tonic-gate * (especially the first line). Note that the key is the full pathname of the 2310Sstevel@tonic-gate * directory to be mounted in a direct map, and ml is the mapentry beyond key. 2320Sstevel@tonic-gate * Returns PARSE_OK or an appropriate error value. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate static int 2350Sstevel@tonic-gate mapline_to_mapent(struct mapent **mapents, struct mapline *ml, char *key, 2360Sstevel@tonic-gate char *mapname, char *mapopts, char *defaultopts, 2370Sstevel@tonic-gate uint_t isdirect) 2380Sstevel@tonic-gate { 2390Sstevel@tonic-gate struct mapent *me = NULL; 2400Sstevel@tonic-gate struct mapent *mp; 2410Sstevel@tonic-gate char w[MAXPATHLEN]; 2420Sstevel@tonic-gate char wq[MAXPATHLEN]; 2430Sstevel@tonic-gate char w1[MAXPATHLEN]; 2440Sstevel@tonic-gate int implied; 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate char *lp = ml->linebuf; 2470Sstevel@tonic-gate char *lq = ml->lineqbuf; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate /* do any macro expansions that are required to complete ml */ 2500Sstevel@tonic-gate if (macro_expand(key, lp, lq, LINESZ)) { 2510Sstevel@tonic-gate syslog(LOG_ERR, 2520Sstevel@tonic-gate "mapline_to_mapent: map %s: line too long (max %d chars)", 2530Sstevel@tonic-gate mapname, LINESZ - 1); 2540Sstevel@tonic-gate return (PARSE_ERROR); 2550Sstevel@tonic-gate } 2560Sstevel@tonic-gate if (trace > 3 && (strcmp(ml->linebuf, lp) != 0)) 2570Sstevel@tonic-gate trace_prt(1, 2580Sstevel@tonic-gate " mapline_to_mapent: (expanded) mapline (%s,%s)\n", 2590Sstevel@tonic-gate ml->linebuf, ml->lineqbuf); 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate /* init the head of mapentry list to null */ 2620Sstevel@tonic-gate *mapents = NULL; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate /* 2650Sstevel@tonic-gate * Get the first word - its either a '-' if default options provided, 2660Sstevel@tonic-gate * a '/', if the mountroot is implicitly provided, or a mount filesystem 2670Sstevel@tonic-gate * if the mountroot is implicit. Note that if the first word begins with 2680Sstevel@tonic-gate * a '-' then the second must be read and it must be a mountpoint or a 2690Sstevel@tonic-gate * mount filesystem. Use mapopts if no default opts are provided. 2700Sstevel@tonic-gate */ 2710Sstevel@tonic-gate if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 2720Sstevel@tonic-gate return (PARSE_ERROR); 2730Sstevel@tonic-gate if (*w == '-') { 2740Sstevel@tonic-gate strcpy(defaultopts, w); 2750Sstevel@tonic-gate if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 2760Sstevel@tonic-gate return (PARSE_ERROR); 2770Sstevel@tonic-gate } else 2780Sstevel@tonic-gate strcpy(defaultopts, mapopts); 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate implied = *w != '/'; /* implied is 1 only if '/' is implicit */ 2810Sstevel@tonic-gate while (*w == '/' || implied) { 2820Sstevel@tonic-gate mp = me; 2830Sstevel@tonic-gate if ((me = (struct mapent *)malloc(sizeof (*me))) == NULL) 2840Sstevel@tonic-gate goto alloc_failed; 2850Sstevel@tonic-gate (void) memset((char *)me, 0, sizeof (*me)); 2860Sstevel@tonic-gate if (*mapents == NULL) /* special case of head */ 2870Sstevel@tonic-gate *mapents = me; 2880Sstevel@tonic-gate else 2890Sstevel@tonic-gate mp->map_next = me; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * direct maps get an empty string as root - to be filled 2930Sstevel@tonic-gate * by the entire path later. Indirect maps get /key as the 2940Sstevel@tonic-gate * map root. Note that xfn maps don't care about the root 2950Sstevel@tonic-gate * - they override it in getmapent_fn(). 2960Sstevel@tonic-gate */ 2970Sstevel@tonic-gate if (isdirect) { 2980Sstevel@tonic-gate *w1 = '\0'; 2990Sstevel@tonic-gate } else { 3000Sstevel@tonic-gate strcpy(w1, "/"); 3010Sstevel@tonic-gate strcat(w1, key); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate if ((me->map_root = strdup(w1)) == NULL) 3040Sstevel@tonic-gate goto alloc_failed; 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate /* mntpnt is empty for the mount root */ 3070Sstevel@tonic-gate if (strcmp(w, "/") == 0 || implied) 3080Sstevel@tonic-gate me->map_mntpnt = strdup(""); 3090Sstevel@tonic-gate else 3100Sstevel@tonic-gate me->map_mntpnt = strdup(w); 3110Sstevel@tonic-gate if (me->map_mntpnt == NULL) 3120Sstevel@tonic-gate goto alloc_failed; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * If implied, the word must be a mount filesystem, 3160Sstevel@tonic-gate * and its already read in; also turn off implied - its 3170Sstevel@tonic-gate * not applicable except for the mount root. Else, 3180Sstevel@tonic-gate * read another (or two) words depending on if there's 3190Sstevel@tonic-gate * an option. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate if (implied) /* must be a mount filesystem */ 3220Sstevel@tonic-gate implied = 0; 3230Sstevel@tonic-gate else { 3240Sstevel@tonic-gate if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 3250Sstevel@tonic-gate return (PARSE_ERROR); 3260Sstevel@tonic-gate if (w[0] == '-') { 3270Sstevel@tonic-gate /* mount options */ 3280Sstevel@tonic-gate if ((me->map_mntopts = strdup(w)) == NULL) 3290Sstevel@tonic-gate goto alloc_failed; 3300Sstevel@tonic-gate if (getword(w, wq, &lp, &lq, ' ', 3310Sstevel@tonic-gate sizeof (w)) == -1) 3320Sstevel@tonic-gate return (PARSE_ERROR); 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * must be a mount filesystem or a set of filesystems at 3380Sstevel@tonic-gate * this point. 3390Sstevel@tonic-gate */ 3400Sstevel@tonic-gate if (w[0] == '\0' || w[0] == '-') { 3410Sstevel@tonic-gate syslog(LOG_ERR, 3420Sstevel@tonic-gate "mapline_to_mapent: bad location=%s map=%s key=%s", 3430Sstevel@tonic-gate w, mapname, key); 3440Sstevel@tonic-gate return (PARSE_ERROR); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate /* 3480Sstevel@tonic-gate * map_fsw and map_fswq hold information which will be 3490Sstevel@tonic-gate * used to determine filesystem information at a later 3500Sstevel@tonic-gate * point. This is required since we can only find out 3510Sstevel@tonic-gate * about the mount file system after the directories 3520Sstevel@tonic-gate * are hierarchically sorted and options have been pushed 3530Sstevel@tonic-gate * down the hierarchies. 3540Sstevel@tonic-gate */ 3550Sstevel@tonic-gate if (((me->map_fsw = strdup(w)) == NULL) || 3560Sstevel@tonic-gate ((me->map_fswq = strdup(wq)) == NULL)) 3570Sstevel@tonic-gate goto alloc_failed; 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate /* 3600Sstevel@tonic-gate * the next word, if any, is either another mount point or a 3610Sstevel@tonic-gate * mount filesystem if more than one server is listed. 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 3640Sstevel@tonic-gate return (PARSE_ERROR); 3650Sstevel@tonic-gate while (*w && *w != '/') { /* more than 1 server listed */ 3660Sstevel@tonic-gate int len; 3670Sstevel@tonic-gate char *fsw, *fswq; 3680Sstevel@tonic-gate len = strlen(me->map_fsw) + strlen(w) + 4; 3690Sstevel@tonic-gate if ((fsw = (char *)malloc(len)) == NULL) 3700Sstevel@tonic-gate goto alloc_failed; 3710Sstevel@tonic-gate sprintf(fsw, "%s %s", me->map_fsw, w); 3720Sstevel@tonic-gate free(me->map_fsw); 3730Sstevel@tonic-gate me->map_fsw = fsw; 3740Sstevel@tonic-gate len = strlen(me->map_fswq) + strlen(wq) + 4; 3750Sstevel@tonic-gate if ((fswq = (char *)malloc(len)) == NULL) 3760Sstevel@tonic-gate goto alloc_failed; 3770Sstevel@tonic-gate sprintf(fswq, "%s %s", me->map_fswq, wq); 3780Sstevel@tonic-gate free(me->map_fswq); 3790Sstevel@tonic-gate me->map_fswq = fswq; 3800Sstevel@tonic-gate if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1) 3810Sstevel@tonic-gate return (PARSE_ERROR); 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate /* initialize flags */ 3850Sstevel@tonic-gate me->map_mntlevel = -1; 3860Sstevel@tonic-gate me->map_modified = FALSE; 3870Sstevel@tonic-gate me->map_faked = FALSE; 3880Sstevel@tonic-gate me->map_err = MAPENT_NOERR; 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate me->map_next = NULL; 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate if (*mapents == NULL || w[0] != '\0') { /* sanity check */ 3940Sstevel@tonic-gate if (verbose) { 3950Sstevel@tonic-gate if (*mapents == NULL) 3960Sstevel@tonic-gate syslog(LOG_ERR, 3970Sstevel@tonic-gate "mapline_to_mapent: parsed with null mapents"); 3980Sstevel@tonic-gate else 3990Sstevel@tonic-gate syslog(LOG_ERR, 4000Sstevel@tonic-gate "mapline_to_mapent: parsed nononempty w=%s", w); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate return (PARSE_ERROR); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate if (trace > 3) 4060Sstevel@tonic-gate trace_mapents("mapline_to_mapent:", *mapents); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate return (PARSE_OK); 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate alloc_failed: 4110Sstevel@tonic-gate syslog(LOG_ERR, "mapline_to_mapent: Memory allocation failed"); 4120Sstevel@tonic-gate return (ENOMEM); 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate /* 4160Sstevel@tonic-gate * hierarchical_sort(struct mapent *mapents, hiernode **rootnode, char *key 4170Sstevel@tonic-gate * char *mapname) 4180Sstevel@tonic-gate * sorts the mntpnts in each mapent to build a hierarchy of nodes, with 4190Sstevel@tonic-gate * with the rootnode being the mount root. The hierarchy is setup as 4200Sstevel@tonic-gate * levels, and subdirs below each level. Provides a link from node to 4210Sstevel@tonic-gate * the relevant mapentry. 4220Sstevel@tonic-gate * Returns PARSE_OK or appropriate error value 4230Sstevel@tonic-gate */ 4240Sstevel@tonic-gate static int 4250Sstevel@tonic-gate hierarchical_sort(struct mapent *mapents, hiernode **rootnode, char *key, 4260Sstevel@tonic-gate char *mapname) 4270Sstevel@tonic-gate { 4280Sstevel@tonic-gate hiernode *prevnode, *currnode, *newnode; 4290Sstevel@tonic-gate char *path; 4300Sstevel@tonic-gate char dirname[MAXFILENAMELEN]; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate int rc = PARSE_OK; 4330Sstevel@tonic-gate struct mapent *me = mapents; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /* allocate the rootnode with a default path of "" */ 4360Sstevel@tonic-gate *rootnode = NULL; 4370Sstevel@tonic-gate if ((rc = alloc_hiernode(rootnode, "")) != PARSE_OK) 4380Sstevel@tonic-gate return (rc); 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate /* 4410Sstevel@tonic-gate * walk through mapents - for each mapent, locate the position 4420Sstevel@tonic-gate * within the hierarchy by walking across leveldirs, and 4430Sstevel@tonic-gate * subdirs of matched leveldirs. Starts one level below 4440Sstevel@tonic-gate * the root (assumes an implicit match with rootnode). 4450Sstevel@tonic-gate * XXX - this could probably be done more cleanly using recursion. 4460Sstevel@tonic-gate */ 4470Sstevel@tonic-gate while (me != NULL) { 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate path = me->map_mntpnt; 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate if ((rc = get_dir_from_path(dirname, &path, 4520Sstevel@tonic-gate sizeof (dirname))) != PARSE_OK) 4530Sstevel@tonic-gate return (rc); 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate prevnode = *rootnode; 4560Sstevel@tonic-gate currnode = (*rootnode)->subdir; 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate while (dirname[0] != '\0') { 4590Sstevel@tonic-gate if (currnode != NULL) { 4600Sstevel@tonic-gate if (strcmp(currnode->dirname, dirname) == 0) { 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * match found - mntpnt is a child of 4630Sstevel@tonic-gate * this node 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate prevnode = currnode; 4660Sstevel@tonic-gate currnode = currnode->subdir; 4670Sstevel@tonic-gate } else { 4680Sstevel@tonic-gate prevnode = currnode; 4690Sstevel@tonic-gate currnode = currnode->leveldir; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate if (currnode == NULL) { 4720Sstevel@tonic-gate /* 4730Sstevel@tonic-gate * No more leveldirs to match. 4740Sstevel@tonic-gate * Add a new one 4750Sstevel@tonic-gate */ 4760Sstevel@tonic-gate if ((rc = alloc_hiernode 4770Sstevel@tonic-gate (&newnode, dirname)) 4780Sstevel@tonic-gate != PARSE_OK) 4790Sstevel@tonic-gate return (rc); 4800Sstevel@tonic-gate prevnode->leveldir = newnode; 4810Sstevel@tonic-gate prevnode = newnode; 4820Sstevel@tonic-gate currnode = newnode->subdir; 4830Sstevel@tonic-gate } else { 4840Sstevel@tonic-gate /* try this leveldir */ 4850Sstevel@tonic-gate continue; 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate } else { 4890Sstevel@tonic-gate /* no more subdirs to match. Add a new one */ 4900Sstevel@tonic-gate if ((rc = alloc_hiernode(&newnode, 4910Sstevel@tonic-gate dirname)) != PARSE_OK) 4920Sstevel@tonic-gate return (rc); 4930Sstevel@tonic-gate prevnode->subdir = newnode; 4940Sstevel@tonic-gate prevnode = newnode; 4950Sstevel@tonic-gate currnode = newnode->subdir; 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate if ((rc = get_dir_from_path(dirname, &path, 4980Sstevel@tonic-gate sizeof (dirname))) != PARSE_OK) 4990Sstevel@tonic-gate return (rc); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate if (prevnode->mapent != NULL) { 5030Sstevel@tonic-gate /* duplicate mntpoint found */ 5040Sstevel@tonic-gate syslog(LOG_ERR, 5050Sstevel@tonic-gate "hierarchical_sort: duplicate mntpnt map=%s key=%s", 5060Sstevel@tonic-gate mapname, key); 5070Sstevel@tonic-gate return (PARSE_ERROR); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /* provide a pointer from node to mapent */ 5110Sstevel@tonic-gate prevnode->mapent = me; 5120Sstevel@tonic-gate me = me->map_next; 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate if (trace > 3) { 5160Sstevel@tonic-gate trace_prt(1, "\n\thierarchical_sort:\n"); 5170Sstevel@tonic-gate trace_hierarchy(*rootnode, 0); /* 0 is rootnode's level */ 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate return (rc); 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate /* 5240Sstevel@tonic-gate * push_options(hiernode *node, char *opts, char *mapopts, int err) 5250Sstevel@tonic-gate * Pushes the options down a hierarchical structure. Works recursively from the 5260Sstevel@tonic-gate * root, which is passed in on the first call. Uses a replacement policy. 5270Sstevel@tonic-gate * If a node points to a mapentry, and it has an option, then thats the option 5280Sstevel@tonic-gate * for that mapentry. Else, the node's mapent inherits the option from the 5290Sstevel@tonic-gate * default (which may be the global option for the entry or mapopts). 5300Sstevel@tonic-gate * err is useful in flagging entries with errors in pushing options. 5310Sstevel@tonic-gate * returns PARSE_OK or appropriate error value. 5320Sstevel@tonic-gate */ 5330Sstevel@tonic-gate static int 5340Sstevel@tonic-gate push_options(hiernode *node, char *defaultopts, char *mapopts, int err) 5350Sstevel@tonic-gate { 5360Sstevel@tonic-gate int rc = PARSE_OK; 5370Sstevel@tonic-gate struct mapent *me = NULL; 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate /* ensure that all the dirs at a level are passed the default options */ 5400Sstevel@tonic-gate while (node != NULL) { 5410Sstevel@tonic-gate me = node->mapent; 5420Sstevel@tonic-gate if (me != NULL) { /* not all nodes point to a mapentry */ 5430Sstevel@tonic-gate me->map_err = err; 5440Sstevel@tonic-gate if ((rc = set_mapent_opts(me, me->map_mntopts, 5450Sstevel@tonic-gate defaultopts, mapopts)) != PARSE_OK) 5460Sstevel@tonic-gate return (rc); 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate /* push the options to subdirs */ 5500Sstevel@tonic-gate if (node->subdir != NULL) { 5510Sstevel@tonic-gate if (node->mapent && strcmp(node->mapent->map_fstype, 5520Sstevel@tonic-gate MNTTYPE_AUTOFS) == 0) 5530Sstevel@tonic-gate err = MAPENT_UATFS; 5540Sstevel@tonic-gate if ((rc = push_options(node->subdir, defaultopts, 5550Sstevel@tonic-gate mapopts, err)) != PARSE_OK) 5560Sstevel@tonic-gate return (rc); 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate node = node->leveldir; 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate return (rc); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate #define BACKFSTYPE "backfstype" /* used in cachefs options */ 5640Sstevel@tonic-gate #define BACKFSTYPE_EQ "backfstype=" 5650Sstevel@tonic-gate #define FSTYPE "fstype" 5660Sstevel@tonic-gate #define FSTYPE_EQ "fstype=" 5670Sstevel@tonic-gate #define NO_OPTS "" 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate /* 5700Sstevel@tonic-gate * set_mapent_opts(struct mapent *me, char *opts, char *defaultopts, 5710Sstevel@tonic-gate * char *mapopts) 5720Sstevel@tonic-gate * sets the mapentry's options, fstype and mounter fields by separating 5730Sstevel@tonic-gate * out the fstype part from the opts. Use default options if opts is NULL. 5740Sstevel@tonic-gate * Note taht defaultopts may be the same as mapopts. 5750Sstevel@tonic-gate * Returns PARSE_OK or appropriate error value. 5760Sstevel@tonic-gate */ 5770Sstevel@tonic-gate static int 5780Sstevel@tonic-gate set_mapent_opts(struct mapent *me, char *opts, char *defaultopts, 5790Sstevel@tonic-gate char *mapopts) 5800Sstevel@tonic-gate { 5810Sstevel@tonic-gate char entryopts[AUTOFS_MAXOPTSLEN]; 5820Sstevel@tonic-gate char fstype[MAX_FSLEN], mounter[MAX_FSLEN]; 5830Sstevel@tonic-gate int rc = PARSE_OK; 5840Sstevel@tonic-gate bool_t fstype_opt = FALSE; 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate strcpy(fstype, MNTTYPE_NFS); /* default */ 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate /* set options to default options, if none exist for this entry */ 5890Sstevel@tonic-gate if (opts == NULL) { 5900Sstevel@tonic-gate opts = defaultopts; 5910Sstevel@tonic-gate if (defaultopts == NULL) { /* NULL opts for entry */ 5920Sstevel@tonic-gate strcpy(mounter, fstype); 5930Sstevel@tonic-gate goto done; 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate if (*opts == '-') 5970Sstevel@tonic-gate opts++; 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate /* separate opts into fstype and (other) entrypopts */ 6000Sstevel@tonic-gate get_opts(opts, entryopts, fstype, &fstype_opt); 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate /* replace any existing opts */ 6030Sstevel@tonic-gate if (me->map_mntopts != NULL) 6040Sstevel@tonic-gate free(me->map_mntopts); 6050Sstevel@tonic-gate if ((me->map_mntopts = strdup(entryopts)) == NULL) 6060Sstevel@tonic-gate return (ENOMEM); 6070Sstevel@tonic-gate strcpy(mounter, fstype); 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate /* 6100Sstevel@tonic-gate * The following ugly chunk of code crept in as a result of 6110Sstevel@tonic-gate * cachefs. If it's a cachefs mount of an nfs filesystem, then 6120Sstevel@tonic-gate * it's important to parse the nfs special field. Otherwise, 6130Sstevel@tonic-gate * just hand the special field to the fs-specific mount 6140Sstevel@tonic-gate */ 6150Sstevel@tonic-gate if (strcmp(fstype, MNTTYPE_CACHEFS) == 0) { 6160Sstevel@tonic-gate struct mnttab m; 6170Sstevel@tonic-gate char *p; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate m.mnt_mntopts = entryopts; 6200Sstevel@tonic-gate if ((p = hasmntopt(&m, BACKFSTYPE)) != NULL) { 6210Sstevel@tonic-gate int len = strlen(MNTTYPE_NFS); 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate p += strlen(BACKFSTYPE_EQ); 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate if (strncmp(p, MNTTYPE_NFS, len) == 0 && 6260Sstevel@tonic-gate (p[len] == '\0' || p[len] == ',')) { 6270Sstevel@tonic-gate /* 6280Sstevel@tonic-gate * Cached nfs mount 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate (void) strcpy(fstype, MNTTYPE_NFS); 6310Sstevel@tonic-gate (void) strcpy(mounter, MNTTYPE_CACHEFS); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate /* 6370Sstevel@tonic-gate * child options are exactly fstype = somefs, we need to do some 6380Sstevel@tonic-gate * more option pushing work. 6390Sstevel@tonic-gate */ 6400Sstevel@tonic-gate if (fstype_opt == TRUE && 6410Sstevel@tonic-gate (strcmp(me->map_mntopts, NO_OPTS) == 0)) { 6420Sstevel@tonic-gate free(me->map_mntopts); 6430Sstevel@tonic-gate if ((rc = fstype_opts(me, opts, defaultopts, 6440Sstevel@tonic-gate mapopts)) != PARSE_OK) 6450Sstevel@tonic-gate return (rc); 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate done: 6490Sstevel@tonic-gate if (((me->map_fstype = strdup(fstype)) == NULL) || 6500Sstevel@tonic-gate ((me->map_mounter = strdup(mounter)) == NULL)) { 6510Sstevel@tonic-gate if (me->map_fstype != NULL) 6520Sstevel@tonic-gate free(me->map_fstype); 6530Sstevel@tonic-gate syslog(LOG_ERR, "set_mapent_opts: No memory"); 6540Sstevel@tonic-gate return (ENOMEM); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate return (rc); 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate /* 6610Sstevel@tonic-gate * Check the option string for an "fstype" 6620Sstevel@tonic-gate * option. If found, return the fstype 6630Sstevel@tonic-gate * and the option string with the fstype 6640Sstevel@tonic-gate * option removed, e.g. 6650Sstevel@tonic-gate * 6660Sstevel@tonic-gate * input: "fstype=cachefs,ro,nosuid" 6670Sstevel@tonic-gate * opts: "ro,nosuid" 6680Sstevel@tonic-gate * fstype: "cachefs" 6690Sstevel@tonic-gate * 6700Sstevel@tonic-gate * Also indicates if the fstype option was present 6710Sstevel@tonic-gate * by setting a flag, if the pointer to the flag 6720Sstevel@tonic-gate * is not NULL. 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate static void 6750Sstevel@tonic-gate get_opts(input, opts, fstype, fstype_opt) 6760Sstevel@tonic-gate char *input; 6770Sstevel@tonic-gate char *opts; /* output */ 6780Sstevel@tonic-gate char *fstype; /* output */ 6790Sstevel@tonic-gate bool_t *fstype_opt; 6800Sstevel@tonic-gate { 6810Sstevel@tonic-gate char *p, *pb; 6820Sstevel@tonic-gate char buf[MAXOPTSLEN]; 6830Sstevel@tonic-gate char *placeholder; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate *opts = '\0'; 6860Sstevel@tonic-gate (void) strcpy(buf, input); 6870Sstevel@tonic-gate pb = buf; 6880Sstevel@tonic-gate while (p = (char *)strtok_r(pb, ",", &placeholder)) { 6890Sstevel@tonic-gate pb = NULL; 6900Sstevel@tonic-gate if (strncmp(p, FSTYPE_EQ, 7) == 0) { 6910Sstevel@tonic-gate if (fstype_opt != NULL) 6920Sstevel@tonic-gate *fstype_opt = TRUE; 6930Sstevel@tonic-gate (void) strcpy(fstype, p + 7); 6940Sstevel@tonic-gate } else { 6950Sstevel@tonic-gate if (*opts) 6960Sstevel@tonic-gate (void) strcat(opts, ","); 6970Sstevel@tonic-gate (void) strcat(opts, p); 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate /* 7030Sstevel@tonic-gate * fstype_opts(struct mapent *me, char *opts, char *defaultopts, 7040Sstevel@tonic-gate * char *mapopts) 7050Sstevel@tonic-gate * We need to push global options to the child entry if it is exactly 7060Sstevel@tonic-gate * fstype=somefs. 7070Sstevel@tonic-gate */ 7080Sstevel@tonic-gate static int 7090Sstevel@tonic-gate fstype_opts(struct mapent *me, char *opts, char *defaultopts, 7100Sstevel@tonic-gate char *mapopts) 7110Sstevel@tonic-gate { 7120Sstevel@tonic-gate char pushopts[AUTOFS_MAXOPTSLEN]; 7130Sstevel@tonic-gate char pushentryopts[AUTOFS_MAXOPTSLEN]; 7140Sstevel@tonic-gate char pushfstype[MAX_FSLEN]; 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate if (defaultopts && *defaultopts == '-') 7170Sstevel@tonic-gate defaultopts++; 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate /* 7200Sstevel@tonic-gate * the options to push are the global defaults for the entry, 7210Sstevel@tonic-gate * if they exist, or mapopts, if the global defaults for the 7220Sstevel@tonic-gate * entry does not exist. 7230Sstevel@tonic-gate */ 7240Sstevel@tonic-gate if (strcmp(defaultopts, opts) == 0) { 7250Sstevel@tonic-gate if (*mapopts == '-') 7260Sstevel@tonic-gate mapopts++; 7270Sstevel@tonic-gate get_opts(mapopts, pushentryopts, pushfstype, NULL); 7280Sstevel@tonic-gate strcpy(pushopts, mapopts); 7290Sstevel@tonic-gate } else { 7300Sstevel@tonic-gate get_opts(defaultopts, pushentryopts, pushfstype, NULL); 7310Sstevel@tonic-gate strcpy(pushopts, defaultopts); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate if (strcmp(pushfstype, MNTTYPE_CACHEFS) == 0) 7350Sstevel@tonic-gate me->map_mntopts = strdup(pushopts); 7360Sstevel@tonic-gate else 7370Sstevel@tonic-gate me->map_mntopts = strdup(pushentryopts); 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate if (!me->map_mntopts) { 7400Sstevel@tonic-gate syslog(LOG_ERR, "fstype_opts: No memory"); 7410Sstevel@tonic-gate return (ENOMEM); 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate return (PARSE_OK); 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate /* 7480Sstevel@tonic-gate * modify_mapents(struct mapent **mapents, char *mapname, 7490Sstevel@tonic-gate * char *mapopts, char *subdir, hiernode *rootnode, 7500Sstevel@tonic-gate * char *key, uint_t isdirect, bool_t mount_access) 7510Sstevel@tonic-gate * modifies the intermediate mapentry list into the final one, and passes 7520Sstevel@tonic-gate * back a pointer to it. The final list may contain faked mapentries for 7530Sstevel@tonic-gate * hiernodes that do not point to a mapentry, or converted mapentries, if 7540Sstevel@tonic-gate * hiernodes that point to a mapentry need to be converted from nfs to autofs. 7550Sstevel@tonic-gate * mounts. Entries that are not directly 1 level below the subdir are removed. 7560Sstevel@tonic-gate * Returns PARSE_OK or PARSE_ERROR 7570Sstevel@tonic-gate */ 7580Sstevel@tonic-gate static int 7590Sstevel@tonic-gate modify_mapents(struct mapent **mapents, char *mapname, 7600Sstevel@tonic-gate char *mapopts, char *subdir, hiernode *rootnode, 7610Sstevel@tonic-gate char *key, uint_t isdirect, bool_t mount_access) 7620Sstevel@tonic-gate { 7630Sstevel@tonic-gate struct mapent *mp = NULL; 7640Sstevel@tonic-gate char w[MAXPATHLEN]; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate struct mapent *me; 7670Sstevel@tonic-gate int rc = PARSE_OK; 7680Sstevel@tonic-gate struct mapent *faked_mapents = NULL; 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate /* 7710Sstevel@tonic-gate * correct the mapentry mntlevel from default -1 to level depending on 7720Sstevel@tonic-gate * position in hierarchy, and build any faked mapentries, if required 7730Sstevel@tonic-gate * at one level below the rootnode given by subdir. 7740Sstevel@tonic-gate */ 7750Sstevel@tonic-gate if ((rc = set_and_fake_mapent_mntlevel(rootnode, subdir, key, mapname, 7760Sstevel@tonic-gate &faked_mapents, isdirect, mapopts, mount_access)) != PARSE_OK) 7770Sstevel@tonic-gate return (rc); 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate /* 7800Sstevel@tonic-gate * attaches faked mapents to real mapents list. Assumes mapents 7810Sstevel@tonic-gate * is not NULL. 7820Sstevel@tonic-gate */ 7830Sstevel@tonic-gate me = *mapents; 7840Sstevel@tonic-gate while (me->map_next != NULL) 7850Sstevel@tonic-gate me = me->map_next; 7860Sstevel@tonic-gate me->map_next = faked_mapents; 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate /* 7890Sstevel@tonic-gate * get rid of nodes marked at level -1 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate me = *mapents; 7920Sstevel@tonic-gate while (me != NULL) { 7930Sstevel@tonic-gate if ((me->map_mntlevel == -1) || (me->map_err) || 7940Sstevel@tonic-gate (mount_access == FALSE && me->map_mntlevel == 0)) { 7950Sstevel@tonic-gate /* 7960Sstevel@tonic-gate * syslog any errors and free entry 7970Sstevel@tonic-gate */ 7980Sstevel@tonic-gate if (me->map_err) 7990Sstevel@tonic-gate dump_mapent_err(me, key, mapname); 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate if (me == (*mapents)) { 8020Sstevel@tonic-gate /* special case when head has to be freed */ 8030Sstevel@tonic-gate *mapents = me->map_next; 8040Sstevel@tonic-gate if ((*mapents) == NULL) { 8050Sstevel@tonic-gate /* something wierd happened */ 8060Sstevel@tonic-gate if (verbose) 8070Sstevel@tonic-gate syslog(LOG_ERR, 8080Sstevel@tonic-gate "modify_mapents: level error"); 8090Sstevel@tonic-gate return (PARSE_ERROR); 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate /* separate out the node */ 8130Sstevel@tonic-gate me->map_next = NULL; 8140Sstevel@tonic-gate free_mapent(me); 8150Sstevel@tonic-gate me = *mapents; 8160Sstevel@tonic-gate } else { 8170Sstevel@tonic-gate mp->map_next = me->map_next; 8180Sstevel@tonic-gate me->map_next = NULL; 8190Sstevel@tonic-gate free_mapent(me); 8200Sstevel@tonic-gate me = mp->map_next; 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate continue; 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate /* 8260Sstevel@tonic-gate * convert level 1 mapents that are not already autonodes 8270Sstevel@tonic-gate * to autonodes 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate if (me->map_mntlevel == 1 && 8300Sstevel@tonic-gate (strcmp(me->map_fstype, MNTTYPE_AUTOFS) != 0) && 8310Sstevel@tonic-gate (me->map_faked != TRUE)) { 8320Sstevel@tonic-gate if ((rc = convert_mapent_to_automount(me, mapname, 8330Sstevel@tonic-gate mapopts)) != PARSE_OK) 8340Sstevel@tonic-gate return (rc); 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate strcpy(w, (me->map_mntpnt+strlen(subdir))); 8370Sstevel@tonic-gate strcpy(me->map_mntpnt, w); 8380Sstevel@tonic-gate mp = me; 8390Sstevel@tonic-gate me = me->map_next; 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate if (trace > 3) 8430Sstevel@tonic-gate trace_mapents("modify_mapents:", *mapents); 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate return (PARSE_OK); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate /* 8490Sstevel@tonic-gate * set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key, 8500Sstevel@tonic-gate * char *mapname, struct mapent **faked_mapents, 8510Sstevel@tonic-gate * uint_t isdirect, char *mapopts, bool_t mount_access) 8520Sstevel@tonic-gate * sets the mapentry mount levels (depths) with respect to the subdir. 8530Sstevel@tonic-gate * Assigns a value of 0 to the new root. Finds the level1 directories by 8540Sstevel@tonic-gate * calling mark_*_level1_*(). Also cleans off extra /'s in level0 and 8550Sstevel@tonic-gate * level1 map_mntpnts. Note that one level below the new root is an existing 8560Sstevel@tonic-gate * mapentry if there's a mapentry (nfs mount) corresponding to the root, 8570Sstevel@tonic-gate * and the direct subdir set for the root, if there's no mapentry corresponding 8580Sstevel@tonic-gate * to the root (we install autodirs). Returns PARSE_OK or error value. 8590Sstevel@tonic-gate */ 8600Sstevel@tonic-gate static int 8610Sstevel@tonic-gate set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key, 8620Sstevel@tonic-gate char *mapname, struct mapent **faked_mapents, 8630Sstevel@tonic-gate uint_t isdirect, char *mapopts, bool_t mount_access) 8640Sstevel@tonic-gate { 8650Sstevel@tonic-gate char dirname[MAXFILENAMELEN]; 8660Sstevel@tonic-gate char traversed_path[MAXPATHLEN]; /* used in building fake mapentries */ 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate char *subdir_child = subdir; 8690Sstevel@tonic-gate hiernode *prevnode = rootnode; 8700Sstevel@tonic-gate hiernode *currnode = rootnode->subdir; 8710Sstevel@tonic-gate int rc = PARSE_OK; 8720Sstevel@tonic-gate traversed_path[0] = '\0'; 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate /* 8750Sstevel@tonic-gate * find and mark the root by tracing down subdir. Use traversed_path 8760Sstevel@tonic-gate * to keep track of how far we go, while guaranteeing that it 8770Sstevel@tonic-gate * contains no '/' at the end. Took some mucking to get that right. 8780Sstevel@tonic-gate */ 8790Sstevel@tonic-gate if ((rc = get_dir_from_path(dirname, &subdir_child, sizeof (dirname))) 8800Sstevel@tonic-gate != PARSE_OK) 8810Sstevel@tonic-gate return (rc); 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate if (dirname[0] != '\0') 8840Sstevel@tonic-gate sprintf(traversed_path, "%s/%s", traversed_path, dirname); 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate prevnode = rootnode; 8870Sstevel@tonic-gate currnode = rootnode->subdir; 8880Sstevel@tonic-gate while (dirname[0] != '\0' && currnode != NULL) { 8890Sstevel@tonic-gate if (strcmp(currnode->dirname, dirname) == 0) { 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate /* subdir is a child of currnode */ 8920Sstevel@tonic-gate prevnode = currnode; 8930Sstevel@tonic-gate currnode = currnode->subdir; 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate if ((rc = get_dir_from_path(dirname, &subdir_child, 8960Sstevel@tonic-gate sizeof (dirname))) != PARSE_OK) 8970Sstevel@tonic-gate return (rc); 8980Sstevel@tonic-gate if (dirname[0] != '\0') 8990Sstevel@tonic-gate sprintf(traversed_path, "%s/%s", 9000Sstevel@tonic-gate traversed_path, dirname); 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate } else { 9030Sstevel@tonic-gate /* try next leveldir */ 9040Sstevel@tonic-gate prevnode = currnode; 9050Sstevel@tonic-gate currnode = currnode->leveldir; 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate if (dirname[0] != '\0') { 9100Sstevel@tonic-gate if (verbose) 9110Sstevel@tonic-gate syslog(LOG_ERR, 9120Sstevel@tonic-gate "set_and_fake_mapent_mntlevel: subdir=%s error: map=%s", 9130Sstevel@tonic-gate subdir, mapname); 9140Sstevel@tonic-gate return (PARSE_ERROR); 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate /* 9180Sstevel@tonic-gate * see if level of root really points to a mapent and if 9190Sstevel@tonic-gate * have access to that filessystem - call appropriate 9200Sstevel@tonic-gate * routine to mark level 1 nodes, and build faked entries 9210Sstevel@tonic-gate */ 9220Sstevel@tonic-gate if (prevnode->mapent != NULL && mount_access == TRUE) { 9230Sstevel@tonic-gate if (trace > 3) 9240Sstevel@tonic-gate trace_prt(1, " node mountpoint %s\t travpath=%s\n", 9250Sstevel@tonic-gate prevnode->mapent->map_mntpnt, traversed_path); 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate /* 9280Sstevel@tonic-gate * Copy traversed path map_mntpnt to get rid of any extra 9290Sstevel@tonic-gate * '/' the map entry may contain. 9300Sstevel@tonic-gate */ 9310Sstevel@tonic-gate if (strlen(prevnode->mapent->map_mntpnt) < 9320Sstevel@tonic-gate strlen(traversed_path)) { /* sanity check */ 9330Sstevel@tonic-gate if (verbose) 9340Sstevel@tonic-gate syslog(LOG_ERR, 9350Sstevel@tonic-gate "set_and_fake_mapent_mntlevel: path=%s error", 9360Sstevel@tonic-gate traversed_path); 9370Sstevel@tonic-gate return (PARSE_ERROR); 9380Sstevel@tonic-gate } 9390Sstevel@tonic-gate if (strcmp(prevnode->mapent->map_mntpnt, traversed_path) != 0) 9400Sstevel@tonic-gate strcpy(prevnode->mapent->map_mntpnt, traversed_path); 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate prevnode->mapent->map_mntlevel = 0; /* root level is 0 */ 9430Sstevel@tonic-gate if (currnode != NULL) { 9440Sstevel@tonic-gate if ((rc = mark_level1_root(currnode, 9450Sstevel@tonic-gate traversed_path)) != PARSE_OK) 9460Sstevel@tonic-gate return (rc); 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate } else if (currnode != NULL) { 9490Sstevel@tonic-gate if (trace > 3) 9500Sstevel@tonic-gate trace_prt(1, " No rootnode, travpath=%s\n", 9510Sstevel@tonic-gate traversed_path); 9520Sstevel@tonic-gate if ((rc = mark_and_fake_level1_noroot(currnode, 9530Sstevel@tonic-gate traversed_path, key, mapname, faked_mapents, isdirect, 9540Sstevel@tonic-gate mapopts)) != PARSE_OK) 9550Sstevel@tonic-gate return (rc); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate if (trace > 3) { 9590Sstevel@tonic-gate trace_prt(1, "\n\tset_and_fake_mapent_mntlevel\n"); 9600Sstevel@tonic-gate trace_hierarchy(rootnode, 0); 9610Sstevel@tonic-gate } 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate return (rc); 9640Sstevel@tonic-gate } 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate /* 9680Sstevel@tonic-gate * mark_level1_root(hiernode *node, char *traversed_path) 9690Sstevel@tonic-gate * marks nodes upto one level below the rootnode given by subdir 9700Sstevel@tonic-gate * recursively. Called if rootnode points to a mapent. 9710Sstevel@tonic-gate * In this routine, a level 1 node is considered to be the 1st existing 9720Sstevel@tonic-gate * mapentry below the root node, so there's no faking involved. 9730Sstevel@tonic-gate * Returns PARSE_OK or error value 9740Sstevel@tonic-gate */ 9750Sstevel@tonic-gate static int 9760Sstevel@tonic-gate mark_level1_root(hiernode *node, char *traversed_path) 9770Sstevel@tonic-gate { 9780Sstevel@tonic-gate /* ensure we touch all leveldirs */ 9790Sstevel@tonic-gate while (node) { 9800Sstevel@tonic-gate /* 9810Sstevel@tonic-gate * mark node level as 1, if one exists - else walk down 9820Sstevel@tonic-gate * subdirs until we find one. 9830Sstevel@tonic-gate */ 9840Sstevel@tonic-gate if (node->mapent == NULL) { 9850Sstevel@tonic-gate char w[MAXPATHLEN]; 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate if (node->subdir != NULL) { 9880Sstevel@tonic-gate sprintf(w, "%s/%s", traversed_path, 9890Sstevel@tonic-gate node->dirname); 9900Sstevel@tonic-gate if (mark_level1_root(node->subdir, w) 9910Sstevel@tonic-gate == PARSE_ERROR) 9920Sstevel@tonic-gate return (PARSE_ERROR); 9930Sstevel@tonic-gate } else { 9940Sstevel@tonic-gate if (verbose) { 9950Sstevel@tonic-gate syslog(LOG_ERR, 9960Sstevel@tonic-gate "mark_level1_root: hierarchy error"); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate return (PARSE_ERROR); 9990Sstevel@tonic-gate } 10000Sstevel@tonic-gate } else { 10010Sstevel@tonic-gate char w[MAXPATHLEN]; 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate sprintf(w, "%s/%s", traversed_path, node->dirname); 10040Sstevel@tonic-gate if (trace > 3) 10050Sstevel@tonic-gate trace_prt(1, " node mntpnt %s\t travpath %s\n", 10060Sstevel@tonic-gate node->mapent->map_mntpnt, w); 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate /* replace mntpnt with travpath to clean extra '/' */ 10090Sstevel@tonic-gate if (strlen(node->mapent->map_mntpnt) < strlen(w)) { 10100Sstevel@tonic-gate if (verbose) { 10110Sstevel@tonic-gate syslog(LOG_ERR, 10120Sstevel@tonic-gate "mark_level1_root: path=%s error", 10130Sstevel@tonic-gate traversed_path); 10140Sstevel@tonic-gate } 10150Sstevel@tonic-gate return (PARSE_ERROR); 10160Sstevel@tonic-gate } 10170Sstevel@tonic-gate if (strcmp(node->mapent->map_mntpnt, w) != 0) 10180Sstevel@tonic-gate strcpy(node->mapent->map_mntpnt, w); 10190Sstevel@tonic-gate node->mapent->map_mntlevel = 1; 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate node = node->leveldir; 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate return (PARSE_OK); 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate /* 10270Sstevel@tonic-gate * mark_and_fake_level1_noroot(hiernode *node, char *traversed_path, 10280Sstevel@tonic-gate * char *key,char *mapname, struct mapent **faked_mapents, 10290Sstevel@tonic-gate * uint_t isdirect, char *mapopts) 10300Sstevel@tonic-gate * Called if the root of the hierarchy does not point to a mapent. marks nodes 10310Sstevel@tonic-gate * upto one physical level below the rootnode given by subdir. checks if 10320Sstevel@tonic-gate * there's a real mapentry. If not, it builds a faked one (autonode) at that 10330Sstevel@tonic-gate * point. The faked autonode is direct, with the map being the same as the 10340Sstevel@tonic-gate * original one from which the call originated. Options are same as that of 10350Sstevel@tonic-gate * the map and assigned in automount_opts(). Returns PARSE_OK or error value. 10360Sstevel@tonic-gate */ 10370Sstevel@tonic-gate static int 10380Sstevel@tonic-gate mark_and_fake_level1_noroot(hiernode *node, char *traversed_path, 10390Sstevel@tonic-gate char *key, char *mapname, struct mapent **faked_mapents, 10400Sstevel@tonic-gate uint_t isdirect, char *mapopts) 10410Sstevel@tonic-gate { 10420Sstevel@tonic-gate struct mapent *me; 10430Sstevel@tonic-gate int rc = 0; 10440Sstevel@tonic-gate char faked_map_mntpnt[MAXPATHLEN]; 10450Sstevel@tonic-gate char w1[MAXPATHLEN]; 10460Sstevel@tonic-gate char w[MAXPATHLEN]; 10470Sstevel@tonic-gate 10480Sstevel@tonic-gate while (node != NULL) { 10490Sstevel@tonic-gate if (node->mapent != NULL) { 10500Sstevel@tonic-gate /* 10510Sstevel@tonic-gate * existing mapentry at level 1 - copy travpath to 10520Sstevel@tonic-gate * get rid of extra '/' in mntpnt 10530Sstevel@tonic-gate */ 10540Sstevel@tonic-gate sprintf(w, "%s/%s", traversed_path, node->dirname); 10550Sstevel@tonic-gate if (trace > 3) 10560Sstevel@tonic-gate trace_prt(1, " node mntpnt=%s\t travpath=%s\n", 10570Sstevel@tonic-gate node->mapent->map_mntpnt, w); 10580Sstevel@tonic-gate if (strlen(node->mapent->map_mntpnt) < strlen(w)) { 10590Sstevel@tonic-gate /* sanity check */ 10600Sstevel@tonic-gate if (verbose) 10610Sstevel@tonic-gate syslog(LOG_ERR, 10620Sstevel@tonic-gate "mark_fake_level1_noroot:path=%s error", 10630Sstevel@tonic-gate traversed_path); 10640Sstevel@tonic-gate return (PARSE_ERROR); 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate if (strcmp(node->mapent->map_mntpnt, w) != 0) 10670Sstevel@tonic-gate strcpy(node->mapent->map_mntpnt, w); 10680Sstevel@tonic-gate node->mapent->map_mntlevel = 1; 10690Sstevel@tonic-gate } else { 10700Sstevel@tonic-gate /* 10710Sstevel@tonic-gate * build the faked autonode 10720Sstevel@tonic-gate */ 10730Sstevel@tonic-gate if ((me = (struct mapent *)malloc(sizeof (*me))) 10740Sstevel@tonic-gate == NULL) { 10750Sstevel@tonic-gate syslog(LOG_ERR, 10760Sstevel@tonic-gate "mark_and_fake_level1_noroot: out of memory"); 10770Sstevel@tonic-gate return (ENOMEM); 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate (void) memset((char *)me, 0, sizeof (*me)); 10800Sstevel@tonic-gate 10810Sstevel@tonic-gate if ((me->map_fs = (struct mapfs *) 10820Sstevel@tonic-gate malloc(sizeof (struct mapfs))) == NULL) 10830Sstevel@tonic-gate return (ENOMEM); 10840Sstevel@tonic-gate (void) memset(me->map_fs, 0, sizeof (struct mapfs)); 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate if (isdirect) { 10870Sstevel@tonic-gate *w1 = '\0'; 10880Sstevel@tonic-gate } else { 10890Sstevel@tonic-gate strcpy(w1, "/"); 10900Sstevel@tonic-gate strcat(w1, key); 10910Sstevel@tonic-gate } 10920Sstevel@tonic-gate me->map_root = strdup(w1); 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate sprintf(faked_map_mntpnt, "%s/%s", traversed_path, 10950Sstevel@tonic-gate node->dirname); 10960Sstevel@tonic-gate me->map_mntpnt = strdup(faked_map_mntpnt); 10970Sstevel@tonic-gate me->map_fstype = strdup(MNTTYPE_AUTOFS); 10980Sstevel@tonic-gate me->map_mounter = strdup(MNTTYPE_AUTOFS); 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate /* set options */ 11010Sstevel@tonic-gate if ((rc = automount_opts(&me->map_mntopts, mapopts)) 11020Sstevel@tonic-gate != PARSE_OK) 11030Sstevel@tonic-gate return (rc); 11040Sstevel@tonic-gate me->map_fs->mfs_dir = strdup(mapname); 11050Sstevel@tonic-gate me->map_mntlevel = 1; 11060Sstevel@tonic-gate me->map_modified = FALSE; 11070Sstevel@tonic-gate me->map_faked = TRUE; /* mark as faked */ 11080Sstevel@tonic-gate if (me->map_root == NULL || 11090Sstevel@tonic-gate me->map_mntpnt == NULL || 11100Sstevel@tonic-gate me->map_fstype == NULL || 11110Sstevel@tonic-gate me->map_mounter == NULL || 11120Sstevel@tonic-gate me->map_mntopts == NULL || 11130Sstevel@tonic-gate me->map_fs->mfs_dir == NULL) { 11140Sstevel@tonic-gate syslog(LOG_ERR, 11150Sstevel@tonic-gate "mark_and_fake_level1_noroot: out of memory"); 11160Sstevel@tonic-gate free_mapent(*faked_mapents); 11170Sstevel@tonic-gate return (ENOMEM); 11180Sstevel@tonic-gate } 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate if (*faked_mapents == NULL) 11210Sstevel@tonic-gate *faked_mapents = me; 11220Sstevel@tonic-gate else { /* attach to the head */ 11230Sstevel@tonic-gate me->map_next = *faked_mapents; 11240Sstevel@tonic-gate *faked_mapents = me; 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate node->mapent = me; 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate node = node->leveldir; 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate return (rc); 11310Sstevel@tonic-gate } 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate /* 11340Sstevel@tonic-gate * convert_mapent_to_automount(struct mapent *me, char *mapname, 11350Sstevel@tonic-gate * char *mapopts) 11360Sstevel@tonic-gate * change the mapentry me to an automount - free fields first and NULL them 11370Sstevel@tonic-gate * to avoid freeing again, while freeing the mapentry at a later stage. 11380Sstevel@tonic-gate * Could have avoided freeing entries here as we don't really look at them. 11390Sstevel@tonic-gate * Give the converted mapent entry the options that came with the map using 11400Sstevel@tonic-gate * automount_opts(). Returns PARSE_OK or appropriate error value. 11410Sstevel@tonic-gate */ 11420Sstevel@tonic-gate static int 11430Sstevel@tonic-gate convert_mapent_to_automount(struct mapent *me, char *mapname, 11440Sstevel@tonic-gate char *mapopts) 11450Sstevel@tonic-gate { 11460Sstevel@tonic-gate struct mapfs *mfs = me->map_fs; /* assumes it exists */ 11470Sstevel@tonic-gate int rc = PARSE_OK; 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate /* free relevant entries */ 11500Sstevel@tonic-gate if (mfs->mfs_host) { 11510Sstevel@tonic-gate free(mfs->mfs_host); 11520Sstevel@tonic-gate mfs->mfs_host = NULL; 11530Sstevel@tonic-gate } 11540Sstevel@tonic-gate while (me->map_fs->mfs_next != NULL) { 11550Sstevel@tonic-gate mfs = me->map_fs->mfs_next; 11560Sstevel@tonic-gate if (mfs->mfs_host) 11570Sstevel@tonic-gate free(mfs->mfs_host); 11580Sstevel@tonic-gate if (mfs->mfs_dir) 11590Sstevel@tonic-gate free(mfs->mfs_dir); 11600Sstevel@tonic-gate me->map_fs->mfs_next = mfs->mfs_next; /* nulls eventually */ 11610Sstevel@tonic-gate free((void*)mfs); 11620Sstevel@tonic-gate } 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate /* replace relevant entries */ 11650Sstevel@tonic-gate if (me->map_fstype) 11660Sstevel@tonic-gate free(me->map_fstype); 11670Sstevel@tonic-gate if ((me->map_fstype = strdup(MNTTYPE_AUTOFS)) == NULL) 11680Sstevel@tonic-gate goto alloc_failed; 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate if (me->map_mounter) 11710Sstevel@tonic-gate free(me->map_mounter); 11720Sstevel@tonic-gate if ((me->map_mounter = strdup(me->map_fstype)) == NULL) 11730Sstevel@tonic-gate goto alloc_failed; 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate if (me->map_fs->mfs_dir) 11760Sstevel@tonic-gate free(me->map_fs->mfs_dir); 11770Sstevel@tonic-gate if ((me->map_fs->mfs_dir = strdup(mapname)) == NULL) 11780Sstevel@tonic-gate goto alloc_failed; 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate /* set options */ 11810Sstevel@tonic-gate if (me->map_mntopts) 11820Sstevel@tonic-gate free(me->map_mntopts); 11830Sstevel@tonic-gate if ((rc = automount_opts(&me->map_mntopts, mapopts)) != PARSE_OK) 11840Sstevel@tonic-gate return (rc); 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate /* mucked with this entry, set the map_modified field to TRUE */ 11870Sstevel@tonic-gate me->map_modified = TRUE; 11880Sstevel@tonic-gate 11890Sstevel@tonic-gate return (rc); 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate alloc_failed: 11920Sstevel@tonic-gate syslog(LOG_ERR, 11930Sstevel@tonic-gate "convert_mapent_to_automount: Memory allocation failed"); 11940Sstevel@tonic-gate return (ENOMEM); 11950Sstevel@tonic-gate } 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate /* 11980Sstevel@tonic-gate * automount_opts(char **map_mntopts, char *mapopts) 11990Sstevel@tonic-gate * modifies automount opts - gets rid of all "indirect" and "direct" strings 12000Sstevel@tonic-gate * if they exist, and then adds a direct string to force a direct automount. 12010Sstevel@tonic-gate * Rest of the mapopts stay intact. Returns PARSE_OK or appropriate error. 12020Sstevel@tonic-gate */ 12030Sstevel@tonic-gate static int 12040Sstevel@tonic-gate automount_opts(char **map_mntopts, char *mapopts) 12050Sstevel@tonic-gate { 12060Sstevel@tonic-gate char *opts; 12070Sstevel@tonic-gate char *opt; 12080Sstevel@tonic-gate int len; 12090Sstevel@tonic-gate char *placeholder; 12100Sstevel@tonic-gate char buf[AUTOFS_MAXOPTSLEN]; 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate char *addopt = "direct"; 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate len = strlen(mapopts)+ strlen(addopt)+2; /* +2 for ",", '\0' */ 12150Sstevel@tonic-gate if (len > AUTOFS_MAXOPTSLEN) { 12160Sstevel@tonic-gate syslog(LOG_ERR, 12170Sstevel@tonic-gate "option string %s too long (max=%d)", mapopts, 12180Sstevel@tonic-gate AUTOFS_MAXOPTSLEN-8); 12190Sstevel@tonic-gate return (PARSE_ERROR); 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate if (((*map_mntopts) = ((char *)malloc(len))) == NULL) { 12230Sstevel@tonic-gate syslog(LOG_ERR, "automount_opts: Memory allocation failed"); 12240Sstevel@tonic-gate return (ENOMEM); 12250Sstevel@tonic-gate } 12260Sstevel@tonic-gate memset(*map_mntopts, 0, len); 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate strcpy(buf, mapopts); 12290Sstevel@tonic-gate opts = buf; 12300Sstevel@tonic-gate while ((opt = strtok_r(opts, ",", &placeholder)) != NULL) { 12310Sstevel@tonic-gate opts = NULL; 12320Sstevel@tonic-gate 12330Sstevel@tonic-gate /* remove trailing and leading spaces */ 12340Sstevel@tonic-gate while (isspace(*opt)) 12350Sstevel@tonic-gate opt++; 12360Sstevel@tonic-gate len = strlen(opt)-1; 12370Sstevel@tonic-gate while (isspace(opt[len])) 12380Sstevel@tonic-gate opt[len--] = '\0'; 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate /* 12410Sstevel@tonic-gate * if direct or indirect found, get rid of it, else put it 12420Sstevel@tonic-gate * back 12430Sstevel@tonic-gate */ 12440Sstevel@tonic-gate if ((strcmp(opt, "indirect") == 0) || 12450Sstevel@tonic-gate (strcmp(opt, "direct") == 0)) 12460Sstevel@tonic-gate continue; 12470Sstevel@tonic-gate if (*map_mntopts[0] != '\0') 12480Sstevel@tonic-gate strcat(*map_mntopts, ","); 12490Sstevel@tonic-gate strcat(*map_mntopts, opt); 12500Sstevel@tonic-gate } 12510Sstevel@tonic-gate 12520Sstevel@tonic-gate /* add the direct string at the end */ 12530Sstevel@tonic-gate if (*map_mntopts[0] != '\0') 12540Sstevel@tonic-gate strcat(*map_mntopts, ","); 12550Sstevel@tonic-gate strcat(*map_mntopts, addopt); 12560Sstevel@tonic-gate 12570Sstevel@tonic-gate return (PARSE_OK); 12580Sstevel@tonic-gate } 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate /* 12610Sstevel@tonic-gate * parse_fsinfo(char *mapname, struct mapent *mapents) 12620Sstevel@tonic-gate * parses the filesystem information stored in me->map_fsw and me->map_fswq 12630Sstevel@tonic-gate * and calls appropriate filesystem parser. 12640Sstevel@tonic-gate * Returns PARSE_OK or an appropriate error value. 12650Sstevel@tonic-gate */ 12660Sstevel@tonic-gate static int 12670Sstevel@tonic-gate parse_fsinfo(char *mapname, struct mapent *mapents) 12680Sstevel@tonic-gate { 12690Sstevel@tonic-gate struct mapent *me = mapents; 12700Sstevel@tonic-gate char *bufp; 12710Sstevel@tonic-gate char *bufq; 12720Sstevel@tonic-gate int wordsz = MAXPATHLEN; 12730Sstevel@tonic-gate int err = 0; 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate while (me != NULL) { 12760Sstevel@tonic-gate bufp = ""; 12770Sstevel@tonic-gate bufq = ""; 12780Sstevel@tonic-gate if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) { 12790Sstevel@tonic-gate err = parse_nfs(mapname, me, me->map_fsw, 12800Sstevel@tonic-gate me->map_fswq, &bufp, &bufq, wordsz); 12810Sstevel@tonic-gate } else { 12820Sstevel@tonic-gate err = parse_special(me, me->map_fsw, me->map_fswq, 12830Sstevel@tonic-gate &bufp, &bufq, wordsz); 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate if (err != PARSE_OK || *me->map_fsw != '\0' || 12870Sstevel@tonic-gate *me->map_fswq != '\0') { 12880Sstevel@tonic-gate /* sanity check */ 12890Sstevel@tonic-gate if (verbose) 12900Sstevel@tonic-gate syslog(LOG_ERR, 12910Sstevel@tonic-gate "parse_fsinfo: mount location error %s", 12920Sstevel@tonic-gate me->map_fsw); 12930Sstevel@tonic-gate return (PARSE_ERROR); 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate me = me->map_next; 12970Sstevel@tonic-gate } 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate if (trace > 3) { 13000Sstevel@tonic-gate trace_mapents("parse_fsinfo:", mapents); 13010Sstevel@tonic-gate } 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate return (PARSE_OK); 13040Sstevel@tonic-gate } 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate /* 13070Sstevel@tonic-gate * This function parses the map entry for a nfs type file system 13080Sstevel@tonic-gate * The input is the string lp (and lq) which can be one of the 13090Sstevel@tonic-gate * following forms: 13100Sstevel@tonic-gate * a) host[(penalty)][,host[(penalty)]]... :/directory 13110Sstevel@tonic-gate * b) host[(penalty)]:/directory[ host[(penalty)]:/directory]... 13120Sstevel@tonic-gate * This routine constructs a mapfs link-list for each of 13130Sstevel@tonic-gate * the hosts and the corresponding file system. The list 13140Sstevel@tonic-gate * is then attatched to the mapent struct passed in. 13150Sstevel@tonic-gate */ 1316*249Sjwahlig int 13170Sstevel@tonic-gate parse_nfs(mapname, me, fsw, fswq, lp, lq, wsize) 13180Sstevel@tonic-gate struct mapent *me; 13190Sstevel@tonic-gate char *mapname, *fsw, *fswq, **lp, **lq; 13200Sstevel@tonic-gate int wsize; 13210Sstevel@tonic-gate { 13220Sstevel@tonic-gate struct mapfs *mfs, **mfsp; 13230Sstevel@tonic-gate char *wlp, *wlq; 13240Sstevel@tonic-gate char *hl, hostlist[1024], *hlq, hostlistq[1024]; 13250Sstevel@tonic-gate char hostname_and_penalty[MXHOSTNAMELEN+5]; 13260Sstevel@tonic-gate char *hn, *hnq, hostname[MXHOSTNAMELEN+1]; 13270Sstevel@tonic-gate char dirname[MAXPATHLEN+1], subdir[MAXPATHLEN+1]; 13280Sstevel@tonic-gate char qbuff[MAXPATHLEN+1], qbuff1[MAXPATHLEN+1]; 13290Sstevel@tonic-gate char pbuff[10], pbuffq[10]; 13300Sstevel@tonic-gate int penalty; 13310Sstevel@tonic-gate char w[MAXPATHLEN]; 13320Sstevel@tonic-gate char wq[MAXPATHLEN]; 13330Sstevel@tonic-gate int host_cnt; 13340Sstevel@tonic-gate 13350Sstevel@tonic-gate mfsp = &me->map_fs; 13360Sstevel@tonic-gate *mfsp = NULL; 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate /* 13390Sstevel@tonic-gate * there may be more than one entry in the map list. Get the 13400Sstevel@tonic-gate * first one. Use temps to handle the word information and 13410Sstevel@tonic-gate * copy back into fsw and fswq fields when done. 13420Sstevel@tonic-gate */ 13430Sstevel@tonic-gate *lp = fsw; 13440Sstevel@tonic-gate *lq = fswq; 13450Sstevel@tonic-gate if (getword(w, wq, lp, lq, ' ', wsize) == -1) 13460Sstevel@tonic-gate return (PARSE_ERROR); 13470Sstevel@tonic-gate while (*w && *w != '/') { 13480Sstevel@tonic-gate bool_t maybe_url; 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate maybe_url = TRUE; 13510Sstevel@tonic-gate 13520Sstevel@tonic-gate wlp = w; wlq = wq; 13530Sstevel@tonic-gate if (getword(hostlist, hostlistq, &wlp, &wlq, ':', 13540Sstevel@tonic-gate sizeof (hostlist)) == -1) 13550Sstevel@tonic-gate return (PARSE_ERROR); 13560Sstevel@tonic-gate if (!*hostlist) 13570Sstevel@tonic-gate goto bad_entry; 13580Sstevel@tonic-gate 13590Sstevel@tonic-gate if (strcmp(hostlist, "nfs") != 0) 13600Sstevel@tonic-gate maybe_url = FALSE; 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate if (getword(dirname, qbuff, &wlp, &wlq, ':', 13630Sstevel@tonic-gate sizeof (dirname)) == -1) 13640Sstevel@tonic-gate return (PARSE_ERROR); 13650Sstevel@tonic-gate if (*dirname == '\0') 13660Sstevel@tonic-gate goto bad_entry; 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate if (maybe_url == TRUE && strncmp(dirname, "//", 2) != 0) 13690Sstevel@tonic-gate maybe_url = FALSE; 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate /* 13720Sstevel@tonic-gate * See the next block comment ("Once upon a time ...") to 13730Sstevel@tonic-gate * understand this. It turns the deprecated concept 13740Sstevel@tonic-gate * of "subdir mounts" produced some useful code for handling 13750Sstevel@tonic-gate * the possibility of a ":port#" in the URL. 13760Sstevel@tonic-gate */ 13770Sstevel@tonic-gate if (maybe_url == FALSE) 13780Sstevel@tonic-gate *subdir = '/'; 13790Sstevel@tonic-gate else 13800Sstevel@tonic-gate *subdir = ':'; 13810Sstevel@tonic-gate 13820Sstevel@tonic-gate *qbuff = ' '; 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate /* 13850Sstevel@tonic-gate * Once upon time, before autofs, there was support for 13860Sstevel@tonic-gate * "subdir mounts". The idea was to "economize" the 13870Sstevel@tonic-gate * number of mounts, so if you had a number of entries 13880Sstevel@tonic-gate * all referring to a common subdirectory, e.g. 13890Sstevel@tonic-gate * 13900Sstevel@tonic-gate * carol seasons:/export/home11/carol 13910Sstevel@tonic-gate * ted seasons:/export/home11/ted 13920Sstevel@tonic-gate * alice seasons:/export/home11/alice 13930Sstevel@tonic-gate * 13940Sstevel@tonic-gate * then you could tell the automounter to mount a 13950Sstevel@tonic-gate * common mountpoint which was delimited by the second 13960Sstevel@tonic-gate * colon: 13970Sstevel@tonic-gate * 13980Sstevel@tonic-gate * carol seasons:/export/home11:carol 13990Sstevel@tonic-gate * ted seasons:/export/home11:ted 14000Sstevel@tonic-gate * alice seasons:/export/home11:alice 14010Sstevel@tonic-gate * 14020Sstevel@tonic-gate * The automounter would mount seasons:/export/home11 14030Sstevel@tonic-gate * then for any other map entry that referenced the same 14040Sstevel@tonic-gate * directory it would build a symbolic link that 14050Sstevel@tonic-gate * appended the remainder of the path after the second 14060Sstevel@tonic-gate * colon, i.e. once the common subdir was mounted, then 14070Sstevel@tonic-gate * other directories could be accessed just by link 14080Sstevel@tonic-gate * building - no further mounts required. 14090Sstevel@tonic-gate * 14100Sstevel@tonic-gate * In theory the "mount saving" idea sounded good. In 14110Sstevel@tonic-gate * practice the saving didn't amount to much and the 14120Sstevel@tonic-gate * symbolic links confused people because the common 14130Sstevel@tonic-gate * mountpoint had to have a pseudonym. 14140Sstevel@tonic-gate * 14150Sstevel@tonic-gate * To remain backward compatible with the existing 14160Sstevel@tonic-gate * maps, we interpret a second colon as a slash. 14170Sstevel@tonic-gate */ 14180Sstevel@tonic-gate if (getword(subdir+1, qbuff+1, &wlp, &wlq, ':', 14190Sstevel@tonic-gate sizeof (subdir)) == -1) 14200Sstevel@tonic-gate return (PARSE_ERROR); 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate if (*(subdir+1)) 14230Sstevel@tonic-gate (void) strcat(dirname, subdir); 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate hl = hostlist; hlq = hostlistq; 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate host_cnt = 0; 14280Sstevel@tonic-gate for (;;) { 14290Sstevel@tonic-gate 14300Sstevel@tonic-gate if (getword(hostname_and_penalty, qbuff, &hl, &hlq, ',', 14310Sstevel@tonic-gate sizeof (hostname_and_penalty)) == -1) 14320Sstevel@tonic-gate return (PARSE_ERROR); 14330Sstevel@tonic-gate if (!*hostname_and_penalty) 14340Sstevel@tonic-gate break; 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate host_cnt++; 14370Sstevel@tonic-gate if (host_cnt > 1) 14380Sstevel@tonic-gate maybe_url = FALSE; 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate hn = hostname_and_penalty; 14410Sstevel@tonic-gate hnq = qbuff; 14420Sstevel@tonic-gate if (getword(hostname, qbuff1, &hn, &hnq, '(', 14430Sstevel@tonic-gate sizeof (hostname)) == -1) 14440Sstevel@tonic-gate return (PARSE_ERROR); 14450Sstevel@tonic-gate if (hostname[0] == '\0') 14460Sstevel@tonic-gate goto bad_entry; 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate if (strcmp(hostname, hostname_and_penalty) == 0) { 14490Sstevel@tonic-gate penalty = 0; 14500Sstevel@tonic-gate } else { 14510Sstevel@tonic-gate maybe_url = FALSE; 14520Sstevel@tonic-gate hn++; hnq++; 14530Sstevel@tonic-gate if (getword(pbuff, pbuffq, &hn, &hnq, ')', 14540Sstevel@tonic-gate sizeof (pbuff)) == -1) 14550Sstevel@tonic-gate return (PARSE_ERROR); 14560Sstevel@tonic-gate if (!*pbuff) 14570Sstevel@tonic-gate penalty = 0; 14580Sstevel@tonic-gate else 14590Sstevel@tonic-gate penalty = atoi(pbuff); 14600Sstevel@tonic-gate } 14610Sstevel@tonic-gate mfs = (struct mapfs *)malloc(sizeof (*mfs)); 14620Sstevel@tonic-gate if (mfs == NULL) { 14630Sstevel@tonic-gate syslog(LOG_ERR, 14640Sstevel@tonic-gate "parse_nfs: Memory allocation failed"); 14650Sstevel@tonic-gate return (PARSE_ERROR); 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate (void) memset(mfs, 0, sizeof (*mfs)); 14680Sstevel@tonic-gate *mfsp = mfs; 14690Sstevel@tonic-gate mfsp = &mfs->mfs_next; 14700Sstevel@tonic-gate 14710Sstevel@tonic-gate if (maybe_url == TRUE) { 14720Sstevel@tonic-gate char *host; 14730Sstevel@tonic-gate char *path; 14740Sstevel@tonic-gate char *sport; 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate host = dirname+2; 14770Sstevel@tonic-gate path = strchr(host, '/'); 14780Sstevel@tonic-gate if (path == NULL) { 14790Sstevel@tonic-gate syslog(LOG_ERR, 14800Sstevel@tonic-gate "parse_nfs: illegal nfs url syntax: %s", 14810Sstevel@tonic-gate host); 14820Sstevel@tonic-gate 14830Sstevel@tonic-gate return (PARSE_ERROR); 14840Sstevel@tonic-gate } 14850Sstevel@tonic-gate *path = '\0'; 14860Sstevel@tonic-gate sport = strchr(host, ':'); 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate if (sport != NULL && sport < path) { 14890Sstevel@tonic-gate *sport = '\0'; 14900Sstevel@tonic-gate mfs->mfs_port = atoi(sport+1); 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate if (mfs->mfs_port > USHRT_MAX) { 14930Sstevel@tonic-gate syslog(LOG_ERR, 14940Sstevel@tonic-gate "parse_nfs: invalid " 14950Sstevel@tonic-gate "port number (%d) in " 14960Sstevel@tonic-gate "NFS URL", 14970Sstevel@tonic-gate mfs->mfs_port); 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate return (PARSE_ERROR); 15000Sstevel@tonic-gate } 15010Sstevel@tonic-gate 15020Sstevel@tonic-gate } 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate path++; 15050Sstevel@tonic-gate if (*path == '\0') 15060Sstevel@tonic-gate path = "."; 15070Sstevel@tonic-gate 15080Sstevel@tonic-gate mfs->mfs_flags |= MFS_URL; 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate mfs->mfs_host = strdup(host); 15110Sstevel@tonic-gate mfs->mfs_dir = strdup(path); 15120Sstevel@tonic-gate } else { 15130Sstevel@tonic-gate mfs->mfs_host = strdup(hostname); 15140Sstevel@tonic-gate mfs->mfs_dir = strdup(dirname); 15150Sstevel@tonic-gate } 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate mfs->mfs_penalty = penalty; 15180Sstevel@tonic-gate if (mfs->mfs_host == NULL || mfs->mfs_dir == NULL) { 15190Sstevel@tonic-gate syslog(LOG_ERR, 15200Sstevel@tonic-gate "parse_nfs: Memory allocation failed"); 15210Sstevel@tonic-gate return (PARSE_ERROR); 15220Sstevel@tonic-gate } 15230Sstevel@tonic-gate } 15240Sstevel@tonic-gate /* 15250Sstevel@tonic-gate * We check host_cnt to make sure we haven't parsed an entry 15260Sstevel@tonic-gate * with no host information. 15270Sstevel@tonic-gate */ 15280Sstevel@tonic-gate if (host_cnt == 0) { 15290Sstevel@tonic-gate syslog(LOG_ERR, 15300Sstevel@tonic-gate "parse_nfs: invalid host specified - bad entry " 15310Sstevel@tonic-gate "in map %s \"%s\"", 15320Sstevel@tonic-gate mapname, w); 15330Sstevel@tonic-gate return (PARSE_ERROR); 15340Sstevel@tonic-gate } 15350Sstevel@tonic-gate if (getword(w, wq, lp, lq, ' ', wsize) == -1) 15360Sstevel@tonic-gate return (PARSE_ERROR); 15370Sstevel@tonic-gate } 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate strcpy(fsw, w); 15400Sstevel@tonic-gate strcpy(fswq, wq); 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate return (PARSE_OK); 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate bad_entry: 15450Sstevel@tonic-gate syslog(LOG_ERR, "parse_nfs: bad entry in map %s \"%s\"", mapname, w); 15460Sstevel@tonic-gate return (PARSE_ERROR); 15470Sstevel@tonic-gate } 15480Sstevel@tonic-gate 15490Sstevel@tonic-gate static int 15500Sstevel@tonic-gate parse_special(me, w, wq, lp, lq, wsize) 15510Sstevel@tonic-gate struct mapent *me; 15520Sstevel@tonic-gate char *w, *wq, **lp, **lq; 15530Sstevel@tonic-gate int wsize; 15540Sstevel@tonic-gate { 15550Sstevel@tonic-gate char devname[MAXPATHLEN + 1], qbuf[MAXPATHLEN + 1]; 15560Sstevel@tonic-gate char *wlp, *wlq; 15570Sstevel@tonic-gate struct mapfs *mfs; 15580Sstevel@tonic-gate 15590Sstevel@tonic-gate wlp = w; 15600Sstevel@tonic-gate wlq = wq; 15610Sstevel@tonic-gate if (getword(devname, qbuf, &wlp, &wlq, ' ', sizeof (devname)) == -1) 15620Sstevel@tonic-gate return (PARSE_ERROR); 15630Sstevel@tonic-gate if (devname[0] == '\0') 15640Sstevel@tonic-gate return (PARSE_ERROR); 15650Sstevel@tonic-gate 15660Sstevel@tonic-gate mfs = (struct mapfs *)malloc(sizeof (struct mapfs)); 15670Sstevel@tonic-gate if (mfs == NULL) 15680Sstevel@tonic-gate return (PARSE_ERROR); 15690Sstevel@tonic-gate (void) memset(mfs, 0, sizeof (*mfs)); 15700Sstevel@tonic-gate 15710Sstevel@tonic-gate /* 15720Sstevel@tonic-gate * A device name that begins with a slash could 15730Sstevel@tonic-gate * be confused with a mountpoint path, hence use 15740Sstevel@tonic-gate * a colon to escape a device string that begins 15750Sstevel@tonic-gate * with a slash, e.g. 15760Sstevel@tonic-gate * 15770Sstevel@tonic-gate * foo -ro /bar foo:/bar 15780Sstevel@tonic-gate * and 15790Sstevel@tonic-gate * foo -ro /dev/sr0 15800Sstevel@tonic-gate * 15810Sstevel@tonic-gate * would confuse the parser. The second instance 15820Sstevel@tonic-gate * must use a colon: 15830Sstevel@tonic-gate * 15840Sstevel@tonic-gate * foo -ro :/dev/sr0 15850Sstevel@tonic-gate */ 15860Sstevel@tonic-gate mfs->mfs_dir = strdup(&devname[devname[0] == ':']); 15870Sstevel@tonic-gate if (mfs->mfs_dir == NULL) 15880Sstevel@tonic-gate return (PARSE_ERROR); 15890Sstevel@tonic-gate me->map_fs = mfs; 15900Sstevel@tonic-gate if (getword(w, wq, lp, lq, ' ', wsize) == -1) 15910Sstevel@tonic-gate return (PARSE_ERROR); 15920Sstevel@tonic-gate return (0); 15930Sstevel@tonic-gate } 15940Sstevel@tonic-gate 15950Sstevel@tonic-gate /* 15960Sstevel@tonic-gate * get_dir_from_path(char *dir, char **path, int dirsz) 15970Sstevel@tonic-gate * gets the directory name dir from path for max string of length dirsz. 15980Sstevel@tonic-gate * A modification of the getword routine. Assumes the delimiter is '/' 15990Sstevel@tonic-gate * and that excess /'s are redundant. 16000Sstevel@tonic-gate * Returns PARSE_OK or PARSE_ERROR 16010Sstevel@tonic-gate */ 16020Sstevel@tonic-gate static int 16030Sstevel@tonic-gate get_dir_from_path(char *dir, char **path, int dirsz) 16040Sstevel@tonic-gate { 16050Sstevel@tonic-gate char *tmp = dir; 16060Sstevel@tonic-gate int count = dirsz; 16070Sstevel@tonic-gate 16080Sstevel@tonic-gate if (dirsz <= 0) { 16090Sstevel@tonic-gate if (verbose) 16100Sstevel@tonic-gate syslog(LOG_ERR, 16110Sstevel@tonic-gate "get_dir_from_path: invalid directory size %d", dirsz); 16120Sstevel@tonic-gate return (PARSE_ERROR); 16130Sstevel@tonic-gate } 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate /* get rid of leading /'s in path */ 16160Sstevel@tonic-gate while (**path == '/') 16170Sstevel@tonic-gate (*path)++; 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate /* now at a word or at the end of path */ 16200Sstevel@tonic-gate while ((**path) && ((**path) != '/')) { 16210Sstevel@tonic-gate if (--count <= 0) { 16220Sstevel@tonic-gate *tmp = '\0'; 16230Sstevel@tonic-gate syslog(LOG_ERR, 16240Sstevel@tonic-gate "get_dir_from_path: max pathlength exceeded %d", dirsz); 16250Sstevel@tonic-gate return (PARSE_ERROR); 16260Sstevel@tonic-gate } 16270Sstevel@tonic-gate *dir++ = *(*path)++; 16280Sstevel@tonic-gate } 16290Sstevel@tonic-gate 16300Sstevel@tonic-gate *dir = '\0'; 16310Sstevel@tonic-gate 16320Sstevel@tonic-gate /* get rid of trailing /'s in path */ 16330Sstevel@tonic-gate while (**path == '/') 16340Sstevel@tonic-gate (*path)++; 16350Sstevel@tonic-gate 16360Sstevel@tonic-gate return (PARSE_OK); 16370Sstevel@tonic-gate } 16380Sstevel@tonic-gate 16390Sstevel@tonic-gate /* 16400Sstevel@tonic-gate * alloc_hiernode(hiernode **newnode, char *dirname) 16410Sstevel@tonic-gate * allocates a new hiernode corresponding to a new directory entry 16420Sstevel@tonic-gate * in the hierarchical structure, and passes a pointer to it back 16430Sstevel@tonic-gate * to the calling program. 16440Sstevel@tonic-gate * Returns PARSE_OK or appropriate error value. 16450Sstevel@tonic-gate */ 16460Sstevel@tonic-gate static int 16470Sstevel@tonic-gate alloc_hiernode(hiernode **newnode, char *dirname) 16480Sstevel@tonic-gate { 16490Sstevel@tonic-gate if ((*newnode = (hiernode *)malloc(sizeof (hiernode))) == NULL) { 16500Sstevel@tonic-gate syslog(LOG_ERR, "alloc_hiernode: Memory allocation failed"); 16510Sstevel@tonic-gate return (ENOMEM); 16520Sstevel@tonic-gate } 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate memset(((char *)*newnode), 0, sizeof (hiernode)); 16550Sstevel@tonic-gate strcpy(((*newnode)->dirname), dirname); 16560Sstevel@tonic-gate return (PARSE_OK); 16570Sstevel@tonic-gate } 16580Sstevel@tonic-gate 16590Sstevel@tonic-gate /* 16600Sstevel@tonic-gate * free_hiernode(hiernode *node) 16610Sstevel@tonic-gate * frees the allocated hiernode given the head of the structure 16620Sstevel@tonic-gate * recursively calls itself until it frees entire structure. 16630Sstevel@tonic-gate * Returns nothing. 16640Sstevel@tonic-gate */ 16650Sstevel@tonic-gate static void 16660Sstevel@tonic-gate free_hiernode(hiernode *node) 16670Sstevel@tonic-gate { 16680Sstevel@tonic-gate hiernode *currnode = node; 16690Sstevel@tonic-gate hiernode *prevnode = NULL; 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate while (currnode != NULL) { 16720Sstevel@tonic-gate if (currnode->subdir != NULL) 16730Sstevel@tonic-gate free_hiernode(currnode->subdir); 16740Sstevel@tonic-gate prevnode = currnode; 16750Sstevel@tonic-gate currnode = currnode->leveldir; 16760Sstevel@tonic-gate free((void*)prevnode); 16770Sstevel@tonic-gate } 16780Sstevel@tonic-gate } 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate /* 16810Sstevel@tonic-gate * free_mapent(struct mapent *) 16820Sstevel@tonic-gate * free the mapentry and its fields 16830Sstevel@tonic-gate */ 16840Sstevel@tonic-gate void 16850Sstevel@tonic-gate free_mapent(me) 16860Sstevel@tonic-gate struct mapent *me; 16870Sstevel@tonic-gate { 16880Sstevel@tonic-gate struct mapfs *mfs; 16890Sstevel@tonic-gate struct mapent *m; 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate while (me) { 16920Sstevel@tonic-gate while (me->map_fs) { 16930Sstevel@tonic-gate mfs = me->map_fs; 16940Sstevel@tonic-gate if (mfs->mfs_host) 16950Sstevel@tonic-gate free(mfs->mfs_host); 16960Sstevel@tonic-gate if (mfs->mfs_dir) 16970Sstevel@tonic-gate free(mfs->mfs_dir); 16980Sstevel@tonic-gate if (mfs->mfs_args) 16990Sstevel@tonic-gate free(mfs->mfs_args); 17000Sstevel@tonic-gate if (mfs->mfs_nconf) 17010Sstevel@tonic-gate freenetconfigent(mfs->mfs_nconf); 17020Sstevel@tonic-gate me->map_fs = mfs->mfs_next; 17030Sstevel@tonic-gate free((char *)mfs); 17040Sstevel@tonic-gate } 17050Sstevel@tonic-gate 17060Sstevel@tonic-gate if (me->map_root) 17070Sstevel@tonic-gate free(me->map_root); 17080Sstevel@tonic-gate if (me->map_mntpnt) 17090Sstevel@tonic-gate free(me->map_mntpnt); 17100Sstevel@tonic-gate if (me->map_mntopts) 17110Sstevel@tonic-gate free(me->map_mntopts); 17120Sstevel@tonic-gate if (me->map_fstype) 17130Sstevel@tonic-gate free(me->map_fstype); 17140Sstevel@tonic-gate if (me->map_mounter) 17150Sstevel@tonic-gate free(me->map_mounter); 17160Sstevel@tonic-gate if (me->map_fsw) 17170Sstevel@tonic-gate free(me->map_fsw); 17180Sstevel@tonic-gate if (me->map_fswq) 17190Sstevel@tonic-gate free(me->map_fswq); 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate m = me; 17220Sstevel@tonic-gate me = me->map_next; 17230Sstevel@tonic-gate free((char *)m); 17240Sstevel@tonic-gate } 17250Sstevel@tonic-gate } 17260Sstevel@tonic-gate 17270Sstevel@tonic-gate /* 17280Sstevel@tonic-gate * trace_mapents(struct mapent *mapents) 17290Sstevel@tonic-gate * traces through the mapentry structure and prints it element by element 17300Sstevel@tonic-gate * returns nothing 17310Sstevel@tonic-gate */ 17320Sstevel@tonic-gate static void 17330Sstevel@tonic-gate trace_mapents(char *s, struct mapent *mapents) 17340Sstevel@tonic-gate { 17350Sstevel@tonic-gate struct mapfs *mfs; 17360Sstevel@tonic-gate struct mapent *me; 17370Sstevel@tonic-gate 17380Sstevel@tonic-gate trace_prt(1, "\n\t%s\n", s); 17390Sstevel@tonic-gate for (me = mapents; me; me = me->map_next) { 17400Sstevel@tonic-gate trace_prt(1, " (%s,%s)\t %s%s -%s\n", 17410Sstevel@tonic-gate me->map_fstype ? me->map_fstype : "", 17420Sstevel@tonic-gate me->map_mounter ? me->map_mounter : "", 17430Sstevel@tonic-gate me->map_root ? me->map_root : "", 17440Sstevel@tonic-gate me->map_mntpnt ? me->map_mntpnt : "", 17450Sstevel@tonic-gate me->map_mntopts ? me->map_mntopts : ""); 17460Sstevel@tonic-gate for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next) 17470Sstevel@tonic-gate trace_prt(0, "\t\t%s:%s\n", 17480Sstevel@tonic-gate mfs->mfs_host ? mfs->mfs_host: "", 17490Sstevel@tonic-gate mfs->mfs_dir ? mfs->mfs_dir : ""); 17500Sstevel@tonic-gate 17510Sstevel@tonic-gate trace_prt(1, "\tme->map_fsw=%s\n", 17520Sstevel@tonic-gate me->map_fsw ? me->map_fsw:"", 17530Sstevel@tonic-gate me->map_fswq ? me->map_fsw:""); 17540Sstevel@tonic-gate trace_prt(1, "\t mntlevel=%d\t%s\t%s err=%d\n", 17550Sstevel@tonic-gate me->map_mntlevel, 17560Sstevel@tonic-gate me->map_modified ? "modify=TRUE":"modify=FALSE", 17570Sstevel@tonic-gate me->map_faked ? "faked=TRUE":"faked=FALSE", 17580Sstevel@tonic-gate me->map_err); 17590Sstevel@tonic-gate } 17600Sstevel@tonic-gate } 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate /* 17630Sstevel@tonic-gate * trace_hierarchy(hiernode *node) 17640Sstevel@tonic-gate * traces the allocated hiernode given the head of the structure 17650Sstevel@tonic-gate * recursively calls itself until it traces entire structure. 17660Sstevel@tonic-gate * the first call made at the root is made with a zero level. 17670Sstevel@tonic-gate * nodelevel is simply used to print tab and make the tracing clean. 17680Sstevel@tonic-gate * Returns nothing. 17690Sstevel@tonic-gate */ 17700Sstevel@tonic-gate static void 17710Sstevel@tonic-gate trace_hierarchy(hiernode *node, int nodelevel) 17720Sstevel@tonic-gate { 17730Sstevel@tonic-gate hiernode *currnode = node; 17740Sstevel@tonic-gate int i; 17750Sstevel@tonic-gate 17760Sstevel@tonic-gate while (currnode != NULL) { 17770Sstevel@tonic-gate if (currnode->subdir != NULL) { 17780Sstevel@tonic-gate for (i = 0; i < nodelevel; i++) 17790Sstevel@tonic-gate trace_prt(0, "\t"); 17800Sstevel@tonic-gate trace_prt(0, "\t(%s, ", 17810Sstevel@tonic-gate currnode->dirname ? currnode->dirname :""); 17820Sstevel@tonic-gate if (currnode->mapent) { 17830Sstevel@tonic-gate trace_prt(0, "%d, %s)\n", 17840Sstevel@tonic-gate currnode->mapent->map_mntlevel, 17850Sstevel@tonic-gate currnode->mapent->map_mntopts ? 17860Sstevel@tonic-gate currnode->mapent->map_mntopts:""); 17870Sstevel@tonic-gate } 17880Sstevel@tonic-gate else 17890Sstevel@tonic-gate trace_prt(0, " ,)\n"); 17900Sstevel@tonic-gate nodelevel++; 17910Sstevel@tonic-gate trace_hierarchy(currnode->subdir, nodelevel); 17920Sstevel@tonic-gate } else { 17930Sstevel@tonic-gate for (i = 0; i < nodelevel; i++) 17940Sstevel@tonic-gate trace_prt(0, "\t"); 17950Sstevel@tonic-gate trace_prt(0, "\t(%s, ", 17960Sstevel@tonic-gate currnode->dirname ? currnode->dirname :""); 17970Sstevel@tonic-gate if (currnode->mapent) { 17980Sstevel@tonic-gate trace_prt(0, "%d, %s)\n", 17990Sstevel@tonic-gate currnode->mapent->map_mntlevel, 18000Sstevel@tonic-gate currnode->mapent->map_mntopts ? 18010Sstevel@tonic-gate currnode->mapent->map_mntopts:""); 18020Sstevel@tonic-gate } 18030Sstevel@tonic-gate else 18040Sstevel@tonic-gate trace_prt(0, ", )\n"); 18050Sstevel@tonic-gate } 18060Sstevel@tonic-gate currnode = currnode->leveldir; 18070Sstevel@tonic-gate } 18080Sstevel@tonic-gate } 18090Sstevel@tonic-gate 18100Sstevel@tonic-gate struct mapent * 18110Sstevel@tonic-gate do_mapent_hosts(mapopts, host, isdirect) 18120Sstevel@tonic-gate char *mapopts, *host; 18130Sstevel@tonic-gate uint_t isdirect; 18140Sstevel@tonic-gate { 18150Sstevel@tonic-gate CLIENT *cl; 18160Sstevel@tonic-gate struct mapent *me, *ms, *mp; 18170Sstevel@tonic-gate struct mapfs *mfs; 18180Sstevel@tonic-gate struct exportnode *ex = NULL; 18190Sstevel@tonic-gate struct exportnode *exlist, *texlist, **texp, *exnext; 18200Sstevel@tonic-gate struct timeval timeout; 18210Sstevel@tonic-gate enum clnt_stat clnt_stat; 18220Sstevel@tonic-gate char name[MAXPATHLEN]; 18230Sstevel@tonic-gate char entryopts[MAXOPTSLEN]; 18240Sstevel@tonic-gate char fstype[32], mounter[32]; 18250Sstevel@tonic-gate int exlen, duplicate; 18260Sstevel@tonic-gate struct mnttab mb; /* needed for hasmntopt() to get nfs version */ 18270Sstevel@tonic-gate rpcvers_t nfsvers; /* version in map options, 0 if not there */ 18280Sstevel@tonic-gate rpcvers_t vers, versmin; /* used to negotiate nfs vers in pingnfs() */ 18290Sstevel@tonic-gate int retries, delay; 18300Sstevel@tonic-gate int foundvers; 18310Sstevel@tonic-gate 18320Sstevel@tonic-gate if (trace > 1) 18330Sstevel@tonic-gate trace_prt(1, " do_mapent_hosts: host %s\n", host); 18340Sstevel@tonic-gate 18350Sstevel@tonic-gate /* check for special case: host is me */ 18360Sstevel@tonic-gate 18370Sstevel@tonic-gate if (self_check(host)) { 18380Sstevel@tonic-gate ms = (struct mapent *)malloc(sizeof (*ms)); 18390Sstevel@tonic-gate if (ms == NULL) 18400Sstevel@tonic-gate goto alloc_failed; 18410Sstevel@tonic-gate (void) memset((char *)ms, 0, sizeof (*ms)); 18420Sstevel@tonic-gate (void) strcpy(fstype, MNTTYPE_NFS); 18430Sstevel@tonic-gate get_opts(mapopts, entryopts, fstype, NULL); 18440Sstevel@tonic-gate ms->map_mntopts = strdup(entryopts); 18450Sstevel@tonic-gate if (ms->map_mntopts == NULL) 18460Sstevel@tonic-gate goto alloc_failed; 18470Sstevel@tonic-gate ms->map_mounter = strdup(fstype); 18480Sstevel@tonic-gate if (ms->map_mounter == NULL) 18490Sstevel@tonic-gate goto alloc_failed; 18500Sstevel@tonic-gate ms->map_fstype = strdup(MNTTYPE_NFS); 18510Sstevel@tonic-gate if (ms->map_fstype == NULL) 18520Sstevel@tonic-gate goto alloc_failed; 18530Sstevel@tonic-gate 18540Sstevel@tonic-gate if (isdirect) 18550Sstevel@tonic-gate name[0] = '\0'; 18560Sstevel@tonic-gate else { 18570Sstevel@tonic-gate (void) strcpy(name, "/"); 18580Sstevel@tonic-gate (void) strcat(name, host); 18590Sstevel@tonic-gate } 18600Sstevel@tonic-gate ms->map_root = strdup(name); 18610Sstevel@tonic-gate if (ms->map_root == NULL) 18620Sstevel@tonic-gate goto alloc_failed; 18630Sstevel@tonic-gate ms->map_mntpnt = strdup(""); 18640Sstevel@tonic-gate if (ms->map_mntpnt == NULL) 18650Sstevel@tonic-gate goto alloc_failed; 18660Sstevel@tonic-gate mfs = (struct mapfs *)malloc(sizeof (*mfs)); 18670Sstevel@tonic-gate if (mfs == NULL) 18680Sstevel@tonic-gate goto alloc_failed; 18690Sstevel@tonic-gate (void) memset((char *)mfs, 0, sizeof (*mfs)); 18700Sstevel@tonic-gate ms->map_fs = mfs; 18710Sstevel@tonic-gate mfs->mfs_host = strdup(host); 18720Sstevel@tonic-gate if (mfs->mfs_host == NULL) 18730Sstevel@tonic-gate goto alloc_failed; 18740Sstevel@tonic-gate mfs->mfs_dir = strdup("/"); 18750Sstevel@tonic-gate if (mfs->mfs_dir == NULL) 18760Sstevel@tonic-gate goto alloc_failed; 18770Sstevel@tonic-gate 18780Sstevel@tonic-gate /* initialize mntlevel and modify */ 18790Sstevel@tonic-gate ms->map_mntlevel = -1; 18800Sstevel@tonic-gate ms->map_modified = FALSE; 18810Sstevel@tonic-gate ms->map_faked = FALSE; 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate if (trace > 1) 18840Sstevel@tonic-gate trace_prt(1, 18850Sstevel@tonic-gate " do_mapent_hosts: self-host %s OK\n", host); 18860Sstevel@tonic-gate 18870Sstevel@tonic-gate return (ms); 18880Sstevel@tonic-gate } 18890Sstevel@tonic-gate 18900Sstevel@tonic-gate /* 18910Sstevel@tonic-gate * Call pingnfs. Note that we can't have replicated hosts in /net. 18920Sstevel@tonic-gate * XXX - we would like to avoid duplicating the across the wire calls 18930Sstevel@tonic-gate * made here in nfsmount(). The pingnfs cache should help avoid it. 18940Sstevel@tonic-gate */ 18950Sstevel@tonic-gate mb.mnt_mntopts = mapopts; 18960Sstevel@tonic-gate foundvers = nopt(&mb, MNTOPT_VERS, (int *)&nfsvers); 18970Sstevel@tonic-gate if (!foundvers) 18980Sstevel@tonic-gate nfsvers = 0; 18990Sstevel@tonic-gate if (set_versrange(nfsvers, &vers, &versmin) != 0) { 19000Sstevel@tonic-gate syslog(LOG_ERR, "Incorrect NFS version specified for %s", host); 19010Sstevel@tonic-gate return ((struct mapent *)NULL); 19020Sstevel@tonic-gate } 19030Sstevel@tonic-gate if (pingnfs(host, get_retry(mapopts) + 1, &vers, versmin, 0, FALSE, 19040Sstevel@tonic-gate NULL, NULL) != RPC_SUCCESS) 19050Sstevel@tonic-gate return ((struct mapent *)NULL); 19060Sstevel@tonic-gate 19070Sstevel@tonic-gate retries = get_retry(mapopts); 19080Sstevel@tonic-gate delay = INITDELAY; 19090Sstevel@tonic-gate retry: 19100Sstevel@tonic-gate /* get export list of host */ 19110Sstevel@tonic-gate cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "circuit_v"); 19120Sstevel@tonic-gate if (cl == NULL) { 19130Sstevel@tonic-gate cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "datagram_v"); 19140Sstevel@tonic-gate if (cl == NULL) { 19150Sstevel@tonic-gate syslog(LOG_ERR, 19160Sstevel@tonic-gate "do_mapent_hosts: %s %s", host, clnt_spcreateerror("")); 19170Sstevel@tonic-gate return ((struct mapent *)NULL); 19180Sstevel@tonic-gate } 19190Sstevel@tonic-gate 19200Sstevel@tonic-gate } 19210Sstevel@tonic-gate #ifdef MALLOC_DEBUG 19220Sstevel@tonic-gate add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__); 19230Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 19240Sstevel@tonic-gate __FILE__, __LINE__); 19250Sstevel@tonic-gate #endif 19260Sstevel@tonic-gate 19270Sstevel@tonic-gate timeout.tv_usec = 0; 19280Sstevel@tonic-gate timeout.tv_sec = 25; 19290Sstevel@tonic-gate if (clnt_stat = clnt_call(cl, MOUNTPROC_EXPORT, xdr_void, 0, 19300Sstevel@tonic-gate xdr_exports, (caddr_t)&ex, timeout)) { 19310Sstevel@tonic-gate 19320Sstevel@tonic-gate if (retries-- > 0) { 19330Sstevel@tonic-gate clnt_destroy(cl); 19340Sstevel@tonic-gate DELAY(delay); 19350Sstevel@tonic-gate goto retry; 19360Sstevel@tonic-gate } 19370Sstevel@tonic-gate 19380Sstevel@tonic-gate syslog(LOG_ERR, 19390Sstevel@tonic-gate "do_mapent_hosts: %s: export list: %s", 19400Sstevel@tonic-gate host, clnt_sperrno(clnt_stat)); 19410Sstevel@tonic-gate #ifdef MALLOC_DEBUG 19420Sstevel@tonic-gate drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__); 19430Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, 19440Sstevel@tonic-gate __FILE__, __LINE__); 19450Sstevel@tonic-gate #endif 19460Sstevel@tonic-gate clnt_destroy(cl); 19470Sstevel@tonic-gate return ((struct mapent *)NULL); 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate #ifdef MALLOC_DEBUG 19510Sstevel@tonic-gate drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__); 19520Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, 19530Sstevel@tonic-gate __FILE__, __LINE__); 19540Sstevel@tonic-gate #endif 19550Sstevel@tonic-gate clnt_destroy(cl); 19560Sstevel@tonic-gate 19570Sstevel@tonic-gate if (ex == NULL) { 19580Sstevel@tonic-gate if (trace > 1) 19590Sstevel@tonic-gate trace_prt(1, 19600Sstevel@tonic-gate gettext(" getmapent_hosts: null export list\n")); 19610Sstevel@tonic-gate return ((struct mapent *)NULL); 19620Sstevel@tonic-gate } 19630Sstevel@tonic-gate 19640Sstevel@tonic-gate /* now sort by length of names - to get mount order right */ 19650Sstevel@tonic-gate exlist = ex; 19660Sstevel@tonic-gate texlist = NULL; 19670Sstevel@tonic-gate #ifdef lint 19680Sstevel@tonic-gate exnext = NULL; 19690Sstevel@tonic-gate #endif 19700Sstevel@tonic-gate for (; ex; ex = exnext) { 19710Sstevel@tonic-gate exnext = ex->ex_next; 19720Sstevel@tonic-gate exlen = strlen(ex->ex_dir); 19730Sstevel@tonic-gate duplicate = 0; 19740Sstevel@tonic-gate for (texp = &texlist; *texp; texp = &((*texp)->ex_next)) { 19750Sstevel@tonic-gate if (exlen < (int)strlen((*texp)->ex_dir)) 19760Sstevel@tonic-gate break; 19770Sstevel@tonic-gate duplicate = (strcmp(ex->ex_dir, (*texp)->ex_dir) == 0); 19780Sstevel@tonic-gate if (duplicate) { 19790Sstevel@tonic-gate /* disregard duplicate entry */ 19800Sstevel@tonic-gate freeex_ent(ex); 19810Sstevel@tonic-gate break; 19820Sstevel@tonic-gate } 19830Sstevel@tonic-gate } 19840Sstevel@tonic-gate if (!duplicate) { 19850Sstevel@tonic-gate ex->ex_next = *texp; 19860Sstevel@tonic-gate *texp = ex; 19870Sstevel@tonic-gate } 19880Sstevel@tonic-gate } 19890Sstevel@tonic-gate exlist = texlist; 19900Sstevel@tonic-gate 19910Sstevel@tonic-gate /* 19920Sstevel@tonic-gate * The following ugly chunk of code crept in as 19930Sstevel@tonic-gate * a result of cachefs. If it's a cachefs mount 19940Sstevel@tonic-gate * of an nfs filesystem, then have it handled as 19950Sstevel@tonic-gate * an nfs mount but have cachefs do the mount. 19960Sstevel@tonic-gate */ 19970Sstevel@tonic-gate (void) strcpy(fstype, MNTTYPE_NFS); 19980Sstevel@tonic-gate get_opts(mapopts, entryopts, fstype, NULL); 19990Sstevel@tonic-gate (void) strcpy(mounter, fstype); 20000Sstevel@tonic-gate if (strcmp(fstype, MNTTYPE_CACHEFS) == 0) { 20010Sstevel@tonic-gate struct mnttab m; 20020Sstevel@tonic-gate char *p; 20030Sstevel@tonic-gate 20040Sstevel@tonic-gate m.mnt_mntopts = entryopts; 20050Sstevel@tonic-gate if ((p = hasmntopt(&m, "backfstype")) != NULL) { 20060Sstevel@tonic-gate int len = strlen(MNTTYPE_NFS); 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate p += 11; 20090Sstevel@tonic-gate if (strncmp(p, MNTTYPE_NFS, len) == 0 && 20100Sstevel@tonic-gate (p[len] == '\0' || p[len] == ',')) { 20110Sstevel@tonic-gate /* 20120Sstevel@tonic-gate * Cached nfs mount 20130Sstevel@tonic-gate */ 20140Sstevel@tonic-gate (void) strcpy(fstype, MNTTYPE_NFS); 20150Sstevel@tonic-gate (void) strcpy(mounter, MNTTYPE_CACHEFS); 20160Sstevel@tonic-gate } 20170Sstevel@tonic-gate } 20180Sstevel@tonic-gate } 20190Sstevel@tonic-gate 20200Sstevel@tonic-gate /* Now create a mapent from the export list */ 20210Sstevel@tonic-gate ms = NULL; 20220Sstevel@tonic-gate me = NULL; 20230Sstevel@tonic-gate 20240Sstevel@tonic-gate for (ex = exlist; ex; ex = ex->ex_next) { 20250Sstevel@tonic-gate mp = me; 20260Sstevel@tonic-gate me = (struct mapent *)malloc(sizeof (*me)); 20270Sstevel@tonic-gate if (me == NULL) 20280Sstevel@tonic-gate goto alloc_failed; 20290Sstevel@tonic-gate (void) memset((char *)me, 0, sizeof (*me)); 20300Sstevel@tonic-gate 20310Sstevel@tonic-gate if (ms == NULL) 20320Sstevel@tonic-gate ms = me; 20330Sstevel@tonic-gate else 20340Sstevel@tonic-gate mp->map_next = me; 20350Sstevel@tonic-gate 20360Sstevel@tonic-gate if (isdirect) 20370Sstevel@tonic-gate name[0] = '\0'; 20380Sstevel@tonic-gate else { 20390Sstevel@tonic-gate (void) strcpy(name, "/"); 20400Sstevel@tonic-gate (void) strcat(name, host); 20410Sstevel@tonic-gate } 20420Sstevel@tonic-gate me->map_root = strdup(name); 20430Sstevel@tonic-gate if (me->map_root == NULL) 20440Sstevel@tonic-gate goto alloc_failed; 20450Sstevel@tonic-gate 20460Sstevel@tonic-gate *name = '\0'; 20470Sstevel@tonic-gate if (strcmp(ex->ex_dir, "/") != 0) { 20480Sstevel@tonic-gate if (*(ex->ex_dir) != '/') 20490Sstevel@tonic-gate (void) strcpy(name, "/"); 20500Sstevel@tonic-gate (void) strcat(name, ex->ex_dir); 20510Sstevel@tonic-gate } 20520Sstevel@tonic-gate me->map_mntpnt = strdup(name); 20530Sstevel@tonic-gate if (me->map_mntpnt == NULL) 20540Sstevel@tonic-gate goto alloc_failed; 20550Sstevel@tonic-gate 20560Sstevel@tonic-gate me->map_fstype = strdup(fstype); 20570Sstevel@tonic-gate if (me->map_fstype == NULL) 20580Sstevel@tonic-gate goto alloc_failed; 20590Sstevel@tonic-gate me->map_mounter = strdup(mounter); 20600Sstevel@tonic-gate if (me->map_mounter == NULL) 20610Sstevel@tonic-gate goto alloc_failed; 20620Sstevel@tonic-gate me->map_mntopts = strdup(entryopts); 20630Sstevel@tonic-gate if (me->map_mntopts == NULL) 20640Sstevel@tonic-gate goto alloc_failed; 20650Sstevel@tonic-gate 20660Sstevel@tonic-gate mfs = (struct mapfs *)malloc(sizeof (*mfs)); 20670Sstevel@tonic-gate if (mfs == NULL) 20680Sstevel@tonic-gate goto alloc_failed; 20690Sstevel@tonic-gate (void) memset((char *)mfs, 0, sizeof (*mfs)); 20700Sstevel@tonic-gate me->map_fs = mfs; 20710Sstevel@tonic-gate mfs->mfs_host = strdup(host); 20720Sstevel@tonic-gate if (mfs->mfs_host == NULL) 20730Sstevel@tonic-gate goto alloc_failed; 20740Sstevel@tonic-gate mfs->mfs_dir = strdup(ex->ex_dir); 20750Sstevel@tonic-gate if (mfs->mfs_dir == NULL) 20760Sstevel@tonic-gate goto alloc_failed; 20770Sstevel@tonic-gate 20780Sstevel@tonic-gate /* initialize mntlevel and modify values */ 20790Sstevel@tonic-gate me->map_mntlevel = -1; 20800Sstevel@tonic-gate me->map_modified = FALSE; 20810Sstevel@tonic-gate me->map_faked = FALSE; 20820Sstevel@tonic-gate } 20830Sstevel@tonic-gate freeex(exlist); 20840Sstevel@tonic-gate 20850Sstevel@tonic-gate if (trace > 1) 20860Sstevel@tonic-gate trace_prt(1, " do_mapent_hosts: host %s OK\n", host); 20870Sstevel@tonic-gate 20880Sstevel@tonic-gate return (ms); 20890Sstevel@tonic-gate 20900Sstevel@tonic-gate alloc_failed: 20910Sstevel@tonic-gate syslog(LOG_ERR, "do_mapent_hosts: Memory allocation failed"); 20920Sstevel@tonic-gate free_mapent(ms); 20930Sstevel@tonic-gate freeex(exlist); 20940Sstevel@tonic-gate return ((struct mapent *)NULL); 20950Sstevel@tonic-gate } 20960Sstevel@tonic-gate 20970Sstevel@tonic-gate 20980Sstevel@tonic-gate static void 20990Sstevel@tonic-gate freeex_ent(ex) 21000Sstevel@tonic-gate struct exportnode *ex; 21010Sstevel@tonic-gate { 21020Sstevel@tonic-gate struct groupnode *groups, *tmpgroups; 21030Sstevel@tonic-gate 21040Sstevel@tonic-gate free(ex->ex_dir); 21050Sstevel@tonic-gate groups = ex->ex_groups; 21060Sstevel@tonic-gate while (groups) { 21070Sstevel@tonic-gate free(groups->gr_name); 21080Sstevel@tonic-gate tmpgroups = groups->gr_next; 21090Sstevel@tonic-gate free((char *)groups); 21100Sstevel@tonic-gate groups = tmpgroups; 21110Sstevel@tonic-gate } 21120Sstevel@tonic-gate free((char *)ex); 21130Sstevel@tonic-gate } 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate static void 21160Sstevel@tonic-gate freeex(ex) 21170Sstevel@tonic-gate struct exportnode *ex; 21180Sstevel@tonic-gate { 21190Sstevel@tonic-gate struct exportnode *tmpex; 21200Sstevel@tonic-gate 21210Sstevel@tonic-gate while (ex) { 21220Sstevel@tonic-gate tmpex = ex->ex_next; 21230Sstevel@tonic-gate freeex_ent(ex); 21240Sstevel@tonic-gate ex = tmpex; 21250Sstevel@tonic-gate } 21260Sstevel@tonic-gate } 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate static const char uatfs_err[] = "submount under fstype=autofs not supported"; 21290Sstevel@tonic-gate /* 21300Sstevel@tonic-gate * dump_mapent_err(struct mapent *me, char *key, char *mapname) 21310Sstevel@tonic-gate * syslog appropriate error in mapentries. 21320Sstevel@tonic-gate */ 21330Sstevel@tonic-gate static void dump_mapent_err(struct mapent *me, char *key, char *mapname) 21340Sstevel@tonic-gate { 21350Sstevel@tonic-gate switch (me->map_err) { 21360Sstevel@tonic-gate case MAPENT_NOERR: 21370Sstevel@tonic-gate if (verbose) 21380Sstevel@tonic-gate syslog(LOG_ERR, 21390Sstevel@tonic-gate "map=%s key=%s mntpnt=%s: no error"); 21400Sstevel@tonic-gate break; 21410Sstevel@tonic-gate case MAPENT_UATFS: 21420Sstevel@tonic-gate syslog(LOG_ERR, 21430Sstevel@tonic-gate "mountpoint %s in map %s key %s not mounted: %s", 21440Sstevel@tonic-gate me->map_mntpnt, mapname, key, uatfs_err); 21450Sstevel@tonic-gate break; 21460Sstevel@tonic-gate default: 21470Sstevel@tonic-gate if (verbose) 21480Sstevel@tonic-gate syslog(LOG_ERR, 21490Sstevel@tonic-gate "map=%s key=%s mntpnt=%s: unknown mapentry error"); 21500Sstevel@tonic-gate } 21510Sstevel@tonic-gate } 2152