xref: /original-bsd/lib/libc/gen/devname.c (revision 6ab384a1)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)devname.c	5.7 (Berkeley) 08/30/90";
10 #endif /* LIBC_SCCS and not lint */
11 
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/file.h>
15 #include <dirent.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <paths.h>
20 
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 {
33 	struct	devs *next;
34 	dev_t	dev;
35 	mode_t	type;
36 	char	name[MAXNAMLEN + 1];
37 };
38 
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;
61 	(void) strcpy(devp->name, name);
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)
125 
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 }
135 
136 char *
137 devname(dev, type)
138 	dev_t dev;
139 	mode_t type;
140 {
141 	register struct devs *devp;
142 	static int devinit;
143 
144 	if (!devinit) {
145 		if (!init_by_db() && !init_by_stat())
146 			return (NULL);
147 		devinit = 1;
148 	}
149 	for (devp = devhash[hash(dev, type)]; devp != NULL; devp = devp->next)
150 		if (dev == devp->dev && type == devp->type)
151 			return (devp->name);
152 
153 	return (NULL);
154 }
155 
156 #ifdef TEST
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);
178 }
179 #endif
180