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 /*
23 * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
24 * All Rights reserved.
25 */
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*LINTLIBRARY*/
30
31 /*
32 * devtab.c
33 *
34 * Contains functions that deal with the device table and are not for
35 * consumption by the general user population.
36 *
37 * Functions defined:
38 * _opendevtab() Opens the device table for commands
39 * _setdevtab() Rewinds the open device table
40 * _enddevtab() Closes the open device table
41 * _getdevtabent() Gets the next entry in the device table
42 * _freedevtabent() Frees memory allocated to a device-table entry
43 * _getdevrec() Gets a specific record from the device table
44 * _devtabpath() Get the pathname of the device table file
45 * _validalias() Is a value a valid alias?
46 */
47
48 /*
49 * Header files
50 *
51 * <sys/sysmacros.h> System macro definitions
52 * <sys/types.h> System data types
53 * <sys/mkdev.h> Device Macros
54 * <unistd.h> System Symbolic Constants
55 * <stdio.h> Standard I/O definitions
56 * <string.h> String handling definitions
57 * <ctype.h> Character types and macros
58 * <errno.h> Error codes
59 * <sys/stat.h> File status information
60 * <devmgmt.h> Global Device Management definitions
61 * "devtab.h" Local Device Management definitions
62 */
63
64 #include <sys/sysmacros.h>
65 #include <sys/types.h>
66 #ifndef SUNOS41
67 #include <sys/mkdev.h>
68 #endif
69 #include <unistd.h>
70 #include <stdio.h>
71 #include <string.h>
72 #include <ctype.h>
73 #include <errno.h>
74 #include <sys/stat.h>
75 #include <devmgmt.h>
76 #include "devtab.h"
77 #include <stdlib.h>
78
79 /*
80 * Static data definitions:
81 * dtabrecnum Record number of the current record (0 to n-1)
82 * leftoff Addr of char to begin next parse using
83 * getfld(), getattrval(), getquoted()
84 * recbufsz The size of the buffer used for reading records
85 * recbuf Addr of malloc() buffer for reading records
86 * xtndcnt Number of malloc()/realloc() calls on record buffer
87 */
88
89 static int xtndcnt = 0;
90 static char *recbuf = NULL;
91 static int recbufsz = 0;
92
93 static char *leftoff = NULL;
94 static int dtabrecnum = 0;
95
96 /*
97 * int samedev(x, y)
98 * struct stat x, y
99 *
100 * Compares pertinent information in a stat() structure
101 * to see if the two structures describe the same device.
102 * If the file modes are the same and they have the same
103 * file system and i-node (i.e. they're links) or they
104 * are block or character devices and have the same major
105 * and minor device numbers (i.e. "mknod"s for the same
106 * device), it's the same device.
107 *
108 * Returns: int
109 * TRUE if the two structures describe the same device
110 * FALSE otherwise
111 */
112
113 static int
samedev(struct stat64 x,struct stat64 y)114 samedev(struct stat64 x, struct stat64 y)
115 {
116 int same;
117
118
119 /* If the devices are of the same type ... */
120 if ((x.st_mode & 0170000) == (y.st_mode & 0170000)) {
121
122 /*
123 * If they are described by the same inode on the same device,
124 * the two devices are the same. Otherwise, if the devices are
125 * character-special or block-special devices, try to match by
126 * device type and major and minor device numbers.
127 */
128
129 if ((x.st_dev == y.st_dev) && (x.st_ino == y.st_ino)) same = TRUE;
130 else
131 if (((x.st_mode & 0170000) == 0020000) ||
132 ((x.st_mode & 0170000) == 0060000)) {
133 if ((major(x.st_rdev) == major(y.st_rdev)) &&
134 (minor(x.st_rdev) == minor(y.st_rdev))) same = TRUE;
135 else same = FALSE;
136 } else same = FALSE;
137
138 } else same = FALSE;
139
140 return (same);
141 }
142
143 /*
144 * void _setdevtab()
145 *
146 * This function rewinds the open device table so that the next
147 * _getdevtabent() returns the first record in the device table.
148 *
149 * Arguments: None
150 *
151 * Returns: Void
152 */
153
154 void
_setdevtab(void)155 _setdevtab(void)
156 {
157 /* If the device table file is open, rewind the file */
158 if (oam_devtab != NULL) {
159 rewind(oam_devtab);
160 dtabrecnum = 0;
161 }
162 }
163
164 /*
165 * void _enddevtab()
166 *
167 * This function closes the open device table. It resets the
168 * open device table external variable to NULL.
169 *
170 * Arguments: None
171 *
172 * Returns: Void
173 */
174
175 void
_enddevtab(void)176 _enddevtab(void)
177 {
178 /* If the device table file is open, close it */
179 if (oam_devtab != NULL) {
180 (void) fclose(oam_devtab);
181 oam_devtab = NULL;
182 dtabrecnum = 0;
183 }
184 }
185
186 /*
187 * char *getfld(ptr, delims)
188 * char *ptr
189 * char *delims
190 *
191 * Notes:
192 * - Can't use "strtok()" because of its use of static data. The caller
193 * may be using strtok() and we'll really mess them up.
194 * - The function returns NULL if it didn't find any token -- '\0' can't
195 * be a delimiter using this algorithm.
196 */
197
198 static char *
getfld(char * ptr,char * delims)199 getfld(
200 char *ptr, /* String to parse */
201 char *delims) /* List of delimiters */
202 {
203 int done; /* TRUE if we're finished */
204 char *p, *q; /* Temp pointers */
205
206 /*
207 * Figure out where to start.
208 * If given a pointer, use that.
209 * Otherwise, use where we left off.
210 */
211
212 p = ptr ? ptr : leftoff;
213
214
215 /*
216 * If there's anything to parse, search the string for the first
217 * occurrence of any of the delimiters. If one is found, change it
218 * to '\0' and remember the place to start for next time. If not
219 * found, forget the restart address and prepare to return NULL.
220 * Don't terminate on "escaped" characters.
221 */
222
223 if (p) { /* Anything to do ?? */
224 q = p; /* Where to begin */
225 done = FALSE; /* We're not done yet */
226 while (*q && !done) { /* Any more chars */
227 if (*q == '\\') { /* Escaped ? */
228 if (*(++q)) q++; /* Skip escaped char */
229 } else /* Not escaped */
230 if (!strchr(delims, *q)) q++; /* Skip non-delim */
231 else done = TRUE; /* Otherwise, done */
232 }
233 if (*q) { /* Terminator found? */
234 *q++ = '\0'; /* Null-terminate token */
235 leftoff = q; /* Remember restart pt. */
236 } else
237 leftoff = p = NULL; /* Nothin found or left */
238 }
239
240 /* Finished */
241 return (p); /* Return ptr to token */
242 }
243
244 /*
245 * char *getquoted(ptr)
246 * char *ptr;
247 *
248 * This function extracts a quoted string from the string pointed
249 * to by <ptr>, or, if <ptr> is NULL, wherever we left off
250 * last time.
251 *
252 * Arguments:
253 * char *ptr Pointer to the character-string to parse, or
254 * (char *) NULL if we're to pick up where we
255 * [getquoted(), getfld(), and getattrval()] left off.
256 *
257 * Returns: char *
258 * The address of malloc()ed space that contains the possibly quoted
259 * string.
260 *
261 * Notes:
262 * - This code only works if it can assume that the last character in
263 * the string it's parsing is a '\n', something that is guarenteed
264 * by the getnextrec() function.
265 */
266
267 static char *
getquoted(char * ptr)268 getquoted(char *ptr)
269 {
270 /* Automatic data */
271 char *rtn; /* Value to return */
272 char *p, *q; /* Temps */
273
274 /* Figure out where to start off */
275 p = ptr ? ptr : leftoff;
276
277 /* If there's anything to parse and it's a quoted string ... */
278 if ((p) && (*p == '"') && (p = getfld(p+1, "\""))) {
279
280 /* Copy string for the caller */
281 if (rtn = malloc(strlen(p)+1)) { /* Malloc() space */
282 q = rtn; /* Set up temp ptr */
283 do {
284 if (*p == '\\') p++; /* Skip escape */
285 *q++ = *p; /* Copy char */
286 } while (*p++); /* While there's chars */
287 } else leftoff = rtn = NULL;
288 } else leftoff = rtn = NULL;
289
290 /* Fini */
291 return (rtn);
292 }
293
294 /*
295 * struct attrval *getattrval(ptr)
296 * char *ptr
297 *
298 * This function extracts the next attr=val pair from <ptr> or wherever
299 * getfld() left off...
300 *
301 * Arguments:
302 * char *ptr The string to parse, or (char *) NULL if we're to
303 * begin wherever we left off last time.
304 *
305 * Returns: struct attrval *
306 * The address of a malloc()ed structure containing the attribute and the
307 * value of the attr=val pair extracted.
308 */
309
310 static struct attrval *
getattrval(char * ptr)311 getattrval(char *ptr)
312 {
313 /* Automatic data */
314 struct attrval *rtn; /* Ptr to struct to return */
315 char *p, *q; /* Temp pointers */
316
317
318 /* Use what's given to us or wherever we left off */
319 p = ptr ? ptr : leftoff;
320
321 /* If there's anything to parse, extract the next attr=val pair */
322 if (p) {
323
324 /* Eat white space */
325 while (*p && isspace((unsigned char)*p)) p++;
326
327 /* Extract the attribute name, if any */
328 if (*p && getfld(p, "=")) {
329
330 /* Allocate space for the structure we're building */
331 if (rtn = malloc(sizeof (struct attrval))) {
332
333 /* Allocate space for the attribute name */
334 if (rtn->attr = malloc(strlen(p)+1)) {
335
336 /* Copy the attribute name into alloc'd space */
337 q = rtn->attr; /* Set up temp ptr */
338 do {
339 if (*p == '\\') p++; /* Skip escape */
340 *q++ = *p; /* Copy char */
341 } while (*p++); /* While more */
342
343 /* Extract the value */
344 if (!(rtn->val = getquoted(NULL))) {
345 /* Error getting value, free resources */
346 free(rtn->attr);
347 free(rtn);
348 leftoff = NULL;
349 rtn = NULL;
350 }
351 } else {
352 /* Error getting space for attribute, free resources */
353 free(rtn);
354 leftoff = NULL;
355 rtn = NULL;
356 }
357
358 } else {
359 /* No space for attr struct */
360 leftoff = NULL;
361 rtn = NULL;
362 }
363
364 } else {
365 /* No attribute name */
366 leftoff = NULL;
367 rtn = NULL;
368 }
369
370 } else {
371 /* Nothing to parse */
372 leftoff = NULL;
373 rtn = NULL;
374 }
375
376 /* Done */
377 return (rtn);
378 }
379
380 /*
381 * char *getnextrec()
382 *
383 * This function gets the next record from the input stream "oam_devtab"
384 * and puts it in the device-table record buffer (whose address is in
385 * "recbuf"). If the buffer is not allocated or is too small to
386 * accommodate the record, the function allocates more space to the
387 * buffer.
388 *
389 * Arguments: None
390 *
391 * Returns: char *
392 * The address of the buffer containing the record.
393 *
394 * Static Data Referenced:
395 * recbuf Address of the buffer containing records read from the
396 * device table file
397 * recbufsz Current size of the record buffer
398 * xtndcnt Number of times the record buffer has been extended
399 * oam_devtab Device table stream, expected to be open for (at
400 * least) reading
401 *
402 * Notes:
403 * - The string returned in the buffer <buf> ALWAYS end in a '\n' (newline)
404 * character followed by a '\0' (null).
405 */
406
407 static char *
getnextrec(void)408 getnextrec(void)
409 {
410 /* Automatic data */
411 char *recp; /* Value to return */
412 char *p; /* Temp pointer */
413 int done; /* TRUE if we're finished */
414 int reclen; /* Number of chars in record */
415
416
417 /* If there's no buffer for records, try to get one */
418 if (!recbuf) {
419 if (recbuf = malloc(DTAB_BUFSIZ)) {
420 recbufsz = DTAB_BUFSIZ;
421 xtndcnt = 0;
422 } else return (NULL);
423 }
424
425
426 /* Get the next record */
427 recp = fgets(recbuf, recbufsz, oam_devtab);
428 done = FALSE;
429
430 /* While we've something to return and we're not finished ... */
431 while (recp && !done) {
432
433 /* If our return string isn't a null-string ... */
434 if ((reclen = (int)strlen(recp)) != 0) {
435
436 /* If we have a complete record, we're finished */
437 if ((*(recp+reclen-1) == '\n') &&
438 ((reclen == 1) || (*(recp+reclen-2) != '\\'))) done = TRUE;
439 else while (!done) {
440
441 /*
442 * Need to complete the record. A complete record is
443 * one which is terminated by an unescaped new-line
444 * character.
445 */
446
447 /* If the buffer is full, expand it and continue reading */
448 if (reclen == recbufsz-1) {
449
450 /* Have we reached our maximum extension count? */
451 if (xtndcnt < XTND_MAXCNT) {
452
453 /* Expand the record buffer */
454 if (p = realloc(recbuf,
455 (size_t)recbufsz+DTAB_BUFINC)) {
456
457 /* Update buffer information */
458 xtndcnt++;
459 recbuf = p;
460 recbufsz += DTAB_BUFINC;
461
462 } else {
463
464 /* Expansion failed */
465 recp = NULL;
466 done = TRUE;
467 }
468
469 } else {
470
471 /* Maximum extend count exceeded. Insane table */
472 recp = NULL;
473 done = TRUE;
474 }
475
476 }
477
478 /* Complete the record */
479 if (!done) {
480
481 /* Read stuff into the expanded space */
482 if (fgets(recbuf+reclen, recbufsz-reclen, oam_devtab)) {
483 reclen = (int)strlen(recbuf);
484 recp = recbuf;
485 if ((*(recp+reclen-1) == '\n') &&
486 ((reclen == 1) || (*(recp+reclen-2) != '\\')))
487 done = TRUE;
488 } else {
489 /* Read failed, corrupt record? */
490 recp = NULL;
491 done = TRUE;
492 }
493 }
494
495 } /* End incomplete record handling */
496
497 } else {
498
499 /* Read a null string? (corrupt table) */
500 recp = NULL;
501 done = TRUE;
502 }
503
504 } /* while (recp && !done) */
505
506 /* Return what we've got (if anything) */
507 return (recp);
508 }
509
510 /*
511 * char *_devtabpath()
512 *
513 * Get the pathname of the device table
514 *
515 * Arguments: None
516 *
517 * Returns: char *
518 * Returns the pathname to the device table of NULL if
519 * there was a problem getting the memory needed to contain the
520 * pathname.
521 *
522 * Algorithm:
523 * 1. If OAM_DEVTAB is defined in the environment and is not
524 * defined as "", it returns the value of that environment
525 * variable.
526 * 2. Otherwise, use the value of the environment variable DTAB_PATH.
527 */
528
529
530 char *
_devtabpath(void)531 _devtabpath(void)
532 {
533
534 /* Automatic data */
535 #ifdef DEBUG
536 char *path; /* Ptr to path in environment */
537 #endif
538 char *rtnval; /* Ptr to value to return */
539
540
541 /*
542 * If compiled with -DDEBUG=1,
543 * look for the pathname in the environment
544 */
545
546 #ifdef DEBUG
547 if (((path = getenv(OAM_DEVTAB)) != NULL) && (*path)) {
548 if (rtnval = malloc(strlen(path)+1))
549 (void) strcpy(rtnval, path);
550 } else {
551 #endif
552 /*
553 * Use the standard device table.
554 */
555
556 if (rtnval = malloc(strlen(DTAB_PATH)+1))
557 (void) strcpy(rtnval, DTAB_PATH);
558
559 #ifdef DEBUG
560 }
561 #endif
562
563 /* Finished */
564 return (rtnval);
565 }
566
567 /*
568 * int _opendevtab(mode)
569 * char *mode
570 *
571 * The _opendevtab() function opens a device table for a command.
572 *
573 * Arguments:
574 * mode The open mode to use to open the file. (i.e. "r" for
575 * reading, "w" for writing. See FOPEN(BA_OS) in SVID.)
576 *
577 * Returns: int
578 * TRUE if it successfully opens the device table file, FALSE otherwise
579 */
580
581 int
_opendevtab(char * mode)582 _opendevtab(char *mode)
583 {
584 /*
585 * Automatic data
586 */
587
588 char *devtabname; /* Ptr to the device table name */
589 int rtnval; /* Value to return */
590
591
592 rtnval = TRUE;
593 if (devtabname = _devtabpath()) {
594 if (oam_devtab) (void) fclose(oam_devtab);
595 if (oam_devtab = fopen(devtabname, mode))
596 dtabrecnum = 0; /* :-) */
597 else rtnval = FALSE; /* :-( */
598 } else rtnval = FALSE; /* :-( */
599 return (rtnval);
600 }
601
602 /*
603 * int _validalias(alias)
604 * char *alias
605 *
606 * Determine if <alias> is a valid alias. Returns TRUE if it is
607 * a valid alias, FALSE otherwise.
608 *
609 * Arguments:
610 * alias Value to check out
611 *
612 * Returns: int
613 * TRUE if <alias> is a valid alias, FALSE otherwise.
614 */
615
616 int
_validalias(char * alias)617 _validalias(char *alias) /* Alias to validate */
618 {
619 /* Automatic data */
620 char *p; /* Temp pointer */
621 size_t len; /* Length of <alias> */
622 int rtn; /* Value to return */
623
624
625 /* Assume the worst */
626 rtn = FALSE;
627
628 /*
629 * A valid alias contains 0 < i <= 14 characters. The first
630 * must be alphanumeric or "@$_." and the rest must be alphanumeric
631 * or "@#$_+-."
632 */
633
634 /* Check length */
635 if ((alias != NULL) && ((len = strlen(alias)) > 0) && (len <= 14)) {
636
637 /* Check the first character */
638 p = alias;
639 if (isalnum((unsigned char)*p) || strchr("@$_.", *p)) {
640
641 /* Check the rest of the characters */
642 for (p++; *p && (isalnum((unsigned char)*p) ||
643 strchr("@#$_-+.", *p)); p++)
644 ;
645 if (!(*p)) rtn = TRUE;
646 }
647 }
648
649 /* Return indicator... */
650 return (rtn);
651
652 } /* int _validalias() */
653
654 /*
655 * struct devtabent *_getdevtabent()
656 *
657 * This function returns the next entry in the device table.
658 * If no device table is open, it opens the standard device table
659 * and returns the first record in the table.
660 *
661 * Arguments: None.
662 *
663 * Returns: struct devtabent *
664 * Pointer to the next record in the device table, or
665 * (struct devtabent *) NULL if it was unable to open the file or there
666 * are no more records to read. "errno" reflects the situation. If
667 * errno is not changed and the function returns NULL, there are no more
668 * records to read. If errno is set, it indicates the error.
669 *
670 * Notes:
671 * - The caller should set "errno" to 0 before calling this function.
672 */
673
674 struct devtabent *
_getdevtabent(void)675 _getdevtabent(void)
676 {
677 /* Automatic data */
678 struct devtabent *ent; /* Ptr to dev table entry structure */
679 struct attrval *attr; /* Ptr to struct for attr/val pair */
680 struct attrval *t; /* Tmp ptr to attr/val struct */
681 char *record; /* Ptr to the record just read */
682 char *p, *q; /* Tmp char ptrs */
683 int done; /* TRUE if we've built an entry */
684
685
686 /* Open the device table if it's not already open */
687 if (oam_devtab == NULL) {
688 if (!_opendevtab("r"))
689 return (NULL);
690 }
691
692 /* Get space for the structure we're returning */
693 if (!(ent = malloc(sizeof (struct devtabent)))) {
694 return (NULL);
695 }
696
697 done = FALSE;
698 while (!done && (record = getnextrec())) {
699
700 /* Save record number in structure */
701 ent->entryno = dtabrecnum++;
702
703 /* Comment record? If so, just save the value and we're through */
704 if (strchr("#\n", *record) || isspace((unsigned char)*record)) {
705 ent->comment = TRUE;
706 done = TRUE;
707 if (ent->attrstr = malloc(strlen(record)+1)) {
708 q = ent->attrstr;
709 p = record;
710 do {
711 if (*p == '\\') p++;
712 *q++ = *p;
713 } while (*p++);
714 } else {
715 free(ent);
716 ent = NULL;
717 }
718 }
719
720 else {
721
722 /* Record is a data record. Parse it. */
723 ent->comment = FALSE;
724 ent->attrstr = NULL; /* For now */
725
726 /* Extract the device alias */
727 if (p = getfld(record, ":")) {
728 if (*p) {
729 if (ent->alias = malloc(strlen(p)+1)) {
730 q = ent->alias;
731 do {
732 if (*p == '\\') p++;
733 *q++ = *p;
734 } while (*p++);
735 }
736 } else ent->alias = NULL;
737
738 /* Extract the character-device name */
739 if ((p = getfld(NULL, ":")) == NULL) {
740 if (ent->alias)
741 free(ent->alias);
742 } else {
743 if (*p) {
744 if (ent->cdevice = malloc(strlen(p)+1)) {
745 q = ent->cdevice;
746 do {
747 if (*p == '\\') p++;
748 *q++ = *p;
749 } while (*p++);
750 }
751 } else ent->cdevice = NULL;
752
753 /* Extract the block-device name */
754 if (!(p = getfld(NULL, ":"))) {
755 if (ent->alias) free(ent->alias);
756 if (ent->cdevice) free(ent->cdevice);
757 } else {
758 if (*p) {
759 if (ent->bdevice = malloc(strlen(p)+1)) {
760 q = ent->bdevice;
761 do {
762 if (*p == '\\') p++;
763 *q++ = *p;
764 } while (*p++);
765 }
766 } else
767 ent->bdevice = NULL;
768
769 /* Extract the pathname */
770 if ((p = getfld(NULL, ":\n")) == NULL) {
771 if (ent->alias) free(ent->alias);
772 if (ent->cdevice) free(ent->cdevice);
773 if (ent->bdevice) free(ent->bdevice);
774 } else {
775 if (*p) {
776 if (ent->pathname = malloc(strlen(p)+1)) {
777 q = ent->pathname;
778 do {
779 if (*p == '\\') p++;
780 *q++ = *p;
781 } while (*p++);
782 }
783 } else
784 ent->pathname = NULL;
785
786 /* Found a valid record */
787 done = TRUE;
788
789 /*
790 * Extract attributes, build a linked list of
791 * 'em (may be none)
792 */
793 if (attr = getattrval(NULL)) {
794 ent->attrlist = attr;
795 t = attr;
796 while (attr = getattrval(NULL)) {
797 t->next = attr;
798 t = attr;
799 }
800 t->next = NULL;
801 } else
802 ent->attrlist = NULL;
803
804 } /* pathname extracted */
805 } /* bdevice extracted */
806 } /* cdevice extracted */
807 } /* alias extracted */
808 }
809 } /* !done && record read */
810
811 /* If no entry was read, free space allocated to the structure */
812 if (!done) {
813 free(ent);
814 ent = NULL;
815 }
816
817 return (ent);
818 }
819
820 /*
821 * void _freedevtabent(devtabent)
822 * struct devtabent *devtabent;
823 *
824 * This function frees space allocated to a device table entry.
825 *
826 * Arguments:
827 * struct devtabent *devtabent The structure whose space is to be
828 * freed.
829 *
830 * Returns: void
831 */
832
833 void
_freedevtabent(struct devtabent * ent)834 _freedevtabent(struct devtabent *ent)
835 {
836 /*
837 * Automatic data
838 */
839
840 struct attrval *p; /* Structure being freed */
841 struct attrval *q; /* Next structure to free */
842
843 if (!ent->comment) {
844
845 /*
846 * Free the attribute list. For each item in the attribute
847 * list,
848 * 1. Free the attribute name (always defined),
849 * 2. Free the value (if any -- it's not defined if we're
850 * changing an existing attribute),
851 * 3. Free the space allocated to the structure.
852 */
853
854 q = ent->attrlist;
855 if (q)
856 do {
857 p = q;
858 q = p->next;
859 free(p->attr);
860 if (p->val) free(p->val);
861 free(p);
862 } while (q);
863
864 /* Free the standard fields (alias, cdevice, bdevice, pathname) */
865 if (ent->alias) free(ent->alias);
866 if (ent->cdevice) free(ent->cdevice);
867 if (ent->bdevice) free(ent->bdevice);
868 if (ent->pathname) free(ent->pathname);
869 }
870
871 /* Free the attribute string */
872 if (ent->attrstr) free(ent->attrstr);
873
874 /* Free the space allocated to the structure */
875 free(ent);
876 }
877
878 /*
879 * struct devtabent *_getdevrec(device)
880 * char *device
881 *
882 * Thie _getdevrec() function returns a pointer to a structure that
883 * contains the information in the device-table entry that describes
884 * the device <device>.
885 *
886 * The device <device> can be a device alias, a pathname contained in
887 * the entry as the "cdevice", "bdevice", or "pathname" attribute,
888 * or a pathname to a device described using the "cdevice", "bdevice",
889 * or "pathname" attribute (depending on whether the pathname references
890 * a character-special file, block-special file, or something else,
891 * respectively.
892 *
893 * Arguments:
894 * char *device A character-string describing the device whose record
895 * is to be retrieved from the device table.
896 *
897 * Returns: struct devtabent *
898 * A pointer to a structure describing the device.
899 *
900 * Notes:
901 * - Someday, add a cache so that repeated requests for the same record
902 * don't require going to the filesystem. (Maybe -- this might belong
903 * in devattr()...)
904 */
905
906 struct devtabent *
_getdevrec(char * device)907 _getdevrec(char *device) /* The device to search for */
908 {
909 /*
910 * Automatic data
911 */
912
913 struct stat64 devstatbuf; /* Stat struct, <device> */
914 struct stat64 tblstatbuf; /* Stat struct, tbl entry */
915 struct devtabent *devrec; /* Pointer to current record */
916 int found; /* TRUE if record found */
917 int olderrno; /* Old value of errno */
918
919
920 /*
921 * Search the device table looking for the requested device
922 */
923
924 _setdevtab();
925 olderrno = errno;
926 found = FALSE;
927 if ((device != NULL) && !_validalias(device)) {
928 while (!found && (devrec = _getdevtabent())) {
929 if (!devrec->comment) {
930 if (devrec->cdevice)
931 if (strcmp(device, devrec->cdevice) == 0) found = TRUE;
932 if (devrec->bdevice)
933 if (strcmp(device, devrec->bdevice) == 0) found = TRUE;
934 if (devrec->pathname)
935 if (strcmp(device, devrec->pathname) == 0) found = TRUE;
936 } else _freedevtabent(devrec);
937 }
938
939 /*
940 * If the device <device> wasn't named explicitly in the device
941 * table, compare it against like entries by comparing file-
942 * system, major device number, and minor device number
943 */
944
945 if (!found) {
946 _setdevtab();
947
948 /* Status the file <device>. If fails, invalid device */
949 if (stat64(device, &devstatbuf) != 0) errno = ENODEV;
950 else {
951
952 /*
953 * If <device> is a block-special device. See if it is
954 * in the table by matching its file-system indicator
955 * and major/minor device numbers against the
956 * file-system and major/minor device numbers of the
957 * "bdevice" entries.
958 */
959
960 if ((devstatbuf.st_mode & 0170000) == 0020000) {
961 while (!found && (devrec = _getdevtabent())) {
962 if (!devrec->comment &&
963 (devrec->cdevice != NULL))
964 if (stat64(devrec->cdevice, &tblstatbuf) == 0) {
965 if (samedev(tblstatbuf, devstatbuf))
966 found = TRUE;
967 } else {
968 /* Ignore stat() errs */
969 errno = olderrno;
970 }
971 if (!found) _freedevtabent(devrec);
972 }
973 }
974
975 /*
976 * If <device> is a block-special device. See if it is
977 * in the table by matching its file-system indicator
978 * and major/minor device numbers against the
979 * file-system and major/minor device numbers of the
980 * "bdevice" entries.
981 */
982
983 else if ((devstatbuf.st_mode & 0170000) == 0060000) {
984 while (!found && (devrec = _getdevtabent())) {
985 if (!devrec->comment &&
986 (devrec->bdevice != NULL))
987 if (stat64(devrec->bdevice, &tblstatbuf) == 0) {
988 if (samedev(tblstatbuf, devstatbuf))
989 found = TRUE;
990 } else {
991 /* Ignore stat() errs */
992 errno = olderrno;
993 }
994 if (!found) _freedevtabent(devrec);
995 }
996 }
997
998 /*
999 * If <device> is neither a block-special or character-
1000 * special device. See if it is in the table by
1001 * matching its file-system indicator and major/minor
1002 * device numbers against the file-system and
1003 * major/minor device numbers of the "pathname" entries.
1004 */
1005
1006 else {
1007 while (!found && (devrec = _getdevtabent())) {
1008 if (!devrec->comment &&
1009 (devrec->pathname != NULL))
1010 if (stat64(devrec->pathname,
1011 &tblstatbuf) == 0) {
1012 if (samedev(tblstatbuf, devstatbuf))
1013 found = TRUE;
1014 } else {
1015 /* Ignore stat() errs */
1016 errno = olderrno;
1017 }
1018 if (!found) _freedevtabent(devrec);
1019 }
1020 }
1021
1022 if (!found) {
1023 devrec = NULL;
1024 errno = ENODEV;
1025 }
1026
1027 } /* End case where stat() on the <device> succeeded */
1028
1029 } /* End case handling pathname not explicitly in device table */
1030
1031 } /* End case handling <device> as a fully-qualified pathname */
1032
1033
1034 /*
1035 * Otherwise the device <device> is an alias.
1036 * Search the table for a record that has as the "alias" attribute
1037 * the value <device>.
1038 */
1039
1040 else {
1041 while (!found && (devrec = _getdevtabent())) {
1042 if (!devrec->comment && (device != NULL) &&
1043 strcmp(device, devrec->alias) == 0)
1044 found = TRUE;
1045 else _freedevtabent(devrec);
1046 }
1047 if (!found) {
1048 devrec = NULL;
1049 errno = ENODEV;
1050 }
1051 }
1052
1053 /* Fini */
1054 return (devrec);
1055 }
1056