Fscanf不使用execl通过管道输出从fdopen分配的流中读取任何值

时间:2017-09-26 03:06:12

标签: c file struct pipe scanf

我正在尝试从usb-devices获取输出并解析它以将其分配给一个简单的结构。但是,我只是无法让fscanf正确读取输出中的值。这是有问题的功能:

struct Devices* getDevices() {

  int pipes[2];
  pid_t pid;

  if (pipe(pipes)==-1)
    die("Failed to create pipe");

  if ((pid = fork()) == -1)
    die("Could not fork process");

  if(pid == 0) {
    dup2 (pipes[1], STDOUT_FILENO);
    close(pipes[0]);
    close(pipes[1]);
    execl("/bin/usb-devices", "usb-devices", (char *)0);
  }
  else {
    close(pipes[1]);
    wait(NULL);
  }

  FILE *rawList = fdopen(pipes[0],"r");

  if (rawList == NULL)
    die("Failed to open file");

  fpos_t pos;
  int pos_init = 0;

  struct Devices *deviceList = malloc(sizeof(struct Devices));
  if(!deviceList) die ("Memory error");

  int i;
  int conn;
  int iBus = -1;
  int iPort = -1;

  for (i = 0; !feof(rawList); i++) {
    if (pos_init) fsetpos(rawList, &pos);

    conn = fscanf(rawList, "T:  Bus=%d Lev=%*d Prnt=%*d Port=%d Cnt=%*d Dev#=  %*d Spd=%*d MxCh= %*d",
          &iBus, &iPort);
    if (!conn) {
      printf("bus%d port%d num %i", iBus, iPort, i);
      deviceList->devNum[i].set = 1;
      deviceList->devNum[i].bus = iBus;
      deviceList->devNum[i].port = iPort;

      fgetpos (rawList,&pos); 
      pos_init = 1;
    }
  }        

  fclose(rawList);

  return deviceList;
}

快速解释应该发生的事情。我正在创建一个管道,所以我可以抓取我正在运行的命令的输出,然后在它运行后我尝试将它放在一个名为rawList的流中通过fdopen。然后,我为结构我malloc一块内存,我将分配我得到的值。

然后,在for循环中,它应检查以“T:”开头的行,其中包含我想要的数据,然后它应该采用usb-devices的输出给我的整数并将其分配给struct每台设备。最后,它应该保存它停止读取的点,以便它可以继续从那里读取以找到我正在寻找的下一行。

printf在那里试图弄清楚发生了什么。它最终打印“-1”,这是在for循环之前分配的值,这告诉我fscanf没有为我的变量赋值。 “我”只是指望程序段错误并最终退出。我不确定该值是否有意义,但Valgrind一直告诉我5个上下文中有77408个错误(main只是运行这个函数,代码中唯一的其他东西是struct声明,die函数和main本身)

当这个过程终于退出时,Valgrind给了我这个:

==11278== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==11278==  Access not within mapped region at address 0x55F0040
==11278==    at 0x108C7A: getDevices (usbDeviceList.c:77)
==11278==    by 0x108D4C: main (usbDeviceList.c:103)

第77行就是这个

deviceList->devNum[i].set = 1;

打印的“i”的最后一个值是15644。

任何和所有帮助都表示赞赏,我已经四处询问,似乎没有人知道发生了什么。我将列出我用来写这篇文章的SO资源:

Grabbing output from exec

easy way to parse a text file?

更新

根据要求,这是结构:

struct deviceData {
  int set;
  int bus;
  int port;
  char manufacturer[MAX_LENGTH_U];
  char product[MAX_LENGTH_U];
};

struct Devices {
  struct deviceData devNum[MAX_DEVICES_U];
};

1 个答案:

答案 0 :(得分:0)

fscanf()实际上有效时,您的代码不会发出任何输出。每the fscanf() documentation

  

返回值

     

成功完成后,这些功能将返回数字   成功匹配并分配输入项目。 ...

这个循环错了:

 for (i = 0; !feof(rawList); i++) {
    if (pos_init) fsetpos(rawList, &pos);

    // if this works, it returns 2
    conn = fscanf(rawList, "T:  Bus=%d Lev=%*d Prnt=%*d Port=%d Cnt=%*d Dev#=  %*d Spd=%*d MxCh= %*d",
          &iBus, &iPort);
    if (!conn) {

      // these only get called if conn is zero!
      printf("bus%d port%d num %i", iBus, iPort, i);
      deviceList->devNum[i].set = 1;
      deviceList->devNum[i].bus = iBus;
      deviceList->devNum[i].port = iPort;

      fgetpos (rawList,&pos); 
      pos_init = 1;
    }
  }

正如评论中所指出的,管道上的fsetpos()是无用的。