Home | History | Annotate | Download | only in libdevinfo
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  4870        jg  * Common Development and Distribution License (the "License").
      6  4870        jg  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21     0    stevel /*
     22  4870        jg  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23     0    stevel  * Use is subject to license terms.
     24     0    stevel  */
     25     0    stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     26     0    stevel 
     27     0    stevel #ifdef	lint
     28     0    stevel #define	_REENTRANT	/* for localtime_r */
     29     0    stevel #endif
     30     0    stevel 
     31     0    stevel #include <stdio.h>
     32     0    stevel #include <ctype.h>
     33     0    stevel #include <stdlib.h>
     34     0    stevel #include <sys/types.h>
     35     0    stevel #include <strings.h>
     36     0    stevel #include <stdarg.h>
     37     0    stevel #include <sys/stat.h>
     38     0    stevel #include <fcntl.h>
     39     0    stevel #include <errno.h>
     40     0    stevel #include <unistd.h>
     41     0    stevel #include <stropts.h>
     42     0    stevel #include <time.h>
     43     0    stevel #include <sys/param.h>
     44     0    stevel #include <sys/vfstab.h>
     45     0    stevel #include <dirent.h>
     46     0    stevel #ifdef __sparc
     47     0    stevel #include <sys/scsi/adapters/scsi_vhci.h>
     48     0    stevel #include <sys/sunmdi.h>
     49     0    stevel #endif /* __sparc */
     50     0    stevel #include "libdevinfo.h"
     51     0    stevel #include "device_info.h"
     52  4870        jg #include <regex.h>
     53     0    stevel 
     54     0    stevel #define	isnewline(ch)	((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
     55     0    stevel #define	isnamechar(ch)  (isalpha(ch) || isdigit(ch) || (ch) == '_' ||\
     56     0    stevel 	(ch) == '-')
     57     0    stevel #define	MAX_TOKEN_SIZE	1024
     58     0    stevel #define	BUFSIZE		1024
     59     0    stevel #define	STRVAL(s)	((s) ? (s) : "NULL")
     60     0    stevel 
     61     0    stevel #define	SCSI_VHCI_CONF		"/kernel/drv/scsi_vhci.conf"
     62     0    stevel #define	QLC_CONF		"/kernel/drv/qlc.conf"
     63     0    stevel #define	FP_CONF			"/kernel/drv/fp.conf"
     64     0    stevel #define	DRIVER_CLASSES		"/etc/driver_classes"
     65     0    stevel #define	FP_AT			"fp@"
     66     0    stevel #define	VHCI_CTL_NODE		"/devices/scsi_vhci:devctl"
     67     0    stevel #define	SLASH_DEVICES		"/devices"
     68     0    stevel #define	SLASH_DEVICES_SLASH	"/devices/"
     69     0    stevel #define	SLASH_FP_AT		"/fp@"
     70     0    stevel #define	SLASH_SCSI_VHCI		"/scsi_vhci"
     71     0    stevel #define	META_DEV		"/dev/md/dsk/"
     72     0    stevel #define	SLASH_DEV_SLASH		"/dev/"
     73     0    stevel 
     74     0    stevel /*
     75     0    stevel  * Macros to produce a quoted string containing the value of a
     76     0    stevel  * preprocessor macro. For example, if SIZE is defined to be 256,
     77     0    stevel  * VAL2STR(SIZE) is "256". This is used to construct format
     78     0    stevel  * strings for scanf-family functions below.
     79     0    stevel  */
     80     0    stevel #define	QUOTE(x)	#x
     81     0    stevel #define	VAL2STR(x)	QUOTE(x)
     82     0    stevel 
     83     0    stevel typedef enum {
     84     0    stevel 	CLIENT_TYPE_UNKNOWN,
     85     0    stevel 	CLIENT_TYPE_PHCI,
     86     0    stevel 	CLIENT_TYPE_VHCI
     87     0    stevel } client_type_t;
     88     0    stevel 
     89     0    stevel typedef enum {
     90     0    stevel 	T_EQUALS,
     91     0    stevel 	T_AMPERSAND,
     92     0    stevel 	T_BIT_OR,
     93     0    stevel 	T_STAR,
     94     0    stevel 	T_POUND,
     95     0    stevel 	T_COLON,
     96     0    stevel 	T_SEMICOLON,
     97     0    stevel 	T_COMMA,
     98     0    stevel 	T_SLASH,
     99     0    stevel 	T_WHITE_SPACE,
    100     0    stevel 	T_NEWLINE,
    101     0    stevel 	T_EOF,
    102     0    stevel 	T_STRING,
    103     0    stevel 	T_HEXVAL,
    104     0    stevel 	T_DECVAL,
    105     0    stevel 	T_NAME
    106     0    stevel } token_t;
    107     0    stevel 
    108     0    stevel typedef enum {
    109     0    stevel 	begin, parent, drvname, drvclass, prop,
    110     0    stevel 	parent_equals, name_equals, drvclass_equals,
    111     0    stevel 	parent_equals_string, name_equals_string,
    112     0    stevel 	drvclass_equals_string,
    113     0    stevel 	prop_equals, prop_equals_string, prop_equals_integer,
    114     0    stevel 	prop_equals_string_comma, prop_equals_integer_comma
    115     0    stevel } conf_state_t;
    116     0    stevel 
    117     0    stevel /* structure to hold entries with mpxio-disable property in driver.conf file */
    118     0    stevel struct conf_entry {
    119     0    stevel 	char *name;
    120     0    stevel 	char *parent;
    121     0    stevel 	char *class;
    122     0    stevel 	char *unit_address;
    123     0    stevel 	int port;
    124     0    stevel 	int mpxio_disable;
    125     0    stevel 	struct conf_entry *next;
    126     0    stevel };
    127     0    stevel 
    128     0    stevel struct conf_file {
    129     0    stevel 	char *filename;
    130     0    stevel 	FILE *fp;
    131     0    stevel 	int linenum;
    132     0    stevel };
    133     0    stevel 
    134     0    stevel static char *tok_err = "Unexpected token '%s'\n";
    135     0    stevel 
    136     0    stevel 
    137     0    stevel /* #define	DEBUG */
    138     0    stevel 
    139     0    stevel #ifdef DEBUG
    140     0    stevel 
    141     0    stevel int devfsmap_debug = 0;
    142     0    stevel /* /var/run is not mounted at install time. Therefore use /tmp */
    143     0    stevel char *devfsmap_logfile = "/tmp/devfsmap.log";
    144     0    stevel static FILE *logfp;
    145     0    stevel #define	logdmsg(args)	log_debug_msg args
    146     0    stevel static void vlog_debug_msg(char *, va_list);
    147     0    stevel static void log_debug_msg(char *, ...);
    148     0    stevel #ifdef __sparc
    149     0    stevel static void log_confent_list(char *, struct conf_entry *, int);
    150     0    stevel static void log_pathlist(char **);
    151     0    stevel #endif /* __sparc */
    152     0    stevel 
    153     0    stevel #else /* DEBUG */
    154     0    stevel #define	logdmsg(args)	/* nothing */
    155     0    stevel #endif /* DEBUG */
    156     0    stevel 
    157     0    stevel 
    158     0    stevel /*
    159     0    stevel  * Leave NEWLINE as the next character.
    160     0    stevel  */
    161     0    stevel static void
    162     0    stevel find_eol(FILE *fp)
    163     0    stevel {
    164     0    stevel 	int ch;
    165     0    stevel 
    166     0    stevel 	while ((ch = getc(fp)) != EOF) {
    167     0    stevel 		if (isnewline(ch)) {
    168     0    stevel 			(void) ungetc(ch, fp);
    169     0    stevel 			break;
    170     0    stevel 		}
    171     0    stevel 	}
    172     0    stevel }
    173     0    stevel 
    174     0    stevel /* ignore parsing errors */
    175     0    stevel /*ARGSUSED*/
    176     0    stevel static void
    177     0    stevel file_err(struct conf_file *filep, char *fmt, ...)
    178     0    stevel {
    179     0    stevel #ifdef DEBUG
    180     0    stevel 	va_list ap;
    181     0    stevel 
    182     0    stevel 	va_start(ap, fmt);
    183     0    stevel 	log_debug_msg("WARNING: %s line # %d: ",
    184     0    stevel 	    filep->filename, filep->linenum);
    185     0    stevel 	vlog_debug_msg(fmt, ap);
    186     0    stevel 	va_end(ap);
    187     0    stevel #endif /* DEBUG */
    188     0    stevel }
    189     0    stevel 
    190     0    stevel /* return the next token from the given driver.conf file, or -1 on error */
    191     0    stevel static token_t
    192     0    stevel lex(struct conf_file *filep, char *val, size_t size)
    193     0    stevel {
    194     0    stevel 	char	*cp;
    195     0    stevel 	int	ch, oval, badquote;
    196     0    stevel 	size_t	remain;
    197     0    stevel 	token_t token;
    198     0    stevel 	FILE	*fp = filep->fp;
    199     0    stevel 
    200     0    stevel 	if (size < 2)
    201     0    stevel 		return (-1);
    202     0    stevel 
    203     0    stevel 	cp = val;
    204     0    stevel 	while ((ch = getc(fp)) == ' ' || ch == '\t')
    205     0    stevel 		;
    206     0    stevel 
    207     0    stevel 	remain = size - 1;
    208     0    stevel 	*cp++ = (char)ch;
    209     0    stevel 	switch (ch) {
    210     0    stevel 	case '=':
    211     0    stevel 		token = T_EQUALS;
    212     0    stevel 		break;
    213     0    stevel 	case '&':
    214     0    stevel 		token = T_AMPERSAND;
    215     0    stevel 		break;
    216     0    stevel 	case '|':
    217     0    stevel 		token = T_BIT_OR;
    218     0    stevel 		break;
    219     0    stevel 	case '*':
    220     0    stevel 		token = T_STAR;
    221     0    stevel 		break;
    222     0    stevel 	case '#':
    223     0    stevel 		token = T_POUND;
    224     0    stevel 		break;
    225     0    stevel 	case ':':
    226     0    stevel 		token = T_COLON;
    227     0    stevel 		break;
    228     0    stevel 	case ';':
    229     0    stevel 		token = T_SEMICOLON;
    230     0    stevel 		break;
    231     0    stevel 	case ',':
    232     0    stevel 		token = T_COMMA;
    233     0    stevel 		break;
    234     0    stevel 	case '/':
    235     0    stevel 		token = T_SLASH;
    236     0    stevel 		break;
    237     0    stevel 	case ' ':
    238     0    stevel 	case '\t':
    239     0    stevel 	case '\f':
    240     0    stevel 		while ((ch = getc(fp)) == ' ' ||
    241     0    stevel 		    ch == '\t' || ch == '\f') {
    242     0    stevel 			if (--remain == 0) {
    243     0    stevel 				*cp = '\0';
    244     0    stevel 				return (-1);
    245     0    stevel 			}
    246     0    stevel 			*cp++ = (char)ch;
    247     0    stevel 		}
    248     0    stevel 		(void) ungetc(ch, fp);
    249     0    stevel 		token = T_WHITE_SPACE;
    250     0    stevel 		break;
    251     0    stevel 	case '\n':
    252     0    stevel 	case '\r':
    253     0    stevel 		token = T_NEWLINE;
    254     0    stevel 		break;
    255     0    stevel 	case '"':
    256     0    stevel 		remain++;
    257     0    stevel 		cp--;
    258     0    stevel 		badquote = 0;
    259     0    stevel 		while (!badquote && (ch  = getc(fp)) != '"') {
    260     0    stevel 			switch (ch) {
    261     0    stevel 			case '\n':
    262     0    stevel 			case EOF:
    263     0    stevel 				file_err(filep, "Missing \"\n");
    264     0    stevel 				remain = size - 1;
    265     0    stevel 				cp = val;
    266     0    stevel 				*cp++ = '\n';
    267     0    stevel 				badquote = 1;
    268     0    stevel 				/* since we consumed the newline/EOF */
    269     0    stevel 				(void) ungetc(ch, fp);
    270     0    stevel 				break;
    271     0    stevel 
    272     0    stevel 			case '\\':
    273     0    stevel 				if (--remain == 0) {
    274     0    stevel 					*cp = '\0';
    275     0    stevel 					return (-1);
    276     0    stevel 				}
    277     0    stevel 				ch = (char)getc(fp);
    278     0    stevel 				if (!isdigit(ch)) {
    279     0    stevel 					/* escape the character */
    280     0    stevel 					*cp++ = (char)ch;
    281     0    stevel 					break;
    282     0    stevel 				}
    283     0    stevel 				oval = 0;
    284     0    stevel 				while (ch >= '0' && ch <= '7') {
    285     0    stevel 					ch -= '0';
    286     0    stevel 					oval = (oval << 3) + ch;
    287     0    stevel 					ch = (char)getc(fp);
    288     0    stevel 				}
    289     0    stevel 				(void) ungetc(ch, fp);
    290     0    stevel 				/* check for character overflow? */
    291     0    stevel 				if (oval > 127) {
    292     0    stevel 					file_err(filep,
    293     0    stevel 					    "Character "
    294     0    stevel 					    "overflow detected.\n");
    295     0    stevel 				}
    296     0    stevel 				*cp++ = (char)oval;
    297     0    stevel 				break;
    298     0    stevel 			default:
    299     0    stevel 				if (--remain == 0) {
    300     0    stevel 					*cp = '\0';
    301     0    stevel 					return (-1);
    302     0    stevel 				}
    303     0    stevel 				*cp++ = (char)ch;
    304     0    stevel 				break;
    305     0    stevel 			}
    306     0    stevel 		}
    307     0    stevel 		token = T_STRING;
    308     0    stevel 		break;
    309     0    stevel 
    310     0    stevel 	case EOF:
    311     0    stevel 		token = T_EOF;
    312     0    stevel 		break;
    313     0    stevel 
    314     0    stevel 	default:
    315     0    stevel 		/*
    316     0    stevel 		 * detect a lone '-' (including at the end of a line), and
    317     0    stevel 		 * identify it as a 'name'
    318     0    stevel 		 */
    319     0    stevel 		if (ch == '-') {
    320     0    stevel 			if (--remain == 0) {
    321     0    stevel 				*cp = '\0';
    322     0    stevel 				return (-1);
    323     0    stevel 			}
    324     0    stevel 			*cp++ = (char)(ch = getc(fp));
    325     0    stevel 			if (ch == ' ' || ch == '\t' || ch == '\n') {
    326     0    stevel 				(void) ungetc(ch, fp);
    327     0    stevel 				remain++;
    328     0    stevel 				cp--;
    329     0    stevel 				token = T_NAME;
    330     0    stevel 				break;
    331     0    stevel 			}
    332     0    stevel 		} else if (ch == '~' || ch == '-') {
    333     0    stevel 			if (--remain == 0) {
    334     0    stevel 				*cp = '\0';
    335     0    stevel 				return (-1);
    336     0    stevel 			}
    337     0    stevel 			*cp++ = (char)(ch = getc(fp));
    338     0    stevel 		}
    339     0    stevel 
    340     0    stevel 
    341     0    stevel 		if (isdigit(ch)) {
    342     0    stevel 			if (ch == '0') {
    343     0    stevel 				if ((ch = getc(fp)) == 'x') {
    344     0    stevel 					if (--remain == 0) {
    345     0    stevel 						*cp = '\0';
    346     0    stevel 						return (-1);
    347     0    stevel 					}
    348     0    stevel 					*cp++ = (char)ch;
    349     0    stevel 					ch = getc(fp);
    350     0    stevel 					while (isxdigit(ch)) {
    351     0    stevel 						if (--remain == 0) {
    352     0    stevel 							*cp = '\0';
    353     0    stevel 							return (-1);
    354     0    stevel 						}
    355     0    stevel 						*cp++ = (char)ch;
    356     0    stevel 						ch = getc(fp);
    357     0    stevel 					}
    358     0    stevel 					(void) ungetc(ch, fp);
    359     0    stevel 					token = T_HEXVAL;
    360     0    stevel 				} else {
    361     0    stevel 					goto digit;
    362     0    stevel 				}
    363     0    stevel 			} else {
    364     0    stevel 				ch = getc(fp);
    365     0    stevel digit:
    366     0    stevel 				while (isdigit(ch)) {
    367     0    stevel 					if (--remain == 0) {
    368     0    stevel 						*cp = '\0';
    369     0    stevel 						return (-1);
    370     0    stevel 					}
    371     0    stevel 					*cp++ = (char)ch;
    372     0    stevel 					ch = getc(fp);
    373     0    stevel 				}
    374     0    stevel 				(void) ungetc(ch, fp);
    375     0    stevel 				token = T_DECVAL;
    376     0    stevel 			}
    377     0    stevel 		} else if (isalpha(ch) || ch == '\\') {
    378     0    stevel 			if (ch != '\\') {
    379     0    stevel 				ch = getc(fp);
    380     0    stevel 			} else {
    381     0    stevel 				/*
    382     0    stevel 				 * if the character was a backslash,
    383     0    stevel 				 * back up so we can overwrite it with
    384     0    stevel 				 * the next (i.e. escaped) character.
    385     0    stevel 				 */
    386     0    stevel 				remain++;
    387     0    stevel 				cp--;
    388     0    stevel 			}
    389     0    stevel 			while (isnamechar(ch) || ch == '\\') {
    390     0    stevel 				if (ch == '\\')
    391     0    stevel 					ch = getc(fp);
    392     0    stevel 				if (--remain == 0) {
    393     0    stevel 					*cp = '\0';
    394     0    stevel 					return (-1);
    395     0    stevel 				}
    396     0    stevel 				*cp++ = (char)ch;
    397     0    stevel 				ch = getc(fp);
    398     0    stevel 			}
    399     0    stevel 			(void) ungetc(ch, fp);
    400     0    stevel 			token = T_NAME;
    401     0    stevel 		} else {
    402     0    stevel 			return (-1);
    403     0    stevel 		}
    404     0    stevel 		break;
    405     0    stevel 	}
    406     0    stevel 
    407     0    stevel 	*cp = '\0';
    408     0    stevel 
    409     0    stevel 	return (token);
    410     0    stevel }
    411  4870        jg 
    412  4870        jg #ifdef __sparc
    413     0    stevel 
    414     0    stevel static void
    415     0    stevel free_confent(struct conf_entry *confent)
    416     0    stevel {
    417     0    stevel 	if (confent->name)
    418     0    stevel 		free(confent->name);
    419     0    stevel 	if (confent->parent)
    420     0    stevel 		free(confent->parent);
    421     0    stevel 	if (confent->class)
    422     0    stevel 		free(confent->class);
    423     0    stevel 	if (confent->unit_address)
    424     0    stevel 		free(confent->unit_address);
    425     0    stevel 	free(confent);
    426     0    stevel }
    427     0    stevel 
    428     0    stevel static void
    429     0    stevel free_confent_list(struct conf_entry *confent_list)
    430     0    stevel {
    431     0    stevel 	struct conf_entry *confent, *next;
    432     0    stevel 
    433     0    stevel 	for (confent = confent_list; confent != NULL; confent = next) {
    434     0    stevel 		next = confent->next;
    435     0    stevel 		free_confent(confent);
    436     0    stevel 	}
    437     0    stevel }
    438     0    stevel 
    439     0    stevel /*
    440     0    stevel  * Parse the next entry from the driver.conf file and return in the form of
    441     0    stevel  * a pointer to the conf_entry.
    442     0    stevel  */
    443     0    stevel static struct conf_entry *
    444     0    stevel parse_conf_entry(struct conf_file *filep, char *tokbuf, size_t linesize)
    445     0    stevel {
    446     0    stevel 	char *prop_name, *string;
    447     0    stevel 	token_t token;
    448     0    stevel 	struct conf_entry *confent;
    449     0    stevel 	conf_state_t state;
    450     0    stevel 	int failed = 1;
    451     0    stevel 
    452     0    stevel 	if ((confent = calloc(1, sizeof (*confent))) == NULL)
    453     0    stevel 		return (NULL);
    454     0    stevel 
    455     0    stevel 	confent->port = -1;
    456     0    stevel 	confent->mpxio_disable = -1;
    457     0    stevel 
    458     0    stevel 	state = begin;
    459     0    stevel 	token = T_NAME;
    460     0    stevel 	prop_name = NULL;
    461     0    stevel 	string = NULL;
    462     0    stevel 	do {
    463     0    stevel 		switch (token) {
    464     0    stevel 		case T_NAME:
    465     0    stevel 			switch (state) {
    466     0    stevel 			case prop_equals_string:
    467     0    stevel 			case prop_equals_integer:
    468     0    stevel 			case begin:
    469     0    stevel 				state = prop;
    470     0    stevel 				if ((prop_name = strdup(tokbuf)) == NULL)
    471     0    stevel 					goto bad;
    472     0    stevel 				break;
    473     0    stevel 			default:
    474     0    stevel 				file_err(filep, tok_err, tokbuf);
    475     0    stevel 			}
    476     0    stevel 			break;
    477     0    stevel 		case T_EQUALS:
    478     0    stevel 			switch (state) {
    479     0    stevel 			case prop:
    480     0    stevel 				state = prop_equals;
    481     0    stevel 				break;
    482     0    stevel 			default:
    483     0    stevel 				file_err(filep, tok_err, tokbuf);
    484     0    stevel 			}
    485     0    stevel 			break;
    486     0    stevel 		case T_STRING:
    487     0    stevel 			switch (state) {
    488     0    stevel 			case prop_equals:
    489     0    stevel 				if ((string = strdup(tokbuf)) == NULL)
    490     0    stevel 					goto bad;
    491     0    stevel 
    492     0    stevel 				state = begin;
    493     0    stevel 				if (strcmp(prop_name, "PARENT") == 0 ||
    494     0    stevel 				    strcmp(prop_name, "parent") == 0) {
    495     0    stevel 					if (confent->parent) {
    496     0    stevel 						file_err(filep,
    497     0    stevel 				"'parent' property already specified\n");
    498     0    stevel 						goto bad;
    499     0    stevel 					}
    500     0    stevel 					confent->parent = string;
    501     0    stevel 				} else if (strcmp(prop_name, "NAME") == 0 ||
    502     0    stevel 				    strcmp(prop_name, "name") == 0) {
    503     0    stevel 					if (confent->name) {
    504     0    stevel 						file_err(filep,
    505     0    stevel 				"'name' property already specified\n");
    506     0    stevel 						goto bad;
    507     0    stevel 					}
    508     0    stevel 					confent->name = string;
    509     0    stevel 				} else if (strcmp(prop_name, "CLASS") == 0 ||
    510     0    stevel 				    strcmp(prop_name, "class") == 0) {
    511     0    stevel 					if (confent->class) {
    512     0    stevel 						file_err(filep,
    513     0    stevel 				"'class' property already specified\n");
    514     0    stevel 						goto bad;
    515     0    stevel 					}
    516     0    stevel 					confent->class = string;
    517     0    stevel 				} else if (strcmp(prop_name, "unit-address")
    518     0    stevel 				    == 0) {
    519     0    stevel 					if (confent->unit_address) {
    520     0    stevel 						file_err(filep,
    521     0    stevel 				"'unit-address' property already specified\n");
    522     0    stevel 						goto bad;
    523     0    stevel 					}
    524     0    stevel 					confent->unit_address = string;
    525     0    stevel 				} else if (strcmp(prop_name, "mpxio-disable")
    526     0    stevel 				    == 0) {
    527     0    stevel 					if (confent->mpxio_disable != -1) {
    528     0    stevel 						file_err(filep,
    529     0    stevel 				"'mpxio-disable' property already specified\n");
    530     0    stevel 						goto bad;
    531     0    stevel 					}
    532     0    stevel 					if (strcmp(string, "yes") == 0)
    533     0    stevel 						confent->mpxio_disable = 1;
    534     0    stevel 					else if (strcmp(string, "no") == 0)
    535     0    stevel 						confent->mpxio_disable = 0;
    536     0    stevel 					else {
    537     0    stevel 						file_err(filep,
    538     0    stevel 				"'mpxio-disable' property setting is invalid. "
    539     0    stevel 				"The value must be either \"yes\" or \"no\"\n");
    540     0    stevel 						goto bad;
    541     0    stevel 					}
    542     0    stevel 					free(string);
    543     0    stevel 				} else {
    544     0    stevel 					free(string);
    545     0    stevel 					state = prop_equals_string;
    546     0    stevel 				}
    547     0    stevel 				string = NULL;
    548     0    stevel 				free(prop_name);
    549     0    stevel 				prop_name = NULL;
    550     0    stevel 				break;
    551     0    stevel 
    552     0    stevel 			case prop_equals_string_comma:
    553     0    stevel 				state = prop_equals_string;
    554     0    stevel 				break;
    555     0    stevel 			default:
    556     0    stevel 				file_err(filep, tok_err, tokbuf);
    557     0    stevel 			}
    558     0    stevel 			break;
    559     0    stevel 		case T_HEXVAL:
    560     0    stevel 		case T_DECVAL:
    561     0    stevel 			switch (state) {
    562     0    stevel 			case prop_equals:
    563     0    stevel 				if (strcmp(prop_name, "port") == 0) {
    564     0    stevel 					if (confent->port != -1) {
    565     0    stevel 						file_err(filep,
    566     0    stevel 					"'port' property already specified\n");
    567     0    stevel 						goto bad;
    568     0    stevel 					}
    569     0    stevel 					confent->port =
    570     0    stevel 					    (int)strtol(tokbuf, NULL, 0);
    571     0    stevel 					state = begin;
    572     0    stevel 				} else
    573     0    stevel 					state = prop_equals_integer;
    574     0    stevel 				free(prop_name);
    575     0    stevel 				prop_name = NULL;
    576     0    stevel 				break;
    577     0    stevel 
    578     0    stevel 			case prop_equals_integer_comma:
    579     0    stevel 				state = prop_equals_integer;
    580     0    stevel 				break;
    581     0    stevel 			default:
    582     0    stevel 				file_err(filep, tok_err, tokbuf);
    583     0    stevel 			}
    584     0    stevel 			break;
    585     0    stevel 		case T_COMMA:
    586     0    stevel 			switch (state) {
    587     0    stevel 			case prop_equals_string:
    588     0    stevel 				state = prop_equals_string_comma;
    589     0    stevel 				break;
    590     0    stevel 			case prop_equals_integer:
    591     0    stevel 				state = prop_equals_integer_comma;
    592     0    stevel 				break;
    593     0    stevel 			default:
    594     0    stevel 				file_err(filep, tok_err, tokbuf);
    595     0    stevel 			}
    596     0    stevel 			break;
    597     0    stevel 		case T_NEWLINE:
    598     0    stevel 			filep->linenum++;
    599     0    stevel 			break;
    600     0    stevel 		case T_POUND:
    601     0    stevel 			find_eol(filep->fp);
    602     0    stevel 			break;
    603     0    stevel 		case T_EOF:
    604     0    stevel 			file_err(filep, "Unexpected EOF\n");
    605     0    stevel 			goto bad;
    606     0    stevel 		default:
    607     0    stevel 			file_err(filep, tok_err, tokbuf);
    608     0    stevel 			goto bad;
    609     0    stevel 		}
    610     0    stevel 	} while ((token = lex(filep, tokbuf, linesize)) != T_SEMICOLON);
    611     0    stevel 
    612     0    stevel 	failed = 0;
    613     0    stevel 
    614     0    stevel bad:
    615     0    stevel 	if (prop_name)
    616     0    stevel 		free(prop_name);
    617     0    stevel 	if (string)
    618     0    stevel 		free(string);
    619     0    stevel 	if (failed == 1) {
    620     0    stevel 		free_confent(confent);
    621     0    stevel 		return (NULL);
    622     0    stevel 	}
    623     0    stevel 	return (confent);
    624     0    stevel }
    625     0    stevel 
    626     0    stevel /*
    627     0    stevel  * Parse all entries with mpxio-disable property in the given driver.conf
    628     0    stevel  * file.
    629     0    stevel  *
    630     0    stevel  * fname		driver.conf file name
    631     0    stevel  * confent_list		on return *confent_list will contain the list of
    632     0    stevel  *			driver.conf file entries with mpxio-disable property.
    633     0    stevel  * mpxio_disable	on return *mpxio_disable is set to the setting of the
    634     0    stevel  * 			driver global mpxio-dissable property as follows.
    635     0    stevel  *			0  if driver mpxio-disable="no"
    636     0    stevel  *			1  if driver mpxio-disable="yes"
    637     0    stevel  *			-1 if driver mpxio-disable property isn't specified.
    638     0    stevel  */
    639     0    stevel static void
    640     0    stevel parse_conf_file(char *fname, struct conf_entry **confent_list,
    641     0    stevel     int *mpxio_disable)
    642     0    stevel {
    643     0    stevel 	struct conf_entry *confent, *tail = NULL;
    644     0    stevel 	token_t token;
    645     0    stevel 	struct conf_file file;
    646     0    stevel 	char tokval[MAX_TOKEN_SIZE];
    647     0    stevel 
    648     0    stevel 	*confent_list = NULL;
    649     0    stevel 	*mpxio_disable = -1;
    650     0    stevel 	if ((file.fp = fopen(fname, "r")) == NULL)
    651     0    stevel 		return;
    652     0    stevel 
    653     0    stevel 	file.filename = fname;
    654     0    stevel 	file.linenum = 1;
    655     0    stevel 
    656     0    stevel 	while ((token = lex(&file, tokval, MAX_TOKEN_SIZE)) != T_EOF) {
    657     0    stevel 		switch (token) {
    658     0    stevel 		case T_POUND:
    659     0    stevel 			/*
    660     0    stevel 			 * Skip comments.
    661     0    stevel 			 */
    662     0    stevel 			find_eol(file.fp);
    663     0    stevel 			break;
    664     0    stevel 		case T_NAME:
    665     0    stevel 			if ((confent = parse_conf_entry(&file, tokval,
    666     0    stevel 			    MAX_TOKEN_SIZE)) == NULL)
    667     0    stevel 				break;
    668     0    stevel 			/*
    669     0    stevel 			 * No name indicates global property.
    670     0    stevel 			 * Make sure parent and class not NULL.
    671     0    stevel 			 */
    672     0    stevel 			if (confent->name == NULL) {
    673     0    stevel 				if (confent->parent ||
    674     0    stevel 				    confent->class) {
    675     0    stevel 					file_err(&file,
    676     0    stevel 					    "missing name attribute\n");
    677     0    stevel 				} else if (confent->mpxio_disable != -1) {
    678     0    stevel 					if (*mpxio_disable == -1)
    679     0    stevel 						*mpxio_disable =
    680     0    stevel 						    confent->mpxio_disable;
    681     0    stevel 					else
    682     0    stevel 						file_err(&file,
    683     0    stevel 				"'mpxio-disable' property already specified\n");
    684     0    stevel 				}
    685     0    stevel 				free_confent(confent);
    686     0    stevel 				break;
    687     0    stevel 			}
    688     0    stevel 
    689     0    stevel 			/*
    690     0    stevel 			 * This is a node spec, either parent or class
    691     0    stevel 			 * must be specified.
    692     0    stevel 			 */
    693     0    stevel 			if (confent->parent == NULL && confent->class == NULL) {
    694     0    stevel 				file_err(&file,
    695     0    stevel 				    "missing parent or class attribute\n");
    696     0    stevel 				free_confent(confent);
    697     0    stevel 				break;
    698     0    stevel 			}
    699     0    stevel 
    700     0    stevel 			/* only need entries with mpxio_disable property */
    701     0    stevel 			if (confent->mpxio_disable == -1) {
    702     0    stevel 				free_confent(confent);
    703     0    stevel 				break;
    704     0    stevel 			}
    705     0    stevel 
    706     0    stevel 			if (tail)
    707     0    stevel 				tail->next = confent;
    708     0    stevel 			else
    709     0    stevel 				*confent_list = confent;
    710     0    stevel 			tail = confent;
    711     0    stevel 			break;
    712     0    stevel 
    713     0    stevel 		case T_NEWLINE:
    714     0    stevel 			file.linenum++;
    715     0    stevel 			break;
    716     0    stevel 		default:
    717     0    stevel 			break;
    718     0    stevel 		}
    719     0    stevel 	}
    720     0    stevel 
    721     0    stevel 	(void) fclose(file.fp);
    722     0    stevel }
    723     0    stevel 
    724     0    stevel /*
    725     0    stevel  * Return the driver class of the given driver_name.
    726     0    stevel  * The memory for the driver class is allocated by this function and the
    727     0    stevel  * caller must free it.
    728     0    stevel  */
    729     0    stevel static char *
    730     0    stevel get_driver_class(char *rootdir, char *driver_name)
    731     0    stevel {
    732     0    stevel 	FILE *fp;
    733     0    stevel 	char buf[BUFSIZE];
    734     0    stevel 	char driver[BUFSIZE];
    735     0    stevel 	char class_name[BUFSIZE];
    736     0    stevel 
    737     0    stevel 	logdmsg(("get_driver_class: rootdir = %s, driver name = %s\n",
    738     0    stevel 	    rootdir, driver_name));
    739     0    stevel 
    740     0    stevel 	(void) snprintf(buf, sizeof (buf), "%s%s", rootdir, DRIVER_CLASSES);
    741     0    stevel 
    742     0    stevel 	if ((fp = fopen(buf, "r")) == NULL) {
    743     0    stevel 		logdmsg(("get_driver_class: failed to open %s: %s\n",
    744     0    stevel 		    buf, strerror(errno)));
    745     0    stevel 		return (NULL);
    746     0    stevel 	}
    747     0    stevel 
    748     0    stevel 	while (fgets(buf, sizeof (buf), fp) != NULL) {
    749     0    stevel 		/* LINTED - unbounded string specifier */
    750     0    stevel 		if ((sscanf(buf, "%s %s", driver, class_name) == 2) &&
    751     0    stevel 		    driver[0] != '#' && strcmp(driver, driver_name) == 0) {
    752     0    stevel 			logdmsg(("get_driver_class: driver class = %s\n",
    753     0    stevel 			    class_name));
    754     0    stevel 			(void) fclose(fp);
    755     0    stevel 			return (strdup(class_name));
    756     0    stevel 		}
    757     0    stevel 	}
    758     0    stevel 
    759     0    stevel 	(void) fclose(fp);
    760     0    stevel 	return (NULL);
    761     0    stevel }
    762     0    stevel 
    763     0    stevel static int
    764     0    stevel lookup_in_confent_list(struct conf_entry *confent_list,
    765     0    stevel     int match_class, char *parent, char *unit_addr, int port)
    766     0    stevel {
    767     0    stevel 	struct conf_entry *confent;
    768     0    stevel 	char *par;
    769     0    stevel 
    770     0    stevel 	logdmsg(("lookup_in_confent_list: %s = \"%s\", unit_addr = \"%s\", "
    771     0    stevel 	    "port = %d\n", (match_class) ? "class" : "parent", parent,
    772     0    stevel 	    STRVAL(unit_addr), port));
    773     0    stevel 
    774     0    stevel 	for (confent = confent_list; confent != NULL; confent = confent->next) {
    775     0    stevel 		par = (match_class) ? confent->class : confent->parent;
    776     0    stevel 		if (unit_addr) {
    777     0    stevel 			if (confent->unit_address != NULL &&
    778     0    stevel 			    strcmp(confent->unit_address, unit_addr) == 0 &&
    779     0    stevel 			    par != NULL && strcmp(par, parent) == 0)
    780     0    stevel 				return (confent->mpxio_disable);
    781     0    stevel 		} else {
    782     0    stevel 			if (confent->port == port &&
    783     0    stevel 			    par != NULL && strcmp(par, parent) == 0)
    784     0    stevel 				return (confent->mpxio_disable);
    785     0    stevel 		}
    786     0    stevel 	}
    787     0    stevel 	return (-1);
    788     0    stevel }
    789     0    stevel 
    790     0    stevel /*
    791     0    stevel  * lookup mpxio-disabled property setting for the given path in the given
    792     0    stevel  * driver.conf file. Match the entries from most specific to least specific.
    793     0    stevel  *
    794     0    stevel  * conf_file	the path name of either fp.conf, qlc.conf or scsi_vhci.conf
    795     0    stevel  * path		/devices node path without the /devices prefix.
    796     0    stevel  *		If the conf_file is fp.conf, path must be a fp node path
    797     0    stevel  *		if the conf_file is qlc.conf, path must be a qlc node path.
    798     0    stevel  *		if the conf_file is scsi_vhci.conf, path must be NULL.
    799     0    stevel  *		ex:	/pci@8,600000/SUNW,qlc@4/fp@0,0
    800     0    stevel  *			/pci@8,600000/SUNW,qlc@4
    801     0    stevel  *
    802     0    stevel  * returns:
    803     0    stevel  *	0	if mpxio-disable="no"
    804     0    stevel  *	1	if mpxio-disable="yes"
    805     0    stevel  *	-1	if mpxio-disable property isn't specified.
    806     0    stevel  */
    807     0    stevel static int
    808     0    stevel lookup_in_conf_file(char *rootdir, char *conf_file, char *path)
    809     0    stevel {
    810     0    stevel 	struct conf_entry *confent_list = NULL;
    811     0    stevel 	int mpxio_disable;
    812     0    stevel 	di_node_t par_node = DI_NODE_NIL;
    813     0    stevel 	char *node_name = NULL, *node_addr = NULL;
    814     0    stevel 	char *unit_addr = NULL;
    815     0    stevel 	int port = -1;
    816     0    stevel 	char *par_node_name = NULL, *par_node_addr = NULL;
    817     0    stevel 	char *par_binding_name = NULL, *par_driver_name = NULL;
    818     0    stevel 	char *par_driver_class = NULL, *par_node_name_addr;
    819     0    stevel 	int rv = -1;
    820     0    stevel 	char buf[MAXPATHLEN];
    821     0    stevel 
    822     0    stevel 	logdmsg(("lookup_in_conf_file: rootdir = \"%s\", conf_file = \"%s\", "
    823     0    stevel 	    "path = \"%s\"\n", rootdir, conf_file, STRVAL(path)));
    824     0    stevel 
    825     0    stevel 	(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, conf_file);
    826     0    stevel 	parse_conf_file(buf, &confent_list, &mpxio_disable);
    827     0    stevel #ifdef DEBUG
    828     0    stevel 	log_confent_list(buf, confent_list, mpxio_disable);
    829     0    stevel #endif
    830     0    stevel 
    831     0    stevel 	/* if path is NULL, return driver global mpxio-disable setting */
    832     0    stevel 	if (path == NULL) {
    833     0    stevel 		rv = mpxio_disable;
    834     0    stevel 		goto done;
    835     0    stevel 	}
    836     0    stevel 
    837     0    stevel 	if ((node_name = strrchr(path, '/')) == NULL)
    838     0    stevel 		goto done;
    839     0    stevel 
    840     0    stevel 	*node_name = '\0';
    841     0    stevel 	node_name++;
    842     0    stevel 
    843     0    stevel 	if ((node_addr = strchr(node_name, '@')) == NULL)
    844     0    stevel 		goto done;
    845     0    stevel 
    846     0    stevel 	*node_addr = '\0';
    847     0    stevel 	node_addr++;
    848     0    stevel 
    849     0    stevel 	if (strcmp(node_name, "fp") == 0) {
    850     0    stevel 		/* get port number; encoded in the node addr as a hex number */
    851     0    stevel 		port = (int)strtol(node_addr, NULL, 16);
    852     0    stevel 	} else
    853     0    stevel 		unit_addr = node_addr;
    854     0    stevel 
    855     0    stevel 	/*
    856     0    stevel 	 * Match from most specific to least specific;
    857     0    stevel 	 * first, start the lookup based on full path.
    858     0    stevel 	 */
    859     0    stevel 	if ((rv = lookup_in_confent_list(confent_list, 0, path,
    860     0    stevel 	    unit_addr, port)) != -1)
    861     0    stevel 		goto done;
    862     0    stevel 
    863     0    stevel 	/* lookup nodename@address */
    864     0    stevel 	if ((par_node_name_addr = strrchr(path, '/')) != NULL) {
    865     0    stevel 		par_node_name_addr++;
    866     0    stevel 		if ((rv = lookup_in_confent_list(confent_list, 0,
    867     0    stevel 		    par_node_name_addr, unit_addr, port)) != -1)
    868     0    stevel 			goto done;
    869     0    stevel 	}
    870     0    stevel 
    871     0    stevel 	/* di_init() doesn't work when 0 is passed in flags */
    872     0    stevel 	par_node = di_init(path, DINFOMINOR);
    873     0    stevel 	if (par_node != DI_NODE_NIL) {
    874     0    stevel 		par_node_name = di_node_name(par_node);
    875     0    stevel 		par_node_addr = di_bus_addr(par_node);
    876     0    stevel 		par_binding_name = di_binding_name(par_node);
    877     0    stevel 		par_driver_name = di_driver_name(par_node);
    878     0    stevel 	}
    879     0    stevel 
    880     0    stevel 	logdmsg(("par_node_name = %s\n", STRVAL(par_node_name)));
    881     0    stevel 	logdmsg(("par_node_addr = %s\n", STRVAL(par_node_addr)));
    882     0    stevel 	logdmsg(("par_binding_name = %s\n", STRVAL(par_binding_name)));
    883     0    stevel 	logdmsg(("par_driver_name = %s\n", STRVAL(par_driver_name)));
    884     0    stevel 
    885     0    stevel 	/* lookup bindingname@address */
    886     0    stevel 	if (par_binding_name != NULL && par_binding_name != par_node_name &&
    887     0    stevel 	    par_node_addr != NULL) {
    888     0    stevel 		(void) snprintf(buf, sizeof (buf), "%s@%s", par_binding_name,
    889     0    stevel 		    par_node_addr);
    890     0    stevel 		if ((rv = lookup_in_confent_list(confent_list, 0,
    891     0    stevel 		    buf, unit_addr, port)) != -1)
    892     0    stevel 			goto done;
    893     0    stevel 	}
    894     0    stevel 
    895     0    stevel 	/* lookup binding name */
    896     0    stevel 	if (par_binding_name != NULL) {
    897     0    stevel 		if ((rv = lookup_in_confent_list(confent_list, 0,
    898     0    stevel 		    par_binding_name, unit_addr, port)) != -1)
    899     0    stevel 			goto done;
    900     0    stevel 	}
    901     0    stevel 
    902     0    stevel 	if (par_driver_name != NULL) {
    903     0    stevel 		/* lookup driver name */
    904     0    stevel 		if ((rv = lookup_in_confent_list(confent_list, 0,
    905     0    stevel 		    par_driver_name, unit_addr, port)) != -1)
    906     0    stevel 			goto done;
    907     0    stevel 
    908     0    stevel 		/* finally, lookup class name */
    909     0    stevel 		par_driver_class = get_driver_class(rootdir, par_driver_name);
    910     0    stevel 		if (par_driver_class != NULL) {
    911     0    stevel 			if ((rv = lookup_in_confent_list(confent_list, 1,
    912     0    stevel 			    par_driver_class, unit_addr, port)) != -1)
    913     0    stevel 				goto done;
    914     0    stevel 		}
    915     0    stevel 	}
    916     0    stevel 
    917     0    stevel 	/*
    918     0    stevel 	 * no match so far;
    919     0    stevel 	 * use the driver global mpxio-disable setting if exists.
    920     0    stevel 	 */
    921     0    stevel 	rv = mpxio_disable;
    922     0    stevel 
    923     0    stevel done:
    924     0    stevel 	if (node_name != NULL)
    925     0    stevel 		*(node_name - 1) = '/';
    926     0    stevel 	if (node_addr != NULL)
    927     0    stevel 		*(node_addr - 1) = '@';
    928     0    stevel 	if (par_driver_class != NULL)
    929     0    stevel 		free(par_driver_class);
    930     0    stevel 	if (confent_list != NULL)
    931     0    stevel 		free_confent_list(confent_list);
    932     0    stevel 	if (par_node != DI_NODE_NIL)
    933     0    stevel 		di_fini(par_node);
    934     0    stevel 
    935     0    stevel 	return (rv);
    936     0    stevel }
    937     0    stevel 
    938     0    stevel /*
    939     0    stevel  * Given client_name return whether it is a phci or vhci based name.
    940     0    stevel  * client_name is /devices name of a client without the /devices prefix.
    941     0    stevel  *
    942     0    stevel  * client_name			Return value
    943     0    stevel  * .../fp@xxx/ssd@yyy		CLIENT_TYPE_PHCI
    944     0    stevel  * .../scsi_vhci/ssd@yyy	CLIENT_TYPE_VHCI
    945     0    stevel  * other			CLIENT_TYPE_UNKNOWN
    946     0    stevel  */
    947     0    stevel static client_type_t
    948     0    stevel client_name_type(char *client_name)
    949     0    stevel {
    950     0    stevel 	client_type_t client_type;
    951     0    stevel 	char *p1, *p2;
    952     0    stevel 
    953     0    stevel 	logdmsg(("client_name_type: client_name = %s\n", client_name));
    954     0    stevel 
    955     0    stevel 	if (strncmp(client_name, SLASH_SCSI_VHCI,
    956     0    stevel 	    sizeof (SLASH_SCSI_VHCI) - 1) == 0)
    957     0    stevel 		return (CLIENT_TYPE_VHCI);
    958     0    stevel 
    959     0    stevel 	if (*client_name != '/')
    960     0    stevel 		return (CLIENT_TYPE_UNKNOWN);
    961     0    stevel 
    962     0    stevel 	if ((p1 = strrchr(client_name, '/')) == NULL)
    963     0    stevel 		return (CLIENT_TYPE_UNKNOWN);
    964     0    stevel 
    965     0    stevel 	*p1 = '\0';
    966     0    stevel 
    967     0    stevel 	if ((p2 = strrchr(client_name, '/')) != NULL &&
    968     0    stevel 	    strncmp(p2, SLASH_FP_AT, sizeof (SLASH_FP_AT) - 1) == 0)
    969     0    stevel 		client_type = CLIENT_TYPE_PHCI;
    970     0    stevel 	else
    971     0    stevel 		client_type = CLIENT_TYPE_UNKNOWN;
    972     0    stevel 
    973     0    stevel 	*p1 = '/';
    974     0    stevel 	return (client_type);
    975     0    stevel }
    976     0    stevel 
    977     0    stevel /*
    978     0    stevel  * Compare controller name portion of dev1 and dev2.
    979     0    stevel  *
    980     0    stevel  * rootdir	root directory of the target environment
    981     0    stevel  * dev1		can be either a /dev link or /devices name in the target
    982     0    stevel  *		environemnt
    983     0    stevel  * dev2		/devices name of a device without the /devices prefix
    984     0    stevel  *
    985     0    stevel  * Returns:
    986     0    stevel  *	0	if controller names match
    987     0    stevel  *	1	if controller names don't match
    988     0    stevel  *	-1	an error occurred.
    989     0    stevel  */
    990     0    stevel static int
    991     0    stevel compare_controller(char *rootdir, char *dev1, char *dev2)
    992     0    stevel {
    993     0    stevel 	int linksize;
    994     0    stevel 	char *p1, *p;
    995     0    stevel 	char physdev1[MAXPATHLEN];
    996     0    stevel 	char buf[MAXPATHLEN];
    997     0    stevel 
    998     0    stevel 	logdmsg(("compare_controller: rootdir = %s, dev1 = %s, dev2 = %s\n",
    999     0    stevel 	    rootdir, dev1, dev2));
   1000     0    stevel 
   1001     0    stevel 	if (strncmp(dev1, SLASH_DEV_SLASH, sizeof (SLASH_DEV_SLASH) - 1)
   1002     0    stevel 	    == 0) {
   1003     0    stevel 		(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, dev1);
   1004     0    stevel 		if ((linksize = readlink(buf, physdev1, MAXPATHLEN)) > 0 &&
   1005     0    stevel 		    linksize < (MAXPATHLEN - 1)) {
   1006     0    stevel 			physdev1[linksize] = '\0';
   1007     0    stevel 			logdmsg(("compare_controller: physdev1 = %s\n",
   1008     0    stevel 			    physdev1));
   1009     0    stevel 		} else
   1010     0    stevel 			return (-1);
   1011     0    stevel 	} else
   1012     0    stevel 		(void) strlcpy(physdev1, dev1, MAXPATHLEN);
   1013     0    stevel 
   1014     0    stevel 	if ((p1 = strstr(physdev1, SLASH_DEVICES)) == NULL)
   1015     0    stevel 		return (-1);
   1016     0    stevel 
   1017     0    stevel 	p1 += sizeof (SLASH_DEVICES) - 1;
   1018     0    stevel 	/* strip the device portion */
   1019     0    stevel 	if ((p = strrchr(p1, '/')) == NULL)
   1020     0    stevel 		return (-1);
   1021     0    stevel 	*p = '\0';
   1022     0    stevel 
   1023     0    stevel 	if ((p = strrchr(dev2, '/')) == NULL)
   1024     0    stevel 		return (-1);
   1025     0    stevel 	*p = '\0';
   1026     0    stevel 
   1027     0    stevel 	logdmsg(("compare_controller: path1 = %s, path2 = %s\n",
   1028     0    stevel 	    p1, dev2));
   1029     0    stevel 	if (strcmp(p1, dev2) == 0) {
   1030     0    stevel 		*p = '/';
   1031     0    stevel 		return (0);
   1032     0    stevel 	} else {
   1033     0    stevel 		*p = '/';
   1034     0    stevel 		return (1);
   1035     0    stevel 	}
   1036     0    stevel }
   1037     0    stevel 
   1038     0    stevel /*
   1039     0    stevel  * Check if the specified device path is on the root controller.
   1040     0    stevel  *
   1041     0    stevel  * rootdir	root directory of the target environment
   1042     0    stevel  * path		/devices name of a device without the /devices prefix
   1043     0    stevel  *
   1044     0    stevel  * Returns
   1045     0    stevel  *	1	if the path is on the root controller
   1046     0    stevel  *	0	if the path is not on the root controller
   1047     0    stevel  *	-1	if an error occurs
   1048     0    stevel  */
   1049     0    stevel static int
   1050     0    stevel is_root_controller(char *rootdir, char *path)
   1051     0    stevel {
   1052     0    stevel 	FILE *fp;
   1053     0    stevel 	char *tmpfile;
   1054     0    stevel 	int rv = -1;
   1055     0    stevel 	struct vfstab vfsent;
   1056     0    stevel 	char buf[MAXPATHLEN];
   1057     0    stevel 	char ctd[MAXNAMELEN + 1];
   1058     0    stevel 
   1059     0    stevel 	logdmsg(("is_root_controller: rootdir = %s, path = %s\n", rootdir,
   1060     0    stevel 	    path));
   1061     0    stevel 
   1062     0    stevel 	(void) snprintf(buf, MAXPATHLEN, "%s%s", rootdir, VFSTAB);
   1063     0    stevel 
   1064     0    stevel 	if ((fp = fopen(buf, "r")) == NULL) {
   1065     0    stevel 		logdmsg(("is_root_controller: failed to open %s: %s\n",
   1066     0    stevel 		    buf, strerror(errno)));
   1067     0    stevel 		return (-1);
   1068     0    stevel 	}
   1069     0    stevel 
   1070     0    stevel 	if (getvfsfile(fp, &vfsent, "/") != 0) {
   1071     0    stevel 		logdmsg(("is_root_controller: getvfsfile: failed to read "
   1072     0    stevel 		    "vfstab entry for mount point \"/\": %s\n",
   1073     0    stevel 		    strerror(errno)));
   1074     0    stevel 		(void) fclose(fp);
   1075     0    stevel 		return (-1);
   1076     0    stevel 	}
   1077     0    stevel 	(void) fclose(fp);
   1078     0    stevel 
   1079     0    stevel 	/* check if the root is an svm metadisk */
   1080     0    stevel 	if (strncmp(vfsent.vfs_special, META_DEV, sizeof (META_DEV) - 1) != 0) {
   1081     0    stevel 		if (compare_controller(rootdir, vfsent.vfs_special, path) == 0)
   1082     0    stevel 			return (1);
   1083     0    stevel 		else
   1084     0    stevel 			return (0);
   1085     0    stevel 	}
   1086     0    stevel 
   1087     0    stevel 	/* Don't use /var/run as it is not mounted in miniroot */
   1088     0    stevel 	if ((tmpfile = tempnam("/tmp", "diirc")) == NULL) {
   1089     0    stevel 		logdmsg(("is_root_controller: tempnam: failed: %s\n",
   1090     0    stevel 		    strerror(errno)));
   1091     0    stevel 		return (-1);
   1092     0    stevel 	}
   1093     0    stevel 
   1094     0    stevel 	/* get metadisk components using metastat command */
   1095     0    stevel 	(void) snprintf(buf, MAXPATHLEN,
   1096     0    stevel 	    "/usr/sbin/metastat -p %s 2>/dev/null | "
   1097     0    stevel 	    "/usr/bin/grep ' 1 1 ' | "
   1098     0    stevel 	    "/usr/bin/sed -e 's/^.* 1 1 //' | "
   1099     0    stevel 	    "/usr/bin/cut -f1 -d ' ' > %s",
   1100     0    stevel 	    vfsent.vfs_special + sizeof (META_DEV) - 1, tmpfile);
   1101     0    stevel 
   1102     0    stevel 	logdmsg(("is_root_controller: command = %s\n", buf));
   1103     0    stevel 	fp = NULL;
   1104     0    stevel 	if (system(buf) == 0 && (fp = fopen(tmpfile, "r")) != NULL) {
   1105     0    stevel 		while (fscanf(fp, "%" VAL2STR(MAXNAMELEN) "s", ctd) == 1) {
   1106     0    stevel 			(void) snprintf(buf, MAXPATHLEN, "/dev/dsk/%s", ctd);
   1107     0    stevel 			if (compare_controller(rootdir, buf, path) == 0) {
   1108     0    stevel 				rv = 1;
   1109     0    stevel 				goto out;
   1110     0    stevel 			}
   1111     0    stevel 		}
   1112     0    stevel 		rv = 0;
   1113     0    stevel 	}
   1114     0    stevel 
   1115     0    stevel out:
   1116     0    stevel 	if (fp)
   1117     0    stevel 		(void) fclose(fp);
   1118     0    stevel 	(void) unlink(tmpfile);
   1119     0    stevel 	free(tmpfile);
   1120     0    stevel 	return (rv);
   1121     0    stevel }
   1122     0    stevel 
   1123     0    stevel static int
   1124     0    stevel file_exists(char *rootdir, char *path)
   1125     0    stevel {
   1126     0    stevel 	struct stat stbuf;
   1127     0    stevel 	char fullpath[MAXPATHLEN];
   1128     0    stevel 	int x;
   1129     0    stevel 
   1130     0    stevel 	(void) snprintf(fullpath, MAXPATHLEN, "%s%s", rootdir, path);
   1131     0    stevel 
   1132     0    stevel 	x = stat(fullpath, &stbuf);
   1133     0    stevel 	logdmsg(("file_exists: %s: %s\n", fullpath, (x == 0) ? "yes" : "no"));
   1134     0    stevel 	if (x == 0)
   1135     0    stevel 		return (1);
   1136     0    stevel 	else
   1137     0    stevel 		return (0);
   1138     0    stevel }
   1139     0    stevel 
   1140     0    stevel /*
   1141     0    stevel  * Check if mpxio is enabled or disabled on the specified device path.
   1142     0    stevel  * Looks through the .conf files to determine the mpxio setting.
   1143     0    stevel  *
   1144     0    stevel  * rootdir	root directory of the target environment
   1145     0    stevel  * path		/devices name of a device without the /devices prefix and
   1146     0    stevel  *		minor name component.
   1147     0    stevel  *
   1148     0    stevel  * Returns
   1149     0    stevel  *	1	if mpxio is disabled
   1150     0    stevel  *	0	if mpxio is enabled
   1151     0    stevel  *	-1	if an error occurs
   1152     0    stevel  */
   1153     0    stevel static int
   1154     0    stevel is_mpxio_disabled(char *rootdir, char *path)
   1155     0    stevel {
   1156     0    stevel 	int mpxio_disable;
   1157     0    stevel 	char *p;
   1158     0    stevel 	int check_root_controller;
   1159     0    stevel 
   1160     0    stevel 	logdmsg(("is_mpxio_disabled: rootdir = %s, path = %s\n",
   1161     0    stevel 	    rootdir, path));
   1162     0    stevel 
   1163     0    stevel 	if (file_exists(rootdir, SCSI_VHCI_CONF) == 0) {
   1164     0    stevel 		/*
   1165     0    stevel 		 * scsi_vhci.conf doesn't exist:
   1166     0    stevel 		 *  if upgrading from a pre solaris 9 release. or
   1167     0    stevel 		 *  if this function is called during fresh or flash install
   1168     0    stevel 		 *  prior to installing scsi_vhci.conf file.
   1169     0    stevel 		 */
   1170     0    stevel 		if (file_exists(rootdir, "/kernel/drv"))
   1171     0    stevel 			/* upgrading from pre solaris 9 */
   1172     0    stevel 			return (1);
   1173     0    stevel 		else
   1174     0    stevel 			/* fresh or flash install */
   1175     0    stevel 			return (0);
   1176     0    stevel 	}
   1177     0    stevel 
   1178     0    stevel 	mpxio_disable = lookup_in_conf_file(rootdir, SCSI_VHCI_CONF, NULL);
   1179     0    stevel 
   1180     0    stevel 	/*
   1181     0    stevel 	 * scsi_vhci.conf contains mpxio-disable property only in s9 and
   1182     0    stevel 	 * s8+sfkpatch. This property is no longer present from s10 onwards.
   1183     0    stevel 	 */
   1184     0    stevel 	if (mpxio_disable == 1) {
   1185     0    stevel 		/* upgrading from s8 or s9 with mpxio globally disabled */
   1186     0    stevel 		return (1);
   1187     0    stevel 	} else if (mpxio_disable == 0) {
   1188     0    stevel 		/* upgrading from s8 or s9 with mpxio globally enabled */
   1189     0    stevel 		check_root_controller = 1;
   1190     0    stevel 	} else {
   1191     0    stevel 		/*
   1192     0    stevel 		 * We are looking at the s10 version of the file. This is
   1193     0    stevel 		 * the case if this function is called after installing the
   1194     0    stevel 		 * new scsi_vhci.conf file.
   1195     0    stevel 		 */
   1196     0    stevel 		check_root_controller = 0;
   1197     0    stevel 	}
   1198     0    stevel 
   1199     0    stevel 	if ((mpxio_disable = lookup_in_conf_file(rootdir, FP_CONF, path))
   1200     0    stevel 	    != -1)
   1201     0    stevel 		return (mpxio_disable);
   1202     0    stevel 
   1203     0    stevel 	if ((p = strrchr(path, '/')) == NULL)
   1204     0    stevel 		return (-1);
   1205     0    stevel 
   1206     0    stevel 	*p = '\0';
   1207     0    stevel 	if ((mpxio_disable = lookup_in_conf_file(rootdir, QLC_CONF, path))
   1208     0    stevel 	    != -1) {
   1209     0    stevel 		*p = '/';
   1210     0    stevel 		return (mpxio_disable);
   1211     0    stevel 	}
   1212     0    stevel 	*p = '/';
   1213     0    stevel 
   1214     0    stevel 	/*
   1215     0    stevel 	 * mpxio-disable setting is not found in the .conf files.
   1216     0    stevel 	 * The default is to enable mpxio, except if the path is on the root
   1217     0    stevel 	 * controller.
   1218     0    stevel 	 *
   1219     0    stevel 	 * In s8 and s9 mpxio is not supported on the root controller.
   1220     0    stevel 	 * NWS supplies a patch to enable root controller support in s8 and s9.
   1221     0    stevel 	 * If the system had the patch installed, the fp.conf file would have
   1222     0    stevel 	 * explicit "mpxio-disable=no" for the root controller. So we would
   1223     0    stevel 	 * have found the mpxio-disable setting when we looked up this property
   1224     0    stevel 	 * in the fp.conf file.
   1225     0    stevel 	 */
   1226     0    stevel 	if (check_root_controller) {
   1227     0    stevel 		mpxio_disable = is_root_controller(rootdir, path);
   1228     0    stevel 		logdmsg(("is_mpxio_disabled: is_root_controller returned %d\n",
   1229     0    stevel 		    mpxio_disable));
   1230     0    stevel 	} else
   1231     0    stevel 		mpxio_disable = 0;
   1232     0    stevel 
   1233     0    stevel 	return (mpxio_disable);
   1234     0    stevel }
   1235     0    stevel 
   1236     0    stevel static int
   1237     0    stevel vhci_ctl(sv_iocdata_t *iocp, int cmd)
   1238     0    stevel {
   1239     0    stevel 	int fd, rv;
   1240     0    stevel 
   1241     0    stevel 	if ((fd = open(VHCI_CTL_NODE, O_RDWR)) < 0)
   1242     0    stevel 		return (-1);
   1243     0    stevel 	rv = ioctl(fd, cmd, iocp);
   1244     0    stevel 	(void) close(fd);
   1245     0    stevel 	return (rv);
   1246     0    stevel }
   1247     0    stevel 
   1248     0    stevel /*
   1249     0    stevel  * Convert a phci client name to vhci client name.
   1250     0    stevel  *
   1251     0    stevel  * phci_name	phci client /devices name without the /devices prefix and
   1252     0    stevel  *		minor name component.
   1253     0    stevel  *		ex: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
   1254     0    stevel  *
   1255     0    stevel  * Returns 	on success, vhci client name is returned. The memory for
   1256     0    stevel  *		the vhci name is allocated by this function and the caller
   1257     0    stevel  * 		must free it.
   1258     0    stevel  *		on failure, NULL is returned.
   1259     0    stevel  */
   1260     0    stevel static char *
   1261     0    stevel phci_to_vhci(char *phci_name)
   1262     0    stevel {
   1263     0    stevel 	sv_iocdata_t ioc;
   1264     0    stevel 	char *slash, *addr, *retp;
   1265     0    stevel 	char vhci_name_buf[MAXPATHLEN];
   1266     0    stevel 	char phci_name_buf[MAXPATHLEN];
   1267     0    stevel 	char addr_buf[MAXNAMELEN];
   1268     0    stevel 
   1269     0    stevel 	logdmsg(("phci_to_vhci: pchi_name =  %s\n", phci_name));
   1270     0    stevel 	(void) strlcpy(phci_name_buf, phci_name, MAXPATHLEN);
   1271     0    stevel 
   1272     0    stevel 	if ((slash = strrchr(phci_name_buf, '/')) == NULL ||
   1273     0    stevel 	    (addr = strchr(slash, '@')) == NULL)
   1274     0    stevel 		return (NULL);
   1275     0    stevel 
   1276     0    stevel 	*slash = '\0';
   1277     0    stevel 	addr++;
   1278     0    stevel 	(void) strlcpy(addr_buf, addr, MAXNAMELEN);
   1279     0    stevel 
   1280     0    stevel 	bzero(&ioc, sizeof (sv_iocdata_t));
   1281     0    stevel 	ioc.client = vhci_name_buf;
   1282     0    stevel 	ioc.phci = phci_name_buf;
   1283     0    stevel 	ioc.addr = addr_buf;
   1284     0    stevel 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_NAME) != 0) {
   1285     0    stevel 		logdmsg(("phci_to_vhci: vhci_ctl failed: %s\n",
   1286     0    stevel 		    strerror(errno)));
   1287     0    stevel 		return (NULL);
   1288     0    stevel 	}
   1289     0    stevel 
   1290     0    stevel 	retp = strdup(vhci_name_buf);
   1291     0    stevel 	logdmsg(("phci_to_vhci: vhci name = %s\n", STRVAL(retp)));
   1292     0    stevel 	return (retp);
   1293     0    stevel }
   1294     0    stevel 
   1295     0    stevel static int
   1296     0    stevel add_to_phci_list(char **phci_list, sv_path_info_t *pi, int npaths, int state,
   1297     0    stevel     char *node_name)
   1298     0    stevel {
   1299     0    stevel 	int rv = 0;
   1300     0    stevel 	char name[MAXPATHLEN];
   1301     0    stevel 
   1302     0    stevel 	while (npaths--) {
   1303     0    stevel 		if (state == pi->ret_state) {
   1304    82       cth 			(void) snprintf(name, MAXPATHLEN, "%s/%s@%s",
   1305     0    stevel 			    pi->device.ret_phci, node_name, pi->ret_addr);
   1306     0    stevel 			if ((*phci_list = strdup(name)) == NULL)
   1307     0    stevel 				return (-1);
   1308     0    stevel 			phci_list++;
   1309     0    stevel 			rv++;
   1310     0    stevel 		}
   1311     0    stevel 		pi++;
   1312     0    stevel 	}
   1313     0    stevel 
   1314     0    stevel 	return (rv);
   1315     0    stevel }
   1316     0    stevel 
   1317     0    stevel static void
   1318     0    stevel free_pathlist(char **pathlist)
   1319     0    stevel {
   1320     0    stevel 	char **p;
   1321     0    stevel 
   1322     0    stevel 	if (pathlist != NULL) {
   1323     0    stevel 		for (p = pathlist; *p != NULL; p++)
   1324     0    stevel 			free(*p);
   1325     0    stevel 		free(pathlist);
   1326     0    stevel 	}
   1327     0    stevel }
   1328     0    stevel 
   1329     0    stevel 
   1330     0    stevel /*
   1331     0    stevel  * Convert a vhci client name to phci client names.
   1332     0    stevel  *
   1333     0    stevel  * vhci_name	vhci client /devices name without the /devices prefix and
   1334     0    stevel  *		minor name component.
   1335     0    stevel  * num_paths	On return, *num_paths is set to the number paths in the
   1336     0    stevel  *		returned path list.
   1337     0    stevel  *
   1338     0    stevel  * Returns 	NULL terminated path list containing phci client paths is
   1339     0    stevel  *		returned on success. The memory for the path list is
   1340     0    stevel  *		allocated by this function and the caller must free it by
   1341     0    stevel  *		calling free_pathlist().
   1342     0    stevel  *		NULL is returned on failure.
   1343     0    stevel  */
   1344     0    stevel static char **
   1345     0    stevel vhci_to_phci(char *vhci_name, int *num_paths)
   1346     0    stevel {
   1347     0    stevel 	sv_iocdata_t ioc;
   1348     0    stevel 	uint_t npaths;
   1349     0    stevel 	int n;
   1350     0    stevel 	char **phci_list = NULL;
   1351     0    stevel 	char *node_name, *at;
   1352     0    stevel 	char vhci_name_buf[MAXPATHLEN];
   1353     0    stevel 
   1354     0    stevel 	logdmsg(("vhci_to_phci: vchi_name =  %s\n", vhci_name));
   1355     0    stevel 
   1356     0    stevel 	*num_paths = 0;
   1357     0    stevel 	(void) strlcpy(vhci_name_buf, vhci_name, MAXPATHLEN);
   1358     0    stevel 
   1359     0    stevel 	/* first get the number paths */
   1360     0    stevel 	bzero(&ioc, sizeof (sv_iocdata_t));
   1361     0    stevel 	ioc.client = vhci_name_buf;
   1362     0    stevel 	ioc.ret_elem = &npaths;
   1363     0    stevel 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO) != 0 ||
   1364     0    stevel 	    npaths == 0) {
   1365     0    stevel 		logdmsg(("vhci_to_phci: vhci_ctl failed to get npaths: %s\n",
   1366     0    stevel 		    strerror(errno)));
   1367     0    stevel 		return (NULL);
   1368     0    stevel 	}
   1369     0    stevel 
   1370     0    stevel 	/* now allocate memory for the path information and get all paths */
   1371     0    stevel 	bzero(&ioc, sizeof (sv_iocdata_t));
   1372     0    stevel 	ioc.client = vhci_name_buf;
   1373     0    stevel 	ioc.buf_elem = npaths;
   1374     0    stevel 	ioc.ret_elem = &npaths;
   1375     0    stevel 	if ((ioc.ret_buf = (sv_path_info_t *)calloc(npaths,
   1376     0    stevel 	    sizeof (sv_path_info_t))) == NULL)
   1377     0    stevel 		return (NULL);
   1378     0    stevel 	if (vhci_ctl(&ioc, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO) != 0 ||
   1379     0    stevel 	    npaths == 0) {
   1380     0    stevel 		logdmsg(("vhci_to_phci: vhci_ctl failed: %s\n",
   1381     0    stevel 		    strerror(errno)));
   1382     0    stevel 		goto out;
   1383     0    stevel 	}
   1384     0    stevel 
   1385     0    stevel 	if (ioc.buf_elem < npaths)
   1386     0    stevel 		npaths = ioc.buf_elem;
   1387     0    stevel 
   1388     0    stevel 	if ((node_name = strrchr(vhci_name_buf, '/')) == NULL ||
   1389     0    stevel 	    (at = strchr(node_name, '@')) == NULL)
   1390     0    stevel 		goto out;
   1391     0    stevel 
   1392     0    stevel 	node_name++;
   1393     0    stevel 	*at = '\0';
   1394     0    stevel 
   1395     0    stevel 	/* allocate one more (than npaths) for the terminating NULL pointer */
   1396     0    stevel 	if ((phci_list = calloc(npaths + 1, sizeof (char *))) == NULL)
   1397     0    stevel 		goto out;
   1398     0    stevel 
   1399     0    stevel 	/*
   1400     0    stevel 	 * add only online paths as non-online paths may not be accessible
   1401     0    stevel 	 * in the target environment.
   1402     0    stevel 	 */
   1403     0    stevel 	if ((n = add_to_phci_list(phci_list, ioc.ret_buf, npaths,
   1404     0    stevel 	    MDI_PATHINFO_STATE_ONLINE, node_name)) <= 0)
   1405     0    stevel 		goto out;
   1406     0    stevel 
   1407     0    stevel 	free(ioc.ret_buf);
   1408     0    stevel 	*num_paths = n;
   1409     0    stevel 
   1410     0    stevel #ifdef DEBUG
   1411     0    stevel 	logdmsg(("vhci_to_phci: phci list:\n"));
   1412     0    stevel 	log_pathlist(phci_list);
   1413     0    stevel #endif
   1414     0    stevel 	return (phci_list);
   1415     0    stevel 
   1416     0    stevel out:
   1417     0    stevel 	free(ioc.ret_buf);
   1418     0    stevel 	if (phci_list)
   1419     0    stevel 		free_pathlist(phci_list);
   1420     0    stevel 	return (NULL);
   1421     0    stevel }
   1422     0    stevel 
   1423     0    stevel /*
   1424     0    stevel  * build list of paths accessible from the target environment
   1425     0    stevel  */
   1426     0    stevel static int
   1427     0    stevel build_pathlist(char *rootdir, char *vhcipath, char **pathlist, int npaths)
   1428     0    stevel {
   1429     0    stevel 	int mpxio_disabled;
   1430     0    stevel 	int i, j;
   1431     0    stevel 	char *vpath = NULL;
   1432     0    stevel 
   1433     0    stevel 	for (i = 0; i < npaths; i++) {
   1434     0    stevel 		mpxio_disabled = is_mpxio_disabled(rootdir, pathlist[i]);
   1435     0    stevel 		logdmsg(("build_pathlist: mpxio_disabled = %d "
   1436     0    stevel 		    "on path %s\n", mpxio_disabled, pathlist[i]));
   1437     0    stevel 		if (mpxio_disabled == -1)
   1438     0    stevel 			return (-1);
   1439     0    stevel 		if (mpxio_disabled == 0) {
   1440     0    stevel 			/*
   1441     0    stevel 			 * mpxio is enabled on this phci path.
   1442     0    stevel 			 * So use vhci path instead of phci path.
   1443     0    stevel 			 */
   1444     0    stevel 			if (vpath == NULL) {
   1445     0    stevel 				if ((vpath = strdup(vhcipath)) == NULL)
   1446     0    stevel 					return (-1);
   1447     0    stevel 				free(pathlist[i]);
   1448     0    stevel 				/* keep vhci path at beginning of the list */
   1449     0    stevel 				for (j = i; j > 0; j--)
   1450     0    stevel 					pathlist[j] = pathlist[j - 1];
   1451     0    stevel 				pathlist[0] = vpath;
   1452     0    stevel 			} else {
   1453     0    stevel 				free(pathlist[i]);
   1454     0    stevel 				npaths--;
   1455     0    stevel 				for (j = i; j < npaths; j++)
   1456     0    stevel 					pathlist[j] = pathlist[j + 1];
   1457     0    stevel 				pathlist[npaths] = NULL;
   1458     0    stevel 				/* compensate for i++ in the for loop */
   1459     0    stevel 				i--;
   1460     0    stevel 			}
   1461     0    stevel 		}
   1462     0    stevel 	}
   1463     0    stevel 
   1464     0    stevel #ifdef DEBUG
   1465     0    stevel 	logdmsg(("build_pathlist: returning npaths = %d, pathlist:\n", npaths));
   1466     0    stevel 	log_pathlist(pathlist);
   1467     0    stevel #endif
   1468     0    stevel 	return (npaths);
   1469     0    stevel }
   1470     0    stevel 
   1471     0    stevel /*
   1472     0    stevel  * Check if the specified device is refenced in the vfstab file.
   1473     0    stevel  * Return 1 if referenced, 0 if not.
   1474     0    stevel  *
   1475     0    stevel  * rootdir	root directory of the target environment
   1476     0    stevel  * nodepath	/devices path of a device in the target environment without
   1477     0    stevel  *		the /devices prefix and minor component.
   1478     0    stevel  */
   1479     0    stevel static int
   1480     0    stevel is_dev_in_vfstab(char *rootdir, char *nodepath)
   1481     0    stevel {
   1482     0    stevel 	FILE *fp;
   1483     0    stevel 	int linksize;
   1484     0    stevel 	struct vfstab vfsent;
   1485     0    stevel 	char *abspath, *minor;
   1486     0    stevel 	char physpath[MAXPATHLEN];
   1487     0    stevel 	char buf[MAXPATHLEN];
   1488     0    stevel 
   1489     0    stevel 	logdmsg(("is_dev_in_vfstab: rootdir = %s, nodepath = %s\n",
   1490     0    stevel 	    rootdir, nodepath));
   1491     0    stevel 
   1492     0    stevel 	(void) snprintf(buf, sizeof (buf), "%s%s", rootdir, VFSTAB);
   1493     0    stevel 
   1494     0    stevel 	if ((fp = fopen(buf, "r")) == NULL)
   1495     0    stevel 		return (0);
   1496     0    stevel 
   1497     0    stevel 	/*
   1498     0    stevel 	 * read device specials from vfstab and compare names at physical
   1499     0    stevel 	 * node path level.
   1500     0    stevel 	 */
   1501     0    stevel 	while (getvfsent(fp, &vfsent) == 0) {
   1502     0    stevel 		if (strncmp(vfsent.vfs_special, SLASH_DEV_SLASH,
   1503     0    stevel 		    sizeof (SLASH_DEV_SLASH) - 1) == 0) {
   1504     0    stevel 			(void) snprintf(buf, MAXPATHLEN, "%s%s",
   1505     0    stevel 			    rootdir, vfsent.vfs_special);
   1506     0    stevel 			if ((linksize = readlink(buf, physpath,
   1507     0    stevel 			    MAXPATHLEN)) > 0 && linksize < (MAXPATHLEN - 1)) {
   1508     0    stevel 				physpath[linksize] = '\0';
   1509     0    stevel 				if ((abspath = strstr(physpath,
   1510     0    stevel 				    SLASH_DEVICES_SLASH)) == NULL)
   1511     0    stevel 					continue;
   1512     0    stevel 			} else
   1513     0    stevel 				continue;
   1514     0    stevel 		} else if (strncmp(vfsent.vfs_special, SLASH_DEVICES_SLASH,
   1515     0    stevel 		    sizeof (SLASH_DEVICES_SLASH) - 1) == 0) {
   1516     0    stevel 			(void) strlcpy(physpath, vfsent.vfs_special,
   1517     0    stevel 			    MAXPATHLEN);
   1518     0    stevel 			abspath = physpath;
   1519     0    stevel 		} else
   1520     0    stevel 			continue;
   1521     0    stevel 
   1522     0    stevel 		/* point to / after /devices */
   1523     0    stevel 		abspath += sizeof (SLASH_DEVICES_SLASH) - 2;
   1524     0    stevel 		/* strip minor component */
   1525     0    stevel 		if ((minor = strrchr(abspath, ':')) != NULL)
   1526     0    stevel 			*minor = '\0';
   1527     0    stevel 
   1528     0    stevel 		if (strcmp(nodepath, abspath) == 0) {
   1529     0    stevel 			(void) fclose(fp);
   1530     0    stevel 			logdmsg(("is_dev_in_vfstab: returning 1\n"));
   1531     0    stevel 			return (1);
   1532     0    stevel 		}
   1533     0    stevel 	}
   1534     0    stevel 
   1535     0    stevel 	(void) fclose(fp);
   1536     0    stevel 	return (0);
   1537     0    stevel }
   1538     0    stevel 
   1539     0    stevel #endif /* __sparc */
   1540     0    stevel 
   1541     0    stevel static int
   1542     0    stevel devlink_callback(di_devlink_t devlink, void *argp)
   1543     0    stevel {
   1544     0    stevel 	const char *link;
   1545     0    stevel 
   1546     0    stevel 	if ((link = di_devlink_path(devlink)) != NULL)
   1547     0    stevel 		(void) strlcpy((char *)argp, link, MAXPATHLEN);
   1548     0    stevel 
   1549     0    stevel 	return (DI_WALK_CONTINUE);
   1550     0    stevel }
   1551     0    stevel 
   1552     0    stevel /*
   1553     0    stevel  * Get the /dev name in the install environment corresponding to physpath.
   1554     0    stevel  *
   1555     0    stevel  * physpath	/devices path in the install environment without the /devices
   1556     0    stevel  * 		prefix.
   1557     0    stevel  * buf		caller supplied buffer where the /dev name is placed on return
   1558     0    stevel  * bufsz	length of the buffer
   1559     0    stevel  *
   1560     0    stevel  * Returns	strlen of the /dev name on success, -1 on failure.
   1561     0    stevel  */
   1562     0    stevel static int
   1563     0    stevel get_install_devlink(char *physpath, char *buf, size_t bufsz)
   1564     0    stevel {
   1565     0    stevel 	di_devlink_handle_t devlink_hdl;
   1566     0    stevel 	char devname[MAXPATHLEN];
   1567     0    stevel 
   1568     0    stevel 	logdmsg(("get_install_devlink: physpath = %s\n", physpath));
   1569     0    stevel 
   1570     0    stevel 	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
   1571     0    stevel 		logdmsg(("get_install_devlink: di_devlink_init() failed: %s\n",
   1572     0    stevel 		    strerror(errno)));
   1573     0    stevel 		return (-1);
   1574     0    stevel 	}
   1575     0    stevel 
   1576     0    stevel 	devname[0] = '\0';
   1577     0    stevel 	if (di_devlink_walk(devlink_hdl, NULL, physpath, DI_PRIMARY_LINK,
   1578     0    stevel 	    devname, devlink_callback) != 0 || devname[0] == '\0') {
   1579     0    stevel 		logdmsg(("get_install_devlink: di_devlink_walk failed: %s\n",
   1580     0    stevel 		    strerror(errno)));
   1581     0    stevel 		(void) di_devlink_fini(&devlink_hdl);
   1582     0    stevel 		return (-1);
   1583     0    stevel 	}
   1584     0    stevel 
   1585     0    stevel 	(void) di_devlink_fini(&devlink_hdl);
   1586     0    stevel 
   1587     0    stevel 	logdmsg(("get_install_devlink: devlink = %s\n", devname));
   1588     0    stevel 	return (strlcpy(buf, devname, bufsz));
   1589     0    stevel }
   1590     0    stevel 
   1591     0    stevel /*
   1592     0    stevel  * Get the /dev name in the target environment corresponding to physpath.
   1593     0    stevel  *
   1594     0    stevel  * rootdir	root directory of the target environment
   1595     0    stevel  * physpath	/devices path in the target environment without the /devices
   1596     0    stevel  * 		prefix.
   1597     0    stevel  * buf		caller supplied buffer where the /dev name is placed on return
   1598     0    stevel  * bufsz	length of the buffer
   1599     0    stevel  *
   1600     0    stevel  * Returns	strlen of the /dev name on success, -1 on failure.
   1601     0    stevel  */
   1602     0    stevel static int
   1603     0    stevel get_target_devlink(char *rootdir, char *physpath, char *buf, size_t bufsz)
   1604     0    stevel {
   1605     0    stevel 	char *p;
   1606     0    stevel 	int linksize;
   1607     0    stevel 	DIR *dirp;
   1608     0    stevel 	struct dirent *direntry;
   1609     0    stevel 	char dirpath[MAXPATHLEN];
   1610     0    stevel 	char devname[MAXPATHLEN];
   1611     0    stevel 	char physdev[MAXPATHLEN];
   1612     0    stevel 
   1613     0    stevel 	logdmsg(("get_target_devlink: rootdir = %s, physpath = %s\n",
   1614     0    stevel 	    rootdir, physpath));
   1615     0    stevel 
   1616     0    stevel 	if ((p = strrchr(physpath, '/')) == NULL)
   1617     0    stevel 		return (-1);
   1618     0    stevel 
   1619     0    stevel 	if (strstr(p, ",raw") != NULL) {
   1620     0    stevel 		(void) snprintf(dirpath, MAXPATHLEN, "%s/dev/rdsk", rootdir);
   1621     0    stevel 	} else {
   1622     0    stevel 		(void) snprintf(dirpath, MAXPATHLEN, "%s/dev/dsk", rootdir);
   1623     0    stevel 	}
   1624     0    stevel 
   1625     0    stevel 	if ((dirp = opendir(dirpath)) == NULL)
   1626     0    stevel 		return (-1);
   1627     0    stevel 
   1628     0    stevel 	while ((direntry = readdir(dirp)) != NULL) {
   1629     0    stevel 		if (strcmp(direntry->d_name, ".") == 0 ||
   1630     0    stevel 		    strcmp(direntry->d_name, "..") == 0)
   1631     0    stevel 			continue;
   1632     0    stevel 
   1633     0    stevel 		(void) snprintf(devname, MAXPATHLEN, "%s/%s",
   1634     0    stevel 		    dirpath, direntry->d_name);
   1635     0    stevel 
   1636     0    stevel 		if ((linksize = readlink(devname, physdev, MAXPATHLEN)) > 0 &&
   1637     0    stevel 		    linksize < (MAXPATHLEN - 1)) {
   1638     0    stevel 			physdev[linksize] = '\0';
   1639     0    stevel 			if ((p = strstr(physdev, SLASH_DEVICES_SLASH)) !=
   1640     0    stevel 			    NULL && strcmp(p + sizeof (SLASH_DEVICES) - 1,
   1641     0    stevel 			    physpath) == 0) {
   1642     0    stevel 				(void) closedir(dirp);
   1643     0    stevel 				logdmsg(("get_target_devlink: devlink = %s\n",
   1644     0    stevel 				    devname + strlen(rootdir)));
   1645     0    stevel 				return (strlcpy(buf, devname + strlen(rootdir),
   1646     0    stevel 				    bufsz));
   1647     0    stevel 			}
   1648     0    stevel 		}
   1649     0    stevel 	}
   1650     0    stevel 
   1651     0    stevel 	(void) closedir(dirp);
   1652     0    stevel 	return (-1);
   1653     0    stevel }
   1654     0    stevel 
   1655     0    stevel /*
   1656     0    stevel  * Convert device name to physpath.
   1657     0    stevel  *
   1658     0    stevel  * rootdir	root directory
   1659     0    stevel  * devname	a /dev name or /devices name under rootdir
   1660     0    stevel  * physpath	caller supplied buffer where the /devices path will be placed
   1661     0    stevel  *		on return (without the /devices prefix).
   1662     0    stevel  * physpathlen	length of the physpath buffer
   1663     0    stevel  *
   1664     0    stevel  * Returns 0 on success, -1 on failure.
   1665     0    stevel  */
   1666     0    stevel static int
   1667     0    stevel devname2physpath(char *rootdir, char *devname, char *physpath, int physpathlen)
   1668     0    stevel {
   1669     0    stevel 	int linksize;
   1670     0    stevel 	char *p;
   1671     0    stevel 	char devlink[MAXPATHLEN];
   1672     0    stevel 	char tmpphyspath[MAXPATHLEN];
   1673     0    stevel 
   1674     0    stevel 	logdmsg(("devname2physpath: rootdir = %s, devname = %s\n",
   1675     0    stevel 	    rootdir, devname));
   1676     0    stevel 
   1677     0    stevel 	if (strncmp(devname, SLASH_DEVICES_SLASH,
   1678     0    stevel 	    sizeof (SLASH_DEVICES_SLASH) - 1) != 0) {
   1679     0    stevel 		if (*rootdir == '\0')
   1680     0    stevel 			linksize = readlink(devname, tmpphyspath, MAXPATHLEN);
   1681     0    stevel 		else {
   1682     0    stevel 			(void) snprintf(devlink, MAXPATHLEN, "%s%s",
   1683     0    stevel 			    rootdir, devname);
   1684     0    stevel 			linksize = readlink(devlink, tmpphyspath, MAXPATHLEN);
   1685     0    stevel 		}
   1686     0    stevel 		if (linksize > 0 && linksize < (MAXPATHLEN - 1)) {
   1687     0    stevel 			tmpphyspath[linksize] = '\0';
   1688     0    stevel 			if ((p = strstr(tmpphyspath, SLASH_DEVICES_SLASH))
   1689     0    stevel 			    == NULL)
   1690     0    stevel 				return (-1);
   1691     0    stevel 		} else
   1692     0    stevel 			return (-1);
   1693     0    stevel 	} else
   1694     0    stevel 		p = devname;
   1695     0    stevel 
   1696     0    stevel 	(void) strlcpy(physpath, p + sizeof (SLASH_DEVICES) - 1, physpathlen);
   1697     0    stevel 	logdmsg(("devname2physpath: physpath = %s\n", physpath));
   1698     0    stevel 	return (0);
   1699     0    stevel }
   1700     0    stevel 
   1701     0    stevel /*
   1702     0    stevel  * Map a device name (devname) from the target environment to the
   1703     0    stevel  * install environment.
   1704     0    stevel  *
   1705     0    stevel  * rootdir	root directory of the target environment
   1706     0    stevel  * devname	/dev or /devices name under the target environment
   1707     0    stevel  * buf		caller supplied buffer where the mapped /dev name is placed
   1708     0    stevel  *		on return
   1709     0    stevel  * bufsz	length of the buffer
   1710     0    stevel  *
   1711     0    stevel  * Returns	strlen of the mapped /dev name on success, -1 on failure.
   1712     0    stevel  */
   1713     0    stevel int
   1714     0    stevel devfs_target2install(const char *rootdir, const char *devname, char *buf,
   1715     0    stevel     size_t bufsz)
   1716     0    stevel {
   1717     0    stevel 	char physpath[MAXPATHLEN];
   1718     0    stevel 
   1719     0    stevel 	logdmsg(("devfs_target2install: rootdir = %s, devname = %s\n",
   1720     0    stevel 	    STRVAL(rootdir), STRVAL(devname)));
   1721     0    stevel 
   1722     0    stevel 	if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
   1723     0    stevel 		return (-1);
   1724     0    stevel 
   1725     0    stevel 	if (strcmp(rootdir, "/") == 0)
   1726     0    stevel 		rootdir = "";
   1727     0    stevel 
   1728     0    stevel 	if (devname2physpath((char *)rootdir, (char *)devname, physpath,
   1729     0    stevel 	    MAXPATHLEN) != 0)
   1730     0    stevel 		return (-1);
   1731     0    stevel 
   1732     0    stevel #ifdef __sparc
   1733     0    stevel 	if (client_name_type(physpath) == CLIENT_TYPE_PHCI) {
   1734     0    stevel 		char *mapped_node_path, *minor;
   1735     0    stevel 		char minorbuf[MAXNAMELEN];
   1736     0    stevel 
   1737     0    stevel 		/* strip minor component if present */
   1738     0    stevel 		if ((minor = strrchr(physpath, ':')) != NULL) {
   1739     0    stevel 			*minor = '\0';
   1740     0    stevel 			minor++;
   1741     0    stevel 			(void) strlcpy(minorbuf, minor, MAXNAMELEN);
   1742     0    stevel 		}
   1743     0    stevel 		if ((mapped_node_path = phci_to_vhci(physpath)) != NULL) {
   1744     0    stevel 			if (minor)
   1745     0    stevel 				(void) snprintf(physpath, MAXPATHLEN,
   1746     0    stevel 				    "%s:%s", mapped_node_path, minorbuf);
   1747     0    stevel 			else
   1748     0    stevel 				(void) strlcpy(physpath, mapped_node_path,
   1749     0    stevel 				    MAXPATHLEN);
   1750     0    stevel 			free(mapped_node_path);
   1751     0    stevel 			logdmsg(("devfs_target2install: mapped physpath: %s\n",
   1752     0    stevel 			    physpath));
   1753     0    stevel 
   1754     0    stevel 		} else if (minor)
   1755     0    stevel 			*(minor - 1) = ':';
   1756     0    stevel 	}
   1757     0    stevel #endif /* __sparc */
   1758     0    stevel 
   1759     0    stevel 	return (get_install_devlink(physpath, buf, bufsz));
   1760     0    stevel }
   1761     0    stevel 
   1762     0    stevel /*
   1763     0    stevel  * Map a device name (devname) from the install environment to the target
   1764     0    stevel  * environment.
   1765     0    stevel  *
   1766     0    stevel  * rootdir	root directory of the target environment
   1767     0    stevel  * devname	/dev or /devices name under the install environment
   1768     0    stevel  * buf		caller supplied buffer where the mapped /dev name is placed
   1769     0    stevel  *		on return
   1770     0    stevel  * bufsz	length of the buffer
   1771     0    stevel  *
   1772     0    stevel  * Returns	strlen of the mapped /dev name on success, -1 on failure.
   1773     0    stevel  */
   1774     0    stevel int
   1775     0    stevel devfs_install2target(const char *rootdir, const char *devname, char *buf,
   1776     0    stevel     size_t bufsz)
   1777     0    stevel {
   1778     0    stevel 	char physpath[MAXPATHLEN];
   1779     0    stevel 
   1780     0    stevel 	logdmsg(("devfs_install2target: rootdir = %s, devname = %s\n",
   1781     0    stevel 	    STRVAL(rootdir), STRVAL(devname)));
   1782     0    stevel 
   1783     0    stevel 	if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
   1784     0    stevel 		return (-1);
   1785     0    stevel 
   1786     0    stevel 	if (strcmp(rootdir, "/") == 0)
   1787     0    stevel 		rootdir = "";
   1788     0    stevel 
   1789     0    stevel 	if (devname2physpath("", (char *)devname, physpath, MAXPATHLEN) != 0)
   1790     0    stevel 		return (-1);
   1791     0    stevel 
   1792     0    stevel #ifdef __sparc
   1793     0    stevel 	if (client_name_type(physpath) == CLIENT_TYPE_VHCI) {
   1794     0    stevel 		char **pathlist;
   1795     0    stevel 		int npaths, i, j;
   1796     0    stevel 		char *minor;
   1797     0    stevel 		char minorbuf[MAXNAMELEN];
   1798     0    stevel 
   1799     0    stevel 		/* strip minor component if present */
   1800     0    stevel 		if ((minor = strrchr(physpath, ':')) != NULL) {
   1801     0    stevel 			*minor = '\0';
   1802     0    stevel 			minor++;
   1803     0    stevel 			(void) strlcpy(minorbuf, minor, MAXNAMELEN);
   1804     0    stevel 		}
   1805     0    stevel 
   1806     0    stevel 		if ((pathlist = vhci_to_phci(physpath, &npaths)) == NULL)
   1807     0    stevel 			return (-1);
   1808     0    stevel 
   1809     0    stevel 		if ((npaths = build_pathlist((char *)rootdir, physpath,
   1810     0    stevel 		    pathlist, npaths)) <= 0) {
   1811     0    stevel 			free_pathlist(pathlist);
   1812     0    stevel 			return (-1);
   1813     0    stevel 		}
   1814     0    stevel 
   1815     0    stevel 		/*
   1816     0    stevel 		 * in case of more than one path, try to use the path
   1817     0    stevel 		 * referenced in the vfstab file, otherwise use the first path.
   1818     0    stevel 		 */
   1819     0    stevel 		j = 0;
   1820     0    stevel 		if (npaths > 1) {
   1821     0    stevel 			for (i = 0; i < npaths; i++) {
   1822     0    stevel 				if (is_dev_in_vfstab((char *)rootdir,
   1823     0    stevel 				    pathlist[i])) {
   1824     0    stevel 					j = i;
   1825     0    stevel 					break;
   1826     0    stevel 				}
   1827     0    stevel 			}
   1828     0    stevel 		}
   1829     0    stevel 
   1830     0    stevel 		if (minor)
   1831     0    stevel 			(void) snprintf(physpath, MAXPATHLEN,
   1832     0    stevel 			    "%s:%s", pathlist[j], minorbuf);
   1833     0    stevel 		else
   1834     0    stevel 			(void) strlcpy(physpath, pathlist[j], MAXPATHLEN);
   1835     0    stevel 		free_pathlist(pathlist);
   1836     0    stevel 	}
   1837     0    stevel #endif /* __sparc */
   1838     0    stevel 
   1839     0    stevel 	return (get_target_devlink((char *)rootdir, physpath, buf, bufsz));
   1840     0    stevel }
   1841     0    stevel 
   1842  4870        jg /*
   1843  4870        jg  * A parser for /etc/path_to_inst.
   1844  4870        jg  * The user-supplied callback is called once for each entry in the file.
   1845  4870        jg  * Returns 0 on success, ENOMEM/ENOENT/EINVAL on error.
   1846  4870        jg  * Callback may return DI_WALK_TERMINATE to terminate the walk,
   1847  4870        jg  * otherwise DI_WALK_CONTINUE.
   1848  4870        jg  */
   1849  4870        jg int
   1850  4870        jg devfs_parse_binding_file(const char *binding_file,
   1851  4870        jg 	int (*callback)(void *, const char *, int,
   1852  4870        jg 	    const char *), void *cb_arg)
   1853  4870        jg {
   1854  4870        jg 	token_t token;
   1855  4870        jg 	struct conf_file file;
   1856  4870        jg 	char tokval[MAX_TOKEN_SIZE];
   1857  4870        jg 	enum { STATE_RESET, STATE_DEVPATH, STATE_INSTVAL } state;
   1858  4870        jg 	char *devpath;
   1859  4870        jg 	char *bindname;
   1860  4870        jg 	int instval = 0;
   1861  4870        jg 	int rv;
   1862  4870        jg 
   1863  4870        jg 	if ((devpath = calloc(1, MAXPATHLEN)) == NULL)
   1864  4870        jg 		return (ENOMEM);
   1865  5467  ethindra 	if ((bindname = calloc(1, MAX_TOKEN_SIZE)) == NULL) {
   1866  5467  ethindra 		free(devpath);
   1867  4870        jg 		return (ENOMEM);
   1868  5467  ethindra 	}
   1869  4870        jg 
   1870  4870        jg 	if ((file.fp = fopen(binding_file, "r")) == NULL) {
   1871  4870        jg 		free(devpath);
   1872  4870        jg 		free(bindname);
   1873  4870        jg 		return (errno);
   1874  4870        jg 	}
   1875  4870        jg 
   1876  4870        jg 	file.filename = (char *)binding_file;
   1877  4870        jg 	file.linenum = 1;
   1878  4870        jg 
   1879  4870        jg 	state = STATE_RESET;
   1880  4870        jg 	while ((token = lex(&file, tokval, MAX_TOKEN_SIZE)) != T_EOF) {
   1881  4870        jg 		switch (token) {
   1882  4870        jg 		case T_POUND:
   1883  4870        jg 			/*
   1884  4870        jg 			 * Skip comments.
   1885  4870        jg 			 */
   1886  4870        jg 			find_eol(file.fp);
   1887  4870        jg 			break;
   1888  4870        jg 		case T_NAME:
   1889  4870        jg 		case T_STRING:
   1890  4870        jg 			switch (state) {
   1891  4870        jg 			case STATE_RESET:
   1892  4870        jg 				if (strlcpy(devpath, tokval,
   1893  4870        jg 				    MAXPATHLEN) >= MAXPATHLEN)
   1894  4870        jg 					goto err;
   1895  4870        jg 				state = STATE_DEVPATH;
   1896  4870        jg 				break;
   1897  4870        jg 			case STATE_INSTVAL:
   1898  4870        jg 				if (strlcpy(bindname, tokval,
   1899  4870        jg 				    MAX_TOKEN_SIZE) >= MAX_TOKEN_SIZE)
   1900  4870        jg 					goto err;
   1901  4870        jg 				rv = callback(cb_arg,
   1902  4870        jg 				    devpath, instval, bindname);
   1903  4870        jg 				if (rv == DI_WALK_TERMINATE)
   1904  4870        jg 					goto done;
   1905  4870        jg 				if (rv != DI_WALK_CONTINUE)
   1906  4870        jg 					goto err;
   1907  4870        jg 				state = STATE_RESET;
   1908  4870        jg 				break;
   1909  4870        jg 			default:
   1910  4870        jg 				file_err(&file, tok_err, tokval);
   1911  4870        jg 				state = STATE_RESET;
   1912  4870        jg 				break;
   1913  4870        jg 			}
   1914  4870        jg 			break;
   1915  4870        jg 		case T_DECVAL:
   1916  4870        jg 		case T_HEXVAL:
   1917  4870        jg 			switch (state) {
   1918  4870        jg 			case STATE_DEVPATH:
   1919  4870        jg 				instval = (int)strtol(tokval, NULL, 0);
   1920  4870        jg 				state = STATE_INSTVAL;
   1921  4870        jg 				break;
   1922  4870        jg 			default:
   1923  4870        jg 				file_err(&file, tok_err, tokval);
   1924  4870        jg 				state = STATE_RESET;
   1925  4870        jg 				break;
   1926  4870        jg 			}
   1927  4870        jg 			break;
   1928  4870        jg 		case T_NEWLINE:
   1929  4870        jg 			file.linenum++;
   1930  4870        jg 			state = STATE_RESET;
   1931  4870        jg 			break;
   1932  4870        jg 		default:
   1933  4870        jg 			file_err(&file, tok_err, tokval);
   1934  4870        jg 			state = STATE_RESET;
   1935  4870        jg 			break;
   1936  4870        jg 		}
   1937  4870        jg 	}
   1938  4870        jg 
   1939  4870        jg done:
   1940  4870        jg 	(void) fclose(file.fp);
   1941  4870        jg 	free(devpath);
   1942  4870        jg 	free(bindname);
   1943  4870        jg 	return (0);
   1944  4870        jg 
   1945  4870        jg err:
   1946  4870        jg 	(void) fclose(file.fp);
   1947  4870        jg 	free(devpath);
   1948  4870        jg 	free(bindname);
   1949  4870        jg 	return (EINVAL);
   1950  4870        jg }
   1951  4870        jg 
   1952  4870        jg /*
   1953  4870        jg  * Walk the minor nodes of all children below the specified device
   1954  4870        jg  * by calling the provided callback with the path to each minor.
   1955  4870        jg  */
   1956  4870        jg static int
   1957  4870        jg devfs_walk_children_minors(const char *device_path, struct stat *st,
   1958  4870        jg     int (*callback)(void *, const char *), void *cb_arg, int *terminate)
   1959  4870        jg {
   1960  4870        jg 	DIR *dir;
   1961  4870        jg 	struct dirent *dp;
   1962  4870        jg 	char *minor_path = NULL;
   1963  4870        jg 	int need_close = 0;
   1964  4870        jg 	int rv;
   1965  4870        jg 
   1966  4870        jg 	if ((minor_path = calloc(1, MAXPATHLEN)) == NULL)
   1967  4870        jg 		return (ENOMEM);
   1968  4870        jg 
   1969  4870        jg 	if ((dir = opendir(device_path)) == NULL) {
   1970  4870        jg 		rv = ENOENT;
   1971  4870        jg 		goto err;
   1972  4870        jg 	}
   1973  4870        jg 	need_close = 1;
   1974  4870        jg 
   1975  4870        jg 	while ((dp = readdir(dir)) != NULL) {
   1976  4870        jg 		if ((strcmp(dp->d_name, ".") == 0) ||
   1977  4870        jg 		    (strcmp(dp->d_name, "..") == 0))
   1978  4870        jg 			continue;
   1979  4870        jg 		(void) snprintf(minor_path, MAXPATHLEN,
   1980  4870        jg 		    "%s/%s", device_path, dp->d_name);
   1981  4870        jg 		if (stat(minor_path, st) == -1)
   1982  4870        jg 			continue;
   1983  4870        jg 		if (S_ISDIR(st->st_mode)) {
   1984  4870        jg 			rv = devfs_walk_children_minors(
   1985  4870        jg 			    (const char *)minor_path, st,
   1986  4870        jg 			    callback, cb_arg, terminate);
   1987  4870        jg 			if (rv != 0)
   1988  4870        jg 				goto err;
   1989  4870        jg 			if (*terminate)
   1990  4870        jg 				break;
   1991  4870        jg 		} else {
   1992  4870        jg 			rv = callback(cb_arg, minor_path);
   1993  4870        jg 			if (rv == DI_WALK_TERMINATE) {
   1994  4870        jg 				*terminate = 1;
   1995  4870        jg 				break;
   1996  4870        jg 			}
   1997  4870        jg 			if (rv != DI_WALK_CONTINUE) {
   1998  4870        jg 				rv = EINVAL;
   1999  4870        jg 				goto err;
   2000  4870        jg 			}
   2001  4870        jg 		}
   2002  4870        jg 	}
   2003  4870        jg 
   2004  4870        jg 	rv = 0;
   2005  4870        jg err:
   2006  4870        jg 	if (need_close)
   2007  4870        jg 		(void) closedir(dir);
   2008  4870        jg 	if (minor_path)
   2009  4870        jg 		free(minor_path);
   2010  4870        jg 	return (rv);
   2011  4870        jg }
   2012  4870        jg 
   2013  4870        jg /*
   2014  4870        jg  * Return the path to each minor node for a device by
   2015  4870        jg  * calling the provided callback.
   2016  4870        jg  */
   2017  4870        jg static int
   2018  4870        jg devfs_walk_device_minors(const char *device_path, struct stat *st,
   2019  4870        jg     int (*callback)(void *, const char *), void *cb_arg, int *terminate)
   2020  4870        jg {
   2021  4870        jg 	char *minor_path;
   2022  4870        jg 	char *devpath;
   2023  4870        jg 	char *expr;
   2024  4870        jg 	regex_t regex;
   2025  4870        jg 	int need_regfree = 0;
   2026  4870        jg 	int need_close = 0;
   2027  4870        jg 	DIR *dir;
   2028  4870        jg 	struct dirent *dp;
   2029  4870        jg 	int rv;
   2030  4870        jg 	char *p;
   2031  4870        jg 
   2032  4870        jg 	minor_path = calloc(1, MAXPATHLEN);
   2033  4870        jg 	devpath = calloc(1, MAXPATHLEN);
   2034  4870        jg 	expr = calloc(1, MAXNAMELEN);
   2035  4870        jg 	if (devpath == NULL || expr == NULL || minor_path == NULL) {
   2036  4870        jg 		rv = ENOMEM;
   2037  4870        jg 		goto err;
   2038  4870        jg 	}
   2039  4870        jg 
   2040  4870        jg 	rv = EINVAL;
   2041  4870        jg 	if (strlcpy(devpath, device_path, MAXPATHLEN) >= MAXPATHLEN)
   2042  4870        jg 		goto err;
   2043  4870        jg 	if ((p = strrchr(devpath, '/')) == NULL)
   2044  4870        jg 		goto err;
   2045  4870        jg 	*p++ = 0;
   2046  4870        jg 	if (strlen(p) == 0)
   2047  4870        jg 		goto err;
   2048  4870        jg 	if (snprintf(expr, MAXNAMELEN, "%s:.*", p) >= MAXNAMELEN)
   2049  4870        jg 		goto err;
   2050  4870        jg 	if (regcomp(&regex, expr, REG_EXTENDED) != 0)
   2051  4870        jg 		goto err;
   2052  4870        jg 	need_regfree = 1;
   2053  4870        jg 
   2054  4870        jg 	if ((dir = opendir(devpath)) == NULL) {
   2055  4870        jg 		rv = ENOENT;
   2056  4870        jg 		goto err;
   2057  4870        jg 	}
   2058  4870        jg 	need_close = 1;
   2059  4870        jg 
   2060  4870        jg 	while ((dp = readdir(dir)) != NULL) {
   2061  4870        jg 		if ((strcmp(dp->d_name, ".") == 0) ||
   2062  4870        jg 		    (strcmp(dp->d_name, "..") == 0))
   2063  4870        jg 			continue;
   2064  4870        jg 		(void) snprintf(minor_path, MAXPATHLEN,
   2065  4870        jg 		    "%s/%s", devpath, dp->d_name);
   2066  4870        jg 		if (stat(minor_path, st) == -1)
   2067  4870        jg 			continue;
   2068  4870        jg 		if ((S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) &&
   2069  4870        jg 		    regexec(&regex, dp->d_name, 0, NULL, 0) == 0) {
   2070  4870        jg 			rv = callback(cb_arg, minor_path);
   2071  4870        jg 			if (rv == DI_WALK_TERMINATE) {
   2072  4870        jg 				*terminate = 1;
   2073  4870        jg 				break;
   2074  4870        jg 			}
   2075  4870        jg 			if (rv != DI_WALK_CONTINUE) {
   2076  4870        jg 				rv = EINVAL;
   2077  4870        jg 				goto err;
   2078  4870        jg 			}
   2079  4870        jg 		}
   2080  4870        jg 	}
   2081  4870        jg 
   2082  4870        jg 	rv = 0;
   2083  4870        jg err:
   2084  4870        jg 	if (need_close)
   2085  4870        jg 		(void) closedir(dir);
   2086  4870        jg 	if (need_regfree)
   2087  4870        jg 		regfree(&regex);
   2088  4870        jg 	if (devpath)
   2089  4870        jg 		free(devpath);
   2090  4870        jg 	if (minor_path)
   2091  4870        jg 		free(minor_path);
   2092  4870        jg 	if (expr)
   2093  4870        jg 		free(expr);
   2094  4870        jg 	return (rv);
   2095  4870        jg }
   2096  4870        jg 
   2097  4870        jg /*
   2098  4870        jg  * Perform a walk of all minor nodes for the specified device,
   2099  4870        jg  * and minor nodes below the device.
   2100  4870        jg  */
   2101  4870        jg int
   2102  4870        jg devfs_walk_minor_nodes(const char *device_path,
   2103  4870        jg 	int (*callback)(void *, const char *), void *cb_arg)
   2104  4870        jg {
   2105  4870        jg 	struct stat stbuf;
   2106  4870        jg 	int rv;
   2107  4870        jg 	int terminate = 0;
   2108  4870        jg 
   2109  4870        jg 	rv = devfs_walk_device_minors(device_path,
   2110  4870        jg 	    &stbuf, callback, cb_arg, &terminate);
   2111  4870        jg 	if (rv == 0 && terminate == 0) {
   2112  4870        jg 		rv = devfs_walk_children_minors(device_path,
   2113  4870        jg 		    &stbuf, callback, cb_arg, &terminate);
   2114  4870        jg 	}
   2115  4870        jg 	return (rv);
   2116  4870        jg }
   2117  4870        jg 
   2118     0    stevel #ifdef DEBUG
   2119     0    stevel 
   2120     0    stevel static void
   2121     0    stevel vlog_debug_msg(char *fmt, va_list ap)
   2122     0    stevel {
   2123     0    stevel 	time_t clock;
   2124     0    stevel 	struct tm t;
   2125     0    stevel 
   2126     0    stevel 	if (!devfsmap_debug)
   2127     0    stevel 		return;
   2128     0    stevel 
   2129     0    stevel 	if (logfp == NULL) {
   2130     0    stevel 		if (*devfsmap_logfile != '\0') {
   2131     0    stevel 			logfp = fopen(devfsmap_logfile, "a");
   2132     0    stevel 			if (logfp)
   2133     0    stevel 				(void) fprintf(logfp, "\nNew Log:\n");
   2134     0    stevel 		}
   2135     0    stevel 
   2136     0    stevel 		if (logfp == NULL)
   2137     0    stevel 			logfp = stdout;
   2138     0    stevel 	}
   2139     0    stevel 
   2140     0    stevel 	clock = time(NULL);
   2141     0    stevel 	(void) localtime_r(&clock, &t);
   2142     0    stevel 	(void) fprintf(logfp, "%02d:%02d:%02d ", t.tm_hour, t.tm_min,
   2143     0    stevel 	    t.tm_sec);
   2144     0    stevel 	(void) vfprintf(logfp, fmt, ap);
   2145     0    stevel 	(void) fflush(logfp);
   2146     0    stevel }
   2147     0    stevel 
   2148     0    stevel static void
   2149     0    stevel log_debug_msg(char *fmt, ...)
   2150     0    stevel {
   2151     0    stevel 	va_list ap;
   2152     0    stevel 
   2153     0    stevel 	va_start(ap, fmt);
   2154     0    stevel 	vlog_debug_msg(fmt, ap);
   2155     0    stevel 	va_end(ap);
   2156     0    stevel }
   2157     0    stevel 
   2158     0    stevel #ifdef __sparc
   2159     0    stevel 
   2160     0    stevel static char *
   2161     0    stevel mpxio_disable_string(int mpxio_disable)
   2162     0    stevel {
   2163     0    stevel 	if (mpxio_disable == 0)
   2164     0    stevel 		return ("no");
   2165     0    stevel 	else if (mpxio_disable == 1)
   2166     0    stevel 		return ("yes");
   2167     0    stevel 	else
   2168     0    stevel 		return ("not specified");
   2169     0    stevel }
   2170     0    stevel 
   2171     0    stevel static void
   2172     0    stevel log_confent_list(char *filename, struct conf_entry *confent_list,
   2173     0    stevel     int global_mpxio_disable)
   2174     0    stevel {
   2175     0    stevel 	struct conf_entry *confent;
   2176     0    stevel 
   2177     0    stevel 	log_debug_msg("log_confent_list: filename = %s:\n", filename);
   2178     0    stevel 	if (global_mpxio_disable != -1)
   2179     0    stevel 		log_debug_msg("\tdriver global mpxio_disable = \"%s\"\n\n",
   2180     0    stevel 		    mpxio_disable_string(global_mpxio_disable));
   2181     0    stevel 
   2182     0    stevel 	for (confent = confent_list; confent != NULL; confent = confent->next) {
   2183     0    stevel 		if (confent->name)
   2184     0    stevel 			log_debug_msg("\tname = %s\n", confent->name);
   2185     0    stevel 		if (confent->parent)
   2186     0    stevel 			log_debug_msg("\tparent = %s\n", confent->parent);
   2187     0    stevel 		if (confent->class)
   2188     0    stevel 			log_debug_msg("\tclass = %s\n", confent->class);
   2189     0    stevel 		if (confent->unit_address)
   2190     0    stevel 			log_debug_msg("\tunit_address = %s\n",
   2191     0    stevel 			    confent->unit_address);
   2192     0    stevel 		if (confent->port != -1)
   2193     0    stevel 			log_debug_msg("\tport = %d\n", confent->port);
   2194     0    stevel 		log_debug_msg("\tmpxio_disable = \"%s\"\n\n",
   2195  4870        jg 		    mpxio_disable_string(confent->mpxio_disable));
   2196     0    stevel 	}
   2197     0    stevel }
   2198     0    stevel 
   2199     0    stevel static void
   2200     0    stevel log_pathlist(char **pathlist)
   2201     0    stevel {
   2202     0    stevel 	char **p;
   2203     0    stevel 
   2204     0    stevel 	for (p = pathlist; *p != NULL; p++)
   2205     0    stevel 		log_debug_msg("\t%s\n", *p);
   2206     0    stevel }
   2207     0    stevel 
   2208     0    stevel #endif /* __sparc */
   2209     0    stevel 
   2210     0    stevel #endif /* DEBUG */
   2211