xref: /onnv-gate/usr/src/cmd/fs.d/autofs/ns_files.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  *	ns_files.c
24*0Sstevel@tonic-gate  *
25*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*0Sstevel@tonic-gate  * Use is subject to license terms.
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #include <stdio.h>
32*0Sstevel@tonic-gate #include <stdlib.h>
33*0Sstevel@tonic-gate #include <syslog.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <ctype.h>
36*0Sstevel@tonic-gate #include <nsswitch.h>
37*0Sstevel@tonic-gate #include <sys/stat.h>
38*0Sstevel@tonic-gate #include <sys/param.h>
39*0Sstevel@tonic-gate #include <rpc/rpc.h>
40*0Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h>
41*0Sstevel@tonic-gate #include <thread.h>
42*0Sstevel@tonic-gate #include <assert.h>
43*0Sstevel@tonic-gate #include <errno.h>
44*0Sstevel@tonic-gate #include <fcntl.h>
45*0Sstevel@tonic-gate #include <unistd.h>
46*0Sstevel@tonic-gate #include <synch.h>
47*0Sstevel@tonic-gate #include <sys/types.h>
48*0Sstevel@tonic-gate #include <sys/wait.h>
49*0Sstevel@tonic-gate #include "automount.h"
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate static int read_execout(char *key, char **lp, char *fname, char *line,
52*0Sstevel@tonic-gate 			int linesz);
53*0Sstevel@tonic-gate static FILE *file_open(char *, char *, char **, char ***);
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /*
56*0Sstevel@tonic-gate  * Initialize the stack
57*0Sstevel@tonic-gate  */
58*0Sstevel@tonic-gate void
59*0Sstevel@tonic-gate init_files(char **stack, char ***stkptr)
60*0Sstevel@tonic-gate {
61*0Sstevel@tonic-gate 	/*
62*0Sstevel@tonic-gate 	 * The call is bogus for automountd since the stack is
63*0Sstevel@tonic-gate 	 * is more appropriately initialized in the thread-private
64*0Sstevel@tonic-gate 	 * routines
65*0Sstevel@tonic-gate 	 */
66*0Sstevel@tonic-gate 	if (stack == NULL && stkptr == NULL)
67*0Sstevel@tonic-gate 		return;
68*0Sstevel@tonic-gate 	(void) stack_op(INIT, NULL, stack, stkptr);
69*0Sstevel@tonic-gate }
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate int
72*0Sstevel@tonic-gate getmapent_files(key, mapname, ml, stack, stkptr, iswildcard, isrestricted)
73*0Sstevel@tonic-gate 	char *key;
74*0Sstevel@tonic-gate 	char *mapname;
75*0Sstevel@tonic-gate 	struct mapline *ml;
76*0Sstevel@tonic-gate 	char **stack, ***stkptr;
77*0Sstevel@tonic-gate 	bool_t *iswildcard;
78*0Sstevel@tonic-gate 	bool_t isrestricted;
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	int nserr;
81*0Sstevel@tonic-gate 	FILE *fp;
82*0Sstevel@tonic-gate 	char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1];
83*0Sstevel@tonic-gate 	char linebuf[LINESZ], lineqbuf[LINESZ];
84*0Sstevel@tonic-gate 	char *lp, *lq;
85*0Sstevel@tonic-gate 	struct stat stbuf;
86*0Sstevel@tonic-gate 	char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
87*0Sstevel@tonic-gate 	int syntaxok = 1;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	if (iswildcard)
90*0Sstevel@tonic-gate 		*iswildcard = FALSE;
91*0Sstevel@tonic-gate 	if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) {
92*0Sstevel@tonic-gate 		nserr = __NSW_UNAVAIL;
93*0Sstevel@tonic-gate 		goto done;
94*0Sstevel@tonic-gate 	}
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	if (stat(fname, &stbuf) < 0) {
97*0Sstevel@tonic-gate 		nserr = __NSW_UNAVAIL;
98*0Sstevel@tonic-gate 		goto done;
99*0Sstevel@tonic-gate 	}
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	/*
102*0Sstevel@tonic-gate 	 * If the file has its execute bit on then
103*0Sstevel@tonic-gate 	 * assume it's an executable map.
104*0Sstevel@tonic-gate 	 * Execute it and pass the key as an argument.
105*0Sstevel@tonic-gate 	 * Expect to get a map entry on the stdout.
106*0Sstevel@tonic-gate 	 * Ignore the "x" bit on restricted maps.
107*0Sstevel@tonic-gate 	 */
108*0Sstevel@tonic-gate 	if (!isrestricted && (stbuf.st_mode & S_IXUSR)) {
109*0Sstevel@tonic-gate 		int rc;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 		if (trace > 1) {
112*0Sstevel@tonic-gate 			trace_prt(1,
113*0Sstevel@tonic-gate 				"\tExecutable map: map=%s key=%s\n",
114*0Sstevel@tonic-gate 				fname, key);
115*0Sstevel@tonic-gate 		}
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 		rc = read_execout(key, &lp, fname, ml->linebuf, LINESZ);
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 		if (rc != 0) {
120*0Sstevel@tonic-gate 			nserr = __NSW_UNAVAIL;
121*0Sstevel@tonic-gate 			goto done;
122*0Sstevel@tonic-gate 		}
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 		if (lp == NULL || strlen(ml->linebuf) == 0) {
125*0Sstevel@tonic-gate 			nserr = __NSW_NOTFOUND;
126*0Sstevel@tonic-gate 			goto done;
127*0Sstevel@tonic-gate 		}
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 		unquote(ml->linebuf, ml->lineqbuf);
130*0Sstevel@tonic-gate 		nserr = __NSW_SUCCESS;
131*0Sstevel@tonic-gate 		goto done;
132*0Sstevel@tonic-gate 	}
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	/*
136*0Sstevel@tonic-gate 	 * It's just a normal map file.
137*0Sstevel@tonic-gate 	 * Search for the entry with the required key.
138*0Sstevel@tonic-gate 	 */
139*0Sstevel@tonic-gate 	for (;;) {
140*0Sstevel@tonic-gate 		lp = get_line(fp, fname, linebuf, sizeof (linebuf));
141*0Sstevel@tonic-gate 		if (lp == NULL) {
142*0Sstevel@tonic-gate 			nserr = __NSW_NOTFOUND;
143*0Sstevel@tonic-gate 			goto done;
144*0Sstevel@tonic-gate 		}
145*0Sstevel@tonic-gate 		if (verbose && syntaxok && isspace(*(uchar_t *)lp)) {
146*0Sstevel@tonic-gate 			syntaxok = 0;
147*0Sstevel@tonic-gate 			syslog(LOG_ERR,
148*0Sstevel@tonic-gate 				"leading space in map entry \"%s\" in %s",
149*0Sstevel@tonic-gate 				lp, mapname);
150*0Sstevel@tonic-gate 		}
151*0Sstevel@tonic-gate 		lq = lineqbuf;
152*0Sstevel@tonic-gate 		unquote(lp, lq);
153*0Sstevel@tonic-gate 		if ((getword(word, wordq, &lp, &lq, ' ', sizeof (word))
154*0Sstevel@tonic-gate 			== -1) || (word[0] == '\0'))
155*0Sstevel@tonic-gate 			continue;
156*0Sstevel@tonic-gate 		if (strcmp(word, key) == 0)
157*0Sstevel@tonic-gate 			break;
158*0Sstevel@tonic-gate 		if (word[0] == '*' && word[1] == '\0') {
159*0Sstevel@tonic-gate 			if (iswildcard)
160*0Sstevel@tonic-gate 				*iswildcard = TRUE;
161*0Sstevel@tonic-gate 			break;
162*0Sstevel@tonic-gate 		}
163*0Sstevel@tonic-gate 		if (word[0] == '+') {
164*0Sstevel@tonic-gate 			nserr = getmapent(key, word+1, ml, stack, stkptr,
165*0Sstevel@tonic-gate 						iswildcard, isrestricted);
166*0Sstevel@tonic-gate 			if (nserr == __NSW_SUCCESS)
167*0Sstevel@tonic-gate 				goto done;
168*0Sstevel@tonic-gate 			continue;
169*0Sstevel@tonic-gate 		}
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 		/*
172*0Sstevel@tonic-gate 		 * sanity check each map entry key against
173*0Sstevel@tonic-gate 		 * the lookup key as the map is searched.
174*0Sstevel@tonic-gate 		 */
175*0Sstevel@tonic-gate 		if (verbose && syntaxok) { /* sanity check entry */
176*0Sstevel@tonic-gate 			if (*key == '/') {
177*0Sstevel@tonic-gate 				if (*word != '/') {
178*0Sstevel@tonic-gate 					syntaxok = 0;
179*0Sstevel@tonic-gate 					syslog(LOG_ERR,
180*0Sstevel@tonic-gate 					"bad key \"%s\" in direct map %s\n",
181*0Sstevel@tonic-gate 					word, mapname);
182*0Sstevel@tonic-gate 				}
183*0Sstevel@tonic-gate 			} else {
184*0Sstevel@tonic-gate 				if (strchr(word, '/')) {
185*0Sstevel@tonic-gate 					syntaxok = 0;
186*0Sstevel@tonic-gate 					syslog(LOG_ERR,
187*0Sstevel@tonic-gate 					"bad key \"%s\" in indirect map %s\n",
188*0Sstevel@tonic-gate 					word, mapname);
189*0Sstevel@tonic-gate 				}
190*0Sstevel@tonic-gate 			}
191*0Sstevel@tonic-gate 		}
192*0Sstevel@tonic-gate 	}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	(void) strcpy(ml->linebuf, lp);
195*0Sstevel@tonic-gate 	(void) strcpy(ml->lineqbuf, lq);
196*0Sstevel@tonic-gate 	nserr = __NSW_SUCCESS;
197*0Sstevel@tonic-gate done:
198*0Sstevel@tonic-gate 	if (fp) {
199*0Sstevel@tonic-gate 		(void) stack_op(POP, (char *)NULL, stack, stkptr);
200*0Sstevel@tonic-gate 		(void) fclose(fp);
201*0Sstevel@tonic-gate 	}
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	return (nserr);
205*0Sstevel@tonic-gate }
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate int
208*0Sstevel@tonic-gate getmapkeys_files(mapname, list, error, cache_time, stack, stkptr)
209*0Sstevel@tonic-gate 	char *mapname;
210*0Sstevel@tonic-gate 	struct dir_entry **list;
211*0Sstevel@tonic-gate 	int *error;
212*0Sstevel@tonic-gate 	int *cache_time;
213*0Sstevel@tonic-gate 	char **stack, ***stkptr;
214*0Sstevel@tonic-gate {
215*0Sstevel@tonic-gate 	FILE *fp = NULL;
216*0Sstevel@tonic-gate 	char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1];
217*0Sstevel@tonic-gate 	char linebuf[LINESZ], lineqbuf[LINESZ];
218*0Sstevel@tonic-gate 	char *lp, *lq;
219*0Sstevel@tonic-gate 	struct stat stbuf;
220*0Sstevel@tonic-gate 	char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
221*0Sstevel@tonic-gate 	int syntaxok = 1;
222*0Sstevel@tonic-gate 	int nserr;
223*0Sstevel@tonic-gate 	struct dir_entry *last = NULL;
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	if (trace > 1)
226*0Sstevel@tonic-gate 		trace_prt(1, "getmapkeys_files %s\n", mapname);
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	*cache_time = RDDIR_CACHE_TIME;
229*0Sstevel@tonic-gate 	if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) {
230*0Sstevel@tonic-gate 		*error = ENOENT;
231*0Sstevel@tonic-gate 		nserr = __NSW_UNAVAIL;
232*0Sstevel@tonic-gate 		goto done;
233*0Sstevel@tonic-gate 	}
234*0Sstevel@tonic-gate 	if (fseek(fp, 0L, SEEK_SET) == -1) {
235*0Sstevel@tonic-gate 		*error = ENOENT;
236*0Sstevel@tonic-gate 		nserr = __NSW_UNAVAIL;
237*0Sstevel@tonic-gate 		goto done;
238*0Sstevel@tonic-gate 	}
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	if (stat(fname, &stbuf) < 0) {
241*0Sstevel@tonic-gate 		*error = ENOENT;
242*0Sstevel@tonic-gate 		nserr = __NSW_UNAVAIL;
243*0Sstevel@tonic-gate 		goto done;
244*0Sstevel@tonic-gate 	}
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	/*
247*0Sstevel@tonic-gate 	 * If the file has its execute bit on then
248*0Sstevel@tonic-gate 	 * assume it's an executable map.
249*0Sstevel@tonic-gate 	 * I don't know how to list executable maps, return
250*0Sstevel@tonic-gate 	 * an empty map.
251*0Sstevel@tonic-gate 	 */
252*0Sstevel@tonic-gate 	if (stbuf.st_mode & S_IXUSR) {
253*0Sstevel@tonic-gate 		*error = 0;
254*0Sstevel@tonic-gate 		nserr = __NSW_SUCCESS;
255*0Sstevel@tonic-gate 		goto done;
256*0Sstevel@tonic-gate 	}
257*0Sstevel@tonic-gate 	/*
258*0Sstevel@tonic-gate 	 * It's just a normal map file.
259*0Sstevel@tonic-gate 	 * List entries one line at a time.
260*0Sstevel@tonic-gate 	 */
261*0Sstevel@tonic-gate 	for (;;) {
262*0Sstevel@tonic-gate 		lp = get_line(fp, fname, linebuf, sizeof (linebuf));
263*0Sstevel@tonic-gate 		if (lp == NULL) {
264*0Sstevel@tonic-gate 			nserr = __NSW_SUCCESS;
265*0Sstevel@tonic-gate 			goto done;
266*0Sstevel@tonic-gate 		}
267*0Sstevel@tonic-gate 		if (syntaxok && isspace(*(uchar_t *)lp)) {
268*0Sstevel@tonic-gate 			syntaxok = 0;
269*0Sstevel@tonic-gate 			syslog(LOG_ERR,
270*0Sstevel@tonic-gate 				"leading space in map entry \"%s\" in %s",
271*0Sstevel@tonic-gate 				lp, mapname);
272*0Sstevel@tonic-gate 		}
273*0Sstevel@tonic-gate 		lq = lineqbuf;
274*0Sstevel@tonic-gate 		unquote(lp, lq);
275*0Sstevel@tonic-gate 		if ((getword(word, wordq, &lp, &lq, ' ', MAXFILENAMELEN)
276*0Sstevel@tonic-gate 				== -1) || (word[0] == '\0'))
277*0Sstevel@tonic-gate 			continue;
278*0Sstevel@tonic-gate 		/*
279*0Sstevel@tonic-gate 		 * Wildcard entries should be ignored and this should be
280*0Sstevel@tonic-gate 		 * the last entry read to corroborate the search through
281*0Sstevel@tonic-gate 		 * files, i.e., search for key until a wildcard is reached.
282*0Sstevel@tonic-gate 		 */
283*0Sstevel@tonic-gate 		if (word[0] == '*' && word[1] == '\0')
284*0Sstevel@tonic-gate 			break;
285*0Sstevel@tonic-gate 		if (word[0] == '+') {
286*0Sstevel@tonic-gate 			/*
287*0Sstevel@tonic-gate 			 * Name switch here
288*0Sstevel@tonic-gate 			 */
289*0Sstevel@tonic-gate 			getmapkeys(word+1, list, error, cache_time,
290*0Sstevel@tonic-gate 				stack, stkptr, 0);
291*0Sstevel@tonic-gate 			/*
292*0Sstevel@tonic-gate 			 * the list may have been updated, therefore
293*0Sstevel@tonic-gate 			 * our 'last' may no longer be valid
294*0Sstevel@tonic-gate 			 */
295*0Sstevel@tonic-gate 			last = NULL;
296*0Sstevel@tonic-gate 			continue;
297*0Sstevel@tonic-gate 		}
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 		if (add_dir_entry(word, list, &last) != 0) {
300*0Sstevel@tonic-gate 			*error = ENOMEM;
301*0Sstevel@tonic-gate 			goto done;
302*0Sstevel@tonic-gate 		}
303*0Sstevel@tonic-gate 		assert(last != NULL);
304*0Sstevel@tonic-gate 	}
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	nserr = __NSW_SUCCESS;
307*0Sstevel@tonic-gate done:
308*0Sstevel@tonic-gate 	if (fp) {
309*0Sstevel@tonic-gate 		(void) stack_op(POP, (char *)NULL, stack, stkptr);
310*0Sstevel@tonic-gate 		(void) fclose(fp);
311*0Sstevel@tonic-gate 	}
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	if (*list != NULL) {
314*0Sstevel@tonic-gate 		/*
315*0Sstevel@tonic-gate 		 * list of entries found
316*0Sstevel@tonic-gate 		 */
317*0Sstevel@tonic-gate 		*error = 0;
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate 	return (nserr);
320*0Sstevel@tonic-gate }
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate loadmaster_files(mastermap, defopts, stack, stkptr)
323*0Sstevel@tonic-gate 	char *mastermap;
324*0Sstevel@tonic-gate 	char *defopts;
325*0Sstevel@tonic-gate 	char **stack, ***stkptr;
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate 	FILE *fp;
328*0Sstevel@tonic-gate 	int done = 0;
329*0Sstevel@tonic-gate 	char *line, *dir, *map, *opts;
330*0Sstevel@tonic-gate 	char linebuf[LINESZ];
331*0Sstevel@tonic-gate 	char lineq[LINESZ];
332*0Sstevel@tonic-gate 	char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	if ((fp = file_open(mastermap, fname, stack, stkptr)) == NULL)
336*0Sstevel@tonic-gate 		return (__NSW_UNAVAIL);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	while ((line = get_line(fp, fname, linebuf,
339*0Sstevel@tonic-gate 				sizeof (linebuf))) != NULL) {
340*0Sstevel@tonic-gate 		unquote(line, lineq);
341*0Sstevel@tonic-gate 		if (macro_expand("", line, lineq, LINESZ)) {
342*0Sstevel@tonic-gate 			syslog(LOG_ERR,
343*0Sstevel@tonic-gate 				"map %s: line too long (max %d chars)",
344*0Sstevel@tonic-gate 				mastermap, LINESZ - 1);
345*0Sstevel@tonic-gate 			continue;
346*0Sstevel@tonic-gate 		}
347*0Sstevel@tonic-gate 		dir = line;
348*0Sstevel@tonic-gate 		while (*dir && isspace(*dir))
349*0Sstevel@tonic-gate 			dir++;
350*0Sstevel@tonic-gate 		if (*dir == '\0')
351*0Sstevel@tonic-gate 			continue;
352*0Sstevel@tonic-gate 		map = dir;
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 		while (*map && !isspace(*map)) map++;
355*0Sstevel@tonic-gate 		if (*map)
356*0Sstevel@tonic-gate 			*map++ = '\0';
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 		if (*dir == '+') {
359*0Sstevel@tonic-gate 			opts = map;
360*0Sstevel@tonic-gate 			while (*opts && isspace(*opts))
361*0Sstevel@tonic-gate 				opts++;
362*0Sstevel@tonic-gate 			if (*opts != '-')
363*0Sstevel@tonic-gate 				opts = defopts;
364*0Sstevel@tonic-gate 			else
365*0Sstevel@tonic-gate 				opts++;
366*0Sstevel@tonic-gate 			/*
367*0Sstevel@tonic-gate 			 * Check for no embedded blanks.
368*0Sstevel@tonic-gate 			 */
369*0Sstevel@tonic-gate 			if (strcspn(opts, " 	") == strlen(opts)) {
370*0Sstevel@tonic-gate 				dir++;
371*0Sstevel@tonic-gate 				(void) loadmaster_map(dir, opts, stack, stkptr);
372*0Sstevel@tonic-gate 			} else {
373*0Sstevel@tonic-gate pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname);
374*0Sstevel@tonic-gate 				continue;
375*0Sstevel@tonic-gate 			}
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 		} else {
378*0Sstevel@tonic-gate 			while (*map && isspace(*map))
379*0Sstevel@tonic-gate 				map++;
380*0Sstevel@tonic-gate 			if (*map == '\0')
381*0Sstevel@tonic-gate 				continue;
382*0Sstevel@tonic-gate 			opts = map;
383*0Sstevel@tonic-gate 			while (*opts && !isspace(*opts))
384*0Sstevel@tonic-gate 				opts++;
385*0Sstevel@tonic-gate 			if (*opts) {
386*0Sstevel@tonic-gate 				*opts++ = '\0';
387*0Sstevel@tonic-gate 				while (*opts && isspace(*opts))
388*0Sstevel@tonic-gate 					opts++;
389*0Sstevel@tonic-gate 			}
390*0Sstevel@tonic-gate 			if (*opts != '-')
391*0Sstevel@tonic-gate 				opts = defopts;
392*0Sstevel@tonic-gate 			else
393*0Sstevel@tonic-gate 				opts++;
394*0Sstevel@tonic-gate 			/*
395*0Sstevel@tonic-gate 			 * Check for no embedded blanks.
396*0Sstevel@tonic-gate 			 */
397*0Sstevel@tonic-gate 			if (strcspn(opts, " 	") == strlen(opts)) {
398*0Sstevel@tonic-gate 				dirinit(dir, map, opts, 0, stack, stkptr);
399*0Sstevel@tonic-gate 			} else {
400*0Sstevel@tonic-gate pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname);
401*0Sstevel@tonic-gate 				continue;
402*0Sstevel@tonic-gate 			}
403*0Sstevel@tonic-gate 		}
404*0Sstevel@tonic-gate 		done++;
405*0Sstevel@tonic-gate 	}
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	(void) stack_op(POP, (char *)NULL, stack, stkptr);
408*0Sstevel@tonic-gate 	(void) fclose(fp);
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	return (done ? __NSW_SUCCESS : __NSW_NOTFOUND);
411*0Sstevel@tonic-gate }
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate loaddirect_files(map, local_map, opts, stack, stkptr)
414*0Sstevel@tonic-gate 	char *map, *local_map, *opts;
415*0Sstevel@tonic-gate 	char **stack, ***stkptr;
416*0Sstevel@tonic-gate {
417*0Sstevel@tonic-gate 	FILE *fp;
418*0Sstevel@tonic-gate 	int done = 0;
419*0Sstevel@tonic-gate 	char *line, *p1, *p2;
420*0Sstevel@tonic-gate 	char linebuf[LINESZ];
421*0Sstevel@tonic-gate 	char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	if ((fp = file_open(map, fname, stack, stkptr)) == NULL)
424*0Sstevel@tonic-gate 		return (__NSW_UNAVAIL);
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	while ((line = get_line(fp, fname, linebuf,
427*0Sstevel@tonic-gate 				sizeof (linebuf))) != NULL) {
428*0Sstevel@tonic-gate 		p1 = line;
429*0Sstevel@tonic-gate 		while (*p1 && isspace(*p1))
430*0Sstevel@tonic-gate 			p1++;
431*0Sstevel@tonic-gate 		if (*p1 == '\0')
432*0Sstevel@tonic-gate 			continue;
433*0Sstevel@tonic-gate 		p2 = p1;
434*0Sstevel@tonic-gate 		while (*p2 && !isspace(*p2))
435*0Sstevel@tonic-gate 			p2++;
436*0Sstevel@tonic-gate 		*p2 = '\0';
437*0Sstevel@tonic-gate 		if (*p1 == '+') {
438*0Sstevel@tonic-gate 			p1++;
439*0Sstevel@tonic-gate 			(void) loaddirect_map(p1, local_map, opts, stack,
440*0Sstevel@tonic-gate 					stkptr);
441*0Sstevel@tonic-gate 		} else {
442*0Sstevel@tonic-gate 			dirinit(p1, local_map, opts, 1, stack, stkptr);
443*0Sstevel@tonic-gate 		}
444*0Sstevel@tonic-gate 		done++;
445*0Sstevel@tonic-gate 	}
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	(void) stack_op(POP, (char *)NULL, stack, stkptr);
448*0Sstevel@tonic-gate 	(void) fclose(fp);
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	return (done ? __NSW_SUCCESS : __NSW_NOTFOUND);
451*0Sstevel@tonic-gate }
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate /*
454*0Sstevel@tonic-gate  * This procedure opens the file and pushes it onto the
455*0Sstevel@tonic-gate  * the stack. Only if a file is opened successfully, is
456*0Sstevel@tonic-gate  * it pushed onto the stack
457*0Sstevel@tonic-gate  */
458*0Sstevel@tonic-gate static FILE *
459*0Sstevel@tonic-gate file_open(map, fname, stack, stkptr)
460*0Sstevel@tonic-gate 	char *map, *fname;
461*0Sstevel@tonic-gate 	char **stack, ***stkptr;
462*0Sstevel@tonic-gate {
463*0Sstevel@tonic-gate 	FILE *fp;
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	if (*map != '/') {
466*0Sstevel@tonic-gate 		/* prepend an "/etc" */
467*0Sstevel@tonic-gate 		(void) strcpy(fname, "/etc/");
468*0Sstevel@tonic-gate 		(void) strcat(fname, map);
469*0Sstevel@tonic-gate 	} else
470*0Sstevel@tonic-gate 		(void) strcpy(fname, map);
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	fp = fopen(fname, "r");
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	if (fp != NULL) {
475*0Sstevel@tonic-gate 		if (!stack_op(PUSH, fname, stack, stkptr)) {
476*0Sstevel@tonic-gate 			(void) fclose(fp);
477*0Sstevel@tonic-gate 			return (NULL);
478*0Sstevel@tonic-gate 		}
479*0Sstevel@tonic-gate 	}
480*0Sstevel@tonic-gate 	return (fp);
481*0Sstevel@tonic-gate }
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate /*
484*0Sstevel@tonic-gate  * reimplemnted to be MT-HOT.
485*0Sstevel@tonic-gate  */
486*0Sstevel@tonic-gate int
487*0Sstevel@tonic-gate stack_op(op, name, stack, stkptr)
488*0Sstevel@tonic-gate 	int op;
489*0Sstevel@tonic-gate 	char *name;
490*0Sstevel@tonic-gate 	char **stack, ***stkptr;
491*0Sstevel@tonic-gate {
492*0Sstevel@tonic-gate 	char **ptr = NULL;
493*0Sstevel@tonic-gate 	char **stk_top = &stack[STACKSIZ - 1];
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	/*
496*0Sstevel@tonic-gate 	 * the stackptr points to the next empty slot
497*0Sstevel@tonic-gate 	 * for PUSH: put the element and increment stkptr
498*0Sstevel@tonic-gate 	 * for POP: decrement stkptr and free
499*0Sstevel@tonic-gate 	 */
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 	switch (op) {
502*0Sstevel@tonic-gate 	case INIT:
503*0Sstevel@tonic-gate 		for (ptr = stack; ptr != stk_top; ptr++)
504*0Sstevel@tonic-gate 			*ptr = (char *)NULL;
505*0Sstevel@tonic-gate 		*stkptr = stack;
506*0Sstevel@tonic-gate 		return (1);
507*0Sstevel@tonic-gate 	case ERASE:
508*0Sstevel@tonic-gate 		for (ptr = stack; ptr != stk_top; ptr++)
509*0Sstevel@tonic-gate 			if (*ptr) {
510*0Sstevel@tonic-gate 				if (trace > 1)
511*0Sstevel@tonic-gate 					trace_prt(1, "  ERASE %s\n", *ptr);
512*0Sstevel@tonic-gate 				free (*ptr);
513*0Sstevel@tonic-gate 				*ptr = (char *)NULL;
514*0Sstevel@tonic-gate 			}
515*0Sstevel@tonic-gate 		*stkptr = stack;
516*0Sstevel@tonic-gate 		return (1);
517*0Sstevel@tonic-gate 	case PUSH:
518*0Sstevel@tonic-gate 		if (*stkptr == stk_top)
519*0Sstevel@tonic-gate 			return (0);
520*0Sstevel@tonic-gate 		for (ptr = stack; ptr != *stkptr; ptr++)
521*0Sstevel@tonic-gate 			if (*ptr && (strcmp(*ptr, name) == 0)) {
522*0Sstevel@tonic-gate 				return (0);
523*0Sstevel@tonic-gate 			}
524*0Sstevel@tonic-gate 		if (trace > 1)
525*0Sstevel@tonic-gate 			trace_prt(1, "  PUSH %s\n", name);
526*0Sstevel@tonic-gate 		if ((**stkptr = strdup(name)) == NULL) {
527*0Sstevel@tonic-gate 			syslog(LOG_ERR, "stack_op: Memory alloc failed : %m");
528*0Sstevel@tonic-gate 			return (0);
529*0Sstevel@tonic-gate 		}
530*0Sstevel@tonic-gate 		(*stkptr)++;
531*0Sstevel@tonic-gate 		return (1);
532*0Sstevel@tonic-gate 	case POP:
533*0Sstevel@tonic-gate 		if (*stkptr != stack)
534*0Sstevel@tonic-gate 			(*stkptr)--;
535*0Sstevel@tonic-gate 		else
536*0Sstevel@tonic-gate 			syslog(LOG_ERR, "Attempt to pop empty stack\n");
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 		if (*stkptr && **stkptr) {
539*0Sstevel@tonic-gate 			if (trace > 1)
540*0Sstevel@tonic-gate 				trace_prt(1, "  POP %s\n", **stkptr);
541*0Sstevel@tonic-gate 			free (**stkptr);
542*0Sstevel@tonic-gate 			**stkptr = (char *)NULL;
543*0Sstevel@tonic-gate 		}
544*0Sstevel@tonic-gate 		return (1);
545*0Sstevel@tonic-gate 	default:
546*0Sstevel@tonic-gate 		return (0);
547*0Sstevel@tonic-gate 	}
548*0Sstevel@tonic-gate }
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate #define	READ_EXECOUT_ARGS 3
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate /*
553*0Sstevel@tonic-gate  * read_execout(char *key, char **lp, char *fname, char *line, int linesz)
554*0Sstevel@tonic-gate  * A simpler, multithreaded implementation of popen(). Used due to
555*0Sstevel@tonic-gate  * non multithreaded implementation of popen() (it calls vfork()) and a
556*0Sstevel@tonic-gate  * significant bug in execl().
557*0Sstevel@tonic-gate  * Returns 0 on OK or -1 on error.
558*0Sstevel@tonic-gate  */
559*0Sstevel@tonic-gate static int
560*0Sstevel@tonic-gate read_execout(char *key, char **lp, char *fname, char *line, int linesz)
561*0Sstevel@tonic-gate {
562*0Sstevel@tonic-gate 	int p[2];
563*0Sstevel@tonic-gate 	int status = 0;
564*0Sstevel@tonic-gate 	int child_pid;
565*0Sstevel@tonic-gate 	char *args[READ_EXECOUT_ARGS];
566*0Sstevel@tonic-gate 	FILE *fp0;
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	if (pipe(p) < 0) {
569*0Sstevel@tonic-gate 		syslog(LOG_ERR, "read_execout: Cannot create pipe");
570*0Sstevel@tonic-gate 		return (-1);
571*0Sstevel@tonic-gate 	}
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	/* setup args for execv */
574*0Sstevel@tonic-gate 	if (((args[0] = strdup(fname)) == NULL) ||
575*0Sstevel@tonic-gate 		((args[1] = strdup(key)) == NULL)) {
576*0Sstevel@tonic-gate 		if (args[0] != NULL)
577*0Sstevel@tonic-gate 			free(args[0]);
578*0Sstevel@tonic-gate 		syslog(LOG_ERR, "read_execout: Memory allocation failed");
579*0Sstevel@tonic-gate 		return (-1);
580*0Sstevel@tonic-gate 	}
581*0Sstevel@tonic-gate 	args[2] = NULL;
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	if (trace > 3)
584*0Sstevel@tonic-gate 		trace_prt(1, "\tread_execout: forking .....\n");
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	switch ((child_pid = fork1())) {
587*0Sstevel@tonic-gate 	case -1:
588*0Sstevel@tonic-gate 		syslog(LOG_ERR, "read_execout: Cannot fork");
589*0Sstevel@tonic-gate 		return (-1);
590*0Sstevel@tonic-gate 	case 0:
591*0Sstevel@tonic-gate 		/*
592*0Sstevel@tonic-gate 		 * Child
593*0Sstevel@tonic-gate 		 */
594*0Sstevel@tonic-gate 		close(p[0]);
595*0Sstevel@tonic-gate 		close(1);
596*0Sstevel@tonic-gate 		if (fcntl(p[1], F_DUPFD, 1) != 1) {
597*0Sstevel@tonic-gate 			syslog(LOG_ERR,
598*0Sstevel@tonic-gate 			"read_execout: dup of stdout failed");
599*0Sstevel@tonic-gate 			_exit(-1);
600*0Sstevel@tonic-gate 		}
601*0Sstevel@tonic-gate 		close(p[1]);
602*0Sstevel@tonic-gate 		execv(fname, &args[0]);
603*0Sstevel@tonic-gate 		_exit(-1);
604*0Sstevel@tonic-gate 	default:
605*0Sstevel@tonic-gate 		/*
606*0Sstevel@tonic-gate 		 * Parent
607*0Sstevel@tonic-gate 		 */
608*0Sstevel@tonic-gate 		close(p[1]);
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 		/*
611*0Sstevel@tonic-gate 		 * wait for child to complete. Note we read after the
612*0Sstevel@tonic-gate 		 * child exits to guarantee a full pipe.
613*0Sstevel@tonic-gate 		 */
614*0Sstevel@tonic-gate 		while (waitpid(child_pid, &status, 0) < 0) {
615*0Sstevel@tonic-gate 			/* if waitpid fails with EINTR, restart */
616*0Sstevel@tonic-gate 			if (errno != EINTR) {
617*0Sstevel@tonic-gate 				status = -1;
618*0Sstevel@tonic-gate 				break;
619*0Sstevel@tonic-gate 			}
620*0Sstevel@tonic-gate 		}
621*0Sstevel@tonic-gate 		if (status != -1) {
622*0Sstevel@tonic-gate 			if ((fp0 = fdopen(p[0], "r")) != NULL) {
623*0Sstevel@tonic-gate 				*lp = get_line(fp0, fname, line, linesz);
624*0Sstevel@tonic-gate 				fclose(fp0);
625*0Sstevel@tonic-gate 			} else {
626*0Sstevel@tonic-gate 				close(p[0]);
627*0Sstevel@tonic-gate 				status = -1;
628*0Sstevel@tonic-gate 			}
629*0Sstevel@tonic-gate 		} else {
630*0Sstevel@tonic-gate 			close(p[0]);
631*0Sstevel@tonic-gate 		}
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 		/* free args */
634*0Sstevel@tonic-gate 		free(args[0]);
635*0Sstevel@tonic-gate 		free(args[1]);
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 		if (trace > 3)
638*0Sstevel@tonic-gate 			trace_prt(1, "\tread_execout: map=%s key=%s line=%s\n",
639*0Sstevel@tonic-gate 			fname, key, line);
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 		return (status);
642*0Sstevel@tonic-gate 	}
643*0Sstevel@tonic-gate }
644