posix_spawn 和管道(stdin、stdout、stderr),不一致错误

问题描述 投票:0回答:1

阅读手册页和几个 stackoverflow/stackexchange 页面,我正在研究 posix_spawn 和管道。然而,我遇到了一个问题。 以下代码,三个管道(stdin、stdout、stderr)看起来工作正常。问题是

rv = write(stdin_pipe[PIPE_TO]...
返回错误 - “没有这样的文件或目录”。奇怪的是,如果在 codelite(一个 ide)中运行,这段代码可以正常工作(没有错误)。我不确定这段代码是否好。它会导致内存泄漏或一些灾难吗?

我很感激任何建议。我对这段代码的意图是向

grep 1
抛出一些字符串,然后捕获标准输出。

#include <spawn.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>

#define PIPE_TO 1
#define PIPE_FROM 0

int main(int argc, char** argv, char** envv){
  int   exit_code;
  int   stdout_pipe[2], stderr_pipe[2], stdin_pipe[2];
  posix_spawn_file_actions_t    *action, act;
  char  *args[4];
  char  *argsmem[] = {"sh", "-c"};
  int   rv;
  char  inbuf[] = "1\na\n3\nb\n5\n6\n7\n8\n9\n10\n11\n12\n\0";
  char  cmd[] = "grep 1";
  action = &act;

  if(pipe(stdout_pipe) || pipe(stderr_pipe) || pipe(stdin_pipe))
      printf("pipe returned an error.\n");

  posix_spawn_file_actions_init(action);
  posix_spawn_file_actions_addclose(action, stdout_pipe[PIPE_FROM]);
  posix_spawn_file_actions_addclose(action, stderr_pipe[PIPE_FROM]);
  posix_spawn_file_actions_addclose(action, stdin_pipe[PIPE_TO]);

  posix_spawn_file_actions_adddup2(action, stdout_pipe[PIPE_TO], STDOUT_FILENO);
  posix_spawn_file_actions_adddup2(action, stderr_pipe[PIPE_TO], STDERR_FILENO);
  posix_spawn_file_actions_adddup2(action, stdin_pipe[PIPE_FROM], STDIN_FILENO);

  posix_spawn_file_actions_addclose(action, stdout_pipe[PIPE_TO]);
  posix_spawn_file_actions_addclose(action, stderr_pipe[PIPE_TO]);
  posix_spawn_file_actions_addclose(action, stdin_pipe[PIPE_FROM]);

  args[0] = argsmem[0];
  args[1] = argsmem[1];
  args[2] = cmd;
  args[3] = NULL;

  pid_t   pid;

  if(posix_spawnp(&pid, args[0], action, NULL, args, NULL))
      printf("posix_spawnp failed with error: %s\n", strerror(errno));

  rv = write(stdin_pipe[PIPE_TO], inbuf, strlen(inbuf));
  printf("rv = %d, errno = %d %s\n", rv, errno, strerror(errno));
  close(stdin_pipe[PIPE_TO]);

  close(stdout_pipe[PIPE_TO]);
  close(stderr_pipe[PIPE_TO]);
  close(stdin_pipe[PIPE_FROM]);

  char  buffer[1001];
  struct pollfd plist[2];
  int   rval, bytes_read;
  int   i;

  plist[0].fd = stdout_pipe[PIPE_FROM];
  plist[0].events = POLLIN;
  plist[1].fd = stderr_pipe[PIPE_FROM];
  plist[1].events = POLLIN;

  while(rval = poll(plist, 2, -1)){
    if(plist[0].revents & POLLIN){
      i = 0;
      while(bytes_read = read(stdout_pipe[PIPE_FROM], buffer, 1000)){
        i += bytes_read;
        buffer[bytes_read] = '\0';
        printf("%s", buffer);
        }
      printf("\nread %d bytes from stdout.\n", i);
      }
    else if(plist[1].revents & POLLIN){
      i = 0;
      while(bytes_read = read(stderr_pipe[PIPE_FROM], buffer, 1000)){
        i += bytes_read;
        buffer[bytes_read] = '\0';
        printf("%s", buffer);
        }
      printf("\nread %d bytes from stderr.\n", i);
      }
    else break;
    }

  waitpid(pid, &exit_code, 0);
  printf("exit code: %d\n", exit_code);

  posix_spawn_file_actions_destroy(action);
  }

我的系统是Linux,Debian amd64测试。摆弄 inbuf 和 cmd,看起来 stdout 和 stderr 都不错。

我尝试了几种设置(都是 debian amd64 测试),但没有解决。我不想期待未来发生任何灾难。

c gcc pipe posix codelite
1个回答
0
投票
  rv = write(stdin_pipe[PIPE_TO], inbuf, strlen(inbuf));
  printf("rv = %d, errno = %d %s\n", rv, errno, strerror(errno));

是错误的。仅当系统调用失败时,测试

errno
才有意义,即
rv == -1
。还要注意,成功的系统调用不会
errno
重置为0,因此
ENOENT
(“没有这样的文件或目录”)是之前某个错误的遗留问题(顺便说一句,
write
不可能返回
ENOENT
) ).

在这种情况下,罪魁祸首是

posix_spawnp
。当然,它并没有失败,但是在各个目录中查找
sh
时,它发生了一些失败的调用。我对 codelite 不熟悉,但很可能它的
PATH
是不同的,并且
sh
位于第一个目录中。

© www.soinside.com 2019 - 2024. All rights reserved.