| /* |
| * lspci - written by Isaac Dunham |
| |
| USE_LSPCI(NEWTOY(lspci, "emkn@", TOYFLAG_USR|TOYFLAG_BIN)) |
| |
| config LSPCI |
| bool "lspci" |
| default n |
| help |
| usage: lspci [-ekmn@] |
| |
| List PCI devices. |
| -e Print all 6 digits in class (like elspci) |
| -k Print kernel driver |
| -m Machine parseable format |
| -n Numeric output |
| |
| config LSPCI_TEXT |
| bool "lspci readable output" |
| depends on LSPCI |
| default n |
| help |
| lspci without -n prints readable descriptions; |
| lspci -nn prints both readable and numeric description |
| */ |
| #define FOR_lspci |
| #include "toys.h" |
| extern int find_in_db(char * , char * , FILE * , char * , char * ); |
| |
| GLOBALS( |
| long numeric; |
| |
| FILE * db; |
| ) |
| |
| char * id_check_match(char * id, char * buf) |
| { |
| int i = 0; |
| while (id[i]) { |
| if (id[i] == buf[i]) { |
| i++; |
| } else { |
| return (char *)0L; |
| } |
| } |
| return (buf + i + 2); |
| } |
| |
| /* |
| * In: vendid, devid, fil |
| * Out: vname, devname |
| * Out must be zeroed before use. |
| * vmame and devname must be char[256], zeroed out |
| * Returns (2 - number of IDs matched): vendor must be matched for |
| * dev to be matched |
| */ |
| int find_in_db(char * vendid, char * devid, FILE * fil, |
| char * vname, char * devname) |
| { |
| fseek(fil, 0, SEEK_SET); |
| char buf[256], *vtext = 0L, *dtext = 0L; |
| while (!(vname[0])) { |
| //loop through |
| if (fgets(buf, 255, fil)==NULL) return 2; |
| if ((vtext = id_check_match(vendid, buf))) |
| strncpy(vname, vtext, strlen(vtext) - 1); |
| } |
| while (!(devname[0])) { |
| if ((fgets(buf, 255, fil)==NULL) || (buf[0] != '\t' )) |
| return 1; |
| if ((dtext = id_check_match(devid, buf + 1))) |
| strncpy(devname, dtext, strlen(dtext) - 1); |
| } |
| return 0; /* Succeeded in matching both */ |
| } |
| |
| int do_lspci(struct dirtree *new) |
| { |
| int alen = 8, dirfd, res = 2; //no textual descriptions read |
| char *dname = dirtree_path(new, &alen); |
| memset(toybuf, 0, 4096); |
| struct { |
| char class[16], vendor[16], device[16], module[256], |
| vname[256], devname[256]; |
| } *bufs = (void*)(toybuf + 2); |
| |
| if (!strcmp("/sys/bus/pci/devices", dname)) return DIRTREE_RECURSE; |
| errno = 0; |
| dirfd = open(dname, O_RDONLY); |
| if (dirfd > 0) { |
| char *p, **fields = (char*[]){"class", "vendor", "device", ""}; |
| |
| for (p = toybuf; **fields; p+=16, fields++) { |
| int fd, size; |
| |
| if ((fd = openat(dirfd, *fields, O_RDONLY)) < 0) continue; |
| size = ((toys.optflags & FLAG_e) && (p == toybuf)) ? 8 : 6; |
| p[read(fd, p, size)] = '\0'; |
| close(fd); |
| } |
| |
| close(dirfd); |
| if (!errno) { |
| char *driver = ""; |
| char *fmt = toys.optflags & FLAG_m ? "%s, \"%s\" \"%s\" \"%s\" \"%s\"\n" |
| : "%s Class %s: %s:%s %s\n"; |
| |
| if (toys.optflags & FLAG_k) { |
| strcat(dname, "/driver"); |
| if (readlink(dname, bufs->module, sizeof(bufs->module)) != -1) |
| driver = basename(bufs->module); |
| } |
| if (CFG_LSPCI_TEXT && (TT.numeric != 1)) { |
| res = find_in_db(bufs->vendor, bufs->device, TT.db, |
| bufs->vname, bufs->devname); |
| } |
| if (CFG_LSPCI_TEXT && (TT.numeric == 2)) { |
| fmt = toys.optflags & FLAG_m |
| ? "%s, \"%s\" \"%s [%s]\" \"%s [%s]\" \"%s\"\n" |
| : "%s Class %s: %s [%s] %s [%s] %s\n"; |
| printf(fmt, new->name + 5, bufs->class, bufs->vname, bufs->vendor, |
| bufs->devname, bufs->device, driver); |
| } else { |
| printf(fmt, new->name + 5, bufs->class, |
| (res < 2) ? bufs->vname : bufs->vendor, |
| !(res) ? bufs->devname : bufs->device, driver); |
| } |
| |
| } |
| } |
| return 0; |
| } |
| |
| void lspci_main(void) |
| { |
| if (CFG_LSPCI_TEXT && (TT.numeric != 1)) { |
| TT.db = fopen("/usr/share/misc/pci.ids", "r"); |
| if (errno) { |
| TT.numeric = 1; |
| error_msg("could not open PCI ID db"); |
| } |
| } |
| |
| dirtree_read("/sys/bus/pci/devices", do_lspci); |
| } |