move radixsort to stdlib, so it's with qsort
[unix-history] / usr / src / lib / libc / gen / devname.c
CommitLineData
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 9static 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
32struct 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
39static struct devs *devhash[HASHSIZ];
40
41#ifdef TEST
42int chainlen[HASHSIZ];
43int verbose;
44#endif
45
46static int
47add(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
76static int
77init_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
118static int
119init_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
136char *
25594745 137devname(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
157main(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