перенаправление стандартного вывода
От: GarikTot  
Дата: 02.07.03 15:58
Оценка:
Добрый вечер, уважаемые!

У меня такой вопрос:
есть процесс, который создаёт терминал,
есть несколько дочерних процессов, которые пишут в стандартный вывод (stdout)
собственно вопрос: как мне из материнского процесса сделать так, чтобы вывод дочерних попадал в мой терминал?

Заранее благодарен

ps.
не пинайте меня сильно, если вопрос дурацкий
Re: перенаправление стандартного вывода
От: Sergeem Израиль  
Дата: 03.07.03 08:02
Оценка:
Здравствуйте, GarikTot, Вы писали:

GT>Добрый вечер, уважаемые!


GT>У меня такой вопрос:

GT>есть процесс, который создаёт терминал,
GT>есть несколько дочерних процессов, которые пишут в стандартный вывод (stdout)
GT>собственно вопрос: как мне из материнского процесса сделать так, чтобы вывод дочерних попадал в мой терминал?

Можно сначала форкануться, в сыне форка переставить свой
стандартный вывод, а затем родить дочерний процесс. Дочка
наследует стандартный ввод/вывод.

GT>Заранее благодарен


GT>ps.

GT>не пинайте меня сильно, если вопрос дурацкий
Serge.

Hасколько проще была бы жизнь, если бы она была в исходниках.
Re: перенаправление стандартного вывода
От: a1EXa Россия  
Дата: 03.07.03 08:18
Оценка:
Никакой эт не дурачкий вопрос, а тема, описанная
в каждой книге про юних. Самый простой пример —
запускаем два терминала и делаем вот так:
$ ps
  PID TTY          TIME CMD
 1085 pts/2    00:00:00 bash
 1151 pts/2    00:00:00 ps
$ echo 'sending text to pts3' > /dev/pts/3


$ ps
  PID TTY          TIME CMD
 1113 pts/3    00:00:00 bash
 1152 pts/3    00:00:00 ps
$
$ sending text to pts3

те каталог /dev/ содержит ссылки на устройства, к коим
есесьно, относится и твой терминал. Просто пиши в твой
материнский терминал (устройство).
Re[2]: перенаправление стандартного вывода
От: Аноним  
Дата: 03.07.03 13:14
Оценка:
Здравствуйте, a1EXa, Вы писали:

EX>Никакой эт не дурачкий вопрос, а тема, описанная

EX>в каждой книге про юних. Самый простой пример -
EX>запускаем два терминала и делаем вот так:
EX>
EX>$ ps
EX>  PID TTY          TIME CMD
EX> 1085 pts/2    00:00:00 bash
EX> 1151 pts/2    00:00:00 ps
EX>$ echo 'sending text to pts3' > /dev/pts/3
EX>


EX>
EX>$ ps
EX>  PID TTY          TIME CMD
EX> 1113 pts/3    00:00:00 bash
EX> 1152 pts/3    00:00:00 ps
EX>$
EX>$ sending text to pts3
EX>

EX>те каталог /dev/ содержит ссылки на устройства, к коим
EX>есесьно, относится и твой терминал. Просто пиши в твой
EX>материнский терминал (устройство).

Дело в том, что дочерние процессы не должны ничего знать о материнском
они пишут в стандартный вывод и изменить здесь ничего нельзя
можно ли как-то изменить параметры наследования, чтобы "сыны" унаследовали вывод матери?
Re[3]: перенаправление стандартного вывода
От: GarikTot  
Дата: 03.07.03 13:19
Оценка:
Извиняюсь за анонимность
Re[2]: перенаправление стандартного вывода
От: GarikTot  
Дата: 03.07.03 13:22
Оценка:
Здравствуйте, Sergeem, Вы писали:

S>Можно сначала форкануться, в сыне форка переставить свой

S>стандартный вывод, а затем родить дочерний процесс. Дочка
S>наследует стандартный ввод/вывод.

Сейчас попробую... А почему нельзя сразу рожать? без форка?
Re[3]: перенаправление стандартного вывода
От: Sergeem Израиль  
Дата: 03.07.03 13:58
Оценка:
Здравствуйте, GarikTot, Вы писали:

GT>Здравствуйте, Sergeem, Вы писали:


S>>Можно сначала форкануться, в сыне форка переставить свой

S>>стандартный вывод, а затем родить дочерний процесс. Дочка
S>>наследует стандартный ввод/вывод.

GT>Сейчас попробую... А почему нельзя сразу рожать? без форка?


чтобы не портить stdout основного процесса.
Serge.

Hасколько проще была бы жизнь, если бы она была в исходниках.
Re[4]: перенаправление стандартного вывода
От: GarikTot  
Дата: 03.07.03 14:22
Оценка:
Здравствуйте, Sergeem, Вы писали:


S>чтобы не портить stdout основного процесса.


