Чи можу я надіслати текст STDIN активного процесу, що працює під час екранного сеансу?


70

У мене давно працює серверний процес всередині екранного сеансу на моєму сервері Linux. Це трохи нестабільно (і, на жаль, не моє програмне забезпечення, тому я не можу це виправити!), Тому я хочу скриптувати нічний перезапуск процесу, щоб забезпечити стабільність. Єдиний спосіб зробити це витонченим відключенням - це перейти до екранного процесу, перейти до вікна, в якому він працює, і ввести рядок "стоп" на його консолі управління.

Чи є якісь розумні перекорення перенаправлення, які я можу зробити, щоб змусити cronjob надсилати цю команду stop у визначений час щодня?

Відповіді:


85

Ця відповідь не вирішує проблему, але вона залишається тут, оскільки 30+ людей вважають її корисною , інакше я б її давно видалив.

Пишіть на /proc/*pid of the program*/fd/0. fdПідкаталог містить дескриптори всіх відкритих файлів і файловий дескриптор 0є стандартний ввід (1 стандартний висновок і 2 є STDERR).

Ви можете використовувати це для виведення повідомлень на tty, де працює програма, хоча це не дозволяє писати до самої програми.

Приклад

Термінал 1:

[ciupicri@hermes ~]$ cat
shows on the tty but bypasses cat

Термінал 2:

[ciupicri@hermes ~]$ pidof cat
7417
[ciupicri@hermes ~]$ echo "shows on the tty but bypasses cat" > /proc/7417/fd/0

3
@James Lawrie: тоді подивіться на proc (5) та proc.txt .
Крістіан Цюпіту

2
+2 незалежно від того, скільки ви думаєте, що знаєте, завжди можна навчитися :) плавно.
troyengel

3
Будьте в курсі, що proc fd перенаправляє лише те, що використовується як джерело stdin. У вашому прикладі, якщо ви вводите щось у терміналі 1, він знову роздруковує його (він надсилається котам stdin і кішка друкує це), в результаті чого ви бачите це двічі. З іншого боку, якщо ви щось надішлите до fd / 0, воно буде надіслано на консоль, але не для котів, і таким чином відображатиметься лише один раз. Оскільки кішка просто надрукує введення знову за допомогою цього прикладу, ви не можете реально побачити, чи друкується ваш вхід чи вихід, таким чином, це неправильне уявлення. / fd / 0 балів до консолі / очок; див ls -l /proc/7417/fd/0.
Кіссакі

4
Приклад із реального світу: я запустив gphoto2 --get-all-файли, і він запитує підтвердження 100 разів. Коли я повторюю "y"> / proc / PID / fd / 0, gphoto2 не продовжується, однак "y" друкується в терміналі.
Торстен Стаерк

2
@ThorstenStaerk, я знаю, тому я додав цю замітку. Ви пишете лише у файл пристрою, що відповідає терміналу, на якому працює gphoto2 (наприклад /dev/pts/19), yсимвол не доходить до самої програми. Це аналогічно тому, що відбувається при використанні команди write (1) . У будь-якому випадку, будь ласка, спробуйте іншу відповідь або графічний інструмент автоматизації, як xdotool .
Крістіан Цюпіту

36

Екранне рішення

Запустіть сервер так:

# screen -d -m -S ServerFault tr a-z A-Z # replace with your server

екран запуститься в окремому режимі, тому якщо ви хочете побачити, що відбувається, запустіть:

# screen -r ServerFault

Керуйте сервером так:

# screen -S ServerFault -p 0 -X stuff "stop^M"
# screen -S ServerFault -p 0 -X stuff "start^M"
# screen -S ServerFault -p 0 -X stuff "^D" # send EOF

(Ця відповідь ґрунтується на надсиланні тексту на окремий екран із веб-сайту побратимів Unix & Linux )

Пояснення параметрів:

-d -m
   Start screen in "detached" mode. This creates a new session but doesn't
   attach to it.  This is useful for system startup scripts.
-S sessionname
   When creating a new session, this option can be used to specify a meaningful
   name for the session.
-r [pid.tty.host]
-r sessionowner/[pid.tty.host]
   resumes a detached screen session.
-p number_or_name|-|=|+
   Preselect a window. This is useful when you want to reattach to a specific
   window or you want to send a command via the "-X" option to a specific
   window.
-X
   Send the specified command to a running screen session e.g. stuff.

речі [рядок]

   Stuff the string string in the input  buffer of the current window.
   This is like the "paste" command but with much less overhead.  Without
   a parameter, screen will prompt for a string to stuff.

розчин на основі tmux

Запустіть сервер так:

# tmux new-session -d -s ServerFault 'tr a-z A-Z' # replace with your server

tmux запуститься в окремому режимі, тому якщо ви хочете побачити, що відбувається, запустіть:

# tmux attach-session -t ServerFault

Керуйте сервером так:

# tmux send-keys -t ServerFault -l stop
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault -l start
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault C-d # send EOF

