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