Thông báo người nghe hành xử kỳ lạ khi nền


7

Tôi đã đấu tranh để làm cho IRC-Bouncer / Thông báo Script của tôi hoạt động.

Đây có nghĩa là một tập lệnh sẽ tự động đăng nhập vào một máy từ xa, đính kèm vào một phiên màn hình (hoặc bắt đầu một phiên bản nếu không tồn tại) đang chạy weechat, đồng thời mở một kết nối ssh khác sử dụng netcat để đọc thông báo từ tệp socket mà phần bổ sung weechat xuất các tin nhắn thông báo của tôi. Các thông báo này sau đó được đưa vào lib-notify (thông qua gửi thông báo) để tôi có thể được cảnh báo về hoạt động trong weechat.

Đây là kịch bản:

#!/bin/bash

BOUNCER="MYUSER@MYBOUNCER.NET"

function irc_notify() {
  ssh $BOUNCER "nc -k -l -U /tmp/weechat.notify.sock" | \
    while read type message; do
     notify-send -i weechat -u critical "$(echo -n $type | base64 -di -)" "$(echo -n $message | base64 -di -)"
    done
}

# Start listening for notifications
irc_notify &

# Attach to remote IRC Bouncer Screen
ssh $BOUNCER -t 'screen -d -R -S irc weechat'

# Cleanup Socket Listener
echo "cleaning up notification socket listener…"
ssh $BOUNCER 'pkill -f -x "nc -k -l -U /tmp/weechat.notify.sock"'

Các thiết lập thực sự hoạt động thực sự tốt, ngoại trừ một trục trặc lớn. Chỉ có hai thông báo được gửi đến trình quản lý thông báo của tôi, mỗi lần gọi tập lệnh. Sau đó: không có gì.

Vì vậy, để loại bỏ các vấn đề với tập lệnh thông báo trong weechat, tôi đã loại bỏ lệnh gọi ssh thứ hai (cái được gắn vào phiên màn hình và bắt đầu weechat) và thay thế nó bằng một readlệnh để chặn thực thi trong khi tôi kiểm tra. Sau đó, sử dụng irbtrên máy từ xa, tôi đã gửi tin nhắn đến ổ cắm bằng ruby.
Tuy nhiên, ngay cả khi tôi đang gửi tin nhắn theo cách thủ công, vẫn chỉ có hai tin nhắn xuất hiện trước khi nó ngừng hoạt động .

stracecho tôi thấy một số hành vi thú vị (khi tôi gắn liền với quá trình rẽ nhánh) trong đó dường như các tin nhắn đã ngừng bị chấm dứt bởi các ký tự dòng mới sau tin nhắn đầu tiên hoặc thứ hai. Nhưng sau một vài lần nữa, họ ngừng xuất hiện stracecùng nhau.

Lúc này tôi quyết định xem có gì trong kịch bản của mình gây ra hành vi lạ không. Vì vậy, trên dòng lệnh tôi chỉ cần gọi ssh $BOUNCER "nc -k -l -U /tmp/weechat.notify.sock"trực tiếp kết nối ssh ( ). Và lo lắng, tất cả các tin nhắn tôi đang gửi bằng tay đều xuất hiện (tất nhiên vẫn được mã hóa base64).

Vì vậy, sau đó tôi đã thêm vào logic để giải mã mọi tin nhắn khi nó đến, giống như tôi có trong kịch bản của mình, và nó cũng hoạt động hoàn hảo cho mọi tin nhắn. Bao gồm cả khi tôi cho những tin nhắn này vào thông báo-gửi.

Vì vậy, tại thời điểm này tôi đã quyết định rằng một cái gì đó kỳ lạ phải xảy ra khi tôi rẽ nhánh . Nhưng tôi quan sát thấy không có sự khác biệt về hiệu quả khi tôi căn cứ lại các lệnh trong thiết bị đầu cuối. Vì vậy, tôi tự hỏi liệu có lẽ điều gì đó kỳ lạ đã xảy ra bởi vì nó đang được chạy từ trong một kịch bản.

Đó là khi mọi thứ trở nên kỳ lạ

Tôi đã bắt đầu bằng cách phá vỡ logic ra khỏi hàm và chỉ cần gọi nó trực tiếp, với một dấu và ở cuối các lệnh được đặt. Thích như vậy:

ssh $BOUNCER "nc -k -l -U /tmp/weechat.notify.sock" | \
  while read type message; do
    notify-send -i weechat -u critical "$(echo -n $type | base64 -di -)" "$(echo -n $message | base64 -di -)"
  done &

