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