xref: /onnv-gate/usr/src/cmd/fs.d/cachefs/cachefspack/rules.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  * Copyright (c) 1996, by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All Rights Reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <locale.h>
30*0Sstevel@tonic-gate #include <sys/types.h>
31*0Sstevel@tonic-gate #include <stdio.h>
32*0Sstevel@tonic-gate #include <sys/param.h>
33*0Sstevel@tonic-gate #include <string.h>
34*0Sstevel@tonic-gate #include <unistd.h>
35*0Sstevel@tonic-gate #include <errno.h>
36*0Sstevel@tonic-gate #include <fcntl.h>
37*0Sstevel@tonic-gate #include <sys/stat.h>
38*0Sstevel@tonic-gate #include <stdlib.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include "rules.h"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate char * lex(FILE *);
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate extern char *mstrdup(const char *);
45*0Sstevel@tonic-gate extern void *mmalloc(size_t size);
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate void
read_rules(FILE * file,int (* rulefunc)())48*0Sstevel@tonic-gate read_rules(FILE *file, int (*rulefunc)())
49*0Sstevel@tonic-gate {
50*0Sstevel@tonic-gate 	char *s;
51*0Sstevel@tonic-gate 	int base_active = 0;
52*0Sstevel@tonic-gate 	int list_ent_cnt = 0;
53*0Sstevel@tonic-gate 	int gign_ent_cnt = 0;
54*0Sstevel@tonic-gate 	int lign_ent_cnt = 0;
55*0Sstevel@tonic-gate 	struct item *add_item();
56*0Sstevel@tonic-gate 	struct item *fitem, *sitem;
57*0Sstevel@tonic-gate 	char version[20];
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate 	last_gign = &gign_hd;
60*0Sstevel@tonic-gate 	gign_hd.i_next = (struct item *)0;
61*0Sstevel@tonic-gate 	gign_hd.i_str = (char *)0;
62*0Sstevel@tonic-gate 	list_hd.i_next = (struct item *)0;
63*0Sstevel@tonic-gate 	list_hd.i_str = (char *)0;
64*0Sstevel@tonic-gate 	while (s = lex(file)) {
65*0Sstevel@tonic-gate 		if (s == (char *)0)
66*0Sstevel@tonic-gate 			break;
67*0Sstevel@tonic-gate 		if (*s == '#')
68*0Sstevel@tonic-gate 			continue;
69*0Sstevel@tonic-gate 		if (*s == '*')
70*0Sstevel@tonic-gate 			continue;
71*0Sstevel@tonic-gate 		if (strcmp(s, BASE) == 0) {
72*0Sstevel@tonic-gate #ifdef DEBUG
73*0Sstevel@tonic-gate 			printf("BASE base_active = %d\n", base_active);
74*0Sstevel@tonic-gate #endif /* DEBUG */
75*0Sstevel@tonic-gate 			if (base_active) {
76*0Sstevel@tonic-gate 				/*
77*0Sstevel@tonic-gate 				 * Tack local IGNORE strings to end of globals
78*0Sstevel@tonic-gate 				 */
79*0Sstevel@tonic-gate 				if (lign_hd.i_next != (struct item *)0) {
80*0Sstevel@tonic-gate 					last_gign->i_next = &lign_hd;
81*0Sstevel@tonic-gate 				}
82*0Sstevel@tonic-gate 				/*
83*0Sstevel@tonic-gate 				 * Process directives for previous BASE command
84*0Sstevel@tonic-gate 				 * if there was one. Also free up LIST items
85*0Sstevel@tonic-gate 				 * and local IGNORE items.
86*0Sstevel@tonic-gate 				 */
87*0Sstevel@tonic-gate 				do_base_dir(basedir, &list_hd, &gign_hd,
88*0Sstevel@tonic-gate 				    rulefunc);
89*0Sstevel@tonic-gate 				/*
90*0Sstevel@tonic-gate 				 * Free up space from LIST item list
91*0Sstevel@tonic-gate 				 */
92*0Sstevel@tonic-gate 				fitem  = list_hd.i_next;
93*0Sstevel@tonic-gate 				if (fitem != (struct item *)0) {
94*0Sstevel@tonic-gate 					while (fitem != (struct item *)0) {
95*0Sstevel@tonic-gate 						free(fitem->i_str);
96*0Sstevel@tonic-gate 						sitem = fitem->i_next;
97*0Sstevel@tonic-gate 						free(fitem);
98*0Sstevel@tonic-gate 						fitem = sitem;
99*0Sstevel@tonic-gate 					}
100*0Sstevel@tonic-gate 				}
101*0Sstevel@tonic-gate 				/*
102*0Sstevel@tonic-gate 				 * Free up space from local IGNORE item list
103*0Sstevel@tonic-gate 				 */
104*0Sstevel@tonic-gate 				fitem  = lign_hd.i_next;
105*0Sstevel@tonic-gate 				if (fitem != (struct item *)0) {
106*0Sstevel@tonic-gate 					while (fitem != (struct item *)0) {
107*0Sstevel@tonic-gate 						free(fitem->i_str);
108*0Sstevel@tonic-gate 						sitem = fitem->i_next;
109*0Sstevel@tonic-gate 						free(fitem);
110*0Sstevel@tonic-gate 						fitem = sitem;
111*0Sstevel@tonic-gate 					}
112*0Sstevel@tonic-gate 				}
113*0Sstevel@tonic-gate 				last_gign->i_next = (struct item *)0;
114*0Sstevel@tonic-gate 			}
115*0Sstevel@tonic-gate 			base_active = 1;
116*0Sstevel@tonic-gate 			/*
117*0Sstevel@tonic-gate 			 * Reset LIST item list and local IGNORE item
118*0Sstevel@tonic-gate 			 * list to be empty.
119*0Sstevel@tonic-gate 			 */
120*0Sstevel@tonic-gate 			last_list = &list_hd;
121*0Sstevel@tonic-gate 			list_hd.i_next = (struct item *)0;
122*0Sstevel@tonic-gate 			list_hd.i_str = (char *)0;
123*0Sstevel@tonic-gate 			last_lign = &lign_hd;
124*0Sstevel@tonic-gate 			lign_hd.i_next = (struct item *)0;
125*0Sstevel@tonic-gate 			lign_hd.i_str = (char *)0;
126*0Sstevel@tonic-gate 			/*
127*0Sstevel@tonic-gate 			 * Get BASE directory specified
128*0Sstevel@tonic-gate 			 */
129*0Sstevel@tonic-gate 			s = lex(0);
130*0Sstevel@tonic-gate 			if (s == (char *)0) {
131*0Sstevel@tonic-gate 				fprintf(stderr, gettext("cachefspack: "));
132*0Sstevel@tonic-gate 				fprintf(stderr, gettext(
133*0Sstevel@tonic-gate 				    "illegal BASE command\n"));
134*0Sstevel@tonic-gate 				return;
135*0Sstevel@tonic-gate 			}
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 			if (*s == '$') {
138*0Sstevel@tonic-gate 				/*
139*0Sstevel@tonic-gate 				 * String starts with a '$', it must be an
140*0Sstevel@tonic-gate 				 * environment variable
141*0Sstevel@tonic-gate 				 */
142*0Sstevel@tonic-gate 				s = getenv(&s[1]);
143*0Sstevel@tonic-gate 				if (s == (char *)NULL) {
144*0Sstevel@tonic-gate 					fprintf(stderr,
145*0Sstevel@tonic-gate 					    gettext("cachefspack: "));
146*0Sstevel@tonic-gate 					fprintf(stderr,
147*0Sstevel@tonic-gate 					    gettext("Can't find "
148*0Sstevel@tonic-gate 					    "environment variable\n"));
149*0Sstevel@tonic-gate 					exit(1);
150*0Sstevel@tonic-gate 				}
151*0Sstevel@tonic-gate 			}
152*0Sstevel@tonic-gate 			basedir = mstrdup(s);
153*0Sstevel@tonic-gate #ifdef DEBUG
154*0Sstevel@tonic-gate 			printf("basedir = %s\n", basedir);
155*0Sstevel@tonic-gate #endif /* DEBUG */
156*0Sstevel@tonic-gate 			continue;
157*0Sstevel@tonic-gate 		}
158*0Sstevel@tonic-gate 		if (strcmp(s, IGNORE) == 0) {
159*0Sstevel@tonic-gate #ifdef DEBUG
160*0Sstevel@tonic-gate 			printf("IGNORE - base_active = %d\n", base_active);
161*0Sstevel@tonic-gate #endif /* DEBUG */
162*0Sstevel@tonic-gate 			if (base_active) {
163*0Sstevel@tonic-gate 				/*
164*0Sstevel@tonic-gate 				 * Local IGNORE rule
165*0Sstevel@tonic-gate 				 */
166*0Sstevel@tonic-gate 				while ((s = lex(0))
167*0Sstevel@tonic-gate 				    != 0) {
168*0Sstevel@tonic-gate 					last_lign = add_item(last_lign, s,
169*0Sstevel@tonic-gate 					    def_lign_flags);
170*0Sstevel@tonic-gate 				}
171*0Sstevel@tonic-gate 			} else {
172*0Sstevel@tonic-gate 				/*
173*0Sstevel@tonic-gate 				 * Global IGNORE rule
174*0Sstevel@tonic-gate 				 */
175*0Sstevel@tonic-gate 				while ((s = lex(0)) != 0) {
176*0Sstevel@tonic-gate 					last_gign = add_item(last_gign, s,
177*0Sstevel@tonic-gate 					    def_gign_flags);
178*0Sstevel@tonic-gate 				}
179*0Sstevel@tonic-gate 			}
180*0Sstevel@tonic-gate 			continue;
181*0Sstevel@tonic-gate 		}
182*0Sstevel@tonic-gate 		if (strcmp(s, LIST) == 0) {
183*0Sstevel@tonic-gate #ifdef DEBUG
184*0Sstevel@tonic-gate 			printf("LIST\n");
185*0Sstevel@tonic-gate #endif /* DEBUG */
186*0Sstevel@tonic-gate 			if (!base_active) {
187*0Sstevel@tonic-gate 				fprintf(stderr,
188*0Sstevel@tonic-gate 				    gettext(
189*0Sstevel@tonic-gate 				    "cachefspack: skipping LIST command - "));
190*0Sstevel@tonic-gate 				fprintf(stderr,
191*0Sstevel@tonic-gate 				    gettext(" no active base\n"));
192*0Sstevel@tonic-gate 				continue;
193*0Sstevel@tonic-gate 			}
194*0Sstevel@tonic-gate 			while ((s = lex(0)) != 0) {
195*0Sstevel@tonic-gate 				last_list = add_item(last_list, s,
196*0Sstevel@tonic-gate 				    def_list_flags);
197*0Sstevel@tonic-gate 			}
198*0Sstevel@tonic-gate 			continue;
199*0Sstevel@tonic-gate 		}
200*0Sstevel@tonic-gate 		if (strcmp(s, VERSION) == 0) {
201*0Sstevel@tonic-gate 			sprintf(version, "%d.%d", VERMAJOR, VERMINOR);
202*0Sstevel@tonic-gate 			s = lex(0);
203*0Sstevel@tonic-gate 			if (s == (char *)0) {
204*0Sstevel@tonic-gate 				fprintf(stderr, gettext("cachefspack: "));
205*0Sstevel@tonic-gate 				fprintf(stderr, gettext("missing version\n"));
206*0Sstevel@tonic-gate 				fprintf(stderr, gettext("cachefspack: "));
207*0Sstevel@tonic-gate 				fprintf(stderr, gettext(
208*0Sstevel@tonic-gate 				    "version = %d.%d\n"), VERMAJOR, VERMINOR);
209*0Sstevel@tonic-gate 				exit(1);
210*0Sstevel@tonic-gate 			}
211*0Sstevel@tonic-gate 			if (strcmp(version, s) != 0) {
212*0Sstevel@tonic-gate 				fprintf(stderr, gettext(
213*0Sstevel@tonic-gate 				    "cachefspack: "));
214*0Sstevel@tonic-gate 				fprintf(stderr, gettext(
215*0Sstevel@tonic-gate 				    "WARNING - version of packing rules "));
216*0Sstevel@tonic-gate 				fprintf(stderr, gettext(
217*0Sstevel@tonic-gate 				    "does not match cachefspack version\n"));
218*0Sstevel@tonic-gate 				fprintf(stderr, gettext(
219*0Sstevel@tonic-gate 				    "version = %d.%d\n"), VERMAJOR, VERMINOR);
220*0Sstevel@tonic-gate 			}
221*0Sstevel@tonic-gate 		}
222*0Sstevel@tonic-gate 	}
223*0Sstevel@tonic-gate 	/*
224*0Sstevel@tonic-gate 	 * Tack local IGNORE strings to end of globals
225*0Sstevel@tonic-gate 	 */
226*0Sstevel@tonic-gate 	if (lign_hd.i_next != (struct item *)0) {
227*0Sstevel@tonic-gate 		last_gign->i_next = &lign_hd;
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 	do_base_dir(basedir, &list_hd, &gign_hd, rulefunc);
230*0Sstevel@tonic-gate }
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate struct item *
add_item(struct item * last_item,char * str,int flags)233*0Sstevel@tonic-gate add_item(struct item *last_item, char *str, int flags)
234*0Sstevel@tonic-gate {
235*0Sstevel@tonic-gate 	struct item * add_cmd_items();
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	if (*str == CMDCHAR) {
238*0Sstevel@tonic-gate 		last_item = add_cmd_items(last_item, &str[1], bang_list_flags);
239*0Sstevel@tonic-gate 	} else {
240*0Sstevel@tonic-gate 		last_item->i_next = (struct item *)mmalloc(
241*0Sstevel@tonic-gate 		    sizeof (struct item));
242*0Sstevel@tonic-gate 		last_item = last_item->i_next;
243*0Sstevel@tonic-gate 		last_item->i_str = mstrdup(str);
244*0Sstevel@tonic-gate 		last_item->i_flag = flags;
245*0Sstevel@tonic-gate 		last_item->i_next = (struct item *)0;
246*0Sstevel@tonic-gate 	}
247*0Sstevel@tonic-gate 	return (last_item);
248*0Sstevel@tonic-gate }
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate struct item *
add_cmd_items(struct item * last_item,char * str,int flags)251*0Sstevel@tonic-gate add_cmd_items(struct item *last_item, char *str, int flags)
252*0Sstevel@tonic-gate {
253*0Sstevel@tonic-gate 	FILE *fd;
254*0Sstevel@tonic-gate 	char inbuf[MAX_RULE_SZ];
255*0Sstevel@tonic-gate 	char *olddir = NULL;
256*0Sstevel@tonic-gate 	char *s;
257*0Sstevel@tonic-gate 	void getcmd(char *, char *);
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	if ((basedir != NULL) && (basedir[0] != '\0')) {
260*0Sstevel@tonic-gate 		olddir = getcwd(NULL, MAXPATHLEN + 1);
261*0Sstevel@tonic-gate 		if (olddir == NULL) {
262*0Sstevel@tonic-gate 			fprintf(stderr, gettext("cannot malloc buffer\n"));
263*0Sstevel@tonic-gate 			exit(1);
264*0Sstevel@tonic-gate 		}
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 		if (chdir(basedir) != 0) {
267*0Sstevel@tonic-gate 			fprintf(stderr, gettext("cannot chdir to %s: %s\n"),
268*0Sstevel@tonic-gate 			    basedir, strerror(errno));
269*0Sstevel@tonic-gate 			exit(1);
270*0Sstevel@tonic-gate 		}
271*0Sstevel@tonic-gate 	}
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	getcmd(str, inbuf);
274*0Sstevel@tonic-gate 	fd = popen(inbuf, "r");
275*0Sstevel@tonic-gate 	if (fd == NULL) {
276*0Sstevel@tonic-gate 		fprintf(stderr, gettext("cachefspack: LIST can't execute - "));
277*0Sstevel@tonic-gate 		fprintf(stderr, "%s\n", inbuf);
278*0Sstevel@tonic-gate 		exit(1);
279*0Sstevel@tonic-gate 	}
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	while (s = lex(fd)) {
282*0Sstevel@tonic-gate 		last_item = add_item(last_item, s, flags);
283*0Sstevel@tonic-gate 		while (s = lex(0)) {
284*0Sstevel@tonic-gate 			last_item = add_item(last_item, s, flags);
285*0Sstevel@tonic-gate 		}
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 	if (pclose(fd) < 0) {
288*0Sstevel@tonic-gate 		fprintf(stderr, gettext("cachefspack: can't close pipe\n"));
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	if (olddir != NULL) {
292*0Sstevel@tonic-gate 		if (chdir(olddir) != 0) {
293*0Sstevel@tonic-gate 			fprintf(stderr, gettext("cannot return to %s: %s\n"),
294*0Sstevel@tonic-gate 			    olddir, strerror(errno));
295*0Sstevel@tonic-gate 			exit(1);
296*0Sstevel@tonic-gate 		}
297*0Sstevel@tonic-gate 		free(olddir);
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	return (last_item);
301*0Sstevel@tonic-gate }
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate void
getcmd(char * str,char * buf)304*0Sstevel@tonic-gate getcmd(char *str, char *buf)
305*0Sstevel@tonic-gate {
306*0Sstevel@tonic-gate 	char *s;
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	strcpy(buf, str);
309*0Sstevel@tonic-gate 	strcat(buf, " ");
310*0Sstevel@tonic-gate 	while (s = lex(0)) {
311*0Sstevel@tonic-gate 		strcat(buf, s);
312*0Sstevel@tonic-gate 		strcat(buf, " ");
313*0Sstevel@tonic-gate 	}
314*0Sstevel@tonic-gate #ifdef DEBUG
315*0Sstevel@tonic-gate 	printf("getcmd: cmd = %s\n", buf);
316*0Sstevel@tonic-gate #endif /* DEBUG */
317*0Sstevel@tonic-gate }
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate /*
320*0Sstevel@tonic-gate  * routine:
321*0Sstevel@tonic-gate  *	lex
322*0Sstevel@tonic-gate  *
323*0Sstevel@tonic-gate  * purpose:
324*0Sstevel@tonic-gate  *	my own version of strtok that handles quoting and escaping
325*0Sstevel@tonic-gate  *
326*0Sstevel@tonic-gate  * parameters:
327*0Sstevel@tonic-gate  *	string to be lexed (or 0 for same string)
328*0Sstevel@tonic-gate  *
329*0Sstevel@tonic-gate  * returns:
330*0Sstevel@tonic-gate  *	pointer to next token
331*0Sstevel@tonic-gate  *
332*0Sstevel@tonic-gate  * notes:
333*0Sstevel@tonic-gate  *	this routine makes no changes to the string it is passed,
334*0Sstevel@tonic-gate  *	copying tokens into a static buffer.
335*0Sstevel@tonic-gate  */
336*0Sstevel@tonic-gate char *
lex(FILE * fd)337*0Sstevel@tonic-gate lex(FILE *fd)
338*0Sstevel@tonic-gate {	char c, delim;
339*0Sstevel@tonic-gate 	char *p;
340*0Sstevel@tonic-gate 	const char *s;
341*0Sstevel@tonic-gate 	static const char *savep = 0;
342*0Sstevel@tonic-gate 	static char namebuf[MAX_RULE_SZ];
343*0Sstevel@tonic-gate 	static char inbuf[MAX_RULE_SZ];
344*0Sstevel@tonic-gate 	int len, space_left;
345*0Sstevel@tonic-gate 	char *err;
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	/*
348*0Sstevel@tonic-gate 	 * if the file descriptor is non-zero read a new command. Otherwise
349*0Sstevel@tonic-gate 	 * get fields from current line.
350*0Sstevel@tonic-gate 	 */
351*0Sstevel@tonic-gate 	if (fd != 0) {
352*0Sstevel@tonic-gate 		len = 0;
353*0Sstevel@tonic-gate 		space_left = sizeof (inbuf);
354*0Sstevel@tonic-gate 		while ((err = fgets(&inbuf[len], space_left, fd)) != NULL) {
355*0Sstevel@tonic-gate 			len = strlen(inbuf);
356*0Sstevel@tonic-gate 			if (len == 1) {
357*0Sstevel@tonic-gate 				/*
358*0Sstevel@tonic-gate 				 * must be a blank line starting command.
359*0Sstevel@tonic-gate 				 * If a blank line occurs after the start of
360*0Sstevel@tonic-gate 				 * a command, blanks will be included in the
361*0Sstevel@tonic-gate 				 * command.
362*0Sstevel@tonic-gate 				 */
363*0Sstevel@tonic-gate 				len = 0;
364*0Sstevel@tonic-gate 				continue;
365*0Sstevel@tonic-gate 			}
366*0Sstevel@tonic-gate 			len -= 2;
367*0Sstevel@tonic-gate 			space_left -= len;
368*0Sstevel@tonic-gate 			s = (char *)((int)inbuf + len);
369*0Sstevel@tonic-gate 			/*
370*0Sstevel@tonic-gate 			 * Continuation character
371*0Sstevel@tonic-gate 			 */
372*0Sstevel@tonic-gate 			if (strcmp(s, "\\\n") == 0) {
373*0Sstevel@tonic-gate 				continue;
374*0Sstevel@tonic-gate 			}
375*0Sstevel@tonic-gate 			break;
376*0Sstevel@tonic-gate 		}
377*0Sstevel@tonic-gate 		if (err == NULL) {
378*0Sstevel@tonic-gate 			return (err);
379*0Sstevel@tonic-gate 		}
380*0Sstevel@tonic-gate 		s = inbuf;
381*0Sstevel@tonic-gate 	} else {
382*0Sstevel@tonic-gate 		if (savep == 0)
383*0Sstevel@tonic-gate 			return (0);
384*0Sstevel@tonic-gate 		s = savep;
385*0Sstevel@tonic-gate 	}
386*0Sstevel@tonic-gate 	savep = 0;
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	/* skip over leading white space	*/
389*0Sstevel@tonic-gate 	while (isspace(*s))
390*0Sstevel@tonic-gate 		s++;
391*0Sstevel@tonic-gate 	if (*s == 0) {
392*0Sstevel@tonic-gate 		return (0);
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	/* see if this is a quoted string	*/
396*0Sstevel@tonic-gate 	c = *s;
397*0Sstevel@tonic-gate 	if (c == '\'' || c == '"') {
398*0Sstevel@tonic-gate 		delim = c;
399*0Sstevel@tonic-gate 		s++;
400*0Sstevel@tonic-gate 	} else
401*0Sstevel@tonic-gate 		delim = 0;
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	/* copy the token into the buffer	*/
404*0Sstevel@tonic-gate 	for (p = namebuf; (c = *s) != 0; s++) {
405*0Sstevel@tonic-gate 		if ((p - namebuf) >= sizeof (namebuf)) {
406*0Sstevel@tonic-gate 			savep = 0;
407*0Sstevel@tonic-gate 			return (0);
408*0Sstevel@tonic-gate 		}
409*0Sstevel@tonic-gate 		/* literal escape		*/
410*0Sstevel@tonic-gate 		if (c == '\\') {
411*0Sstevel@tonic-gate 			s++;
412*0Sstevel@tonic-gate 			*p++ = *s;
413*0Sstevel@tonic-gate 			continue;
414*0Sstevel@tonic-gate 		}
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 		/* closing delimiter		*/
417*0Sstevel@tonic-gate 		if (c == delim) {
418*0Sstevel@tonic-gate 			s++;
419*0Sstevel@tonic-gate 			break;
420*0Sstevel@tonic-gate 		}
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 		/* delimiting white space	*/
423*0Sstevel@tonic-gate 		if (delim == 0 && isspace(c))
424*0Sstevel@tonic-gate 			break;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 		/* ordinary characters		*/
427*0Sstevel@tonic-gate 		*p++ = *s;
428*0Sstevel@tonic-gate 	}
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	/* remember where we left off		*/
432*0Sstevel@tonic-gate 	savep = *s ? s : 0;
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	/* null terminate and return the buffer	*/
435*0Sstevel@tonic-gate 	*p = 0;
436*0Sstevel@tonic-gate 	return (namebuf);
437*0Sstevel@tonic-gate }
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate char *
mk_base_dir(char * path,char * linkpath)440*0Sstevel@tonic-gate mk_base_dir(char *path, char *linkpath)
441*0Sstevel@tonic-gate {
442*0Sstevel@tonic-gate 	static char pathb[MAXPATHLEN];
443*0Sstevel@tonic-gate 	char *dnam;
444*0Sstevel@tonic-gate 	char *get_dirname(char *);
445*0Sstevel@tonic-gate 	int len;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	/*
448*0Sstevel@tonic-gate 	 * absolute path name
449*0Sstevel@tonic-gate 	 */
450*0Sstevel@tonic-gate 	if (*linkpath == '/') {
451*0Sstevel@tonic-gate 		strcpy(pathb, linkpath);
452*0Sstevel@tonic-gate 	} else {
453*0Sstevel@tonic-gate 		/*
454*0Sstevel@tonic-gate 		 * relative path
455*0Sstevel@tonic-gate 		 */
456*0Sstevel@tonic-gate 		dnam = get_dirname(path);
457*0Sstevel@tonic-gate 		if (dnam == (char *)0) {
458*0Sstevel@tonic-gate 			return ((char *) 0);
459*0Sstevel@tonic-gate 		}
460*0Sstevel@tonic-gate 		strcpy(pathb, dnam);
461*0Sstevel@tonic-gate 		len = strlen(pathb);
462*0Sstevel@tonic-gate 		if (len == 0)
463*0Sstevel@tonic-gate 			return (pathb);
464*0Sstevel@tonic-gate 		if (pathb[len-1] != '/')
465*0Sstevel@tonic-gate 		    strcat(pathb, "/");
466*0Sstevel@tonic-gate 		if (strncmp(linkpath, "../", 3) == 0) {
467*0Sstevel@tonic-gate 			/*
468*0Sstevel@tonic-gate 			 * path is relative to directory containing sym link
469*0Sstevel@tonic-gate 			 * remove "../" from beginning of linkpath
470*0Sstevel@tonic-gate 			 */
471*0Sstevel@tonic-gate 			strcat(pathb, &linkpath[3]);
472*0Sstevel@tonic-gate 		} else {
473*0Sstevel@tonic-gate 			/*
474*0Sstevel@tonic-gate 			 * path is relative to directory containing sym link
475*0Sstevel@tonic-gate 			 */
476*0Sstevel@tonic-gate 			strcat(pathb, linkpath);
477*0Sstevel@tonic-gate 		}
478*0Sstevel@tonic-gate 	}
479*0Sstevel@tonic-gate 	return (pathb);
480*0Sstevel@tonic-gate }
481