Ngay khi tôi làm điều đó, các tin nhắn đột nhiên bắt đầu hoạt động. Và ngay sau khi tôi hoàn nguyên thay đổi, tôi đã quay lại quảng trường với hành vi chỉ có hai tin nhắn kỳ lạ.

Nhưng sửa chữa này, giới thiệu một số hành vi kỳ lạ khác. Khi tôi ở trong phiên màn hình, tôi sẽ phải nhấn từng phím nhiều lần trước khi chương trình được đăng ký. Như thể có một điều kiện cuộc đua chiến đấu với STDIN.

Có lẽ hai phiên SSH đã chiến đấu với nó (mặc dù tôi không chắc tại sao) Tôi đã cố gắng đóng và / hoặc chiếm STDIN trên lệnh ssh đầu tiên thông qua nhiều phương tiện khác nhau. Chẳng hạn như bằng cách đặt ống : |trước nó, hoặc nối <&-hoặc </dev/nullsau phần SSH của đường ống. Và trong khi điều đó dường như đã giải quyết được tình trạng chủng tộc, điều này lại giới thiệu hành vi chỉ có hai tin nhắn.

Nghĩ rằng nó có thể có liên quan đến việc xử lý nhiều lớp phụ , sau đó tôi đã cố gắng tái tạo điều này bằng cách gói cuộc gọi SSH bằng bash -cnhư vậy : bash -c 'ssh $BOUNCER "nc -k -l -U /tmp/weechat.notify.sock" &'. Và điều này cũng thể hiện hành vi chỉ có hai tin nhắn.

Tôi cũng đã tiếp tục và thử nghiệm điều này trực tiếp trên máy từ xa (SSH đến localhost và gói trong hai lệnh bash -c) và chứng kiến ​​hành vi bị hỏng tương tự. Nó cũng dường như không liên quan đến việc gấp đôi gây ra các quá trình mồ côi. Vì nó dường như không quan trọng nếu quá trình kết thúc mồ côi hay không.

Tôi cũng xác minh điều này cũng xảy ra theozsh .

Có vẻ như điều này bằng cách nào đó liên quan đến cách xử lý STDIN và STDOUT khi một quy trình được chạy dưới các lớp xử lý phụ.

Repro. Hướng dẫn & straceđầu ra:

Để đơn giản hóa việc gỡ lỗi, tôi đã xóa SSH khỏi ảnh và viết hai tập lệnh kiểm tra đơn giản hóa để tái tạo thành công hành vi hoàn toàn cục bộ.

Sử dụng socketlệnh của Juergen Nickelsen, tôi đã tạo một Ổ cắm tên miền UNIX ( socket -l -s ./test.sock) cục bộ và một lần nữa có thể gửi tin nhắn thử nghiệm tới nó bằng irbcách sử dụng đoạn mã Ruby sau:

require 'socket'
require 'base64'

SOCKET = './test.sock'

def send(subtitle, message)
  UNIXSocket.open(SOCKET) do |socket|
    socket.puts "#{Base64.strict_encode64(subtitle)} #{Base64.strict_encode64(message)}"
  end
end

send('test', 'hi')
send('test', 'hi')
send('test', 'hi')
send('test', 'hi')
send('test', 'hi')
send('test', 'hi')

Tập lệnh đầu tiên chỉ làm nền cho biểu thức đường ống (như đã nêu trước đây, đã xử lý số lượng tin nhắn không giới hạn):

#!/bin/bash

# to aid in cleanup when using Ctrl-C to exit strace
trap "pkill -f -x 'nc -k -l -U $HOME/test.sock'; exit" SIGINT

# Start listening for notifications
nc -k -l -U $HOME/test.sock | \
  while read type message; do
    # write messages to a local file instead of sending to notification daemon for simplicity.
    echo "$(echo -n $type | base64 -di -)" "$(echo -n $message | base64 -di -)" >> /tmp/msg
  done &

read

Và tạo ra đầu ra sau khi chạy với strace -f: http://pastebin.com/SMjti3qW

Tập lệnh thứ hai làm nền cho chức năng gói (kích hoạt hành vi 2 và thực hiện):

#!/bin/bash

# to aid in cleanup when using Ctrl-C to exit strace
trap "pkill -f -x 'nc -k -l -U $HOME/test.sock'; exit" SIGINT

# Start listening for notifications
function irc_notify() {
  nc -k -l -U $HOME/test.sock | \
    while read type message; do
      # write messages to a local file instead of sending to notification daemon for simplicity.
      echo "$(echo -n $type | base64 -di -)" "$(echo -n $message | base64 -di -)" >> /tmp/msg
    done
}

