xref: /third_party/toybox/toys/other/lspci.c (revision 0f66f451)
1/*
2 * lspci - written by Isaac Dunham
3
4USE_LSPCI(NEWTOY(lspci, "emkn"USE_LSPCI_TEXT("@i:"), TOYFLAG_USR|TOYFLAG_BIN))
5
6config LSPCI
7  bool "lspci"
8  default y
9  help
10    usage: lspci [-ekm]
11
12    List PCI devices.
13
14    -e	Print all 6 digits in class
15    -k	Print kernel driver
16    -m	Machine readable format
17
18config LSPCI_TEXT
19  bool "lspci readable output"
20  depends on LSPCI
21  default y
22  help
23    usage: lspci [-n] [-i FILE ]
24
25    -n	Numeric output (repeat for readable and numeric)
26    -i	PCI ID database (default /usr/share/misc/pci.ids)
27
28*/
29
30#define FOR_lspci
31#include "toys.h"
32
33GLOBALS(
34  char *i;
35  long n;
36
37  FILE *db;
38)
39
40static int do_lspci(struct dirtree *new)
41{
42  char *p = toybuf, *vendor = toybuf+9, *device = toybuf+18,
43       driver[256], *vbig = 0, *dbig = 0, **fields;
44  int dirfd;
45
46  if (!new->parent) return DIRTREE_RECURSE;
47
48  // Parse data out of /proc
49
50  if (-1 == (dirfd = openat(dirtree_parentfd(new), new->name, O_RDONLY)))
51    return 0;
52
53  *driver = 0;
54  if (FLAG(k)) readlinkat0(dirfd, "driver", driver, sizeof(driver));
55
56  for (fields = (char*[]){"class", "vendor", "device", 0}; *fields; fields++) {
57    int fd, size = 6 + 2*(FLAG(e) && p == toybuf);
58    *p = 0;
59
60    if (-1 == (fd = openat(dirfd, *fields, O_RDONLY))) {
61      close(dirfd);
62      return 0;
63    }
64    xreadall(fd, p, size);
65    memmove(p, p+2, size -= 2);
66    p[size] = 0;
67    close(fd);
68    p += 9;
69  }
70
71  close(dirfd);
72
73  // Lookup/display data from pci.ids?
74
75  if (CFG_LSPCI_TEXT && TT.db) {
76    if (TT.n != 1) {
77      char *s;
78
79      fseek(TT.db, 0, SEEK_SET);
80      while (!vbig || !dbig) {
81        s = p;
82        if (!fgets(s, sizeof(toybuf)-(p-toybuf)-1, TT.db)) break;
83        while (isspace(*s)) s++;
84        if (*s == '#') continue;
85        if (vbig && s == p) break;
86        if (strstart(&s, vbig ? device : vendor)) {
87          if (vbig) dbig = s+2;
88          else vbig = s+2;
89          s += strlen(s);
90          s[-1] = 0; // trim ending newline
91          p = s + 1;
92        }
93      }
94    }
95
96    if (TT.n > 1) {
97      printf(FLAG(m) ? "%s, \"%s\" \"%s [%s]\" \"%s [%s]\""
98        : "%s Class %s: %s [%s] %s [%s]",
99        new->name+5, toybuf, vbig ? vbig : "", vendor,
100        dbig ? dbig : "", device);
101
102      goto driver;
103    }
104  }
105
106  printf(FLAG(m) ? "%s \"%s\" \"%s\" \"%s\"" : "%s Class %s: %s:%s",
107    new->name+5, toybuf, vbig ? vbig : vendor, dbig ? dbig : device);
108
109driver:
110  if (*driver) printf(FLAG(m) ? " \"%s\"" : " %s", basename(driver));
111  xputc('\n');
112
113  return 0;
114}
115
116void lspci_main(void)
117{
118  if (CFG_LSPCI_TEXT && TT.n != 1) {
119    if (!TT.i) TT.i = "/usr/share/misc/pci.ids";
120    if (!(TT.db = fopen(TT.i, "r"))) perror_msg("%s", TT.i);
121  }
122
123  dirtree_read("/sys/bus/pci/devices", do_lspci);
124}
125