Question

J'essaie d'écrire un programme de contrôle à distance pour omxplayer sur mon Raspberry Pi

Je peux faire fonctionner omxplayer correctement dans un processus enfant, mais je ne semble pas être en mesure de faire fonctionner correctement les canaux pour envoyer des commandes au processus enfant.

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

Lorsque j'ai testé avec top et exécuté le programme, je peux voir la sortie top apparaître dans la fenêtre du terminal et je peux voir la commande q dans la fenêtre, mais il semble qu'elle soit dirigée vers le processus parent plutôt que vers l'enfant.Est-ce que je fais quelque chose de mal avec les tuyaux ou n'est-il pas possible d'envoyer des commandes au processus enfant généré ?

J'ai essayé de changer l'instruction child dup2 pour la copier du tube vers stdin

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

Mais ensuite, top ne parvient pas à démarrer avec un message d'échec de réception du tty

Était-ce utile?

La solution

Pour interagir avec un programme qui s'attend à pouvoir manipuler un terminal, vous devez utiliser un pseudo tty.Cela évitera le failed tty get erreur.

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

Noter que forkpty n'est pas POSIX, mais une interface disponible sur les versions BSD et Linux d'UNIX.

Vous pouvez exécuter top en mode batch, mais vous ne pouvez pas utiliser de commande pour quitter.Vous devez le tuer.

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

Bien que l'exécution en mode batch vous permettrait d'ouvrir le processus avec un appel plus simple (comme popen comme mux le suggère), à ​​moins que cet appel ne renvoie l'identifiant du processus de l'enfant, vous ne pourrez pas le tuer (sans exécuter un pkill, ou parcourez la table des processus pour trouver le bon processus enfant à tuer).

Je pense que vous avez une certaine confusion sur la façon d'utiliser dup2.La page de manuel utilise les termes oldfd et newfd, et ça veut dire que oldfd va devenir newfd.Pour illustrer, voici un programme simple qui redirige stdout et stderr vers un fichier journal, appelle une fonction, puis restaure ensuite stdout et 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;
}

Comme mux l'a souligné, votre programme écrit au mauvais bout du canal.Le pipe La commande renvoie une paire unidirectionnelle de descripteurs de fichiers, où tout ce qui est écrit fd_pipe[1] peut être lu à partir de fd_pipe[0].

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top