xref: /titanic_50/usr/src/lib/libbsm/common/getdment.c (revision 399f067736e659e2754e97190952abea40f1d0d6)
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 /*
22*399f0677SJan Parcel  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
23*399f0677SJan Parcel  *
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 *);
57*399f0677SJan Parcel static int dmap_resolve_link(char *devpath, char **devfs_path);
5845916cd2Sjpk 
5945916cd2Sjpk int	dmap_matchdev(devmap_t *, char *);
6045916cd2Sjpk int	dmap_matchname(devmap_t *, char *);
6145916cd2Sjpk 
6245916cd2Sjpk 
637c478bd9Sstevel@tonic-gate /*
6445916cd2Sjpk  * _dmapalloc -
6545916cd2Sjpk  *	allocates common buffers and structures.
6645916cd2Sjpk  *	returns pointer to the new structure, else returns NULL on error.
677c478bd9Sstevel@tonic-gate  */
6845916cd2Sjpk static struct _dmapbuff *
_dmapalloc(void)6945916cd2Sjpk _dmapalloc(void)
707c478bd9Sstevel@tonic-gate {
7145916cd2Sjpk 	struct _dmapbuff *_dmap = __dmapbuff;
7245916cd2Sjpk 
7345916cd2Sjpk 	if (_dmap == NULL) {
7445916cd2Sjpk 		_dmap = (struct _dmapbuff *)calloc((unsigned)1,
7545916cd2Sjpk 		    (unsigned)sizeof (*__dmapbuff));
7645916cd2Sjpk 		if (_dmap == NULL)
777c478bd9Sstevel@tonic-gate 			return (NULL);
7845916cd2Sjpk 		DEVMAPS_FILE = "/etc/security/device_maps";
7945916cd2Sjpk 		dmapf = NULL;
8045916cd2Sjpk 		__dmapbuff = _dmap;
817c478bd9Sstevel@tonic-gate 	}
8245916cd2Sjpk 
8345916cd2Sjpk 	return (_dmap);
847c478bd9Sstevel@tonic-gate }
8545916cd2Sjpk 
867c478bd9Sstevel@tonic-gate /*
8745916cd2Sjpk  * setdmapent -
8845916cd2Sjpk  *	rewinds the device_maps file to the beginning.
8945916cd2Sjpk  */
9045916cd2Sjpk void
setdmapent(void)9145916cd2Sjpk setdmapent(void)
9245916cd2Sjpk {
9345916cd2Sjpk 	struct _dmapbuff *_dmap = _dmapalloc();
9445916cd2Sjpk 
9545916cd2Sjpk 	if (_dmap == NULL)
9645916cd2Sjpk 		return;
9745916cd2Sjpk 	if (dmapf == NULL)
98004388ebScasper 		dmapf = fopen(DEVMAPS_FILE, "rF");
9945916cd2Sjpk 	else
10045916cd2Sjpk 		rewind(dmapf);
10145916cd2Sjpk }
10245916cd2Sjpk 
10345916cd2Sjpk /*
10445916cd2Sjpk  * enddmapent -
10545916cd2Sjpk  *	closes device_maps file.
10645916cd2Sjpk  */
10745916cd2Sjpk void
enddmapent(void)10845916cd2Sjpk enddmapent(void)
10945916cd2Sjpk {
11045916cd2Sjpk 	struct _dmapbuff *_dmap = _dmapalloc();
11145916cd2Sjpk 
11245916cd2Sjpk 	if (_dmap == NULL)
11345916cd2Sjpk 		return;
11445916cd2Sjpk 	if (dmapf != NULL) {
11545916cd2Sjpk 		(void) fclose(dmapf);
11645916cd2Sjpk 		dmapf = NULL;
11745916cd2Sjpk 	}
11845916cd2Sjpk }
11945916cd2Sjpk 
12045916cd2Sjpk void
freedmapent(devmap_t * dmap)12145916cd2Sjpk freedmapent(devmap_t *dmap)
12245916cd2Sjpk {
12345916cd2Sjpk 	char	**darp;
12445916cd2Sjpk 
12545916cd2Sjpk 	if ((darp = dmap->dmap_devarray) != NULL) {
12645916cd2Sjpk 		while (*darp != NULL)
12745916cd2Sjpk 			free(*darp++);
12845916cd2Sjpk 		free(dmap->dmap_devarray);
12945916cd2Sjpk 		dmap->dmap_devarray = NULL;
13045916cd2Sjpk 	}
13145916cd2Sjpk }
13245916cd2Sjpk 
13345916cd2Sjpk /*
13445916cd2Sjpk  * setdmapfile -
13545916cd2Sjpk  *	changes the default device_maps file to the one specified.
13645916cd2Sjpk  *	It does not close the previous file. If this is desired, enddmapent
13745916cd2Sjpk  *	should be called prior to setdampfile.
13845916cd2Sjpk  */
13945916cd2Sjpk void
setdmapfile(char * file)14045916cd2Sjpk setdmapfile(char *file)
14145916cd2Sjpk {
14245916cd2Sjpk 	struct _dmapbuff *_dmap = _dmapalloc();
14345916cd2Sjpk 
14445916cd2Sjpk 	if (_dmap == NULL)
14545916cd2Sjpk 		return;
14645916cd2Sjpk 	if (dmapf != NULL) {
14745916cd2Sjpk 		(void) fclose(dmapf);
14845916cd2Sjpk 		dmapf = NULL;
14945916cd2Sjpk 	}
15045916cd2Sjpk 	DEVMAPS_FILE = file;
15145916cd2Sjpk }
15245916cd2Sjpk 
15345916cd2Sjpk /*
15445916cd2Sjpk  * getdmapent -
15545916cd2Sjpk  * 	When first called, returns a pointer to the first devmap_t structure
15645916cd2Sjpk  * 	in device_maps; thereafter, it returns a pointer to the next devmap_t
15745916cd2Sjpk  *	structure in the file. Thus successive calls can be used to read the
15845916cd2Sjpk  *	entire file.
15945916cd2Sjpk  *	call to getdmapent should be bracketed by setdmapent and enddmapent.
16045916cd2Sjpk  * 	returns pointer to devmap_t found, else returns NULL if no entry found
16145916cd2Sjpk  * 	or on error.
16245916cd2Sjpk  */
16345916cd2Sjpk devmap_t *
getdmapent(void)16445916cd2Sjpk getdmapent(void)
16545916cd2Sjpk {
16645916cd2Sjpk 	devmap_t		*dmap;
16745916cd2Sjpk 	struct _dmapbuff 	*_dmap = _dmapalloc();
16845916cd2Sjpk 
16945916cd2Sjpk 	if ((_dmap == 0) || (dmapf == NULL))
17045916cd2Sjpk 		return (NULL);
17145916cd2Sjpk 
17245916cd2Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
17345916cd2Sjpk 	    dmapf) != 0) {
17445916cd2Sjpk 		if ((dmap = dmap_interpret(interpdmline,
17545916cd2Sjpk 		    &interpdevmap)) == NULL)
17645916cd2Sjpk 			continue;
17745916cd2Sjpk 		return (dmap);
17845916cd2Sjpk 	}
17945916cd2Sjpk 
18045916cd2Sjpk 	return (NULL);
18145916cd2Sjpk }
18245916cd2Sjpk 
18345916cd2Sjpk /*
18445916cd2Sjpk  * getdmapnam -
18545916cd2Sjpk  *	searches from the beginning of device_maps for the device specified by
18645916cd2Sjpk  *	its name.
18745916cd2Sjpk  *	call to getdmapnam should be bracketed by setdmapent and enddmapent.
18845916cd2Sjpk  * 	returns pointer to devmapt_t for the device if it is found, else
18945916cd2Sjpk  * 	returns NULL if device not found or in case of error.
19045916cd2Sjpk  */
19145916cd2Sjpk devmap_t *
getdmapnam(char * name)19245916cd2Sjpk getdmapnam(char *name)
19345916cd2Sjpk {
19445916cd2Sjpk 	devmap_t		*dmap;
19545916cd2Sjpk 	struct _dmapbuff	*_dmap = _dmapalloc();
19645916cd2Sjpk 
19745916cd2Sjpk 	if ((name == NULL) || (_dmap == 0) || (dmapf == NULL))
19845916cd2Sjpk 		return (NULL);
19945916cd2Sjpk 
20045916cd2Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
20145916cd2Sjpk 	    dmapf) != 0) {
20245916cd2Sjpk 		if (strstr(interpdmline, name) == NULL)
20345916cd2Sjpk 			continue;
20445916cd2Sjpk 		if ((dmap = dmap_interpretf(interpdmline,
20545916cd2Sjpk 		    &interpdevmap)) == NULL)
20645916cd2Sjpk 			continue;
20745916cd2Sjpk 		if (dmap_matchname(dmap, name)) {
20845916cd2Sjpk 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
20945916cd2Sjpk 				continue;
21045916cd2Sjpk 			enddmapent();
21145916cd2Sjpk 			return (dmap);
21245916cd2Sjpk 		}
21345916cd2Sjpk 		freedmapent(dmap);
21445916cd2Sjpk 	}
21545916cd2Sjpk 
21645916cd2Sjpk 	return (NULL);
21745916cd2Sjpk }
21845916cd2Sjpk 
21945916cd2Sjpk /*
22045916cd2Sjpk  * getdmapdev -
22145916cd2Sjpk  *	searches from the beginning of device_maps for the device specified by
22245916cd2Sjpk  *	its logical name.
22345916cd2Sjpk  *	call to getdmapdev should be bracketed by setdmapent and enddmapent.
22445916cd2Sjpk  * 	returns  pointer to the devmap_t for the device if device is found,
22545916cd2Sjpk  *	else returns NULL if device not found or on error.
22645916cd2Sjpk  */
22745916cd2Sjpk devmap_t *
getdmapdev(char * dev)22845916cd2Sjpk getdmapdev(char *dev)
22945916cd2Sjpk {
23045916cd2Sjpk 	devmap_t		*dmap;
23145916cd2Sjpk 	struct _dmapbuff	*_dmap = _dmapalloc();
23245916cd2Sjpk 
23345916cd2Sjpk 	if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL))
23445916cd2Sjpk 		return (NULL);
23545916cd2Sjpk 
23645916cd2Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
23745916cd2Sjpk 	    dmapf) != 0) {
23845916cd2Sjpk 		if ((dmap = dmap_interpret(interpdmline,
23945916cd2Sjpk 		    &interpdevmap)) == NULL)
24045916cd2Sjpk 			continue;
24145916cd2Sjpk 		if (dmap_matchdev(dmap, dev)) {
24245916cd2Sjpk 			enddmapent();
24345916cd2Sjpk 			return (dmap);
24445916cd2Sjpk 		}
24545916cd2Sjpk 		freedmapent(dmap);
24645916cd2Sjpk 	}
24745916cd2Sjpk 
24845916cd2Sjpk 	return (NULL);
24945916cd2Sjpk }
25045916cd2Sjpk 
25145916cd2Sjpk /*
25245916cd2Sjpk  * getdmaptype -
25345916cd2Sjpk  *	searches from the beginning of device_maps for the device specified by
25445916cd2Sjpk  *	its type.
25545916cd2Sjpk  *	call to getdmaptype should be bracketed by setdmapent and enddmapent.
25645916cd2Sjpk  * 	returns pointer to devmap_t found, else returns NULL if no entry found
25745916cd2Sjpk  * 	or on error.
25845916cd2Sjpk  */
25945916cd2Sjpk devmap_t *
getdmaptype(char * type)26045916cd2Sjpk getdmaptype(char *type)
26145916cd2Sjpk {
26245916cd2Sjpk 	devmap_t		*dmap;
26345916cd2Sjpk 	struct _dmapbuff	*_dmap = _dmapalloc();
26445916cd2Sjpk 
26545916cd2Sjpk 	if ((type == NULL) || (_dmap == 0) || (dmapf == NULL))
26645916cd2Sjpk 		return (NULL);
26745916cd2Sjpk 
26845916cd2Sjpk 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
26945916cd2Sjpk 	    dmapf) != 0) {
27045916cd2Sjpk 		if ((dmap = dmap_interpretf(interpdmline,
27145916cd2Sjpk 		    &interpdevmap)) == NULL)
27245916cd2Sjpk 			continue;
27345916cd2Sjpk 		if (dmap->dmap_devtype != NULL &&
27445916cd2Sjpk 		    strcmp(type, dmap->dmap_devtype) == 0) {
27545916cd2Sjpk 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
27645916cd2Sjpk 				continue;
27745916cd2Sjpk 			return (dmap);
27845916cd2Sjpk 		}
27945916cd2Sjpk 		freedmapent(dmap);
28045916cd2Sjpk 	}
28145916cd2Sjpk 
28245916cd2Sjpk 	return (NULL);
28345916cd2Sjpk }
28445916cd2Sjpk 
28545916cd2Sjpk /*
2867e3e5701SJan Parcel  * dmap_match_one_dev -
2877e3e5701SJan Parcel  *    Checks if the specified devmap_t contains strings
288*399f0677SJan Parcel  *    for the same link as the device specified.
2897e3e5701SJan Parcel  *
2907e3e5701SJan Parcel  *    Returns 1 for a match, else returns 0.
2917e3e5701SJan Parcel  */
2927e3e5701SJan Parcel static int
dmap_match_one_dev(devmap_t * dmap,char * dev)2937e3e5701SJan Parcel dmap_match_one_dev(devmap_t *dmap, char *dev)
2947e3e5701SJan Parcel {
2957e3e5701SJan Parcel 	char **dva;
2967e3e5701SJan Parcel 	char *dv;
297*399f0677SJan Parcel 	char *dmap_link;
298*399f0677SJan Parcel 	char *dev_link;
299*399f0677SJan Parcel 	char stage_link[PATH_MAX + 1];
3007e3e5701SJan Parcel 
3017e3e5701SJan Parcel 	if (dmap->dmap_devarray == NULL)
3027e3e5701SJan Parcel 		return (0);
3037e3e5701SJan Parcel 
3047e3e5701SJan Parcel 	for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva++) {
3057e3e5701SJan Parcel 		if (strstr(dev, dv) != NULL)
3067e3e5701SJan Parcel 			return (1);
3077e3e5701SJan Parcel 	}
308*399f0677SJan Parcel 	/* check if both refer to same physical device */
309*399f0677SJan Parcel 	(void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link));
310*399f0677SJan Parcel 	if (dmap_resolve_link(stage_link, &dmap_link) != 0)
311*399f0677SJan Parcel 		return (0);
312*399f0677SJan Parcel 	(void) strncpy(stage_link, dev, sizeof (stage_link));
313*399f0677SJan Parcel 	if (dmap_resolve_link(stage_link, &dev_link) != 0) {
314*399f0677SJan Parcel 		free(dmap_link);
315*399f0677SJan Parcel 		return (0);
316*399f0677SJan Parcel 	}
317*399f0677SJan Parcel 	if (strcmp(dev_link, dmap_link) == 0) {
318*399f0677SJan Parcel 		free(dmap_link);
319*399f0677SJan Parcel 		free(dev_link);
320*399f0677SJan Parcel 		return (1);
321*399f0677SJan Parcel 	}
322*399f0677SJan Parcel 	free(dmap_link);
323*399f0677SJan Parcel 	free(dev_link);
3247e3e5701SJan Parcel 	return (0);
3257e3e5701SJan Parcel }
3267e3e5701SJan Parcel 
3277e3e5701SJan Parcel /*
32845916cd2Sjpk  * dmap_matchdev -
32945916cd2Sjpk  * 	checks if the specified devmap_t is for the device specified.
33045916cd2Sjpk  *	returns 1 if it is, else returns 0.
33145916cd2Sjpk  */
33245916cd2Sjpk int
dmap_matchdev(devmap_t * dmap,char * dev)33345916cd2Sjpk dmap_matchdev(devmap_t *dmap, char *dev)
33445916cd2Sjpk {
33545916cd2Sjpk 	char **dva;
33645916cd2Sjpk 	char *dv;
33745916cd2Sjpk 
33845916cd2Sjpk 	if (dmap->dmap_devarray == NULL)
33945916cd2Sjpk 		return (0);
34045916cd2Sjpk 	for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva ++) {
34145916cd2Sjpk 		if (strcmp(dv, dev) == 0)
34245916cd2Sjpk 			return (1);
34345916cd2Sjpk 	}
34445916cd2Sjpk 
34545916cd2Sjpk 	return (0);
34645916cd2Sjpk }
34745916cd2Sjpk 
34845916cd2Sjpk /*
349*399f0677SJan Parcel  * Requires a match of the /dev/? links, not just the logical devname
3507e3e5701SJan Parcel  * Returns 1 for match found, 0 for match not found, 2 for invalid arguments.
351*399f0677SJan Parcel  *
352*399f0677SJan Parcel  * Also looks for an instance number at the end of the logical name, and
353*399f0677SJan Parcel  * puts instance or -1 into *num.
3547e3e5701SJan Parcel  */
3557e3e5701SJan Parcel int
dmap_exact_dev(devmap_t * dmap,char * dev,int * num)3567e3e5701SJan Parcel dmap_exact_dev(devmap_t *dmap, char *dev, int *num)
3577e3e5701SJan Parcel {
3587e3e5701SJan Parcel 	char *dv;
3597e3e5701SJan Parcel 
3607e3e5701SJan Parcel 	if ((dev == NULL) || (dmap->dmap_devname == NULL))
3617e3e5701SJan Parcel 		return (2);
3627e3e5701SJan Parcel 	dv = dmap->dmap_devname;
3637e3e5701SJan Parcel 	dv +=  strcspn(dmap->dmap_devname, "0123456789");
3647e3e5701SJan Parcel 	if (sscanf(dv, "%d", num) != 1)
365*399f0677SJan Parcel 		*num = -1;
3667e3e5701SJan Parcel 	/* during some add processes, dev can be shorter than dmap */
3677e3e5701SJan Parcel 	return (dmap_match_one_dev(dmap, dev));
3687e3e5701SJan Parcel }
3697e3e5701SJan Parcel 
3707e3e5701SJan Parcel /*
37145916cd2Sjpk  * dmap_matchtype -
37245916cd2Sjpk  *	checks if the specified devmap_t is for the device specified.
37345916cd2Sjpk  *	returns 1 if it is, else returns 0.
37445916cd2Sjpk  */
37545916cd2Sjpk int
dmap_matchtype(devmap_t * dmap,char * type)37645916cd2Sjpk dmap_matchtype(devmap_t *dmap, char *type)
37745916cd2Sjpk {
37845916cd2Sjpk 	if ((dmap->dmap_devtype == NULL) || (type == NULL))
37945916cd2Sjpk 		return (0);
38045916cd2Sjpk 
38145916cd2Sjpk 	return ((strcmp(dmap->dmap_devtype, type) == 0));
38245916cd2Sjpk }
38345916cd2Sjpk 
38445916cd2Sjpk /*
38545916cd2Sjpk  * dmap_matchname -
38645916cd2Sjpk  * 	checks if the specified devmap_t is for the device specified.
38745916cd2Sjpk  * 	returns 1 if it is, else returns 0.
38845916cd2Sjpk  */
38945916cd2Sjpk int
dmap_matchname(devmap_t * dmap,char * name)39045916cd2Sjpk dmap_matchname(devmap_t *dmap, char *name)
39145916cd2Sjpk {
39245916cd2Sjpk 	if (dmap->dmap_devname == NULL)
39345916cd2Sjpk 		return (0);
39445916cd2Sjpk 
39545916cd2Sjpk 	return ((strcmp(dmap->dmap_devname, name) == 0));
39645916cd2Sjpk }
39745916cd2Sjpk 
39845916cd2Sjpk /*
399914d7362SJan Parcel  * Temporarily duplicated directly from libdevinfo's is_minor_node(),
400914d7362SJan Parcel  * and renamed, because we cannot link this from libdevinfo.
401914d7362SJan Parcel  *
402914d7362SJan Parcel  * To be resolved in a couple of builds.
403914d7362SJan Parcel  *
404914d7362SJan Parcel  * The real fix is to move device allocation out of libbsm.
405914d7362SJan Parcel  *
406914d7362SJan Parcel  * returns 1 if contents is a minor node in /devices.
407914d7362SJan Parcel  * If mn_root is not NULL, mn_root is set to:
408914d7362SJan Parcel  *	if contents is a /dev node, mn_root = contents
409914d7362SJan Parcel  *			OR
410914d7362SJan Parcel  *	if contents is a /devices node, mn_root set to the '/'
411914d7362SJan Parcel  *	following /devices.
412914d7362SJan Parcel  */
413914d7362SJan Parcel static int
dmap_minor_root(const char * contents,const char ** mn_root)414914d7362SJan Parcel dmap_minor_root(const char *contents, const char **mn_root)
415914d7362SJan Parcel {
416914d7362SJan Parcel 	char *ptr, *prefix;
417914d7362SJan Parcel 
418914d7362SJan Parcel 	prefix = "../devices/";
419914d7362SJan Parcel 
420914d7362SJan Parcel 	if ((ptr = strstr(contents, prefix)) != NULL) {
421914d7362SJan Parcel 
422914d7362SJan Parcel 		/* mn_root should point to the / following /devices */
423914d7362SJan Parcel 		if (mn_root != NULL) {
424914d7362SJan Parcel 			*mn_root = ptr += strlen(prefix) - 1;
425914d7362SJan Parcel 		}
426914d7362SJan Parcel 		return (1);
427914d7362SJan Parcel 	}
428914d7362SJan Parcel 
429914d7362SJan Parcel 	prefix = "/devices/";
430914d7362SJan Parcel 
431914d7362SJan Parcel 	if (strncmp(contents, prefix, strlen(prefix)) == 0) {
432914d7362SJan Parcel 
433914d7362SJan Parcel 		/* mn_root should point to the / following /devices/ */
434914d7362SJan Parcel 		if (mn_root != NULL) {
435914d7362SJan Parcel 			*mn_root = contents + strlen(prefix) - 1;
436914d7362SJan Parcel 		}
437914d7362SJan Parcel 		return (1);
438914d7362SJan Parcel 	}
439914d7362SJan Parcel 
440914d7362SJan Parcel 	if (mn_root != NULL) {
441914d7362SJan Parcel 		*mn_root = contents;
442914d7362SJan Parcel 	}
443914d7362SJan Parcel 	return (0);
444914d7362SJan Parcel }
445914d7362SJan Parcel 
446914d7362SJan Parcel /*
447914d7362SJan Parcel  * Temporarily duplicated directly from libdevinfo's devfs_resolve_link(),
448914d7362SJan Parcel  * and renamed, because we cannot link this from libdevinfo now, and will
449914d7362SJan Parcel  * create a sensible solution in the near future.
450914d7362SJan Parcel  *
451914d7362SJan Parcel  * returns 0 if resolved, -1 otherwise.
452914d7362SJan Parcel  * devpath: Absolute path to /dev link
453914d7362SJan Parcel  * devfs_path: Returns malloced string: /devices path w/out "/devices"
454914d7362SJan Parcel  */
455914d7362SJan Parcel static int
dmap_resolve_link(char * devpath,char ** devfs_path)456914d7362SJan Parcel dmap_resolve_link(char *devpath, char **devfs_path)
457914d7362SJan Parcel {
458914d7362SJan Parcel 	char contents[PATH_MAX + 1];
459914d7362SJan Parcel 	char stage_link[PATH_MAX + 1];
460914d7362SJan Parcel 	char *ptr;
461914d7362SJan Parcel 	int linksize;
462914d7362SJan Parcel 	char *slashdev = "/dev/";
463914d7362SJan Parcel 
464914d7362SJan Parcel 	if (devfs_path) {
465914d7362SJan Parcel 		*devfs_path = NULL;
466914d7362SJan Parcel 	}
467914d7362SJan Parcel 
468914d7362SJan Parcel 	linksize = readlink(devpath, contents, PATH_MAX);
469914d7362SJan Parcel 
470914d7362SJan Parcel 	if (linksize <= 0) {
471914d7362SJan Parcel 		return (-1);
472914d7362SJan Parcel 	} else {
473914d7362SJan Parcel 		contents[linksize] = '\0';
474914d7362SJan Parcel 	}
475914d7362SJan Parcel 
476914d7362SJan Parcel 	/*
477914d7362SJan Parcel 	 * if the link contents is not a minor node assume
478914d7362SJan Parcel 	 * that link contents is really a pointer to another
479914d7362SJan Parcel 	 * link, and if so recurse and read its link contents.
480914d7362SJan Parcel 	 */
481914d7362SJan Parcel 	if (dmap_minor_root((const char *)contents, (const char **)&ptr) !=
482914d7362SJan Parcel 	    1) {
483914d7362SJan Parcel 		if (strncmp(contents, slashdev, strlen(slashdev)) == 0)  {
484914d7362SJan Parcel 			/* absolute path, starting with /dev */
485914d7362SJan Parcel 			(void) strcpy(stage_link, contents);
486914d7362SJan Parcel 		} else {
487914d7362SJan Parcel 			/* relative path, prefix devpath */
488914d7362SJan Parcel 			if ((ptr = strrchr(devpath, '/')) == NULL) {
489914d7362SJan Parcel 				/* invalid link */
490914d7362SJan Parcel 				return (-1);
491914d7362SJan Parcel 			}
492914d7362SJan Parcel 			*ptr = '\0';
493914d7362SJan Parcel 			(void) strcpy(stage_link, devpath);
494914d7362SJan Parcel 			*ptr = '/';
495914d7362SJan Parcel 			(void) strcat(stage_link, "/");
496914d7362SJan Parcel 			(void) strcat(stage_link, contents);
497914d7362SJan Parcel 
498914d7362SJan Parcel 		}
499914d7362SJan Parcel 		return (dmap_resolve_link(stage_link, devfs_path));
500914d7362SJan Parcel 	}
501914d7362SJan Parcel 
502914d7362SJan Parcel 	if (devfs_path) {
503914d7362SJan Parcel 		*devfs_path = strdup(ptr);
504914d7362SJan Parcel 		if (*devfs_path == NULL) {
505914d7362SJan Parcel 			return (-1);
506914d7362SJan Parcel 		}
507914d7362SJan Parcel 	}
508914d7362SJan Parcel 
509914d7362SJan Parcel 	return (0);
510914d7362SJan Parcel }
511914d7362SJan Parcel 
512914d7362SJan Parcel /*
5137e3e5701SJan Parcel  * dmap_physname: path to /devices device
5147e3e5701SJan Parcel  * Returns:
5157e3e5701SJan Parcel  *	strdup'd (i.e. malloc'd) real device file if successful
5167e3e5701SJan Parcel  *      NULL on error
5177e3e5701SJan Parcel  */
5187e3e5701SJan Parcel char *
dmap_physname(devmap_t * dmap)5197e3e5701SJan Parcel dmap_physname(devmap_t *dmap)
5207e3e5701SJan Parcel {
5217e3e5701SJan Parcel 	char *oldlink;
5227e3e5701SJan Parcel 	char stage_link[PATH_MAX + 1];
5237e3e5701SJan Parcel 
5247e3e5701SJan Parcel 	if ((dmap == NULL) || (dmap->dmap_devarray == NULL) ||
5257e3e5701SJan Parcel 	    (dmap->dmap_devarray[0] == NULL))
5267e3e5701SJan Parcel 		return (NULL);
5277e3e5701SJan Parcel 
5287e3e5701SJan Parcel 	(void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link));
5297e3e5701SJan Parcel 
530914d7362SJan Parcel 	if (dmap_resolve_link(stage_link, &oldlink) == 0)
5317e3e5701SJan Parcel 		return (oldlink);
5327e3e5701SJan Parcel 	return (NULL);
5337e3e5701SJan Parcel }
5347e3e5701SJan Parcel 
5357e3e5701SJan Parcel /*
53645916cd2Sjpk  * dm_match -
53745916cd2Sjpk  *	calls dmap_matchname or dmap_matchtype as appropriate.
53845916cd2Sjpk  */
53945916cd2Sjpk int
dm_match(devmap_t * dmap,da_args * dargs)54045916cd2Sjpk dm_match(devmap_t *dmap, da_args *dargs)
54145916cd2Sjpk {
54245916cd2Sjpk 	if (dargs->devinfo->devname)
54345916cd2Sjpk 		return (dmap_matchname(dmap, dargs->devinfo->devname));
54445916cd2Sjpk 	else if (dargs->devinfo->devtype)
54545916cd2Sjpk 		return (dmap_matchtype(dmap, dargs->devinfo->devtype));
54645916cd2Sjpk 
54745916cd2Sjpk 	return (0);
54845916cd2Sjpk }
54945916cd2Sjpk 
55045916cd2Sjpk /*
55145916cd2Sjpk  * dmap_interpret -
55245916cd2Sjpk  *	calls dmap_interpretf and dmap_dlexpand to parse devmap_t line.
55345916cd2Sjpk  *	returns  pointer to parsed devmapt_t entry, else returns NULL on error.
55445916cd2Sjpk  */
55545916cd2Sjpk devmap_t  *
dmap_interpret(char * val,devmap_t * dm)55645916cd2Sjpk dmap_interpret(char *val, devmap_t *dm)
55745916cd2Sjpk {
55845916cd2Sjpk 	if (dmap_interpretf(val, dm) == NULL)
55945916cd2Sjpk 		return (NULL);
56045916cd2Sjpk 
56145916cd2Sjpk 	return (dmap_dlexpand(dm));
56245916cd2Sjpk }
56345916cd2Sjpk 
56445916cd2Sjpk /*
56545916cd2Sjpk  * dmap_interpretf -
56645916cd2Sjpk  * 	parses string "val" and initializes pointers in the given devmap_t to
56745916cd2Sjpk  * 	fields in "val".
56845916cd2Sjpk  * 	returns pointer to updated devmap_t.
56945916cd2Sjpk  */
57045916cd2Sjpk static devmap_t  *
dmap_interpretf(char * val,devmap_t * dm)57145916cd2Sjpk dmap_interpretf(char *val, devmap_t *dm)
57245916cd2Sjpk {
57345916cd2Sjpk 	dm->dmap_devname = getdadmfield(val, KV_TOKEN_DELIMIT);
57445916cd2Sjpk 	dm->dmap_devtype = getdadmfield(NULL, KV_TOKEN_DELIMIT);
57545916cd2Sjpk 	dm->dmap_devlist = getdadmfield(NULL, KV_TOKEN_DELIMIT);
57645916cd2Sjpk 	dm->dmap_devarray = NULL;
57745916cd2Sjpk 	if (dm->dmap_devname == NULL ||
57845916cd2Sjpk 	    dm->dmap_devtype == NULL ||
57945916cd2Sjpk 	    dm->dmap_devlist == NULL)
58045916cd2Sjpk 		return (NULL);
58145916cd2Sjpk 
58245916cd2Sjpk 	return (dm);
58345916cd2Sjpk }
58445916cd2Sjpk 
58545916cd2Sjpk /*
58645916cd2Sjpk  * dmap_dlexpand -
58745916cd2Sjpk  * 	expands dmap_devlist of the form `devlist_generate`
58845916cd2Sjpk  *	returns unexpanded form if there is no '\`' or in case of error.
58945916cd2Sjpk  */
59045916cd2Sjpk static devmap_t *
dmap_dlexpand(devmap_t * dmp)59145916cd2Sjpk dmap_dlexpand(devmap_t *dmp)
59245916cd2Sjpk {
59345916cd2Sjpk 	char	tmplist[DA_BUFSIZE + 1];
59445916cd2Sjpk 	char	*cp, *cpl, **darp;
59545916cd2Sjpk 	int	count;
59645916cd2Sjpk 	FILE	*expansion;
59745916cd2Sjpk 
59845916cd2Sjpk 	dmp->dmap_devarray = NULL;
59945916cd2Sjpk 	if (dmp->dmap_devlist == NULL)
60045916cd2Sjpk 		return (NULL);
60145916cd2Sjpk 	if (*(dmp->dmap_devlist) != '`') {
60245916cd2Sjpk 		(void) strcpy(tmplist, dmp->dmap_devlist);
60345916cd2Sjpk 	} else {
60445916cd2Sjpk 		(void) strcpy(tmplist, dmp->dmap_devlist + 1);
60545916cd2Sjpk 		if ((cp = strchr(tmplist, '`')) != NULL)
60645916cd2Sjpk 			*cp = '\0';
607004388ebScasper 		if ((expansion = popen(tmplist, "rF")) == NULL)
60845916cd2Sjpk 			return (NULL);
60945916cd2Sjpk 		count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion);
61045916cd2Sjpk 		(void) pclose(expansion);
61145916cd2Sjpk 		tmplist[count] = '\0';
61245916cd2Sjpk 	}
61345916cd2Sjpk 
61445916cd2Sjpk 	/* cleanup the list */
61545916cd2Sjpk 	count = pack_white(tmplist);
61645916cd2Sjpk 	dmp->dmap_devarray = darp =
61745916cd2Sjpk 	    (char **)malloc((count + 2) * sizeof (char *));
61845916cd2Sjpk 	if (darp == NULL)
61945916cd2Sjpk 		return (NULL);
62045916cd2Sjpk 	cp = tmplist;
62145916cd2Sjpk 	while ((cp = strtok_r(cp, " ", &cpl)) != NULL) {
62245916cd2Sjpk 		*darp = strdup(cp);
62345916cd2Sjpk 		if (*darp == NULL) {
62445916cd2Sjpk 			freedmapent(dmp);
62545916cd2Sjpk 			return (NULL);
62645916cd2Sjpk 		}
62745916cd2Sjpk 		darp++;
62845916cd2Sjpk 		cp = NULL;
62945916cd2Sjpk 	}
63045916cd2Sjpk 	*darp = NULL;
63145916cd2Sjpk 
63245916cd2Sjpk 	return (dmp);
63345916cd2Sjpk }
63445916cd2Sjpk 
63545916cd2Sjpk /*
63645916cd2Sjpk  * dmapskip -
63745916cd2Sjpk  * 	scans input string to find next colon or end of line.
63845916cd2Sjpk  *	returns pointer to next char.
6397c478bd9Sstevel@tonic-gate  */
6407c478bd9Sstevel@tonic-gate static char *
dmapskip(char * p)64145916cd2Sjpk dmapskip(char *p)
6427c478bd9Sstevel@tonic-gate {
6437c478bd9Sstevel@tonic-gate 	while (*p && *p != ':' && *p != '\n')
6447c478bd9Sstevel@tonic-gate 		++p;
6457c478bd9Sstevel@tonic-gate 	if (*p == '\n')
6467c478bd9Sstevel@tonic-gate 		*p = '\0';
6477c478bd9Sstevel@tonic-gate 	else if (*p != '\0')
6487c478bd9Sstevel@tonic-gate 		*p++ = '\0';
64945916cd2Sjpk 
6507c478bd9Sstevel@tonic-gate 	return (p);
6517c478bd9Sstevel@tonic-gate }
65245916cd2Sjpk 
6537c478bd9Sstevel@tonic-gate /*
65445916cd2Sjpk  * dmapdskip -
65545916cd2Sjpk  * 	scans input string to find next space or end of line.
65645916cd2Sjpk  *	returns pointer to next char.
6577c478bd9Sstevel@tonic-gate  */
6587c478bd9Sstevel@tonic-gate static char *
dmapdskip(p)65945916cd2Sjpk dmapdskip(p)
66045916cd2Sjpk 	register char *p;
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate 	while (*p && *p != ' ' && *p != '\n')
6637c478bd9Sstevel@tonic-gate 		++p;
6647c478bd9Sstevel@tonic-gate 	if (*p != '\0')
6657c478bd9Sstevel@tonic-gate 		*p++ = '\0';
66645916cd2Sjpk 
6677c478bd9Sstevel@tonic-gate 	return (p);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
67045916cd2Sjpk char *
getdmapfield(char * ptr)67145916cd2Sjpk getdmapfield(char *ptr)
6727c478bd9Sstevel@tonic-gate {
6737c478bd9Sstevel@tonic-gate 	static	char	*tptr;
67445916cd2Sjpk 
6757c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
6767c478bd9Sstevel@tonic-gate 		ptr = tptr;
6777c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
6787c478bd9Sstevel@tonic-gate 		return (NULL);
6797c478bd9Sstevel@tonic-gate 	tptr = dmapskip(ptr);
6807c478bd9Sstevel@tonic-gate 	ptr = trim_white(ptr);
6817c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
6827c478bd9Sstevel@tonic-gate 		return (NULL);
6837c478bd9Sstevel@tonic-gate 	if (*ptr == NULL)
6847c478bd9Sstevel@tonic-gate 		return (NULL);
68545916cd2Sjpk 
6867c478bd9Sstevel@tonic-gate 	return (ptr);
6877c478bd9Sstevel@tonic-gate }
68845916cd2Sjpk 
68945916cd2Sjpk char *
getdmapdfield(char * ptr)69045916cd2Sjpk getdmapdfield(char *ptr)
6917c478bd9Sstevel@tonic-gate {
6927c478bd9Sstevel@tonic-gate 	static	char	*tptr;
6937c478bd9Sstevel@tonic-gate 	if (ptr != NULL) {
6947c478bd9Sstevel@tonic-gate 		ptr = trim_white(ptr);
6957c478bd9Sstevel@tonic-gate 	} else {
6967c478bd9Sstevel@tonic-gate 		ptr = tptr;
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
6997c478bd9Sstevel@tonic-gate 		return (NULL);
7007c478bd9Sstevel@tonic-gate 	tptr = dmapdskip(ptr);
7017c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
7027c478bd9Sstevel@tonic-gate 		return (NULL);
7037c478bd9Sstevel@tonic-gate 	if (*ptr == NULL)
7047c478bd9Sstevel@tonic-gate 		return (NULL);
70545916cd2Sjpk 
7067c478bd9Sstevel@tonic-gate 	return (ptr);
7077c478bd9Sstevel@tonic-gate }
708