xref: /illumos-gate/usr/src/lib/libadm/common/dgrpent.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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,1998,2002 by Sun Microsystems, Inc.
28  * All rights reserved.
29  */
30 
31 /*LINTLIBRARY*/
32 
33 /*
34  * dgrpent.c
35  *
36  *  Contains functions that deal with the device-group table and are not for
37  *  consumption by the general user population.
38  *
39  *  Functions defined:
40  *	_opendgrptab()		Opens the device-group table for commands
41  *	_setdgrptab()		Rewinds the open device table
42  *	_enddgrptab()		Closes the open device table
43  *	_getdgrptabent()	Gets the next entry in the device table
44  *	_freedgrptabent()	Frees memory allocated to a device-table entry
45  *	_getdgrprec()		Gets a specific record from the device table
46  *	_dgrptabpath()		Gets the pathname of the device group file
47  */
48 
49 /*
50  *  Header files
51  *	<sys/types.h>	System data types
52  *	<unistd.h>	Standard UNIX(r) definitions
53  *	<stdio.h>	Standard I/O Definitions
54  *	<string.h>	String handling definitions
55  *	<ctype.h>	Character types and macros
56  *	<errno.h>	Errorcode definitions
57  *	<sys/stat.h>	File status information
58  *	<devmgmt.h>	Global Device Management definitions
59  *	"devtab.h"	Local device table definitions
60  */
61 
62 #include	<sys/types.h>
63 #include	<unistd.h>
64 #include	<stdio.h>
65 #include	<string.h>
66 #include	<ctype.h>
67 #include	<errno.h>
68 #include	<sys/stat.h>
69 #include	<devmgmt.h>
70 #include	"devtab.h"
71 #include	<stdlib.h>
72 
73 /*
74  *  Local definitions
75  */
76 
77 
78 /*
79  *  Static data definitions:
80  *	leftoff		Addr of char to begin next parse using
81  *			getfld(), getattrval(), getquoted()
82  *	recbufsz	The size of the buffer used for reading records
83  *	recbuf		Addr of malloc() buffer for reading records
84  *	recnum		Record number of next record to read
85  *	xtndcnt		Number of times the buffer has been extended
86  */
87 
88 static	char		*leftoff = NULL;
89 static	int		recbufsz = 0;
90 static	char		*recbuf = NULL;
91 static	int		recnum = 0;
92 static	int		xtndcnt = 0;
93 
94 /*
95  *  void _setdgrptab()
96  *
97  *	This function rewinds the open device table so that the next
98  *	_getdgrptabent() returns the first record in the device table.
99  *
100  *  Arguments:  None
101  *
102  *  Returns:  Void
103  */
104 
105 void
_setdgrptab(void)106 _setdgrptab(void)
107 {
108 	/*  If the device table file is open, rewind the file  */
109 	if (oam_dgroup) {
110 	    rewind(oam_dgroup);
111 	    recnum = 0;
112 	}
113 }
114 
115 /*
116  *  void _enddgrptab()
117  *
118  *	This function closes the open device table.  It resets the
119  *	open device table external variable to NULL.
120  *
121  *  Arguments:  None
122  *
123  *  Returns:  Void
124  */
125 
126 void
_enddgrptab(void)127 _enddgrptab(void)
128 {
129 	/*  If the device table file is open, close it  */
130 	if (oam_dgroup) {
131 	    (void) fclose(oam_dgroup);
132 	    recnum = 0;
133 	    oam_dgroup = NULL;
134 	}
135 }
136 
137 /*
138  *  char *getfld(ptr, delims)
139  *	char   *ptr
140  *	char   *delims
141  *
142  *  Notes:
143  *    -	Can't use "strtok()" because of its use of static data.  The caller
144  *	may be using strtok() and we'll really mess them up.
145  *    - The function returns NULL if it didn't find any token -- '\0' can't
146  *	be a delimiter using this algorithm.
147  */
148 
149 static char *
getfld(char * ptr,char * delims)150 getfld(
151 	char   *ptr,		/* String to parse */
152 	char   *delims)		/* List of delimiters */
153 {
154 	char   *p, *q;
155 
156 	/*
157 	 *  Figure out where to start.
158 	 *  If given a pointer, use that.
159 	 *  Otherwise, use where we left off.
160 	 */
161 
162 	p = ptr ? ptr : leftoff;
163 
164 
165 	/*
166 	 *  If there's anything to parse, search the string for the first
167 	 *  occurrence of any of the delimiters.  If one is found, change it
168 	 *  to '\0' and remember the place to start for next time.  If not
169 	 *  found, forget the restart address and prepare to return NULL
170 	 */
171 
172 	if (p) {
173 	    while (*p && isspace((unsigned char)*p)) p++;
174 	    if (*p) {
175 		q = p;
176 		while (*q && !strchr(delims, *q)) q++;
177 		if (*q) {
178 		    *q++ = '\0';
179 		    leftoff = q;
180 		} else leftoff = NULL;
181 	    } else leftoff = p = NULL;
182 	}
183 
184 	/*  Finished  */
185 	return (p);
186 }
187 
188 /*
189  *  char *getnextrec()
190  *
191  *	This function gets the next record from the input stream "oam_dgroup"
192  *	and puts it in the device-group table record buffer (whose address is
193  *	in "recbuf").  If the buffer is not allocated or is too small to
194  *	accommodate the record, the function allocates more space to the
195  *	buffer.
196  *
197  *  Arguments:  None
198  *
199  *  Returns:  char *
200  *	The address of the buffer containing the record.
201  *
202  *  Static Data Referenced:
203  *	recbuf		Address of the buffer containing records read from the
204  *			device table file
205  *	recbufsz	Current size of the record buffer
206  *	xtndcnt		Number of times the record buffer has been extended
207  *	oam_dgroup	Device-group table stream, expected to be open for (at
208  *			least) reading
209  *
210  *  Notes:
211  *    - The string returned in the buffer <buf> ALWAYS end in a '\n' (newline)
212  *	character followed by a '\0' (null).
213  */
214 
215 static char *
getnextrec(void)216 getnextrec(void)
217 {
218 	/* Automatic data */
219 	char		*recp;		/* Value to return */
220 	char		*p;		/* Temp pointer */
221 	int		done;		/* TRUE if we're finished */
222 	int		reclen;		/* Number of chars in record */
223 
224 
225 	/* If there's no buffer for records, try to get one */
226 	if (!recbuf) {
227 	    if (recbuf = malloc(DGRP_BUFSIZ)) {
228 		recbufsz = DGRP_BUFSIZ;
229 		xtndcnt = 0;
230 	    } else return (NULL);
231 	}
232 
233 
234 	/* Get the next record */
235 	recp = fgets(recbuf, recbufsz, oam_dgroup);
236 	done = FALSE;
237 
238 	/* While we've something to return and we're not finished ... */
239 	while (recp && !done) {
240 
241 	    /* If our return string isn't a null-string ... */
242 	    if ((reclen = (int)strlen(recp)) != 0) {
243 
244 		/* If we have a complete record, we're finished */
245 		if (*(recp+reclen-1) == '\n') done = TRUE;
246 		else while (!done) {
247 
248 		/*
249 		 * Need to complete the record.  A complete record is one
250 		 * which is terminated by a new-line character
251 		 */
252 
253 		    /* If the buffer is full, expand it and continue reading */
254 		    if (reclen == recbufsz-1) {
255 
256 			/* Have we reached our maximum extension count? */
257 			if (xtndcnt < XTND_MAXCNT) {
258 
259 			    /* Expand the record buffer */
260 			    if (p = realloc(recbuf,
261 				(size_t)(recbufsz+DGRP_BUFINC))) {
262 
263 				/* Update buffer information */
264 				xtndcnt++;
265 				recbuf = p;
266 				recbufsz += DGRP_BUFINC;
267 
268 			    } else {
269 
270 				/* Expansion failed */
271 				recp = NULL;
272 				done = TRUE;
273 			    }
274 
275 			} else {
276 
277 			    /* Maximum extend count exceeded.  Insane table */
278 			    recp = NULL;
279 			    done = TRUE;
280 			}
281 
282 		    }
283 
284 		    /* Complete the record */
285 		    if (!done) {
286 
287 			/* Read stuff into the expanded space */
288 			if (fgets(recbuf+reclen, recbufsz-reclen, oam_dgroup)) {
289 			    reclen = (int)strlen(recbuf);
290 			    recp = recbuf;
291 			    if (*(recp+reclen-1) == '\n') done = TRUE;
292 			} else {
293 			    /* Read failed, corrupt record? */
294 			    recp = NULL;
295 			    done = TRUE;
296 			}
297 		    }
298 
299 		}   /* End incomplete record handling */
300 
301 	    } else {
302 
303 		/* Read a null string?  (corrupt table) */
304 		recp = NULL;
305 		done = TRUE;
306 	    }
307 
308 	}   /* while (recp && !done) */
309 
310 	/* Return what we've got (if anything) */
311 	return (recp);
312 }
313 
314 /*
315  *  char *_dgrptabpath()
316  *
317  *	Get the pathname of the device-group table file
318  *
319  *  Arguments:  None
320  *
321  *  Returns:  char *
322  *	Returns the pathname to the device group table of (char *) NULL if
323  *	there was a problem getting the memory needed to contain the
324  *	pathname.
325  *
326  *  Algorithm:
327  *	1.  If OAM_DGRP is defined in the environment and is not
328  *	    defined as "", it returns the value of that environment
329  *	    variable.
330  *	2.  Otherwise, use the devault pathname (as defined by the
331  *	    environment variable DGRP_PATH in <devmgmt.h>.
332  */
333 
334 
335 char *
_dgrptabpath(void)336 _dgrptabpath(void)
337 {
338 
339 	/* Automatic data */
340 #ifdef	DEBUG
341 	char		*path;		/* Ptr to path in environment */
342 #endif
343 	char		*rtnval;		/* Ptr to value to return */
344 
345 
346 	/*
347 	 * If compiled with -DDEBUG=1,
348 	 * look for the pathname in the environment
349 	 */
350 
351 #ifdef	DEBUG
352 	if (((path = getenv(OAM_DGROUP)) != NULL) && (*path)) {
353 	    if (rtnval = malloc(strlen(path)+1))
354 		(void) strcpy(rtnval, path);
355 	} else {
356 #endif
357 	/*
358 	 * Use the default name.
359 	 */
360 
361 	    if (rtnval = malloc(strlen(DGRP_PATH)+1))
362 		(void) strcpy(rtnval, DGRP_PATH);
363 
364 #ifdef	DEBUG
365 	}
366 #endif
367 
368 	/* Finished */
369 	return (rtnval);
370 }
371 
372 /*
373  *  int _opendgrptab(mode)
374  *	char   *mode
375  *
376  *	The _opendgrptab() function opens a device-group table for a command.
377  *
378  *  Arguments:
379  *	mode	The open mode to use to open the file.  (i.e. "r" for
380  *		reading, "w" for writing.  See FOPEN(BA_OS) in SVID.)
381  *
382  *  Returns:  int
383  *	TRUE if successful, FALSE otherwise
384  */
385 
386 int
_opendgrptab(char * mode)387 _opendgrptab(char *mode)
388 {
389 	/* Automatic data */
390 	char   *dgrptabname;	/* Ptr to the device-group table name */
391 	int	rtnval;		/* Value to return */
392 
393 	rtnval = TRUE;
394 	if (dgrptabname = _dgrptabpath()) {
395 	    if (oam_dgroup) (void) fclose(oam_dgroup);
396 	    if (oam_dgroup = fopen(dgrptabname, mode)) {
397 		xtndcnt = 0;
398 		recnum = 0;
399 	    } else rtnval = FALSE;  /* :-( */
400 	} else rtnval = FALSE;    /* :-( */
401 	return (rtnval);
402 }
403 
404 /*
405  *  struct dgrptabent *_getdgrptabent()
406  *
407  *  	This function returns the next entry in the device-group table.
408  *	If no device-group table is open, it opens the standard device-group
409  *      table and returns the first record in the table.
410  *
411  *  Arguments:  None.
412  *
413  *  Returns:  struct dgrptabent *
414  *	Pointer to the next record in the device-group table, or
415  *	(struct dgrptabent *) NULL if it was unable to open the file or there
416  *	are no more records to read.  "errno" reflects the situation.  If
417  *	errno is not changed and the function returns NULL, there are no more
418  *	records to read.  If errno is set, it indicates the error.
419  *
420  *  Notes:
421  *    - The caller should set "errno" to 0 before calling this function.
422  */
423 
424 struct dgrptabent *
_getdgrptabent(void)425 _getdgrptabent(void)
426 {
427 	/*  Automatic data  */
428 	struct dgrptabent	*ent;		/* Dev table entry structure */
429 	struct member		*q, *r;		/* Tmps for member structs */
430 	char			*record;		/* Record just read */
431 	char			*p;		/* Tmp char ptr */
432 	int			done;		/* TRUE if built an entry */
433 
434 
435 	/*  Open the device-group table if it's not already open */
436 	if (!oam_dgroup)
437 	    if (!_opendgrptab("r"))
438 		return (NULL);
439 
440 
441 	/*  Get space for the structure we're returning  */
442 	if (!(ent = malloc(sizeof (struct dgrptabent)))) {
443 	    return (NULL);
444 	}
445 
446 	done = FALSE;
447 	while (!done && (record = getnextrec())) {
448 
449 	    /* Is this a comment record or a data record */
450 	    if (strchr("#\n", *record) ||
451 			isspace((unsigned char)*record)) {
452 
453 		/*
454 		 *  Record is a comment record
455 		 */
456 		ent->comment = TRUE;
457 		ent->entryno = recnum++;
458 
459 		/* Alloc space for the comment and save pointer in struct */
460 		if (ent->dataspace = malloc(strlen(record)+1)) {
461 		    (void) strcpy(ent->dataspace, record);
462 		} else {
463 		    free(ent);
464 		    ent = NULL;
465 		}
466 		done = TRUE;
467 
468 	    } else {
469 
470 		/*
471 		 *  Record is a data record
472 		 */
473 		ent->comment = FALSE;
474 
475 		/* Extract the device-group name */
476 		if (p = getfld(record, ":")) {
477 
478 		/* Record is a proper record */
479 		    done = TRUE;
480 		    ent->entryno = recnum++;
481 
482 		    /* Copy device group name into malloc()ed space */
483 		    if (!(ent->name = malloc(strlen(p)+1))) {
484 
485 			free(ent);
486 			return (NULL);
487 		    }
488 		    (void) strcpy(ent->name, p);
489 
490 			/*
491 			 * Extract the membership from the membership list
492 			 */
493 
494 		    /* Get the 1st member */
495 		    ent->dataspace = NULL;
496 		    while (((p = getfld(NULL, ",\n")) != NULL) && !(*p))
497 			;
498 		    if (p) {
499 			if (!(q = malloc(sizeof (struct member)))) {
500 
501 			    free(ent->name);
502 			    free(ent);
503 			    return (NULL);
504 			}
505 			if (!(q->name = malloc(strlen(p)+1))) {
506 			    free(q);
507 			    free(ent->name);
508 			    free((char *)ent);
509 			    return (NULL);
510 			}
511 			(void) strcpy(q->name, p);
512 			ent->membership = q;
513 			q->next = NULL;
514 
515 			/* Get the rest of the members */
516 			while (p = getfld(NULL, ",\n"))
517 			    if (*p) {
518 				if (!(r = malloc(sizeof (struct member)))) {
519 				    for (q = ent->membership; q; q = r) {
520 					free(q->name);
521 					r = q->next;
522 					free(q);
523 				    }
524 				    free(ent->name);
525 				    free(ent);
526 				    return (NULL);
527 				}
528 				if (!(r->name = malloc(strlen(p)+1))) {
529 				    free(r);
530 				    for (q = ent->membership; q; q = r) {
531 					free(q->name);
532 					r = q->next;
533 					free(q);
534 				    }
535 				    free(ent->name);
536 				    free(ent);
537 				    return (NULL);
538 				}
539 
540 				q->next = r;
541 				(void) strcpy(r->name, p);
542 				r->next = NULL;
543 				q = r;
544 			    }
545 
546 		    } else {
547 			/* No members */
548 			ent->membership = NULL;
549 		    }
550 
551 		}   /* record contains a group name */
552 
553 	    }   /* record is a data record */
554 
555 	}   /* while (!done && there's more records) */
556 
557 
558 	/*  An entry read?  If not, free alloc'd space and return NULL */
559 	if (!done) {
560 	    free(ent);
561 	    ent = NULL;
562 	}
563 
564 	/* Finis */
565 	return (ent);
566 }
567 
568 /*
569  *  void _freedgrptabent(dgrptabent)
570  *	struct dgrptabent       *dgrptabent;
571  *
572  *	This function frees space allocated to a device table entry.
573  *
574  *  Arguments:
575  *	struct dgrptabent *dgrptabent	The structure whose space is to be
576  *					freed.
577  *
578  *  Returns:  void
579  */
580 
581 void
_freedgrptabent(struct dgrptabent * ent)582 _freedgrptabent(struct dgrptabent *ent)	/* Structure to free */
583 {
584 	/*
585 	 * Automatic data
586 	 */
587 
588 	struct member  *p;		/* Structure being freed */
589 	struct member  *q;		/* Next structure to free */
590 
591 	/*
592 	 *  Free the space allocated to the membership structure.
593 	 */
594 
595 	if (!ent->comment) {
596 	    if ((q = ent->membership) != NULL) do {
597 		p = q;
598 		q = p->next;
599 		if (p->name) free(p->name);
600 		free(p);
601 	    } while (q);
602 
603 	    /* Free the device group name */
604 	    if (ent->name) free(ent->name);
605 	}
606 
607 	/* Free the membership string */
608 	if (ent->dataspace) free(ent->dataspace);
609 }
610 
611 /*
612  *  struct dgrptabent *_getdgrprec(dgroup)
613  *	char *dgroup
614  *
615  *	Thie _getdgrprec() function returns a pointer to a structure that
616  *	contains the information in the device-group table entry that describes
617  *	the device-group <dgroup>.
618  *
619  *  Arguments:
620  *	char *dgroup	A character-string describing the device-group whose
621  *			record is to be retrieved from the device-group table.
622  *
623  *  Returns:  struct dgrptabent *
624  *	A pointer to a structure describing the device group.
625  */
626 
627 struct dgrptabent *
_getdgrprec(char * dgroup)628 _getdgrprec(char *dgroup)		/* dgroup to search for */
629 {
630 	/*
631 	 *  Automatic data
632 	 */
633 
634 	struct dgrptabent	*dgrprec;	/* Pointer to current record */
635 	int			found;		/* FLAG, TRUE if found */
636 
637 
638 	/*
639 	 *  Search the device-group table looking for the requested
640 	 *  device group
641 	 */
642 
643 	_setdgrptab();
644 	errno = 0;
645 	found = FALSE;
646 	while (!found && (dgrprec = _getdgrptabent())) {
647 	    if (!dgrprec->comment && strcmp(dgroup, dgrprec->name) == 0)
648 		found = TRUE;
649 	    else _freedgrptabent(dgrprec);
650 	}
651 
652 	/*  Set up return codes if we've failed  */
653 	if (!found) {
654 	    if (errno == 0) errno = EINVAL;
655 	    dgrprec = NULL;
656 	}
657 
658 	/*  Finis  */
659 	return (dgrprec);
660 }
661