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