xref: /onnv-gate/usr/src/lib/libadm/common/getdev.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate  * Copyright (c) 1997, by Sun Microsystems, Inc.
28*0Sstevel@tonic-gate  * All rights reserved.
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma	ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.4 */
32*0Sstevel@tonic-gate /*LINTLIBRARY*/
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate /*
35*0Sstevel@tonic-gate  *  getdev.c
36*0Sstevel@tonic-gate  *
37*0Sstevel@tonic-gate  *  Contents:
38*0Sstevel@tonic-gate  *	getdev()	List devices that match certain criteria.
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate  * Header files referenced:
43*0Sstevel@tonic-gate  *	<sys/types.h>	System Data Types
44*0Sstevel@tonic-gate  *	<errno.h>	Error handling
45*0Sstevel@tonic-gate  *	<fcntl.h>	File controlling
46*0Sstevel@tonic-gate  *	<ctype.h>	Character types
47*0Sstevel@tonic-gate  *	<string.h>	String handling
48*0Sstevel@tonic-gate  *	<devmgmt.h>	Global device-management def'ns
49*0Sstevel@tonic-gate  *	"devtab.h"	Local device-management dev'ns
50*0Sstevel@tonic-gate  */
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate #include	<sys/types.h>
53*0Sstevel@tonic-gate #include	<errno.h>
54*0Sstevel@tonic-gate #include	<fcntl.h>
55*0Sstevel@tonic-gate #include	<ctype.h>
56*0Sstevel@tonic-gate #include	<string.h>
57*0Sstevel@tonic-gate #include	<devmgmt.h>
58*0Sstevel@tonic-gate #include	"devtab.h"
59*0Sstevel@tonic-gate #include	<stdlib.h>
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate /*
62*0Sstevel@tonic-gate  * Local definitions
63*0Sstevel@tonic-gate  *	NULL		Nil address
64*0Sstevel@tonic-gate  *	TRUE		Boolean TRUE
65*0Sstevel@tonic-gate  *	FALSE		Boolean FALSE
66*0Sstevel@tonic-gate  */
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate #ifndef	NULL
69*0Sstevel@tonic-gate #define	NULL			0
70*0Sstevel@tonic-gate #endif
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate #ifndef	TRUE
73*0Sstevel@tonic-gate #define	TRUE			('t')
74*0Sstevel@tonic-gate #endif
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate #ifndef	FALSE
77*0Sstevel@tonic-gate #define	FALSE			0
78*0Sstevel@tonic-gate #endif
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate /*
82*0Sstevel@tonic-gate  *  Comparison values.  These values are placed in the struct srch
83*0Sstevel@tonic-gate  *  structure by buildsearchlist() and are used to compare values
84*0Sstevel@tonic-gate  *  in matches().
85*0Sstevel@tonic-gate  *	EQUAL		Attribute must equal this value
86*0Sstevel@tonic-gate  *	NOTEQUAL	Attribute must not equal this value
87*0Sstevel@tonic-gate  *	EXISTS		Attribute must exist
88*0Sstevel@tonic-gate  *	NOEXISTS	Attribute must not exist
89*0Sstevel@tonic-gate  *	IGNORE		Ignore this entry
90*0Sstevel@tonic-gate  *	ENDLIST		This entry ends the list
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate #define	EQUAL			1
94*0Sstevel@tonic-gate #define	NOTEQUAL		2
95*0Sstevel@tonic-gate #define	EXISTS			3
96*0Sstevel@tonic-gate #define	NOEXISTS		4
97*0Sstevel@tonic-gate #define	IGNORE			5
98*0Sstevel@tonic-gate #define	ENDLIST			0
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate /*
102*0Sstevel@tonic-gate  *  Structure definitions:
103*0Sstevel@tonic-gate  * 	deviceent	Defines a device that matches criteria
104*0Sstevel@tonic-gate  *	srch		Describes a criteria
105*0Sstevel@tonic-gate  */
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate struct deviceent {
108*0Sstevel@tonic-gate 	struct deviceent	*next;	/* Pointer to next item in the list */
109*0Sstevel@tonic-gate 	char			*name;	/* Presentation name of the device */
110*0Sstevel@tonic-gate };
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate struct srch {
113*0Sstevel@tonic-gate 	char   *name;			/* Name of field to compare */
114*0Sstevel@tonic-gate 	char   *cmp;			/* Value to compare against */
115*0Sstevel@tonic-gate 	int	fcn;			/* Type of comparison (see above) */
116*0Sstevel@tonic-gate };
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate /*
120*0Sstevel@tonic-gate  * Local functions referenced
121*0Sstevel@tonic-gate  *	oktoaddtolist()		Determines if device can be added to the
122*0Sstevel@tonic-gate  *				list by examining the devices list and
123*0Sstevel@tonic-gate  *				the options governing the search
124*0Sstevel@tonic-gate  *	initdevicelist()	Initializes the linked list of devices
125*0Sstevel@tonic-gate  *				to be included in the list-to-return
126*0Sstevel@tonic-gate  *	freedevicelist()	Frees the resources allocated to the linked
127*0Sstevel@tonic-gate  *				list of devices
128*0Sstevel@tonic-gate  *	addtodevicelist()	Adds an entry to the linked list of devices
129*0Sstevel@tonic-gate  *	buildsearchlist()	Builds a list of struct srch structures from
130*0Sstevel@tonic-gate  *				the criteria strings
131*0Sstevel@tonic-gate  *	freesearchlist()	Frees the resources allocated to the list of
132*0Sstevel@tonic-gate  *				struct srch structures
133*0Sstevel@tonic-gate  *	buildreturnlist()	Builds the list of devices to return from the
134*0Sstevel@tonic-gate  *				linked list of devices we've accumulated
135*0Sstevel@tonic-gate  *	makealiaslist()		Builds a list of aliases from the list of
136*0Sstevel@tonic-gate  *				devices presented by the caller
137*0Sstevel@tonic-gate  *	freealiaslist()		Frees the resources allocated to the list of
138*0Sstevel@tonic-gate  *				devices aliases
139*0Sstevel@tonic-gate  *	getnextmatch()		Get the next device that matches the search
140*0Sstevel@tonic-gate  *				criteria
141*0Sstevel@tonic-gate  *	matchallcriteria()	See if the device attributes match all of the
142*0Sstevel@tonic-gate  *				search criteria
143*0Sstevel@tonic-gate  *	matchanycriteria()	See if the device attributes match any of the
144*0Sstevel@tonic-gate  *				search criteria
145*0Sstevel@tonic-gate  *	matches()		See if the criteria and attribute match
146*0Sstevel@tonic-gate  */
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate static	char		*oktoaddtolist(char   *, char  **, char  **, int);
149*0Sstevel@tonic-gate static	void		initdevicelist(void);
150*0Sstevel@tonic-gate static	void		freedevicelist(void);
151*0Sstevel@tonic-gate static	int		addtodevicelist(char *);
152*0Sstevel@tonic-gate static	struct srch	*buildsearchlist(char **);
153*0Sstevel@tonic-gate static	void 		freesearchlist(struct srch *);
154*0Sstevel@tonic-gate static	char		**buildreturnlist(void);
155*0Sstevel@tonic-gate static	char		**makealiaslist(char **);
156*0Sstevel@tonic-gate static	void		freealiaslist(char **);
157*0Sstevel@tonic-gate static	char		*getnextmatch(struct srch *, int);
158*0Sstevel@tonic-gate static	int		matchallcriteria(struct devtabent *, struct srch *);
159*0Sstevel@tonic-gate static	int		matchanycriteria(struct devtabent *, struct srch *);
160*0Sstevel@tonic-gate static	int		matches(char *, char *, int);
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate /*
164*0Sstevel@tonic-gate  * Global Data
165*0Sstevel@tonic-gate  */
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate /*
168*0Sstevel@tonic-gate  * Static Data
169*0Sstevel@tonic-gate  *	devicelisthead	The first item (dummy) in the linked list of devices
170*0Sstevel@tonic-gate  *			we're building
171*0Sstevel@tonic-gate  *	devicelist	Structure describing the linked list of devices
172*0Sstevel@tonic-gate  */
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate static	struct deviceent	devicelisthead;
175*0Sstevel@tonic-gate static	struct {
176*0Sstevel@tonic-gate 	struct deviceent	*head;
177*0Sstevel@tonic-gate 	int			count;
178*0Sstevel@tonic-gate } devicelist = {&devicelisthead, 0};
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /*
181*0Sstevel@tonic-gate  *  char **getdev(devices, criteria, options)
182*0Sstevel@tonic-gate  *	char  **devices
183*0Sstevel@tonic-gate  *	char  **criteria
184*0Sstevel@tonic-gate  *	int	options
185*0Sstevel@tonic-gate  *
186*0Sstevel@tonic-gate  *	This function builds a list of devices that match criteria,
187*0Sstevel@tonic-gate  *	governed by the device list.
188*0Sstevel@tonic-gate  *
189*0Sstevel@tonic-gate  *  Arguments:
190*0Sstevel@tonic-gate  *	devices		The list of devices to select from or the list of
191*0Sstevel@tonic-gate  *			devices to exclude, depending on the value of
192*0Sstevel@tonic-gate  *			"options"
193*0Sstevel@tonic-gate  *	criteria	The list of criteria governing the device selection
194*0Sstevel@tonic-gate  *			Of the form <attr><op><val>
195*0Sstevel@tonic-gate  *	options		Options controlling the device selection.  May require
196*0Sstevel@tonic-gate  *			that a device meet all of the criteria (default is
197*0Sstevel@tonic-gate  *			any one of the criteria), or may require that the
198*0Sstevel@tonic-gate  *			devices in the list of devices be excluded from the
199*0Sstevel@tonic-gate  *			generated list (default is to select only those
200*0Sstevel@tonic-gate  * 			devices in the list)
201*0Sstevel@tonic-gate  *
202*0Sstevel@tonic-gate  *  Returns:  char **
203*0Sstevel@tonic-gate  *	The address of the first item in the list of devices that meet
204*0Sstevel@tonic-gate  *	the selection criteria
205*0Sstevel@tonic-gate  */
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate char  **
getdev(char ** devices,char ** criteria,int options)208*0Sstevel@tonic-gate getdev(
209*0Sstevel@tonic-gate 	char  **devices,		/* List of devices to constrain */
210*0Sstevel@tonic-gate 	char  **criteria,		/* List of selection criteria */
211*0Sstevel@tonic-gate 	int	options)		/* Options governing the search */
212*0Sstevel@tonic-gate {
213*0Sstevel@tonic-gate 	/* Automatic data */
214*0Sstevel@tonic-gate 	char		**aliases;	/* List of constraining devices */
215*0Sstevel@tonic-gate 	char		**returnlist;	/* List of ptrs to aliases to return */
216*0Sstevel@tonic-gate 	struct srch	*searchlist;	/* Pointer to searching criteria */
217*0Sstevel@tonic-gate 	char		*entry;		/* Pointer to alias in record */
218*0Sstevel@tonic-gate 	int		errflag;	/* FLAG:  TRUE if error */
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/*
222*0Sstevel@tonic-gate 	 *  Initializations
223*0Sstevel@tonic-gate 	 */
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	/*  Make sure the exclude/include list is all aliases */
226*0Sstevel@tonic-gate 	aliases = makealiaslist(devices);
227*0Sstevel@tonic-gate 	if (devices && !aliases)
228*0Sstevel@tonic-gate 		return (NULL);
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	/*  Build the search list  */
231*0Sstevel@tonic-gate 	if (criteria) {
232*0Sstevel@tonic-gate 	    if (!(searchlist = buildsearchlist(criteria)))
233*0Sstevel@tonic-gate 		return (NULL);
234*0Sstevel@tonic-gate 	} else searchlist = NULL;
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	/*  Initialize searching  */
237*0Sstevel@tonic-gate 	initdevicelist();
238*0Sstevel@tonic-gate 	_setdevtab();
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	/*
242*0Sstevel@tonic-gate 	 *  Keep on going until we get no more matches
243*0Sstevel@tonic-gate 	 */
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	errflag = FALSE;
246*0Sstevel@tonic-gate 	while (!errflag && (entry = getnextmatch(searchlist, options))) {
247*0Sstevel@tonic-gate 	    if (entry = oktoaddtolist(entry, devices, aliases, options)) {
248*0Sstevel@tonic-gate 		errflag = addtodevicelist(entry);
249*0Sstevel@tonic-gate 	    }
250*0Sstevel@tonic-gate 	}
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/*
254*0Sstevel@tonic-gate 	 *  Clean up:
255*0Sstevel@tonic-gate 	 *    -	Free the entry space we've allocated.
256*0Sstevel@tonic-gate 	 *    -	Close the device table.
257*0Sstevel@tonic-gate 	 *    - Build the list to return to the caller.
258*0Sstevel@tonic-gate 	 *    - Free the accumulate device space (but not the strings!)
259*0Sstevel@tonic-gate 	 *    - Free the alias list
260*0Sstevel@tonic-gate 	 *    - Return the built list to the caller.
261*0Sstevel@tonic-gate 	 */
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	returnlist = buildreturnlist();
264*0Sstevel@tonic-gate 	freedevicelist();
265*0Sstevel@tonic-gate 	freealiaslist(aliases);
266*0Sstevel@tonic-gate 	_enddevtab();
267*0Sstevel@tonic-gate 	return (returnlist);
268*0Sstevel@tonic-gate }
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate /*
271*0Sstevel@tonic-gate  *  char *oktoaddtolist(devtabentry, devices, aliases, options)
272*0Sstevel@tonic-gate  *	char   *devtabentry
273*0Sstevel@tonic-gate  *	char  **devices
274*0Sstevel@tonic-gate  *	char  **aliases
275*0Sstevel@tonic-gate  *	int	options
276*0Sstevel@tonic-gate  *
277*0Sstevel@tonic-gate  *	This function determines the device "devtabentry" can be
278*0Sstevel@tonic-gate  *	added to the list of devices we're accumulating.  If so,
279*0Sstevel@tonic-gate  *	it returns the device name (not the alias).
280*0Sstevel@tonic-gate  *
281*0Sstevel@tonic-gate  *  Arguments:
282*0Sstevel@tonic-gate  *	devtabentry	The device alias that may or may not belong in the
283*0Sstevel@tonic-gate  *			list we're building.
284*0Sstevel@tonic-gate  *	devices		The devices specified by the caller
285*0Sstevel@tonic-gate  *	aliases		The aliases of the devices specified by the caller
286*0Sstevel@tonic-gate  *			(1-1 correspondence with "devices")
287*0Sstevel@tonic-gate  *	options		Options controlling the search
288*0Sstevel@tonic-gate  */
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate static	char *
oktoaddtolist(char * devtabentry,char ** devices,char ** aliases,int options)291*0Sstevel@tonic-gate oktoaddtolist(
292*0Sstevel@tonic-gate 	char   *devtabentry,	/* Alias to check against list */
293*0Sstevel@tonic-gate 	char  **devices,	/* List of devices to check against */
294*0Sstevel@tonic-gate 	char  **aliases,	/* List of alias of those devices */
295*0Sstevel@tonic-gate 	int	options)	/* Options governing search */
296*0Sstevel@tonic-gate {
297*0Sstevel@tonic-gate 	/* Automatic data */
298*0Sstevel@tonic-gate 	char   *rtnval;		/* Value to return */
299*0Sstevel@tonic-gate 	int	found;		/* Flag:  TRUE if found */
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	/* If there's a constraint list, is this device in it? */
302*0Sstevel@tonic-gate 	if (devices && aliases) {
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	    /* Set "found" to TRUE if the device is in the list */
305*0Sstevel@tonic-gate 	    found = FALSE;
306*0Sstevel@tonic-gate 	    while (!found && *aliases) {
307*0Sstevel@tonic-gate 		if (strcmp(devtabentry, *aliases) == 0) found = TRUE;
308*0Sstevel@tonic-gate 		else {
309*0Sstevel@tonic-gate 		    devices++;
310*0Sstevel@tonic-gate 		    aliases++;
311*0Sstevel@tonic-gate 		}
312*0Sstevel@tonic-gate 	    }
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	    /* Set value to return */
315*0Sstevel@tonic-gate 	    if (found)
316*0Sstevel@tonic-gate 		rtnval = (options & DTAB_EXCLUDEFLAG) ?
317*0Sstevel@tonic-gate 		    NULL : *devices;
318*0Sstevel@tonic-gate 	    else
319*0Sstevel@tonic-gate 		rtnval = (options & DTAB_EXCLUDEFLAG) ?
320*0Sstevel@tonic-gate 		    devtabentry : NULL;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	} else rtnval = devtabentry;  /* No constraint list */
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	return (rtnval);
325*0Sstevel@tonic-gate }
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate /*
328*0Sstevel@tonic-gate  *  void initdevicelist()
329*0Sstevel@tonic-gate  *
330*0Sstevel@tonic-gate  *	This function initializes the list of accumulated devices.
331*0Sstevel@tonic-gate  *
332*0Sstevel@tonic-gate  *  Arguments:  None
333*0Sstevel@tonic-gate  *
334*0Sstevel@tonic-gate  *  Returns:  Void.
335*0Sstevel@tonic-gate  *
336*0Sstevel@tonic-gate  *  Notes:
337*0Sstevel@tonic-gate  */
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate static	void
initdevicelist(void)340*0Sstevel@tonic-gate initdevicelist(void)
341*0Sstevel@tonic-gate {
342*0Sstevel@tonic-gate 	/* Make the list a null list */
343*0Sstevel@tonic-gate 	(devicelist.head)->next = NULL;
344*0Sstevel@tonic-gate 	devicelist.count = 0;
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate /*
348*0Sstevel@tonic-gate  *  void freedevicelist()
349*0Sstevel@tonic-gate  *
350*0Sstevel@tonic-gate  *	This function frees the resources allocated to the linked list of
351*0Sstevel@tonic-gate  *	devices we've been accumulating.
352*0Sstevel@tonic-gate  *
353*0Sstevel@tonic-gate  *  Arguments:  none
354*0Sstevel@tonic-gate  *
355*0Sstevel@tonic-gate  *  Returns:  void
356*0Sstevel@tonic-gate  */
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate static	void
freedevicelist(void)359*0Sstevel@tonic-gate freedevicelist(void)
360*0Sstevel@tonic-gate {
361*0Sstevel@tonic-gate 	/* Automatic data */
362*0Sstevel@tonic-gate 	struct deviceent	*pdevice;	/* Pointer to current entry */
363*0Sstevel@tonic-gate 	char			*freeblk;	/* Pointer space to free */
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	/* List has a dummy head node */
366*0Sstevel@tonic-gate 	pdevice = (devicelist.head)->next;
367*0Sstevel@tonic-gate 	while (pdevice) {
368*0Sstevel@tonic-gate 	    freeblk = (char *) pdevice;
369*0Sstevel@tonic-gate 	    pdevice = pdevice->next;
370*0Sstevel@tonic-gate 	    free(freeblk);
371*0Sstevel@tonic-gate 	}
372*0Sstevel@tonic-gate }
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate /*
375*0Sstevel@tonic-gate  *  int addtodevicelist(deventry)
376*0Sstevel@tonic-gate  *	char   *deventry
377*0Sstevel@tonic-gate  *
378*0Sstevel@tonic-gate  * 	This function adds the device <deventry> to the list of devices already
379*0Sstevel@tonic-gate  *	accumulated.  It will not add the device if that device already exists
380*0Sstevel@tonic-gate  *	in the list.  The function returns 0 if successful, -1 if not with
381*0Sstevel@tonic-gate  *	"errno" set (by functions called) to indicate the error.
382*0Sstevel@tonic-gate  *
383*0Sstevel@tonic-gate  *  Arguments:
384*0Sstevel@tonic-gate  *	deventry		char *
385*0Sstevel@tonic-gate  *				The name of the device to add to the list of
386*0Sstevel@tonic-gate  *				accumulated devices
387*0Sstevel@tonic-gate  *
388*0Sstevel@tonic-gate  *  Returns:
389*0Sstevel@tonic-gate  *	0	If successful
390*0Sstevel@tonic-gate  *	-1	If failed.  "errno" will be set to a value that indicates the
391*0Sstevel@tonic-gate  *		error.
392*0Sstevel@tonic-gate  *
393*0Sstevel@tonic-gate  *  Notes:
394*0Sstevel@tonic-gate  *    -	The memory allocation scheme has the potential to fragment the memory
395*0Sstevel@tonic-gate  *	in the malloc heap.  We're allocating space for a local structure,
396*0Sstevel@tonic-gate  *	which will be freed by getdev(), then allocating space for the device
397*0Sstevel@tonic-gate  *	name, which will be freed (maybe) by the application using getdev().
398*0Sstevel@tonic-gate  *	Not worrying about this at the moment.
399*0Sstevel@tonic-gate  */
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate static	int
addtodevicelist(char * deventry)402*0Sstevel@tonic-gate addtodevicelist(char *deventry)
403*0Sstevel@tonic-gate {
404*0Sstevel@tonic-gate 	/* Automatic data */
405*0Sstevel@tonic-gate 	struct deviceent	*p;	/* Pointer to current device */
406*0Sstevel@tonic-gate 	struct deviceent	*q;	/* Pointer to next device */
407*0Sstevel@tonic-gate 	struct deviceent	*new;	/* Pointer to the alloc'd new node */
408*0Sstevel@tonic-gate 	char			*str;	/* Pointer to alloc'd space for name */
409*0Sstevel@tonic-gate 	int			rtncd;	/* Value to return to the caller */
410*0Sstevel@tonic-gate 	int			cmpcd;	/* strcmp() value, comparing names */
411*0Sstevel@tonic-gate 	int			done;	/* Loop control, TRUE if done */
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	/* Initializations */
415*0Sstevel@tonic-gate 	rtncd = FALSE;
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	/*
419*0Sstevel@tonic-gate 	 * Find the place in the found device list devicelist where this
420*0Sstevel@tonic-gate 	 * device is to reside
421*0Sstevel@tonic-gate 	 */
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	p = devicelist.head;
424*0Sstevel@tonic-gate 	done = FALSE;
425*0Sstevel@tonic-gate 	while (!done) {
426*0Sstevel@tonic-gate 	    q = p->next;
427*0Sstevel@tonic-gate 	    if (!q) done = TRUE;
428*0Sstevel@tonic-gate 	    else if ((cmpcd = strcmp(deventry, q->name)) <= 0) done = TRUE;
429*0Sstevel@tonic-gate 	    else p = q;
430*0Sstevel@tonic-gate 	}
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	/*
433*0Sstevel@tonic-gate 	 *  If the device is not already in the list, insert it in the list
434*0Sstevel@tonic-gate 	 */
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	if (!q || (cmpcd != 0)) {
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	    /* Alloc space for the new node */
439*0Sstevel@tonic-gate 	    if (new = malloc(sizeof (struct deviceent))) {
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 		/* Alloc space for the device character string */
442*0Sstevel@tonic-gate 		if (str = malloc(strlen(deventry)+1)) {
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 		/*
445*0Sstevel@tonic-gate 		 * Insert an entry in the found device list containing
446*0Sstevel@tonic-gate 		 * this device name
447*0Sstevel@tonic-gate 		 */
448*0Sstevel@tonic-gate 		    new->next = q;
449*0Sstevel@tonic-gate 		    p->next = new;
450*0Sstevel@tonic-gate 		    new->name = strcpy(str, deventry);
451*0Sstevel@tonic-gate 		    devicelist.count++;
452*0Sstevel@tonic-gate 		}
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 		/* Couldn't alloc space for the device name.  Error. */
455*0Sstevel@tonic-gate 		else rtncd = TRUE;
456*0Sstevel@tonic-gate 	    }
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	    /* Couldn't alloc space for new node in the found list.  Error. */
459*0Sstevel@tonic-gate 	    else rtncd = TRUE;
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	}
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 	/* Return an value indicating success or failure */
464*0Sstevel@tonic-gate 	return (rtncd);
465*0Sstevel@tonic-gate }
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate /*
468*0Sstevel@tonic-gate  *  struct srch *buildsearchlist(criteria)
469*0Sstevel@tonic-gate  *	char  **criteria
470*0Sstevel@tonic-gate  *
471*0Sstevel@tonic-gate  *	This function builds a list of search criteria structures from the
472*0Sstevel@tonic-gate  *	criteria strings in the list of criteria whose first argument is
473*0Sstevel@tonic-gate  *	specified by "criteria".
474*0Sstevel@tonic-gate  *
475*0Sstevel@tonic-gate  *  Arguments:
476*0Sstevel@tonic-gate  *	criteria	The address of the first item in a list of
477*0Sstevel@tonic-gate  *			character-strings specifying search criteria
478*0Sstevel@tonic-gate  *
479*0Sstevel@tonic-gate  *  Returns: struct srch *
480*0Sstevel@tonic-gate  *	The address of the structure in the list of structures describing the
481*0Sstevel@tonic-gate  *	search criteria.
482*0Sstevel@tonic-gate  *
483*0Sstevel@tonic-gate  *  Notes:
484*0Sstevel@tonic-gate  *    -	The only "regular expression" currently supported by the
485*0Sstevel@tonic-gate  *	kywd:exp and kywd!:exp forms is exp=*.  This function assumes
486*0Sstevel@tonic-gate  *	that kywd:exp means "if kywd exist" and that kywd!:exp means
487*0Sstevel@tonic-gate  *	"if kywd doesn't exist".
488*0Sstevel@tonic-gate  */
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate static 	struct srch *
buildsearchlist(char ** criteria)491*0Sstevel@tonic-gate buildsearchlist(char **criteria)	/* Criteria from caller */
492*0Sstevel@tonic-gate {
493*0Sstevel@tonic-gate 	/*  Automatic data  */
494*0Sstevel@tonic-gate 	struct srch	*rtnbuf;	/* Value to return */
495*0Sstevel@tonic-gate 	struct srch	*psrch;		/* Running pointer */
496*0Sstevel@tonic-gate 	char		*str;		/* Ptr to malloc()ed string space */
497*0Sstevel@tonic-gate 	char		*p;		/* Temp pointer to char */
498*0Sstevel@tonic-gate 	int		noerror;	/* TRUE if all's well */
499*0Sstevel@tonic-gate 	int		n;		/* Temp counter */
500*0Sstevel@tonic-gate 	char		**pp;		/* Running ptr to (char *) */
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	/*  Initializations  */
504*0Sstevel@tonic-gate 	rtnbuf = NULL;				/* Nothing to return yet */
505*0Sstevel@tonic-gate 	noerror = TRUE;				/* No errors (yet) */
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	/* If we were given any criteria ... */
508*0Sstevel@tonic-gate 	if (criteria) {
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	    /* Count the number of criteria in the list */
511*0Sstevel@tonic-gate 	    for (n = 1, pp = criteria; *pp++; n++)
512*0Sstevel@tonic-gate 		;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	    /* Allocate space for structures describing the criteria */
515*0Sstevel@tonic-gate 	    if (rtnbuf = malloc(n*sizeof (struct srch))) {
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 		/* Build structures describing the criteria */
518*0Sstevel@tonic-gate 		pp = criteria;
519*0Sstevel@tonic-gate 		psrch = rtnbuf;
520*0Sstevel@tonic-gate 		while (noerror && *pp) {
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 		    /* Keep list sane for cleanup if necessary */
523*0Sstevel@tonic-gate 		    psrch->fcn = ENDLIST;
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 		    /* Alloc space for strings referenced by the structure */
526*0Sstevel@tonic-gate 		    if (str = malloc(strlen(*pp)+1)) {
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 			/* Extract field name, function, and compare string */
529*0Sstevel@tonic-gate 			(void) strcpy(str, *pp);
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 			/* If criteria contains an equal sign ('=') ... */
532*0Sstevel@tonic-gate 			if (p = strchr(str+1, '=')) {
533*0Sstevel@tonic-gate 			    if (*(p-1) == '!') {
534*0Sstevel@tonic-gate 				*(p-1) = '\0';
535*0Sstevel@tonic-gate 				psrch->fcn = NOTEQUAL;
536*0Sstevel@tonic-gate 			    } else {
537*0Sstevel@tonic-gate 				*p = '\0';
538*0Sstevel@tonic-gate 				psrch->fcn = EQUAL;
539*0Sstevel@tonic-gate 			    }
540*0Sstevel@tonic-gate 			    psrch->cmp = p+1;
541*0Sstevel@tonic-gate 			    psrch->name = str;
542*0Sstevel@tonic-gate 			    psrch++;
543*0Sstevel@tonic-gate 			}
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 			/* If criteria contains a colon (':') ... */
546*0Sstevel@tonic-gate 			else if (p = strchr(str+1, ':')) {
547*0Sstevel@tonic-gate 			    if (*(p-1) == '!') {
548*0Sstevel@tonic-gate 				*(p-1) = '\0';
549*0Sstevel@tonic-gate 				psrch->fcn = NOEXISTS;
550*0Sstevel@tonic-gate 			    } else {
551*0Sstevel@tonic-gate 				*p = '\0';
552*0Sstevel@tonic-gate 				psrch->fcn = EXISTS;
553*0Sstevel@tonic-gate 			    }
554*0Sstevel@tonic-gate 			    psrch->cmp = p+1;
555*0Sstevel@tonic-gate 			    psrch->name = str;
556*0Sstevel@tonic-gate 			    psrch++;
557*0Sstevel@tonic-gate 			}
558*0Sstevel@tonic-gate 		    } else {
559*0Sstevel@tonic-gate 			/* Unable to malloc() string space.  Clean up */
560*0Sstevel@tonic-gate 			freesearchlist(rtnbuf);
561*0Sstevel@tonic-gate 			noerror = FALSE;
562*0Sstevel@tonic-gate 		    }
563*0Sstevel@tonic-gate 		    /* Next criteria */
564*0Sstevel@tonic-gate 		    pp++;
565*0Sstevel@tonic-gate 		}
566*0Sstevel@tonic-gate 		/* Terminate list */
567*0Sstevel@tonic-gate 		if (noerror) psrch->fcn = ENDLIST;
568*0Sstevel@tonic-gate 	    }
569*0Sstevel@tonic-gate 	}
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	/* Return a pointer to allocated space (if any) */
572*0Sstevel@tonic-gate 	return (rtnbuf);
573*0Sstevel@tonic-gate }
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate /*
576*0Sstevel@tonic-gate  *  void freesearchlist(list)
577*0Sstevel@tonic-gate  *	struct srch  *list
578*0Sstevel@tonic-gate  *
579*0Sstevel@tonic-gate  *	This function frees the resources allocated to the searchlist <list>.
580*0Sstevel@tonic-gate  *
581*0Sstevel@tonic-gate  *  Arguments:
582*0Sstevel@tonic-gate  *	list		The list whose resources are to be released.
583*0Sstevel@tonic-gate  *
584*0Sstevel@tonic-gate  *  Returns:  void
585*0Sstevel@tonic-gate  */
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate static	void
freesearchlist(struct srch * list)588*0Sstevel@tonic-gate freesearchlist(struct srch *list)
589*0Sstevel@tonic-gate {
590*0Sstevel@tonic-gate 	/* Automatic data */
591*0Sstevel@tonic-gate 	struct srch		*psrch;		/* Running ptr to structs */
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 	/* Free all of the string space allocated for the structure elememts */
595*0Sstevel@tonic-gate 	for (psrch = list; psrch->fcn != ENDLIST; psrch++) {
596*0Sstevel@tonic-gate 	    free(psrch->name);
597*0Sstevel@tonic-gate 	}
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 	/* Free the list space */
600*0Sstevel@tonic-gate 	free(list);
601*0Sstevel@tonic-gate }
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate /*
604*0Sstevel@tonic-gate  *  char **buildreturnlist()
605*0Sstevel@tonic-gate  *
606*0Sstevel@tonic-gate  *	This function builds a list of addresses of character-strings
607*0Sstevel@tonic-gate  *	to be returned from the linked-list of devices we've been
608*0Sstevel@tonic-gate  *	building.  It returns a pointer to the first item in that list.
609*0Sstevel@tonic-gate  *
610*0Sstevel@tonic-gate  *  Arguments:  none
611*0Sstevel@tonic-gate  *
612*0Sstevel@tonic-gate  *  Returns:  char **
613*0Sstevel@tonic-gate  *	The address of the first item in the return list
614*0Sstevel@tonic-gate  */
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate static	char **
buildreturnlist(void)617*0Sstevel@tonic-gate buildreturnlist(void)
618*0Sstevel@tonic-gate {
619*0Sstevel@tonic-gate 	/* Automatic data */
620*0Sstevel@tonic-gate 	char			**list;
621*0Sstevel@tonic-gate 	char			**q;
622*0Sstevel@tonic-gate 	struct deviceent	*p;
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	/*
626*0Sstevel@tonic-gate 	 * Allocate space for the return list,
627*0Sstevel@tonic-gate 	 * with space for the terminating node
628*0Sstevel@tonic-gate 	 */
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 	if (list = malloc((devicelist.count+1)*sizeof (char *))) {
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	/*
633*0Sstevel@tonic-gate 	 * Walk the list of accumulated devices, putting pointers to
634*0Sstevel@tonic-gate 	 * device names in the list to return
635*0Sstevel@tonic-gate 	 */
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	    q = list;
638*0Sstevel@tonic-gate 	    for (p = devicelist.head->next; p; p = p->next) *q++ = p->name;
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	    /* End the list with a null-pointer */
641*0Sstevel@tonic-gate 	    *q = NULL;
642*0Sstevel@tonic-gate 	}
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 	/* Return a pointer to the list we've built */
646*0Sstevel@tonic-gate 	return (list);
647*0Sstevel@tonic-gate }
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate /*
650*0Sstevel@tonic-gate  *  char **makealiaslist(devices)
651*0Sstevel@tonic-gate  *	char  **devices		List of aliases
652*0Sstevel@tonic-gate  *
653*0Sstevel@tonic-gate  *	Builds a list of aliases of the devices in the "devices"
654*0Sstevel@tonic-gate  *	list.  This list will be terminated by (char *) NULL and
655*0Sstevel@tonic-gate  *	will have the same number of elements as "devices".  If
656*0Sstevel@tonic-gate  *	a device couldn't be found, that alias will be "".  There
657*0Sstevel@tonic-gate  *	will be a one-to-one correspondence of devices to aliases
658*0Sstevel@tonic-gate  *	in the device list "devices" and the generated list.
659*0Sstevel@tonic-gate  *
660*0Sstevel@tonic-gate  *  Arguments:
661*0Sstevel@tonic-gate  *	devices		The list of devices to derive aliases from
662*0Sstevel@tonic-gate  *
663*0Sstevel@tonic-gate  *  Returns:  char **
664*0Sstevel@tonic-gate  *	The address of the list of addresses of aliases.  The list
665*0Sstevel@tonic-gate  *	and aliases will be allocated using the malloc() function.
666*0Sstevel@tonic-gate  */
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate static	char **
makealiaslist(char ** devices)669*0Sstevel@tonic-gate makealiaslist(char **devices)
670*0Sstevel@tonic-gate {
671*0Sstevel@tonic-gate 	/*  Automatic data  */
672*0Sstevel@tonic-gate 	char		**pp;		/* Running ptr to (char *) */
673*0Sstevel@tonic-gate 	char		**qq;		/* Running ptr to (char *) */
674*0Sstevel@tonic-gate 	char		**aliases;	/* List being returned */
675*0Sstevel@tonic-gate 	char		*alias;		/* Alias of current device */
676*0Sstevel@tonic-gate 	int		olderrno;	/* Value of errno on entry */
677*0Sstevel@tonic-gate 	int		noerror;	/* Flag, TRUE if all's well */
678*0Sstevel@tonic-gate 	int		n;		/* Count of entries in "devices" */
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	noerror = TRUE;
682*0Sstevel@tonic-gate 	olderrno = errno;
683*0Sstevel@tonic-gate 	if (devices) {
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	    /* Get the number of entries in the constaint list */
686*0Sstevel@tonic-gate 	    for (n = 1, pp = devices; *pp; pp++) n++;
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 	    /* Get space for the alias list */
689*0Sstevel@tonic-gate 	    if (aliases = malloc(n*sizeof (char *))) {
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 		/* Build the alias list */
692*0Sstevel@tonic-gate 		qq = aliases;
693*0Sstevel@tonic-gate 		for (pp = devices; noerror && *pp; pp++) {
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 		    /* Get the device's alias and put it in the list */
696*0Sstevel@tonic-gate 		    if (alias = devattr(*pp, DTAB_ALIAS)) *qq++ = alias;
697*0Sstevel@tonic-gate 		    else {
698*0Sstevel@tonic-gate 			errno = olderrno;
699*0Sstevel@tonic-gate 			if (alias = malloc(strlen("")+1))
700*0Sstevel@tonic-gate 			    *qq++ = strcpy(alias, "");
701*0Sstevel@tonic-gate 			else {
702*0Sstevel@tonic-gate 			    /* No space for a null string?  Yeech... */
703*0Sstevel@tonic-gate 			    for (qq = aliases; *qq; qq++) free(*qq);
704*0Sstevel@tonic-gate 			    free(aliases);
705*0Sstevel@tonic-gate 			    aliases = NULL;
706*0Sstevel@tonic-gate 			    noerror = FALSE;
707*0Sstevel@tonic-gate 			}
708*0Sstevel@tonic-gate 		    }
709*0Sstevel@tonic-gate 		}
710*0Sstevel@tonic-gate 		if (noerror)
711*0Sstevel@tonic-gate 			*qq = NULL;
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	    }
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 	} else
716*0Sstevel@tonic-gate 		aliases = NULL;  /* No constraint list */
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	/* Return ptr to generated list or NULL if none or error */
719*0Sstevel@tonic-gate 	return (aliases);
720*0Sstevel@tonic-gate }
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate /*
723*0Sstevel@tonic-gate  *  void freealiaslist(aliaslist)
724*0Sstevel@tonic-gate  *	char  **aliaslist;
725*0Sstevel@tonic-gate  *
726*0Sstevel@tonic-gate  *	Free the space allocated to the aliaslist.  It frees the space
727*0Sstevel@tonic-gate  *	allocated to the character-strings referenced by the list then
728*0Sstevel@tonic-gate  *	it frees the list.
729*0Sstevel@tonic-gate  *
730*0Sstevel@tonic-gate  *  Arguments:
731*0Sstevel@tonic-gate  *	aliaslist	The address of the first item in the list of
732*0Sstevel@tonic-gate  *			aliases that is to be freed
733*0Sstevel@tonic-gate  *
734*0Sstevel@tonic-gate  *  Returns:  void
735*0Sstevel@tonic-gate  */
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate static	void
freealiaslist(char ** aliaslist)738*0Sstevel@tonic-gate freealiaslist(char **aliaslist)		/* Ptr to new device list */
739*0Sstevel@tonic-gate {
740*0Sstevel@tonic-gate 	/* Automatic Data */
741*0Sstevel@tonic-gate 	char   **pp;			/* Running pointer */
742*0Sstevel@tonic-gate 
743*0Sstevel@tonic-gate 	/* If there's a list ... */
744*0Sstevel@tonic-gate 	if (aliaslist) {
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 	    /* For each entry in the old list, free the entry */
747*0Sstevel@tonic-gate 	    for (pp = aliaslist; *pp; pp++) free(*pp);
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	    /* Free the list */
750*0Sstevel@tonic-gate 	    free(aliaslist);
751*0Sstevel@tonic-gate 	}
752*0Sstevel@tonic-gate }
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate /*
755*0Sstevel@tonic-gate  *  char *getnextmatch(criteria, options)
756*0Sstevel@tonic-gate  *	struct srch	       *criteria
757*0Sstevel@tonic-gate  *	int			options
758*0Sstevel@tonic-gate  *
759*0Sstevel@tonic-gate  *  	Gets the next device in the device table that matches the criteria.
760*0Sstevel@tonic-gate  *	Returns the alias of that device.
761*0Sstevel@tonic-gate  *
762*0Sstevel@tonic-gate  *  Arguments:
763*0Sstevel@tonic-gate  *	criteria	The linked list of criteria to use to match a device
764*0Sstevel@tonic-gate  *	options		Options modifying the criteria (only one that's really
765*0Sstevel@tonic-gate  *			important is the DTAB_ANDCRITERIA flag)
766*0Sstevel@tonic-gate  *
767*0Sstevel@tonic-gate  *  Returns:  char *
768*0Sstevel@tonic-gate  *	A pointer to a malloc()ed string containing the alias of the next
769*0Sstevel@tonic-gate  *	device that matches the criteria, or (char *) NULL if none.
770*0Sstevel@tonic-gate  */
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate static	char   *
getnextmatch(struct srch * criteria,int options)773*0Sstevel@tonic-gate getnextmatch(struct srch *criteria, int options)
774*0Sstevel@tonic-gate {
775*0Sstevel@tonic-gate 	/* Automatic data */
776*0Sstevel@tonic-gate 	struct devtabent	*devtabent;	/* Ptr to current record */
777*0Sstevel@tonic-gate 	char			*alias;		/* Alias of device found */
778*0Sstevel@tonic-gate 	int			notdone;	/* Flag, done yet? */
779*0Sstevel@tonic-gate 	int			noerror;	/* Flag, had an error yet? */
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	/*
783*0Sstevel@tonic-gate 	 *  Initializations:
784*0Sstevel@tonic-gate 	 *    -	No alias yet
785*0Sstevel@tonic-gate 	 *    - Not finished yet
786*0Sstevel@tonic-gate 	 *    -	Make sure there are criteria we're to use
787*0Sstevel@tonic-gate 	 */
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 	alias = NULL;
790*0Sstevel@tonic-gate 	notdone = TRUE;
791*0Sstevel@tonic-gate 	noerror = TRUE;
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	/*  If we're to "and" the criteria...  */
794*0Sstevel@tonic-gate 	if (options & DTAB_ANDCRITERIA) {
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 	/*
797*0Sstevel@tonic-gate 	 *  Search the device table until we've got a record that matches
798*0Sstevel@tonic-gate 	 *  all of the criteria or we run out of records
799*0Sstevel@tonic-gate 	 */
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate 	    while (notdone && (devtabent = _getdevtabent())) {
802*0Sstevel@tonic-gate 		if (!devtabent->comment) {
803*0Sstevel@tonic-gate 		    if (!criteria || matchallcriteria(devtabent, criteria)) {
804*0Sstevel@tonic-gate 			if (alias = malloc(strlen(devtabent->alias)+1))
805*0Sstevel@tonic-gate 			    (void) strcpy(alias, devtabent->alias);
806*0Sstevel@tonic-gate 			else noerror = FALSE;
807*0Sstevel@tonic-gate 			notdone = FALSE;
808*0Sstevel@tonic-gate 		    }
809*0Sstevel@tonic-gate 		}
810*0Sstevel@tonic-gate 		_freedevtabent(devtabent);
811*0Sstevel@tonic-gate 	    }
812*0Sstevel@tonic-gate 	} else {
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	/*
815*0Sstevel@tonic-gate 	 *  Search the device table until we've got a record that matches
816*0Sstevel@tonic-gate 	 *  any of the criteria or we run out of records
817*0Sstevel@tonic-gate 	 */
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate 	    while (notdone && (devtabent = _getdevtabent())) {
820*0Sstevel@tonic-gate 		if (!devtabent->comment) {
821*0Sstevel@tonic-gate 		    if (!criteria || matchanycriteria(devtabent, criteria)) {
822*0Sstevel@tonic-gate 			if (alias = malloc(strlen(devtabent->alias)+1))
823*0Sstevel@tonic-gate 			    (void) strcpy(alias, devtabent->alias);
824*0Sstevel@tonic-gate 			else noerror = FALSE;
825*0Sstevel@tonic-gate 			notdone = FALSE;
826*0Sstevel@tonic-gate 		    }
827*0Sstevel@tonic-gate 		}
828*0Sstevel@tonic-gate 		_freedevtabent(devtabent);
829*0Sstevel@tonic-gate 	    }
830*0Sstevel@tonic-gate 	}
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	/* Return pointer to extracted alias (or NULL if none) */
834*0Sstevel@tonic-gate 	if ((alias == NULL) && noerror) errno = ENOENT;
835*0Sstevel@tonic-gate 	return (alias);
836*0Sstevel@tonic-gate }
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate /*
839*0Sstevel@tonic-gate  * int matchallcriteria(devtabent, criteria)
840*0Sstevel@tonic-gate  *
841*0Sstevel@tonic-gate  *	This function examines the record contained in "devtabent" and
842*0Sstevel@tonic-gate  *	determines if that record meets all of the criteria specified by
843*0Sstevel@tonic-gate  *	"criteria".
844*0Sstevel@tonic-gate  *
845*0Sstevel@tonic-gate  * Arguments:
846*0Sstevel@tonic-gate  *	struct devtabent *devtabent	The device table entry to examine.
847*0Sstevel@tonic-gate  *	struct srch    *criteria	The criteria to match.
848*0Sstevel@tonic-gate  *
849*0Sstevel@tonic-gate  * Returns:	int
850*0Sstevel@tonic-gate  *	Returns TRUE if the record matches criteria, FALSE otherwise.
851*0Sstevel@tonic-gate  */
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate static	int
matchallcriteria(struct devtabent * ent,struct srch * criteria)854*0Sstevel@tonic-gate matchallcriteria(
855*0Sstevel@tonic-gate 	struct devtabent	*ent,		/* Entry to check */
856*0Sstevel@tonic-gate 	struct srch		*criteria)	/* Criteria governing match */
857*0Sstevel@tonic-gate {
858*0Sstevel@tonic-gate 	/* Automatic data */
859*0Sstevel@tonic-gate 	struct srch    *p;		/* Pointer to current criteria */
860*0Sstevel@tonic-gate 	struct attrval *q;		/* Pointer to current attr/val pair */
861*0Sstevel@tonic-gate 	int		notfound;	/* TRUE if attr found in list */
862*0Sstevel@tonic-gate 	int		failed;		/* TRUE if record failed to match */
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 	/* Test only if there's criteria to test against */
866*0Sstevel@tonic-gate 	if (criteria && (criteria->fcn != ENDLIST)) {
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 	    failed = FALSE;
869*0Sstevel@tonic-gate 	    for (p = criteria; !failed && (p->fcn != ENDLIST); p++) {
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 		/*
872*0Sstevel@tonic-gate 		 * Don't compare against this criteria if it's function is
873*0Sstevel@tonic-gate 		 * "IGNORE"
874*0Sstevel@tonic-gate 		 */
875*0Sstevel@tonic-gate 		if (p->fcn != IGNORE) {
876*0Sstevel@tonic-gate 		    if (p->fcn != NOEXISTS) {
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 			/*  Alias?  */
879*0Sstevel@tonic-gate 			if (strcmp(p->name, DTAB_ALIAS) == 0)
880*0Sstevel@tonic-gate 			    failed = !matches(ent->alias, p->cmp, p->fcn);
881*0Sstevel@tonic-gate 
882*0Sstevel@tonic-gate 			/*  Char special device?  */
883*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_CDEVICE) == 0)
884*0Sstevel@tonic-gate 			    failed = !matches(ent->cdevice, p->cmp, p->fcn);
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 			/*  Block special device?  */
887*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_BDEVICE) == 0)
888*0Sstevel@tonic-gate 			    failed = !matches(ent->bdevice, p->cmp, p->fcn);
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate 			/*  Pathname?  */
891*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_PATHNAME) == 0)
892*0Sstevel@tonic-gate 			    failed = !matches(ent->pathname, p->cmp, p->fcn);
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 			/*  Check other attributes...  */
895*0Sstevel@tonic-gate 			else {
896*0Sstevel@tonic-gate 			    notfound = TRUE;
897*0Sstevel@tonic-gate 			    q = ent->attrlist;
898*0Sstevel@tonic-gate 			    while (notfound && q) {
899*0Sstevel@tonic-gate 				if (strcmp(p->name, q->attr) == 0) {
900*0Sstevel@tonic-gate 				    notfound = FALSE;
901*0Sstevel@tonic-gate 				    if (!matches(q->val, p->cmp, p->fcn))
902*0Sstevel@tonic-gate 					failed = TRUE;
903*0Sstevel@tonic-gate 				} else q = q->next;
904*0Sstevel@tonic-gate 			    }
905*0Sstevel@tonic-gate 			    if (notfound) failed = TRUE;
906*0Sstevel@tonic-gate 			}
907*0Sstevel@tonic-gate 		    } else {
908*0Sstevel@tonic-gate 			if (strcmp(p->name, DTAB_ALIAS) == 0) failed = TRUE;
909*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_CDEVICE) == 0)
910*0Sstevel@tonic-gate 				failed = FALSE;
911*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_BDEVICE) == 0)
912*0Sstevel@tonic-gate 				failed = FALSE;
913*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_PATHNAME) == 0)
914*0Sstevel@tonic-gate 				failed = FALSE;
915*0Sstevel@tonic-gate 			else {
916*0Sstevel@tonic-gate 			    q = ent->attrlist;
917*0Sstevel@tonic-gate 			    while (!failed && q) {
918*0Sstevel@tonic-gate 				if (strcmp(p->name, q->attr) == 0)
919*0Sstevel@tonic-gate 					failed = TRUE;
920*0Sstevel@tonic-gate 				else q = q->next;
921*0Sstevel@tonic-gate 			    }
922*0Sstevel@tonic-gate 			}
923*0Sstevel@tonic-gate 		    }
924*0Sstevel@tonic-gate 
925*0Sstevel@tonic-gate 		}  /* Search function is not "IGNORE" */
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate 	    }  /* for loop, checking each criteria */
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 	}  /* if (criteria) */
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 	else failed = FALSE;  /* No criteria specified, it's a match */
932*0Sstevel@tonic-gate 
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	/* Return a value indicating if the record matches all criteria */
935*0Sstevel@tonic-gate 	return (!failed);
936*0Sstevel@tonic-gate }
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate /*
939*0Sstevel@tonic-gate  * int matchanycriteria(devtabent, criteria)
940*0Sstevel@tonic-gate  *
941*0Sstevel@tonic-gate  *	This function examines the record contained in "devtabent" and
942*0Sstevel@tonic-gate  *	determines if that record meets any of the criteria specified by
943*0Sstevel@tonic-gate  *	"criteria".
944*0Sstevel@tonic-gate  *
945*0Sstevel@tonic-gate  * Arguments:
946*0Sstevel@tonic-gate  *	struct devtabent *devtabent	The device table entry to examine.
947*0Sstevel@tonic-gate  *	struct srch      *criteria	The criteria to match.
948*0Sstevel@tonic-gate  *
949*0Sstevel@tonic-gate  * Returns:	int
950*0Sstevel@tonic-gate  *	Returns TRUE if the record matches criteria, FALSE otherwise.
951*0Sstevel@tonic-gate  */
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate static	int
matchanycriteria(struct devtabent * ent,struct srch * criteria)954*0Sstevel@tonic-gate matchanycriteria(
955*0Sstevel@tonic-gate 	struct devtabent	*ent,		/* Entry to check */
956*0Sstevel@tonic-gate 	struct srch		*criteria)	/* Criteria governing match */
957*0Sstevel@tonic-gate {
958*0Sstevel@tonic-gate 	/* Automatic data */
959*0Sstevel@tonic-gate 	struct srch    *p;		/* Pointer to current criteria */
960*0Sstevel@tonic-gate 	struct attrval *q;		/* Pointer to current attr/val pair */
961*0Sstevel@tonic-gate 	int		matched;	/* FLAG: TRUE if record matched */
962*0Sstevel@tonic-gate 	int		found;		/* FLAG: TRUE if attribute found */
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 	/* Test only if there's criteria to test against */
966*0Sstevel@tonic-gate 	if (criteria && (criteria->fcn != ENDLIST)) {
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate 	    matched = FALSE;
969*0Sstevel@tonic-gate 	    for (p = criteria; !matched && (p->fcn != ENDLIST); p++) {
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 		/*
972*0Sstevel@tonic-gate 		 * Don't compare against this criteria if it's function is
973*0Sstevel@tonic-gate 		 * "IGNORE"
974*0Sstevel@tonic-gate 		 */
975*0Sstevel@tonic-gate 		if (p->fcn != IGNORE) {
976*0Sstevel@tonic-gate 		    if (p->fcn != NOEXISTS) {
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 			/*  Alias?  */
979*0Sstevel@tonic-gate 			if (strcmp(p->name, DTAB_ALIAS) == 0)
980*0Sstevel@tonic-gate 			    matched = matches(ent->alias, p->cmp, p->fcn);
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate 			/*  Char special device?  */
983*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_CDEVICE) == 0)
984*0Sstevel@tonic-gate 			    matched = matches(ent->cdevice, p->cmp, p->fcn);
985*0Sstevel@tonic-gate 
986*0Sstevel@tonic-gate 			/*  Block special device?  */
987*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_BDEVICE) == 0)
988*0Sstevel@tonic-gate 			    matched = matches(ent->bdevice, p->cmp, p->fcn);
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 			/*  Pathname?  */
991*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_PATHNAME) == 0)
992*0Sstevel@tonic-gate 			    matched = matches(ent->pathname, p->cmp, p->fcn);
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 			/*  Check other attributes...  */
995*0Sstevel@tonic-gate 			else {
996*0Sstevel@tonic-gate 			    q = ent->attrlist;
997*0Sstevel@tonic-gate 			    found = FALSE;
998*0Sstevel@tonic-gate 			    while (!found && q)
999*0Sstevel@tonic-gate 				if (strcmp(p->name, q->attr) == 0) {
1000*0Sstevel@tonic-gate 				    matched = matches(q->val, p->cmp, p->fcn);
1001*0Sstevel@tonic-gate 				    found = TRUE;
1002*0Sstevel@tonic-gate 				} else q = q->next;
1003*0Sstevel@tonic-gate 			}
1004*0Sstevel@tonic-gate 		    } else {
1005*0Sstevel@tonic-gate 			if (strcmp(p->name, DTAB_ALIAS) == 0) matched = FALSE;
1006*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_CDEVICE) == 0)
1007*0Sstevel@tonic-gate 				matched = FALSE;
1008*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_BDEVICE) == 0)
1009*0Sstevel@tonic-gate 				matched = FALSE;
1010*0Sstevel@tonic-gate 			else if (strcmp(p->name, DTAB_PATHNAME) == 0)
1011*0Sstevel@tonic-gate 				matched = FALSE;
1012*0Sstevel@tonic-gate 			else {
1013*0Sstevel@tonic-gate 			    q = ent->attrlist;
1014*0Sstevel@tonic-gate 			    matched = TRUE;
1015*0Sstevel@tonic-gate 			    while (matched && q) {
1016*0Sstevel@tonic-gate 				if (strcmp(p->name, q->attr) == 0)
1017*0Sstevel@tonic-gate 					matched = FALSE;
1018*0Sstevel@tonic-gate 				else q = q->next;
1019*0Sstevel@tonic-gate 			    }
1020*0Sstevel@tonic-gate 			}
1021*0Sstevel@tonic-gate 		    }
1022*0Sstevel@tonic-gate 		}  /* Search function is not "IGNORE" */
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate 	    }  /* for loop, checking each criteria */
1025*0Sstevel@tonic-gate 
1026*0Sstevel@tonic-gate 	}  /* if (criteria) */
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 	else matched = TRUE;  /* No criteria specified, it's a match */
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 
1031*0Sstevel@tonic-gate 	/* Return a value indicating if the record matches all criteria */
1032*0Sstevel@tonic-gate 	return (matched);
1033*0Sstevel@tonic-gate }
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate /*
1036*0Sstevel@tonic-gate  *  int matches(value, compare, function)
1037*0Sstevel@tonic-gate  *	char   *value
1038*0Sstevel@tonic-gate  *	char   *compare
1039*0Sstevel@tonic-gate  *	int	function
1040*0Sstevel@tonic-gate  *
1041*0Sstevel@tonic-gate  *	This function sees if the operation <function> is satisfied by
1042*0Sstevel@tonic-gate  *	comparing the value <value> with <compare>.  It returns TRUE
1043*0Sstevel@tonic-gate  *	if so, FALSE otherwise.
1044*0Sstevel@tonic-gate  *
1045*0Sstevel@tonic-gate  *  Arguments:
1046*0Sstevel@tonic-gate  *	value		Value to compare
1047*0Sstevel@tonic-gate  *	compare		Value to compare against
1048*0Sstevel@tonic-gate  *	function	Function to be satisfied
1049*0Sstevel@tonic-gate  *
1050*0Sstevel@tonic-gate  *  Returns:  int
1051*0Sstevel@tonic-gate  *	TRUE if the function is satisfied, FALSE otherwise
1052*0Sstevel@tonic-gate  */
1053*0Sstevel@tonic-gate 
1054*0Sstevel@tonic-gate static	int
matches(char * value,char * compare,int function)1055*0Sstevel@tonic-gate matches(char *value, char *compare, int function)
1056*0Sstevel@tonic-gate {
1057*0Sstevel@tonic-gate 	/*  Automatic data  */
1058*0Sstevel@tonic-gate 	int	rtn;		/* Value to return */
1059*0Sstevel@tonic-gate 
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	if (value == NULL)
1062*0Sstevel@tonic-gate 		value = "";
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 	/* Do case depending on the function */
1065*0Sstevel@tonic-gate 	switch (function) {
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	/* attr=val */
1068*0Sstevel@tonic-gate 	case EQUAL:
1069*0Sstevel@tonic-gate 	    rtn = (strcmp(value, compare) == 0);
1070*0Sstevel@tonic-gate 	    break;
1071*0Sstevel@tonic-gate 
1072*0Sstevel@tonic-gate 	/* attr!=val */
1073*0Sstevel@tonic-gate 	case NOTEQUAL:
1074*0Sstevel@tonic-gate 	    rtn = (strcmp(value, compare) != 0);
1075*0Sstevel@tonic-gate 	    break;
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate 	/* attr:* */
1078*0Sstevel@tonic-gate 	case EXISTS:
1079*0Sstevel@tonic-gate 	    rtn = TRUE;
1080*0Sstevel@tonic-gate 	    break;
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate 	/* attr!:* */
1083*0Sstevel@tonic-gate 	case NOEXISTS:
1084*0Sstevel@tonic-gate 	    rtn = FALSE;
1085*0Sstevel@tonic-gate 	    break;
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	/* Shouldn't get here... */
1088*0Sstevel@tonic-gate 	default:
1089*0Sstevel@tonic-gate 	    rtn = FALSE;
1090*0Sstevel@tonic-gate 	    break;
1091*0Sstevel@tonic-gate 	}
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate 	/* Return a value indicating if the match was made */
1094*0Sstevel@tonic-gate 	return (rtn);
1095*0Sstevel@tonic-gate }
1096