Что-то у меня не получается
Можно простенький примерчик?

Может я что неправильно делаю?

есть несколько дочерних процессов, которые делают что-то и при этом пишут в стандартный вывод
они ничего не должны знать о "матери"
материнский процесс создаёт терминал и перенаправляет туда вывод
после этого запускает дочерние
однако их вывод идёт на консоль, а не в терминал

пробовал сделать как ты советовал в предыдущем посте, т.е. заменить вызов spawn комбинацией forc+exec
при этом получается то же самое
Re: перенаправление стандартного вывода
От: Murr Россия  
Дата: 03.07.03 15:55
Оценка:
Здравствуйте, GarikTot, Вы писали:

Вопрос довольно сложный и ответ на него сильно зависит от системы.
Если терминал чужой, то как уже написали, в него писать можно всегда.

Если терминал свой, то можно попробовать извратиться как-нибудь так:

#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
int main (int argc, char *argv[]) {
    pid_t oldpgrp, mypid;
    pid_t p = fork ();

    if (p < 0) {    // AP: fork failed somehow
        return -1;
    }

    if (p == 0) {  //  AP: child process
        int fd;

        mypid = getpid ();

        fclose (stdin); fclose (stdout); fclose (stderr);

        fd = open ("/dev/tty", O_RDWR); // AP: there should be some correct way of doing that ...
        if (fd == -1) {
            // AP: we may fail here because of some reasons like
            //          a) there was no controlling terminal
            //          b) we're called from the chroot'ed environment
            //          c) etc
            return -1;
        }

        dup2 (fd, 0); // AP: we are able to use dup(fd) here at least in Linux
        dup2 (fd, 1); // AP: we are able to use dup(fd) here at least in Linux
        dup2 (fd, 2); // AP: we are able to use dup(fd) here at least in Linux

        if (setpgrp () == -1) {
            // AP: looks like this can never happen, because we're no leader of the session
            return -1;
        }

        (void)ioctl (0, TIOCGPGRP, &oldpgrp); // AP: i'm not sure if we really have to try to save old pgrp, it just doesn't hurt!
        signal (SIGTTOU, SIG_IGN); // AP: mysterious things, but Linux expects this in tty_check_change
        if (ioctl (0, TIOCSPGRP, &mypid) == -1) {
            // AP: failed to acquire terminal
            return -1;
        }
        stdin = fdopen (0, "r"); stdout = fdopen (1, "w"); stderr = fdopen (2, "w"); // AP: does ISO requires std* to be public writable vars?
        {
            printf ("Hello, world!\n");
        }
        ioctl (0, TIOCSPGRP, &oldpgrp); // AP: i believe that this never works, but why not just try?
    }
}


Тут единственная проблема в том, что set process group несколько странно работает в Linux и сменить группу процессов на чужую, похоже, нельзя (или надо подумать как).
Re[2]: перенаправление стандартного вывода
От: Murr Россия  
Дата: 03.07.03 16:07
Оценка:
Здравствуйте, Murr, Вы писали:

Хотя может я раздуваю несущественное. Может и правда для записи (не для чтения) будет достаточно:

signal (SIGTTOU, SIG_IGN);
fclose (stdin); fclose (stdout); fclose (stderr);
open ("/dev/tty", O_RDWR);
dup(0);
dup(0);
stdin = fdopen (0, "r"); stdout = fdopen (1, "w"); stderr = fdopen (2, "w");


Поэкспериментируйте...
Re[3]: перенаправление стандартного вывода
От: Murr Россия  
Дата: 03.07.03 18:54
Оценка: 3 (1)
Вроде доковырял пример до работоспособного состояния (по крайней мере в Linux):
/**********************************************************************
    Terminal refetching sample.
    Copyright (C) Murr. 2003.

    Feel free to use the code in any educational or commercial purposes.
***********************************************************************/

/**********************************************************************
    The process changes the foreground process group of its controlling
    terminal onto itself by freezing the whole foreground group and
    switching pgrp and then making some I/O on it (output+input+output).

    The process can be run in the context of whatever pgrp and/or
    any with whatever redirected stdin/stdout/stderr.
***********************************************************************/
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <errno.h>

