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