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