xref: /onnv-gate/usr/src/cmd/fs.d/autofs/auto_subr.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) 1988-1999 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 <ctype.h>
30*0Sstevel@tonic-gate #include <stdio.h>
31*0Sstevel@tonic-gate #include <stdlib.h>
32*0Sstevel@tonic-gate #include <unistd.h>
33*0Sstevel@tonic-gate #include <locale.h>
34*0Sstevel@tonic-gate #include <syslog.h>
35*0Sstevel@tonic-gate #include <errno.h>
36*0Sstevel@tonic-gate #include <string.h>
37*0Sstevel@tonic-gate #include <stdarg.h>
38*0Sstevel@tonic-gate #include <dirent.h>
39*0Sstevel@tonic-gate #include <thread.h>
40*0Sstevel@tonic-gate #include <sys/param.h>
41*0Sstevel@tonic-gate #include <sys/time.h>
42*0Sstevel@tonic-gate #include <sys/vfs.h>
43*0Sstevel@tonic-gate #include <sys/types.h>
44*0Sstevel@tonic-gate #include <sys/stat.h>
45*0Sstevel@tonic-gate #include <sys/mnttab.h>
46*0Sstevel@tonic-gate #include <sys/mntent.h>
47*0Sstevel@tonic-gate #include <sys/mount.h>
48*0Sstevel@tonic-gate #include <sys/signal.h>
49*0Sstevel@tonic-gate #include <sys/utsname.h>
50*0Sstevel@tonic-gate #include <sys/systeminfo.h>
51*0Sstevel@tonic-gate #include <sys/tiuser.h>
52*0Sstevel@tonic-gate #include <sys/utsname.h>
53*0Sstevel@tonic-gate #include <rpc/rpc.h>
54*0Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h>
55*0Sstevel@tonic-gate #include <assert.h>
56*0Sstevel@tonic-gate #include "automount.h"
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate static char *check_hier(char *);
59*0Sstevel@tonic-gate static int natisa(char *, size_t);
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate struct mntlist *current_mounts;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate static bool_t nodirect_map = FALSE;
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate void
66*0Sstevel@tonic-gate dirinit(char *mntpnt, char *map, char *opts, int direct, char **stack,
67*0Sstevel@tonic-gate 	char ***stkptr)
68*0Sstevel@tonic-gate {
69*0Sstevel@tonic-gate 	struct autodir *dir;
70*0Sstevel@tonic-gate 	char *p;
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate 	if (strcmp(map, "-null") == 0) {
73*0Sstevel@tonic-gate 		if (strcmp(mntpnt, "/-") == 0)
74*0Sstevel@tonic-gate 			nodirect_map = TRUE;
75*0Sstevel@tonic-gate 		goto enter;
76*0Sstevel@tonic-gate 	}
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	p = mntpnt + (strlen(mntpnt) - 1);
79*0Sstevel@tonic-gate 	if (*p == '/')
80*0Sstevel@tonic-gate 		*p = '\0';	/* trim trailing / */
81*0Sstevel@tonic-gate 	if (*mntpnt != '/') {
82*0Sstevel@tonic-gate 		pr_msg("dir %s must start with '/'", mntpnt);
83*0Sstevel@tonic-gate 		return;
84*0Sstevel@tonic-gate 	}
85*0Sstevel@tonic-gate 	if (p = check_hier(mntpnt)) {
86*0Sstevel@tonic-gate 		pr_msg("hierarchical mountpoint: %s and %s",
87*0Sstevel@tonic-gate 			p, mntpnt);
88*0Sstevel@tonic-gate 		return;
89*0Sstevel@tonic-gate 	}
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	/*
92*0Sstevel@tonic-gate 	 * If it's a direct map then call dirinit
93*0Sstevel@tonic-gate 	 * for every map entry.
94*0Sstevel@tonic-gate 	 */
95*0Sstevel@tonic-gate 	if ((strcmp(mntpnt, "/-") == 0) && !(nodirect_map)) {
96*0Sstevel@tonic-gate 		(void) loaddirect_map(map, map, opts, stack, stkptr);
97*0Sstevel@tonic-gate 		return;
98*0Sstevel@tonic-gate 	}
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate enter:
101*0Sstevel@tonic-gate 	dir = (struct autodir *)malloc(sizeof (*dir));
102*0Sstevel@tonic-gate 	if (dir == NULL)
103*0Sstevel@tonic-gate 		goto alloc_failed;
104*0Sstevel@tonic-gate 	dir->dir_name = strdup(mntpnt);
105*0Sstevel@tonic-gate 	if (dir->dir_name == NULL)
106*0Sstevel@tonic-gate 		goto alloc_failed;
107*0Sstevel@tonic-gate 	dir->dir_map = strdup(map);
108*0Sstevel@tonic-gate 	if (dir->dir_map == NULL)
109*0Sstevel@tonic-gate 		goto alloc_failed;
110*0Sstevel@tonic-gate 	dir->dir_opts = strdup(opts);
111*0Sstevel@tonic-gate 	if (dir->dir_opts == NULL)
112*0Sstevel@tonic-gate 		goto alloc_failed;
113*0Sstevel@tonic-gate 	dir->dir_direct = direct;
114*0Sstevel@tonic-gate 	dir->dir_remount = 0;
115*0Sstevel@tonic-gate 	dir->dir_next = NULL;
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	/*
118*0Sstevel@tonic-gate 	 * Append to dir chain
119*0Sstevel@tonic-gate 	 */
120*0Sstevel@tonic-gate 	if (dir_head == NULL)
121*0Sstevel@tonic-gate 		dir_head = dir;
122*0Sstevel@tonic-gate 	else
123*0Sstevel@tonic-gate 		dir_tail->dir_next = dir;
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	dir->dir_prev = dir_tail;
126*0Sstevel@tonic-gate 	dir_tail = dir;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	return;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate alloc_failed:
131*0Sstevel@tonic-gate 	if (dir != NULL) {
132*0Sstevel@tonic-gate 		if (dir->dir_opts)
133*0Sstevel@tonic-gate 			free(dir->dir_opts);
134*0Sstevel@tonic-gate 		if (dir->dir_map)
135*0Sstevel@tonic-gate 			free(dir->dir_map);
136*0Sstevel@tonic-gate 		if (dir->dir_name)
137*0Sstevel@tonic-gate 			free(dir->dir_name);
138*0Sstevel@tonic-gate 		free(dir);
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate 	pr_msg("dirinit: memory allocation failed");
141*0Sstevel@tonic-gate }
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate /*
144*0Sstevel@tonic-gate  *  Check whether the mount point is a
145*0Sstevel@tonic-gate  *  subdirectory or a parent directory
146*0Sstevel@tonic-gate  *  of any previously mounted automount
147*0Sstevel@tonic-gate  *  mount point.
148*0Sstevel@tonic-gate  */
149*0Sstevel@tonic-gate static char *
150*0Sstevel@tonic-gate check_hier(mntpnt)
151*0Sstevel@tonic-gate 	char *mntpnt;
152*0Sstevel@tonic-gate {
153*0Sstevel@tonic-gate 	register struct autodir *dir;
154*0Sstevel@tonic-gate 	register char *p, *q;
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	for (dir = dir_head; dir; dir = dir->dir_next) {
157*0Sstevel@tonic-gate 		p = dir->dir_name;
158*0Sstevel@tonic-gate 		q = mntpnt;
159*0Sstevel@tonic-gate 		for (; *p == *q; p++, q++)
160*0Sstevel@tonic-gate 			if (*p == '\0')
161*0Sstevel@tonic-gate 				break;
162*0Sstevel@tonic-gate 		if (*p == '/' && *q == '\0')
163*0Sstevel@tonic-gate 			return (dir->dir_name);
164*0Sstevel@tonic-gate 		if (*p == '\0' && *q == '/')
165*0Sstevel@tonic-gate 			return (dir->dir_name);
166*0Sstevel@tonic-gate 		if (*p == '\0' && *q == '\0')
167*0Sstevel@tonic-gate 			return (NULL);
168*0Sstevel@tonic-gate 	}
169*0Sstevel@tonic-gate 	return (NULL);	/* it's not a subdir or parent */
170*0Sstevel@tonic-gate }
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate /*
173*0Sstevel@tonic-gate  * Gets the next token from the string "p" and copies
174*0Sstevel@tonic-gate  * it into "w".  Both "wq" and "w" are quote vectors
175*0Sstevel@tonic-gate  * for "w" and "p".  Delim is the character to be used
176*0Sstevel@tonic-gate  * as a delimiter for the scan.  A space means "whitespace".
177*0Sstevel@tonic-gate  * The call to getword must provide buffers w and wq of size at
178*0Sstevel@tonic-gate  * least wordsz. getword() will pass strings of maximum length
179*0Sstevel@tonic-gate  * (wordsz-1), since it needs to null terminate the string.
180*0Sstevel@tonic-gate  * Returns 0 on ok and -1 on error.
181*0Sstevel@tonic-gate  */
182*0Sstevel@tonic-gate int
183*0Sstevel@tonic-gate getword(char *w, char *wq, char **p, char **pq, char delim, int wordsz)
184*0Sstevel@tonic-gate {
185*0Sstevel@tonic-gate 	char *tmp = w;
186*0Sstevel@tonic-gate 	char *tmpq = wq;
187*0Sstevel@tonic-gate 	int count = wordsz;
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	if (wordsz <= 0) {
190*0Sstevel@tonic-gate 		if (verbose)
191*0Sstevel@tonic-gate 			syslog(LOG_ERR,
192*0Sstevel@tonic-gate 			"getword: input word size %d must be > 0", wordsz);
193*0Sstevel@tonic-gate 		return (-1);
194*0Sstevel@tonic-gate 	}
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	while ((delim == ' ' ? isspace(**p) : **p == delim) && **pq == ' ')
197*0Sstevel@tonic-gate 		(*p)++, (*pq)++;
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	while (**p &&
200*0Sstevel@tonic-gate 		!((delim == ' ' ? isspace(**p) : **p == delim) &&
201*0Sstevel@tonic-gate 			**pq == ' ')) {
202*0Sstevel@tonic-gate 		if (--count <= 0) {
203*0Sstevel@tonic-gate 			*tmp = '\0';
204*0Sstevel@tonic-gate 			*tmpq = '\0';
205*0Sstevel@tonic-gate 			syslog(LOG_ERR,
206*0Sstevel@tonic-gate 			"maximum word length (%d) exceeded", wordsz);
207*0Sstevel@tonic-gate 			return (-1);
208*0Sstevel@tonic-gate 		}
209*0Sstevel@tonic-gate 		*w++  = *(*p)++;
210*0Sstevel@tonic-gate 		*wq++ = *(*pq)++;
211*0Sstevel@tonic-gate 	}
212*0Sstevel@tonic-gate 	*w  = '\0';
213*0Sstevel@tonic-gate 	*wq = '\0';
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	return (0);
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate /*
219*0Sstevel@tonic-gate  * get_line attempts to get a line from the map, upto LINESZ. A line in
220*0Sstevel@tonic-gate  * the map is a concatenation of lines if the continuation symbol '\'
221*0Sstevel@tonic-gate  * is used at the end of the line. Returns line on success, a NULL on
222*0Sstevel@tonic-gate  * EOF, and an empty string on lines > linesz.
223*0Sstevel@tonic-gate  */
224*0Sstevel@tonic-gate char *
225*0Sstevel@tonic-gate get_line(FILE *fp, char *map, char *line, int linesz)
226*0Sstevel@tonic-gate {
227*0Sstevel@tonic-gate 	register char *p = line;
228*0Sstevel@tonic-gate 	register int len;
229*0Sstevel@tonic-gate 	int excess = 0;
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	*p = '\0';
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	for (;;) {
234*0Sstevel@tonic-gate 		if (fgets(p, linesz - (p-line), fp) == NULL) {
235*0Sstevel@tonic-gate 			return (*line ? line : NULL);	/* EOF */
236*0Sstevel@tonic-gate 		}
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 		len = strlen(line);
239*0Sstevel@tonic-gate 		if (len <= 0) {
240*0Sstevel@tonic-gate 			p = line;
241*0Sstevel@tonic-gate 			continue;
242*0Sstevel@tonic-gate 		}
243*0Sstevel@tonic-gate 		p = &line[len - 1];
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 		/*
246*0Sstevel@tonic-gate 		 * Is input line too long?
247*0Sstevel@tonic-gate 		 */
248*0Sstevel@tonic-gate 		if (*p != '\n') {
249*0Sstevel@tonic-gate 			excess = 1;
250*0Sstevel@tonic-gate 			/*
251*0Sstevel@tonic-gate 			 * Perhaps last char read was '\'. Reinsert it
252*0Sstevel@tonic-gate 			 * into the stream to ease the parsing when we
253*0Sstevel@tonic-gate 			 * read the rest of the line to discard.
254*0Sstevel@tonic-gate 			 */
255*0Sstevel@tonic-gate 			(void) ungetc(*p, fp);
256*0Sstevel@tonic-gate 			break;
257*0Sstevel@tonic-gate 		}
258*0Sstevel@tonic-gate trim:
259*0Sstevel@tonic-gate 		/* trim trailing white space */
260*0Sstevel@tonic-gate 		while (p >= line && isspace(*(uchar_t *)p))
261*0Sstevel@tonic-gate 			*p-- = '\0';
262*0Sstevel@tonic-gate 		if (p < line) {			/* empty line */
263*0Sstevel@tonic-gate 			p = line;
264*0Sstevel@tonic-gate 			continue;
265*0Sstevel@tonic-gate 		}
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 		if (*p == '\\') {		/* continuation */
268*0Sstevel@tonic-gate 			*p = '\0';
269*0Sstevel@tonic-gate 			continue;
270*0Sstevel@tonic-gate 		}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 		/*
273*0Sstevel@tonic-gate 		 * Ignore comments. Comments start with '#'
274*0Sstevel@tonic-gate 		 * which must be preceded by a whitespace, unless
275*0Sstevel@tonic-gate 		 * if '#' is the first character in the line.
276*0Sstevel@tonic-gate 		 */
277*0Sstevel@tonic-gate 		p = line;
278*0Sstevel@tonic-gate 		while (p = strchr(p, '#')) {
279*0Sstevel@tonic-gate 			if (p == line || isspace(*(p-1))) {
280*0Sstevel@tonic-gate 				*p-- = '\0';
281*0Sstevel@tonic-gate 				goto trim;
282*0Sstevel@tonic-gate 			}
283*0Sstevel@tonic-gate 			p++;
284*0Sstevel@tonic-gate 		}
285*0Sstevel@tonic-gate 		break;
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 	if (excess) {
288*0Sstevel@tonic-gate 		int c;
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 		/*
291*0Sstevel@tonic-gate 		 * discard rest of line and return an empty string.
292*0Sstevel@tonic-gate 		 * done to set the stream to the correct place when
293*0Sstevel@tonic-gate 		 * we are done with this line.
294*0Sstevel@tonic-gate 		 */
295*0Sstevel@tonic-gate 		while ((c = getc(fp)) != EOF) {
296*0Sstevel@tonic-gate 			*p = c;
297*0Sstevel@tonic-gate 			if (*p == '\n')		/* end of the long line */
298*0Sstevel@tonic-gate 				break;
299*0Sstevel@tonic-gate 			else if (*p == '\\') {		/* continuation */
300*0Sstevel@tonic-gate 				if (getc(fp) == EOF)	/* ignore next char */
301*0Sstevel@tonic-gate 					break;
302*0Sstevel@tonic-gate 			}
303*0Sstevel@tonic-gate 		}
304*0Sstevel@tonic-gate 		syslog(LOG_ERR,
305*0Sstevel@tonic-gate 			"map %s: line too long (max %d chars)",
306*0Sstevel@tonic-gate 			map, linesz-1);
307*0Sstevel@tonic-gate 		*line = '\0';
308*0Sstevel@tonic-gate 	}
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	return (line);
311*0Sstevel@tonic-gate }
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate /*
314*0Sstevel@tonic-gate  * Gets the retry=n entry from opts.
315*0Sstevel@tonic-gate  * Returns 0 if retry=n is not present in option string,
316*0Sstevel@tonic-gate  * retry=n is invalid, or when option string is NULL.
317*0Sstevel@tonic-gate  */
318*0Sstevel@tonic-gate int
319*0Sstevel@tonic-gate get_retry(char *opts)
320*0Sstevel@tonic-gate {
321*0Sstevel@tonic-gate 	int retry = 0;
322*0Sstevel@tonic-gate 	char buf[MAXOPTSLEN];
323*0Sstevel@tonic-gate 	char *p, *pb, *lasts;
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	if (opts == NULL)
326*0Sstevel@tonic-gate 		return (retry);
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	(void) strcpy(buf, opts);
329*0Sstevel@tonic-gate 	pb = buf;
330*0Sstevel@tonic-gate 	while (p = (char *)strtok_r(pb, ",", &lasts)) {
331*0Sstevel@tonic-gate 		pb = NULL;
332*0Sstevel@tonic-gate 		if (strncmp(p, "retry=", 6) == 0)
333*0Sstevel@tonic-gate 			retry = atoi(p+6);
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 	return (retry > 0 ? retry : 0);
336*0Sstevel@tonic-gate }
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate /*
339*0Sstevel@tonic-gate  * Returns zero if "opt" is found in mnt->mnt_opts, setting
340*0Sstevel@tonic-gate  * *sval to whatever follows the equal sign after "opt".
341*0Sstevel@tonic-gate  * str_opt allocates a string long enough to store the value of
342*0Sstevel@tonic-gate  * "opt" plus a terminating null character and returns it as *sval.
343*0Sstevel@tonic-gate  * It is the responsability of the caller to deallocate *sval.
344*0Sstevel@tonic-gate  * *sval will be equal to NULL upon return if either "opt=" is not found,
345*0Sstevel@tonic-gate  * or "opt=" has no value associated with it.
346*0Sstevel@tonic-gate  *
347*0Sstevel@tonic-gate  * stropt will return -1 on error.
348*0Sstevel@tonic-gate  */
349*0Sstevel@tonic-gate int
350*0Sstevel@tonic-gate str_opt(struct mnttab *mnt, char *opt, char **sval)
351*0Sstevel@tonic-gate {
352*0Sstevel@tonic-gate 	char *str, *comma;
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	/*
355*0Sstevel@tonic-gate 	 * is "opt" in the options field?
356*0Sstevel@tonic-gate 	 */
357*0Sstevel@tonic-gate 	if (str = hasmntopt(mnt, opt)) {
358*0Sstevel@tonic-gate 		str += strlen(opt);
359*0Sstevel@tonic-gate 		if (*str++ != '=' ||
360*0Sstevel@tonic-gate 		    (*str == ',' || *str == '\0')) {
361*0Sstevel@tonic-gate 			syslog(LOG_ERR, "Bad option field");
362*0Sstevel@tonic-gate 			return (-1);
363*0Sstevel@tonic-gate 		}
364*0Sstevel@tonic-gate 		comma = strchr(str, ',');
365*0Sstevel@tonic-gate 		if (comma != NULL)
366*0Sstevel@tonic-gate 			*comma = '\0';
367*0Sstevel@tonic-gate 		*sval = strdup(str);
368*0Sstevel@tonic-gate 		if (comma != NULL)
369*0Sstevel@tonic-gate 			*comma = ',';
370*0Sstevel@tonic-gate 		if (*sval == NULL)
371*0Sstevel@tonic-gate 			return (-1);
372*0Sstevel@tonic-gate 	} else
373*0Sstevel@tonic-gate 		*sval = NULL;
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	return (0);
376*0Sstevel@tonic-gate }
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate /*
379*0Sstevel@tonic-gate  * Performs text expansions in the string "pline".
380*0Sstevel@tonic-gate  * "plineq" is the quote vector for "pline".
381*0Sstevel@tonic-gate  * An identifier prefixed by "$" is replaced by the
382*0Sstevel@tonic-gate  * corresponding environment variable string.  A "&"
383*0Sstevel@tonic-gate  * is replaced by the key string for the map entry.
384*0Sstevel@tonic-gate  *
385*0Sstevel@tonic-gate  * This routine will return an error (non-zero) if *size* would be
386*0Sstevel@tonic-gate  * exceeded after expansion, indicating that the macro_expand failed.
387*0Sstevel@tonic-gate  * This is to prevent writing past the end of pline and plineq.
388*0Sstevel@tonic-gate  * Both pline and plineq are left untouched in such error case.
389*0Sstevel@tonic-gate  */
390*0Sstevel@tonic-gate int
391*0Sstevel@tonic-gate macro_expand(key, pline, plineq, size)
392*0Sstevel@tonic-gate 	char *key, *pline, *plineq;
393*0Sstevel@tonic-gate 	int size;
394*0Sstevel@tonic-gate {
395*0Sstevel@tonic-gate 	register char *p,  *q;
396*0Sstevel@tonic-gate 	register char *bp, *bq;
397*0Sstevel@tonic-gate 	register char *s;
398*0Sstevel@tonic-gate 	char buffp[LINESZ], buffq[LINESZ];
399*0Sstevel@tonic-gate 	char namebuf[64], *pn;
400*0Sstevel@tonic-gate 	int expand = 0;
401*0Sstevel@tonic-gate 	struct utsname name;
402*0Sstevel@tonic-gate 	char isaname[64];
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	p = pline;  q = plineq;
405*0Sstevel@tonic-gate 	bp = buffp; bq = buffq;
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	while (*p) {
408*0Sstevel@tonic-gate 		if (*p == '&' && *q == ' ') {	/* insert key */
409*0Sstevel@tonic-gate 			/*
410*0Sstevel@tonic-gate 			 * make sure we don't overflow buffer
411*0Sstevel@tonic-gate 			 */
412*0Sstevel@tonic-gate 			if ((int)((bp - buffp) + strlen(key)) < size) {
413*0Sstevel@tonic-gate 				for (s = key; *s; s++) {
414*0Sstevel@tonic-gate 					*bp++ = *s;
415*0Sstevel@tonic-gate 					*bq++ = ' ';
416*0Sstevel@tonic-gate 				}
417*0Sstevel@tonic-gate 				expand++;
418*0Sstevel@tonic-gate 				p++; q++;
419*0Sstevel@tonic-gate 				continue;
420*0Sstevel@tonic-gate 			} else {
421*0Sstevel@tonic-gate 				/*
422*0Sstevel@tonic-gate 				 * line too long...
423*0Sstevel@tonic-gate 				 */
424*0Sstevel@tonic-gate 				return (1);
425*0Sstevel@tonic-gate 			}
426*0Sstevel@tonic-gate 		}
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 		if (*p == '$' && *q == ' ') {	/* insert env var */
429*0Sstevel@tonic-gate 			p++; q++;
430*0Sstevel@tonic-gate 			pn = namebuf;
431*0Sstevel@tonic-gate 			if (*p == '{') {
432*0Sstevel@tonic-gate 				p++; q++;
433*0Sstevel@tonic-gate 				while (*p && *p != '}') {
434*0Sstevel@tonic-gate 					*pn++ = *p++;
435*0Sstevel@tonic-gate 					q++;
436*0Sstevel@tonic-gate 				}
437*0Sstevel@tonic-gate 				if (*p) {
438*0Sstevel@tonic-gate 					p++; q++;
439*0Sstevel@tonic-gate 				}
440*0Sstevel@tonic-gate 			} else {
441*0Sstevel@tonic-gate 				while (*p && (*p == '_' || isalnum(*p))) {
442*0Sstevel@tonic-gate 					*pn++ = *p++;
443*0Sstevel@tonic-gate 					q++;
444*0Sstevel@tonic-gate 				}
445*0Sstevel@tonic-gate 			}
446*0Sstevel@tonic-gate 			*pn = '\0';
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 			s = getenv(namebuf);
449*0Sstevel@tonic-gate 			if (!s) {
450*0Sstevel@tonic-gate 				/* not found in env */
451*0Sstevel@tonic-gate 				if (strcmp(namebuf, "HOST") == 0) {
452*0Sstevel@tonic-gate 					(void) uname(&name);
453*0Sstevel@tonic-gate 					s = name.nodename;
454*0Sstevel@tonic-gate 				} else if (strcmp(namebuf, "OSREL") == 0) {
455*0Sstevel@tonic-gate 					(void) uname(&name);
456*0Sstevel@tonic-gate 					s = name.release;
457*0Sstevel@tonic-gate 				} else if (strcmp(namebuf, "OSNAME") == 0) {
458*0Sstevel@tonic-gate 					(void) uname(&name);
459*0Sstevel@tonic-gate 					s = name.sysname;
460*0Sstevel@tonic-gate 				} else if (strcmp(namebuf, "OSVERS") == 0) {
461*0Sstevel@tonic-gate 					(void) uname(&name);
462*0Sstevel@tonic-gate 					s = name.version;
463*0Sstevel@tonic-gate 				} else if (strcmp(namebuf, "NATISA") == 0) {
464*0Sstevel@tonic-gate 					if (natisa(isaname, sizeof (isaname)))
465*0Sstevel@tonic-gate 						s = isaname;
466*0Sstevel@tonic-gate 				}
467*0Sstevel@tonic-gate 			}
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 			if (s) {
470*0Sstevel@tonic-gate 				if ((int)((bp - buffp) + strlen(s)) < size) {
471*0Sstevel@tonic-gate 					while (*s) {
472*0Sstevel@tonic-gate 						*bp++ = *s++;
473*0Sstevel@tonic-gate 						*bq++ = ' ';
474*0Sstevel@tonic-gate 					}
475*0Sstevel@tonic-gate 				} else {
476*0Sstevel@tonic-gate 					/*
477*0Sstevel@tonic-gate 					 * line too long...
478*0Sstevel@tonic-gate 					 */
479*0Sstevel@tonic-gate 					return (1);
480*0Sstevel@tonic-gate 				}
481*0Sstevel@tonic-gate 			}
482*0Sstevel@tonic-gate 			expand++;
483*0Sstevel@tonic-gate 			continue;
484*0Sstevel@tonic-gate 		}
485*0Sstevel@tonic-gate 		/*
486*0Sstevel@tonic-gate 		 * Since buffp needs to be null terminated, we need to
487*0Sstevel@tonic-gate 		 * check that there's still room in the buffer to
488*0Sstevel@tonic-gate 		 * place at least two more characters, *p and the
489*0Sstevel@tonic-gate 		 * terminating null.
490*0Sstevel@tonic-gate 		 */
491*0Sstevel@tonic-gate 		if (bp - buffp == size - 1) {
492*0Sstevel@tonic-gate 			/*
493*0Sstevel@tonic-gate 			 * There was not enough room for at least two more
494*0Sstevel@tonic-gate 			 * characters, return with an error.
495*0Sstevel@tonic-gate 			 */
496*0Sstevel@tonic-gate 			return (1);
497*0Sstevel@tonic-gate 		}
498*0Sstevel@tonic-gate 		/*
499*0Sstevel@tonic-gate 		 * The total number of characters so far better be less
500*0Sstevel@tonic-gate 		 * than the size of buffer passed in.
501*0Sstevel@tonic-gate 		 */
502*0Sstevel@tonic-gate 		*bp++ = *p++;
503*0Sstevel@tonic-gate 		*bq++ = *q++;
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	}
506*0Sstevel@tonic-gate 	if (!expand)
507*0Sstevel@tonic-gate 		return (0);
508*0Sstevel@tonic-gate 	*bp = '\0';
509*0Sstevel@tonic-gate 	*bq = '\0';
510*0Sstevel@tonic-gate 	/*
511*0Sstevel@tonic-gate 	 * We know buffp/buffq will fit in pline/plineq since we
512*0Sstevel@tonic-gate 	 * processed at most size characters.
513*0Sstevel@tonic-gate 	 */
514*0Sstevel@tonic-gate 	(void) strcpy(pline, buffp);
515*0Sstevel@tonic-gate 	(void) strcpy(plineq, buffq);
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 	return (0);
518*0Sstevel@tonic-gate }
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate /*
521*0Sstevel@tonic-gate  * Removes quotes from the string "str" and returns
522*0Sstevel@tonic-gate  * the quoting information in "qbuf". e.g.
523*0Sstevel@tonic-gate  * original str: 'the "quick brown" f\ox'
524*0Sstevel@tonic-gate  * unquoted str: 'the quick brown fox'
525*0Sstevel@tonic-gate  * and the qbuf: '    ^^^^^^^^^^^  ^ '
526*0Sstevel@tonic-gate  */
527*0Sstevel@tonic-gate void
528*0Sstevel@tonic-gate unquote(str, qbuf)
529*0Sstevel@tonic-gate 	char *str, *qbuf;
530*0Sstevel@tonic-gate {
531*0Sstevel@tonic-gate 	register int escaped, inquote, quoted;
532*0Sstevel@tonic-gate 	register char *ip, *bp, *qp;
533*0Sstevel@tonic-gate 	char buf[LINESZ];
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	escaped = inquote = quoted = 0;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	for (ip = str, bp = buf, qp = qbuf; *ip; ip++) {
538*0Sstevel@tonic-gate 		if (!escaped) {
539*0Sstevel@tonic-gate 			if (*ip == '\\') {
540*0Sstevel@tonic-gate 				escaped = 1;
541*0Sstevel@tonic-gate 				quoted++;
542*0Sstevel@tonic-gate 				continue;
543*0Sstevel@tonic-gate 			} else
544*0Sstevel@tonic-gate 			if (*ip == '"') {
545*0Sstevel@tonic-gate 				inquote = !inquote;
546*0Sstevel@tonic-gate 				quoted++;
547*0Sstevel@tonic-gate 				continue;
548*0Sstevel@tonic-gate 			}
549*0Sstevel@tonic-gate 		}
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 		*bp++ = *ip;
552*0Sstevel@tonic-gate 		*qp++ = (inquote || escaped) ? '^' : ' ';
553*0Sstevel@tonic-gate 		escaped = 0;
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 	*bp = '\0';
556*0Sstevel@tonic-gate 	*qp = '\0';
557*0Sstevel@tonic-gate 	if (quoted)
558*0Sstevel@tonic-gate 		(void) strcpy(str, buf);
559*0Sstevel@tonic-gate }
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate /*
562*0Sstevel@tonic-gate  * Removes trailing spaces from string "s".
563*0Sstevel@tonic-gate  */
564*0Sstevel@tonic-gate void
565*0Sstevel@tonic-gate trim(s)
566*0Sstevel@tonic-gate 	char *s;
567*0Sstevel@tonic-gate {
568*0Sstevel@tonic-gate 	char *p = &s[strlen(s) - 1];
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	while (p >= s && isspace(*(uchar_t *)p))
571*0Sstevel@tonic-gate 		*p-- = '\0';
572*0Sstevel@tonic-gate }
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate /*
575*0Sstevel@tonic-gate  * try to allocate memory using malloc, if malloc fails, then flush the
576*0Sstevel@tonic-gate  * rddir caches, and retry. If the second allocation after the readdir
577*0Sstevel@tonic-gate  * caches have been flushed fails too, then return NULL to indicate
578*0Sstevel@tonic-gate  * memory could not be allocated.
579*0Sstevel@tonic-gate  */
580*0Sstevel@tonic-gate char *
581*0Sstevel@tonic-gate auto_rddir_malloc(unsigned nbytes)
582*0Sstevel@tonic-gate {
583*0Sstevel@tonic-gate 	char *p;
584*0Sstevel@tonic-gate 	int again = 0;
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	if ((p = malloc(nbytes)) == NULL) {
587*0Sstevel@tonic-gate 		/*
588*0Sstevel@tonic-gate 		 * No memory, free rddir caches and try again
589*0Sstevel@tonic-gate 		 */
590*0Sstevel@tonic-gate 		mutex_lock(&cleanup_lock);
591*0Sstevel@tonic-gate 		cond_signal(&cleanup_start_cv);
592*0Sstevel@tonic-gate 		if (cond_wait(&cleanup_done_cv, &cleanup_lock)) {
593*0Sstevel@tonic-gate 			mutex_unlock(&cleanup_lock);
594*0Sstevel@tonic-gate 			syslog(LOG_ERR, "auto_rddir_malloc interrupted\n");
595*0Sstevel@tonic-gate 		} else {
596*0Sstevel@tonic-gate 			mutex_unlock(&cleanup_lock);
597*0Sstevel@tonic-gate 			again = 1;
598*0Sstevel@tonic-gate 		}
599*0Sstevel@tonic-gate 	}
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	if (again)
602*0Sstevel@tonic-gate 		p = malloc(nbytes);
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	return (p);
605*0Sstevel@tonic-gate }
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate /*
608*0Sstevel@tonic-gate  * try to strdup a string, if it fails, then flush the rddir caches,
609*0Sstevel@tonic-gate  * and retry. If the second strdup fails, return NULL to indicate failure.
610*0Sstevel@tonic-gate  */
611*0Sstevel@tonic-gate char *
612*0Sstevel@tonic-gate auto_rddir_strdup(const char *s1)
613*0Sstevel@tonic-gate {
614*0Sstevel@tonic-gate 	char *s2;
615*0Sstevel@tonic-gate 	int again = 0;
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 	if ((s2 = strdup(s1)) == NULL) {
618*0Sstevel@tonic-gate 		/*
619*0Sstevel@tonic-gate 		 * No memory, free rddir caches and try again
620*0Sstevel@tonic-gate 		 */
621*0Sstevel@tonic-gate 		mutex_lock(&cleanup_lock);
622*0Sstevel@tonic-gate 		cond_signal(&cleanup_start_cv);
623*0Sstevel@tonic-gate 		if (cond_wait(&cleanup_done_cv, &cleanup_lock)) {
624*0Sstevel@tonic-gate 			mutex_unlock(&cleanup_lock);
625*0Sstevel@tonic-gate 			syslog(LOG_ERR, "auto_rddir_strdup interrupted\n");
626*0Sstevel@tonic-gate 		} else {
627*0Sstevel@tonic-gate 			mutex_unlock(&cleanup_lock);
628*0Sstevel@tonic-gate 			again = 1;
629*0Sstevel@tonic-gate 		}
630*0Sstevel@tonic-gate 	}
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	if (again)
633*0Sstevel@tonic-gate 		s2 = strdup(s1);
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 	return (s2);
636*0Sstevel@tonic-gate }
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate /*
639*0Sstevel@tonic-gate  * Returns a pointer to the entry corresponding to 'name' if found,
640*0Sstevel@tonic-gate  * otherwise it returns NULL.
641*0Sstevel@tonic-gate  */
642*0Sstevel@tonic-gate struct dir_entry *
643*0Sstevel@tonic-gate btree_lookup(struct dir_entry *head, char *name)
644*0Sstevel@tonic-gate {
645*0Sstevel@tonic-gate 	register struct dir_entry *p;
646*0Sstevel@tonic-gate 	register int direction;
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	for (p = head; p != NULL; ) {
649*0Sstevel@tonic-gate 		direction = strcmp(name, p->name);
650*0Sstevel@tonic-gate 		if (direction == 0)
651*0Sstevel@tonic-gate 			return (p);
652*0Sstevel@tonic-gate 		if (direction > 0)
653*0Sstevel@tonic-gate 			p = p->right;
654*0Sstevel@tonic-gate 		else p = p->left;
655*0Sstevel@tonic-gate 	}
656*0Sstevel@tonic-gate 	return (NULL);
657*0Sstevel@tonic-gate }
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate /*
660*0Sstevel@tonic-gate  * Add entry to binary tree
661*0Sstevel@tonic-gate  * Duplicate entries are not added
662*0Sstevel@tonic-gate  */
663*0Sstevel@tonic-gate void
664*0Sstevel@tonic-gate btree_enter(struct dir_entry **head, struct dir_entry *ent)
665*0Sstevel@tonic-gate {
666*0Sstevel@tonic-gate 	register struct dir_entry *p, *prev = NULL;
667*0Sstevel@tonic-gate 	register int direction;
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	ent->right = ent->left = NULL;
670*0Sstevel@tonic-gate 	if (*head == NULL) {
671*0Sstevel@tonic-gate 		*head = ent;
672*0Sstevel@tonic-gate 		return;
673*0Sstevel@tonic-gate 	}
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	for (p = *head; p != NULL; ) {
676*0Sstevel@tonic-gate 		prev = p;
677*0Sstevel@tonic-gate 		direction = strcmp(ent->name, p->name);
678*0Sstevel@tonic-gate 		if (direction == 0) {
679*0Sstevel@tonic-gate 			/*
680*0Sstevel@tonic-gate 			 * entry already in btree
681*0Sstevel@tonic-gate 			 */
682*0Sstevel@tonic-gate 			return;
683*0Sstevel@tonic-gate 		}
684*0Sstevel@tonic-gate 		if (direction > 0)
685*0Sstevel@tonic-gate 			p = p->right;
686*0Sstevel@tonic-gate 		else p = p->left;
687*0Sstevel@tonic-gate 	}
688*0Sstevel@tonic-gate 	assert(prev != NULL);
689*0Sstevel@tonic-gate 	if (direction > 0)
690*0Sstevel@tonic-gate 		prev->right = ent;
691*0Sstevel@tonic-gate 	else prev->left = ent;
692*0Sstevel@tonic-gate }
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate /*
695*0Sstevel@tonic-gate  * If entry doesn't exist already, add it to the linear list
696*0Sstevel@tonic-gate  * after '*last' and to the binary tree list.
697*0Sstevel@tonic-gate  * If '*last == NULL' then the list is walked till the end.
698*0Sstevel@tonic-gate  * *last is always set to the new element after successful completion.
699*0Sstevel@tonic-gate  * if entry already exists '*last' is only updated if not previously
700*0Sstevel@tonic-gate  * provided.
701*0Sstevel@tonic-gate  */
702*0Sstevel@tonic-gate int
703*0Sstevel@tonic-gate add_dir_entry(char *name, struct dir_entry **list, struct dir_entry **last)
704*0Sstevel@tonic-gate {
705*0Sstevel@tonic-gate 	struct dir_entry *e, *l;
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	if ((*list != NULL) && (*last == NULL)) {
708*0Sstevel@tonic-gate 		/*
709*0Sstevel@tonic-gate 		 * walk the list to find last element
710*0Sstevel@tonic-gate 		 */
711*0Sstevel@tonic-gate 		for (l = *list; l != NULL; l = l->next)
712*0Sstevel@tonic-gate 			*last = l;
713*0Sstevel@tonic-gate 	}
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 	if (btree_lookup(*list, name) == NULL) {
716*0Sstevel@tonic-gate 		/*
717*0Sstevel@tonic-gate 		 * not a duplicate, add it to list
718*0Sstevel@tonic-gate 		 */
719*0Sstevel@tonic-gate 		/* LINTED pointer alignment */
720*0Sstevel@tonic-gate 		e = (struct dir_entry *)
721*0Sstevel@tonic-gate 			auto_rddir_malloc(sizeof (struct dir_entry));
722*0Sstevel@tonic-gate 		if (e == NULL)
723*0Sstevel@tonic-gate 			return (ENOMEM);
724*0Sstevel@tonic-gate 		(void) memset((char *)e, 0, sizeof (*e));
725*0Sstevel@tonic-gate 		e->name = auto_rddir_strdup(name);
726*0Sstevel@tonic-gate 		if (e->name == NULL) {
727*0Sstevel@tonic-gate 			free(e);
728*0Sstevel@tonic-gate 			return (ENOMEM);
729*0Sstevel@tonic-gate 		}
730*0Sstevel@tonic-gate 		e->next = NULL;
731*0Sstevel@tonic-gate 		if (*list == NULL) {
732*0Sstevel@tonic-gate 			/*
733*0Sstevel@tonic-gate 			 * list is empty
734*0Sstevel@tonic-gate 			 */
735*0Sstevel@tonic-gate 			*list = *last = e;
736*0Sstevel@tonic-gate 		} else {
737*0Sstevel@tonic-gate 			/*
738*0Sstevel@tonic-gate 			 * append to end of list
739*0Sstevel@tonic-gate 			 */
740*0Sstevel@tonic-gate 			assert(*last != NULL);
741*0Sstevel@tonic-gate 			(*last)->next = e;
742*0Sstevel@tonic-gate 			*last = e;
743*0Sstevel@tonic-gate 		}
744*0Sstevel@tonic-gate 		/*
745*0Sstevel@tonic-gate 		 * add to binary tree
746*0Sstevel@tonic-gate 		 */
747*0Sstevel@tonic-gate 		btree_enter(list, e);
748*0Sstevel@tonic-gate 	}
749*0Sstevel@tonic-gate 	return (0);
750*0Sstevel@tonic-gate }
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate /*
753*0Sstevel@tonic-gate  * Print trace output.
754*0Sstevel@tonic-gate  * Like fprintf(stderr, fmt, ...) except that if "id" is nonzero, the output
755*0Sstevel@tonic-gate  * is preceeded by the ID of the calling thread.
756*0Sstevel@tonic-gate  */
757*0Sstevel@tonic-gate #define	FMT_BUFSIZ 1024
758*0Sstevel@tonic-gate 
759*0Sstevel@tonic-gate void
760*0Sstevel@tonic-gate trace_prt(int id, char *fmt, ...)
761*0Sstevel@tonic-gate {
762*0Sstevel@tonic-gate 	va_list args;
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 	char buf[FMT_BUFSIZ];
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate 	if (id) {
767*0Sstevel@tonic-gate 		(void) sprintf(buf, "t%u\t%s", thr_self(), fmt);
768*0Sstevel@tonic-gate 		fmt = buf;
769*0Sstevel@tonic-gate 	}
770*0Sstevel@tonic-gate 	va_start(args, fmt);
771*0Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, args);
772*0Sstevel@tonic-gate 	va_end(args);
773*0Sstevel@tonic-gate }
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate /*
776*0Sstevel@tonic-gate  * Extract the isalist(5) for userland from the kernel.
777*0Sstevel@tonic-gate  */
778*0Sstevel@tonic-gate static char *
779*0Sstevel@tonic-gate isalist(void)
780*0Sstevel@tonic-gate {
781*0Sstevel@tonic-gate 	char *buf;
782*0Sstevel@tonic-gate 	size_t bufsize = BUFSIZ;	/* wild guess */
783*0Sstevel@tonic-gate 	long ret;
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate 	buf = malloc(bufsize);
786*0Sstevel@tonic-gate 	do {
787*0Sstevel@tonic-gate 		ret = sysinfo(SI_ISALIST, buf, bufsize);
788*0Sstevel@tonic-gate 		if (ret == -1l)
789*0Sstevel@tonic-gate 			return (NULL);
790*0Sstevel@tonic-gate 		if (ret > bufsize) {
791*0Sstevel@tonic-gate 			bufsize = ret;
792*0Sstevel@tonic-gate 			buf = realloc(buf, bufsize);
793*0Sstevel@tonic-gate 		} else
794*0Sstevel@tonic-gate 			break;
795*0Sstevel@tonic-gate 	} while (buf != NULL);
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	return (buf);
798*0Sstevel@tonic-gate }
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate /*
801*0Sstevel@tonic-gate  * Classify isa's as to bitness of the corresponding ABIs.
802*0Sstevel@tonic-gate  * isa's which have no "official" system ABI are returned
803*0Sstevel@tonic-gate  * unrecognised i.e. zero bits.
804*0Sstevel@tonic-gate  */
805*0Sstevel@tonic-gate static int
806*0Sstevel@tonic-gate bitness(char *isaname)
807*0Sstevel@tonic-gate {
808*0Sstevel@tonic-gate 	if (strcmp(isaname, "sparc") == 0 ||
809*0Sstevel@tonic-gate 	    strcmp(isaname, "i386") == 0)
810*0Sstevel@tonic-gate 		return (32);
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	if (strcmp(isaname, "sparcv9") == 0)
813*0Sstevel@tonic-gate 		return (64);
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 	return (0);
816*0Sstevel@tonic-gate }
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate /*
819*0Sstevel@tonic-gate  * Find the left-most element in the isalist that matches our idea of a
820*0Sstevel@tonic-gate  * system ABI.
821*0Sstevel@tonic-gate  *
822*0Sstevel@tonic-gate  * On machines with only one ABI, this is usually the same as uname -p.
823*0Sstevel@tonic-gate  */
824*0Sstevel@tonic-gate static int
825*0Sstevel@tonic-gate natisa(char *buf, size_t bufsize)
826*0Sstevel@tonic-gate {
827*0Sstevel@tonic-gate 	int bits;
828*0Sstevel@tonic-gate 	char *isa, *list;
829*0Sstevel@tonic-gate 	char *lasts;
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate 	if ((list = isalist()) == NULL)
832*0Sstevel@tonic-gate 		return (0);
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate 	for (isa = strtok_r(list, " ", &lasts);
835*0Sstevel@tonic-gate 	    isa; isa = strtok_r(0, " ", &lasts))
836*0Sstevel@tonic-gate 		if ((bits = bitness(isa)) != 0)
837*0Sstevel@tonic-gate 			break;	/* ignore "extension" architectures */
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 	if (isa == 0 || bits == 0) {
840*0Sstevel@tonic-gate 		free(list);
841*0Sstevel@tonic-gate 		return (0);	/* can't figure it out :( */
842*0Sstevel@tonic-gate 	}
843*0Sstevel@tonic-gate 
844*0Sstevel@tonic-gate 	(void) strncpy(buf, isa, bufsize);
845*0Sstevel@tonic-gate 	free(list);
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate 	return (1);
848*0Sstevel@tonic-gate }
849