Пейджер Xterm - выход на два терминала - с использованием pipe и dup2

Я пытаюсь реализовать пейджер на C, я хочу, чтобы код открывал другой терминал (xterm) и печатал в нем некоторые выходные данные.

Итак, я сначала создаю канал и разветвляю основную программу, потомок будет выполнять xterm с помощью команды tail, основная программа будет выводить данные в канал, а потомок перед выполнением xterm будет дублировать связь канала с дескриптором файла stdin файла ребенок.

Возможно, я неправильно понял использование pipe и dup2, потому что мой код не работает.

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

Пока я что-то набираю в родительском, и ничего не печатается в обоих процессах. Итак, как мне создать связь между xterm и родительским процессом?

Изменить: пример моей программы:

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

В основном:

verbosity(VERBM_XTERMO);

Затем последовало несколько звонков verbose. Вы можете увидеть в init_outputxterm тентави для записи в xterm сразу после создания xterm, как в решении. Но все отображалось только после того, как я вышел из программы, жестоко закрыв основной терминал, сделав дочерний процесс сиротой (если я выйду с помощью Ctrl-C, дочерний процесс также будет убит).


person Nicolas Scotto Di Perto    schedule 07.04.2016    source источник


Ответы (1)


Сам Xterm не читает со стандартного ввода, поэтому передача ему данных не будет иметь никакого эффекта. Но вы можете открыть именованный канал и прочитать из него с помощью tail -f /tmp/mypipe, например так:

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

Это откроет именованный канал /tmp/mypipe. Родительский процесс записывает в него данные, а tail -f-процесс в xterm впоследствии их выводит.

person Ctx    schedule 07.04.2016
comment
Может быть, путь к вашему tail другой или канал /tmp/mypipe по какой-то причине не был создан правильно? - person Ctx; 07.04.2016
comment
Это работает, спасибо! Проблема возникла из-за моего мозаичного оконного менеджера i3, потому что основной терминал был запущен в плавающем режиме, а i3 не знал, как управлять всплывающим окном. Проблема решается путем запуска основного терминала в мозаичном режиме. - person Nicolas Scotto Di Perto; 07.04.2016
comment
Я не знаю почему, но в моей полной программе вывод пришел в подчиненный дочерний терминал только тогда, когда я вышел из программы... Я пробовал как write, так и fprintf в сочетании с fflush, хотя он работает в простой основной с кодом выше . Моя программа имеет многопоточность, может ли проблема быть из-за этого? Я так не думаю, потому что это та же проблема, что и с printf, который обращается к стандартному вводу. - person Nicolas Scotto Di Perto; 07.04.2016
comment
Можете ли вы предоставить минимальный пример кода? Либо в вашем вопросе выше, либо как новый вопрос - person Ctx; 07.04.2016
comment
Возможно, tail все-таки не подходит для этой задачи... Просто используйте cat /tmp/mypipe, чтобы избежать проблем с буферизацией - person Ctx; 07.04.2016