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.8 (Berkeley) 11/07/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; 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 devp->name = strdup(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