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