Пояснення параметрів:

 new-session [-AdDP] [-c start-directory] [-F format] [-n window-name] [-s
         session-name] [-t target-session] [-x width] [-y height]
         [shell-command]
         Create a new session with name session-name.

         The new session is attached to the current terminal unless -d is
         given.  window-name and shell-command are the name of and shell
         command to execute in the initial window.  If -d is used, -x and
         -y specify the size of the initial window (80 by 24 if not
         given).

 send-keys [-lR] [-t target-pane] key ...
               (alias: send)
         Send a key or keys to a window.  Each argument key is the name of
         the key (such as `C-a' or `npage' ) to send; if the string is not
         recognised as a key, it is sent as a series of characters.  The
         -l flag disables key name lookup and sends the keys literally.

4

Спробуйте це для початку:

# screen
# cd /path/to/wd
# mkfifo cmd
# my_cmd <cmd
C-A d

І це вбити:

# cd /path/to/wd
# echo "stop" > cmd
# rm cmd

3
Це добре, але це може мати недолік у тому, що він не може надсилати інші команди під час роботи програми. Якщо програма зупиняється, коли вона потрапляє на EOF на stdin, тоді на першому echo "xxx" > cmdпрограма зупиняється (тому що труба буде закрита). Хоча деякі програми є досить розумними, щоб знову відкрити ( rewind(3)) їх stdin, коли вони стикаються з EOF.
Крістіан Цюпіту

2

Можна відправляти вхідний текст до запущеного процесу без запуску screenутиліти чи будь-якої іншої вигадливої ​​утиліти. А це можна зробити, надіславши цей вхідний текст у файл «стандартного введення» процесу /proc/PID#/fd/0.

Однак вхідний текст потрібно надсилати спеціальним чином, щоб прочитати процес. Надсилання тексту введення за допомогою writeметоду звичайного файлу не призведе до отримання тексту тексту. Це тому, що це буде додано лише до цього "файлу", але не запустить процес зчитування байтів.

Щоб запустити процес зчитування байтів, необхідно виконати IOCTLоперацію типу TIOCSTIдля кожного окремого байту, що надсилається. Це помістить байт у стандартну вхідну чергу процесу.

Це обговорюється тут на деяких прикладах у C, Perl та Python:

https://unix.stackexchange.com/questions/48103/construct-a-command-by-putting-a-string-into-a-tty/48221

-

Отже, щоб відповісти на оригінальне запитання, яке було задано майже 9 років тому, для роботи з cron потрібно було б запустити невеликий скрипт / програму утиліти, подібну до тих прикладів, які люди написали для цього іншого запитання, який би надіслав рядок "стоп \ n" на цей серверний процес у запитанні, надсилаючи кожен з 5 байтів через IOCTLоперацію типу TIOCSTI.

Звичайно, це буде працювати лише в системах, що підтримують TIOCSTI IOCTLтип операції (наприклад, Linux), і тільки з rootоблікового запису користувача, оскільки ці "файли" під /proc/"належать" root.


1

У разі , якщо це допомагає будь-кому: У
мене була аналогічна проблема, і як процес , я використовую не під screenабо tmux, я повинен був взяти інший підхід.

Я доклав gdbдо xtermщо мій процес був запущений в, і використовується call write(5, "stop\n", 5)від gdbзапису в дескрипторі майстер псевдотермінал файлу.
Я з'ясував, до якого дескриптора файлів надсилати дані, переглянувши /proc/<pid>/fdпосилання, /dev/ptmxа потім пробну помилку між двома параметрами (надіслати мою рядок обом дескрипторам відповідних файлів, здавалося, не завдасть шкоди).

EDIT

Виявилося, що xtermпроцес, до якого я приєднався, був породжений spawn-new-terminal() xtermдією з прив'язки клавіш, а другий ptmxвідкритий дескриптор файлу був просто ptmxтим батьківським xtermпроцесом, який не був закритий.
Отже, виклики проб і помилок надіслали вихід до цього іншого терміналу.
Більшість xtermпроцесів не мають двох ptmxдескрипторів файлів.

END EDIT

Це ефективно набрало цю рядок у термінал, а відтак надіслало її до процесу, що працює під ним.

nb, можливо, вам доведеться дозволити приєднання до запущеного процесу з чимось подібним
sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope"


0

Оскільки я не можу коментувати найбільш прийняту відповідь Крістіана Цюпіту (2010 р.), Я повинен викласти це окремою відповіддю:

Це питання вже було вирішено в цій темі: https://stackoverflow.com/questions/5374255/how-to-write-data-to-existing-processs-stdin-from-external-process

Коротко:

Ви повинні почати свій процес з труби для stdin, яка не блокується і не закривається, коли був записаний поточний вхід. Це може бути реалізовано простим нескінченним циклом, який буде прокладений у відповідний процес:

$ (while [ 1 ]; do sleep 1; done) | yourProgramToStart

Я можу підтвердити, що це різний спосіб Кріссі відкрити трубу, яка не працювала в моєму випадку. Показане рішення натомість спрацювало.

Потім ви можете записати у файл / / fd / 0 файл процесу, щоб надіслати йому інструкції. Єдиний недолік полягає в тому, що вам потрібно також припинити процес bash, який виконує нескінченний цикл після вимкнення сервера.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.