int main (int argc, char *argv[]) {
    int status, have_to_lock_term = 1;
    struct termios t_old, t_new;

    pid_t oldpgrp, mypid, realpgrp;
    pid_t p = fork (); //AP: no real need for forking here, it's just to show forked redirection
    char str[11];

    if (p < 0) {    // AP: fork failed somehow
        return -1;
    }

    if (p == 0) {  //  AP: child process
        int fd;

        mypid = getpid ();

        fclose (stdin); fclose (stdout); fclose (stderr);

        fd = open ("/dev/tty", O_RDWR); // AP: there should be some correct way of doing that ...
        if (fd == -1) {
            // AP: we may fail here because of some reasons like
            //          a) there was no controlling terminal
            //          b) we're called from the chroot'ed environment (hence /dev is unreachable)
            //          c) etc
            //     Is anyone aware of how controlling tty may be opened in most common case?
            return -1;
        }

        dup2 (fd, 0); // AP: we are able to use dup(fd) here at least in Linux
        dup2 (fd, 1); // AP: we are able to use dup(fd) here at least in Linux
        dup2 (fd, 2); // AP: we are able to use dup(fd) here at least in Linux

        (void)ioctl (0, TIOCGPGRP, &oldpgrp); // AP: saving foreground group id to restore it later

        if (oldpgrp == getpgrp ())
            have_to_lock_term = 0;

        if (have_to_lock_term) {
                killpg (oldpgrp, SIGSTOP); // AP: freeze foreground group

                if (setpgrp () == -1) {
                    // AP: looks like this can never happen, because we're never a leader of a session
                    return -1;
                }

                signal (SIGTTOU, SIG_IGN); // AP: mysterious things, but Linux expects this in tty_check_change
                                            //          so this should always be done ...

                if (ioctl (0, TIOCSPGRP, &mypid) != 0) {
                    // AP: failed to acquire terminal
                    return -1;
                }
        }

        tcgetattr (0, &t_old);          // AP: i used to change ECHO mode with tcgetattr, while ioctl is fine ;)
        t_new.c_iflag = ICRNL | IXON;
        t_new.c_oflag = OPOST | ONLCR;
        t_new.c_cflag = B38400 | CS8 | CREAD | HUPCL;
        t_new.c_lflag = (ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN);
        tcsetattr (0, TCSANOW, &t_new); // AP: set the default mode

        stdin = fdopen (0, "r"); stdout = fdopen (1, "w"); stderr = fdopen (2, "w"); // AP: does ANSI/ISO requires std* to be public writable vars?
        printf ("Hello, stranger! Please, enter something:\n"); // AP: output demo
        fgets (str, 10, stdin);     // AP: input demo
        printf ("You entered %s\n (error code = %lu)\n", str, errno); // AP: output demo

        tcsetattr (0, TCSANOW, &t_old); // AP: restoring old terminal settings

        if (have_to_lock_term) {
                ioctl (0, TIOCSPGRP, &oldpgrp); // AP: switching back the foreground process group
                killpg (oldpgrp, SIGCONT);      // AP: unfreeze the foreground group
        }
        return 0;
    }
    wait (&status); // AP: do not poll the status - that really doesn't matter
    return 0;
}


hell:~> ./ttytest
Hello, stranger! Please, enter something:
test123456
You entered test12345
 (error code = 29)
hell:~> ./ttytest &
[1] 26395
hell:~> Hello, stranger! Please, enter something:
test987654321
You entered test98765
 (error code = 29)

[1]+  Done                    ./ttytest
hell:~>
Re[4]: перенаправление стандартного вывода
От: GarikTot  
Дата: 05.07.03 08:12
Оценка:
Здравствуйте, Murr, Вы писали:

M>Вроде доковырял пример до работоспособного состояния (по крайней мере в Linux):



Спасибо!

то, что нужно
Re[5]: перенаправление стандартного вывода
От: Sergeem Израиль  
Дата: 06.07.03 07:08
Оценка:
Здравствуйте, GarikTot, Вы писали:


GT>Что-то у меня не получается

GT>Можно простенький примерчик?

Насколько я помню, лучше всего про это написано в книжке
"Unix Network Programming".
Serge.

Hасколько проще была бы жизнь, если бы она была в исходниках.
Re: перенаправление стандартного вывода
От: Kubyshev Andrey  
Дата: 07.07.03 11:03
Оценка:
Здравствуйте, GarikTot, Вы писали:

может я не совсем понял, но почему не использовать popen ?
Re[5]: перенаправление стандартного вывода
От: DSD Россия http://911.ru/cv
Дата: 08.07.03 06:46
Оценка:
Здравствуйте, GarikTot, Вы писали:


Как вариант на ту же тему:
http://rsdn.ru/Forum/?mid=316436
Автор: DSD
Дата: 05.07.03
--
DSD
Re[5]: перенаправление стандартного вывода
От: Murr Россия  
Дата: 08.07.03 11:51
Оценка:
Здравствуйте, GarikTot.

Если есть интерес ковыряться в устройстве терминалов, то я выложил у себя этот пример и накропал небольшую статейку (со временем буду ее дописывать): http://213.147.59.155:6666/Projects/Linux/index.html



Так что, welcome!
Re: перенаправление стандартного вывода
От: GarikTot  
Дата: 15.07.03 15:08
Оценка:
Спасибо всем за советы!

Кстати, если кому интересно, в QNX'е есть такая функция
qnx_spawn()

в замен стандартной POSIX'ной
Так вот она позволяет решить ту же проблему, что называется, в одну строчку

Ещё раз спасибо всем
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.