Domanda

Sto cercando di scrivere un programma di controllo remoto per OMXPlayer sul mio rasperry PI

Posso ottenere OmxPlayer a funzionare OK in un processo figlio ma non sembra essere in grado di far funzionare i tubi correttamente per inviare effettivamente comandi al processo figlio.

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);
    }
}
.

Quando stavo testando con Top e correva il programma, posso vedere l'uscita superiore appaita nella finestra del terminale e posso vedere il comando q nella finestra, ma sembra che sia andato al processo genitore piuttosto che al bambino.Sto facendo qualcosa di sbagliato con i tubi o non è possibile inviare comandi al processo figlio generato?

Ho provato a cambiare la dichiarazione del figlio DUP2 per copiare dal tubo a STDIN

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

Ma quindi la parte superiore non riesce a iniziare con un messaggio Tty fallito

È stato utile?

Soluzione

Per interagire con un programma che si aspetta di essere in grado di manipolare un terminale, dovresti usare un pseudo TTY. Questo eviterà l'errore failed tty get.

/*...*/
#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;
}
.

Nota che forkpty non è POSIX, ma un'interfaccia disponibile su BSD e Linux Sapori di Unix.

È possibile eseguire top in modalità batch, ma non è possibile utilizzare un comando per uscire. Devi ucciderlo.

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;
}
.

Sebbene in esecuzione in modalità batch ti consenta di aprire il processo con una chiamata più semplice (ad esempio popen come suggerisce MUX), a meno che tale chiamata non ritorna l'ID di processo del bambino, non sarà possibile ucciderlo (senza Esecuzione di un pkill o scavare attraverso la tabella dei processi per trovare il giusto processo figlio da uccidere).

Penso che tu abbia una certa confusione su come usare dup2. La pagina manuale utilizza i termini oldfd e newfd e significa che oldfd diventerà newfd. Per illustrare, ecco un semplice programma che reindirizza Stdout e Stderr a un file di registro, chiama una funzione, quindi ripristina lo stdout e Stderr in seguito.

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;
}
.

Come sottolineato MUX, il tuo programma scrive sulla parte sbagliata del tubo. Il comando pipe restituisce una coppia unidirezionale di descrittori di file, dove ciò che è mai stato scritto su fd_pipe[1] può essere letto da fd_pipe[0].

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top