Commit | Line | Data |
---|---|---|
25594745 MT |
1 | /* |
2 | * Copyright (c) 1989 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
27c71911 | 5 | * %sccs.include.redist.c% |
25594745 MT |
6 | */ |
7 | ||
8 | #if defined(LIBC_SCCS) && !defined(lint) | |
b1aa9338 | 9 | static char sccsid[] = "@(#)devname.c 5.8 (Berkeley) %G%"; |
25594745 MT |
10 | #endif /* LIBC_SCCS and not lint */ |
11 | ||
89962e19 | 12 | #include <sys/types.h> |
89962e19 | 13 | #include <sys/stat.h> |
25594745 MT |
14 | #include <sys/file.h> |
15 | #include <dirent.h> | |
b5bb6e20 MT |
16 | #include <stdio.h> |
17 | #include <stdlib.h> | |
18 | #include <string.h> | |
25594745 | 19 | #include <paths.h> |
89962e19 | 20 | |
b5bb6e20 MT |
21 | /* |
22 | * Routine to convert a major+minor device number (st_rdev field) | |
23 | * plus a mode (S_IFCHR or S_IFBLK) into a name relative to /dev. | |
24 | * | |
25 | * We build a hash table of everything in /dev, with the hash being | |
26 | * a function of the number and mode. | |
27 | */ | |
28 | ||
29 | #define HASHSIZ 512 /* MUST BE A POWER OF 2 */ | |
30 | #define hash(x, t) ((((t) >> 14) + 4*minor(x) + major(x)) & (HASHSIZ-1)) | |
31 | ||
32 | struct devs { | |
25594745 | 33 | struct devs *next; |
89962e19 | 34 | dev_t dev; |
97b4e907 | 35 | mode_t type; |
b1aa9338 | 36 | char *name; |
89962e19 MT |
37 | }; |
38 | ||
b5bb6e20 MT |
39 | static struct devs *devhash[HASHSIZ]; |
40 | ||
41 | #ifdef TEST | |
42 | int chainlen[HASHSIZ]; | |
43 | int verbose; | |
44 | #endif | |
45 | ||
46 | static int | |
47 | add(type, dev, name) | |
48 | mode_t type; | |
49 | dev_t dev; | |
50 | char *name; | |
51 | { | |
52 | register struct devs *devp, **p; | |
53 | int h; | |
54 | ||
55 | devp = (struct devs *)malloc(sizeof *devp); | |
56 | if (devp == NULL) | |
57 | return (0); | |
58 | devp->next = NULL; | |
59 | devp->dev = dev; | |
60 | devp->type = type; | |
b1aa9338 | 61 | devp->name = strdup(name); |
b5bb6e20 MT |
62 | h = hash(dev, type); |
63 | for (p = &devhash[h]; *p; p = &(*p)->next) | |
64 | /* void */; | |
65 | *p = devp; | |
66 | #ifdef TEST | |
67 | chainlen[h]++; | |
68 | if (verbose) | |
69 | (void) printf("adding %c %d,%d %s (hash=%d)\n", | |
70 | type == S_IFBLK ? 'b': 'c', major(dev), minor(dev), | |
71 | name, h); | |
72 | #endif | |
73 | return (1); | |
74 | } | |
75 | ||
76 | static int | |
77 | init_by_stat() | |
78 | { | |
79 | register struct dirent *entry; | |
80 | struct stat sb; | |
81 | DIR *dp; | |
82 | int savewd; | |
83 | mode_t specialtype; | |
84 | ||
85 | if ((savewd = open(".", O_RDONLY, 0)) == -1) | |
86 | return (0); | |
87 | if (chdir(_PATH_DEV) == -1) { | |
88 | (void) close(savewd); | |
89 | return (0); | |
90 | } | |
91 | if ((dp = opendir(".")) == NULL) { | |
92 | (void) fchdir(savewd); | |
93 | (void) close(savewd); | |
94 | return (0); | |
95 | } | |
96 | while ((entry = readdir(dp)) != NULL) { | |
97 | if (stat(entry->d_name, &sb) == -1) | |
98 | continue; | |
99 | switch (sb.st_mode & S_IFMT) { | |
100 | case S_IFCHR: | |
101 | specialtype = S_IFCHR; | |
102 | break; | |
103 | case S_IFBLK: | |
104 | specialtype = S_IFBLK; | |
105 | break; | |
106 | default: | |
107 | continue; | |
108 | } | |
109 | if (!add(specialtype, sb.st_rdev, entry->d_name)) | |
110 | break; | |
111 | } | |
112 | (void) fchdir(savewd); | |
113 | (void) close(savewd); | |
114 | (void) closedir(dp); | |
115 | return (1); | |
116 | } | |
117 | ||
118 | static int | |
119 | init_by_db() | |
120 | { | |
121 | register FILE *fp; | |
122 | char type, name[MAXNAMLEN + 1]; | |
123 | int maj, min; | |
124 | #define specialtype(c) ((c) == 'b' ? (mode_t)S_IFBLK : (mode_t)S_IFCHR) | |
89962e19 | 125 | |
b5bb6e20 MT |
126 | if ((fp = fopen("/var/run/devdatabase", "r")) == NULL) |
127 | return (0); | |
128 | while (fscanf(fp, " %c %d,%d %s", &type, &maj, &min, name) == 4) | |
129 | if (!add(specialtype(type), makedev(maj, min), name)) | |
130 | break; | |
131 | (void) fclose(fp); | |
132 | return (1); | |
133 | #undef specialtype | |
134 | } | |
89962e19 MT |
135 | |
136 | char * | |
25594745 | 137 | devname(dev, type) |
89962e19 | 138 | dev_t dev; |
97b4e907 | 139 | mode_t type; |
89962e19 | 140 | { |
b5bb6e20 MT |
141 | register struct devs *devp; |
142 | static int devinit; | |
89962e19 | 143 | |
b5bb6e20 MT |
144 | if (!devinit) { |
145 | if (!init_by_db() && !init_by_stat()) | |
89962e19 | 146 | return (NULL); |
25594745 | 147 | devinit = 1; |
89962e19 | 148 | } |
b5bb6e20 | 149 | for (devp = devhash[hash(dev, type)]; devp != NULL; devp = devp->next) |
25594745 | 150 | if (dev == devp->dev && type == devp->type) |
b5bb6e20 | 151 | return (devp->name); |
89962e19 MT |
152 | |
153 | return (NULL); | |
154 | } | |
155 | ||
156 | #ifdef TEST | |
b5bb6e20 MT |
157 | main(argc, argv) |
158 | int argc; | |
159 | char **argv; | |
160 | { | |
161 | register int i, sum, longest; | |
162 | struct stat st; | |
163 | char *p, *ttyname(); | |
164 | ||
165 | if (argc > 1 && strcmp(argv[1], "-v") == 0) | |
166 | verbose = 1, argc--, argv++; | |
167 | p = argc > 1 ? argv[1] : ttyname(0); | |
168 | (void) stat(p, &st); | |
169 | (void) printf(" %s \n", devname(st.st_rdev, (mode_t)S_IFCHR)); | |
170 | longest = sum = 0; | |
171 | for (i = 0; i < HASHSIZ; i++) { | |
172 | sum += chainlen[i]; | |
173 | if (chainlen[i] > longest) | |
174 | longest = chainlen[i]; | |
175 | } | |
176 | (void) printf("average hash chain length %.2f, longest %d\n", | |
177 | (double)sum / HASHSIZ, longest); | |
89962e19 MT |
178 | } |
179 | #endif |