10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * ns_files.c 240Sstevel@tonic-gate * 25*249Sjwahlig * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 260Sstevel@tonic-gate * Use is subject to license terms. 270Sstevel@tonic-gate */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 300Sstevel@tonic-gate 310Sstevel@tonic-gate #include <stdio.h> 320Sstevel@tonic-gate #include <stdlib.h> 330Sstevel@tonic-gate #include <syslog.h> 340Sstevel@tonic-gate #include <string.h> 350Sstevel@tonic-gate #include <ctype.h> 360Sstevel@tonic-gate #include <nsswitch.h> 370Sstevel@tonic-gate #include <sys/stat.h> 380Sstevel@tonic-gate #include <sys/param.h> 390Sstevel@tonic-gate #include <rpc/rpc.h> 400Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h> 410Sstevel@tonic-gate #include <thread.h> 420Sstevel@tonic-gate #include <assert.h> 430Sstevel@tonic-gate #include <errno.h> 440Sstevel@tonic-gate #include <fcntl.h> 450Sstevel@tonic-gate #include <unistd.h> 460Sstevel@tonic-gate #include <synch.h> 470Sstevel@tonic-gate #include <sys/types.h> 480Sstevel@tonic-gate #include <sys/wait.h> 490Sstevel@tonic-gate #include "automount.h" 500Sstevel@tonic-gate 510Sstevel@tonic-gate static int read_execout(char *key, char **lp, char *fname, char *line, 520Sstevel@tonic-gate int linesz); 530Sstevel@tonic-gate static FILE *file_open(char *, char *, char **, char ***); 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * Initialize the stack 570Sstevel@tonic-gate */ 580Sstevel@tonic-gate void 590Sstevel@tonic-gate init_files(char **stack, char ***stkptr) 600Sstevel@tonic-gate { 610Sstevel@tonic-gate /* 620Sstevel@tonic-gate * The call is bogus for automountd since the stack is 630Sstevel@tonic-gate * is more appropriately initialized in the thread-private 640Sstevel@tonic-gate * routines 650Sstevel@tonic-gate */ 660Sstevel@tonic-gate if (stack == NULL && stkptr == NULL) 670Sstevel@tonic-gate return; 680Sstevel@tonic-gate (void) stack_op(INIT, NULL, stack, stkptr); 690Sstevel@tonic-gate } 700Sstevel@tonic-gate 710Sstevel@tonic-gate int 720Sstevel@tonic-gate getmapent_files(key, mapname, ml, stack, stkptr, iswildcard, isrestricted) 730Sstevel@tonic-gate char *key; 740Sstevel@tonic-gate char *mapname; 750Sstevel@tonic-gate struct mapline *ml; 760Sstevel@tonic-gate char **stack, ***stkptr; 770Sstevel@tonic-gate bool_t *iswildcard; 780Sstevel@tonic-gate bool_t isrestricted; 790Sstevel@tonic-gate { 800Sstevel@tonic-gate int nserr; 810Sstevel@tonic-gate FILE *fp; 820Sstevel@tonic-gate char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1]; 830Sstevel@tonic-gate char linebuf[LINESZ], lineqbuf[LINESZ]; 840Sstevel@tonic-gate char *lp, *lq; 850Sstevel@tonic-gate struct stat stbuf; 860Sstevel@tonic-gate char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */ 870Sstevel@tonic-gate int syntaxok = 1; 880Sstevel@tonic-gate 890Sstevel@tonic-gate if (iswildcard) 900Sstevel@tonic-gate *iswildcard = FALSE; 910Sstevel@tonic-gate if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) { 920Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 930Sstevel@tonic-gate goto done; 940Sstevel@tonic-gate } 950Sstevel@tonic-gate 960Sstevel@tonic-gate if (stat(fname, &stbuf) < 0) { 970Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 980Sstevel@tonic-gate goto done; 990Sstevel@tonic-gate } 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate /* 1020Sstevel@tonic-gate * If the file has its execute bit on then 1030Sstevel@tonic-gate * assume it's an executable map. 1040Sstevel@tonic-gate * Execute it and pass the key as an argument. 1050Sstevel@tonic-gate * Expect to get a map entry on the stdout. 1060Sstevel@tonic-gate * Ignore the "x" bit on restricted maps. 1070Sstevel@tonic-gate */ 1080Sstevel@tonic-gate if (!isrestricted && (stbuf.st_mode & S_IXUSR)) { 1090Sstevel@tonic-gate int rc; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate if (trace > 1) { 1120Sstevel@tonic-gate trace_prt(1, 1130Sstevel@tonic-gate "\tExecutable map: map=%s key=%s\n", 1140Sstevel@tonic-gate fname, key); 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate rc = read_execout(key, &lp, fname, ml->linebuf, LINESZ); 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate if (rc != 0) { 1200Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 1210Sstevel@tonic-gate goto done; 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate if (lp == NULL || strlen(ml->linebuf) == 0) { 1250Sstevel@tonic-gate nserr = __NSW_NOTFOUND; 1260Sstevel@tonic-gate goto done; 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate unquote(ml->linebuf, ml->lineqbuf); 1300Sstevel@tonic-gate nserr = __NSW_SUCCESS; 1310Sstevel@tonic-gate goto done; 1320Sstevel@tonic-gate } 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate /* 1360Sstevel@tonic-gate * It's just a normal map file. 1370Sstevel@tonic-gate * Search for the entry with the required key. 1380Sstevel@tonic-gate */ 1390Sstevel@tonic-gate for (;;) { 1400Sstevel@tonic-gate lp = get_line(fp, fname, linebuf, sizeof (linebuf)); 1410Sstevel@tonic-gate if (lp == NULL) { 1420Sstevel@tonic-gate nserr = __NSW_NOTFOUND; 1430Sstevel@tonic-gate goto done; 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate if (verbose && syntaxok && isspace(*(uchar_t *)lp)) { 1460Sstevel@tonic-gate syntaxok = 0; 1470Sstevel@tonic-gate syslog(LOG_ERR, 1480Sstevel@tonic-gate "leading space in map entry \"%s\" in %s", 1490Sstevel@tonic-gate lp, mapname); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate lq = lineqbuf; 1520Sstevel@tonic-gate unquote(lp, lq); 1530Sstevel@tonic-gate if ((getword(word, wordq, &lp, &lq, ' ', sizeof (word)) 1540Sstevel@tonic-gate == -1) || (word[0] == '\0')) 1550Sstevel@tonic-gate continue; 1560Sstevel@tonic-gate if (strcmp(word, key) == 0) 1570Sstevel@tonic-gate break; 1580Sstevel@tonic-gate if (word[0] == '*' && word[1] == '\0') { 1590Sstevel@tonic-gate if (iswildcard) 1600Sstevel@tonic-gate *iswildcard = TRUE; 1610Sstevel@tonic-gate break; 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate if (word[0] == '+') { 1640Sstevel@tonic-gate nserr = getmapent(key, word+1, ml, stack, stkptr, 1650Sstevel@tonic-gate iswildcard, isrestricted); 1660Sstevel@tonic-gate if (nserr == __NSW_SUCCESS) 1670Sstevel@tonic-gate goto done; 1680Sstevel@tonic-gate continue; 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /* 1720Sstevel@tonic-gate * sanity check each map entry key against 1730Sstevel@tonic-gate * the lookup key as the map is searched. 1740Sstevel@tonic-gate */ 1750Sstevel@tonic-gate if (verbose && syntaxok) { /* sanity check entry */ 1760Sstevel@tonic-gate if (*key == '/') { 1770Sstevel@tonic-gate if (*word != '/') { 1780Sstevel@tonic-gate syntaxok = 0; 1790Sstevel@tonic-gate syslog(LOG_ERR, 1800Sstevel@tonic-gate "bad key \"%s\" in direct map %s\n", 1810Sstevel@tonic-gate word, mapname); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate } else { 1840Sstevel@tonic-gate if (strchr(word, '/')) { 1850Sstevel@tonic-gate syntaxok = 0; 1860Sstevel@tonic-gate syslog(LOG_ERR, 1870Sstevel@tonic-gate "bad key \"%s\" in indirect map %s\n", 1880Sstevel@tonic-gate word, mapname); 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate (void) strcpy(ml->linebuf, lp); 1950Sstevel@tonic-gate (void) strcpy(ml->lineqbuf, lq); 1960Sstevel@tonic-gate nserr = __NSW_SUCCESS; 1970Sstevel@tonic-gate done: 1980Sstevel@tonic-gate if (fp) { 1990Sstevel@tonic-gate (void) stack_op(POP, (char *)NULL, stack, stkptr); 2000Sstevel@tonic-gate (void) fclose(fp); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate return (nserr); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate int 2080Sstevel@tonic-gate getmapkeys_files(mapname, list, error, cache_time, stack, stkptr) 2090Sstevel@tonic-gate char *mapname; 2100Sstevel@tonic-gate struct dir_entry **list; 2110Sstevel@tonic-gate int *error; 2120Sstevel@tonic-gate int *cache_time; 2130Sstevel@tonic-gate char **stack, ***stkptr; 2140Sstevel@tonic-gate { 2150Sstevel@tonic-gate FILE *fp = NULL; 2160Sstevel@tonic-gate char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1]; 2170Sstevel@tonic-gate char linebuf[LINESZ], lineqbuf[LINESZ]; 2180Sstevel@tonic-gate char *lp, *lq; 2190Sstevel@tonic-gate struct stat stbuf; 2200Sstevel@tonic-gate char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */ 2210Sstevel@tonic-gate int syntaxok = 1; 2220Sstevel@tonic-gate int nserr; 2230Sstevel@tonic-gate struct dir_entry *last = NULL; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate if (trace > 1) 2260Sstevel@tonic-gate trace_prt(1, "getmapkeys_files %s\n", mapname); 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate *cache_time = RDDIR_CACHE_TIME; 2290Sstevel@tonic-gate if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) { 2300Sstevel@tonic-gate *error = ENOENT; 2310Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 2320Sstevel@tonic-gate goto done; 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate if (fseek(fp, 0L, SEEK_SET) == -1) { 2350Sstevel@tonic-gate *error = ENOENT; 2360Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 2370Sstevel@tonic-gate goto done; 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate if (stat(fname, &stbuf) < 0) { 2410Sstevel@tonic-gate *error = ENOENT; 2420Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 2430Sstevel@tonic-gate goto done; 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate /* 2470Sstevel@tonic-gate * If the file has its execute bit on then 2480Sstevel@tonic-gate * assume it's an executable map. 2490Sstevel@tonic-gate * I don't know how to list executable maps, return 2500Sstevel@tonic-gate * an empty map. 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate if (stbuf.st_mode & S_IXUSR) { 2530Sstevel@tonic-gate *error = 0; 2540Sstevel@tonic-gate nserr = __NSW_SUCCESS; 2550Sstevel@tonic-gate goto done; 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate /* 2580Sstevel@tonic-gate * It's just a normal map file. 2590Sstevel@tonic-gate * List entries one line at a time. 2600Sstevel@tonic-gate */ 2610Sstevel@tonic-gate for (;;) { 2620Sstevel@tonic-gate lp = get_line(fp, fname, linebuf, sizeof (linebuf)); 2630Sstevel@tonic-gate if (lp == NULL) { 2640Sstevel@tonic-gate nserr = __NSW_SUCCESS; 2650Sstevel@tonic-gate goto done; 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate if (syntaxok && isspace(*(uchar_t *)lp)) { 2680Sstevel@tonic-gate syntaxok = 0; 2690Sstevel@tonic-gate syslog(LOG_ERR, 2700Sstevel@tonic-gate "leading space in map entry \"%s\" in %s", 2710Sstevel@tonic-gate lp, mapname); 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate lq = lineqbuf; 2740Sstevel@tonic-gate unquote(lp, lq); 2750Sstevel@tonic-gate if ((getword(word, wordq, &lp, &lq, ' ', MAXFILENAMELEN) 2760Sstevel@tonic-gate == -1) || (word[0] == '\0')) 2770Sstevel@tonic-gate continue; 2780Sstevel@tonic-gate /* 2790Sstevel@tonic-gate * Wildcard entries should be ignored and this should be 2800Sstevel@tonic-gate * the last entry read to corroborate the search through 2810Sstevel@tonic-gate * files, i.e., search for key until a wildcard is reached. 2820Sstevel@tonic-gate */ 2830Sstevel@tonic-gate if (word[0] == '*' && word[1] == '\0') 2840Sstevel@tonic-gate break; 2850Sstevel@tonic-gate if (word[0] == '+') { 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * Name switch here 2880Sstevel@tonic-gate */ 2890Sstevel@tonic-gate getmapkeys(word+1, list, error, cache_time, 2900Sstevel@tonic-gate stack, stkptr, 0); 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * the list may have been updated, therefore 2930Sstevel@tonic-gate * our 'last' may no longer be valid 2940Sstevel@tonic-gate */ 2950Sstevel@tonic-gate last = NULL; 2960Sstevel@tonic-gate continue; 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate if (add_dir_entry(word, list, &last) != 0) { 3000Sstevel@tonic-gate *error = ENOMEM; 3010Sstevel@tonic-gate goto done; 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate assert(last != NULL); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate nserr = __NSW_SUCCESS; 3070Sstevel@tonic-gate done: 3080Sstevel@tonic-gate if (fp) { 3090Sstevel@tonic-gate (void) stack_op(POP, (char *)NULL, stack, stkptr); 3100Sstevel@tonic-gate (void) fclose(fp); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate if (*list != NULL) { 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * list of entries found 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate *error = 0; 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate return (nserr); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 322*249Sjwahlig int 3230Sstevel@tonic-gate loadmaster_files(mastermap, defopts, stack, stkptr) 3240Sstevel@tonic-gate char *mastermap; 3250Sstevel@tonic-gate char *defopts; 3260Sstevel@tonic-gate char **stack, ***stkptr; 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate FILE *fp; 3290Sstevel@tonic-gate int done = 0; 3300Sstevel@tonic-gate char *line, *dir, *map, *opts; 3310Sstevel@tonic-gate char linebuf[LINESZ]; 3320Sstevel@tonic-gate char lineq[LINESZ]; 3330Sstevel@tonic-gate char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */ 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate if ((fp = file_open(mastermap, fname, stack, stkptr)) == NULL) 3370Sstevel@tonic-gate return (__NSW_UNAVAIL); 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate while ((line = get_line(fp, fname, linebuf, 3400Sstevel@tonic-gate sizeof (linebuf))) != NULL) { 3410Sstevel@tonic-gate unquote(line, lineq); 3420Sstevel@tonic-gate if (macro_expand("", line, lineq, LINESZ)) { 3430Sstevel@tonic-gate syslog(LOG_ERR, 3440Sstevel@tonic-gate "map %s: line too long (max %d chars)", 3450Sstevel@tonic-gate mastermap, LINESZ - 1); 3460Sstevel@tonic-gate continue; 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate dir = line; 3490Sstevel@tonic-gate while (*dir && isspace(*dir)) 3500Sstevel@tonic-gate dir++; 3510Sstevel@tonic-gate if (*dir == '\0') 3520Sstevel@tonic-gate continue; 3530Sstevel@tonic-gate map = dir; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate while (*map && !isspace(*map)) map++; 3560Sstevel@tonic-gate if (*map) 3570Sstevel@tonic-gate *map++ = '\0'; 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate if (*dir == '+') { 3600Sstevel@tonic-gate opts = map; 3610Sstevel@tonic-gate while (*opts && isspace(*opts)) 3620Sstevel@tonic-gate opts++; 3630Sstevel@tonic-gate if (*opts != '-') 3640Sstevel@tonic-gate opts = defopts; 3650Sstevel@tonic-gate else 3660Sstevel@tonic-gate opts++; 3670Sstevel@tonic-gate /* 3680Sstevel@tonic-gate * Check for no embedded blanks. 3690Sstevel@tonic-gate */ 3700Sstevel@tonic-gate if (strcspn(opts, " ") == strlen(opts)) { 3710Sstevel@tonic-gate dir++; 3720Sstevel@tonic-gate (void) loadmaster_map(dir, opts, stack, stkptr); 3730Sstevel@tonic-gate } else { 3740Sstevel@tonic-gate pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname); 3750Sstevel@tonic-gate continue; 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate } else { 3790Sstevel@tonic-gate while (*map && isspace(*map)) 3800Sstevel@tonic-gate map++; 3810Sstevel@tonic-gate if (*map == '\0') 3820Sstevel@tonic-gate continue; 3830Sstevel@tonic-gate opts = map; 3840Sstevel@tonic-gate while (*opts && !isspace(*opts)) 3850Sstevel@tonic-gate opts++; 3860Sstevel@tonic-gate if (*opts) { 3870Sstevel@tonic-gate *opts++ = '\0'; 3880Sstevel@tonic-gate while (*opts && isspace(*opts)) 3890Sstevel@tonic-gate opts++; 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate if (*opts != '-') 3920Sstevel@tonic-gate opts = defopts; 3930Sstevel@tonic-gate else 3940Sstevel@tonic-gate opts++; 3950Sstevel@tonic-gate /* 3960Sstevel@tonic-gate * Check for no embedded blanks. 3970Sstevel@tonic-gate */ 3980Sstevel@tonic-gate if (strcspn(opts, " ") == strlen(opts)) { 3990Sstevel@tonic-gate dirinit(dir, map, opts, 0, stack, stkptr); 4000Sstevel@tonic-gate } else { 4010Sstevel@tonic-gate pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname); 4020Sstevel@tonic-gate continue; 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate done++; 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate (void) stack_op(POP, (char *)NULL, stack, stkptr); 4090Sstevel@tonic-gate (void) fclose(fp); 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate return (done ? __NSW_SUCCESS : __NSW_NOTFOUND); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 414*249Sjwahlig int 4150Sstevel@tonic-gate loaddirect_files(map, local_map, opts, stack, stkptr) 4160Sstevel@tonic-gate char *map, *local_map, *opts; 4170Sstevel@tonic-gate char **stack, ***stkptr; 4180Sstevel@tonic-gate { 4190Sstevel@tonic-gate FILE *fp; 4200Sstevel@tonic-gate int done = 0; 4210Sstevel@tonic-gate char *line, *p1, *p2; 4220Sstevel@tonic-gate char linebuf[LINESZ]; 4230Sstevel@tonic-gate char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */ 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate if ((fp = file_open(map, fname, stack, stkptr)) == NULL) 4260Sstevel@tonic-gate return (__NSW_UNAVAIL); 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate while ((line = get_line(fp, fname, linebuf, 4290Sstevel@tonic-gate sizeof (linebuf))) != NULL) { 4300Sstevel@tonic-gate p1 = line; 4310Sstevel@tonic-gate while (*p1 && isspace(*p1)) 4320Sstevel@tonic-gate p1++; 4330Sstevel@tonic-gate if (*p1 == '\0') 4340Sstevel@tonic-gate continue; 4350Sstevel@tonic-gate p2 = p1; 4360Sstevel@tonic-gate while (*p2 && !isspace(*p2)) 4370Sstevel@tonic-gate p2++; 4380Sstevel@tonic-gate *p2 = '\0'; 4390Sstevel@tonic-gate if (*p1 == '+') { 4400Sstevel@tonic-gate p1++; 4410Sstevel@tonic-gate (void) loaddirect_map(p1, local_map, opts, stack, 4420Sstevel@tonic-gate stkptr); 4430Sstevel@tonic-gate } else { 4440Sstevel@tonic-gate dirinit(p1, local_map, opts, 1, stack, stkptr); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate done++; 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate (void) stack_op(POP, (char *)NULL, stack, stkptr); 4500Sstevel@tonic-gate (void) fclose(fp); 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate return (done ? __NSW_SUCCESS : __NSW_NOTFOUND); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* 4560Sstevel@tonic-gate * This procedure opens the file and pushes it onto the 4570Sstevel@tonic-gate * the stack. Only if a file is opened successfully, is 4580Sstevel@tonic-gate * it pushed onto the stack 4590Sstevel@tonic-gate */ 4600Sstevel@tonic-gate static FILE * 4610Sstevel@tonic-gate file_open(map, fname, stack, stkptr) 4620Sstevel@tonic-gate char *map, *fname; 4630Sstevel@tonic-gate char **stack, ***stkptr; 4640Sstevel@tonic-gate { 4650Sstevel@tonic-gate FILE *fp; 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate if (*map != '/') { 4680Sstevel@tonic-gate /* prepend an "/etc" */ 4690Sstevel@tonic-gate (void) strcpy(fname, "/etc/"); 4700Sstevel@tonic-gate (void) strcat(fname, map); 4710Sstevel@tonic-gate } else 4720Sstevel@tonic-gate (void) strcpy(fname, map); 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate fp = fopen(fname, "r"); 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate if (fp != NULL) { 4770Sstevel@tonic-gate if (!stack_op(PUSH, fname, stack, stkptr)) { 4780Sstevel@tonic-gate (void) fclose(fp); 4790Sstevel@tonic-gate return (NULL); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate return (fp); 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate /* 4860Sstevel@tonic-gate * reimplemnted to be MT-HOT. 4870Sstevel@tonic-gate */ 4880Sstevel@tonic-gate int 4890Sstevel@tonic-gate stack_op(op, name, stack, stkptr) 4900Sstevel@tonic-gate int op; 4910Sstevel@tonic-gate char *name; 4920Sstevel@tonic-gate char **stack, ***stkptr; 4930Sstevel@tonic-gate { 4940Sstevel@tonic-gate char **ptr = NULL; 4950Sstevel@tonic-gate char **stk_top = &stack[STACKSIZ - 1]; 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate /* 4980Sstevel@tonic-gate * the stackptr points to the next empty slot 4990Sstevel@tonic-gate * for PUSH: put the element and increment stkptr 5000Sstevel@tonic-gate * for POP: decrement stkptr and free 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate switch (op) { 5040Sstevel@tonic-gate case INIT: 5050Sstevel@tonic-gate for (ptr = stack; ptr != stk_top; ptr++) 5060Sstevel@tonic-gate *ptr = (char *)NULL; 5070Sstevel@tonic-gate *stkptr = stack; 5080Sstevel@tonic-gate return (1); 5090Sstevel@tonic-gate case ERASE: 5100Sstevel@tonic-gate for (ptr = stack; ptr != stk_top; ptr++) 5110Sstevel@tonic-gate if (*ptr) { 5120Sstevel@tonic-gate if (trace > 1) 5130Sstevel@tonic-gate trace_prt(1, " ERASE %s\n", *ptr); 5140Sstevel@tonic-gate free (*ptr); 5150Sstevel@tonic-gate *ptr = (char *)NULL; 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate *stkptr = stack; 5180Sstevel@tonic-gate return (1); 5190Sstevel@tonic-gate case PUSH: 5200Sstevel@tonic-gate if (*stkptr == stk_top) 5210Sstevel@tonic-gate return (0); 5220Sstevel@tonic-gate for (ptr = stack; ptr != *stkptr; ptr++) 5230Sstevel@tonic-gate if (*ptr && (strcmp(*ptr, name) == 0)) { 5240Sstevel@tonic-gate return (0); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate if (trace > 1) 5270Sstevel@tonic-gate trace_prt(1, " PUSH %s\n", name); 5280Sstevel@tonic-gate if ((**stkptr = strdup(name)) == NULL) { 5290Sstevel@tonic-gate syslog(LOG_ERR, "stack_op: Memory alloc failed : %m"); 5300Sstevel@tonic-gate return (0); 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate (*stkptr)++; 5330Sstevel@tonic-gate return (1); 5340Sstevel@tonic-gate case POP: 5350Sstevel@tonic-gate if (*stkptr != stack) 5360Sstevel@tonic-gate (*stkptr)--; 5370Sstevel@tonic-gate else 5380Sstevel@tonic-gate syslog(LOG_ERR, "Attempt to pop empty stack\n"); 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate if (*stkptr && **stkptr) { 5410Sstevel@tonic-gate if (trace > 1) 5420Sstevel@tonic-gate trace_prt(1, " POP %s\n", **stkptr); 5430Sstevel@tonic-gate free (**stkptr); 5440Sstevel@tonic-gate **stkptr = (char *)NULL; 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate return (1); 5470Sstevel@tonic-gate default: 5480Sstevel@tonic-gate return (0); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate #define READ_EXECOUT_ARGS 3 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate /* 5550Sstevel@tonic-gate * read_execout(char *key, char **lp, char *fname, char *line, int linesz) 5560Sstevel@tonic-gate * A simpler, multithreaded implementation of popen(). Used due to 5570Sstevel@tonic-gate * non multithreaded implementation of popen() (it calls vfork()) and a 5580Sstevel@tonic-gate * significant bug in execl(). 5590Sstevel@tonic-gate * Returns 0 on OK or -1 on error. 5600Sstevel@tonic-gate */ 5610Sstevel@tonic-gate static int 5620Sstevel@tonic-gate read_execout(char *key, char **lp, char *fname, char *line, int linesz) 5630Sstevel@tonic-gate { 5640Sstevel@tonic-gate int p[2]; 5650Sstevel@tonic-gate int status = 0; 5660Sstevel@tonic-gate int child_pid; 5670Sstevel@tonic-gate char *args[READ_EXECOUT_ARGS]; 5680Sstevel@tonic-gate FILE *fp0; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate if (pipe(p) < 0) { 5710Sstevel@tonic-gate syslog(LOG_ERR, "read_execout: Cannot create pipe"); 5720Sstevel@tonic-gate return (-1); 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate /* setup args for execv */ 5760Sstevel@tonic-gate if (((args[0] = strdup(fname)) == NULL) || 5770Sstevel@tonic-gate ((args[1] = strdup(key)) == NULL)) { 5780Sstevel@tonic-gate if (args[0] != NULL) 5790Sstevel@tonic-gate free(args[0]); 5800Sstevel@tonic-gate syslog(LOG_ERR, "read_execout: Memory allocation failed"); 5810Sstevel@tonic-gate return (-1); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate args[2] = NULL; 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate if (trace > 3) 5860Sstevel@tonic-gate trace_prt(1, "\tread_execout: forking .....\n"); 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate switch ((child_pid = fork1())) { 5890Sstevel@tonic-gate case -1: 5900Sstevel@tonic-gate syslog(LOG_ERR, "read_execout: Cannot fork"); 5910Sstevel@tonic-gate return (-1); 5920Sstevel@tonic-gate case 0: 5930Sstevel@tonic-gate /* 5940Sstevel@tonic-gate * Child 5950Sstevel@tonic-gate */ 5960Sstevel@tonic-gate close(p[0]); 5970Sstevel@tonic-gate close(1); 5980Sstevel@tonic-gate if (fcntl(p[1], F_DUPFD, 1) != 1) { 5990Sstevel@tonic-gate syslog(LOG_ERR, 6000Sstevel@tonic-gate "read_execout: dup of stdout failed"); 6010Sstevel@tonic-gate _exit(-1); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate close(p[1]); 6040Sstevel@tonic-gate execv(fname, &args[0]); 6050Sstevel@tonic-gate _exit(-1); 6060Sstevel@tonic-gate default: 6070Sstevel@tonic-gate /* 6080Sstevel@tonic-gate * Parent 6090Sstevel@tonic-gate */ 6100Sstevel@tonic-gate close(p[1]); 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate /* 6130Sstevel@tonic-gate * wait for child to complete. Note we read after the 6140Sstevel@tonic-gate * child exits to guarantee a full pipe. 6150Sstevel@tonic-gate */ 6160Sstevel@tonic-gate while (waitpid(child_pid, &status, 0) < 0) { 6170Sstevel@tonic-gate /* if waitpid fails with EINTR, restart */ 6180Sstevel@tonic-gate if (errno != EINTR) { 6190Sstevel@tonic-gate status = -1; 6200Sstevel@tonic-gate break; 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate if (status != -1) { 6240Sstevel@tonic-gate if ((fp0 = fdopen(p[0], "r")) != NULL) { 6250Sstevel@tonic-gate *lp = get_line(fp0, fname, line, linesz); 6260Sstevel@tonic-gate fclose(fp0); 6270Sstevel@tonic-gate } else { 6280Sstevel@tonic-gate close(p[0]); 6290Sstevel@tonic-gate status = -1; 6300Sstevel@tonic-gate } 6310Sstevel@tonic-gate } else { 6320Sstevel@tonic-gate close(p[0]); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate /* free args */ 6360Sstevel@tonic-gate free(args[0]); 6370Sstevel@tonic-gate free(args[1]); 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate if (trace > 3) 6400Sstevel@tonic-gate trace_prt(1, "\tread_execout: map=%s key=%s line=%s\n", 6410Sstevel@tonic-gate fname, key, line); 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate return (status); 6440Sstevel@tonic-gate } 6450Sstevel@tonic-gate } 646