view toys/pending/lspci.c @ 1387:a0d26c5e3271 draft

Release notes for 0.4.9.
author Rob Landley <rob@landley.net>
date Mon, 07 Jul 2014 07:32:56 -0500
parents bc618abf4fb2
children e36306d6eece
line wrap: on
line source

/*
 * lspci - written by Isaac Dunham

USE_LSPCI(NEWTOY(lspci, "emkn"USE_LSPCI_TEXT("@i:"), TOYFLAG_USR|TOYFLAG_BIN))

config LSPCI
  bool "lspci"
  default n
  help
    usage: lspci [-ekm]

    List PCI devices.

    -e	Print all 6 digits in class (like elspci)
    -k	Print kernel driver
    -m	Machine parseable format

config LSPCI_TEXT
  bool "lspci readable output"
  depends on LSPCI
  default n
  help
    usage: lspci [-n] [-i FILE ]

    -n	Numeric output (repeat for readable and numeric)
    -i	PCI ID database (default /usr/share/misc/pci.ids)

*/

#define FOR_lspci
#include "toys.h"

GLOBALS(
  char *ids;
  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 0;
  }

  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)
{
  char buf[256], *vtext = 0L, *dtext = 0L;

  fseek(fil, 0, SEEK_SET);
  while (!*vname) {
    //loop through
    if (!fgets(buf, 255, fil)) return 2;
    if ((vtext = id_check_match(vendid, buf)))
      strncpy(vname, vtext, strlen(vtext) - 1);
  }
  while (!*devname) {
    if (!fgets(buf, 255, fil) || (*buf != '\t' && *buf != '#')) return 1;
    if (*buf == '#') continue;
    if ((dtext = id_check_match(devid, buf + 1)))
      strncpy(devname, dtext, strlen(dtext) - 1);
  }

  // matched both
  return 0;
}

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 (!new->parent) 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 = ((toys.optflags & FLAG_e) && p == toybuf) ? 8 : 6;

      if ((fd = openat(dirfd, *fields, O_RDONLY)) < 0) continue;
      xread(fd, p, size);
      close(fd);

      p[size] = 0;
    }

    close(dirfd);
    if (errno) return 0;

    {
      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 > 1) {
        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(TT.ids ? TT.ids : "/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);
}