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