xref: /illumos-gate/usr/src/lib/libadm/common/getdgrp.c (revision 86d949f9497332fe19be6b5d711d265eb957439f)
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 **
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
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
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
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
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 **
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
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