xref: /onnv-gate/usr/src/lib/libbsm/common/getdment.c (revision 12373:a6d4ab1b6cf3)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12373SJan.Parcel@Sun.COM  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
23*12373SJan.Parcel@Sun.COM  *
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <string.h>
2711529SJan.Parcel@Sun.COM #include <strings.h>
281676Sjpk #include <stdlib.h>
2911529SJan.Parcel@Sun.COM #include <unistd.h>
3011529SJan.Parcel@Sun.COM #include <limits.h>
310Sstevel@tonic-gate #include <bsm/devices.h>
321676Sjpk #include <bsm/devalloc.h>
331676Sjpk 
341676Sjpk char *strtok_r(char *, const char *, char **);
350Sstevel@tonic-gate 
361676Sjpk /* externs from getdaent.c */
371676Sjpk extern char *trim_white(char *);
381676Sjpk extern int pack_white(char *);
391676Sjpk extern char *getdadmfield(char *, char *);
401676Sjpk extern int getdadmline(char *, int, FILE *);
410Sstevel@tonic-gate 
420Sstevel@tonic-gate static struct _dmapbuff {
431676Sjpk 	FILE		*_dmapf;	/* for /etc/security/device_maps */
441676Sjpk 	devmap_t	_interpdevmap;
451676Sjpk 	char		_interpdmline[DA_BUFSIZE + 1];
461676Sjpk 	char		*_DEVMAP;
470Sstevel@tonic-gate } *__dmapbuff;
480Sstevel@tonic-gate 
491676Sjpk #define	dmapf	(_dmap->_dmapf)
501676Sjpk #define	interpdevmap	(_dmap->_interpdevmap)
511676Sjpk #define	interpdmline	(_dmap->_interpdmline)
521676Sjpk #define	DEVMAPS_FILE	(_dmap->_DEVMAP)
531676Sjpk 
541676Sjpk devmap_t	*dmap_interpret(char *, devmap_t *);
551676Sjpk static devmap_t	*dmap_interpretf(char *, devmap_t *);
561676Sjpk static devmap_t *dmap_dlexpand(devmap_t *);
57*12373SJan.Parcel@Sun.COM static int dmap_resolve_link(char *devpath, char **devfs_path);
581676Sjpk 
591676Sjpk int	dmap_matchdev(devmap_t *, char *);
601676Sjpk int	dmap_matchname(devmap_t *, char *);
611676Sjpk 
621676Sjpk 
631676Sjpk /*
641676Sjpk  * _dmapalloc -
651676Sjpk  *	allocates common buffers and structures.
661676Sjpk  *	returns pointer to the new structure, else returns NULL on error.
671676Sjpk  */
681676Sjpk static struct _dmapbuff *
_dmapalloc(void)691676Sjpk _dmapalloc(void)
701676Sjpk {
711676Sjpk 	struct _dmapbuff *_dmap = __dmapbuff;
721676Sjpk 
731676Sjpk 	if (_dmap == NULL) {
741676Sjpk 		_dmap = (struct _dmapbuff *)calloc((unsigned)1,
751676Sjpk 		    (unsigned)sizeof (*__dmapbuff));
761676Sjpk 		if (_dmap == NULL)
771676Sjpk 			return (NULL);
781676Sjpk 		DEVMAPS_FILE = "/etc/security/device_maps";
791676Sjpk 		dmapf = NULL;
801676Sjpk 		__dmapbuff = _dmap;
811676Sjpk 	}
821676Sjpk 
831676Sjpk 	return (_dmap);
841676Sjpk }
851676Sjpk 
861676Sjpk /*
871676Sjpk  * setdmapent -
881676Sjpk  *	rewinds the device_maps file to the beginning.
891676Sjpk  */
901676Sjpk void
setdmapent(void)911676Sjpk setdmapent(void)
921676Sjpk {
931676Sjpk 	struct _dmapbuff *_dmap = _dmapalloc();
941676Sjpk 
951676Sjpk 	if (_dmap == NULL)
961676Sjpk 		return;
971676Sjpk 	if (dmapf == NULL)
981914Scasper 		dmapf = fopen(DEVMAPS_FILE, "rF");
991676Sjpk 	else
1001676Sjpk 		rewind(dmapf);
1011676Sjpk }
1021676Sjpk 
1031676Sjpk /*
1041676Sjpk  * enddmapent -
1051676Sjpk  *	closes device_maps file.
1061676Sjpk  */
1071676Sjpk void
enddmapent(void)1081676Sjpk enddmapent(void)
1091676Sjpk {
1101676Sjpk 	struct _dmapbuff *_dmap = _dmapalloc();
1111676Sjpk 
1121676Sjpk 	if (_dmap == NULL)
1131676Sjpk 		return;
1141676Sjpk 	if (dmapf != NULL) {
1151676Sjpk 		(void) fclose(dmapf);
1161676Sjpk 		dmapf = NULL;
1171676Sjpk 	}
1181676Sjpk }
1191676Sjpk 
1201676Sjpk void
freedmapent(devmap_t * dmap)1211676Sjpk freedmapent(devmap_t *dmap)
1221676Sjpk {
1231676Sjpk 	char	**darp;
1241676Sjpk 
1251676Sjpk 	if ((darp = dmap->dmap_devarray) != NULL) {
1261676Sjpk 		while (*darp != NULL)
1271676Sjpk 			free(*darp++);
1281676Sjpk 		free(dmap->dmap_devarray);
1291676Sjpk 		dmap->dmap_devarray = NULL;
1301676Sjpk 	}
1311676Sjpk }
1321676Sjpk 
1331676Sjpk /*
1341676Sjpk  * setdmapfile -
1351676Sjpk  *	changes the default device_maps file to the one specified.
1361676Sjpk  *	It does not close the previous file. If this is desired, enddmapent
1371676Sjpk  *	should be called prior to setdampfile.
1381676Sjpk  */
1391676Sjpk void
setdmapfile(char * file)1401676Sjpk setdmapfile(char *file)
1411676Sjpk {
1421676Sjpk 	struct _dmapbuff *_dmap = _dmapalloc();
1431676Sjpk 
1441676Sjpk 	if (_dmap == NULL)
1451676Sjpk 		return;
1461676Sjpk 	if (dmapf != NULL) {
1471676Sjpk 		(void) fclose(dmapf);
1481676Sjpk 		dmapf = NULL;
1491676Sjpk 	}
1501676Sjpk 	DEVMAPS_FILE = file;
1511676Sjpk }
1521676Sjpk 
1531676Sjpk /*
1541676Sjpk  * getdmapent -
1551676Sjpk  * 	When first called, returns a pointer to the first devmap_t structure
1561676Sjpk  * 	in device_maps; thereafter, it returns a pointer to the next devmap_t
1571676Sjpk  *	structure in the file. Thus successive calls can be used to read the
1581676Sjpk  *	entire file.
1591676Sjpk  *	call to getdmapent should be bracketed by setdmapent and enddmapent.
1601676Sjpk  * 	returns pointer to devmap_t found, else returns NULL if no entry found
1611676Sjpk  * 	or on error.
1621676Sjpk  */
1631676Sjpk devmap_t *
getdmapent(void)1641676Sjpk getdmapent(void)
1651676Sjpk {
1661676Sjpk 	devmap_t		*dmap;
1671676Sjpk 	struct _dmapbuff 	*_dmap = _dmapalloc();
1681676Sjpk 
1691676Sjpk 	if ((_dmap == 0) || (dmapf == NULL))
1701676Sjpk 		return (NULL);
1711676Sjpk 
1721676Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
1731676Sjpk 	    dmapf) != 0) {
1741676Sjpk 		if ((dmap = dmap_interpret(interpdmline,
1751676Sjpk 		    &interpdevmap)) == NULL)
1761676Sjpk 			continue;
1771676Sjpk 		return (dmap);
1781676Sjpk 	}
1791676Sjpk 
1801676Sjpk 	return (NULL);
1811676Sjpk }
1821676Sjpk 
1831676Sjpk /*
1841676Sjpk  * getdmapnam -
1851676Sjpk  *	searches from the beginning of device_maps for the device specified by
1861676Sjpk  *	its name.
1871676Sjpk  *	call to getdmapnam should be bracketed by setdmapent and enddmapent.
1881676Sjpk  * 	returns pointer to devmapt_t for the device if it is found, else
1891676Sjpk  * 	returns NULL if device not found or in case of error.
1901676Sjpk  */
1911676Sjpk devmap_t *
getdmapnam(char * name)1921676Sjpk getdmapnam(char *name)
1931676Sjpk {
1941676Sjpk 	devmap_t		*dmap;
1951676Sjpk 	struct _dmapbuff	*_dmap = _dmapalloc();
1961676Sjpk 
1971676Sjpk 	if ((name == NULL) || (_dmap == 0) || (dmapf == NULL))
1981676Sjpk 		return (NULL);
1991676Sjpk 
2001676Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
2011676Sjpk 	    dmapf) != 0) {
2021676Sjpk 		if (strstr(interpdmline, name) == NULL)
2031676Sjpk 			continue;
2041676Sjpk 		if ((dmap = dmap_interpretf(interpdmline,
2051676Sjpk 		    &interpdevmap)) == NULL)
2061676Sjpk 			continue;
2071676Sjpk 		if (dmap_matchname(dmap, name)) {
2081676Sjpk 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
2091676Sjpk 				continue;
2101676Sjpk 			enddmapent();
2111676Sjpk 			return (dmap);
2121676Sjpk 		}
2131676Sjpk 		freedmapent(dmap);
2141676Sjpk 	}
2151676Sjpk 
2161676Sjpk 	return (NULL);
2171676Sjpk }
2181676Sjpk 
2190Sstevel@tonic-gate /*
2201676Sjpk  * getdmapdev -
2211676Sjpk  *	searches from the beginning of device_maps for the device specified by
2221676Sjpk  *	its logical name.
2231676Sjpk  *	call to getdmapdev should be bracketed by setdmapent and enddmapent.
2241676Sjpk  * 	returns  pointer to the devmap_t for the device if device is found,
2251676Sjpk  *	else returns NULL if device not found or on error.
2261676Sjpk  */
2271676Sjpk devmap_t *
getdmapdev(char * dev)2281676Sjpk getdmapdev(char *dev)
2291676Sjpk {
2301676Sjpk 	devmap_t		*dmap;
2311676Sjpk 	struct _dmapbuff	*_dmap = _dmapalloc();
2321676Sjpk 
2331676Sjpk 	if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL))
2341676Sjpk 		return (NULL);
2351676Sjpk 
2361676Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
2371676Sjpk 	    dmapf) != 0) {
2381676Sjpk 		if ((dmap = dmap_interpret(interpdmline,
2391676Sjpk 		    &interpdevmap)) == NULL)
2401676Sjpk 			continue;
2411676Sjpk 		if (dmap_matchdev(dmap, dev)) {
2421676Sjpk 			enddmapent();
2431676Sjpk 			return (dmap);
2441676Sjpk 		}
2451676Sjpk 		freedmapent(dmap);
2461676Sjpk 	}
2471676Sjpk 
2481676Sjpk 	return (NULL);
2491676Sjpk }
2501676Sjpk 
2511676Sjpk /*
2521676Sjpk  * getdmaptype -
2531676Sjpk  *	searches from the beginning of device_maps for the device specified by
2541676Sjpk  *	its type.
2551676Sjpk  *	call to getdmaptype should be bracketed by setdmapent and enddmapent.
2561676Sjpk  * 	returns pointer to devmap_t found, else returns NULL if no entry found
2571676Sjpk  * 	or on error.
2581676Sjpk  */
2591676Sjpk devmap_t *
getdmaptype(char * type)2601676Sjpk getdmaptype(char *type)
2611676Sjpk {
2621676Sjpk 	devmap_t		*dmap;
2631676Sjpk 	struct _dmapbuff	*_dmap = _dmapalloc();
2641676Sjpk 
2651676Sjpk 	if ((type == NULL) || (_dmap == 0) || (dmapf == NULL))
2661676Sjpk 		return (NULL);
2671676Sjpk 
2681676Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
2691676Sjpk 	    dmapf) != 0) {
2701676Sjpk 		if ((dmap = dmap_interpretf(interpdmline,
2711676Sjpk 		    &interpdevmap)) == NULL)
2721676Sjpk 			continue;
2731676Sjpk 		if (dmap->dmap_devtype != NULL &&
2741676Sjpk 		    strcmp(type, dmap->dmap_devtype) == 0) {
2751676Sjpk 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
2761676Sjpk 				continue;
2771676Sjpk 			return (dmap);
2781676Sjpk 		}
2791676Sjpk 		freedmapent(dmap);
2801676Sjpk 	}
2811676Sjpk 
2821676Sjpk 	return (NULL);
2831676Sjpk }
2841676Sjpk 
2851676Sjpk /*
28611529SJan.Parcel@Sun.COM  * dmap_match_one_dev -
28711529SJan.Parcel@Sun.COM  *    Checks if the specified devmap_t contains strings
288*12373SJan.Parcel@Sun.COM  *    for the same link as the device specified.
28911529SJan.Parcel@Sun.COM  *
29011529SJan.Parcel@Sun.COM  *    Returns 1 for a match, else returns 0.
29111529SJan.Parcel@Sun.COM  */
29211529SJan.Parcel@Sun.COM static int
dmap_match_one_dev(devmap_t * dmap,char * dev)29311529SJan.Parcel@Sun.COM dmap_match_one_dev(devmap_t *dmap, char *dev)
29411529SJan.Parcel@Sun.COM {
29511529SJan.Parcel@Sun.COM 	char **dva;
29611529SJan.Parcel@Sun.COM 	char *dv;
297*12373SJan.Parcel@Sun.COM 	char *dmap_link;
298*12373SJan.Parcel@Sun.COM 	char *dev_link;
299*12373SJan.Parcel@Sun.COM 	char stage_link[PATH_MAX + 1];
30011529SJan.Parcel@Sun.COM 
30111529SJan.Parcel@Sun.COM 	if (dmap->dmap_devarray == NULL)
30211529SJan.Parcel@Sun.COM 		return (0);
30311529SJan.Parcel@Sun.COM 
30411529SJan.Parcel@Sun.COM 	for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva++) {
30511529SJan.Parcel@Sun.COM 		if (strstr(dev, dv) != NULL)
30611529SJan.Parcel@Sun.COM 			return (1);
30711529SJan.Parcel@Sun.COM 	}
308*12373SJan.Parcel@Sun.COM 	/* check if both refer to same physical device */
309*12373SJan.Parcel@Sun.COM 	(void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link));
310*12373SJan.Parcel@Sun.COM 	if (dmap_resolve_link(stage_link, &dmap_link) != 0)
311*12373SJan.Parcel@Sun.COM 		return (0);
312*12373SJan.Parcel@Sun.COM 	(void) strncpy(stage_link, dev, sizeof (stage_link));
313*12373SJan.Parcel@Sun.COM 	if (dmap_resolve_link(stage_link, &dev_link) != 0) {
314*12373SJan.Parcel@Sun.COM 		free(dmap_link);
315*12373SJan.Parcel@Sun.COM 		return (0);
316*12373SJan.Parcel@Sun.COM 	}
317*12373SJan.Parcel@Sun.COM 	if (strcmp(dev_link, dmap_link) == 0) {
318*12373SJan.Parcel@Sun.COM 		free(dmap_link);
319*12373SJan.Parcel@Sun.COM 		free(dev_link);
320*12373SJan.Parcel@Sun.COM 		return (1);
321*12373SJan.Parcel@Sun.COM 	}
322*12373SJan.Parcel@Sun.COM 	free(dmap_link);
323*12373SJan.Parcel@Sun.COM 	free(dev_link);
32411529SJan.Parcel@Sun.COM 	return (0);
32511529SJan.Parcel@Sun.COM }
32611529SJan.Parcel@Sun.COM 
32711529SJan.Parcel@Sun.COM /*
3281676Sjpk  * dmap_matchdev -
3291676Sjpk  * 	checks if the specified devmap_t is for the device specified.
3301676Sjpk  *	returns 1 if it is, else returns 0.
3311676Sjpk  */
3321676Sjpk int
dmap_matchdev(devmap_t * dmap,char * dev)3331676Sjpk dmap_matchdev(devmap_t *dmap, char *dev)
3341676Sjpk {
3351676Sjpk 	char **dva;
3361676Sjpk 	char *dv;
3371676Sjpk 
3381676Sjpk 	if (dmap->dmap_devarray == NULL)
3391676Sjpk 		return (0);
3401676Sjpk 	for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva ++) {
3411676Sjpk 		if (strcmp(dv, dev) == 0)
3421676Sjpk 			return (1);
3431676Sjpk 	}
3441676Sjpk 
3451676Sjpk 	return (0);
3461676Sjpk }
3471676Sjpk 
3481676Sjpk /*
349*12373SJan.Parcel@Sun.COM  * Requires a match of the /dev/? links, not just the logical devname
35011529SJan.Parcel@Sun.COM  * Returns 1 for match found, 0 for match not found, 2 for invalid arguments.
351*12373SJan.Parcel@Sun.COM  *
352*12373SJan.Parcel@Sun.COM  * Also looks for an instance number at the end of the logical name, and
353*12373SJan.Parcel@Sun.COM  * puts instance or -1 into *num.
35411529SJan.Parcel@Sun.COM  */
35511529SJan.Parcel@Sun.COM int
dmap_exact_dev(devmap_t * dmap,char * dev,int * num)35611529SJan.Parcel@Sun.COM dmap_exact_dev(devmap_t *dmap, char *dev, int *num)
35711529SJan.Parcel@Sun.COM {
35811529SJan.Parcel@Sun.COM 	char *dv;
35911529SJan.Parcel@Sun.COM 
36011529SJan.Parcel@Sun.COM 	if ((dev == NULL) || (dmap->dmap_devname == NULL))
36111529SJan.Parcel@Sun.COM 		return (2);
36211529SJan.Parcel@Sun.COM 	dv = dmap->dmap_devname;
36311529SJan.Parcel@Sun.COM 	dv +=  strcspn(dmap->dmap_devname, "0123456789");
36411529SJan.Parcel@Sun.COM 	if (sscanf(dv, "%d", num) != 1)
365*12373SJan.Parcel@Sun.COM 		*num = -1;
36611529SJan.Parcel@Sun.COM 	/* during some add processes, dev can be shorter than dmap */
36711529SJan.Parcel@Sun.COM 	return (dmap_match_one_dev(dmap, dev));
36811529SJan.Parcel@Sun.COM }
36911529SJan.Parcel@Sun.COM 
37011529SJan.Parcel@Sun.COM /*
3711676Sjpk  * dmap_matchtype -
3721676Sjpk  *	checks if the specified devmap_t is for the device specified.
3731676Sjpk  *	returns 1 if it is, else returns 0.
3741676Sjpk  */
3751676Sjpk int
dmap_matchtype(devmap_t * dmap,char * type)3761676Sjpk dmap_matchtype(devmap_t *dmap, char *type)
3771676Sjpk {
3781676Sjpk 	if ((dmap->dmap_devtype == NULL) || (type == NULL))
3791676Sjpk 		return (0);
3801676Sjpk 
3811676Sjpk 	return ((strcmp(dmap->dmap_devtype, type) == 0));
3821676Sjpk }
3831676Sjpk 
3841676Sjpk /*
3851676Sjpk  * dmap_matchname -
3861676Sjpk  * 	checks if the specified devmap_t is for the device specified.
3871676Sjpk  * 	returns 1 if it is, else returns 0.
3881676Sjpk  */
3891676Sjpk int
dmap_matchname(devmap_t * dmap,char * name)3901676Sjpk dmap_matchname(devmap_t *dmap, char *name)
3911676Sjpk {
3921676Sjpk 	if (dmap->dmap_devname == NULL)
3931676Sjpk 		return (0);
3941676Sjpk 
3951676Sjpk 	return ((strcmp(dmap->dmap_devname, name) == 0));
3961676Sjpk }
3971676Sjpk 
3981676Sjpk /*
39911612SJan.Parcel@Sun.COM  * Temporarily duplicated directly from libdevinfo's is_minor_node(),
40011612SJan.Parcel@Sun.COM  * and renamed, because we cannot link this from libdevinfo.
40111612SJan.Parcel@Sun.COM  *
40211612SJan.Parcel@Sun.COM  * To be resolved in a couple of builds.
40311612SJan.Parcel@Sun.COM  *
40411612SJan.Parcel@Sun.COM  * The real fix is to move device allocation out of libbsm.
40511612SJan.Parcel@Sun.COM  *
40611612SJan.Parcel@Sun.COM  * returns 1 if contents is a minor node in /devices.
40711612SJan.Parcel@Sun.COM  * If mn_root is not NULL, mn_root is set to:
40811612SJan.Parcel@Sun.COM  *	if contents is a /dev node, mn_root = contents
40911612SJan.Parcel@Sun.COM  *			OR
41011612SJan.Parcel@Sun.COM  *	if contents is a /devices node, mn_root set to the '/'
41111612SJan.Parcel@Sun.COM  *	following /devices.
41211612SJan.Parcel@Sun.COM  */
41311612SJan.Parcel@Sun.COM static int
dmap_minor_root(const char * contents,const char ** mn_root)41411612SJan.Parcel@Sun.COM dmap_minor_root(const char *contents, const char **mn_root)
41511612SJan.Parcel@Sun.COM {
41611612SJan.Parcel@Sun.COM 	char *ptr, *prefix;
41711612SJan.Parcel@Sun.COM 
41811612SJan.Parcel@Sun.COM 	prefix = "../devices/";
41911612SJan.Parcel@Sun.COM 
42011612SJan.Parcel@Sun.COM 	if ((ptr = strstr(contents, prefix)) != NULL) {
42111612SJan.Parcel@Sun.COM 
42211612SJan.Parcel@Sun.COM 		/* mn_root should point to the / following /devices */
42311612SJan.Parcel@Sun.COM 		if (mn_root != NULL) {
42411612SJan.Parcel@Sun.COM 			*mn_root = ptr += strlen(prefix) - 1;
42511612SJan.Parcel@Sun.COM 		}
42611612SJan.Parcel@Sun.COM 		return (1);
42711612SJan.Parcel@Sun.COM 	}
42811612SJan.Parcel@Sun.COM 
42911612SJan.Parcel@Sun.COM 	prefix = "/devices/";
43011612SJan.Parcel@Sun.COM 
43111612SJan.Parcel@Sun.COM 	if (strncmp(contents, prefix, strlen(prefix)) == 0) {
43211612SJan.Parcel@Sun.COM 
43311612SJan.Parcel@Sun.COM 		/* mn_root should point to the / following /devices/ */
43411612SJan.Parcel@Sun.COM 		if (mn_root != NULL) {
43511612SJan.Parcel@Sun.COM 			*mn_root = contents + strlen(prefix) - 1;
43611612SJan.Parcel@Sun.COM 		}
43711612SJan.Parcel@Sun.COM 		return (1);
43811612SJan.Parcel@Sun.COM 	}
43911612SJan.Parcel@Sun.COM 
44011612SJan.Parcel@Sun.COM 	if (mn_root != NULL) {
44111612SJan.Parcel@Sun.COM 		*mn_root = contents;
44211612SJan.Parcel@Sun.COM 	}
44311612SJan.Parcel@Sun.COM 	return (0);
44411612SJan.Parcel@Sun.COM }
44511612SJan.Parcel@Sun.COM 
44611612SJan.Parcel@Sun.COM /*
44711612SJan.Parcel@Sun.COM  * Temporarily duplicated directly from libdevinfo's devfs_resolve_link(),
44811612SJan.Parcel@Sun.COM  * and renamed, because we cannot link this from libdevinfo now, and will
44911612SJan.Parcel@Sun.COM  * create a sensible solution in the near future.
45011612SJan.Parcel@Sun.COM  *
45111612SJan.Parcel@Sun.COM  * returns 0 if resolved, -1 otherwise.
45211612SJan.Parcel@Sun.COM  * devpath: Absolute path to /dev link
45311612SJan.Parcel@Sun.COM  * devfs_path: Returns malloced string: /devices path w/out "/devices"
45411612SJan.Parcel@Sun.COM  */
45511612SJan.Parcel@Sun.COM static int
dmap_resolve_link(char * devpath,char ** devfs_path)45611612SJan.Parcel@Sun.COM dmap_resolve_link(char *devpath, char **devfs_path)
45711612SJan.Parcel@Sun.COM {
45811612SJan.Parcel@Sun.COM 	char contents[PATH_MAX + 1];
45911612SJan.Parcel@Sun.COM 	char stage_link[PATH_MAX + 1];
46011612SJan.Parcel@Sun.COM 	char *ptr;
46111612SJan.Parcel@Sun.COM 	int linksize;
46211612SJan.Parcel@Sun.COM 	char *slashdev = "/dev/";
46311612SJan.Parcel@Sun.COM 
46411612SJan.Parcel@Sun.COM 	if (devfs_path) {
46511612SJan.Parcel@Sun.COM 		*devfs_path = NULL;
46611612SJan.Parcel@Sun.COM 	}
46711612SJan.Parcel@Sun.COM 
46811612SJan.Parcel@Sun.COM 	linksize = readlink(devpath, contents, PATH_MAX);
46911612SJan.Parcel@Sun.COM 
47011612SJan.Parcel@Sun.COM 	if (linksize <= 0) {
47111612SJan.Parcel@Sun.COM 		return (-1);
47211612SJan.Parcel@Sun.COM 	} else {
47311612SJan.Parcel@Sun.COM 		contents[linksize] = '\0';
47411612SJan.Parcel@Sun.COM 	}
47511612SJan.Parcel@Sun.COM 
47611612SJan.Parcel@Sun.COM 	/*
47711612SJan.Parcel@Sun.COM 	 * if the link contents is not a minor node assume
47811612SJan.Parcel@Sun.COM 	 * that link contents is really a pointer to another
47911612SJan.Parcel@Sun.COM 	 * link, and if so recurse and read its link contents.
48011612SJan.Parcel@Sun.COM 	 */
48111612SJan.Parcel@Sun.COM 	if (dmap_minor_root((const char *)contents, (const char **)&ptr) !=
48211612SJan.Parcel@Sun.COM 	    1) {
48311612SJan.Parcel@Sun.COM 		if (strncmp(contents, slashdev, strlen(slashdev)) == 0)  {
48411612SJan.Parcel@Sun.COM 			/* absolute path, starting with /dev */
48511612SJan.Parcel@Sun.COM 			(void) strcpy(stage_link, contents);
48611612SJan.Parcel@Sun.COM 		} else {
48711612SJan.Parcel@Sun.COM 			/* relative path, prefix devpath */
48811612SJan.Parcel@Sun.COM 			if ((ptr = strrchr(devpath, '/')) == NULL) {
48911612SJan.Parcel@Sun.COM 				/* invalid link */
49011612SJan.Parcel@Sun.COM 				return (-1);
49111612SJan.Parcel@Sun.COM 			}
49211612SJan.Parcel@Sun.COM 			*ptr = '\0';
49311612SJan.Parcel@Sun.COM 			(void) strcpy(stage_link, devpath);
49411612SJan.Parcel@Sun.COM 			*ptr = '/';
49511612SJan.Parcel@Sun.COM 			(void) strcat(stage_link, "/");
49611612SJan.Parcel@Sun.COM 			(void) strcat(stage_link, contents);
49711612SJan.Parcel@Sun.COM 
49811612SJan.Parcel@Sun.COM 		}
49911612SJan.Parcel@Sun.COM 		return (dmap_resolve_link(stage_link, devfs_path));
50011612SJan.Parcel@Sun.COM 	}
50111612SJan.Parcel@Sun.COM 
50211612SJan.Parcel@Sun.COM 	if (devfs_path) {
50311612SJan.Parcel@Sun.COM 		*devfs_path = strdup(ptr);
50411612SJan.Parcel@Sun.COM 		if (*devfs_path == NULL) {
50511612SJan.Parcel@Sun.COM 			return (-1);
50611612SJan.Parcel@Sun.COM 		}
50711612SJan.Parcel@Sun.COM 	}
50811612SJan.Parcel@Sun.COM 
50911612SJan.Parcel@Sun.COM 	return (0);
51011612SJan.Parcel@Sun.COM }
51111612SJan.Parcel@Sun.COM 
51211612SJan.Parcel@Sun.COM /*
51311529SJan.Parcel@Sun.COM  * dmap_physname: path to /devices device
51411529SJan.Parcel@Sun.COM  * Returns:
51511529SJan.Parcel@Sun.COM  *	strdup'd (i.e. malloc'd) real device file if successful
51611529SJan.Parcel@Sun.COM  *      NULL on error
51711529SJan.Parcel@Sun.COM  */
51811529SJan.Parcel@Sun.COM char *
dmap_physname(devmap_t * dmap)51911529SJan.Parcel@Sun.COM dmap_physname(devmap_t *dmap)
52011529SJan.Parcel@Sun.COM {
52111529SJan.Parcel@Sun.COM 	char *oldlink;
52211529SJan.Parcel@Sun.COM 	char stage_link[PATH_MAX + 1];
52311529SJan.Parcel@Sun.COM 
52411529SJan.Parcel@Sun.COM 	if ((dmap == NULL) || (dmap->dmap_devarray == NULL) ||
52511529SJan.Parcel@Sun.COM 	    (dmap->dmap_devarray[0] == NULL))
52611529SJan.Parcel@Sun.COM 		return (NULL);
52711529SJan.Parcel@Sun.COM 
52811529SJan.Parcel@Sun.COM 	(void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link));
52911529SJan.Parcel@Sun.COM 
53011612SJan.Parcel@Sun.COM 	if (dmap_resolve_link(stage_link, &oldlink) == 0)
53111529SJan.Parcel@Sun.COM 		return (oldlink);
53211529SJan.Parcel@Sun.COM 	return (NULL);
53311529SJan.Parcel@Sun.COM }
53411529SJan.Parcel@Sun.COM 
53511529SJan.Parcel@Sun.COM /*
5361676Sjpk  * dm_match -
5371676Sjpk  *	calls dmap_matchname or dmap_matchtype as appropriate.
5381676Sjpk  */
5391676Sjpk int
dm_match(devmap_t * dmap,da_args * dargs)5401676Sjpk dm_match(devmap_t *dmap, da_args *dargs)
5411676Sjpk {
5421676Sjpk 	if (dargs->devinfo->devname)
5431676Sjpk 		return (dmap_matchname(dmap, dargs->devinfo->devname));
5441676Sjpk 	else if (dargs->devinfo->devtype)
5451676Sjpk 		return (dmap_matchtype(dmap, dargs->devinfo->devtype));
5461676Sjpk 
5471676Sjpk 	return (0);
5481676Sjpk }
5491676Sjpk 
5501676Sjpk /*
5511676Sjpk  * dmap_interpret -
5521676Sjpk  *	calls dmap_interpretf and dmap_dlexpand to parse devmap_t line.
5531676Sjpk  *	returns  pointer to parsed devmapt_t entry, else returns NULL on error.
5541676Sjpk  */
5551676Sjpk devmap_t  *
dmap_interpret(char * val,devmap_t * dm)5561676Sjpk dmap_interpret(char *val, devmap_t *dm)
5571676Sjpk {
5581676Sjpk 	if (dmap_interpretf(val, dm) == NULL)
5591676Sjpk 		return (NULL);
5601676Sjpk 
5611676Sjpk 	return (dmap_dlexpand(dm));
5621676Sjpk }
5631676Sjpk 
5641676Sjpk /*
5651676Sjpk  * dmap_interpretf -
5661676Sjpk  * 	parses string "val" and initializes pointers in the given devmap_t to
5671676Sjpk  * 	fields in "val".
5681676Sjpk  * 	returns pointer to updated devmap_t.
5691676Sjpk  */
5701676Sjpk static devmap_t  *
dmap_interpretf(char * val,devmap_t * dm)5711676Sjpk dmap_interpretf(char *val, devmap_t *dm)
5721676Sjpk {
5731676Sjpk 	dm->dmap_devname = getdadmfield(val, KV_TOKEN_DELIMIT);
5741676Sjpk 	dm->dmap_devtype = getdadmfield(NULL, KV_TOKEN_DELIMIT);
5751676Sjpk 	dm->dmap_devlist = getdadmfield(NULL, KV_TOKEN_DELIMIT);
5761676Sjpk 	dm->dmap_devarray = NULL;
5771676Sjpk 	if (dm->dmap_devname == NULL ||
5781676Sjpk 	    dm->dmap_devtype == NULL ||
5791676Sjpk 	    dm->dmap_devlist == NULL)
5801676Sjpk 		return (NULL);
5811676Sjpk 
5821676Sjpk 	return (dm);
5831676Sjpk }
5841676Sjpk 
5851676Sjpk /*
5861676Sjpk  * dmap_dlexpand -
5871676Sjpk  * 	expands dmap_devlist of the form `devlist_generate`
5881676Sjpk  *	returns unexpanded form if there is no '\`' or in case of error.
5891676Sjpk  */
5901676Sjpk static devmap_t *
dmap_dlexpand(devmap_t * dmp)5911676Sjpk dmap_dlexpand(devmap_t *dmp)
5921676Sjpk {
5931676Sjpk 	char	tmplist[DA_BUFSIZE + 1];
5941676Sjpk 	char	*cp, *cpl, **darp;
5951676Sjpk 	int	count;
5961676Sjpk 	FILE	*expansion;
5971676Sjpk 
5981676Sjpk 	dmp->dmap_devarray = NULL;
5991676Sjpk 	if (dmp->dmap_devlist == NULL)
6001676Sjpk 		return (NULL);
6011676Sjpk 	if (*(dmp->dmap_devlist) != '`') {
6021676Sjpk 		(void) strcpy(tmplist, dmp->dmap_devlist);
6031676Sjpk 	} else {
6041676Sjpk 		(void) strcpy(tmplist, dmp->dmap_devlist + 1);
6051676Sjpk 		if ((cp = strchr(tmplist, '`')) != NULL)
6061676Sjpk 			*cp = '\0';
6071914Scasper 		if ((expansion = popen(tmplist, "rF")) == NULL)
6081676Sjpk 			return (NULL);
6091676Sjpk 		count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion);
6101676Sjpk 		(void) pclose(expansion);
6111676Sjpk 		tmplist[count] = '\0';
6121676Sjpk 	}
6131676Sjpk 
6141676Sjpk 	/* cleanup the list */
6151676Sjpk 	count = pack_white(tmplist);
6161676Sjpk 	dmp->dmap_devarray = darp =
6171676Sjpk 	    (char **)malloc((count + 2) * sizeof (char *));
6181676Sjpk 	if (darp == NULL)
6191676Sjpk 		return (NULL);
6201676Sjpk 	cp = tmplist;
6211676Sjpk 	while ((cp = strtok_r(cp, " ", &cpl)) != NULL) {
6221676Sjpk 		*darp = strdup(cp);
6231676Sjpk 		if (*darp == NULL) {
6241676Sjpk 			freedmapent(dmp);
6251676Sjpk 			return (NULL);
6261676Sjpk 		}
6271676Sjpk 		darp++;
6281676Sjpk 		cp = NULL;
6291676Sjpk 	}
6301676Sjpk 	*darp = NULL;
6311676Sjpk 
6321676Sjpk 	return (dmp);
6331676Sjpk }
6341676Sjpk 
6351676Sjpk /*
6361676Sjpk  * dmapskip -
6371676Sjpk  * 	scans input string to find next colon or end of line.
6381676Sjpk  *	returns pointer to next char.
6390Sstevel@tonic-gate  */
6400Sstevel@tonic-gate static char *
dmapskip(char * p)6411676Sjpk dmapskip(char *p)
6420Sstevel@tonic-gate {
6430Sstevel@tonic-gate 	while (*p && *p != ':' && *p != '\n')
6440Sstevel@tonic-gate 		++p;
6450Sstevel@tonic-gate 	if (*p == '\n')
6460Sstevel@tonic-gate 		*p = '\0';
6470Sstevel@tonic-gate 	else if (*p != '\0')
6480Sstevel@tonic-gate 		*p++ = '\0';
6491676Sjpk 
6500Sstevel@tonic-gate 	return (p);
6510Sstevel@tonic-gate }
6521676Sjpk 
6530Sstevel@tonic-gate /*
6541676Sjpk  * dmapdskip -
6551676Sjpk  * 	scans input string to find next space or end of line.
6561676Sjpk  *	returns pointer to next char.
6570Sstevel@tonic-gate  */
6580Sstevel@tonic-gate static char *
dmapdskip(p)6591676Sjpk dmapdskip(p)
6601676Sjpk 	register char *p;
6610Sstevel@tonic-gate {
6620Sstevel@tonic-gate 	while (*p && *p != ' ' && *p != '\n')
6630Sstevel@tonic-gate 		++p;
6640Sstevel@tonic-gate 	if (*p != '\0')
6650Sstevel@tonic-gate 		*p++ = '\0';
6661676Sjpk 
6670Sstevel@tonic-gate 	return (p);
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate 
6701676Sjpk char *
getdmapfield(char * ptr)6711676Sjpk getdmapfield(char *ptr)
6720Sstevel@tonic-gate {
6730Sstevel@tonic-gate 	static	char	*tptr;
6741676Sjpk 
6750Sstevel@tonic-gate 	if (ptr == NULL)
6760Sstevel@tonic-gate 		ptr = tptr;
6770Sstevel@tonic-gate 	if (ptr == NULL)
6780Sstevel@tonic-gate 		return (NULL);
6790Sstevel@tonic-gate 	tptr = dmapskip(ptr);
6800Sstevel@tonic-gate 	ptr = trim_white(ptr);
6810Sstevel@tonic-gate 	if (ptr == NULL)
6820Sstevel@tonic-gate 		return (NULL);
6830Sstevel@tonic-gate 	if (*ptr == NULL)
6840Sstevel@tonic-gate 		return (NULL);
6851676Sjpk 
6860Sstevel@tonic-gate 	return (ptr);
6870Sstevel@tonic-gate }
6881676Sjpk 
6891676Sjpk char *
getdmapdfield(char * ptr)6901676Sjpk getdmapdfield(char *ptr)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate 	static	char	*tptr;
6930Sstevel@tonic-gate 	if (ptr != NULL) {
6940Sstevel@tonic-gate 		ptr = trim_white(ptr);
6950Sstevel@tonic-gate 	} else {
6960Sstevel@tonic-gate 		ptr = tptr;
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 	if (ptr == NULL)
6990Sstevel@tonic-gate 		return (NULL);
7000Sstevel@tonic-gate 	tptr = dmapdskip(ptr);
7010Sstevel@tonic-gate 	if (ptr == NULL)
7020Sstevel@tonic-gate 		return (NULL);
7030Sstevel@tonic-gate 	if (*ptr == NULL)
7040Sstevel@tonic-gate 		return (NULL);
7051676Sjpk 
7060Sstevel@tonic-gate 	return (ptr);
7070Sstevel@tonic-gate }
708