irc_notify &

read

Và lần lượt, đã tạo ra đầu ra sau đây khi chạy với strace -f: http://pastebin.com/WsrXX0EJ

Một điều nổi bật với tôi khi nhìn vào straceđầu ra từ các tập lệnh trên là đầu ra cụ thể cho nclệnh . Dường như cho thấy một trong những khác biệt chính giữa việc thực hiện hai tập lệnh này.

Đầu ra "làm việc" của tập lệnh đầu tiênnc strace :

accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3,

Hành vi "2 và xong" của Script thứ hai được thấy ở nc straceđầu ra:

accept(3, {sa_family=AF_FILE, NULL}, [2]) = 4
poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 2 ([{fd=4, revents=POLLIN|POLLHUP}, {fd=0, revents=POLLHUP}])
read(4, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
shutdown(4, 1 /* send */)               = 0
close(0)                                = 0
poll([{fd=4, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=4, revents=POLLIN|POLLHUP}])
read(4, "", 2048)                       = 0
shutdown(4, 0 /* receive */)            = 0
close(4)                                = 0
accept(3, {sa_family=AF_FILE, NULL}, [2]) = 0
poll([{fd=0, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 2 ([{fd=0, revents=POLLIN|POLLHUP}, {fd=0, revents=POLLIN|POLLHUP}])
read(0, "dGVzdA== aGk=\n", 2048)        = 14
write(1, "dGVzdA== aGk=\n", 14)         = 14
read(0, "", 2048)                       = 0
shutdown(0, 1 /* send */)               = 0
close(0)                                = 0
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
poll([{fd=0, events=POLLIN}, {fd=-1}], 2, -1) = 1 ([{fd=0, revents=POLLNVAL}])
.......[truncated].......

Tôi không phải là nơi tôi muốn liên quan đến stracekhả năng đọc đầu ra của mình , vì vậy tôi không chắc chắn chính xác những gì các đầu ra khác nhau này có nghĩa là vượt qua sự thật rằng một cái rõ ràng là hoạt động trong khi cái kia thì không.

Khi tôi đi qua straceđầu ra lớn hơn , có vẻ như các tin nhắn sau hai lần đầu tiên không còn bị chấm dứt bởi một dòng mới? Nhưng một lần nữa, tôi không chắc điều đó có nghĩa gì, hoặc nếu tôi đọc đúng.

Và tôi chắc chắn không hiểu làm thế nào các kỹ thuật xử lý phụ khác nhau, hoặc thậm chí đóng STDIN, có thể ảnh hưởng đến hành vi này.

Có ai biết tôi đang gặp phải điều gì ở đây không?

-

tl; dr

Tôi đang cố gắng tìm hiểu tại sao chạy trình nghe thông báo của mình dưới nhiều lớp kết quả xử lý phụ chỉ trong hai tin nhắn được xử lý; và không làm như vậy dẫn đến tình trạng đua trên STDIN.


Lưu ý rằng ssh -nsẽ ngăn đọc từ stdin, mặc dù điều này dường như không phải là nguyên nhân của vấn đề chính. Những gì hiện stracecủa ncchương trình khi so sánh với các tiến trình con? Là ncnhận và phát dữ liệu? Có phải nó đang chặn? Đóng stdout cho quy trình con có ảnh hưởng gì không?
zackse

thêm -nvào ssh dường như có tác dụng tương tự như bất kỳ nỗ lực nào khác để đóng STDIN (hai và thực hiện hành vi). Cũng như đóng STDIN trên quy trình con. Tôi chạy stracevào ncmặc dù, và nó cho thấy một số khác biệt về hành vi thú vị giữa kịch bản mà tất cả các thư nhận được thông qua ( pastebin.com/tCSwtA99 ), và khi chỉ có hai get qua ( pastebin.com/gZueVpb0 ). Tôi không phải là người giỏi nhất trong việc đọc straceđầu ra. Tôi có thể phải đào qua một số tài liệu gọi hệ thống để hiểu điều này.
CRThaze

Bạn có thể dán đầu ra của strace -f? Điều đó sẽ theo dĩa để bao gồm dấu vết từ tất cả các quy trình con sinh ra.
zackse

thêm -fvào nc stracekhông có bất kỳ ảnh hưởng nào, vì nckhông ngã ba chút nào. Tôi sẽ cung cấp cho bạn toàn bộ đầu ra để chạy trên tập lệnh phía máy khách, nhưng những gì nó cung cấp quá dài và chứa quá nhiều thông tin nhạy cảm (từ LDAP, v.v.) mà tôi không thể vệ sinh đúng cách để dán ở đây. Nhưng tôi có thể nói với bạn rằng, những gì tôi luôn quan sát khi tôi thử rằng hai tin nhắn luôn được chuyển qua, nhưng tin nhắn cuối cùng dường như không bị chấm dứt chính xác (nó thiếu một ký tự dòng mới) hoặc một cái gì đó, và dường như trùng với khi ncbắt đầu phun poll()tin nhắn.
CRThaze

ĐỒNG Ý. Vì vậy, tôi đã tái tạo hành vi này sau khi xóa SSH khỏi ảnh và thực hiện mọi thứ cục bộ mà kết quả là straceđầu ra sạch hơn . Tôi đã chạy hai phiên bản của kịch bản thử nghiệm này với strace -f; một trong đó làm nền cho biểu thức đường ống và sẽ xử lý các thông báo kiểm tra không giới hạn ( pastebin.com/GDjxTJuJ ) và một trong đó làm nền cho chức năng gói và chỉ xử lý hai thông báo trước khi ngắt ( pastebin.com/GMtkKefP ). Đầu strace -fra của các tập lệnh tương ứng này là 1) pastebin.com/SMjti3qW và 2) pastebin.com/WsrXX0EJ
CRThaze

Câu trả lời:


1

Các dẫn xuất mới hơn của OpenBSD netcat, bao gồm FreeBSD [1] và Debian [2], hỗ trợ một -dcờ ngăn việc đọc từ stdin và khắc phục vấn đề bạn mô tả.

Vấn đề là netcat đang bỏ phiếu stdin cũng như fd "mạng" của nó và stdin được mở lại từ /dev/nulltrường hợp thứ hai ở trên, nơi hàm shell được chạy trong nền trước khi đường ống được tạo. Điều đó có nghĩa là EOF ngay lập tức trong lần đọc đầu tiên từ stdin (fd 0), nhưng netcat sẽ tiếp tục poll(2)trên stdin hiện đang đóng, tạo ra một vòng lặp vô tận.

Đây là sự chuyển hướng của stdin trước khi tạo đường ống:

249 [pid 23186] open("/dev/null", O_RDONLY <unfinished ...>
251 [pid 23186] <... open resumed> )        = 3
253 [pid 23186] dup2(3, 0)                  = 0
254 [pid 23186] close(3)                    = 0

Bây giờ khi netcat (pid 23187) gọi lần đầu tiên poll(2), nó đọc EOF từ stdin và đóng fd 0:

444 [pid 23187] poll([{fd=4, events=POLLIN}, {fd=0, events=POLLIN}], 2, 4294967295) = 2 ([{fd=4, revents=POLLIN|POLLHUP}, {fd=0, revents=POLLIN}])
448 [pid 23187] read(0,  <unfinished ...>
450 [pid 23187] <... read resumed> "", 2048) = 0
456 [pid 23187] close(0 <unfinished ...>
458 [pid 23187] <... close resumed> )       = 0

Cuộc gọi tiếp theo accept(2)mang lại một khách hàng trên fd 0, hiện là fd miễn phí được đánh số thấp nhất:

476 [pid 23187] accept(3,  <unfinished ...>
929 [pid 23187] <... accept resumed> {sa_family=AF_LOCAL, NULL}, [2]) = 0

Lưu ý ở đây rằng netcat hiện bao gồm fd 0 trong các đối số thành poll(2)hai lần: một lần cho STDIN_FILENO, điều này luôn được bao gồm trong trường hợp không có -dtham số dòng lệnh và một lần cho máy khách mới được kết nối:

930 [pid 23187] poll([{fd=0, events=POLLIN}, {fd=0, events=POLLIN}], 2, 4294967295) = 2 ([{fd=0, revents=POLLIN|POLLHUP}, {fd=0, revents=POLLIN|POLLHUP}])

Máy khách gửi ngắt kết nối EOF và netcat:

936 [pid 23187] read(0,  <unfinished ...>
938 [pid 23187] <... read resumed> "", 2048) = 0
940 [pid 23187] shutdown(0, SHUT_WR <unfinished ...>
942 [pid 23187] <... shutdown resumed> )    = 0
944 [pid 23187] close(0 <unfinished ...>
947 [pid 23187] <... close resumed> )       = 0

Nhưng bây giờ nó đang gặp rắc rối vì nó sẽ tiếp tục thăm dò ý kiến ​​trên fd 0, hiện đã đóng cửa. Mã netcat không xử lý trường hợp POLLNVALđược đặt trong .reventsthành viên của struct pollfd, do đó, nó đi vào một vòng lặp vô tận, không bao giờ gọi accept(2)lại:

949 [pid 23187] poll([{fd=0, events=POLLIN}, {fd=-1}], 2, 4294967295 <unfinished ...>
951 [pid 23187] <... poll resumed> )        = 1 ([{fd=0, revents=POLLNVAL}])
953 [pid 23187] poll([{fd=0, events=POLLIN}, {fd=-1}], 2, 4294967295 <unfinished ...>
955 [pid 23187] <... poll resumed> )        = 1 ([{fd=0, revents=POLLNVAL}])
...

Trong lệnh đầu tiên, nơi đường ống được làm nền nhưng không chạy trong hàm shell, stdin bị bỏ ngỏ, vì vậy trường hợp này không phát sinh.

Tham chiếu mã (xem readwritechức năng):

  1. http://svnweb.freebsd.org/base/head/contrib/netcat/
  2. https://source.debian.net/src/netcat-openbsd/1.105-7/

Ah! Vì vậy, giải thích tại sao backgrounding chức năng phương pháp khác nhau đóng STDIN dẫn đến sự chính xác hành vi tương tự. Bởi vì tất cả chúng đều dẫn đến một đường ống dẫn đến hư không nc. Tôi đã rất quan tâm đến việc xử lý phụ, khi thay vào đó, vấn đề nằm ở phần mô tả tệp. Điều này hoàn toàn giải quyết vấn đề của tôi và cung cấp một lời giải thích chi tiết. Cảm ơn!
CRThaze

Câu hỏi: không nên SIGTTIN đối phó với loại hành vi này và ngăn chặn tình trạng chủng tộc trên STDIN? Điều này có nghĩa nclà chỉ đơn giản là không tôn vinh Tín hiệu?
CRThaze

Nếu cha mẹ không đóng (hoặc chuyển hướng) STDIN và nccố đọc từ nó, thì có, nó sẽ nhận được SIGTTIN, vì STDIN vẫn được gắn vào thiết bị đầu cuối của bạn. Bạn có thể quan sát điều này bằng cách chạy cat &trong vỏ của bạn và lưu ý rằng nó bị dừng ngay lập tức do SIGTTIN. Tuy nhiên, trong trường hợp trên, cha mẹ chuyển hướng STDIN từ /dev/nullđó, có tác dụng ngắt kết nối STDIN khỏi tty của bạn. Sau đó, khi ncđọc fd 0, nó đang đọc từ /dev/null. Điều đó có ý nghĩa?
zackse

Vâng, tôi hiểu làm thế nào điều này hoạt động khi nó chỉ xử lý hai tin nhắn. Nhưng tôi đang đề cập đến khi tôi gặp phải tình trạng chủng tộc khi tôi chỉ làm nền cho biểu thức đường ống và sau đó thấy rằng chỉ một số tổ hợp phím của tôi được đọc bởi Weechat qua SSH.
CRThaze

1
Để sửa nhận xét trước đó của tôi, ncsẽ chỉ nhận được tín hiệu read(2)nếu bạn bắt đầu đường dẫn từ vỏ tương tác (nghĩa là không phải từ tập lệnh), vì sau đó nó sẽ ở trong nền. Nhưng ở đây, trong một tập lệnh shell nằm ở phía trước, các quy trình con ( ssh/ ncpipe, ssh ... screen) là một phần của cùng một nhóm quy trình, do đó không có tín hiệu nào được phát. Khi bạn làm nền cho đường ống, bạn thực sự đã thấy một trường hợp trong đó hai quy trình đang "chiến đấu" với STDIN, bởi vì cả hai đều là một phần của cùng một nhóm quy trình tiền cảnh có quyền truy cập vào thiết bị đầu cuối kiểm soát.
zackse

1

Có vấn đề biến mất nếu bạn chạy các chức năng như thế này?

irc_notify </dev/null &

Nếu vậy, vấn đề có lẽ là hai quá trình đồng thời cố gắng đọc từ stdin. Chạy tất cả các lệnh ssh với -n, như zackse đã đề xuất, cũng có thể giúp ích, ít nhất là để gỡ lỗi các quá trình đang chiến đấu với stdin.


Kết quả tương tự như thể tôi không đặt </dev/null. Tôi không nhận được điều kiện cuộc đua trên STDIN, nhưng chỉ có hai thông báo vượt qua.
CRThaze
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.