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 5*1676Sjpk * Common Development and Distribution License (the "License"). 6*1676Sjpk * 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*1676Sjpk * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*1676Sjpk * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <ctype.h> 290Sstevel@tonic-gate #include <stdio.h> 300Sstevel@tonic-gate #include <stdlib.h> 310Sstevel@tonic-gate #include <unistd.h> 320Sstevel@tonic-gate #include <locale.h> 330Sstevel@tonic-gate #include <syslog.h> 340Sstevel@tonic-gate #include <errno.h> 350Sstevel@tonic-gate #include <string.h> 360Sstevel@tonic-gate #include <stdarg.h> 370Sstevel@tonic-gate #include <dirent.h> 380Sstevel@tonic-gate #include <thread.h> 390Sstevel@tonic-gate #include <sys/param.h> 400Sstevel@tonic-gate #include <sys/time.h> 410Sstevel@tonic-gate #include <sys/vfs.h> 420Sstevel@tonic-gate #include <sys/types.h> 430Sstevel@tonic-gate #include <sys/stat.h> 440Sstevel@tonic-gate #include <sys/mnttab.h> 450Sstevel@tonic-gate #include <sys/mntent.h> 460Sstevel@tonic-gate #include <sys/mount.h> 470Sstevel@tonic-gate #include <sys/signal.h> 480Sstevel@tonic-gate #include <sys/utsname.h> 490Sstevel@tonic-gate #include <sys/systeminfo.h> 500Sstevel@tonic-gate #include <sys/tiuser.h> 510Sstevel@tonic-gate #include <sys/utsname.h> 520Sstevel@tonic-gate #include <rpc/rpc.h> 530Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h> 540Sstevel@tonic-gate #include <assert.h> 550Sstevel@tonic-gate #include "automount.h" 56*1676Sjpk #include <zone.h> 57*1676Sjpk #include <priv.h> 58*1676Sjpk #include <fcntl.h> 590Sstevel@tonic-gate 600Sstevel@tonic-gate static char *check_hier(char *); 610Sstevel@tonic-gate static int natisa(char *, size_t); 620Sstevel@tonic-gate 630Sstevel@tonic-gate struct mntlist *current_mounts; 640Sstevel@tonic-gate 650Sstevel@tonic-gate static bool_t nodirect_map = FALSE; 660Sstevel@tonic-gate 67*1676Sjpk /* 68*1676Sjpk * If the system is labeled then we need to 69*1676Sjpk * have a uniquely-named auto_home map for each zone. 70*1676Sjpk * The maps are made unique by appending the zonename. 71*1676Sjpk * The home directory is made unique by prepending /zone/<zonename> 72*1676Sjpk * for each zone that is dominated by the current zone. 73*1676Sjpk * The current zone's home directory mount point is not changed. 74*1676Sjpk * 75*1676Sjpk * For each auto_home_<zonename> a default template map is created 76*1676Sjpk * only if it doesn't exist yet. The default entry is used to declare 77*1676Sjpk * local home directories created within each zone. For example: 78*1676Sjpk * 79*1676Sjpk * +auto_home_public 80*1676Sjpk * * -fstype=lofs :/zone/public/export/home/& 81*1676Sjpk */ 82*1676Sjpk static void 83*1676Sjpk loadzone_maps(char *mntpnt, char *map, char *opts, char **stack, char ***stkptr) 84*1676Sjpk { 85*1676Sjpk zoneid_t *zids = NULL; 86*1676Sjpk zoneid_t my_zoneid; 87*1676Sjpk uint_t nzents_saved; 88*1676Sjpk uint_t nzents; 89*1676Sjpk int i; 90*1676Sjpk 91*1676Sjpk if (!priv_ineffect(PRIV_SYS_MOUNT)) 92*1676Sjpk return; 93*1676Sjpk 94*1676Sjpk if (zone_list(NULL, &nzents) != 0) { 95*1676Sjpk return; 96*1676Sjpk } 97*1676Sjpk my_zoneid = getzoneid(); 98*1676Sjpk again: 99*1676Sjpk if (nzents == 0) 100*1676Sjpk return; 101*1676Sjpk 102*1676Sjpk zids = malloc(nzents * sizeof (zoneid_t)); 103*1676Sjpk nzents_saved = nzents; 104*1676Sjpk 105*1676Sjpk if (zone_list(zids, &nzents) != 0) { 106*1676Sjpk free(zids); 107*1676Sjpk return; 108*1676Sjpk } 109*1676Sjpk if (nzents != nzents_saved) { 110*1676Sjpk /* list changed, try again */ 111*1676Sjpk free(zids); 112*1676Sjpk goto again; 113*1676Sjpk } 114*1676Sjpk 115*1676Sjpk for (i = 0; i < nzents; i++) { 116*1676Sjpk char zonename[ZONENAME_MAX]; 117*1676Sjpk char zoneroot[MAXPATHLEN]; 118*1676Sjpk 119*1676Sjpk if (getzonenamebyid(zids[i], zonename, ZONENAME_MAX) != -1) { 120*1676Sjpk char appended_map[MAXPATHLEN]; 121*1676Sjpk char prepended_mntpnt[MAXPATHLEN]; 122*1676Sjpk char map_path[MAXPATHLEN]; 123*1676Sjpk int fd; 124*1676Sjpk 125*1676Sjpk (void) snprintf(appended_map, sizeof (appended_map), 126*1676Sjpk "%s_%s", map, zonename); 127*1676Sjpk 128*1676Sjpk /* for current zone, leave mntpnt alone */ 129*1676Sjpk if (zids[i] != my_zoneid) { 130*1676Sjpk (void) snprintf(prepended_mntpnt, 131*1676Sjpk sizeof (prepended_mntpnt), 132*1676Sjpk "/zone/%s%s", zonename, mntpnt); 133*1676Sjpk if (zone_getattr(zids[i], ZONE_ATTR_ROOT, 134*1676Sjpk zoneroot, sizeof (zoneroot)) == -1) 135*1676Sjpk continue; 136*1676Sjpk } else { 137*1676Sjpk (void) strcpy(prepended_mntpnt, mntpnt); 138*1676Sjpk zoneroot[0] = '\0'; 139*1676Sjpk } 140*1676Sjpk 141*1676Sjpk dirinit(prepended_mntpnt, appended_map, opts, 0, stack, 142*1676Sjpk stkptr); 143*1676Sjpk /* 144*1676Sjpk * Next create auto_home_<zone> maps for each zone 145*1676Sjpk */ 146*1676Sjpk 147*1676Sjpk (void) snprintf(map_path, sizeof (map_path), 148*1676Sjpk "/etc/%s", appended_map); 149*1676Sjpk /* 150*1676Sjpk * If the map file doesn't exist create a template 151*1676Sjpk */ 152*1676Sjpk if ((fd = open(map_path, O_RDWR | O_CREAT | O_EXCL, 153*1676Sjpk S_IRUSR | S_IWUSR | S_IRGRP| S_IROTH)) != -1) { 154*1676Sjpk int len; 155*1676Sjpk char map_rec[MAXPATHLEN]; 156*1676Sjpk 157*1676Sjpk len = snprintf(map_rec, sizeof (map_rec), 158*1676Sjpk "+%s\n*\t-fstype=lofs\t:%s/export/home/&\n", 159*1676Sjpk appended_map, zoneroot); 160*1676Sjpk if (len <= sizeof (map_rec)) 161*1676Sjpk (void) write(fd, map_rec, len); 162*1676Sjpk (void) close(fd); 163*1676Sjpk } 164*1676Sjpk } 165*1676Sjpk } 166*1676Sjpk free(zids); 167*1676Sjpk } 168*1676Sjpk 1690Sstevel@tonic-gate void 1700Sstevel@tonic-gate dirinit(char *mntpnt, char *map, char *opts, int direct, char **stack, 171*1676Sjpk char ***stkptr) 1720Sstevel@tonic-gate { 1730Sstevel@tonic-gate struct autodir *dir; 1740Sstevel@tonic-gate char *p; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate if (strcmp(map, "-null") == 0) { 1770Sstevel@tonic-gate if (strcmp(mntpnt, "/-") == 0) 1780Sstevel@tonic-gate nodirect_map = TRUE; 1790Sstevel@tonic-gate goto enter; 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate p = mntpnt + (strlen(mntpnt) - 1); 1830Sstevel@tonic-gate if (*p == '/') 1840Sstevel@tonic-gate *p = '\0'; /* trim trailing / */ 1850Sstevel@tonic-gate if (*mntpnt != '/') { 1860Sstevel@tonic-gate pr_msg("dir %s must start with '/'", mntpnt); 1870Sstevel@tonic-gate return; 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate if (p = check_hier(mntpnt)) { 1900Sstevel@tonic-gate pr_msg("hierarchical mountpoint: %s and %s", 1910Sstevel@tonic-gate p, mntpnt); 1920Sstevel@tonic-gate return; 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate /* 1960Sstevel@tonic-gate * If it's a direct map then call dirinit 1970Sstevel@tonic-gate * for every map entry. 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate if ((strcmp(mntpnt, "/-") == 0) && !(nodirect_map)) { 2000Sstevel@tonic-gate (void) loaddirect_map(map, map, opts, stack, stkptr); 2010Sstevel@tonic-gate return; 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate 204*1676Sjpk /* 205*1676Sjpk * Home directories are polyinstantiated on 206*1676Sjpk * labeled systems. 207*1676Sjpk */ 208*1676Sjpk if (is_system_labeled() && 209*1676Sjpk (strcmp(mntpnt, "/home") == 0) && 210*1676Sjpk (strcmp(map, "auto_home") == 0)) { 211*1676Sjpk (void) loadzone_maps(mntpnt, map, opts, stack, stkptr); 212*1676Sjpk return; 213*1676Sjpk } 2140Sstevel@tonic-gate enter: 2150Sstevel@tonic-gate dir = (struct autodir *)malloc(sizeof (*dir)); 2160Sstevel@tonic-gate if (dir == NULL) 2170Sstevel@tonic-gate goto alloc_failed; 2180Sstevel@tonic-gate dir->dir_name = strdup(mntpnt); 2190Sstevel@tonic-gate if (dir->dir_name == NULL) 2200Sstevel@tonic-gate goto alloc_failed; 2210Sstevel@tonic-gate dir->dir_map = strdup(map); 2220Sstevel@tonic-gate if (dir->dir_map == NULL) 2230Sstevel@tonic-gate goto alloc_failed; 2240Sstevel@tonic-gate dir->dir_opts = strdup(opts); 2250Sstevel@tonic-gate if (dir->dir_opts == NULL) 2260Sstevel@tonic-gate goto alloc_failed; 2270Sstevel@tonic-gate dir->dir_direct = direct; 2280Sstevel@tonic-gate dir->dir_remount = 0; 2290Sstevel@tonic-gate dir->dir_next = NULL; 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* 2320Sstevel@tonic-gate * Append to dir chain 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate if (dir_head == NULL) 2350Sstevel@tonic-gate dir_head = dir; 2360Sstevel@tonic-gate else 2370Sstevel@tonic-gate dir_tail->dir_next = dir; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate dir->dir_prev = dir_tail; 2400Sstevel@tonic-gate dir_tail = dir; 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate return; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate alloc_failed: 2450Sstevel@tonic-gate if (dir != NULL) { 2460Sstevel@tonic-gate if (dir->dir_opts) 2470Sstevel@tonic-gate free(dir->dir_opts); 2480Sstevel@tonic-gate if (dir->dir_map) 2490Sstevel@tonic-gate free(dir->dir_map); 2500Sstevel@tonic-gate if (dir->dir_name) 2510Sstevel@tonic-gate free(dir->dir_name); 2520Sstevel@tonic-gate free(dir); 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate pr_msg("dirinit: memory allocation failed"); 2550Sstevel@tonic-gate } 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* 2580Sstevel@tonic-gate * Check whether the mount point is a 2590Sstevel@tonic-gate * subdirectory or a parent directory 2600Sstevel@tonic-gate * of any previously mounted automount 2610Sstevel@tonic-gate * mount point. 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate static char * 2640Sstevel@tonic-gate check_hier(mntpnt) 2650Sstevel@tonic-gate char *mntpnt; 2660Sstevel@tonic-gate { 2670Sstevel@tonic-gate register struct autodir *dir; 2680Sstevel@tonic-gate register char *p, *q; 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate for (dir = dir_head; dir; dir = dir->dir_next) { 2710Sstevel@tonic-gate p = dir->dir_name; 2720Sstevel@tonic-gate q = mntpnt; 2730Sstevel@tonic-gate for (; *p == *q; p++, q++) 2740Sstevel@tonic-gate if (*p == '\0') 2750Sstevel@tonic-gate break; 2760Sstevel@tonic-gate if (*p == '/' && *q == '\0') 2770Sstevel@tonic-gate return (dir->dir_name); 2780Sstevel@tonic-gate if (*p == '\0' && *q == '/') 2790Sstevel@tonic-gate return (dir->dir_name); 2800Sstevel@tonic-gate if (*p == '\0' && *q == '\0') 2810Sstevel@tonic-gate return (NULL); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate return (NULL); /* it's not a subdir or parent */ 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * Gets the next token from the string "p" and copies 2880Sstevel@tonic-gate * it into "w". Both "wq" and "w" are quote vectors 2890Sstevel@tonic-gate * for "w" and "p". Delim is the character to be used 2900Sstevel@tonic-gate * as a delimiter for the scan. A space means "whitespace". 2910Sstevel@tonic-gate * The call to getword must provide buffers w and wq of size at 2920Sstevel@tonic-gate * least wordsz. getword() will pass strings of maximum length 2930Sstevel@tonic-gate * (wordsz-1), since it needs to null terminate the string. 2940Sstevel@tonic-gate * Returns 0 on ok and -1 on error. 2950Sstevel@tonic-gate */ 2960Sstevel@tonic-gate int 2970Sstevel@tonic-gate getword(char *w, char *wq, char **p, char **pq, char delim, int wordsz) 2980Sstevel@tonic-gate { 2990Sstevel@tonic-gate char *tmp = w; 3000Sstevel@tonic-gate char *tmpq = wq; 3010Sstevel@tonic-gate int count = wordsz; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate if (wordsz <= 0) { 3040Sstevel@tonic-gate if (verbose) 3050Sstevel@tonic-gate syslog(LOG_ERR, 3060Sstevel@tonic-gate "getword: input word size %d must be > 0", wordsz); 3070Sstevel@tonic-gate return (-1); 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate while ((delim == ' ' ? isspace(**p) : **p == delim) && **pq == ' ') 3110Sstevel@tonic-gate (*p)++, (*pq)++; 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate while (**p && 3140Sstevel@tonic-gate !((delim == ' ' ? isspace(**p) : **p == delim) && 3150Sstevel@tonic-gate **pq == ' ')) { 3160Sstevel@tonic-gate if (--count <= 0) { 3170Sstevel@tonic-gate *tmp = '\0'; 3180Sstevel@tonic-gate *tmpq = '\0'; 3190Sstevel@tonic-gate syslog(LOG_ERR, 3200Sstevel@tonic-gate "maximum word length (%d) exceeded", wordsz); 3210Sstevel@tonic-gate return (-1); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate *w++ = *(*p)++; 3240Sstevel@tonic-gate *wq++ = *(*pq)++; 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate *w = '\0'; 3270Sstevel@tonic-gate *wq = '\0'; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate return (0); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * get_line attempts to get a line from the map, upto LINESZ. A line in 3340Sstevel@tonic-gate * the map is a concatenation of lines if the continuation symbol '\' 3350Sstevel@tonic-gate * is used at the end of the line. Returns line on success, a NULL on 3360Sstevel@tonic-gate * EOF, and an empty string on lines > linesz. 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate char * 3390Sstevel@tonic-gate get_line(FILE *fp, char *map, char *line, int linesz) 3400Sstevel@tonic-gate { 3410Sstevel@tonic-gate register char *p = line; 3420Sstevel@tonic-gate register int len; 3430Sstevel@tonic-gate int excess = 0; 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate *p = '\0'; 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate for (;;) { 3480Sstevel@tonic-gate if (fgets(p, linesz - (p-line), fp) == NULL) { 3490Sstevel@tonic-gate return (*line ? line : NULL); /* EOF */ 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate len = strlen(line); 3530Sstevel@tonic-gate if (len <= 0) { 3540Sstevel@tonic-gate p = line; 3550Sstevel@tonic-gate continue; 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate p = &line[len - 1]; 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate /* 3600Sstevel@tonic-gate * Is input line too long? 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate if (*p != '\n') { 3630Sstevel@tonic-gate excess = 1; 3640Sstevel@tonic-gate /* 3650Sstevel@tonic-gate * Perhaps last char read was '\'. Reinsert it 3660Sstevel@tonic-gate * into the stream to ease the parsing when we 3670Sstevel@tonic-gate * read the rest of the line to discard. 3680Sstevel@tonic-gate */ 3690Sstevel@tonic-gate (void) ungetc(*p, fp); 3700Sstevel@tonic-gate break; 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate trim: 3730Sstevel@tonic-gate /* trim trailing white space */ 3740Sstevel@tonic-gate while (p >= line && isspace(*(uchar_t *)p)) 3750Sstevel@tonic-gate *p-- = '\0'; 3760Sstevel@tonic-gate if (p < line) { /* empty line */ 3770Sstevel@tonic-gate p = line; 3780Sstevel@tonic-gate continue; 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate if (*p == '\\') { /* continuation */ 3820Sstevel@tonic-gate *p = '\0'; 3830Sstevel@tonic-gate continue; 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate /* 3870Sstevel@tonic-gate * Ignore comments. Comments start with '#' 3880Sstevel@tonic-gate * which must be preceded by a whitespace, unless 3890Sstevel@tonic-gate * if '#' is the first character in the line. 3900Sstevel@tonic-gate */ 3910Sstevel@tonic-gate p = line; 3920Sstevel@tonic-gate while (p = strchr(p, '#')) { 3930Sstevel@tonic-gate if (p == line || isspace(*(p-1))) { 3940Sstevel@tonic-gate *p-- = '\0'; 3950Sstevel@tonic-gate goto trim; 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate p++; 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate break; 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate if (excess) { 4020Sstevel@tonic-gate int c; 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate /* 4050Sstevel@tonic-gate * discard rest of line and return an empty string. 4060Sstevel@tonic-gate * done to set the stream to the correct place when 4070Sstevel@tonic-gate * we are done with this line. 4080Sstevel@tonic-gate */ 4090Sstevel@tonic-gate while ((c = getc(fp)) != EOF) { 4100Sstevel@tonic-gate *p = c; 4110Sstevel@tonic-gate if (*p == '\n') /* end of the long line */ 4120Sstevel@tonic-gate break; 4130Sstevel@tonic-gate else if (*p == '\\') { /* continuation */ 4140Sstevel@tonic-gate if (getc(fp) == EOF) /* ignore next char */ 4150Sstevel@tonic-gate break; 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate syslog(LOG_ERR, 4190Sstevel@tonic-gate "map %s: line too long (max %d chars)", 4200Sstevel@tonic-gate map, linesz-1); 4210Sstevel@tonic-gate *line = '\0'; 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate return (line); 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate /* 4280Sstevel@tonic-gate * Gets the retry=n entry from opts. 4290Sstevel@tonic-gate * Returns 0 if retry=n is not present in option string, 4300Sstevel@tonic-gate * retry=n is invalid, or when option string is NULL. 4310Sstevel@tonic-gate */ 4320Sstevel@tonic-gate int 4330Sstevel@tonic-gate get_retry(char *opts) 4340Sstevel@tonic-gate { 4350Sstevel@tonic-gate int retry = 0; 4360Sstevel@tonic-gate char buf[MAXOPTSLEN]; 4370Sstevel@tonic-gate char *p, *pb, *lasts; 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate if (opts == NULL) 4400Sstevel@tonic-gate return (retry); 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate (void) strcpy(buf, opts); 4430Sstevel@tonic-gate pb = buf; 4440Sstevel@tonic-gate while (p = (char *)strtok_r(pb, ",", &lasts)) { 4450Sstevel@tonic-gate pb = NULL; 4460Sstevel@tonic-gate if (strncmp(p, "retry=", 6) == 0) 4470Sstevel@tonic-gate retry = atoi(p+6); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate return (retry > 0 ? retry : 0); 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate /* 4530Sstevel@tonic-gate * Returns zero if "opt" is found in mnt->mnt_opts, setting 4540Sstevel@tonic-gate * *sval to whatever follows the equal sign after "opt". 4550Sstevel@tonic-gate * str_opt allocates a string long enough to store the value of 4560Sstevel@tonic-gate * "opt" plus a terminating null character and returns it as *sval. 4570Sstevel@tonic-gate * It is the responsability of the caller to deallocate *sval. 4580Sstevel@tonic-gate * *sval will be equal to NULL upon return if either "opt=" is not found, 4590Sstevel@tonic-gate * or "opt=" has no value associated with it. 4600Sstevel@tonic-gate * 4610Sstevel@tonic-gate * stropt will return -1 on error. 4620Sstevel@tonic-gate */ 4630Sstevel@tonic-gate int 4640Sstevel@tonic-gate str_opt(struct mnttab *mnt, char *opt, char **sval) 4650Sstevel@tonic-gate { 4660Sstevel@tonic-gate char *str, *comma; 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate /* 4690Sstevel@tonic-gate * is "opt" in the options field? 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate if (str = hasmntopt(mnt, opt)) { 4720Sstevel@tonic-gate str += strlen(opt); 4730Sstevel@tonic-gate if (*str++ != '=' || 4740Sstevel@tonic-gate (*str == ',' || *str == '\0')) { 4750Sstevel@tonic-gate syslog(LOG_ERR, "Bad option field"); 4760Sstevel@tonic-gate return (-1); 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate comma = strchr(str, ','); 4790Sstevel@tonic-gate if (comma != NULL) 4800Sstevel@tonic-gate *comma = '\0'; 4810Sstevel@tonic-gate *sval = strdup(str); 4820Sstevel@tonic-gate if (comma != NULL) 4830Sstevel@tonic-gate *comma = ','; 4840Sstevel@tonic-gate if (*sval == NULL) 4850Sstevel@tonic-gate return (-1); 4860Sstevel@tonic-gate } else 4870Sstevel@tonic-gate *sval = NULL; 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate return (0); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate /* 4930Sstevel@tonic-gate * Performs text expansions in the string "pline". 4940Sstevel@tonic-gate * "plineq" is the quote vector for "pline". 4950Sstevel@tonic-gate * An identifier prefixed by "$" is replaced by the 4960Sstevel@tonic-gate * corresponding environment variable string. A "&" 4970Sstevel@tonic-gate * is replaced by the key string for the map entry. 4980Sstevel@tonic-gate * 4990Sstevel@tonic-gate * This routine will return an error (non-zero) if *size* would be 5000Sstevel@tonic-gate * exceeded after expansion, indicating that the macro_expand failed. 5010Sstevel@tonic-gate * This is to prevent writing past the end of pline and plineq. 5020Sstevel@tonic-gate * Both pline and plineq are left untouched in such error case. 5030Sstevel@tonic-gate */ 5040Sstevel@tonic-gate int 5050Sstevel@tonic-gate macro_expand(key, pline, plineq, size) 5060Sstevel@tonic-gate char *key, *pline, *plineq; 5070Sstevel@tonic-gate int size; 5080Sstevel@tonic-gate { 5090Sstevel@tonic-gate register char *p, *q; 5100Sstevel@tonic-gate register char *bp, *bq; 5110Sstevel@tonic-gate register char *s; 5120Sstevel@tonic-gate char buffp[LINESZ], buffq[LINESZ]; 5130Sstevel@tonic-gate char namebuf[64], *pn; 5140Sstevel@tonic-gate int expand = 0; 5150Sstevel@tonic-gate struct utsname name; 5160Sstevel@tonic-gate char isaname[64]; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate p = pline; q = plineq; 5190Sstevel@tonic-gate bp = buffp; bq = buffq; 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate while (*p) { 5220Sstevel@tonic-gate if (*p == '&' && *q == ' ') { /* insert key */ 5230Sstevel@tonic-gate /* 5240Sstevel@tonic-gate * make sure we don't overflow buffer 5250Sstevel@tonic-gate */ 5260Sstevel@tonic-gate if ((int)((bp - buffp) + strlen(key)) < size) { 5270Sstevel@tonic-gate for (s = key; *s; s++) { 5280Sstevel@tonic-gate *bp++ = *s; 5290Sstevel@tonic-gate *bq++ = ' '; 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate expand++; 5320Sstevel@tonic-gate p++; q++; 5330Sstevel@tonic-gate continue; 5340Sstevel@tonic-gate } else { 5350Sstevel@tonic-gate /* 5360Sstevel@tonic-gate * line too long... 5370Sstevel@tonic-gate */ 5380Sstevel@tonic-gate return (1); 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate if (*p == '$' && *q == ' ') { /* insert env var */ 5430Sstevel@tonic-gate p++; q++; 5440Sstevel@tonic-gate pn = namebuf; 5450Sstevel@tonic-gate if (*p == '{') { 5460Sstevel@tonic-gate p++; q++; 5470Sstevel@tonic-gate while (*p && *p != '}') { 5480Sstevel@tonic-gate *pn++ = *p++; 5490Sstevel@tonic-gate q++; 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate if (*p) { 5520Sstevel@tonic-gate p++; q++; 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate } else { 5550Sstevel@tonic-gate while (*p && (*p == '_' || isalnum(*p))) { 5560Sstevel@tonic-gate *pn++ = *p++; 5570Sstevel@tonic-gate q++; 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate *pn = '\0'; 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate s = getenv(namebuf); 5630Sstevel@tonic-gate if (!s) { 5640Sstevel@tonic-gate /* not found in env */ 5650Sstevel@tonic-gate if (strcmp(namebuf, "HOST") == 0) { 5660Sstevel@tonic-gate (void) uname(&name); 5670Sstevel@tonic-gate s = name.nodename; 5680Sstevel@tonic-gate } else if (strcmp(namebuf, "OSREL") == 0) { 5690Sstevel@tonic-gate (void) uname(&name); 5700Sstevel@tonic-gate s = name.release; 5710Sstevel@tonic-gate } else if (strcmp(namebuf, "OSNAME") == 0) { 5720Sstevel@tonic-gate (void) uname(&name); 5730Sstevel@tonic-gate s = name.sysname; 5740Sstevel@tonic-gate } else if (strcmp(namebuf, "OSVERS") == 0) { 5750Sstevel@tonic-gate (void) uname(&name); 5760Sstevel@tonic-gate s = name.version; 5770Sstevel@tonic-gate } else if (strcmp(namebuf, "NATISA") == 0) { 5780Sstevel@tonic-gate if (natisa(isaname, sizeof (isaname))) 5790Sstevel@tonic-gate s = isaname; 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (s) { 5840Sstevel@tonic-gate if ((int)((bp - buffp) + strlen(s)) < size) { 5850Sstevel@tonic-gate while (*s) { 5860Sstevel@tonic-gate *bp++ = *s++; 5870Sstevel@tonic-gate *bq++ = ' '; 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate } else { 5900Sstevel@tonic-gate /* 5910Sstevel@tonic-gate * line too long... 5920Sstevel@tonic-gate */ 5930Sstevel@tonic-gate return (1); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate expand++; 5970Sstevel@tonic-gate continue; 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate /* 6000Sstevel@tonic-gate * Since buffp needs to be null terminated, we need to 6010Sstevel@tonic-gate * check that there's still room in the buffer to 6020Sstevel@tonic-gate * place at least two more characters, *p and the 6030Sstevel@tonic-gate * terminating null. 6040Sstevel@tonic-gate */ 6050Sstevel@tonic-gate if (bp - buffp == size - 1) { 6060Sstevel@tonic-gate /* 6070Sstevel@tonic-gate * There was not enough room for at least two more 6080Sstevel@tonic-gate * characters, return with an error. 6090Sstevel@tonic-gate */ 6100Sstevel@tonic-gate return (1); 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate /* 6130Sstevel@tonic-gate * The total number of characters so far better be less 6140Sstevel@tonic-gate * than the size of buffer passed in. 6150Sstevel@tonic-gate */ 6160Sstevel@tonic-gate *bp++ = *p++; 6170Sstevel@tonic-gate *bq++ = *q++; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate if (!expand) 6210Sstevel@tonic-gate return (0); 6220Sstevel@tonic-gate *bp = '\0'; 6230Sstevel@tonic-gate *bq = '\0'; 6240Sstevel@tonic-gate /* 6250Sstevel@tonic-gate * We know buffp/buffq will fit in pline/plineq since we 6260Sstevel@tonic-gate * processed at most size characters. 6270Sstevel@tonic-gate */ 6280Sstevel@tonic-gate (void) strcpy(pline, buffp); 6290Sstevel@tonic-gate (void) strcpy(plineq, buffq); 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate return (0); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate /* 6350Sstevel@tonic-gate * Removes quotes from the string "str" and returns 6360Sstevel@tonic-gate * the quoting information in "qbuf". e.g. 6370Sstevel@tonic-gate * original str: 'the "quick brown" f\ox' 6380Sstevel@tonic-gate * unquoted str: 'the quick brown fox' 6390Sstevel@tonic-gate * and the qbuf: ' ^^^^^^^^^^^ ^ ' 6400Sstevel@tonic-gate */ 6410Sstevel@tonic-gate void 6420Sstevel@tonic-gate unquote(str, qbuf) 6430Sstevel@tonic-gate char *str, *qbuf; 6440Sstevel@tonic-gate { 6450Sstevel@tonic-gate register int escaped, inquote, quoted; 6460Sstevel@tonic-gate register char *ip, *bp, *qp; 6470Sstevel@tonic-gate char buf[LINESZ]; 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate escaped = inquote = quoted = 0; 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate for (ip = str, bp = buf, qp = qbuf; *ip; ip++) { 6520Sstevel@tonic-gate if (!escaped) { 6530Sstevel@tonic-gate if (*ip == '\\') { 6540Sstevel@tonic-gate escaped = 1; 6550Sstevel@tonic-gate quoted++; 6560Sstevel@tonic-gate continue; 6570Sstevel@tonic-gate } else 6580Sstevel@tonic-gate if (*ip == '"') { 6590Sstevel@tonic-gate inquote = !inquote; 6600Sstevel@tonic-gate quoted++; 6610Sstevel@tonic-gate continue; 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate *bp++ = *ip; 6660Sstevel@tonic-gate *qp++ = (inquote || escaped) ? '^' : ' '; 6670Sstevel@tonic-gate escaped = 0; 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate *bp = '\0'; 6700Sstevel@tonic-gate *qp = '\0'; 6710Sstevel@tonic-gate if (quoted) 6720Sstevel@tonic-gate (void) strcpy(str, buf); 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate /* 6760Sstevel@tonic-gate * Removes trailing spaces from string "s". 6770Sstevel@tonic-gate */ 6780Sstevel@tonic-gate void 6790Sstevel@tonic-gate trim(s) 6800Sstevel@tonic-gate char *s; 6810Sstevel@tonic-gate { 6820Sstevel@tonic-gate char *p = &s[strlen(s) - 1]; 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate while (p >= s && isspace(*(uchar_t *)p)) 6850Sstevel@tonic-gate *p-- = '\0'; 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate /* 6890Sstevel@tonic-gate * try to allocate memory using malloc, if malloc fails, then flush the 6900Sstevel@tonic-gate * rddir caches, and retry. If the second allocation after the readdir 6910Sstevel@tonic-gate * caches have been flushed fails too, then return NULL to indicate 6920Sstevel@tonic-gate * memory could not be allocated. 6930Sstevel@tonic-gate */ 6940Sstevel@tonic-gate char * 6950Sstevel@tonic-gate auto_rddir_malloc(unsigned nbytes) 6960Sstevel@tonic-gate { 6970Sstevel@tonic-gate char *p; 6980Sstevel@tonic-gate int again = 0; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate if ((p = malloc(nbytes)) == NULL) { 7010Sstevel@tonic-gate /* 7020Sstevel@tonic-gate * No memory, free rddir caches and try again 7030Sstevel@tonic-gate */ 7040Sstevel@tonic-gate mutex_lock(&cleanup_lock); 7050Sstevel@tonic-gate cond_signal(&cleanup_start_cv); 7060Sstevel@tonic-gate if (cond_wait(&cleanup_done_cv, &cleanup_lock)) { 7070Sstevel@tonic-gate mutex_unlock(&cleanup_lock); 7080Sstevel@tonic-gate syslog(LOG_ERR, "auto_rddir_malloc interrupted\n"); 7090Sstevel@tonic-gate } else { 7100Sstevel@tonic-gate mutex_unlock(&cleanup_lock); 7110Sstevel@tonic-gate again = 1; 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate if (again) 7160Sstevel@tonic-gate p = malloc(nbytes); 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate return (p); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate /* 7220Sstevel@tonic-gate * try to strdup a string, if it fails, then flush the rddir caches, 7230Sstevel@tonic-gate * and retry. If the second strdup fails, return NULL to indicate failure. 7240Sstevel@tonic-gate */ 7250Sstevel@tonic-gate char * 7260Sstevel@tonic-gate auto_rddir_strdup(const char *s1) 7270Sstevel@tonic-gate { 7280Sstevel@tonic-gate char *s2; 7290Sstevel@tonic-gate int again = 0; 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate if ((s2 = strdup(s1)) == NULL) { 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * No memory, free rddir caches and try again 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate mutex_lock(&cleanup_lock); 7360Sstevel@tonic-gate cond_signal(&cleanup_start_cv); 7370Sstevel@tonic-gate if (cond_wait(&cleanup_done_cv, &cleanup_lock)) { 7380Sstevel@tonic-gate mutex_unlock(&cleanup_lock); 7390Sstevel@tonic-gate syslog(LOG_ERR, "auto_rddir_strdup interrupted\n"); 7400Sstevel@tonic-gate } else { 7410Sstevel@tonic-gate mutex_unlock(&cleanup_lock); 7420Sstevel@tonic-gate again = 1; 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate if (again) 7470Sstevel@tonic-gate s2 = strdup(s1); 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate return (s2); 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate /* 7530Sstevel@tonic-gate * Returns a pointer to the entry corresponding to 'name' if found, 7540Sstevel@tonic-gate * otherwise it returns NULL. 7550Sstevel@tonic-gate */ 7560Sstevel@tonic-gate struct dir_entry * 7570Sstevel@tonic-gate btree_lookup(struct dir_entry *head, char *name) 7580Sstevel@tonic-gate { 7590Sstevel@tonic-gate register struct dir_entry *p; 7600Sstevel@tonic-gate register int direction; 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate for (p = head; p != NULL; ) { 7630Sstevel@tonic-gate direction = strcmp(name, p->name); 7640Sstevel@tonic-gate if (direction == 0) 7650Sstevel@tonic-gate return (p); 7660Sstevel@tonic-gate if (direction > 0) 7670Sstevel@tonic-gate p = p->right; 7680Sstevel@tonic-gate else p = p->left; 7690Sstevel@tonic-gate } 7700Sstevel@tonic-gate return (NULL); 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate /* 7740Sstevel@tonic-gate * Add entry to binary tree 7750Sstevel@tonic-gate * Duplicate entries are not added 7760Sstevel@tonic-gate */ 7770Sstevel@tonic-gate void 7780Sstevel@tonic-gate btree_enter(struct dir_entry **head, struct dir_entry *ent) 7790Sstevel@tonic-gate { 7800Sstevel@tonic-gate register struct dir_entry *p, *prev = NULL; 7810Sstevel@tonic-gate register int direction; 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate ent->right = ent->left = NULL; 7840Sstevel@tonic-gate if (*head == NULL) { 7850Sstevel@tonic-gate *head = ent; 7860Sstevel@tonic-gate return; 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate for (p = *head; p != NULL; ) { 7900Sstevel@tonic-gate prev = p; 7910Sstevel@tonic-gate direction = strcmp(ent->name, p->name); 7920Sstevel@tonic-gate if (direction == 0) { 7930Sstevel@tonic-gate /* 7940Sstevel@tonic-gate * entry already in btree 7950Sstevel@tonic-gate */ 7960Sstevel@tonic-gate return; 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate if (direction > 0) 7990Sstevel@tonic-gate p = p->right; 8000Sstevel@tonic-gate else p = p->left; 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate assert(prev != NULL); 8030Sstevel@tonic-gate if (direction > 0) 8040Sstevel@tonic-gate prev->right = ent; 8050Sstevel@tonic-gate else prev->left = ent; 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate /* 8090Sstevel@tonic-gate * If entry doesn't exist already, add it to the linear list 8100Sstevel@tonic-gate * after '*last' and to the binary tree list. 8110Sstevel@tonic-gate * If '*last == NULL' then the list is walked till the end. 8120Sstevel@tonic-gate * *last is always set to the new element after successful completion. 8130Sstevel@tonic-gate * if entry already exists '*last' is only updated if not previously 8140Sstevel@tonic-gate * provided. 8150Sstevel@tonic-gate */ 8160Sstevel@tonic-gate int 8170Sstevel@tonic-gate add_dir_entry(char *name, struct dir_entry **list, struct dir_entry **last) 8180Sstevel@tonic-gate { 8190Sstevel@tonic-gate struct dir_entry *e, *l; 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate if ((*list != NULL) && (*last == NULL)) { 8220Sstevel@tonic-gate /* 8230Sstevel@tonic-gate * walk the list to find last element 8240Sstevel@tonic-gate */ 8250Sstevel@tonic-gate for (l = *list; l != NULL; l = l->next) 8260Sstevel@tonic-gate *last = l; 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate if (btree_lookup(*list, name) == NULL) { 8300Sstevel@tonic-gate /* 8310Sstevel@tonic-gate * not a duplicate, add it to list 8320Sstevel@tonic-gate */ 8330Sstevel@tonic-gate /* LINTED pointer alignment */ 8340Sstevel@tonic-gate e = (struct dir_entry *) 8350Sstevel@tonic-gate auto_rddir_malloc(sizeof (struct dir_entry)); 8360Sstevel@tonic-gate if (e == NULL) 8370Sstevel@tonic-gate return (ENOMEM); 8380Sstevel@tonic-gate (void) memset((char *)e, 0, sizeof (*e)); 8390Sstevel@tonic-gate e->name = auto_rddir_strdup(name); 8400Sstevel@tonic-gate if (e->name == NULL) { 8410Sstevel@tonic-gate free(e); 8420Sstevel@tonic-gate return (ENOMEM); 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate e->next = NULL; 8450Sstevel@tonic-gate if (*list == NULL) { 8460Sstevel@tonic-gate /* 8470Sstevel@tonic-gate * list is empty 8480Sstevel@tonic-gate */ 8490Sstevel@tonic-gate *list = *last = e; 8500Sstevel@tonic-gate } else { 8510Sstevel@tonic-gate /* 8520Sstevel@tonic-gate * append to end of list 8530Sstevel@tonic-gate */ 8540Sstevel@tonic-gate assert(*last != NULL); 8550Sstevel@tonic-gate (*last)->next = e; 8560Sstevel@tonic-gate *last = e; 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate /* 8590Sstevel@tonic-gate * add to binary tree 8600Sstevel@tonic-gate */ 8610Sstevel@tonic-gate btree_enter(list, e); 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate return (0); 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* 8670Sstevel@tonic-gate * Print trace output. 8680Sstevel@tonic-gate * Like fprintf(stderr, fmt, ...) except that if "id" is nonzero, the output 8690Sstevel@tonic-gate * is preceeded by the ID of the calling thread. 8700Sstevel@tonic-gate */ 8710Sstevel@tonic-gate #define FMT_BUFSIZ 1024 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate void 8740Sstevel@tonic-gate trace_prt(int id, char *fmt, ...) 8750Sstevel@tonic-gate { 8760Sstevel@tonic-gate va_list args; 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate char buf[FMT_BUFSIZ]; 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate if (id) { 8810Sstevel@tonic-gate (void) sprintf(buf, "t%u\t%s", thr_self(), fmt); 8820Sstevel@tonic-gate fmt = buf; 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate va_start(args, fmt); 8850Sstevel@tonic-gate (void) vfprintf(stderr, fmt, args); 8860Sstevel@tonic-gate va_end(args); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate /* 8900Sstevel@tonic-gate * Extract the isalist(5) for userland from the kernel. 8910Sstevel@tonic-gate */ 8920Sstevel@tonic-gate static char * 8930Sstevel@tonic-gate isalist(void) 8940Sstevel@tonic-gate { 8950Sstevel@tonic-gate char *buf; 8960Sstevel@tonic-gate size_t bufsize = BUFSIZ; /* wild guess */ 8970Sstevel@tonic-gate long ret; 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate buf = malloc(bufsize); 9000Sstevel@tonic-gate do { 9010Sstevel@tonic-gate ret = sysinfo(SI_ISALIST, buf, bufsize); 9020Sstevel@tonic-gate if (ret == -1l) 9030Sstevel@tonic-gate return (NULL); 9040Sstevel@tonic-gate if (ret > bufsize) { 9050Sstevel@tonic-gate bufsize = ret; 9060Sstevel@tonic-gate buf = realloc(buf, bufsize); 9070Sstevel@tonic-gate } else 9080Sstevel@tonic-gate break; 9090Sstevel@tonic-gate } while (buf != NULL); 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate return (buf); 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate /* 9150Sstevel@tonic-gate * Classify isa's as to bitness of the corresponding ABIs. 9160Sstevel@tonic-gate * isa's which have no "official" system ABI are returned 9170Sstevel@tonic-gate * unrecognised i.e. zero bits. 9180Sstevel@tonic-gate */ 9190Sstevel@tonic-gate static int 9200Sstevel@tonic-gate bitness(char *isaname) 9210Sstevel@tonic-gate { 9220Sstevel@tonic-gate if (strcmp(isaname, "sparc") == 0 || 9230Sstevel@tonic-gate strcmp(isaname, "i386") == 0) 9240Sstevel@tonic-gate return (32); 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate if (strcmp(isaname, "sparcv9") == 0) 9270Sstevel@tonic-gate return (64); 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate return (0); 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate /* 9330Sstevel@tonic-gate * Find the left-most element in the isalist that matches our idea of a 9340Sstevel@tonic-gate * system ABI. 9350Sstevel@tonic-gate * 9360Sstevel@tonic-gate * On machines with only one ABI, this is usually the same as uname -p. 9370Sstevel@tonic-gate */ 9380Sstevel@tonic-gate static int 9390Sstevel@tonic-gate natisa(char *buf, size_t bufsize) 9400Sstevel@tonic-gate { 9410Sstevel@tonic-gate int bits; 9420Sstevel@tonic-gate char *isa, *list; 9430Sstevel@tonic-gate char *lasts; 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate if ((list = isalist()) == NULL) 9460Sstevel@tonic-gate return (0); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate for (isa = strtok_r(list, " ", &lasts); 9490Sstevel@tonic-gate isa; isa = strtok_r(0, " ", &lasts)) 9500Sstevel@tonic-gate if ((bits = bitness(isa)) != 0) 9510Sstevel@tonic-gate break; /* ignore "extension" architectures */ 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate if (isa == 0 || bits == 0) { 9540Sstevel@tonic-gate free(list); 9550Sstevel@tonic-gate return (0); /* can't figure it out :( */ 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate (void) strncpy(buf, isa, bufsize); 9590Sstevel@tonic-gate free(list); 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate return (1); 9620Sstevel@tonic-gate } 963