1

I am trying to implement a pager in C, I want the code to open another terminal (xterm) and print some outputs in it.

So I first create a pipe and fork the main program, the child will execute xterm with the tail command, the main program will output things in the pipe and the child before executing xterm will dupplicate associate the pipe out with the stdin file descriptor of the child.

I may have misunderstood the usage of pipe and dup2 because my code doesn't work.

int p[2];
pipe(p);
char buff[512];
switch (fork()) {
    case -1:
        fprintf(stderr, "Fork error.\n");
        break;
    case 0:
        dup2(p[0], 0);
        close(p[0]);
        close(p[1]);
        execlp("xterm", "xterm", "tail", NULL);
        break; 
    default:
        scanf("%s", buff);
        write(p[1], buff, strlen(buff));
        getchar();
        break;
}

For now I type something in the parent and nothing is printed, in both process. So how do I create a communication between xterm and the parent process ?

Edit: a sample of my program:

#define VERBM_NOVERB 0
#define VERBM_STDOUT 1
#define VERBM_XTERMO 2

static int fd_xterm = -1;

void init_outputxterm() {
    mkfifo("/tmp/mypipe", 0600);
    switch (fork()) {
        case -1:
            fprintf(stderr, "Fork error.\n");
            break;
        case 0:
            execlp("xterm", "xterm", "-e", "/usr/bin/tail -f /tmp/mypipe", NULL);
            printf("FAILURE\n");
            exit(EXIT_FAILURE);
            break; 
        default:
            if ((fd_xterm = open("/tmp/mypipe", O_WRONLY)) == -1) {
                fprintf(stderr, "Can't open pipe");
                exit(1);
            }
            write(fd_xterm, "yayay\n", 6);
            dprintf(fd_xterm, "Hello world\n");
            getchar();
            break;
    }
}

void verbose_xterm(char *format, ...) {
    dprintf(fd_xterm, BOLD UNDERLINED "verbose - " RESET);
    va_list aptr;
    va_start(aptr, format);
    dprintf(fd_xterm, format, aptr);
    va_end(aptr);
}


void verbose_stdout(char *format, ...) {
    printf(BOLD UNDERLINED "verbose - " RESET);
    va_list aptr;
    va_start(aptr, format);
    vprintf(format, aptr);
    va_end(aptr);
}

void verbose_noverb(char *format, ...) {
}

void (*verbose)(char *format, ...) = verbose_stdout;


void (*verbose_mode[])(char *, ...) = { 
    verbose_noverb,
    verbose_stdout,
    verbose_xterm
};

void verbosity(int mode) {
    if (mode == VERBM_XTERMO)
        init_outputxterm();
    verbose = verbose_mode[mode];
}

In the main:

verbosity(VERBM_XTERMO);

Followed by several calls to verbose. You can see in init_outputxterm a tentavie to write in xterm just after the creation of xterm, like in the solution. But everything displayed only after I quit the program by closing the main terminal brutaly, making the child process orphan (if I quit with Ctrl-C the child is also killed).

1 Answers1

2

Xterm itself doesn't read from stdin, so feeding data to it will not have an effect. But you could open a named pipe and read with tail -f /tmp/mypipe from it, for example like this:

mkfifo("/tmp/mypipe", 0600);
switch (fork()) {
    case -1:
        fprintf(stderr, "Fork error.\n");
        break;
    case 0:
        execlp("xterm", "xterm", "-e", "/usr/bin/tail -f /tmp/mypipe", NULL);
        exit(EXIT_FAILURE);
        break; 
    default:
        ;
        char buff[512];
        int fd = open("/tmp/mypipe", O_WRONLY);
        scanf("%s", buff);
        write(fd, buff, strlen(buff));
        getchar();
        break;
}

This will open a named pipe /tmp/mypipe. The parent process writes data to it and the tail -f-process in the xterm will output it subsequently.

Ctx
  • 18,090
  • 24
  • 36
  • 51
  • Maybe the path to your `tail` is different or the pipe `/tmp/mypipe` wasn't created correctly for some reason? – Ctx Apr 07 '16 at 11:53
  • It works, thank you! The problem came from my tiling window manager, i3, because the main terminal has been launched in floating mode and i3 didn't know how to manage the poped window, the is solved by running the main terminal in tiling mode. – Nicolas Scotto Di Perto Apr 07 '16 at 12:30
  • I don't know why but in my full program the output came in the slave child terminal only when I quit the program... I have tried both `write` and `fprintf` combined with `fflush`, though it works in a simple main with the code above. My program has multithreading, can the problem come from that? I don't think so because it's the same problem that printf who access to stdin. – Nicolas Scotto Di Perto Apr 07 '16 at 13:23
  • Can you provide a minimal code example? Either in your question above or as a new question – Ctx Apr 07 '16 at 13:25
  • Maybe `tail` is not so suitable for that task after all... Just use `cat /tmp/mypipe` to avoid buffering issues – Ctx Apr 07 '16 at 13:53