xref: /onnv-gate/usr/src/cmd/fs.d/autofs/auto_subr.c (revision 13080:fcc1e406c13f)
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
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*13080SPavan.Mettu@Oracle.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <ctype.h>
270Sstevel@tonic-gate #include <stdio.h>
280Sstevel@tonic-gate #include <stdlib.h>
290Sstevel@tonic-gate #include <unistd.h>
300Sstevel@tonic-gate #include <locale.h>
310Sstevel@tonic-gate #include <syslog.h>
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <stdarg.h>
350Sstevel@tonic-gate #include <dirent.h>
36*13080SPavan.Mettu@Oracle.COM #include <limits.h>
370Sstevel@tonic-gate #include <thread.h>
380Sstevel@tonic-gate #include <sys/param.h>
390Sstevel@tonic-gate #include <sys/time.h>
400Sstevel@tonic-gate #include <sys/vfs.h>
410Sstevel@tonic-gate #include <sys/types.h>
420Sstevel@tonic-gate #include <sys/stat.h>
430Sstevel@tonic-gate #include <sys/mnttab.h>
440Sstevel@tonic-gate #include <sys/mntent.h>
450Sstevel@tonic-gate #include <sys/mount.h>
460Sstevel@tonic-gate #include <sys/signal.h>
470Sstevel@tonic-gate #include <sys/utsname.h>
480Sstevel@tonic-gate #include <sys/systeminfo.h>
490Sstevel@tonic-gate #include <sys/tiuser.h>
500Sstevel@tonic-gate #include <sys/utsname.h>
510Sstevel@tonic-gate #include <rpc/rpc.h>
520Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h>
53*13080SPavan.Mettu@Oracle.COM #include <rpcsvc/daemon_utils.h>
540Sstevel@tonic-gate #include <assert.h>
550Sstevel@tonic-gate #include "automount.h"
562673Spetede #include <deflt.h>
571676Sjpk #include <zone.h>
581676Sjpk #include <priv.h>
591676Sjpk #include <fcntl.h>
60*13080SPavan.Mettu@Oracle.COM #include <libshare.h>
61*13080SPavan.Mettu@Oracle.COM #include <libscf.h>
62*13080SPavan.Mettu@Oracle.COM #include "smfcfg.h"
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static char *check_hier(char *);
652673Spetede static int arch(char *, size_t, bool_t);
662673Spetede static int cpu(char *, size_t);
670Sstevel@tonic-gate static int natisa(char *, size_t);
682673Spetede static int platform(char *, size_t);
690Sstevel@tonic-gate 
700Sstevel@tonic-gate struct mntlist *current_mounts;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static bool_t nodirect_map = FALSE;
730Sstevel@tonic-gate 
741676Sjpk /*
751676Sjpk  * If the system is labeled then we need to
761676Sjpk  * have a uniquely-named auto_home map for each zone.
771676Sjpk  * The maps are made unique by appending the zonename.
781676Sjpk  * The home directory is made unique by prepending /zone/<zonename>
791676Sjpk  * for each zone that is dominated by the current zone.
801676Sjpk  * The current zone's home directory mount point is not changed.
811676Sjpk  *
821676Sjpk  * For each auto_home_<zonename> a default template map is created
831676Sjpk  * only if it doesn't exist yet. The default entry is used to declare
841676Sjpk  * local home directories created within each zone. For example:
851676Sjpk  *
861676Sjpk  *	+auto_home_public
871676Sjpk  *      * -fstype=lofs :/zone/public/export/home/&
881676Sjpk  */
891676Sjpk static void
loadzone_maps(char * mntpnt,char * map,char * opts,char ** stack,char *** stkptr)901676Sjpk loadzone_maps(char *mntpnt, char *map, char *opts, char **stack, char ***stkptr)
911676Sjpk {
921676Sjpk 	zoneid_t *zids = NULL;
931676Sjpk 	zoneid_t my_zoneid;
941676Sjpk 	uint_t nzents_saved;
951676Sjpk 	uint_t nzents;
961676Sjpk 	int i;
971676Sjpk 
981676Sjpk 	if (!priv_ineffect(PRIV_SYS_MOUNT))
991676Sjpk 		return;
1001676Sjpk 
1011676Sjpk 	if (zone_list(NULL, &nzents) != 0) {
1021676Sjpk 		return;
1031676Sjpk 	}
1041676Sjpk 	my_zoneid = getzoneid();
1051676Sjpk again:
1061676Sjpk 	if (nzents == 0)
1071676Sjpk 		return;
1081676Sjpk 
1091676Sjpk 	zids = malloc(nzents * sizeof (zoneid_t));
1101676Sjpk 	nzents_saved = nzents;
1111676Sjpk 
1121676Sjpk 	if (zone_list(zids, &nzents) != 0) {
1131676Sjpk 		free(zids);
1141676Sjpk 		return;
1151676Sjpk 	}
1161676Sjpk 	if (nzents != nzents_saved) {
1171676Sjpk 		/* list changed, try again */
1181676Sjpk 		free(zids);
1191676Sjpk 		goto again;
1201676Sjpk 	}
1211676Sjpk 
1221676Sjpk 	for (i = 0; i < nzents; i++) {
1231676Sjpk 		char zonename[ZONENAME_MAX];
1241676Sjpk 		char zoneroot[MAXPATHLEN];
1251676Sjpk 
1261676Sjpk 		if (getzonenamebyid(zids[i], zonename, ZONENAME_MAX) != -1) {
1271676Sjpk 			char appended_map[MAXPATHLEN];
1281676Sjpk 			char prepended_mntpnt[MAXPATHLEN];
1291676Sjpk 			char map_path[MAXPATHLEN];
1301676Sjpk 			int fd;
1311676Sjpk 
1321676Sjpk 			(void) snprintf(appended_map, sizeof (appended_map),
1331676Sjpk 			    "%s_%s", map, zonename);
1341676Sjpk 
1351676Sjpk 			/* for current zone, leave mntpnt alone */
1361676Sjpk 			if (zids[i] != my_zoneid) {
1371676Sjpk 				(void) snprintf(prepended_mntpnt,
1381676Sjpk 				    sizeof (prepended_mntpnt),
1391676Sjpk 				    "/zone/%s%s", zonename, mntpnt);
1401676Sjpk 				if (zone_getattr(zids[i], ZONE_ATTR_ROOT,
1411676Sjpk 				    zoneroot, sizeof (zoneroot)) == -1)
1421676Sjpk 					continue;
1431676Sjpk 			} else {
1441676Sjpk 				(void) strcpy(prepended_mntpnt, mntpnt);
1451676Sjpk 				zoneroot[0] = '\0';
1461676Sjpk 			}
1471676Sjpk 
1481676Sjpk 			dirinit(prepended_mntpnt, appended_map, opts, 0, stack,
1491676Sjpk 			    stkptr);
1501676Sjpk 			/*
1511676Sjpk 			 * Next create auto_home_<zone> maps for each zone
1521676Sjpk 			 */
1531676Sjpk 
1541676Sjpk 			(void) snprintf(map_path, sizeof (map_path),
1551676Sjpk 			    "/etc/%s", appended_map);
1561676Sjpk 			/*
1571676Sjpk 			 * If the map file doesn't exist create a template
1581676Sjpk 			 */
1591676Sjpk 			if ((fd = open(map_path, O_RDWR | O_CREAT | O_EXCL,
1601676Sjpk 			    S_IRUSR | S_IWUSR | S_IRGRP| S_IROTH)) != -1) {
1611676Sjpk 				int len;
1621676Sjpk 				char map_rec[MAXPATHLEN];
1631676Sjpk 
1641676Sjpk 				len = snprintf(map_rec, sizeof (map_rec),
1651676Sjpk 				    "+%s\n*\t-fstype=lofs\t:%s/export/home/&\n",
1661676Sjpk 				    appended_map, zoneroot);
1671676Sjpk 				if (len <= sizeof (map_rec))
1681676Sjpk 					(void) write(fd, map_rec, len);
1691676Sjpk 				(void) close(fd);
1701676Sjpk 			}
1711676Sjpk 		}
1721676Sjpk 	}
1731676Sjpk 	free(zids);
1741676Sjpk }
1751676Sjpk 
1760Sstevel@tonic-gate void
dirinit(char * mntpnt,char * map,char * opts,int direct,char ** stack,char *** stkptr)1770Sstevel@tonic-gate dirinit(char *mntpnt, char *map, char *opts, int direct, char **stack,
1781676Sjpk     char ***stkptr)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	struct autodir *dir;
1810Sstevel@tonic-gate 	char *p;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	if (strcmp(map, "-null") == 0) {
1840Sstevel@tonic-gate 		if (strcmp(mntpnt, "/-") == 0)
1850Sstevel@tonic-gate 			nodirect_map = TRUE;
1860Sstevel@tonic-gate 		goto enter;
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	p = mntpnt + (strlen(mntpnt) - 1);
1900Sstevel@tonic-gate 	if (*p == '/')
1910Sstevel@tonic-gate 		*p = '\0';	/* trim trailing / */
1920Sstevel@tonic-gate 	if (*mntpnt != '/') {
1930Sstevel@tonic-gate 		pr_msg("dir %s must start with '/'", mntpnt);
1940Sstevel@tonic-gate 		return;
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate 	if (p = check_hier(mntpnt)) {
1970Sstevel@tonic-gate 		pr_msg("hierarchical mountpoint: %s and %s",
198*13080SPavan.Mettu@Oracle.COM 		    p, mntpnt);
1990Sstevel@tonic-gate 		return;
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	/*
2030Sstevel@tonic-gate 	 * If it's a direct map then call dirinit
2040Sstevel@tonic-gate 	 * for every map entry.
2050Sstevel@tonic-gate 	 */
2060Sstevel@tonic-gate 	if ((strcmp(mntpnt, "/-") == 0) && !(nodirect_map)) {
2070Sstevel@tonic-gate 		(void) loaddirect_map(map, map, opts, stack, stkptr);
2080Sstevel@tonic-gate 		return;
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 
2111676Sjpk 	/*
2121676Sjpk 	 * Home directories are polyinstantiated on
2131676Sjpk 	 * labeled systems.
2141676Sjpk 	 */
2151676Sjpk 	if (is_system_labeled() &&
2161676Sjpk 	    (strcmp(mntpnt, "/home") == 0) &&
2171676Sjpk 	    (strcmp(map, "auto_home") == 0)) {
2181676Sjpk 		(void) loadzone_maps(mntpnt, map, opts, stack, stkptr);
2191676Sjpk 		return;
2201676Sjpk 	}
2210Sstevel@tonic-gate enter:
2220Sstevel@tonic-gate 	dir = (struct autodir *)malloc(sizeof (*dir));
2230Sstevel@tonic-gate 	if (dir == NULL)
2240Sstevel@tonic-gate 		goto alloc_failed;
2250Sstevel@tonic-gate 	dir->dir_name = strdup(mntpnt);
2260Sstevel@tonic-gate 	if (dir->dir_name == NULL)
2270Sstevel@tonic-gate 		goto alloc_failed;
2280Sstevel@tonic-gate 	dir->dir_map = strdup(map);
2290Sstevel@tonic-gate 	if (dir->dir_map == NULL)
2300Sstevel@tonic-gate 		goto alloc_failed;
2310Sstevel@tonic-gate 	dir->dir_opts = strdup(opts);
2320Sstevel@tonic-gate 	if (dir->dir_opts == NULL)
2330Sstevel@tonic-gate 		goto alloc_failed;
2340Sstevel@tonic-gate 	dir->dir_direct = direct;
2350Sstevel@tonic-gate 	dir->dir_remount = 0;
2360Sstevel@tonic-gate 	dir->dir_next = NULL;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	/*
2390Sstevel@tonic-gate 	 * Append to dir chain
2400Sstevel@tonic-gate 	 */
2410Sstevel@tonic-gate 	if (dir_head == NULL)
2420Sstevel@tonic-gate 		dir_head = dir;
2430Sstevel@tonic-gate 	else
2440Sstevel@tonic-gate 		dir_tail->dir_next = dir;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	dir->dir_prev = dir_tail;
2470Sstevel@tonic-gate 	dir_tail = dir;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	return;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate alloc_failed:
2520Sstevel@tonic-gate 	if (dir != NULL) {
2530Sstevel@tonic-gate 		if (dir->dir_opts)
2540Sstevel@tonic-gate 			free(dir->dir_opts);
2550Sstevel@tonic-gate 		if (dir->dir_map)
2560Sstevel@tonic-gate 			free(dir->dir_map);
2570Sstevel@tonic-gate 		if (dir->dir_name)
2580Sstevel@tonic-gate 			free(dir->dir_name);
2590Sstevel@tonic-gate 		free(dir);
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 	pr_msg("dirinit: memory allocation failed");
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate  *  Check whether the mount point is a
2660Sstevel@tonic-gate  *  subdirectory or a parent directory
2670Sstevel@tonic-gate  *  of any previously mounted automount
2680Sstevel@tonic-gate  *  mount point.
2690Sstevel@tonic-gate  */
2700Sstevel@tonic-gate static char *
check_hier(mntpnt)2710Sstevel@tonic-gate check_hier(mntpnt)
2720Sstevel@tonic-gate 	char *mntpnt;
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	register struct autodir *dir;
2750Sstevel@tonic-gate 	register char *p, *q;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	for (dir = dir_head; dir; dir = dir->dir_next) {
2780Sstevel@tonic-gate 		p = dir->dir_name;
2790Sstevel@tonic-gate 		q = mntpnt;
2800Sstevel@tonic-gate 		for (; *p == *q; p++, q++)
2810Sstevel@tonic-gate 			if (*p == '\0')
2820Sstevel@tonic-gate 				break;
2830Sstevel@tonic-gate 		if (*p == '/' && *q == '\0')
2840Sstevel@tonic-gate 			return (dir->dir_name);
2850Sstevel@tonic-gate 		if (*p == '\0' && *q == '/')
2860Sstevel@tonic-gate 			return (dir->dir_name);
2870Sstevel@tonic-gate 		if (*p == '\0' && *q == '\0')
2880Sstevel@tonic-gate 			return (NULL);
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 	return (NULL);	/* it's not a subdir or parent */
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate /*
2943767Sjs195444  * Gets the next token from the string "p" and copies it into "w".  The "wq" is
2953767Sjs195444  * a quote vector for "w" and is derived from "pq", which is a quote vector for
2963767Sjs195444  * "p". Delim is the character to be used as a delimiter for the scan.  A space
2973767Sjs195444  * means "whitespace". The call to getword must provide buffers w and wq of size
2983767Sjs195444  * at least wordsz. getword() will pass strings of maximum length (wordsz-1),
2993767Sjs195444  * since it needs to null terminate the string.
3000Sstevel@tonic-gate  * Returns 0 on ok and -1 on error.
3010Sstevel@tonic-gate  */
3020Sstevel@tonic-gate int
getword(char * w,char * wq,char ** p,char ** pq,char delim,int wordsz)3030Sstevel@tonic-gate getword(char *w, char *wq, char **p, char **pq, char delim, int wordsz)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	char *tmp = w;
3060Sstevel@tonic-gate 	char *tmpq = wq;
3070Sstevel@tonic-gate 	int count = wordsz;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	if (wordsz <= 0) {
3100Sstevel@tonic-gate 		if (verbose)
3110Sstevel@tonic-gate 			syslog(LOG_ERR,
3120Sstevel@tonic-gate 			"getword: input word size %d must be > 0", wordsz);
3130Sstevel@tonic-gate 		return (-1);
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	while ((delim == ' ' ? isspace(**p) : **p == delim) && **pq == ' ')
3170Sstevel@tonic-gate 		(*p)++, (*pq)++;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	while (**p &&
320*13080SPavan.Mettu@Oracle.COM 	    !((delim == ' ' ? isspace(**p) : **p == delim) &&
321*13080SPavan.Mettu@Oracle.COM 	    **pq == ' ')) {
3220Sstevel@tonic-gate 		if (--count <= 0) {
3230Sstevel@tonic-gate 			*tmp = '\0';
3240Sstevel@tonic-gate 			*tmpq = '\0';
3250Sstevel@tonic-gate 			syslog(LOG_ERR,
3260Sstevel@tonic-gate 			"maximum word length (%d) exceeded", wordsz);
3270Sstevel@tonic-gate 			return (-1);
3280Sstevel@tonic-gate 		}
3290Sstevel@tonic-gate 		*w++  = *(*p)++;
3300Sstevel@tonic-gate 		*wq++ = *(*pq)++;
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate 	*w  = '\0';
3330Sstevel@tonic-gate 	*wq = '\0';
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	return (0);
3360Sstevel@tonic-gate }
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate /*
3390Sstevel@tonic-gate  * get_line attempts to get a line from the map, upto LINESZ. A line in
3400Sstevel@tonic-gate  * the map is a concatenation of lines if the continuation symbol '\'
3410Sstevel@tonic-gate  * is used at the end of the line. Returns line on success, a NULL on
3420Sstevel@tonic-gate  * EOF, and an empty string on lines > linesz.
3430Sstevel@tonic-gate  */
3440Sstevel@tonic-gate char *
get_line(FILE * fp,char * map,char * line,int linesz)3450Sstevel@tonic-gate get_line(FILE *fp, char *map, char *line, int linesz)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate 	register char *p = line;
3480Sstevel@tonic-gate 	register int len;
3490Sstevel@tonic-gate 	int excess = 0;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	*p = '\0';
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	for (;;) {
3540Sstevel@tonic-gate 		if (fgets(p, linesz - (p-line), fp) == NULL) {
3550Sstevel@tonic-gate 			return (*line ? line : NULL);	/* EOF */
3560Sstevel@tonic-gate 		}
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 		len = strlen(line);
3590Sstevel@tonic-gate 		if (len <= 0) {
3600Sstevel@tonic-gate 			p = line;
3610Sstevel@tonic-gate 			continue;
3620Sstevel@tonic-gate 		}
3630Sstevel@tonic-gate 		p = &line[len - 1];
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 		/*
3660Sstevel@tonic-gate 		 * Is input line too long?
3670Sstevel@tonic-gate 		 */
3680Sstevel@tonic-gate 		if (*p != '\n') {
3690Sstevel@tonic-gate 			excess = 1;
3700Sstevel@tonic-gate 			/*
3710Sstevel@tonic-gate 			 * Perhaps last char read was '\'. Reinsert it
3720Sstevel@tonic-gate 			 * into the stream to ease the parsing when we
3730Sstevel@tonic-gate 			 * read the rest of the line to discard.
3740Sstevel@tonic-gate 			 */
3750Sstevel@tonic-gate 			(void) ungetc(*p, fp);
3760Sstevel@tonic-gate 			break;
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate trim:
3790Sstevel@tonic-gate 		/* trim trailing white space */
3800Sstevel@tonic-gate 		while (p >= line && isspace(*(uchar_t *)p))
3810Sstevel@tonic-gate 			*p-- = '\0';
3820Sstevel@tonic-gate 		if (p < line) {			/* empty line */
3830Sstevel@tonic-gate 			p = line;
3840Sstevel@tonic-gate 			continue;
3850Sstevel@tonic-gate 		}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 		if (*p == '\\') {		/* continuation */
3880Sstevel@tonic-gate 			*p = '\0';
3890Sstevel@tonic-gate 			continue;
3900Sstevel@tonic-gate 		}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 		/*
3930Sstevel@tonic-gate 		 * Ignore comments. Comments start with '#'
3940Sstevel@tonic-gate 		 * which must be preceded by a whitespace, unless
3950Sstevel@tonic-gate 		 * if '#' is the first character in the line.
3960Sstevel@tonic-gate 		 */
3970Sstevel@tonic-gate 		p = line;
3980Sstevel@tonic-gate 		while (p = strchr(p, '#')) {
3990Sstevel@tonic-gate 			if (p == line || isspace(*(p-1))) {
4000Sstevel@tonic-gate 				*p-- = '\0';
4010Sstevel@tonic-gate 				goto trim;
4020Sstevel@tonic-gate 			}
4030Sstevel@tonic-gate 			p++;
4040Sstevel@tonic-gate 		}
4050Sstevel@tonic-gate 		break;
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 	if (excess) {
4080Sstevel@tonic-gate 		int c;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 		/*
4110Sstevel@tonic-gate 		 * discard rest of line and return an empty string.
4120Sstevel@tonic-gate 		 * done to set the stream to the correct place when
4130Sstevel@tonic-gate 		 * we are done with this line.
4140Sstevel@tonic-gate 		 */
4150Sstevel@tonic-gate 		while ((c = getc(fp)) != EOF) {
4160Sstevel@tonic-gate 			*p = c;
4170Sstevel@tonic-gate 			if (*p == '\n')		/* end of the long line */
4180Sstevel@tonic-gate 				break;
4190Sstevel@tonic-gate 			else if (*p == '\\') {		/* continuation */
4200Sstevel@tonic-gate 				if (getc(fp) == EOF)	/* ignore next char */
4210Sstevel@tonic-gate 					break;
4220Sstevel@tonic-gate 			}
4230Sstevel@tonic-gate 		}
4240Sstevel@tonic-gate 		syslog(LOG_ERR,
425*13080SPavan.Mettu@Oracle.COM 		    "map %s: line too long (max %d chars)",
426*13080SPavan.Mettu@Oracle.COM 		    map, linesz-1);
4270Sstevel@tonic-gate 		*line = '\0';
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	return (line);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate /*
4340Sstevel@tonic-gate  * Gets the retry=n entry from opts.
4350Sstevel@tonic-gate  * Returns 0 if retry=n is not present in option string,
4360Sstevel@tonic-gate  * retry=n is invalid, or when option string is NULL.
4370Sstevel@tonic-gate  */
4380Sstevel@tonic-gate int
get_retry(char * opts)4390Sstevel@tonic-gate get_retry(char *opts)
4400Sstevel@tonic-gate {
4410Sstevel@tonic-gate 	int retry = 0;
4420Sstevel@tonic-gate 	char buf[MAXOPTSLEN];
4430Sstevel@tonic-gate 	char *p, *pb, *lasts;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	if (opts == NULL)
4460Sstevel@tonic-gate 		return (retry);
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	(void) strcpy(buf, opts);
4490Sstevel@tonic-gate 	pb = buf;
4500Sstevel@tonic-gate 	while (p = (char *)strtok_r(pb, ",", &lasts)) {
4510Sstevel@tonic-gate 		pb = NULL;
4520Sstevel@tonic-gate 		if (strncmp(p, "retry=", 6) == 0)
4530Sstevel@tonic-gate 			retry = atoi(p+6);
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 	return (retry > 0 ? retry : 0);
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate /*
4590Sstevel@tonic-gate  * Returns zero if "opt" is found in mnt->mnt_opts, setting
4600Sstevel@tonic-gate  * *sval to whatever follows the equal sign after "opt".
4610Sstevel@tonic-gate  * str_opt allocates a string long enough to store the value of
4620Sstevel@tonic-gate  * "opt" plus a terminating null character and returns it as *sval.
4630Sstevel@tonic-gate  * It is the responsability of the caller to deallocate *sval.
4640Sstevel@tonic-gate  * *sval will be equal to NULL upon return if either "opt=" is not found,
4650Sstevel@tonic-gate  * or "opt=" has no value associated with it.
4660Sstevel@tonic-gate  *
4670Sstevel@tonic-gate  * stropt will return -1 on error.
4680Sstevel@tonic-gate  */
4690Sstevel@tonic-gate int
str_opt(struct mnttab * mnt,char * opt,char ** sval)4700Sstevel@tonic-gate str_opt(struct mnttab *mnt, char *opt, char **sval)
4710Sstevel@tonic-gate {
4720Sstevel@tonic-gate 	char *str, *comma;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/*
4750Sstevel@tonic-gate 	 * is "opt" in the options field?
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	if (str = hasmntopt(mnt, opt)) {
4780Sstevel@tonic-gate 		str += strlen(opt);
4790Sstevel@tonic-gate 		if (*str++ != '=' ||
4800Sstevel@tonic-gate 		    (*str == ',' || *str == '\0')) {
4810Sstevel@tonic-gate 			syslog(LOG_ERR, "Bad option field");
4820Sstevel@tonic-gate 			return (-1);
4830Sstevel@tonic-gate 		}
4840Sstevel@tonic-gate 		comma = strchr(str, ',');
4850Sstevel@tonic-gate 		if (comma != NULL)
4860Sstevel@tonic-gate 			*comma = '\0';
4870Sstevel@tonic-gate 		*sval = strdup(str);
4880Sstevel@tonic-gate 		if (comma != NULL)
4890Sstevel@tonic-gate 			*comma = ',';
4900Sstevel@tonic-gate 		if (*sval == NULL)
4910Sstevel@tonic-gate 			return (-1);
4920Sstevel@tonic-gate 	} else
4930Sstevel@tonic-gate 		*sval = NULL;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	return (0);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate  * Performs text expansions in the string "pline".
5000Sstevel@tonic-gate  * "plineq" is the quote vector for "pline".
5010Sstevel@tonic-gate  * An identifier prefixed by "$" is replaced by the
5020Sstevel@tonic-gate  * corresponding environment variable string.  A "&"
5030Sstevel@tonic-gate  * is replaced by the key string for the map entry.
5040Sstevel@tonic-gate  *
5050Sstevel@tonic-gate  * This routine will return an error (non-zero) if *size* would be
5060Sstevel@tonic-gate  * exceeded after expansion, indicating that the macro_expand failed.
5070Sstevel@tonic-gate  * This is to prevent writing past the end of pline and plineq.
5080Sstevel@tonic-gate  * Both pline and plineq are left untouched in such error case.
5090Sstevel@tonic-gate  */
5100Sstevel@tonic-gate int
macro_expand(key,pline,plineq,size)5110Sstevel@tonic-gate macro_expand(key, pline, plineq, size)
5120Sstevel@tonic-gate 	char *key, *pline, *plineq;
5130Sstevel@tonic-gate 	int size;
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate 	register char *p,  *q;
5160Sstevel@tonic-gate 	register char *bp, *bq;
5170Sstevel@tonic-gate 	register char *s;
5180Sstevel@tonic-gate 	char buffp[LINESZ], buffq[LINESZ];
5190Sstevel@tonic-gate 	char namebuf[64], *pn;
5200Sstevel@tonic-gate 	int expand = 0;
5210Sstevel@tonic-gate 	struct utsname name;
5222673Spetede 	char procbuf[SYS_NMLN];
5230Sstevel@tonic-gate 	char isaname[64];
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	p = pline;  q = plineq;
5260Sstevel@tonic-gate 	bp = buffp; bq = buffq;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	while (*p) {
5290Sstevel@tonic-gate 		if (*p == '&' && *q == ' ') {	/* insert key */
5300Sstevel@tonic-gate 			/*
5310Sstevel@tonic-gate 			 * make sure we don't overflow buffer
5320Sstevel@tonic-gate 			 */
5330Sstevel@tonic-gate 			if ((int)((bp - buffp) + strlen(key)) < size) {
5340Sstevel@tonic-gate 				for (s = key; *s; s++) {
5350Sstevel@tonic-gate 					*bp++ = *s;
5360Sstevel@tonic-gate 					*bq++ = ' ';
5370Sstevel@tonic-gate 				}
5380Sstevel@tonic-gate 				expand++;
5390Sstevel@tonic-gate 				p++; q++;
5400Sstevel@tonic-gate 				continue;
5410Sstevel@tonic-gate 			} else {
5420Sstevel@tonic-gate 				/*
5430Sstevel@tonic-gate 				 * line too long...
5440Sstevel@tonic-gate 				 */
5450Sstevel@tonic-gate 				return (1);
5460Sstevel@tonic-gate 			}
5470Sstevel@tonic-gate 		}
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 		if (*p == '$' && *q == ' ') {	/* insert env var */
5500Sstevel@tonic-gate 			p++; q++;
5510Sstevel@tonic-gate 			pn = namebuf;
5520Sstevel@tonic-gate 			if (*p == '{') {
5530Sstevel@tonic-gate 				p++; q++;
5540Sstevel@tonic-gate 				while (*p && *p != '}') {
5550Sstevel@tonic-gate 					*pn++ = *p++;
5560Sstevel@tonic-gate 					q++;
5570Sstevel@tonic-gate 				}
5580Sstevel@tonic-gate 				if (*p) {
5590Sstevel@tonic-gate 					p++; q++;
5600Sstevel@tonic-gate 				}
5610Sstevel@tonic-gate 			} else {
5620Sstevel@tonic-gate 				while (*p && (*p == '_' || isalnum(*p))) {
5630Sstevel@tonic-gate 					*pn++ = *p++;
5640Sstevel@tonic-gate 					q++;
5650Sstevel@tonic-gate 				}
5660Sstevel@tonic-gate 			}
5670Sstevel@tonic-gate 			*pn = '\0';
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 			s = getenv(namebuf);
5700Sstevel@tonic-gate 			if (!s) {
5710Sstevel@tonic-gate 				/* not found in env */
5722673Spetede 				if (strcmp(namebuf, "ARCH") == 0) {
5732673Spetede 					if (arch(procbuf, sizeof (procbuf),
5742673Spetede 					    FALSE))
5752673Spetede 						s = procbuf;
5762673Spetede 				} else if (strcmp(namebuf, "CPU") == 0) {
5772673Spetede 					if (cpu(procbuf, sizeof (procbuf)))
5782673Spetede 						s = procbuf;
5792673Spetede 				} else if (strcmp(namebuf, "HOST") == 0) {
5800Sstevel@tonic-gate 					(void) uname(&name);
5810Sstevel@tonic-gate 					s = name.nodename;
5822673Spetede 				} else if (strcmp(namebuf, "KARCH") == 0) {
5832673Spetede 					if (arch(procbuf, sizeof (procbuf),
5842673Spetede 					    TRUE))
5852673Spetede 						s = procbuf;
5860Sstevel@tonic-gate 				} else if (strcmp(namebuf, "OSREL") == 0) {
5870Sstevel@tonic-gate 					(void) uname(&name);
5880Sstevel@tonic-gate 					s = name.release;
5890Sstevel@tonic-gate 				} else if (strcmp(namebuf, "OSNAME") == 0) {
5900Sstevel@tonic-gate 					(void) uname(&name);
5910Sstevel@tonic-gate 					s = name.sysname;
5920Sstevel@tonic-gate 				} else if (strcmp(namebuf, "OSVERS") == 0) {
5930Sstevel@tonic-gate 					(void) uname(&name);
5940Sstevel@tonic-gate 					s = name.version;
5950Sstevel@tonic-gate 				} else if (strcmp(namebuf, "NATISA") == 0) {
5960Sstevel@tonic-gate 					if (natisa(isaname, sizeof (isaname)))
5970Sstevel@tonic-gate 						s = isaname;
5982673Spetede 				} else if (strcmp(namebuf, "PLATFORM") == 0) {
5992673Spetede 					if (platform(procbuf, sizeof (procbuf)))
6002673Spetede 						s = procbuf;
6010Sstevel@tonic-gate 				}
6020Sstevel@tonic-gate 			}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 			if (s) {
6050Sstevel@tonic-gate 				if ((int)((bp - buffp) + strlen(s)) < size) {
6060Sstevel@tonic-gate 					while (*s) {
6070Sstevel@tonic-gate 						*bp++ = *s++;
6080Sstevel@tonic-gate 						*bq++ = ' ';
6090Sstevel@tonic-gate 					}
6100Sstevel@tonic-gate 				} else {
6110Sstevel@tonic-gate 					/*
6120Sstevel@tonic-gate 					 * line too long...
6130Sstevel@tonic-gate 					 */
6140Sstevel@tonic-gate 					return (1);
6150Sstevel@tonic-gate 				}
6160Sstevel@tonic-gate 			}
6170Sstevel@tonic-gate 			expand++;
6180Sstevel@tonic-gate 			continue;
6190Sstevel@tonic-gate 		}
6200Sstevel@tonic-gate 		/*
6210Sstevel@tonic-gate 		 * Since buffp needs to be null terminated, we need to
6220Sstevel@tonic-gate 		 * check that there's still room in the buffer to
6230Sstevel@tonic-gate 		 * place at least two more characters, *p and the
6240Sstevel@tonic-gate 		 * terminating null.
6250Sstevel@tonic-gate 		 */
6260Sstevel@tonic-gate 		if (bp - buffp == size - 1) {
6270Sstevel@tonic-gate 			/*
6280Sstevel@tonic-gate 			 * There was not enough room for at least two more
6290Sstevel@tonic-gate 			 * characters, return with an error.
6300Sstevel@tonic-gate 			 */
6310Sstevel@tonic-gate 			return (1);
6320Sstevel@tonic-gate 		}
6330Sstevel@tonic-gate 		/*
6340Sstevel@tonic-gate 		 * The total number of characters so far better be less
6350Sstevel@tonic-gate 		 * than the size of buffer passed in.
6360Sstevel@tonic-gate 		 */
6370Sstevel@tonic-gate 		*bp++ = *p++;
6380Sstevel@tonic-gate 		*bq++ = *q++;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	}
6410Sstevel@tonic-gate 	if (!expand)
6420Sstevel@tonic-gate 		return (0);
6430Sstevel@tonic-gate 	*bp = '\0';
6440Sstevel@tonic-gate 	*bq = '\0';
6450Sstevel@tonic-gate 	/*
6460Sstevel@tonic-gate 	 * We know buffp/buffq will fit in pline/plineq since we
6470Sstevel@tonic-gate 	 * processed at most size characters.
6480Sstevel@tonic-gate 	 */
6490Sstevel@tonic-gate 	(void) strcpy(pline, buffp);
6500Sstevel@tonic-gate 	(void) strcpy(plineq, buffq);
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	return (0);
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate /*
6563767Sjs195444  * Removes backslashes, quotes and brackets from the string "str"
6573767Sjs195444  * and returns the quoting information in "qbuf". Character is
6583767Sjs195444  * considered escaped when it is
6593767Sjs195444  *
6603767Sjs195444  * 	preceded with '\'	e.g. \a
6613767Sjs195444  * 	within quotes		e.g. "string"
6623767Sjs195444  * 	a ':' in brackets 	e.g. [an:ip:6::ad::d:re:s:s]
6633767Sjs195444  *
6643767Sjs195444  * original str: 'the "brown" f\ox said: [fe80::20a:e4ff:fe35:8b0d]'
6653767Sjs195444  * unquoted str: 'the brown fox said: [fe80::20a:e4ff:fe35:8b0d]'
6663767Sjs195444  * and the qbuf: '    ^^^^^  ^             ^^   ^    ^    ^     '
6670Sstevel@tonic-gate  */
6680Sstevel@tonic-gate void
unquote(str,qbuf)6690Sstevel@tonic-gate unquote(str, qbuf)
6700Sstevel@tonic-gate 	char *str, *qbuf;
6710Sstevel@tonic-gate {
6723767Sjs195444 	register int escaped, inquote, inbracket, quoted;
6730Sstevel@tonic-gate 	register char *ip, *bp, *qp;
6740Sstevel@tonic-gate 	char buf[LINESZ];
6750Sstevel@tonic-gate 
6763767Sjs195444 	escaped = inquote = inbracket = quoted = 0;
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	for (ip = str, bp = buf, qp = qbuf; *ip; ip++) {
6790Sstevel@tonic-gate 		if (!escaped) {
6800Sstevel@tonic-gate 			if (*ip == '\\') {
6810Sstevel@tonic-gate 				escaped = 1;
6820Sstevel@tonic-gate 				quoted++;
6830Sstevel@tonic-gate 				continue;
6840Sstevel@tonic-gate 			} else
6850Sstevel@tonic-gate 			if (*ip == '"') {
6860Sstevel@tonic-gate 				inquote = !inquote;
6870Sstevel@tonic-gate 				quoted++;
6880Sstevel@tonic-gate 				continue;
6893767Sjs195444 			} else
6903767Sjs195444 			if (*ip == '[') {
6913767Sjs195444 				inbracket++;
6923767Sjs195444 				quoted++;
6933767Sjs195444 			} else
6943767Sjs195444 			if (*ip == ']') {
6953767Sjs195444 				if (inbracket > 0) inbracket--;
6960Sstevel@tonic-gate 			}
6970Sstevel@tonic-gate 		}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 		*bp++ = *ip;
7003767Sjs195444 		*qp++ = (inquote || escaped) ? '^'
7013767Sjs195444 				: ((inbracket && (*ip == ':')) ? '^' : ' ');
7020Sstevel@tonic-gate 		escaped = 0;
7030Sstevel@tonic-gate 	}
7043767Sjs195444 
7050Sstevel@tonic-gate 	*bp = '\0';
7060Sstevel@tonic-gate 	*qp = '\0';
7073767Sjs195444 
7080Sstevel@tonic-gate 	if (quoted)
7090Sstevel@tonic-gate 		(void) strcpy(str, buf);
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate /*
7133767Sjs195444  * If str is enclosed in [brackets], trim them off.
7143767Sjs195444  */
7153767Sjs195444 void
unbracket(s)7163767Sjs195444 unbracket(s)
7173767Sjs195444 	char **s;
7183767Sjs195444 {
7193767Sjs195444 	char *b = *s + strlen(*s) - 1;
7203767Sjs195444 
7213767Sjs195444 	if (*b == ']')
7223767Sjs195444 		*b = '\0';
7233767Sjs195444 	if (**s == '[')
7243767Sjs195444 		(*s)++;
7253767Sjs195444 }
7263767Sjs195444 
7273767Sjs195444 /*
7280Sstevel@tonic-gate  * Removes trailing spaces from string "s".
7290Sstevel@tonic-gate  */
7300Sstevel@tonic-gate void
trim(s)7310Sstevel@tonic-gate trim(s)
7320Sstevel@tonic-gate 	char *s;
7330Sstevel@tonic-gate {
7340Sstevel@tonic-gate 	char *p = &s[strlen(s) - 1];
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	while (p >= s && isspace(*(uchar_t *)p))
7370Sstevel@tonic-gate 		*p-- = '\0';
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate /*
7410Sstevel@tonic-gate  * try to allocate memory using malloc, if malloc fails, then flush the
7420Sstevel@tonic-gate  * rddir caches, and retry. If the second allocation after the readdir
7430Sstevel@tonic-gate  * caches have been flushed fails too, then return NULL to indicate
7440Sstevel@tonic-gate  * memory could not be allocated.
7450Sstevel@tonic-gate  */
7460Sstevel@tonic-gate char *
auto_rddir_malloc(unsigned nbytes)7470Sstevel@tonic-gate auto_rddir_malloc(unsigned nbytes)
7480Sstevel@tonic-gate {
7490Sstevel@tonic-gate 	char *p;
7500Sstevel@tonic-gate 	int again = 0;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	if ((p = malloc(nbytes)) == NULL) {
7530Sstevel@tonic-gate 		/*
7540Sstevel@tonic-gate 		 * No memory, free rddir caches and try again
7550Sstevel@tonic-gate 		 */
7560Sstevel@tonic-gate 		mutex_lock(&cleanup_lock);
7570Sstevel@tonic-gate 		cond_signal(&cleanup_start_cv);
7580Sstevel@tonic-gate 		if (cond_wait(&cleanup_done_cv, &cleanup_lock)) {
7590Sstevel@tonic-gate 			mutex_unlock(&cleanup_lock);
7600Sstevel@tonic-gate 			syslog(LOG_ERR, "auto_rddir_malloc interrupted\n");
7610Sstevel@tonic-gate 		} else {
7620Sstevel@tonic-gate 			mutex_unlock(&cleanup_lock);
7630Sstevel@tonic-gate 			again = 1;
7640Sstevel@tonic-gate 		}
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	if (again)
7680Sstevel@tonic-gate 		p = malloc(nbytes);
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	return (p);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate /*
7740Sstevel@tonic-gate  * try to strdup a string, if it fails, then flush the rddir caches,
7750Sstevel@tonic-gate  * and retry. If the second strdup fails, return NULL to indicate failure.
7760Sstevel@tonic-gate  */
7770Sstevel@tonic-gate char *
auto_rddir_strdup(const char * s1)7780Sstevel@tonic-gate auto_rddir_strdup(const char *s1)
7790Sstevel@tonic-gate {
7800Sstevel@tonic-gate 	char *s2;
7810Sstevel@tonic-gate 	int again = 0;
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	if ((s2 = strdup(s1)) == NULL) {
7840Sstevel@tonic-gate 		/*
7850Sstevel@tonic-gate 		 * No memory, free rddir caches and try again
7860Sstevel@tonic-gate 		 */
7870Sstevel@tonic-gate 		mutex_lock(&cleanup_lock);
7880Sstevel@tonic-gate 		cond_signal(&cleanup_start_cv);
7890Sstevel@tonic-gate 		if (cond_wait(&cleanup_done_cv, &cleanup_lock)) {
7900Sstevel@tonic-gate 			mutex_unlock(&cleanup_lock);
7910Sstevel@tonic-gate 			syslog(LOG_ERR, "auto_rddir_strdup interrupted\n");
7920Sstevel@tonic-gate 		} else {
7930Sstevel@tonic-gate 			mutex_unlock(&cleanup_lock);
7940Sstevel@tonic-gate 			again = 1;
7950Sstevel@tonic-gate 		}
7960Sstevel@tonic-gate 	}
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	if (again)
7990Sstevel@tonic-gate 		s2 = strdup(s1);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	return (s2);
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate /*
8050Sstevel@tonic-gate  * Returns a pointer to the entry corresponding to 'name' if found,
8060Sstevel@tonic-gate  * otherwise it returns NULL.
8070Sstevel@tonic-gate  */
8080Sstevel@tonic-gate struct dir_entry *
btree_lookup(struct dir_entry * head,char * name)8090Sstevel@tonic-gate btree_lookup(struct dir_entry *head, char *name)
8100Sstevel@tonic-gate {
8110Sstevel@tonic-gate 	register struct dir_entry *p;
8120Sstevel@tonic-gate 	register int direction;
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	for (p = head; p != NULL; ) {
8150Sstevel@tonic-gate 		direction = strcmp(name, p->name);
8160Sstevel@tonic-gate 		if (direction == 0)
8170Sstevel@tonic-gate 			return (p);
8180Sstevel@tonic-gate 		if (direction > 0)
8190Sstevel@tonic-gate 			p = p->right;
8200Sstevel@tonic-gate 		else p = p->left;
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 	return (NULL);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate /*
8260Sstevel@tonic-gate  * Add entry to binary tree
8270Sstevel@tonic-gate  * Duplicate entries are not added
8280Sstevel@tonic-gate  */
8290Sstevel@tonic-gate void
btree_enter(struct dir_entry ** head,struct dir_entry * ent)8300Sstevel@tonic-gate btree_enter(struct dir_entry **head, struct dir_entry *ent)
8310Sstevel@tonic-gate {
8320Sstevel@tonic-gate 	register struct dir_entry *p, *prev = NULL;
8330Sstevel@tonic-gate 	register int direction;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	ent->right = ent->left = NULL;
8360Sstevel@tonic-gate 	if (*head == NULL) {
8370Sstevel@tonic-gate 		*head = ent;
8380Sstevel@tonic-gate 		return;
8390Sstevel@tonic-gate 	}
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	for (p = *head; p != NULL; ) {
8420Sstevel@tonic-gate 		prev = p;
8430Sstevel@tonic-gate 		direction = strcmp(ent->name, p->name);
8440Sstevel@tonic-gate 		if (direction == 0) {
8450Sstevel@tonic-gate 			/*
8460Sstevel@tonic-gate 			 * entry already in btree
8470Sstevel@tonic-gate 			 */
8480Sstevel@tonic-gate 			return;
8490Sstevel@tonic-gate 		}
8500Sstevel@tonic-gate 		if (direction > 0)
8510Sstevel@tonic-gate 			p = p->right;
8520Sstevel@tonic-gate 		else p = p->left;
8530Sstevel@tonic-gate 	}
8540Sstevel@tonic-gate 	assert(prev != NULL);
8550Sstevel@tonic-gate 	if (direction > 0)
8560Sstevel@tonic-gate 		prev->right = ent;
8570Sstevel@tonic-gate 	else prev->left = ent;
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate /*
8610Sstevel@tonic-gate  * If entry doesn't exist already, add it to the linear list
8620Sstevel@tonic-gate  * after '*last' and to the binary tree list.
8630Sstevel@tonic-gate  * If '*last == NULL' then the list is walked till the end.
8640Sstevel@tonic-gate  * *last is always set to the new element after successful completion.
8650Sstevel@tonic-gate  * if entry already exists '*last' is only updated if not previously
8660Sstevel@tonic-gate  * provided.
8670Sstevel@tonic-gate  */
8680Sstevel@tonic-gate int
add_dir_entry(char * name,struct dir_entry ** list,struct dir_entry ** last)8690Sstevel@tonic-gate add_dir_entry(char *name, struct dir_entry **list, struct dir_entry **last)
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 	struct dir_entry *e, *l;
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	if ((*list != NULL) && (*last == NULL)) {
8740Sstevel@tonic-gate 		/*
8750Sstevel@tonic-gate 		 * walk the list to find last element
8760Sstevel@tonic-gate 		 */
8770Sstevel@tonic-gate 		for (l = *list; l != NULL; l = l->next)
8780Sstevel@tonic-gate 			*last = l;
8790Sstevel@tonic-gate 	}
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	if (btree_lookup(*list, name) == NULL) {
8820Sstevel@tonic-gate 		/*
8830Sstevel@tonic-gate 		 * not a duplicate, add it to list
8840Sstevel@tonic-gate 		 */
8850Sstevel@tonic-gate 		/* LINTED pointer alignment */
8860Sstevel@tonic-gate 		e = (struct dir_entry *)
887*13080SPavan.Mettu@Oracle.COM 		    auto_rddir_malloc(sizeof (struct dir_entry));
8880Sstevel@tonic-gate 		if (e == NULL)
8890Sstevel@tonic-gate 			return (ENOMEM);
8900Sstevel@tonic-gate 		(void) memset((char *)e, 0, sizeof (*e));
8910Sstevel@tonic-gate 		e->name = auto_rddir_strdup(name);
8920Sstevel@tonic-gate 		if (e->name == NULL) {
8930Sstevel@tonic-gate 			free(e);
8940Sstevel@tonic-gate 			return (ENOMEM);
8950Sstevel@tonic-gate 		}
8960Sstevel@tonic-gate 		e->next = NULL;
8970Sstevel@tonic-gate 		if (*list == NULL) {
8980Sstevel@tonic-gate 			/*
8990Sstevel@tonic-gate 			 * list is empty
9000Sstevel@tonic-gate 			 */
9010Sstevel@tonic-gate 			*list = *last = e;
9020Sstevel@tonic-gate 		} else {
9030Sstevel@tonic-gate 			/*
9040Sstevel@tonic-gate 			 * append to end of list
9050Sstevel@tonic-gate 			 */
9060Sstevel@tonic-gate 			assert(*last != NULL);
9070Sstevel@tonic-gate 			(*last)->next = e;
9080Sstevel@tonic-gate 			*last = e;
9090Sstevel@tonic-gate 		}
9100Sstevel@tonic-gate 		/*
9110Sstevel@tonic-gate 		 * add to binary tree
9120Sstevel@tonic-gate 		 */
9130Sstevel@tonic-gate 		btree_enter(list, e);
9140Sstevel@tonic-gate 	}
9150Sstevel@tonic-gate 	return (0);
9160Sstevel@tonic-gate }
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate /*
9190Sstevel@tonic-gate  * Print trace output.
9200Sstevel@tonic-gate  * Like fprintf(stderr, fmt, ...) except that if "id" is nonzero, the output
9210Sstevel@tonic-gate  * is preceeded by the ID of the calling thread.
9220Sstevel@tonic-gate  */
9230Sstevel@tonic-gate #define	FMT_BUFSIZ 1024
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate void
trace_prt(int id,char * fmt,...)9260Sstevel@tonic-gate trace_prt(int id, char *fmt, ...)
9270Sstevel@tonic-gate {
9280Sstevel@tonic-gate 	va_list args;
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	char buf[FMT_BUFSIZ];
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	if (id) {
9330Sstevel@tonic-gate 		(void) sprintf(buf, "t%u\t%s", thr_self(), fmt);
9340Sstevel@tonic-gate 		fmt = buf;
9350Sstevel@tonic-gate 	}
9360Sstevel@tonic-gate 	va_start(args, fmt);
9370Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, args);
9380Sstevel@tonic-gate 	va_end(args);
9390Sstevel@tonic-gate }
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate /*
9420Sstevel@tonic-gate  * Extract the isalist(5) for userland from the kernel.
9430Sstevel@tonic-gate  */
9440Sstevel@tonic-gate static char *
isalist(void)9450Sstevel@tonic-gate isalist(void)
9460Sstevel@tonic-gate {
9470Sstevel@tonic-gate 	char *buf;
9480Sstevel@tonic-gate 	size_t bufsize = BUFSIZ;	/* wild guess */
9490Sstevel@tonic-gate 	long ret;
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	buf = malloc(bufsize);
9520Sstevel@tonic-gate 	do {
9530Sstevel@tonic-gate 		ret = sysinfo(SI_ISALIST, buf, bufsize);
9540Sstevel@tonic-gate 		if (ret == -1l)
9550Sstevel@tonic-gate 			return (NULL);
9560Sstevel@tonic-gate 		if (ret > bufsize) {
9570Sstevel@tonic-gate 			bufsize = ret;
9580Sstevel@tonic-gate 			buf = realloc(buf, bufsize);
9590Sstevel@tonic-gate 		} else
9600Sstevel@tonic-gate 			break;
9610Sstevel@tonic-gate 	} while (buf != NULL);
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 	return (buf);
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate /*
9670Sstevel@tonic-gate  * Classify isa's as to bitness of the corresponding ABIs.
9680Sstevel@tonic-gate  * isa's which have no "official" system ABI are returned
9690Sstevel@tonic-gate  * unrecognised i.e. zero bits.
9700Sstevel@tonic-gate  */
9710Sstevel@tonic-gate static int
bitness(char * isaname)9720Sstevel@tonic-gate bitness(char *isaname)
9730Sstevel@tonic-gate {
9740Sstevel@tonic-gate 	if (strcmp(isaname, "sparc") == 0 ||
9750Sstevel@tonic-gate 	    strcmp(isaname, "i386") == 0)
9760Sstevel@tonic-gate 		return (32);
9770Sstevel@tonic-gate 
9782156Smaheshvs 	if (strcmp(isaname, "sparcv9") == 0 ||
9792156Smaheshvs 	    strcmp(isaname, "amd64") == 0)
9800Sstevel@tonic-gate 		return (64);
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	return (0);
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate /*
9862673Spetede  * Determine the application architecture (derived from uname -m) to expand
9872673Spetede  * the $ARCH and $KARCH macros.
9882673Spetede  *
9892673Spetede  * Like arch(1), we need to substitute "sun4" for "sun4u", "sun4v", ... for
9902673Spetede  * backward compatibility. When kflag is set (like arch -k), the unmodifed
9912673Spetede  * value is returned instead.
9922673Spetede  */
9932673Spetede static int
arch(char * buf,size_t bufsize,bool_t karch)9942673Spetede arch(char *buf, size_t bufsize, bool_t karch)
9952673Spetede {
9962673Spetede 	long ret;
9972673Spetede 
9982673Spetede 	ret = sysinfo(SI_MACHINE, buf, bufsize);
9992673Spetede 	if (ret == -1L)
10002673Spetede 		return (0);
10012673Spetede 	if (!karch && strncmp(buf, "sun4", 4) == 0)
10022673Spetede 		(void) strlcpy(buf, "sun4", bufsize);
10032673Spetede 	return (1);
10042673Spetede }
10052673Spetede 
10062673Spetede /*
10072673Spetede  * Determine the basic ISA (uname -p) to expand the $CPU macro.
10082673Spetede  */
10092673Spetede static int
cpu(char * buf,size_t bufsize)10102673Spetede cpu(char *buf, size_t bufsize)
10112673Spetede {
10122673Spetede 	long ret;
10132673Spetede 
10142673Spetede 	ret = sysinfo(SI_ARCHITECTURE, buf, bufsize);
10152673Spetede 	if (ret == -1L)
10162673Spetede 		return (0);
10172673Spetede 	else
10182673Spetede 		return (1);
10192673Spetede }
10202673Spetede 
10212673Spetede /*
10220Sstevel@tonic-gate  * Find the left-most element in the isalist that matches our idea of a
10230Sstevel@tonic-gate  * system ABI.
10240Sstevel@tonic-gate  *
10250Sstevel@tonic-gate  * On machines with only one ABI, this is usually the same as uname -p.
10260Sstevel@tonic-gate  */
10270Sstevel@tonic-gate static int
natisa(char * buf,size_t bufsize)10280Sstevel@tonic-gate natisa(char *buf, size_t bufsize)
10290Sstevel@tonic-gate {
10300Sstevel@tonic-gate 	int bits;
10310Sstevel@tonic-gate 	char *isa, *list;
10320Sstevel@tonic-gate 	char *lasts;
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	if ((list = isalist()) == NULL)
10350Sstevel@tonic-gate 		return (0);
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	for (isa = strtok_r(list, " ", &lasts);
10380Sstevel@tonic-gate 	    isa; isa = strtok_r(0, " ", &lasts))
10390Sstevel@tonic-gate 		if ((bits = bitness(isa)) != 0)
10400Sstevel@tonic-gate 			break;	/* ignore "extension" architectures */
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	if (isa == 0 || bits == 0) {
10430Sstevel@tonic-gate 		free(list);
10440Sstevel@tonic-gate 		return (0);	/* can't figure it out :( */
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	(void) strncpy(buf, isa, bufsize);
10480Sstevel@tonic-gate 	free(list);
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	return (1);
10510Sstevel@tonic-gate }
10522673Spetede 
10532673Spetede /*
10542673Spetede  * Determine the platform (uname -i) to expand the $PLATFORM macro.
10552673Spetede  */
10562673Spetede static int
platform(char * buf,size_t bufsize)10572673Spetede platform(char *buf, size_t bufsize)
10582673Spetede {
10592673Spetede 	long ret;
10602673Spetede 
10612673Spetede 	ret = sysinfo(SI_PLATFORM, buf, bufsize);
10622673Spetede 	if (ret == -1L)
10632673Spetede 		return (0);
10642673Spetede 	else
10652673Spetede 		return (1);
10662673Spetede }
10672673Spetede 
10682673Spetede /*
1069*13080SPavan.Mettu@Oracle.COM  * Set environment variables
10702673Spetede  */
10712673Spetede void
put_automountd_env(void)10722673Spetede put_automountd_env(void)
10732673Spetede {
1074*13080SPavan.Mettu@Oracle.COM 	char defval[PATH_MAX], *p, *a, *c;
1075*13080SPavan.Mettu@Oracle.COM 	int ret = 0, bufsz = PATH_MAX;
10762673Spetede 
1077*13080SPavan.Mettu@Oracle.COM 	ret = autofs_smf_get_prop("environment", defval, DEFAULT_INSTANCE,
1078*13080SPavan.Mettu@Oracle.COM 	    SCF_TYPE_ASTRING, AUTOMOUNTD, &bufsz);
1079*13080SPavan.Mettu@Oracle.COM 	if (ret == SA_OK) {
1080*13080SPavan.Mettu@Oracle.COM 		a = c = defval;
1081*13080SPavan.Mettu@Oracle.COM 		if (*a == NULL)
1082*13080SPavan.Mettu@Oracle.COM 			return;
1083*13080SPavan.Mettu@Oracle.COM 		/*
1084*13080SPavan.Mettu@Oracle.COM 		 * Environment variables can have more than one value
1085*13080SPavan.Mettu@Oracle.COM 		 * seperated by a comma and there can be multiple
1086*13080SPavan.Mettu@Oracle.COM 		 * environment variables. * a=b\,c,d=e. For multiple
1087*13080SPavan.Mettu@Oracle.COM 		 * valued environment variable, values are seperated
1088*13080SPavan.Mettu@Oracle.COM 		 * with an escape character.
1089*13080SPavan.Mettu@Oracle.COM 		 */
1090*13080SPavan.Mettu@Oracle.COM 		while ((p = strchr(c, ',')) != NULL) {
1091*13080SPavan.Mettu@Oracle.COM 			if (*(p - 1) == '\\') {
1092*13080SPavan.Mettu@Oracle.COM 				c = p + 1;
1093*13080SPavan.Mettu@Oracle.COM 				continue;
1094*13080SPavan.Mettu@Oracle.COM 			}
1095*13080SPavan.Mettu@Oracle.COM 			*p = '\0';
1096*13080SPavan.Mettu@Oracle.COM 			if ((c = strchr(a, '=')) != NULL)
1097*13080SPavan.Mettu@Oracle.COM 				putenv(strdup(a));
1098*13080SPavan.Mettu@Oracle.COM 			a = c = p + 1;
1099*13080SPavan.Mettu@Oracle.COM 		}
1100*13080SPavan.Mettu@Oracle.COM 		if (*a != NULL) {
1101*13080SPavan.Mettu@Oracle.COM 			if ((c = strchr(a, '=')) != NULL)
1102*13080SPavan.Mettu@Oracle.COM 				putenv(strdup(a));
1103*13080SPavan.Mettu@Oracle.COM 		}
11042673Spetede 	}
11052673Spetede }
1106