Nhận ssh để chuyển tiếp tín hiệu


22

Tôi muốn có thể gửi tín hiệu (SIGINT là quan trọng nhất) thông qua ssh.

Lệnh này:

ssh server "sleep 1000;echo f" > foo

sẽ bắt đầu ngủ trên máy chủ và sau 1000 giây, nó sẽ đặt 'f \ n' vào tệp foo trên máy cục bộ của tôi. Nếu tôi nhấn CTRL-C (tức là gửi SIGINT tới ssh) thì nó sẽ giết ssh, nhưng nó sẽ không giết được giấc ngủ trên máy chủ từ xa. Tôi muốn nó giết giấc ngủ trên máy chủ từ xa.

Vì vậy, tôi đã cố gắng:

ssh server -t "sleep 1000;echo f" > foo

Nhưng nếu stdin không phải là thiết bị đầu cuối, tôi gặp lỗi này:

Pseudo-terminal will not be allocated because stdin is not a terminal.

và sau đó SIGINT vẫn không được chuyển tiếp.

Vì vậy, tôi đã cố gắng:

ssh server -t -t "sleep 1000;echo f" > output

Nhưng sau đó, đầu ra trong foo không phải là 'f \ n' mà thay vào đó là 'f \ r \ n', điều này thật tai hại trong tình huống của tôi (vì đầu ra của tôi là dữ liệu nhị phân).

Ở trên tôi sử dụng "ngủ 1000; echo f", nhưng trong thực tế được cung cấp bởi người dùng, do đó nó có thể chứa bất cứ thứ gì. Tuy nhiên, nếu chúng ta có thể làm cho nó hoạt động cho "ngủ 1000; echo f" thì rất có thể chúng ta có thể làm cho nó hoạt động cho tất cả các tình huống thực tế.

Tôi thực sự không quan tâm đến việc có một thiết bị đầu cuối giả ở đầu kia, nhưng tôi đã không thể tìm thấy bất kỳ cách nào khác để có được ssh để chuyển tiếp SIGINT của tôi.

Có cách nào khác không?

Chỉnh sửa:

Người dùng có thể đưa ra các lệnh đọc dữ liệu nhị phân từ stdin, chẳng hạn như:

seq 1000 | gzip | ssh server "zcat|bzip2; sleep 1000" | bzcat > foo

Người dùng có thể đưa ra các lệnh chuyên sâu về cpu, như:

ssh server "timeout 1000 burnP6"

Chỉnh sửa2:

Phiên bản có vẻ phù hợp với tôi là:

your_preprocessing |
  uuencode a | ssh -tt -oLogLevel=quiet server "stty isig -echoctl -echo ; uudecode -o - |
your_command |
  uuencode a" | uudecode -o - |
your_postprocessing

Cảm ơn digital_infinity đã chỉ cho tôi đi đúng hướng.


1
Tôi nghĩ rằng việc sử dụng thực tế của bạn sshphải phức tạp hơn những gì bạn thể hiện như các ví dụ, bởi vì bạn có thể có được hành vi bạn muốn với một sự sắp xếp lại đơn giản: sleep 1000 && ssh server "echo f" > foo(Nó phải &&, không ;, để việc giết chết sleepngăn sshlệnh chạy.) Nếu tôi 'đúng, xin vui lòng làm cho các ví dụ của bạn đại diện hơn cho việc sử dụng thực tế của bạn, để có thể đưa ra câu trả lời tốt hơn.
Warren Young

Đúng: giấc ngủ và tiếng vang thực sự là các tập lệnh do người dùng cung cấp và không thực sự là giấc ngủ và tiếng vang. Vì vậy, chúng tôi không biết những gì họ làm và nên cho là tồi tệ nhất.
Ole Tange

Sooo ... bạn sẽ đưa ra một lệnh ví dụ tốt hơn, phải không? Một nơi mà sự sắp xếp lại đơn giản không khắc phục được vấn đề? Bạn hỏi một câu hỏi hay và tôi muốn xem câu trả lời, nhưng bạn ít có khả năng nhận được câu trả lời nếu "vì vậy đừng làm vậy," là một câu trả lời hợp lý.
Warren Young

À nhân tiện ... Đừng làm vậy;)
Tim

Như được giải thích trong câu hỏi: "" "Ở trên tôi sử dụng" ngủ 1000; echo f ", nhưng trong thực tế được cung cấp bởi người dùng, do đó nó có thể chứa bất cứ thứ gì" ""
Ole Tange

Câu trả lời:


10

Câu trả lời ngắn:

ssh -t fs "stty isig intr ^N -echoctl ; trap '/bin/true' SIGINT; sleep 1000; echo f" > foo

và dừng chương trình bằng CTRL + N.

Giải thích dài dòng:

  1. Bạn phải sử dụng sttytùy chọn intrđể thay đổi máy chủ hoặc ký tự ngắt cục bộ để không va chạm với nhau. Trong lệnh trên, tôi đã thay đổi ký tự ngắt máy chủ thành CTRL + N. Bạn có thể thay đổi ký tự ngắt cục bộ của mình và rời khỏi máy chủ mà không có bất kỳ thay đổi nào.
  2. Nếu bạn không muốn ký tự ngắt ở đầu ra của bạn (và bất kỳ ký tự điều khiển nào khác) sử dụng stty -echoctl.
  3. Bạn phải đảm bảo rằng các ký tự điều khiển được bật trên bash máy chủ được gọi bởi sshd. Nếu bạn không, bạn có thể kết thúc với các quy trình vẫn treo xung quanh sau khi bạn đăng xuất.stty isig
  4. Bạn thực sự bắt SIGINTtín hiệu bằng cách trap '/bin/true' SIGINTtuyên bố trống rỗng. Nếu không có bẫy, bạn sẽ không có bất kỳ thiết bị xuất nào sau tín hiệu SIGINT ở cuối.

