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
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.
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]
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
27 * Copyright (c) 1997, by Sun Microsystems, Inc.
28 * All rights reserved.
31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
38 * getdev() List devices that match certain criteria.
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
52 #include <sys/types.h>
82 * Comparison values. These values are placed in the struct srch
83 * structure by buildsearchlist() and are used to compare values
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
102 * Structure definitions:
103 * deviceent Defines a device that matches criteria
104 * srch Describes a criteria
108 struct deviceent
*next
; /* Pointer to next item in the list */
109 char *name
; /* Presentation name of the device */
113 char *name
; /* Name of field to compare */
114 char *cmp
; /* Value to compare against */
115 int fcn
; /* Type of comparison (see above) */
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
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
139 * getnextmatch() Get the next device that matches the search
141 * matchallcriteria() See if the device attributes match all of the
143 * matchanycriteria() See if the device attributes match any of the
145 * matches() See if the criteria and attribute match
148 static char *oktoaddtolist(char *, char **, char **, int);
149 static void initdevicelist(void);
150 static void freedevicelist(void);
151 static int addtodevicelist(char *);
152 static struct srch
*buildsearchlist(char **);
153 static void freesearchlist(struct srch
*);
154 static char **buildreturnlist(void);
155 static char **makealiaslist(char **);
156 static void freealiaslist(char **);
157 static char *getnextmatch(struct srch
*, int);
158 static int matchallcriteria(struct devtabent
*, struct srch
*);
159 static int matchanycriteria(struct devtabent
*, struct srch
*);
160 static int matches(char *, char *, int);
169 * devicelisthead The first item (dummy) in the linked list of devices
171 * devicelist Structure describing the linked list of devices
174 static struct deviceent devicelisthead
;
176 struct deviceent
*head
;
178 } devicelist
= {&devicelisthead
, 0};
181 * char **getdev(devices, criteria, options)
186 * This function builds a list of devices that match criteria,
187 * governed by the device list.
190 * devices The list of devices to select from or the list of
191 * devices to exclude, depending on the value of
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)
203 * The address of the first item in the list of devices that meet
204 * the selection criteria
209 char **devices
, /* List of devices to constrain */
210 char **criteria
, /* List of selection criteria */
211 int options
) /* Options governing the search */
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 */
225 /* Make sure the exclude/include list is all aliases */
226 aliases
= makealiaslist(devices
);
227 if (devices
&& !aliases
)
230 /* Build the search list */
232 if (!(searchlist
= buildsearchlist(criteria
)))
234 } else searchlist
= NULL
;
236 /* Initialize searching */
242 * Keep on going until we get no more matches
246 while (!errflag
&& (entry
= getnextmatch(searchlist
, options
))) {
247 if (entry
= oktoaddtolist(entry
, devices
, aliases
, options
)) {
248 errflag
= addtodevicelist(entry
);
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.
263 returnlist
= buildreturnlist();
265 freealiaslist(aliases
);
271 * char *oktoaddtolist(devtabentry, devices, aliases, options)
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).
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
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 */
298 char *rtnval
; /* Value to return */
299 int found
; /* Flag: TRUE if found */
301 /* If there's a constraint list, is this device in it? */
302 if (devices
&& aliases
) {
304 /* Set "found" to TRUE if the device is in the list */
306 while (!found
&& *aliases
) {
307 if (strcmp(devtabentry
, *aliases
) == 0) found
= TRUE
;
314 /* Set value to return */
316 rtnval
= (options
& DTAB_EXCLUDEFLAG
) ?
319 rtnval
= (options
& DTAB_EXCLUDEFLAG
) ?
322 } else rtnval
= devtabentry
; /* No constraint list */
328 * void initdevicelist()
330 * This function initializes the list of accumulated devices.
342 /* Make the list a null list */
343 (devicelist
.head
)->next
= NULL
;
344 devicelist
.count
= 0;
348 * void freedevicelist()
350 * This function frees the resources allocated to the linked list of
351 * devices we've been accumulating.
362 struct deviceent
*pdevice
; /* Pointer to current entry */
363 char *freeblk
; /* Pointer space to free */
365 /* List has a dummy head node */
366 pdevice
= (devicelist
.head
)->next
;
368 freeblk
= (char *) pdevice
;
369 pdevice
= pdevice
->next
;
375 * int addtodevicelist(deventry)
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.
385 * The name of the device to add to the list of
386 * accumulated devices
390 * -1 If failed. "errno" will be set to a value that indicates the
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.
402 addtodevicelist(char *deventry
)
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 */
414 /* Initializations */
419 * Find the place in the found device list devicelist where this
420 * device is to reside
428 else if ((cmpcd
= strcmp(deventry
, q
->name
)) <= 0) done
= TRUE
;
433 * If the device is not already in the list, insert it in the list
436 if (!q
|| (cmpcd
!= 0)) {
438 /* Alloc space for the new node */
439 if (new = malloc(sizeof (struct deviceent
))) {
441 /* Alloc space for the device character string */
442 if (str
= malloc(strlen(deventry
)+1)) {
445 * Insert an entry in the found device list containing
450 new->name
= strcpy(str
, deventry
);
454 /* Couldn't alloc space for the device name. Error. */
458 /* Couldn't alloc space for new node in the found list. Error. */
463 /* Return an value indicating success or failure */
468 * struct srch *buildsearchlist(criteria)
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".
476 * criteria The address of the first item in a list of
477 * character-strings specifying search criteria
479 * Returns: struct srch *
480 * The address of the structure in the list of structures describing the
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".
491 buildsearchlist(char **criteria
) /* Criteria from caller */
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 *) */
503 /* Initializations */
504 rtnbuf
= NULL
; /* Nothing to return yet */
505 noerror
= TRUE
; /* No errors (yet) */
507 /* If we were given any criteria ... */
510 /* Count the number of criteria in the list */
511 for (n
= 1, pp
= criteria
; *pp
++; n
++)
514 /* Allocate space for structures describing the criteria */
515 if (rtnbuf
= malloc(n
*sizeof (struct srch
))) {
517 /* Build structures describing the criteria */
520 while (noerror
&& *pp
) {
522 /* Keep list sane for cleanup if necessary */
523 psrch
->fcn
= ENDLIST
;
525 /* Alloc space for strings referenced by the structure */
526 if (str
= malloc(strlen(*pp
)+1)) {
528 /* Extract field name, function, and compare string */
529 (void) strcpy(str
, *pp
);
531 /* If criteria contains an equal sign ('=') ... */
532 if (p
= strchr(str
+1, '=')) {
535 psrch
->fcn
= NOTEQUAL
;
545 /* If criteria contains a colon (':') ... */
546 else if (p
= strchr(str
+1, ':')) {
549 psrch
->fcn
= NOEXISTS
;
559 /* Unable to malloc() string space. Clean up */
560 freesearchlist(rtnbuf
);
567 if (noerror
) psrch
->fcn
= ENDLIST
;
571 /* Return a pointer to allocated space (if any) */
576 * void freesearchlist(list)
579 * This function frees the resources allocated to the searchlist <list>.
582 * list The list whose resources are to be released.
588 freesearchlist(struct srch
*list
)
591 struct srch
*psrch
; /* Running ptr to structs */
594 /* Free all of the string space allocated for the structure elememts */
595 for (psrch
= list
; psrch
->fcn
!= ENDLIST
; psrch
++) {
599 /* Free the list space */
604 * char **buildreturnlist()
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.
613 * The address of the first item in the return list
617 buildreturnlist(void)
626 * Allocate space for the return list,
627 * with space for the terminating node
630 if (list
= malloc((devicelist
.count
+1)*sizeof (char *))) {
633 * Walk the list of accumulated devices, putting pointers to
634 * device names in the list to return
638 for (p
= devicelist
.head
->next
; p
; p
= p
->next
) *q
++ = p
->name
;
640 /* End the list with a null-pointer */
645 /* Return a pointer to the list we've built */
650 * char **makealiaslist(devices)
651 * char **devices List of aliases
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.
661 * devices The list of devices to derive aliases from
664 * The address of the list of addresses of aliases. The list
665 * and aliases will be allocated using the malloc() function.
669 makealiaslist(char **devices
)
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" */
685 /* Get the number of entries in the constaint list */
686 for (n
= 1, pp
= devices
; *pp
; pp
++) n
++;
688 /* Get space for the alias list */
689 if (aliases
= malloc(n
*sizeof (char *))) {
691 /* Build the alias list */
693 for (pp
= devices
; noerror
&& *pp
; pp
++) {
695 /* Get the device's alias and put it in the list */
696 if (alias
= devattr(*pp
, DTAB_ALIAS
)) *qq
++ = alias
;
699 if (alias
= malloc(strlen("")+1))
700 *qq
++ = strcpy(alias
, "");
702 /* No space for a null string? Yeech... */
703 for (qq
= aliases
; *qq
; qq
++) free(*qq
);
716 aliases
= NULL
; /* No constraint list */
718 /* Return ptr to generated list or NULL if none or error */
723 * void freealiaslist(aliaslist)
726 * Free the space allocated to the aliaslist. It frees the space
727 * allocated to the character-strings referenced by the list then
731 * aliaslist The address of the first item in the list of
732 * aliases that is to be freed
738 freealiaslist(char **aliaslist
) /* Ptr to new device list */
741 char **pp
; /* Running pointer */
743 /* If there's a list ... */
746 /* For each entry in the old list, free the entry */
747 for (pp
= aliaslist
; *pp
; pp
++) free(*pp
);
755 * char *getnextmatch(criteria, options)
756 * struct srch *criteria
759 * Gets the next device in the device table that matches the criteria.
760 * Returns the alias of that device.
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)
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.
773 getnextmatch(struct srch
*criteria
, int options
)
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? */
786 * - Make sure there are criteria we're to use
793 /* If we're to "and" the criteria... */
794 if (options
& DTAB_ANDCRITERIA
) {
797 * Search the device table until we've got a record that matches
798 * all of the criteria or we run out of records
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
;
810 _freedevtabent(devtabent
);
815 * Search the device table until we've got a record that matches
816 * any of the criteria or we run out of records
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
;
828 _freedevtabent(devtabent
);
833 /* Return pointer to extracted alias (or NULL if none) */
834 if ((alias
== NULL
) && noerror
) errno
= ENOENT
;
839 * int matchallcriteria(devtabent, criteria)
841 * This function examines the record contained in "devtabent" and
842 * determines if that record meets all of the criteria specified by
846 * struct devtabent *devtabent The device table entry to examine.
847 * struct srch *criteria The criteria to match.
850 * Returns TRUE if the record matches criteria, FALSE otherwise.
855 struct devtabent
*ent
, /* Entry to check */
856 struct srch
*criteria
) /* Criteria governing match */
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 */
865 /* Test only if there's criteria to test against */
866 if (criteria
&& (criteria
->fcn
!= ENDLIST
)) {
869 for (p
= criteria
; !failed
&& (p
->fcn
!= ENDLIST
); p
++) {
872 * Don't compare against this criteria if it's function is
875 if (p
->fcn
!= IGNORE
) {
876 if (p
->fcn
!= NOEXISTS
) {
879 if (strcmp(p
->name
, DTAB_ALIAS
) == 0)
880 failed
= !matches(ent
->alias
, p
->cmp
, p
->fcn
);
882 /* Char special device? */
883 else if (strcmp(p
->name
, DTAB_CDEVICE
) == 0)
884 failed
= !matches(ent
->cdevice
, p
->cmp
, p
->fcn
);
886 /* Block special device? */
887 else if (strcmp(p
->name
, DTAB_BDEVICE
) == 0)
888 failed
= !matches(ent
->bdevice
, p
->cmp
, p
->fcn
);
891 else if (strcmp(p
->name
, DTAB_PATHNAME
) == 0)
892 failed
= !matches(ent
->pathname
, p
->cmp
, p
->fcn
);
894 /* Check other attributes... */
898 while (notfound
&& q
) {
899 if (strcmp(p
->name
, q
->attr
) == 0) {
901 if (!matches(q
->val
, p
->cmp
, p
->fcn
))
905 if (notfound
) failed
= TRUE
;
908 if (strcmp(p
->name
, DTAB_ALIAS
) == 0) failed
= TRUE
;
909 else if (strcmp(p
->name
, DTAB_CDEVICE
) == 0)
911 else if (strcmp(p
->name
, DTAB_BDEVICE
) == 0)
913 else if (strcmp(p
->name
, DTAB_PATHNAME
) == 0)
917 while (!failed
&& q
) {
918 if (strcmp(p
->name
, q
->attr
) == 0)
925 } /* Search function is not "IGNORE" */
927 } /* for loop, checking each criteria */
929 } /* if (criteria) */
931 else failed
= FALSE
; /* No criteria specified, it's a match */
934 /* Return a value indicating if the record matches all criteria */
939 * int matchanycriteria(devtabent, criteria)
941 * This function examines the record contained in "devtabent" and
942 * determines if that record meets any of the criteria specified by
946 * struct devtabent *devtabent The device table entry to examine.
947 * struct srch *criteria The criteria to match.
950 * Returns TRUE if the record matches criteria, FALSE otherwise.
955 struct devtabent
*ent
, /* Entry to check */
956 struct srch
*criteria
) /* Criteria governing match */
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 */
965 /* Test only if there's criteria to test against */
966 if (criteria
&& (criteria
->fcn
!= ENDLIST
)) {
969 for (p
= criteria
; !matched
&& (p
->fcn
!= ENDLIST
); p
++) {
972 * Don't compare against this criteria if it's function is
975 if (p
->fcn
!= IGNORE
) {
976 if (p
->fcn
!= NOEXISTS
) {
979 if (strcmp(p
->name
, DTAB_ALIAS
) == 0)
980 matched
= matches(ent
->alias
, p
->cmp
, p
->fcn
);
982 /* Char special device? */
983 else if (strcmp(p
->name
, DTAB_CDEVICE
) == 0)
984 matched
= matches(ent
->cdevice
, p
->cmp
, p
->fcn
);
986 /* Block special device? */
987 else if (strcmp(p
->name
, DTAB_BDEVICE
) == 0)
988 matched
= matches(ent
->bdevice
, p
->cmp
, p
->fcn
);
991 else if (strcmp(p
->name
, DTAB_PATHNAME
) == 0)
992 matched
= matches(ent
->pathname
, p
->cmp
, p
->fcn
);
994 /* Check other attributes... */
999 if (strcmp(p
->name
, q
->attr
) == 0) {
1000 matched
= matches(q
->val
, p
->cmp
, p
->fcn
);
1005 if (strcmp(p
->name
, DTAB_ALIAS
) == 0) matched
= FALSE
;
1006 else if (strcmp(p
->name
, DTAB_CDEVICE
) == 0)
1008 else if (strcmp(p
->name
, DTAB_BDEVICE
) == 0)
1010 else if (strcmp(p
->name
, DTAB_PATHNAME
) == 0)
1015 while (matched
&& q
) {
1016 if (strcmp(p
->name
, q
->attr
) == 0)
1022 } /* Search function is not "IGNORE" */
1024 } /* for loop, checking each criteria */
1026 } /* if (criteria) */
1028 else matched
= TRUE
; /* No criteria specified, it's a match */
1031 /* Return a value indicating if the record matches all criteria */
1036 * int matches(value, compare, function)
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.
1046 * value Value to compare
1047 * compare Value to compare against
1048 * function Function to be satisfied
1051 * TRUE if the function is satisfied, FALSE otherwise
1055 matches(char *value
, char *compare
, int function
)
1057 /* Automatic data */
1058 int rtn
; /* Value to return */
1064 /* Do case depending on the function */
1069 rtn
= (strcmp(value
, compare
) == 0);
1074 rtn
= (strcmp(value
, compare
) != 0);
1087 /* Shouldn't get here... */
1093 /* Return a value indicating if the match was made */