xref: /titanic_52/usr/src/lib/libbsm/common/getdment.c (revision 914d7362e7da089c86db1d24a546fe0ccbccac44)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227e3e5701SJan Parcel  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <string.h>
277e3e5701SJan Parcel #include <strings.h>
2845916cd2Sjpk #include <stdlib.h>
297e3e5701SJan Parcel #include <unistd.h>
307e3e5701SJan Parcel #include <limits.h>
317c478bd9Sstevel@tonic-gate #include <bsm/devices.h>
3245916cd2Sjpk #include <bsm/devalloc.h>
337c478bd9Sstevel@tonic-gate 
3445916cd2Sjpk char *strtok_r(char *, const char *, char **);
3545916cd2Sjpk 
3645916cd2Sjpk /* externs from getdaent.c */
3745916cd2Sjpk extern char *trim_white(char *);
3845916cd2Sjpk extern int pack_white(char *);
3945916cd2Sjpk extern char *getdadmfield(char *, char *);
4045916cd2Sjpk extern int getdadmline(char *, int, FILE *);
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate static struct _dmapbuff {
4345916cd2Sjpk 	FILE		*_dmapf;	/* for /etc/security/device_maps */
447c478bd9Sstevel@tonic-gate 	devmap_t	_interpdevmap;
4545916cd2Sjpk 	char		_interpdmline[DA_BUFSIZE + 1];
467c478bd9Sstevel@tonic-gate 	char		*_DEVMAP;
477c478bd9Sstevel@tonic-gate } *__dmapbuff;
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #define	dmapf	(_dmap->_dmapf)
507c478bd9Sstevel@tonic-gate #define	interpdevmap	(_dmap->_interpdevmap)
5145916cd2Sjpk #define	interpdmline	(_dmap->_interpdmline)
5245916cd2Sjpk #define	DEVMAPS_FILE	(_dmap->_DEVMAP)
5345916cd2Sjpk 
5445916cd2Sjpk devmap_t	*dmap_interpret(char *, devmap_t *);
5545916cd2Sjpk static devmap_t	*dmap_interpretf(char *, devmap_t *);
5645916cd2Sjpk static devmap_t *dmap_dlexpand(devmap_t *);
5745916cd2Sjpk 
5845916cd2Sjpk int	dmap_matchdev(devmap_t *, char *);
5945916cd2Sjpk int	dmap_matchname(devmap_t *, char *);
6045916cd2Sjpk 
6145916cd2Sjpk 
627c478bd9Sstevel@tonic-gate /*
6345916cd2Sjpk  * _dmapalloc -
6445916cd2Sjpk  *	allocates common buffers and structures.
6545916cd2Sjpk  *	returns pointer to the new structure, else returns NULL on error.
667c478bd9Sstevel@tonic-gate  */
6745916cd2Sjpk static struct _dmapbuff *
6845916cd2Sjpk _dmapalloc(void)
697c478bd9Sstevel@tonic-gate {
7045916cd2Sjpk 	struct _dmapbuff *_dmap = __dmapbuff;
7145916cd2Sjpk 
7245916cd2Sjpk 	if (_dmap == NULL) {
7345916cd2Sjpk 		_dmap = (struct _dmapbuff *)calloc((unsigned)1,
7445916cd2Sjpk 		    (unsigned)sizeof (*__dmapbuff));
7545916cd2Sjpk 		if (_dmap == NULL)
767c478bd9Sstevel@tonic-gate 			return (NULL);
7745916cd2Sjpk 		DEVMAPS_FILE = "/etc/security/device_maps";
7845916cd2Sjpk 		dmapf = NULL;
7945916cd2Sjpk 		__dmapbuff = _dmap;
807c478bd9Sstevel@tonic-gate 	}
8145916cd2Sjpk 
8245916cd2Sjpk 	return (_dmap);
837c478bd9Sstevel@tonic-gate }
8445916cd2Sjpk 
857c478bd9Sstevel@tonic-gate /*
8645916cd2Sjpk  * setdmapent -
8745916cd2Sjpk  *	rewinds the device_maps file to the beginning.
8845916cd2Sjpk  */
8945916cd2Sjpk void
9045916cd2Sjpk setdmapent(void)
9145916cd2Sjpk {
9245916cd2Sjpk 	struct _dmapbuff *_dmap = _dmapalloc();
9345916cd2Sjpk 
9445916cd2Sjpk 	if (_dmap == NULL)
9545916cd2Sjpk 		return;
9645916cd2Sjpk 	if (dmapf == NULL)
97004388ebScasper 		dmapf = fopen(DEVMAPS_FILE, "rF");
9845916cd2Sjpk 	else
9945916cd2Sjpk 		rewind(dmapf);
10045916cd2Sjpk }
10145916cd2Sjpk 
10245916cd2Sjpk /*
10345916cd2Sjpk  * enddmapent -
10445916cd2Sjpk  *	closes device_maps file.
10545916cd2Sjpk  */
10645916cd2Sjpk void
10745916cd2Sjpk enddmapent(void)
10845916cd2Sjpk {
10945916cd2Sjpk 	struct _dmapbuff *_dmap = _dmapalloc();
11045916cd2Sjpk 
11145916cd2Sjpk 	if (_dmap == NULL)
11245916cd2Sjpk 		return;
11345916cd2Sjpk 	if (dmapf != NULL) {
11445916cd2Sjpk 		(void) fclose(dmapf);
11545916cd2Sjpk 		dmapf = NULL;
11645916cd2Sjpk 	}
11745916cd2Sjpk }
11845916cd2Sjpk 
11945916cd2Sjpk void
12045916cd2Sjpk freedmapent(devmap_t *dmap)
12145916cd2Sjpk {
12245916cd2Sjpk 	char	**darp;
12345916cd2Sjpk 
12445916cd2Sjpk 	if ((darp = dmap->dmap_devarray) != NULL) {
12545916cd2Sjpk 		while (*darp != NULL)
12645916cd2Sjpk 			free(*darp++);
12745916cd2Sjpk 		free(dmap->dmap_devarray);
12845916cd2Sjpk 		dmap->dmap_devarray = NULL;
12945916cd2Sjpk 	}
13045916cd2Sjpk }
13145916cd2Sjpk 
13245916cd2Sjpk /*
13345916cd2Sjpk  * setdmapfile -
13445916cd2Sjpk  *	changes the default device_maps file to the one specified.
13545916cd2Sjpk  *	It does not close the previous file. If this is desired, enddmapent
13645916cd2Sjpk  *	should be called prior to setdampfile.
13745916cd2Sjpk  */
13845916cd2Sjpk void
13945916cd2Sjpk setdmapfile(char *file)
14045916cd2Sjpk {
14145916cd2Sjpk 	struct _dmapbuff *_dmap = _dmapalloc();
14245916cd2Sjpk 
14345916cd2Sjpk 	if (_dmap == NULL)
14445916cd2Sjpk 		return;
14545916cd2Sjpk 	if (dmapf != NULL) {
14645916cd2Sjpk 		(void) fclose(dmapf);
14745916cd2Sjpk 		dmapf = NULL;
14845916cd2Sjpk 	}
14945916cd2Sjpk 	DEVMAPS_FILE = file;
15045916cd2Sjpk }
15145916cd2Sjpk 
15245916cd2Sjpk /*
15345916cd2Sjpk  * getdmapent -
15445916cd2Sjpk  * 	When first called, returns a pointer to the first devmap_t structure
15545916cd2Sjpk  * 	in device_maps; thereafter, it returns a pointer to the next devmap_t
15645916cd2Sjpk  *	structure in the file. Thus successive calls can be used to read the
15745916cd2Sjpk  *	entire file.
15845916cd2Sjpk  *	call to getdmapent should be bracketed by setdmapent and enddmapent.
15945916cd2Sjpk  * 	returns pointer to devmap_t found, else returns NULL if no entry found
16045916cd2Sjpk  * 	or on error.
16145916cd2Sjpk  */
16245916cd2Sjpk devmap_t *
16345916cd2Sjpk getdmapent(void)
16445916cd2Sjpk {
16545916cd2Sjpk 	devmap_t		*dmap;
16645916cd2Sjpk 	struct _dmapbuff 	*_dmap = _dmapalloc();
16745916cd2Sjpk 
16845916cd2Sjpk 	if ((_dmap == 0) || (dmapf == NULL))
16945916cd2Sjpk 		return (NULL);
17045916cd2Sjpk 
17145916cd2Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
17245916cd2Sjpk 	    dmapf) != 0) {
17345916cd2Sjpk 		if ((dmap = dmap_interpret(interpdmline,
17445916cd2Sjpk 		    &interpdevmap)) == NULL)
17545916cd2Sjpk 			continue;
17645916cd2Sjpk 		return (dmap);
17745916cd2Sjpk 	}
17845916cd2Sjpk 
17945916cd2Sjpk 	return (NULL);
18045916cd2Sjpk }
18145916cd2Sjpk 
18245916cd2Sjpk /*
18345916cd2Sjpk  * getdmapnam -
18445916cd2Sjpk  *	searches from the beginning of device_maps for the device specified by
18545916cd2Sjpk  *	its name.
18645916cd2Sjpk  *	call to getdmapnam should be bracketed by setdmapent and enddmapent.
18745916cd2Sjpk  * 	returns pointer to devmapt_t for the device if it is found, else
18845916cd2Sjpk  * 	returns NULL if device not found or in case of error.
18945916cd2Sjpk  */
19045916cd2Sjpk devmap_t *
19145916cd2Sjpk getdmapnam(char *name)
19245916cd2Sjpk {
19345916cd2Sjpk 	devmap_t		*dmap;
19445916cd2Sjpk 	struct _dmapbuff	*_dmap = _dmapalloc();
19545916cd2Sjpk 
19645916cd2Sjpk 	if ((name == NULL) || (_dmap == 0) || (dmapf == NULL))
19745916cd2Sjpk 		return (NULL);
19845916cd2Sjpk 
19945916cd2Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
20045916cd2Sjpk 	    dmapf) != 0) {
20145916cd2Sjpk 		if (strstr(interpdmline, name) == NULL)
20245916cd2Sjpk 			continue;
20345916cd2Sjpk 		if ((dmap = dmap_interpretf(interpdmline,
20445916cd2Sjpk 		    &interpdevmap)) == NULL)
20545916cd2Sjpk 			continue;
20645916cd2Sjpk 		if (dmap_matchname(dmap, name)) {
20745916cd2Sjpk 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
20845916cd2Sjpk 				continue;
20945916cd2Sjpk 			enddmapent();
21045916cd2Sjpk 			return (dmap);
21145916cd2Sjpk 		}
21245916cd2Sjpk 		freedmapent(dmap);
21345916cd2Sjpk 	}
21445916cd2Sjpk 
21545916cd2Sjpk 	return (NULL);
21645916cd2Sjpk }
21745916cd2Sjpk 
21845916cd2Sjpk /*
21945916cd2Sjpk  * getdmapdev -
22045916cd2Sjpk  *	searches from the beginning of device_maps for the device specified by
22145916cd2Sjpk  *	its logical name.
22245916cd2Sjpk  *	call to getdmapdev should be bracketed by setdmapent and enddmapent.
22345916cd2Sjpk  * 	returns  pointer to the devmap_t for the device if device is found,
22445916cd2Sjpk  *	else returns NULL if device not found or on error.
22545916cd2Sjpk  */
22645916cd2Sjpk devmap_t *
22745916cd2Sjpk getdmapdev(char *dev)
22845916cd2Sjpk {
22945916cd2Sjpk 	devmap_t		*dmap;
23045916cd2Sjpk 	struct _dmapbuff	*_dmap = _dmapalloc();
23145916cd2Sjpk 
23245916cd2Sjpk 	if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL))
23345916cd2Sjpk 		return (NULL);
23445916cd2Sjpk 
23545916cd2Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
23645916cd2Sjpk 	    dmapf) != 0) {
23745916cd2Sjpk 		if ((dmap = dmap_interpret(interpdmline,
23845916cd2Sjpk 		    &interpdevmap)) == NULL)
23945916cd2Sjpk 			continue;
24045916cd2Sjpk 		if (dmap_matchdev(dmap, dev)) {
24145916cd2Sjpk 			enddmapent();
24245916cd2Sjpk 			return (dmap);
24345916cd2Sjpk 		}
24445916cd2Sjpk 		freedmapent(dmap);
24545916cd2Sjpk 	}
24645916cd2Sjpk 
24745916cd2Sjpk 	return (NULL);
24845916cd2Sjpk }
24945916cd2Sjpk 
25045916cd2Sjpk /*
25145916cd2Sjpk  * getdmaptype -
25245916cd2Sjpk  *	searches from the beginning of device_maps for the device specified by
25345916cd2Sjpk  *	its type.
25445916cd2Sjpk  *	call to getdmaptype should be bracketed by setdmapent and enddmapent.
25545916cd2Sjpk  * 	returns pointer to devmap_t found, else returns NULL if no entry found
25645916cd2Sjpk  * 	or on error.
25745916cd2Sjpk  */
25845916cd2Sjpk devmap_t *
25945916cd2Sjpk getdmaptype(char *type)
26045916cd2Sjpk {
26145916cd2Sjpk 	devmap_t		*dmap;
26245916cd2Sjpk 	struct _dmapbuff	*_dmap = _dmapalloc();
26345916cd2Sjpk 
26445916cd2Sjpk 	if ((type == NULL) || (_dmap == 0) || (dmapf == NULL))
26545916cd2Sjpk 		return (NULL);
26645916cd2Sjpk 
26745916cd2Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
26845916cd2Sjpk 	    dmapf) != 0) {
26945916cd2Sjpk 		if ((dmap = dmap_interpretf(interpdmline,
27045916cd2Sjpk 		    &interpdevmap)) == NULL)
27145916cd2Sjpk 			continue;
27245916cd2Sjpk 		if (dmap->dmap_devtype != NULL &&
27345916cd2Sjpk 		    strcmp(type, dmap->dmap_devtype) == 0) {
27445916cd2Sjpk 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
27545916cd2Sjpk 				continue;
27645916cd2Sjpk 			return (dmap);
27745916cd2Sjpk 		}
27845916cd2Sjpk 		freedmapent(dmap);
27945916cd2Sjpk 	}
28045916cd2Sjpk 
28145916cd2Sjpk 	return (NULL);
28245916cd2Sjpk }
28345916cd2Sjpk 
28445916cd2Sjpk /*
2857e3e5701SJan Parcel  * dmap_match_one_dev -
2867e3e5701SJan Parcel  *    Checks if the specified devmap_t contains strings
2877e3e5701SJan Parcel  *    for the same logical link as the device specified.
2887e3e5701SJan Parcel  *    This guarantees that the beginnings of a devlist build
2897e3e5701SJan Parcel  *    match a more-complete devlist for the same device.
2907e3e5701SJan Parcel  *
2917e3e5701SJan Parcel  *    Returns 1 for a match, else returns 0.
2927e3e5701SJan Parcel  */
2937e3e5701SJan Parcel static int
2947e3e5701SJan Parcel dmap_match_one_dev(devmap_t *dmap, char *dev)
2957e3e5701SJan Parcel {
2967e3e5701SJan Parcel 	char **dva;
2977e3e5701SJan Parcel 	char *dv;
2987e3e5701SJan Parcel 
2997e3e5701SJan Parcel 	if (dmap->dmap_devarray == NULL)
3007e3e5701SJan Parcel 		return (0);
3017e3e5701SJan Parcel 
3027e3e5701SJan Parcel 	for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva++) {
3037e3e5701SJan Parcel 		if (strstr(dev, dv) != NULL)
3047e3e5701SJan Parcel 			return (1);
3057e3e5701SJan Parcel 	}
3067e3e5701SJan Parcel 	return (0);
3077e3e5701SJan Parcel }
3087e3e5701SJan Parcel 
3097e3e5701SJan Parcel /*
31045916cd2Sjpk  * dmap_matchdev -
31145916cd2Sjpk  * 	checks if the specified devmap_t is for the device specified.
31245916cd2Sjpk  *	returns 1 if it is, else returns 0.
31345916cd2Sjpk  */
31445916cd2Sjpk int
31545916cd2Sjpk dmap_matchdev(devmap_t *dmap, char *dev)
31645916cd2Sjpk {
31745916cd2Sjpk 	char **dva;
31845916cd2Sjpk 	char *dv;
31945916cd2Sjpk 
32045916cd2Sjpk 	if (dmap->dmap_devarray == NULL)
32145916cd2Sjpk 		return (0);
32245916cd2Sjpk 	for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva ++) {
32345916cd2Sjpk 		if (strcmp(dv, dev) == 0)
32445916cd2Sjpk 			return (1);
32545916cd2Sjpk 	}
32645916cd2Sjpk 
32745916cd2Sjpk 	return (0);
32845916cd2Sjpk }
32945916cd2Sjpk 
33045916cd2Sjpk /*
3317e3e5701SJan Parcel  * Requires a match of the /dev/?dsk links, not just the logical devname
3327e3e5701SJan Parcel  * Returns 1 for match found, 0 for match not found, 2 for invalid arguments.
3337e3e5701SJan Parcel  */
3347e3e5701SJan Parcel int
3357e3e5701SJan Parcel dmap_exact_dev(devmap_t *dmap, char *dev, int *num)
3367e3e5701SJan Parcel {
3377e3e5701SJan Parcel 	char *dv;
3387e3e5701SJan Parcel 
3397e3e5701SJan Parcel 	if ((dev == NULL) || (dmap->dmap_devname == NULL))
3407e3e5701SJan Parcel 		return (2);
3417e3e5701SJan Parcel 	dv = dmap->dmap_devname;
3427e3e5701SJan Parcel 	dv +=  strcspn(dmap->dmap_devname, "0123456789");
3437e3e5701SJan Parcel 	if (sscanf(dv, "%d", num) != 1)
3447e3e5701SJan Parcel 		return (2);
3457e3e5701SJan Parcel 	/* during some add processes, dev can be shorter than dmap */
3467e3e5701SJan Parcel 	return (dmap_match_one_dev(dmap, dev));
3477e3e5701SJan Parcel }
3487e3e5701SJan Parcel 
3497e3e5701SJan Parcel /*
35045916cd2Sjpk  * dmap_matchtype -
35145916cd2Sjpk  *	checks if the specified devmap_t is for the device specified.
35245916cd2Sjpk  *	returns 1 if it is, else returns 0.
35345916cd2Sjpk  */
35445916cd2Sjpk int
35545916cd2Sjpk dmap_matchtype(devmap_t *dmap, char *type)
35645916cd2Sjpk {
35745916cd2Sjpk 	if ((dmap->dmap_devtype == NULL) || (type == NULL))
35845916cd2Sjpk 		return (0);
35945916cd2Sjpk 
36045916cd2Sjpk 	return ((strcmp(dmap->dmap_devtype, type) == 0));
36145916cd2Sjpk }
36245916cd2Sjpk 
36345916cd2Sjpk /*
36445916cd2Sjpk  * dmap_matchname -
36545916cd2Sjpk  * 	checks if the specified devmap_t is for the device specified.
36645916cd2Sjpk  * 	returns 1 if it is, else returns 0.
36745916cd2Sjpk  */
36845916cd2Sjpk int
36945916cd2Sjpk dmap_matchname(devmap_t *dmap, char *name)
37045916cd2Sjpk {
37145916cd2Sjpk 	if (dmap->dmap_devname == NULL)
37245916cd2Sjpk 		return (0);
37345916cd2Sjpk 
37445916cd2Sjpk 	return ((strcmp(dmap->dmap_devname, name) == 0));
37545916cd2Sjpk }
37645916cd2Sjpk 
37745916cd2Sjpk /*
378*914d7362SJan Parcel  * Temporarily duplicated directly from libdevinfo's is_minor_node(),
379*914d7362SJan Parcel  * and renamed, because we cannot link this from libdevinfo.
380*914d7362SJan Parcel  *
381*914d7362SJan Parcel  * To be resolved in a couple of builds.
382*914d7362SJan Parcel  *
383*914d7362SJan Parcel  * The real fix is to move device allocation out of libbsm.
384*914d7362SJan Parcel  *
385*914d7362SJan Parcel  * returns 1 if contents is a minor node in /devices.
386*914d7362SJan Parcel  * If mn_root is not NULL, mn_root is set to:
387*914d7362SJan Parcel  *	if contents is a /dev node, mn_root = contents
388*914d7362SJan Parcel  *			OR
389*914d7362SJan Parcel  *	if contents is a /devices node, mn_root set to the '/'
390*914d7362SJan Parcel  *	following /devices.
391*914d7362SJan Parcel  */
392*914d7362SJan Parcel static int
393*914d7362SJan Parcel dmap_minor_root(const char *contents, const char **mn_root)
394*914d7362SJan Parcel {
395*914d7362SJan Parcel 	char *ptr, *prefix;
396*914d7362SJan Parcel 
397*914d7362SJan Parcel 	prefix = "../devices/";
398*914d7362SJan Parcel 
399*914d7362SJan Parcel 	if ((ptr = strstr(contents, prefix)) != NULL) {
400*914d7362SJan Parcel 
401*914d7362SJan Parcel 		/* mn_root should point to the / following /devices */
402*914d7362SJan Parcel 		if (mn_root != NULL) {
403*914d7362SJan Parcel 			*mn_root = ptr += strlen(prefix) - 1;
404*914d7362SJan Parcel 		}
405*914d7362SJan Parcel 		return (1);
406*914d7362SJan Parcel 	}
407*914d7362SJan Parcel 
408*914d7362SJan Parcel 	prefix = "/devices/";
409*914d7362SJan Parcel 
410*914d7362SJan Parcel 	if (strncmp(contents, prefix, strlen(prefix)) == 0) {
411*914d7362SJan Parcel 
412*914d7362SJan Parcel 		/* mn_root should point to the / following /devices/ */
413*914d7362SJan Parcel 		if (mn_root != NULL) {
414*914d7362SJan Parcel 			*mn_root = contents + strlen(prefix) - 1;
415*914d7362SJan Parcel 		}
416*914d7362SJan Parcel 		return (1);
417*914d7362SJan Parcel 	}
418*914d7362SJan Parcel 
419*914d7362SJan Parcel 	if (mn_root != NULL) {
420*914d7362SJan Parcel 		*mn_root = contents;
421*914d7362SJan Parcel 	}
422*914d7362SJan Parcel 	return (0);
423*914d7362SJan Parcel }
424*914d7362SJan Parcel 
425*914d7362SJan Parcel /*
426*914d7362SJan Parcel  * Temporarily duplicated directly from libdevinfo's devfs_resolve_link(),
427*914d7362SJan Parcel  * and renamed, because we cannot link this from libdevinfo now, and will
428*914d7362SJan Parcel  * create a sensible solution in the near future.
429*914d7362SJan Parcel  *
430*914d7362SJan Parcel  * returns 0 if resolved, -1 otherwise.
431*914d7362SJan Parcel  * devpath: Absolute path to /dev link
432*914d7362SJan Parcel  * devfs_path: Returns malloced string: /devices path w/out "/devices"
433*914d7362SJan Parcel  */
434*914d7362SJan Parcel static int
435*914d7362SJan Parcel dmap_resolve_link(char *devpath, char **devfs_path)
436*914d7362SJan Parcel {
437*914d7362SJan Parcel 	char contents[PATH_MAX + 1];
438*914d7362SJan Parcel 	char stage_link[PATH_MAX + 1];
439*914d7362SJan Parcel 	char *ptr;
440*914d7362SJan Parcel 	int linksize;
441*914d7362SJan Parcel 	char *slashdev = "/dev/";
442*914d7362SJan Parcel 
443*914d7362SJan Parcel 	if (devfs_path) {
444*914d7362SJan Parcel 		*devfs_path = NULL;
445*914d7362SJan Parcel 	}
446*914d7362SJan Parcel 
447*914d7362SJan Parcel 	linksize = readlink(devpath, contents, PATH_MAX);
448*914d7362SJan Parcel 
449*914d7362SJan Parcel 	if (linksize <= 0) {
450*914d7362SJan Parcel 		return (-1);
451*914d7362SJan Parcel 	} else {
452*914d7362SJan Parcel 		contents[linksize] = '\0';
453*914d7362SJan Parcel 	}
454*914d7362SJan Parcel 
455*914d7362SJan Parcel 	/*
456*914d7362SJan Parcel 	 * if the link contents is not a minor node assume
457*914d7362SJan Parcel 	 * that link contents is really a pointer to another
458*914d7362SJan Parcel 	 * link, and if so recurse and read its link contents.
459*914d7362SJan Parcel 	 */
460*914d7362SJan Parcel 	if (dmap_minor_root((const char *)contents, (const char **)&ptr) !=
461*914d7362SJan Parcel 	    1) {
462*914d7362SJan Parcel 		if (strncmp(contents, slashdev, strlen(slashdev)) == 0)  {
463*914d7362SJan Parcel 			/* absolute path, starting with /dev */
464*914d7362SJan Parcel 			(void) strcpy(stage_link, contents);
465*914d7362SJan Parcel 		} else {
466*914d7362SJan Parcel 			/* relative path, prefix devpath */
467*914d7362SJan Parcel 			if ((ptr = strrchr(devpath, '/')) == NULL) {
468*914d7362SJan Parcel 				/* invalid link */
469*914d7362SJan Parcel 				return (-1);
470*914d7362SJan Parcel 			}
471*914d7362SJan Parcel 			*ptr = '\0';
472*914d7362SJan Parcel 			(void) strcpy(stage_link, devpath);
473*914d7362SJan Parcel 			*ptr = '/';
474*914d7362SJan Parcel 			(void) strcat(stage_link, "/");
475*914d7362SJan Parcel 			(void) strcat(stage_link, contents);
476*914d7362SJan Parcel 
477*914d7362SJan Parcel 		}
478*914d7362SJan Parcel 		return (dmap_resolve_link(stage_link, devfs_path));
479*914d7362SJan Parcel 	}
480*914d7362SJan Parcel 
481*914d7362SJan Parcel 	if (devfs_path) {
482*914d7362SJan Parcel 		*devfs_path = strdup(ptr);
483*914d7362SJan Parcel 		if (*devfs_path == NULL) {
484*914d7362SJan Parcel 			return (-1);
485*914d7362SJan Parcel 		}
486*914d7362SJan Parcel 	}
487*914d7362SJan Parcel 
488*914d7362SJan Parcel 	return (0);
489*914d7362SJan Parcel }
490*914d7362SJan Parcel 
491*914d7362SJan Parcel /*
4927e3e5701SJan Parcel  * dmap_physname: path to /devices device
4937e3e5701SJan Parcel  * Returns:
4947e3e5701SJan Parcel  *	strdup'd (i.e. malloc'd) real device file if successful
4957e3e5701SJan Parcel  *      NULL on error
4967e3e5701SJan Parcel  */
4977e3e5701SJan Parcel char *
4987e3e5701SJan Parcel dmap_physname(devmap_t *dmap)
4997e3e5701SJan Parcel {
5007e3e5701SJan Parcel 	char *oldlink;
5017e3e5701SJan Parcel 	char stage_link[PATH_MAX + 1];
5027e3e5701SJan Parcel 
5037e3e5701SJan Parcel 	if ((dmap == NULL) || (dmap->dmap_devarray == NULL) ||
5047e3e5701SJan Parcel 	    (dmap->dmap_devarray[0] == NULL))
5057e3e5701SJan Parcel 		return (NULL);
5067e3e5701SJan Parcel 
5077e3e5701SJan Parcel 	(void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link));
5087e3e5701SJan Parcel 
509*914d7362SJan Parcel 	if (dmap_resolve_link(stage_link, &oldlink) == 0)
5107e3e5701SJan Parcel 		return (oldlink);
5117e3e5701SJan Parcel 	return (NULL);
5127e3e5701SJan Parcel }
5137e3e5701SJan Parcel 
5147e3e5701SJan Parcel /*
51545916cd2Sjpk  * dm_match -
51645916cd2Sjpk  *	calls dmap_matchname or dmap_matchtype as appropriate.
51745916cd2Sjpk  */
51845916cd2Sjpk int
51945916cd2Sjpk dm_match(devmap_t *dmap, da_args *dargs)
52045916cd2Sjpk {
52145916cd2Sjpk 	if (dargs->devinfo->devname)
52245916cd2Sjpk 		return (dmap_matchname(dmap, dargs->devinfo->devname));
52345916cd2Sjpk 	else if (dargs->devinfo->devtype)
52445916cd2Sjpk 		return (dmap_matchtype(dmap, dargs->devinfo->devtype));
52545916cd2Sjpk 
52645916cd2Sjpk 	return (0);
52745916cd2Sjpk }
52845916cd2Sjpk 
52945916cd2Sjpk /*
53045916cd2Sjpk  * dmap_interpret -
53145916cd2Sjpk  *	calls dmap_interpretf and dmap_dlexpand to parse devmap_t line.
53245916cd2Sjpk  *	returns  pointer to parsed devmapt_t entry, else returns NULL on error.
53345916cd2Sjpk  */
53445916cd2Sjpk devmap_t  *
53545916cd2Sjpk dmap_interpret(char *val, devmap_t *dm)
53645916cd2Sjpk {
53745916cd2Sjpk 	if (dmap_interpretf(val, dm) == NULL)
53845916cd2Sjpk 		return (NULL);
53945916cd2Sjpk 
54045916cd2Sjpk 	return (dmap_dlexpand(dm));
54145916cd2Sjpk }
54245916cd2Sjpk 
54345916cd2Sjpk /*
54445916cd2Sjpk  * dmap_interpretf -
54545916cd2Sjpk  * 	parses string "val" and initializes pointers in the given devmap_t to
54645916cd2Sjpk  * 	fields in "val".
54745916cd2Sjpk  * 	returns pointer to updated devmap_t.
54845916cd2Sjpk  */
54945916cd2Sjpk static devmap_t  *
55045916cd2Sjpk dmap_interpretf(char *val, devmap_t *dm)
55145916cd2Sjpk {
55245916cd2Sjpk 	dm->dmap_devname = getdadmfield(val, KV_TOKEN_DELIMIT);
55345916cd2Sjpk 	dm->dmap_devtype = getdadmfield(NULL, KV_TOKEN_DELIMIT);
55445916cd2Sjpk 	dm->dmap_devlist = getdadmfield(NULL, KV_TOKEN_DELIMIT);
55545916cd2Sjpk 	dm->dmap_devarray = NULL;
55645916cd2Sjpk 	if (dm->dmap_devname == NULL ||
55745916cd2Sjpk 	    dm->dmap_devtype == NULL ||
55845916cd2Sjpk 	    dm->dmap_devlist == NULL)
55945916cd2Sjpk 		return (NULL);
56045916cd2Sjpk 
56145916cd2Sjpk 	return (dm);
56245916cd2Sjpk }
56345916cd2Sjpk 
56445916cd2Sjpk /*
56545916cd2Sjpk  * dmap_dlexpand -
56645916cd2Sjpk  * 	expands dmap_devlist of the form `devlist_generate`
56745916cd2Sjpk  *	returns unexpanded form if there is no '\`' or in case of error.
56845916cd2Sjpk  */
56945916cd2Sjpk static devmap_t *
57045916cd2Sjpk dmap_dlexpand(devmap_t *dmp)
57145916cd2Sjpk {
57245916cd2Sjpk 	char	tmplist[DA_BUFSIZE + 1];
57345916cd2Sjpk 	char	*cp, *cpl, **darp;
57445916cd2Sjpk 	int	count;
57545916cd2Sjpk 	FILE	*expansion;
57645916cd2Sjpk 
57745916cd2Sjpk 	dmp->dmap_devarray = NULL;
57845916cd2Sjpk 	if (dmp->dmap_devlist == NULL)
57945916cd2Sjpk 		return (NULL);
58045916cd2Sjpk 	if (*(dmp->dmap_devlist) != '`') {
58145916cd2Sjpk 		(void) strcpy(tmplist, dmp->dmap_devlist);
58245916cd2Sjpk 	} else {
58345916cd2Sjpk 		(void) strcpy(tmplist, dmp->dmap_devlist + 1);
58445916cd2Sjpk 		if ((cp = strchr(tmplist, '`')) != NULL)
58545916cd2Sjpk 			*cp = '\0';
586004388ebScasper 		if ((expansion = popen(tmplist, "rF")) == NULL)
58745916cd2Sjpk 			return (NULL);
58845916cd2Sjpk 		count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion);
58945916cd2Sjpk 		(void) pclose(expansion);
59045916cd2Sjpk 		tmplist[count] = '\0';
59145916cd2Sjpk 	}
59245916cd2Sjpk 
59345916cd2Sjpk 	/* cleanup the list */
59445916cd2Sjpk 	count = pack_white(tmplist);
59545916cd2Sjpk 	dmp->dmap_devarray = darp =
59645916cd2Sjpk 	    (char **)malloc((count + 2) * sizeof (char *));
59745916cd2Sjpk 	if (darp == NULL)
59845916cd2Sjpk 		return (NULL);
59945916cd2Sjpk 	cp = tmplist;
60045916cd2Sjpk 	while ((cp = strtok_r(cp, " ", &cpl)) != NULL) {
60145916cd2Sjpk 		*darp = strdup(cp);
60245916cd2Sjpk 		if (*darp == NULL) {
60345916cd2Sjpk 			freedmapent(dmp);
60445916cd2Sjpk 			return (NULL);
60545916cd2Sjpk 		}
60645916cd2Sjpk 		darp++;
60745916cd2Sjpk 		cp = NULL;
60845916cd2Sjpk 	}
60945916cd2Sjpk 	*darp = NULL;
61045916cd2Sjpk 
61145916cd2Sjpk 	return (dmp);
61245916cd2Sjpk }
61345916cd2Sjpk 
61445916cd2Sjpk /*
61545916cd2Sjpk  * dmapskip -
61645916cd2Sjpk  * 	scans input string to find next colon or end of line.
61745916cd2Sjpk  *	returns pointer to next char.
6187c478bd9Sstevel@tonic-gate  */
6197c478bd9Sstevel@tonic-gate static char *
62045916cd2Sjpk dmapskip(char *p)
6217c478bd9Sstevel@tonic-gate {
6227c478bd9Sstevel@tonic-gate 	while (*p && *p != ':' && *p != '\n')
6237c478bd9Sstevel@tonic-gate 		++p;
6247c478bd9Sstevel@tonic-gate 	if (*p == '\n')
6257c478bd9Sstevel@tonic-gate 		*p = '\0';
6267c478bd9Sstevel@tonic-gate 	else if (*p != '\0')
6277c478bd9Sstevel@tonic-gate 		*p++ = '\0';
62845916cd2Sjpk 
6297c478bd9Sstevel@tonic-gate 	return (p);
6307c478bd9Sstevel@tonic-gate }
63145916cd2Sjpk 
6327c478bd9Sstevel@tonic-gate /*
63345916cd2Sjpk  * dmapdskip -
63445916cd2Sjpk  * 	scans input string to find next space or end of line.
63545916cd2Sjpk  *	returns pointer to next char.
6367c478bd9Sstevel@tonic-gate  */
6377c478bd9Sstevel@tonic-gate static char *
63845916cd2Sjpk dmapdskip(p)
63945916cd2Sjpk 	register char *p;
6407c478bd9Sstevel@tonic-gate {
6417c478bd9Sstevel@tonic-gate 	while (*p && *p != ' ' && *p != '\n')
6427c478bd9Sstevel@tonic-gate 		++p;
6437c478bd9Sstevel@tonic-gate 	if (*p != '\0')
6447c478bd9Sstevel@tonic-gate 		*p++ = '\0';
64545916cd2Sjpk 
6467c478bd9Sstevel@tonic-gate 	return (p);
6477c478bd9Sstevel@tonic-gate }
6487c478bd9Sstevel@tonic-gate 
64945916cd2Sjpk char *
65045916cd2Sjpk getdmapfield(char *ptr)
6517c478bd9Sstevel@tonic-gate {
6527c478bd9Sstevel@tonic-gate 	static	char	*tptr;
65345916cd2Sjpk 
6547c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
6557c478bd9Sstevel@tonic-gate 		ptr = tptr;
6567c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
6577c478bd9Sstevel@tonic-gate 		return (NULL);
6587c478bd9Sstevel@tonic-gate 	tptr = dmapskip(ptr);
6597c478bd9Sstevel@tonic-gate 	ptr = trim_white(ptr);
6607c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
6617c478bd9Sstevel@tonic-gate 		return (NULL);
6627c478bd9Sstevel@tonic-gate 	if (*ptr == NULL)
6637c478bd9Sstevel@tonic-gate 		return (NULL);
66445916cd2Sjpk 
6657c478bd9Sstevel@tonic-gate 	return (ptr);
6667c478bd9Sstevel@tonic-gate }
66745916cd2Sjpk 
66845916cd2Sjpk char *
66945916cd2Sjpk getdmapdfield(char *ptr)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate 	static	char	*tptr;
6727c478bd9Sstevel@tonic-gate 	if (ptr != NULL) {
6737c478bd9Sstevel@tonic-gate 		ptr = trim_white(ptr);
6747c478bd9Sstevel@tonic-gate 	} else {
6757c478bd9Sstevel@tonic-gate 		ptr = tptr;
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
6787c478bd9Sstevel@tonic-gate 		return (NULL);
6797c478bd9Sstevel@tonic-gate 	tptr = dmapdskip(ptr);
6807c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
6817c478bd9Sstevel@tonic-gate 		return (NULL);
6827c478bd9Sstevel@tonic-gate 	if (*ptr == NULL)
6837c478bd9Sstevel@tonic-gate 		return (NULL);
68445916cd2Sjpk 
6857c478bd9Sstevel@tonic-gate 	return (ptr);
6867c478bd9Sstevel@tonic-gate }
687