Updated with Tizen:Base source codes
[external/procps.git] / proc / devname.c
1 /*
2  * Copyright 1998-2002 by Albert Cahalan; all rights resered.         
3  * This file may be used subject to the terms and conditions of the
4  * GNU Library General Public License Version 2, or any later version  
5  * at your option, as published by the Free Software Foundation.
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU Library General Public License for more details.
10  */                                 
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include "version.h"
20 #include "devname.h"
21
22 // This is the buffer size for a tty name. Any path is legal,
23 // which makes PAGE_SIZE appropriate (see kernel source), but
24 // that is only 99% portable and utmp only holds 32 anyway.
25 // We need at least 20 for guess_name().
26 #define TTY_NAME_SIZE 128
27
28 /* Who uses what:
29  *
30  * tty_to_dev   w (there is a fancy version in ps)
31  * dev_to_tty   top, ps
32  */
33
34 #if 0
35 #include <sys/sysmacros.h>
36 #define MAJOR_OF(d) ((unsigned)major(d))
37 #define MINOR_OF(d) ((unsigned)minor(d))
38 #else
39 #define MAJOR_OF(d) ( ((unsigned)(d)>>8u) & 0xfffu )
40 #define MINOR_OF(d) ( ((unsigned)(d)&0xffu) | (((unsigned)(d)&0xfff00000u)>>12u) )
41 #undef major
42 #undef minor
43 #define major <-- do not use -->
44 #define minor <-- do not use -->
45 #endif
46
47 typedef struct tty_map_node {
48   struct tty_map_node *next;
49   unsigned short devfs_type;  // bool
50   unsigned short major_number;
51   unsigned minor_first;
52   unsigned minor_last;
53   char name[16];
54 } tty_map_node;
55
56 static tty_map_node *tty_map = NULL;
57
58 /* Load /proc/tty/drivers for device name mapping use. */
59 static void load_drivers(void){
60   char buf[10000];
61   char *p;
62   int fd;
63   int bytes;
64   fd = open("/proc/tty/drivers",O_RDONLY);
65   if(fd == -1) goto fail;
66   bytes = read(fd, buf, sizeof(buf) - 1);
67   if(bytes == -1) goto fail;
68   buf[bytes] = '\0';
69   p = buf;
70   while(( p = strstr(p, " /dev/") )){  // " /dev/" is the second column
71     tty_map_node *tmn;
72     int len;
73     char *end;
74     p += 6;
75     end = strchr(p, ' ');
76     if(!end) continue;
77     len = end - p;
78     tmn = calloc(1, sizeof(tty_map_node));
79     tmn->next = tty_map;
80     tty_map = tmn;
81     /* if we have a devfs type name such as /dev/tts/%d then strip the %d but
82        keep a flag. */
83     if(len >= 3 && !strncmp(end - 2, "%d", 2)){
84       len -= 2;
85       tmn->devfs_type = 1;
86     }
87     if(len >= sizeof tmn->name)
88       len = sizeof tmn->name - 1; // mangle it to avoid overflow
89     memcpy(tmn->name, p, len);
90     p = end; /* set p to point past the %d as well if there is one */
91     while(*p == ' ') p++;
92     tmn->major_number = atoi(p);
93     p += strspn(p, "0123456789");
94     while(*p == ' ') p++;
95     switch(sscanf(p, "%u-%u", &tmn->minor_first, &tmn->minor_last)){
96     default:
97       /* Can't finish parsing this line so we remove it from the list */
98       tty_map = tty_map->next;
99       free(tmn);
100       break;
101     case 1:
102       tmn->minor_last = tmn->minor_first;
103       break;
104     case 2:
105       break;
106     }
107   }
108 fail:
109   if(fd != -1) close(fd);
110   if(!tty_map) tty_map = (tty_map_node *)-1;
111 }
112
113 /* Try to guess the device name from /proc/tty/drivers info. */
114 static int driver_name(char *restrict const buf, unsigned maj, unsigned min){
115   struct stat sbuf;
116   tty_map_node *tmn;
117   if(!tty_map) load_drivers();
118   if(tty_map == (tty_map_node *)-1) return 0;
119   tmn = tty_map;
120   for(;;){
121     if(!tmn) return 0;
122     if(tmn->major_number == maj && tmn->minor_first <= min && tmn->minor_last >= min) break;
123     tmn = tmn->next;
124   }
125   sprintf(buf, "/dev/%s%d", tmn->name, min);  /* like "/dev/ttyZZ255" */
126   if(stat(buf, &sbuf) < 0){
127     if(tmn->devfs_type) return 0;
128     sprintf(buf, "/dev/%s", tmn->name);  /* like "/dev/ttyZZ255" */
129     if(stat(buf, &sbuf) < 0) return 0;
130   }
131   if(min != MINOR_OF(sbuf.st_rdev)) return 0;
132   if(maj != MAJOR_OF(sbuf.st_rdev)) return 0;
133   return 1;
134 }
135
136 // major 204 is a mess -- "Low-density serial ports"
137 static const char low_density_names[][6] = {
138 "LU0",  "LU1",  "LU2",  "LU3",
139 "FB0",
140 "SA0",  "SA1",  "SA2",
141 "SC0",  "SC1",  "SC2",  "SC3",
142 "FW0",  "FW1",  "FW2",  "FW3",
143 "AM0",  "AM1",  "AM2",  "AM3",  "AM4",  "AM5",  "AM6",  "AM7",
144 "AM8",  "AM9",  "AM10", "AM11", "AM12", "AM13", "AM14", "AM15",
145 "DB0",  "DB1",  "DB2",  "DB3",  "DB4",  "DB5",  "DB6",  "DB7",
146 "SG0",
147 "SMX0",  "SMX1",  "SMX2",
148 "MM0",  "MM1",
149 "CPM0", "CPM1", "CPM2", "CPM3", /* "CPM4", "CPM5", */  // bad allocation?
150 "IOC0",  "IOC1",  "IOC2",  "IOC3",  "IOC4",  "IOC5",  "IOC6",  "IOC7",
151 "IOC8",  "IOC9",  "IOC10", "IOC11", "IOC12", "IOC13", "IOC14", "IOC15",
152 "IOC16", "IOC17", "IOC18", "IOC19", "IOC20", "IOC21", "IOC22", "IOC23",
153 "IOC24", "IOC25", "IOC26", "IOC27", "IOC28", "IOC29", "IOC30", "IOC31",
154 "VR0", "VR1",
155 "IOC84",  "IOC85",  "IOC86",  "IOC87",  "IOC88",  "IOC89",  "IOC90",  "IOC91",
156 "IOC92",  "IOC93",  "IOC94", "IOC95", "IOC96", "IOC97", "IOC98", "IOC99",
157 "IOC100", "IOC101", "IOC102", "IOC103", "IOC104", "IOC105", "IOC106", "IOC107",
158 "IOC108", "IOC109", "IOC110", "IOC111", "IOC112", "IOC113", "IOC114", "IOC115",
159 "SIOC0",  "SIOC1",  "SIOC2",  "SIOC3",  "SIOC4",  "SIOC5",  "SIOC6",  "SIOC7",
160 "SIOC8",  "SIOC9",  "SIOC10", "SIOC11", "SIOC12", "SIOC13", "SIOC14", "SIOC15",
161 "SIOC16", "SIOC17", "SIOC18", "SIOC19", "SIOC20", "SIOC21", "SIOC22", "SIOC23",
162 "SIOC24", "SIOC25", "SIOC26", "SIOC27", "SIOC28", "SIOC29", "SIOC30", "SIOC31",
163 "PSC0", "PSC1", "PSC2", "PSC3", "PSC4", "PSC5",
164 "AT0",  "AT1",  "AT2",  "AT3",  "AT4",  "AT5",  "AT6",  "AT7",
165 "AT8",  "AT9",  "AT10", "AT11", "AT12", "AT13", "AT14", "AT15",
166 "NX0",  "NX1",  "NX2",  "NX3",  "NX4",  "NX5",  "NX6",  "NX7",
167 "NX8",  "NX9",  "NX10", "NX11", "NX12", "NX13", "NX14", "NX15",
168 "J0",   // minor is 186
169 "UL0","UL1","UL2","UL3",
170 "xvc0", // FAIL -- "/dev/xvc0" lacks "tty" prefix
171 "PZ0","PZ1","PZ2","PZ3",
172 "TX0","TX1","TX2","TX3","TX4","TX5","TX6","TX7",
173 "SC0","SC1","SC2","SC3",
174 "MAX0","MAX1","MAX2","MAX3",
175 };
176
177 #if 0
178 // test code
179 #include <stdio.h>
180 #define AS(x) (sizeof(x)/sizeof((x)[0]))
181 int main(int argc, char *argv[]){
182   int i = 0;
183   while(i<AS(low_density_names)){
184     printf("%3d = /dev/tty%.*s\n",i,sizeof low_density_names[i],low_density_names[i]);
185     i++;
186   }
187   return 0;
188 }
189 #endif
190
191 /* Try to guess the device name (useful until /proc/PID/tty is added) */
192 static int guess_name(char *restrict const buf, unsigned maj, unsigned min){
193   struct stat sbuf;
194   int t0, t1;
195   unsigned tmpmin = min;
196
197   switch(maj){
198   case   3:      /* /dev/[pt]ty[p-za-o][0-9a-z] is 936 */
199     if(tmpmin > 255) return 0;   // should never happen; array index protection
200     t0 = "pqrstuvwxyzabcde"[tmpmin>>4];
201     t1 = "0123456789abcdef"[tmpmin&0x0f];
202     sprintf(buf, "/dev/tty%c%c", t0, t1);
203     break;
204   case   4:
205     if(min<64){
206       sprintf(buf, "/dev/tty%d", min);
207       break;
208     }
209     sprintf(buf, "/dev/ttyS%d", min-64);
210     break;
211   case  11:  sprintf(buf, "/dev/ttyB%d",  min); break;
212   case  17:  sprintf(buf, "/dev/ttyH%d",  min); break;
213   case  19:  sprintf(buf, "/dev/ttyC%d",  min); break;
214   case  22:  sprintf(buf, "/dev/ttyD%d",  min); break; /* devices.txt */
215   case  23:  sprintf(buf, "/dev/ttyD%d",  min); break; /* driver code */
216   case  24:  sprintf(buf, "/dev/ttyE%d",  min); break;
217   case  32:  sprintf(buf, "/dev/ttyX%d",  min); break;
218   case  43:  sprintf(buf, "/dev/ttyI%d",  min); break;
219   case  46:  sprintf(buf, "/dev/ttyR%d",  min); break;
220   case  48:  sprintf(buf, "/dev/ttyL%d",  min); break;
221   case  57:  sprintf(buf, "/dev/ttyP%d",  min); break;
222   case  71:  sprintf(buf, "/dev/ttyF%d",  min); break;
223   case  75:  sprintf(buf, "/dev/ttyW%d",  min); break;
224   case  78:  sprintf(buf, "/dev/ttyM%d",  min); break; /* conflict */
225   case 105:  sprintf(buf, "/dev/ttyV%d",  min); break;
226   case 112:  sprintf(buf, "/dev/ttyM%d",  min); break; /* conflict */
227   /* 136 ... 143 are /dev/pts/0, /dev/pts/1, /dev/pts/2 ... */
228   case 136 ... 143:  sprintf(buf, "/dev/pts/%d",  min+(maj-136)*256); break;
229   case 148:  sprintf(buf, "/dev/ttyT%d",  min); break;
230   case 154:  sprintf(buf, "/dev/ttySR%d", min); break;
231   case 156:  sprintf(buf, "/dev/ttySR%d", min+256); break;
232   case 164:  sprintf(buf, "/dev/ttyCH%d",  min); break;
233   case 166:  sprintf(buf, "/dev/ttyACM%d", min); break; /* bummer, 9-char */
234   case 172:  sprintf(buf, "/dev/ttyMX%d",  min); break;
235   case 174:  sprintf(buf, "/dev/ttySI%d",  min); break;
236   case 188:  sprintf(buf, "/dev/ttyUSB%d", min); break; /* bummer, 9-char */
237   case 204:
238     if(min >= sizeof low_density_names / sizeof low_density_names[0]) return 0;
239     memcpy(buf,"/dev/tty",8);
240     memcpy(buf+8, low_density_names[min], sizeof low_density_names[0]);
241     buf[8 + sizeof low_density_names[0]] = '\0';
242 //    snprintf(buf, 9 + sizeof low_density_names[0], "/dev/tty%.*s", sizeof low_density_names[0], low_density_names[min]);
243     break;
244   case 208:  sprintf(buf, "/dev/ttyU%d",  min); break;
245   case 216:  sprintf(buf, "/dev/ttyUB%d",  min); break; // "/dev/rfcomm%d" now?
246   case 224:  sprintf(buf, "/dev/ttyY%d",  min); break;
247   case 227:  sprintf(buf, "/dev/3270/tty%d", min); break; /* bummer, HUGE */
248   case 229:  sprintf(buf, "/dev/iseries/vtty%d",  min); break; /* bummer, HUGE */
249   case 256:  sprintf(buf, "/dev/ttyEQ%d",  min); break;
250   default: return 0;
251   }
252   if(stat(buf, &sbuf) < 0) return 0;
253   if(min != MINOR_OF(sbuf.st_rdev)) return 0;
254   if(maj != MAJOR_OF(sbuf.st_rdev)) return 0;
255   return 1;
256 }
257
258 /* Linux 2.2 can give us filenames that might be correct.
259  * Useful names could be in /proc/PID/fd/2 (stderr, seldom redirected)
260  * and in /proc/PID/fd/255 (used by bash to remember the tty).
261  */
262 static int link_name(char *restrict const buf, unsigned maj, unsigned min, int pid, const char *restrict name){
263   struct stat sbuf;
264   char path[32];
265   int count;
266   sprintf(path, "/proc/%d/%s", pid, name);  /* often permission denied */
267   count = readlink(path,buf,TTY_NAME_SIZE-1);
268   if(count == -1) return 0;
269   buf[count] = '\0';
270   if(stat(buf, &sbuf) < 0) return 0;
271   if(min != MINOR_OF(sbuf.st_rdev)) return 0;
272   if(maj != MAJOR_OF(sbuf.st_rdev)) return 0;
273   return 1;
274 }
275
276 /* number --> name */
277 unsigned dev_to_tty(char *restrict ret, unsigned chop, dev_t dev_t_dev, int pid, unsigned int flags) {
278   static char buf[TTY_NAME_SIZE];
279   char *restrict tmp = buf;
280   unsigned dev = dev_t_dev;
281   unsigned i = 0;
282   int c;
283   if(dev == 0u) goto no_tty;
284   if(linux_version_code > LINUX_VERSION(2, 7, 0)){  // not likely to make 2.6.xx
285     if(link_name(tmp, MAJOR_OF(dev), MINOR_OF(dev), pid, "tty"   )) goto abbrev;
286   }
287   if(driver_name(tmp, MAJOR_OF(dev), MINOR_OF(dev)               )) goto abbrev;
288   if(  link_name(tmp, MAJOR_OF(dev), MINOR_OF(dev), pid, "fd/2"  )) goto abbrev;
289   if( guess_name(tmp, MAJOR_OF(dev), MINOR_OF(dev)               )) goto abbrev;
290   if(  link_name(tmp, MAJOR_OF(dev), MINOR_OF(dev), pid, "fd/255")) goto abbrev;
291   // fall through if unable to find a device file
292 no_tty:
293   strcpy(ret, "?");
294   return 1;
295 abbrev:
296   if((flags&ABBREV_DEV) && !strncmp(tmp,"/dev/",5) && tmp[5]) tmp += 5;
297   if((flags&ABBREV_TTY) && !strncmp(tmp,"tty",  3) && tmp[3]) tmp += 3;
298   if((flags&ABBREV_PTS) && !strncmp(tmp,"pts/", 4) && tmp[4]) tmp += 4;
299   /* gotta check before we chop or we may chop someone else's memory */
300   if(chop + (unsigned long)(tmp-buf) <= sizeof buf)
301     tmp[chop] = '\0';
302   /* replace non-ASCII characters with '?' and return the number of chars */
303   for(;;){
304     c = *tmp;
305     tmp++;
306     if(!c) break;
307     i++;
308     if(c<=' ') c = '?';
309     if(c>126)  c = '?';
310     *ret = c;
311     ret++;
312   }
313   *ret = '\0';
314   return i;
315 }
316
317 /* name --> number */
318 int tty_to_dev(const char *restrict const name) {
319   struct stat sbuf;
320   static char buf[32];
321   if(name[0]=='/' && stat(name, &sbuf) >= 0) return sbuf.st_rdev;
322   snprintf(buf,32,"/dev/%s",name);
323   if(stat(buf, &sbuf) >= 0) return sbuf.st_rdev;
324   snprintf(buf,32,"/dev/tty%s",name);
325   if(stat(buf, &sbuf) >= 0) return sbuf.st_rdev;
326   snprintf(buf,32,"/dev/pts/%s",name);
327   if(stat(buf, &sbuf) >= 0) return sbuf.st_rdev;
328   return -1;
329 }