Pregunta

Estoy intentando escribir un programa de control remoto para omxplayer en mi rasperry Pi

Puedo hacer que omxplayer se ejecute correctamente en un proceso secundario, pero parece que no puedo hacer que las tuberías funcionen correctamente para enviar comandos al proceso secundario.

int fd_pipe[2];
pipe (fd_pipe);

while(1) {  // main accept() loop

    printf("server: got connection from %s\n", s);

    /* Attempt to fork and check for errors */
    if( (pid=fork()) == -1){
        fprintf(stderr,"Fork error. Exiting.\n");  /* something went wrong */
        exit(1);
    }

    if (pid==0) 
    { // this is the child process
        dup2(0, fd_pipe[0]);
        close(fd_pipe[1]);


        if(execl("/usr/bin/top","top",NULL) == -1){
            fprintf(stderr,"execl Error!");
            exit(1);
        }

        //try and send command here
        write(fd_pipe[0], "q", 1);

        exit(0);

    } else {

        close(new_fd);  // parent doesn't need this
        dup2(1, fd_pipe[1]);

        //try and send here too
        write(fd_pipe[0], "q", 1);
    }
}

Cuando estaba probando con top y ejecuté el programa, puedo ver aparecer la salida superior en la ventana del terminal y puedo ver el comando q en la ventana, pero parece que va al proceso principal en lugar del secundario.¿Estoy haciendo algo mal con las tuberías o no es posible enviar comandos al proceso secundario generado?

Intenté cambiar la declaración secundaria dup2 para copiarla desde la tubería a la entrada estándar.

        { // this is the child process
        dup2(fd_pipe[0], 0);

Pero luego la parte superior no puede comenzar con un mensaje tty fallido.

¿Fue útil?

Solución

Para interactuar con un programa que espera poder manipular una terminal, debes usar un pseudo tty.Esto evitará la failed tty get error.

/*...*/
#include <pty.h>

void do_child () {
    if (execlp("top", "top", (const char *)0) < 0) {
        perror("exec top");
        exit(EXIT_FAILURE);
    }
    /* NOTREACHED */
}

void do_parent (int fd, pid_t p) {
    sleep(5);
    char r;
    write(fd, "q", 1);
    while (read(fd, &r, 1) > 0) { write(1, &r, 1); }
    waitpid(p, 0, 0);
    close(fd);
}

int main () {
    int fd;
    pid_t p = forkpty(&fd, 0, 0, 0);
    switch (p) {
    case 0:  do_child();
             /* NOTREACHED */
    case -1: perror("forkpty");
             exit(EXIT_FAILURE);
    default: break;
    }
    do_parent(fd, p);
    return 0;
}

Tenga en cuenta que forkpty no es POSIX, sino una interfaz que está disponible en las versiones BSD y Linux de UNIX.

puedes ejecutar top en modo por lotes, pero no puede usar un comando para salir.Tienes que matarlo.

void do_child () {
    if (execlp("top", "top", "-b", (const char *)0) < 0) {
        perror("exec top");
        exit(EXIT_FAILURE);
    }
    /* NOT REACHED */
}

void do_parent (pid_t p) {
    sleep(5);
    if (kill(p, SIGINT) < 0) {
        perror("kill");
        exit(EXIT_FAILURE);
    }
    waitpid(p, 0, 0);
}

int main () {
    pid_t p;
    switch ((p = fork())) {
    case 0:  do_child();
    case -1: perror("fork"); exit(EXIT_FAILURE);
    default: break;
    }
    do_parent(p);
    return 0;
}

Aunque ejecutarlo en modo por lotes le permitiría abrir el proceso con una llamada más simple (como popen como sugiere mux), a menos que esa llamada devuelva la identificación del proceso del niño, no podrá eliminarlo (sin ejecutar un pkill, o explore la tabla de procesos para encontrar el proceso secundario correcto para eliminar).

Creo que tienes cierta confusión sobre cómo usar dup2.La página del manual utiliza los términos oldfd y newfd, y significa que oldfd se convertirá newfd.Para ilustrar, aquí hay un programa simple que redirige stdout y stderr a un archivo de registro, llama a una función y luego restaura stdout y stderr.

void do_something () {
    fputs("Error message\n", stderr);
    puts("This is regular output.");
    fputs("Error message\n", stderr);
    puts("This is regular output.");
}

int main () {
    int fd = creat("/tmp/output.log", 0664);
    int outfd = dup(fileno(stdout));
    int errfd = dup(fileno(stderr));
    fflush(stdout);
    fflush(stderr);
    dup2(fd, fileno(stdout));
    dup2(fd, fileno(stderr));
    setlinebuf(stdout);

    do_something();

    fflush(stdout);
    fflush(stderr);
    dup2(outfd, fileno(stdout));
    dup2(errfd, fileno(stderr));
    close(outfd);
    close(errfd);

    fputs("Error to the screen\n", stderr);
    puts("Regular output to screen");
    fputs("Error to the screen\n", stderr);
    puts("Regular output to screen");

    return 0;
}

Como señaló mux, su programa está escribiendo en el extremo equivocado de la tubería.El pipe El comando devuelve un par unidireccional de descriptores de archivos, donde lo que se escribe fd_pipe[1] se puede leer desde fd_pipe[0].

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top