execve() 从文件重定向标准输入

execve() with redirected stdin from file

想要将标准输入重定向到 execve() 中的文件。所以程序应该像这样执行,我的意思是我在 shell 中是这样执行的并且它有效:

/opt/prog < in.txt

下面是我写的代码,但是好像不行。 in.txt 是二进制文件,我想在执行的程序中将它重定向到标准输入。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
    int fd[2];
    pid_t pid;


    FILE *f = fopen("in.txt", "rb");

    if (pipe(fd) < 0)
        return EXIT_FAILURE;

    if ((pid = fork()) < 0)
        return EXIT_FAILURE;
    else if (pid != 0) { /* father */
        close(fd[1]);
        dup2(fd[0], STDIN_FILENO);
        execlp("/opt/prog", "prog", (char *)0);
        printf("done\n");
    } else { /* son */

        fseek(f, 0, SEEK_END);
        long fsize = ftell(f);
        fseek(f, 0, SEEK_SET);

        char *string = malloc(fsize + 1);
        fread(string, fsize, 1, f);
        fclose(f);
        close(fd[0]);
        write(fd[1], string, 11);
    }

    return EXIT_SUCCESS;
}

更新 1:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
    int fd[2];
    pid_t pid;

    FILE *f = fopen("in.txt", "rb");

    if (pipe(fd) < 0)
        return EXIT_FAILURE;

    if ((pid = fork()) < 0)
        return EXIT_FAILURE;
    else if (pid != 0) { /* father */
        fseek(f, 0, SEEK_END);
        long fsize = ftell(f);
        fseek(f, 0, SEEK_SET);

        char *string = malloc(fsize + 1);
        fread(string, fsize, 1, f);
        fclose(f);
        close(fd[0]);
        write(fd[1], string, 11);

    } else { /* son */
        close(fd[1]);
        dup2(fd[0], STDIN_FILENO);
        execlp("/opt/prog", "prog", (char *)0);
        printf("done\n");

    }

    return EXIT_SUCCESS;
}

如果您只是想让进程从文件中读取,则不需要 pipe:只需 dup2 STDIN_FILENO 上的文件描述符。你也想在 parentexeclp 因为否则当你的 child 时 prog 会变得意外 SIGCHLD退出...

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>

int main(void)
{
    pid_t pid;
    int fd;

    fd = open("in.txt", O_RDONLY);
    if (fd < 0) {
        perror("open");
        return EXIT_FAILURE;
    }

    if ((pid = fork()) < 0) {
        perror("fork");
        return EXIT_FAILURE;
    } else if (! pid) { /* child */
        dup2(fd, STDIN_FILENO);
        close(fd);
        execlp("/opt/prog", "prog", (char *)0);
        perror("exec");
        return EXIT_FAILURE;
    } else { /* parent */
        close(fd);
        printf("Parent waiting\n");
        getchar();
    }

    return EXIT_SUCCESS;
}

我喜欢上面的解决方案,但是如果你只想执行 execve,并在完成后退出。你必须在父进程中使用 wait 直到子进程退出。

    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    int main(int argc, char **argv) {
      int fd, status;
      pid_t child_pid;
      char c;
      char *args[2] = {"/opt/prog", NULL};

      if (argc != 2)
        exit(1);
      fd = open(argv[1], O_RDONLY);
      child_pid = fork();
      if (child_pid == 0) {
        if (dup2(fd, STDIN_FILENO) == -1) {
          perror("dup2");
          return (EXIT_FAILURE);
        }
        close(fd);
        execve(args[0], args, NULL);
      }
      if (child_pid != 0) {
        close(fd);
        wait(&status);
      }
      return (EXIT_SUCCESS);
    }