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