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 /*LINTLIBRARY*/
32
33 /*
34 * getdgrp.c
35 *
36 * Contains the following global functions:
37 * getdgrp() Get the device groups that meet certain criteria.
38 */
39
40 /*
41 * Header Files Referenced
42 * <sys/types.h> Data Types
43 * <stdio.h> Standard I/O definitions
44 * <string.h> Character-string definitions
45 * <devmgmt.h> Definitions for accessing device table files
46 * "devtab.h" Local definitions for device tables
47 */
48
49 #include <sys/types.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <devmgmt.h>
54 #include "devtab.h"
55
56 /*
57 * Local definitions
58 * struct dgrplist Structure that makes up the internal device
59 * group list
60 * Members:
61 * name Name of the device group
62 * next Pointer to the next in the list
63 */
64
65 struct dgrplist {
66 char *name;
67 struct dgrplist *next;
68 };
69
70
71 /*
72 * Local functions
73 * initdgrplist Initialize the internal device group list
74 * addtodgrplist Add a device group to the device group list
75 * isindevlist Does the device group contain a device?
76 * isincallerslist Is a device group in the caller's list?
77 * buildreturnlist Build list of device groups to return
78 * freedgrplist Free the internal device group list
79 */
80
81 static void initdgrplist(void);
82 static int addtodgrplist(struct dgrptabent *);
83 static int isindevlist(struct dgrptabent *, char **);
84 static int isincallerslist(struct dgrptabent *, char **);
85 static char **buildreturnlist(void);
86 static void freedgrplist(void);
87
88
89 /*
90 * Local data
91 * dgrplistfirst First (dummy) node in the device group list
92 * dgrplistcount Number of items in the device group list
93 */
94
95 static struct dgrplist dgrplistfirst;
96 static int dgrplistcount;
97
98 /*
99 * char **getdgrp(dgroups, criteria, options)
100 * char **dgroups
101 * char **criteria
102 * int options
103 *
104 * This function compiles a list of device groups containing devices
105 * that meet certain criteria and returns a pointer to the first
106 * item in that list.
107 *
108 * Arguments:
109 * dgroups The list of device groups to choose from or the list
110 * of device groups to exclude from the list (depends on
111 * "options"
112 * criteria The criteria that a device must meet
113 * options Indicates 1) whether to "and" the criteria or to "or"
114 * the criteria, 2) indicates whether to limit the
115 * generated list to "dgroups" or to exclude those
116 * device-groups from the list, 3) to list all device
117 * groups even if they don't contain valid devices.
118 *
119 * Returns: char **
120 * A pointer to the first address in the list of addresses of generated
121 * device groups
122 */
123
124 char **
getdgrp(char ** dgroups,char ** criteria,int options)125 getdgrp(
126 char **dgroups, /* List of device groups */
127 char **criteria, /* List of criteria to meet */
128 int options) /* Options governing the search */
129 {
130 /* Automatic data */
131 char **devlist; /* Devices that meet criteria */
132 char **plist; /* Device groups to return */
133 struct dgrptabent *dgrp; /* Dgrp information struct */
134 int errorflag; /* TRUE if error occurred */
135 int listallflag; /* TRUE if DTAB_LISTALL && (!criteria || !*criteria) */
136
137
138 /*
139 * Open the device-group table if needed
140 */
141
142 if (!oam_dgroup && !_opendgrptab("r"))
143 return (NULL);
144
145
146 /*
147 * Get the list of devices that meet the criteria specified
148 * This step can be skipped if DTAB_LISTALL is requested and
149 * there is no criteria list.
150 */
151
152 if (((options & DTAB_LISTALL) == 0) || (criteria && *criteria)) {
153 devlist = getdev(NULL, criteria, (options & DTAB_ANDCRITERIA));
154 listallflag = FALSE;
155 } else {
156 devlist = NULL;
157 listallflag = TRUE;
158 }
159
160
161 /*
162 * Initialize the device group list (contains the device groups
163 * we're accumulating)
164 */
165
166 errorflag = FALSE;
167 initdgrplist();
168
169
170 /*
171 * If no device groups were specified by the caller, accumulate all
172 * device groups
173 */
174
175 _setdgrptab();
176 if (!dgroups || !(*dgroups)) {
177 while (!errorflag && (dgrp = _getdgrptabent())) {
178 if (!dgrp->comment && (listallflag ||
179 isindevlist(dgrp, devlist)))
180 errorflag = !addtodgrplist(dgrp);
181 _freedgrptabent(dgrp);
182 }
183 }
184
185 else {
186
187 /*
188 * If the exclusion flag is not set, build a list of device
189 * groups that is a subset of those specified by the caller
190 */
191
192 if ((options & DTAB_EXCLUDEFLAG) == 0) {
193 while (!errorflag && (dgrp = _getdgrptabent())) {
194 if (!dgrp->comment && isincallerslist(dgrp, dgroups) &&
195 (listallflag || isindevlist(dgrp, devlist))) {
196 errorflag = !addtodgrplist(dgrp);
197 }
198 _freedgrptabent(dgrp);
199 }
200 }
201
202 /*
203 * If the exclusion flag is set, build a list of device groups
204 * that meet the criteria and are not in the list of device
205 * groups specified by the caller.
206 */
207 else {
208 while (!errorflag && (dgrp = _getdgrptabent())) {
209 if (!dgrp->comment && !isincallerslist(dgrp, dgroups) &&
210 (listallflag || isindevlist(dgrp, devlist))) {
211 errorflag = !addtodgrplist(dgrp);
212 }
213 _freedgrptabent(dgrp);
214 }
215 }
216 }
217 plist = buildreturnlist();
218 freedgrplist();
219 _enddgrptab();
220 return (plist);
221 }
222
223 /*
224 * int initdgrplist()
225 *
226 * Initializes the internal device group linked list
227 *
228 * Arguments: None
229 *
230 * Returns: void
231 */
232
233 static void
initdgrplist(void)234 initdgrplist(void)
235 {
236 /* Automatic data */
237
238 /*
239 * Initialize the structure. Dummy node points to nothing, count to
240 * zero.
241 */
242 dgrplistcount = 0;
243 dgrplistfirst.name = "";
244 dgrplistfirst.next = NULL;
245 }
246
247 /*
248 * int addtodgrplist(dgrp)
249 * struct dgrptabent *dgrp
250 *
251 * Adds the device group described by the "dgrp" structure to the
252 * internal list of device-groups we're accumulating.
253 *
254 * Arguments:
255 * dgrp Describes the device-group we're adding
256 *
257 * Returns: int
258 * TRUE if successful, FALSE otherwise
259 */
260
261 static int
addtodgrplist(struct dgrptabent * dgrp)262 addtodgrplist(struct dgrptabent *dgrp)
263 {
264 /* Automatic data */
265 struct dgrplist *newnode; /* Allocated node */
266 struct dgrplist *p; /* Running dgrp list ptr */
267 struct dgrplist *q; /* Another Running dgrp list ptr */
268 char *newstr; /* Space for the dgroup name */
269 int errorflag; /* TRUE if error */
270 int cmpval; /* Value from strcmp() */
271
272 /* No errors seen yet */
273 errorflag = FALSE;
274
275 /* Find where we're supposed to insert this item in the list */
276 q = &dgrplistfirst;
277 p = q->next;
278 while (p && ((cmpval = strcmp(p->name, dgrp->name)) < 0)) {
279 q = p;
280 p = p->next;
281 }
282
283 /* If the item isn't already in the list, insert it */
284 if ((p == NULL) || (cmpval != 0)) {
285
286 /* Allocate space for the structure */
287 newnode = malloc(sizeof (struct dgrplist));
288 if (newnode) {
289
290 /* Allocate space for the device group name */
291 if (newstr = malloc(strlen(dgrp->name)+1)) {
292
293 /* Link the new structure into the list */
294 newnode->name = strcpy(newstr, dgrp->name);
295 newnode->next = p;
296 q->next = newnode;
297 dgrplistcount++;
298 } else {
299 /* No space for the string. Clean up */
300 errorflag = TRUE;
301 free(newnode);
302 }
303 } else errorflag = TRUE;
304 }
305
306 /* Return a value that indicates whether we've had an error */
307 return (!errorflag);
308 }
309
310 /*
311 * int isindevlist(dgrp, devlist)
312 * struct dgrptabent *dgrp
313 * char **devlist
314 *
315 * This function searches the device membership list of the device
316 * group <dgrp> for any of the devices listed in the list of devices
317 * <devlist>. It returns TRUE if at least one device in <devlist> is
318 * found in <dgrp>, otherwise it returns false.
319 *
320 * Arguments:
321 * dgrp The device group to examine
322 * devlist The list of devices to search for
323 *
324 * Returns: int
325 * TRUE if one of the devices in <devlist> is a member of the device
326 * group <dgrp>, FALSE otherwise
327 */
328
329 static int
isindevlist(struct dgrptabent * dgrp,char ** devlist)330 isindevlist(
331 struct dgrptabent *dgrp, /* Dgrp to search for */
332 char **devlist) /* List of devices to search against */
333 {
334 /* Automatic data */
335 struct member *pmbr; /* Next member of the dgrp list */
336 char **pdev; /* Next device in the dev list */
337 char *mbralias; /* The alias of a group member */
338 int cmpval; /* strcmp() result */
339 int notfound; /* TRUE if no mbr of dgrp is in dev list */
340 int allocflag; /* TRUE if the mbralias string is malloc()ed */
341
342
343 /*
344 * For each device in the device group, search the alphabetically
345 * sorted list of devices for that device.
346 */
347
348 notfound = TRUE;
349 for (pmbr = dgrp->membership; notfound && pmbr; pmbr = pmbr->next) {
350
351 /*
352 * Get the member's alias (we've got it if the member is not a
353 * pathname)
354 */
355 allocflag = (*pmbr->name == '/');
356 if (allocflag)
357 mbralias = devattr(pmbr->name, DTAB_ALIAS);
358 else mbralias = pmbr->name;
359
360 /* If we've got a member alias, search the device list for it */
361 if (mbralias)
362 for (pdev = devlist; notfound && *pdev; pdev++)
363
364 if ((cmpval = strcmp(mbralias, *pdev)) == 0) notfound = FALSE;
365 else if (cmpval < 0)
366 break; /* Optimization: alpha sorted list */
367
368 /*
369 * Free the space allocated to the member alias
370 * (if it was allocated above by devattr())
371 */
372 if (allocflag) free(mbralias);
373
374 }
375
376
377 /*
378 * Return a value indicating that we the device group contains
379 * a member that is in the list of devices
380 */
381
382 return (!notfound);
383 }
384
385 /*
386 * int isincallerslist(dgrp, dgroups)
387 * struct dgrptabent *dgrp
388 * char **dgroups
389 *
390 * This function looks through the "dgroups" list for the device
391 * group described by "dgrp"
392 *
393 * Arguments:
394 * dgrp Device group to search for
395 * dgroups The address of the first item in the list of device
396 * groups to search
397 *
398 * Returns: int
399 * TRUE if found, FALSE otherwise
400 */
401
402 static int
isincallerslist(struct dgrptabent * dgrp,char ** dgroups)403 isincallerslist(
404 struct dgrptabent *dgrp, /* Dgrp to search for */
405 char **dgroups) /* Caller's list of dgroups */
406 {
407 /* Automatic data */
408 char **pdgrp;
409 int notfound;
410
411 /*
412 * Search the list of device groups for the name of the device group
413 * in the structure described by <dgrp>.
414 */
415
416 /* Initializations */
417 notfound = TRUE;
418
419 /* Search the device group list for name of this device group */
420 for (pdgrp = dgroups; notfound && *pdgrp; pdgrp++) {
421 if (strcmp(dgrp->name, *pdgrp) == 0) notfound = FALSE;
422 }
423
424 /* Return TRUE if the device group is in the list, FALSE otherwise */
425 return (!notfound);
426 }
427
428 /*
429 * char **buildreturnlist()
430 *
431 * This function builds the list of pointers to device groups
432 * to return to the caller from the linked list of device-groups
433 * we've been accumulating.
434 *
435 * Arguments: none
436 *
437 * Returns: char **
438 * A pointer to the first element in the malloc()ed list of pointers
439 * to malloc()ed character strings containing device groups which have
440 * member devices which match the criteria
441 */
442
443 static char **
buildreturnlist(void)444 buildreturnlist(void)
445 {
446 char **list; /* List being built */
447 char **pp; /* Temp ptr within list */
448 struct dgrplist *pdgrpent; /* Ptr into list of dgrps to return */
449
450 /* Allocate space for the list of pointers to device groups */
451 list = malloc((dgrplistcount+1)*sizeof (char *));
452
453 /*
454 * For each item in the device group list, put an entry in the
455 * list of names we're building
456 */
457 if ((pp = list) != NULL) {
458 for (pdgrpent = dgrplistfirst.next; pdgrpent;
459 pdgrpent = pdgrpent->next) {
460
461 *pp++ = pdgrpent->name;
462 }
463 /* The list ends with a null pointer */
464 *pp = NULL;
465 }
466
467 /* Return a pointer to the allocated list */
468 return (list);
469 }
470
471 /*
472 * void freedgrplist()
473 *
474 * This function frees the resources allocated to the internal
475 * linked list of device groups
476 *
477 * Arguments: none
478 *
479 * Returns: void
480 */
481
482 static void
freedgrplist(void)483 freedgrplist(void)
484 {
485 struct dgrplist *pdgrpent; /* Dgrp to free */
486 struct dgrplist *nextnode; /* Next one to free */
487
488 for (pdgrpent = dgrplistfirst.next; pdgrpent; pdgrpent = nextnode) {
489 nextnode = pdgrpent->next;
490 free(pdgrpent);
491 }
492 }
493