Có vẻ như không xử lý tốt với đầu vào nhị phân: seq 1000 | gzip | ssh -t -t máy chủ "stty isig int ^ N -echoctl; bẫy '/ bin / true' SIGINT; ngủ 1; zcat | bzip2" | bzcat> foo;
Ole Tange

Bạn không thể ngắt bằng bàn điều khiển nếu bạn đặt đầu vào tiêu chuẩn cho ssh cho thứ khác sau đó là bàn điều khiển. Trong trường hợp này, bạn phải ngắt dòng stdin.
digital_infinity

Tôi thấy rằng điều này seq 1000 | gzip | ssh -tt dell-test "zcat|bzip2" | bzcat > fookhông làm việc quá. Để có lệnh này, chúng ta cần phải loại bỏ -tt. Vì vậy, phân bổ thiết bị đầu cuối giả có thể lấy một số đầu vào từ stdin
digital_infinity

Tôi đã thử uuencode. Trong phiên bản này, nó không hoạt động: cat foo.gz | perl -ne 'gói in ("u", $ _)' | ssh -t -t máy chủ 'perl -ne "in giải nén (\" u \ ", \ $ _)" | mèo | gzip | perl -ne "gói in (\" u \ ", \ $ _)" '| perl -ne 'in unpack ("u", $ _)'> foo2.gz
Ole Tange

1
Tôi có cái này : (sleep 1; seq 1000 ) | gzip | uuencode bin | ssh -tt dell-test "stty isig intr ^N -echoctl -echo ; trap '/bin/true' SIGINT; sleep 1; uudecode -o /dev/stdout | zcat |bzip2 | uuencode bin2 " | uudecode -o /dev/stdout | bzcat >foo. Mặc dù ký tự ngắt không hoạt động - chúng ta cần một số phương thức truyền cho ký tự ngắt trong khi stdin đang bận .
digital_infinity

3

Tôi đã thử tất cả các giải pháp và đây là cách tốt nhất:

ssh host "sleep 99 < <(cat; kill -INT 0)" <&1

/programming//questions / 320180 / start-a


Điều đó không dừng sleepquá trình trong trường hợp mất kết nối.
xanh

Khi mất kết nối, stdin bị hỏng, bỏ chặn con mèo sẽ giết nhóm quy trình. Liệu tín hiệu INTerrupt đó có đủ tốt cho nhiệm vụ của bạn hay không là một câu hỏi khác.
Eric Woodruff

Nó sẽ là đủ tốt cho sleep, không nên? Tôi đã thêm một số date >> /tmp/killedsau cat, nhưng nó không được kích hoạt. Có một số thời gian chờ liên quan? Tôi đang sử dụng Zsh bình thường, nhưng cũng đã thử nghiệm nó với bash làm vỏ đăng nhập từ xa.
xanh lam

Tôi nghĩ rằng bạn đang ở trong thời gian chờ kết nối.
Eric Woodruff

Có cài đặt để kiểm soát điều này? Đối với phía khách hàng -o ServerAliveInterval=3 -o ServerAliveCountMax=2cho phép phát hiện nhanh chóng, nhưng có điều gì cho phía máy chủ không?
xanh lam

2

Tôi nghĩ rằng bạn có thể tìm thấy PID của quá trình bạn đang chạy trên máy chủ và gửi tín hiệu bằng cách sử dụng một sshlệnh khác (như thế này ssh server "kill -2 PID":).

Tôi sử dụng phương pháp này để gửi tín hiệu cấu hình lại cho các ứng dụng chạy trên một máy khác (ứng dụng của tôi bắt SIGUSR1 và đọc tệp cấu hình). Trong trường hợp của tôi, việc tìm kiếm PID rất dễ dàng, bởi vì tôi có các tên tiến trình duy nhất và tôi có thể tìm thấy PID bằng cách gửi psyêu cầu qua ssh.


Tôi không thấy một cách chống đạn để tìm ra PID của chương trình đang chạy trên remote. Hãy nhớ nó được đưa ra bởi người dùng. Nó có thể là: ssh server 'exec $ (echo fyrrc 1000 | / usr / games / rot13)'
Ole Tange

1

Giải pháp đã phát triển thành http://www.gnu.org/software/abul/abul_design.html#Remote-Ctrl-C-and-stiteria-error-stderr

$SIG{CHLD} = sub { $done = 1; };
$pid = fork;
unless($pid) {
    # Make own process group to be able to kill HUP it later
    setpgrp;
    exec $ENV{SHELL}, "-c", ($bashfunc."@ARGV");
    die "exec: $!\n";
}
do {
    # Parent is not init (ppid=1), so sshd is alive
    # Exponential sleep up to 1 sec
    $s = $s < 1 ? 0.001 + $s * 1.03 : $s;
    select(undef, undef, undef, $s);
} until ($done || getppid == 1);
# Kill HUP the process group if job not done
kill(SIGHUP, -${pid}) unless $done;
wait;
exit ($?&127 ? 128+($?&127) : 1+$?>>8)

0

----- lệnh.sh

#! /bin/sh
trap 'trap - EXIT; kill 0; exit' EXIT
(sleep 1000;echo f) &
read ans

----- trên thiết bị đầu cuối địa phương

sleep 864000 | ssh -T server command.sh > foo

Chào! Tôi nghĩ rằng bạn có thể làm cho câu trả lời của bạn hữu ích hơn rất nhiều bằng cách giải thích, chi tiết đến mức bạn thấy có liên quan, cách thức hoạt động. Đừng ngần ngại chỉnh sửa nó để chèn thông tin mới.
dhag
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.