build-sys: Relocate library to library/
All the dependent programs needed to have their includes moved too Signed-off-by: Craig Small <csmall@dropbear.xyz>
This commit is contained in:
361
library/devname.c
Normal file
361
library/devname.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* devname - device name functions
|
||||
* Copyright 1998-2002 by Albert Cahalan
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "misc.h"
|
||||
#include "devname.h"
|
||||
|
||||
// This is the buffer size for a tty name. Any path is legal,
|
||||
// which makes PAGE_SIZE appropriate (see kernel source), but
|
||||
// that is only 99% portable and utmp only holds 32 anyway.
|
||||
// We need at least 20 for guess_name().
|
||||
#define TTY_NAME_SIZE 128
|
||||
|
||||
/* Who uses what:
|
||||
*
|
||||
* dev_to_tty top, ps
|
||||
*/
|
||||
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#elif defined MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#else
|
||||
#define major(d) ( ((unsigned)(d)>>8u) & 0xfffu )
|
||||
#define minor(d) ( ((unsigned)(d)&0xffu) | (((unsigned)(d)&0xfff00000u)>>12u) )
|
||||
#endif
|
||||
|
||||
typedef struct tty_map_node {
|
||||
struct tty_map_node *next;
|
||||
unsigned short devfs_type; // bool
|
||||
unsigned short major_number;
|
||||
unsigned minor_first;
|
||||
unsigned minor_last;
|
||||
char name[16];
|
||||
} tty_map_node;
|
||||
|
||||
static __thread tty_map_node *tty_map = NULL;
|
||||
|
||||
/* Load /proc/tty/drivers for device name mapping use. */
|
||||
static void load_drivers(void){
|
||||
char buf[10000];
|
||||
char *p;
|
||||
int fd;
|
||||
int bytes;
|
||||
fd = open("/proc/tty/drivers",O_RDONLY);
|
||||
if(fd == -1) goto fail;
|
||||
bytes = read(fd, buf, sizeof(buf) - 1);
|
||||
if(bytes == -1) goto fail;
|
||||
buf[bytes] = '\0';
|
||||
p = buf;
|
||||
while(( p = strstr(p, " /dev/") )){ // " /dev/" is the second column
|
||||
tty_map_node *tmn;
|
||||
size_t len;
|
||||
char *end;
|
||||
p += 6;
|
||||
end = strchr(p, ' ');
|
||||
if(!end) continue;
|
||||
len = end - p;
|
||||
if (!(tmn = calloc(1, sizeof(tty_map_node))))
|
||||
goto fail;
|
||||
tmn->next = tty_map;
|
||||
tty_map = tmn;
|
||||
/* if we have a devfs type name such as /dev/tts/%d then strip the %d but
|
||||
keep a flag. */
|
||||
if(len >= 3 && !strncmp(end - 2, "%d", 2)){
|
||||
len -= 2;
|
||||
tmn->devfs_type = 1;
|
||||
}
|
||||
if(len >= sizeof tmn->name)
|
||||
len = sizeof tmn->name - 1; // mangle it to avoid overflow
|
||||
memcpy(tmn->name, p, len);
|
||||
p = end; /* set p to point past the %d as well if there is one */
|
||||
while(*p == ' ') p++;
|
||||
tmn->major_number = atoi(p);
|
||||
p += strspn(p, "0123456789");
|
||||
while(*p == ' ') p++;
|
||||
switch(sscanf(p, "%u-%u", &tmn->minor_first, &tmn->minor_last)){
|
||||
default:
|
||||
/* Can't finish parsing this line so we remove it from the list */
|
||||
tty_map = tty_map->next;
|
||||
free(tmn);
|
||||
break;
|
||||
case 1:
|
||||
tmn->minor_last = tmn->minor_first;
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
}
|
||||
}
|
||||
fail:
|
||||
if(fd != -1) close(fd);
|
||||
if(!tty_map) tty_map = (tty_map_node *)-1;
|
||||
}
|
||||
|
||||
/* Try to guess the device name from /proc/tty/drivers info. */
|
||||
static int driver_name(char *restrict const buf, unsigned maj, unsigned min){
|
||||
struct stat sbuf;
|
||||
tty_map_node *tmn;
|
||||
if(!tty_map) load_drivers();
|
||||
if(tty_map == (tty_map_node *)-1) return 0;
|
||||
tmn = tty_map;
|
||||
for(;;){
|
||||
if(!tmn) return 0;
|
||||
if(tmn->major_number == maj && tmn->minor_first <= min && tmn->minor_last >= min) break;
|
||||
tmn = tmn->next;
|
||||
}
|
||||
sprintf(buf, "/dev/%s%d", tmn->name, min); /* like "/dev/ttyZZ255" */
|
||||
if(stat(buf, &sbuf) < 0){
|
||||
sprintf(buf, "/dev/%s/%d", tmn->name, min); /* like "/dev/pts/255" */
|
||||
if(stat(buf, &sbuf) < 0){
|
||||
if(tmn->devfs_type) return 0;
|
||||
sprintf(buf, "/dev/%s", tmn->name); /* like "/dev/ttyZZ255" */
|
||||
if(stat(buf, &sbuf) < 0) return 0;
|
||||
}
|
||||
}
|
||||
if(min != minor(sbuf.st_rdev)) return 0;
|
||||
if(maj != major(sbuf.st_rdev)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// major 204 is a mess -- "Low-density serial ports"
|
||||
static const char low_density_names[][6] = {
|
||||
"LU0", "LU1", "LU2", "LU3",
|
||||
"FB0",
|
||||
"SA0", "SA1", "SA2",
|
||||
"SC0", "SC1", "SC2", "SC3",
|
||||
"FW0", "FW1", "FW2", "FW3",
|
||||
"AM0", "AM1", "AM2", "AM3", "AM4", "AM5", "AM6", "AM7",
|
||||
"AM8", "AM9", "AM10", "AM11", "AM12", "AM13", "AM14", "AM15",
|
||||
"DB0", "DB1", "DB2", "DB3", "DB4", "DB5", "DB6", "DB7",
|
||||
"SG0",
|
||||
"SMX0", "SMX1", "SMX2",
|
||||
"MM0", "MM1",
|
||||
"CPM0", "CPM1", "CPM2", "CPM3", /* "CPM4", "CPM5", */ // bad allocation?
|
||||
"IOC0", "IOC1", "IOC2", "IOC3", "IOC4", "IOC5", "IOC6", "IOC7",
|
||||
"IOC8", "IOC9", "IOC10", "IOC11", "IOC12", "IOC13", "IOC14", "IOC15",
|
||||
"IOC16", "IOC17", "IOC18", "IOC19", "IOC20", "IOC21", "IOC22", "IOC23",
|
||||
"IOC24", "IOC25", "IOC26", "IOC27", "IOC28", "IOC29", "IOC30", "IOC31",
|
||||
"VR0", "VR1",
|
||||
"IOC84", "IOC85", "IOC86", "IOC87", "IOC88", "IOC89", "IOC90", "IOC91",
|
||||
"IOC92", "IOC93", "IOC94", "IOC95", "IOC96", "IOC97", "IOC98", "IOC99",
|
||||
"IOC100", "IOC101", "IOC102", "IOC103", "IOC104", "IOC105", "IOC106", "IOC107",
|
||||
"IOC108", "IOC109", "IOC110", "IOC111", "IOC112", "IOC113", "IOC114", "IOC115",
|
||||
"SIOC0", "SIOC1", "SIOC2", "SIOC3", "SIOC4", "SIOC5", "SIOC6", "SIOC7",
|
||||
"SIOC8", "SIOC9", "SIOC10", "SIOC11", "SIOC12", "SIOC13", "SIOC14", "SIOC15",
|
||||
"SIOC16", "SIOC17", "SIOC18", "SIOC19", "SIOC20", "SIOC21", "SIOC22", "SIOC23",
|
||||
"SIOC24", "SIOC25", "SIOC26", "SIOC27", "SIOC28", "SIOC29", "SIOC30", "SIOC31",
|
||||
"PSC0", "PSC1", "PSC2", "PSC3", "PSC4", "PSC5",
|
||||
"AT0", "AT1", "AT2", "AT3", "AT4", "AT5", "AT6", "AT7",
|
||||
"AT8", "AT9", "AT10", "AT11", "AT12", "AT13", "AT14", "AT15",
|
||||
"NX0", "NX1", "NX2", "NX3", "NX4", "NX5", "NX6", "NX7",
|
||||
"NX8", "NX9", "NX10", "NX11", "NX12", "NX13", "NX14", "NX15",
|
||||
"J0", // minor is 186
|
||||
"UL0","UL1","UL2","UL3",
|
||||
"xvc0", // FAIL -- "/dev/xvc0" lacks "tty" prefix
|
||||
"PZ0","PZ1","PZ2","PZ3",
|
||||
"TX0","TX1","TX2","TX3","TX4","TX5","TX6","TX7",
|
||||
"SC0","SC1","SC2","SC3",
|
||||
"MAX0","MAX1","MAX2","MAX3",
|
||||
};
|
||||
|
||||
#if 0
|
||||
// test code
|
||||
#include <stdio.h>
|
||||
#define AS(x) (sizeof(x)/sizeof((x)[0]))
|
||||
int main(int argc, char *argv[]){
|
||||
int i = 0;
|
||||
while(i<AS(low_density_names)){
|
||||
printf("%3d = /dev/tty%.*s\n",i,sizeof low_density_names[i],low_density_names[i]);
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Try to guess the device name (useful until /proc/PID/tty is added) */
|
||||
static int guess_name(char *restrict const buf, unsigned maj, unsigned min){
|
||||
struct stat sbuf;
|
||||
#ifndef __CYGWIN__
|
||||
int t0, t1;
|
||||
#endif
|
||||
unsigned tmpmin = min;
|
||||
|
||||
switch(maj){
|
||||
case 3: /* /dev/[pt]ty[p-za-o][0-9a-z] is 936 */
|
||||
if(tmpmin > 255) return 0; // should never happen; array index protection
|
||||
#ifdef __CYGWIN__
|
||||
sprintf(buf, "cons%d", tmpmin);
|
||||
/* Skip stat call. The reason is that cons devices are local to
|
||||
* the processes running in that console. Calling stat from another
|
||||
* console or pty will return -1. */
|
||||
return 1;
|
||||
#else
|
||||
t0 = "pqrstuvwxyzabcde"[tmpmin>>4];
|
||||
t1 = "0123456789abcdef"[tmpmin&0x0f];
|
||||
sprintf(buf, "/dev/tty%c%c", t0, t1);
|
||||
#endif
|
||||
break;
|
||||
case 4:
|
||||
if(min<64){
|
||||
sprintf(buf, "/dev/tty%d", min);
|
||||
break;
|
||||
}
|
||||
sprintf(buf, "/dev/ttyS%d", min-64);
|
||||
break;
|
||||
case 11: sprintf(buf, "/dev/ttyB%d", min); break;
|
||||
case 17: sprintf(buf, "/dev/ttyH%d", min); break;
|
||||
case 19: sprintf(buf, "/dev/ttyC%d", min); break;
|
||||
case 22: sprintf(buf, "/dev/ttyD%d", min); break; /* devices.txt */
|
||||
case 23: sprintf(buf, "/dev/ttyD%d", min); break; /* driver code */
|
||||
case 24: sprintf(buf, "/dev/ttyE%d", min); break;
|
||||
case 32: sprintf(buf, "/dev/ttyX%d", min); break;
|
||||
case 43: sprintf(buf, "/dev/ttyI%d", min); break;
|
||||
case 46: sprintf(buf, "/dev/ttyR%d", min); break;
|
||||
case 48: sprintf(buf, "/dev/ttyL%d", min); break;
|
||||
case 57: sprintf(buf, "/dev/ttyP%d", min); break;
|
||||
case 71: sprintf(buf, "/dev/ttyF%d", min); break;
|
||||
case 75: sprintf(buf, "/dev/ttyW%d", min); break;
|
||||
case 78: sprintf(buf, "/dev/ttyM%d", min); break; /* conflict */
|
||||
case 105: sprintf(buf, "/dev/ttyV%d", min); break;
|
||||
case 112: sprintf(buf, "/dev/ttyM%d", min); break; /* conflict */
|
||||
#ifdef __CYGWIN__
|
||||
case 136: sprintf(buf, "/dev/pty%d", min); break;
|
||||
#else
|
||||
/* 136 ... 143 are /dev/pts/0, /dev/pts/1, /dev/pts/2 ... */
|
||||
case 136 ... 143: sprintf(buf, "/dev/pts/%d", min+(maj-136)*256); break;
|
||||
#endif
|
||||
case 148: sprintf(buf, "/dev/ttyT%d", min); break;
|
||||
case 154: sprintf(buf, "/dev/ttySR%d", min); break;
|
||||
case 156: sprintf(buf, "/dev/ttySR%d", min+256); break;
|
||||
case 164: sprintf(buf, "/dev/ttyCH%d", min); break;
|
||||
case 166: sprintf(buf, "/dev/ttyACM%d", min); break; /* bummer, 9-char */
|
||||
case 172: sprintf(buf, "/dev/ttyMX%d", min); break;
|
||||
case 174: sprintf(buf, "/dev/ttySI%d", min); break;
|
||||
case 188: sprintf(buf, "/dev/ttyUSB%d", min); break; /* bummer, 9-char */
|
||||
case 204:
|
||||
if(min >= sizeof low_density_names / sizeof low_density_names[0]) return 0;
|
||||
memcpy(buf,"/dev/tty",8);
|
||||
memcpy(buf+8, low_density_names[min], sizeof low_density_names[0]);
|
||||
buf[8 + sizeof low_density_names[0]] = '\0';
|
||||
// snprintf(buf, 9 + sizeof low_density_names[0], "/dev/tty%.*s", sizeof low_density_names[0], low_density_names[min]);
|
||||
break;
|
||||
case 208: sprintf(buf, "/dev/ttyU%d", min); break;
|
||||
case 216: sprintf(buf, "/dev/ttyUB%d", min); break; // "/dev/rfcomm%d" now?
|
||||
case 224: sprintf(buf, "/dev/ttyY%d", min); break;
|
||||
case 227: sprintf(buf, "/dev/3270/tty%d", min); break; /* bummer, HUGE */
|
||||
case 229: sprintf(buf, "/dev/iseries/vtty%d", min); break; /* bummer, HUGE */
|
||||
case 256: sprintf(buf, "/dev/ttyEQ%d", min); break;
|
||||
default: return 0;
|
||||
}
|
||||
if(stat(buf, &sbuf) < 0) return 0;
|
||||
if(min != minor(sbuf.st_rdev)) return 0;
|
||||
if(maj != major(sbuf.st_rdev)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Linux 2.2 can give us filenames that might be correct.
|
||||
* Useful names could be in /proc/PID/fd/2 (stderr, seldom redirected)
|
||||
* and in /proc/PID/fd/255 (used by bash to remember the tty).
|
||||
*/
|
||||
static int link_name(char *restrict const buf, unsigned maj, unsigned min, int pid, const char *restrict name){
|
||||
struct stat sbuf;
|
||||
char path[32];
|
||||
ssize_t count;
|
||||
const int len = snprintf(path, sizeof path, "/proc/%d/%s", pid, name); /* often permission denied */
|
||||
if(len <= 0 || (size_t)len >= sizeof path) return 0;
|
||||
count = readlink(path,buf,TTY_NAME_SIZE-1);
|
||||
if(count <= 0 || count >= TTY_NAME_SIZE-1) return 0;
|
||||
buf[count] = '\0';
|
||||
if(stat(buf, &sbuf) < 0) return 0;
|
||||
if(min != minor(sbuf.st_rdev)) return 0;
|
||||
if(maj != major(sbuf.st_rdev)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef USE_PROC_CTTY
|
||||
/* Cygwin keeps the name to the controlling tty in a virtual file called
|
||||
/proc/PID/ctty, including a trailing LF (sigh). */
|
||||
static int ctty_name(char *restrict const buf, int pid) {
|
||||
char path[32];
|
||||
FILE *fp;
|
||||
char *lf;
|
||||
sprintf (path, "/proc/%d/ctty", pid); /* often permission denied */
|
||||
fp = fopen (path, "r");
|
||||
if (!fp)
|
||||
return 0;
|
||||
if (!fgets (buf,TTY_NAME_SIZE,fp))
|
||||
{
|
||||
fclose (fp);
|
||||
return 0;
|
||||
}
|
||||
fclose (fp);
|
||||
lf = strchr (buf, '\n');
|
||||
if (lf)
|
||||
*lf = (lf == buf ? '?' : '\0');
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* number --> name */
|
||||
unsigned dev_to_tty(char *restrict ret, unsigned chop, dev_t dev_t_dev, int pid, unsigned int flags) {
|
||||
static __thread char buf[TTY_NAME_SIZE];
|
||||
char *restrict tmp = buf;
|
||||
unsigned dev = dev_t_dev;
|
||||
unsigned i = 0;
|
||||
int c;
|
||||
#ifdef USE_PROC_CTTY
|
||||
if( ctty_name(tmp, pid )) goto abbrev;
|
||||
#endif
|
||||
if(dev == 0u) goto no_tty;
|
||||
if(driver_name(tmp, major(dev), minor(dev) )) goto abbrev;
|
||||
if( link_name(tmp, major(dev), minor(dev), pid, "fd/2" )) goto abbrev;
|
||||
if( guess_name(tmp, major(dev), minor(dev) )) goto abbrev;
|
||||
if( link_name(tmp, major(dev), minor(dev), pid, "fd/255")) goto abbrev;
|
||||
// fall through if unable to find a device file
|
||||
no_tty:
|
||||
strcpy(ret, chop >= 1 ? "?" : "");
|
||||
return 1;
|
||||
abbrev:
|
||||
if((flags&ABBREV_DEV) && !strncmp(tmp,"/dev/",5) && tmp[5]) tmp += 5;
|
||||
if((flags&ABBREV_TTY) && !strncmp(tmp,"tty", 3) && tmp[3]) tmp += 3;
|
||||
if((flags&ABBREV_PTS) && !strncmp(tmp,"pts/", 4) && tmp[4]) tmp += 4;
|
||||
/* gotta check before we chop or we may chop someone else's memory */
|
||||
if(chop + (unsigned long)(tmp-buf) < sizeof buf)
|
||||
tmp[chop] = '\0';
|
||||
/* replace non-ASCII characters with '?' and return the number of chars */
|
||||
while(i < chop){
|
||||
c = *tmp;
|
||||
tmp++;
|
||||
if(!c) break;
|
||||
i++;
|
||||
if(c<=' ') c = '?';
|
||||
if(c>126) c = '?';
|
||||
*ret = c;
|
||||
ret++;
|
||||
}
|
||||
*ret = '\0';
|
||||
return i;
|
||||
}
|
Reference in New Issue
Block a user