Jak przekierować na stdin działającej powłoki bash?

7

Teoretycznie, jeśli znam pid działającej powłoki bash, mogę uruchomić kota, którego stdout jest przekierowany na stdin tej powłoki. Wydaje się, że wpisuję coś na tej powłoce. Niestety, BĘDZIE strumień pochodzący od kota, ALE NIE sprawi, że powłoka będzie działać poprawnie (wprowadzone polecenie od kota nie zostanie wykonane przez bash).

Otwórz terminal:

ps -ef | grep bash
ymf       4906  4887  0 16:19 pts/0    00:00:00 /bin/bash

Na innym terminalu:

cat 1> /proc/4906/fd/0
echo 'hello!'

Dlaczego?

Wyznacznik
źródło
1
Czy wysłałeś również klucz „Return”? Ponieważ byłoby to potrzebne do zakończenia polecenia.
poniedziałek
@boretom Oczywiście, że tak.
Determinant
Tak, widzę ciekawe pytanie. Dane wejściowe do bash wydają się być przekierowane na standardowe wyjście. Spróbuj uruchomić komendę podobną, topa zobaczysz, że stdin po prostu dodaje gdzieś do wyniku. Domyślam się, że ponieważ powłoka jest uruchamiana jako powłoka interaktywna, nie przyjmuje poleceń ze standardowego wejścia. Ale to czysta spekulacja.
poniedziałek
Chociaż nie jestem tu guru, myślę, że piszesz do emulatora terminali, a nie do omawianego procesu. IE piszesz do właściwego złącza rury, ale kończy się źle w dwóch rurach.
Eroen
@boretom spróbuj ls -l /proc/PID/fd/. 0, 1, 2 są przekierowywane na /dev/pts/TERM_NUMERNieważne, czy akceptuje polecenia ze standardowego wejścia, jestem pewien, że fd0 służy do wprowadzania danych i już przekierowałem do niego wyjście cat.
Determinant

Odpowiedzi:

7

Mam dość limitu „tylko jeden akapit” w komentarzach =)

Jeśli uruchomisz powłokę shi dostaniesz pid $pid, możesz znaleźć deskryptory plików tak, jak to opisano. Przykład:

$ ls -l /proc/29201/fd
total 0
lrwx------ 1 eroen users 64 Mar 22 15:52 0 -> /dev/pts/2
lrwx------ 1 eroen users 64 Mar 22 15:52 1 -> /dev/pts/2
lrwx------ 1 eroen users 64 Mar 22 15:52 2 -> /dev/pts/2
lrwx------ 1 eroen users 64 Mar 22 15:52 255 -> /dev/pts/2

Można zauważyć, że 1, 2i 3są wszystkie dowiązania do tego samego terminala (a chardev). Innymi słowy, dane wejściowe do procesu są odczytywane z tego samego węzła urządzenia, do którego zapisywane są dane wyjściowe.

Podczas próby zapisu (w innym procesie) do tego samego terminala (jak albo /proc/$pid/fd/0czy /dev/pts/?Ci osiągnąć dokładnie to samo jak proces samo robi gdy zapisuje dane na jego wyjście; dane pojawia się w oknie terminala.

Właściwie zmiana punktu fd [0-2] po uruchomieniu procesu jest dość skomplikowana, ale nie niemożliwa. Reptyr to darmowa aplikacja typu open source, która modyfikuje istniejący proces, więc fd [0-2] wskazuje na inny tty (a także kilka innych rzeczy). Odbywa się to za pomocą frameworka ptrace . W poście wspomniano również o innych programach, które robią to samo i że można tego dokonać za pomocą gdb .

W zależności od tego, co naprawdę chciałeś osiągnąć, możesz znaleźć Reptyr lub inne oprogramowanie, które zrobi to, czego potrzebujesz. W przeciwnym razie możesz spojrzeć na / skopiować / zmodyfikować kod źródłowy i dowiedzieć się, jak sobie radzą.

Uzupełnienie:
ten zawiera kilka diagramy ilustrujące, w szczególności trzeci schemat z góry.

Eroen
źródło
1
Tak więc, tty faktycznie czyta z klawiatury w magiczny sposób, a pisanie cokolwiek do tty może tylko powodować wyświetlanie wiadomości.
Determinant
2
Mniej magii i więcej „w jądrze”, ale tak.
Eroen
5

Idź do terminala A dowolnego typu tty

dostaniesz coś takiego jak „/ dev / pts / 0”

Teraz przejdź do terminala B i wpisz exec 0</dev/pts/0(lub cokolwiek, co dało ci polecenie tty)

Wróć do terminala A, a wprowadzone polecenia będą działać na terminalu B.

JeffG
źródło
3
Wspomnę, że stwarza to interesujący warunek wyścigu, który w moim systemie sprawia, że ​​pozornie losowa powłoka otrzymuje postać.
Eroen
Eoren, to brzmi jak dwa czytniki dla jednego wejścia, które konkurują o dane z tego samego strumienia.
Ray
1

Jak przekierować na stdin działającej powłoki bash?

za pomocą C ( https://stackoverflow.com/a/7370822 . Nie przetestowałem tego):

char* cmd="ls\n";
int fd = open (ptsname, O_RDWR);

while (*cmd)
{
    ioctl(fd, TIOCSTI, cmd++);
}

używanie Perla ( https://unix.stackexchange.com/a/48221 . działa idealnie, ale tylko w przypadku bieżącej powłoki):

require "sys/ioctl.ph";
ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV;
atti
źródło
1
Na superużytkowniku mówimy o powłoce, a nie o C lub perlu.
poza godzinami pracy