Làm thế nào để có được tên thật của thiết bị đầu cuối kiểm soát?


13

Làm thế nào người ta có thể lấy tên thật của thiết bị đầu cuối kiểm soát (nếu có một lỗi khác) làm tên đường dẫn?

Theo "tên thật", ý tôi là không /dev/tty, không thể được sử dụng bởi các quy trình tùy ý khác để chỉ đến cùng một thiết bị đầu cuối. Tôi thích câu trả lời là mã shell đơn giản (như ví dụ bên dưới) nếu có thể, nếu không thì là hàm C.

Lưu ý rằng điều này phải hoạt động ngay cả khi đầu vào tiêu chuẩn được chuyển hướng, do đó ttykhông thể sử dụng tiện ích: người ta sẽ gặp not a ttylỗi trong trường hợp đó, vì ttychỉ in tên tệp của thiết bị đầu cuối được kết nối với đầu vào tiêu chuẩn.

Trong Linux, người ta có thể sử dụng:

echo "/dev/`ps -p $$ -o tty | tail -n 1`"

nhưng đây không phải là di động, vì theo POSIX, định dạng của tên thiết bị đầu cuối là không xác định .

Liên quan đến chức năng C, ctermid (NULL)trả về /dev/tty, đó là vô dụng ở đây.

Lưu ý: theo zshtài liệu, người ta có thể làm

zsh -c 'echo $TTY'

nhưng hiện tại (phiên bản 5.0.7) không thành công khi cả đầu vào tiêu chuẩn và đầu ra tiêu chuẩn đều được chuyển hướng:

$ zsh -c 'echo $TTY > /dev/tty' < /dev/null
/dev/pts/9
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null > /dev/null
/dev/tty

@mikeerv Tôi nghĩ rằng psgiải pháp này bao gồm hầu hết các hệ thống (và whokhông giúp được gì nhiều hơn ps), có thể có thêm một chút mã để xử lý mã định danh một mình (như "04"). Tôi đã tự hỏi nếu có một giải pháp di động hơn nữa.
vinc17

Nó có thể phải làm với các bộ được ghép nối trước - có thể là các cặp pty kiểu bsd cũ . Không phải tất cả các pty đều là loại UNIX 98. Dù sao, từ man xterm: -Sccn Tùy chọn này cho phép xtermđược sử dụng làm kênh i / o cho một chương trình hiện có ... Giá trị tùy chọn là một vài chữ cái tên của một pty để sử dụng trong chế độ nô lệ, cộng với số fd được kế thừa. Nếu tùy chọn chứa một ký tự của người Viking /, nó sẽ phân định tên pty từ fd.
mikeerv

@mikeserv Lưu ý rằng các giải pháp không làm việc với pstừ busybox (được sử dụng bởi Android, BTW), ngay cả dưới GNU / Linux. Bạn có ý nghĩa gì bởi " xtermcó thể xử lý 04"?
vinc17

busyboxkhông phù hợp với POSIX. toyboxTuy nhiên, làm rất tốt.
mikeerv

Câu trả lời:


8

"Thiết bị đầu cuối kiểm soát" aka. ctty, được distincted từ " các quá trình thiết bị đầu cuối được tương tác với".

Cách tiêu chuẩn để có được đường dẫn của ctty là ctermid (3). Khi gọi điều này, trong freebsd kể từ phiên bản 10, một đường dẫn thực tế được tìm kiếm [1], trong khi các triển khai freebsd và glibc cũ hơn [2] trả về vô điều kiện "/ dev / tty"].

ps (1) từ gói linux 3.2 3.2, đọc mục nhập số trong / Proc / * / stat [3], sau đó khấu trừ một phần tên đường dẫn bằng cách đoán [4, 5] do thiếu hỗ trợ hệ thống [6] .

Tuy nhiên, nếu chúng ta không thực sự quan tâm đến ctty nhưng bất kỳ thiết bị đầu cuối nào được liên kết với stdio, tty (1) sẽ in đường dẫn đầu cuối được kết nối với stdin, giống hệt ttyname(fileno(stdin))trong c, và một phương án khác là readlink /proc/self/fd/0.


Suy nghĩ ít quan trọng hơn về hành vi "/ dev / tty" vô điều kiện: Thông số kỹ thuật chỉ nói chuỗi được trả về bởi ctermid "khi được sử dụng làm tên đường dẫn, tham khảo thiết bị đầu cuối kiểm soát hiện tại", thay vì một số đơn giản "là tên đường dẫn của hiện tại thiết bị đầu cuối điều khiển ". Nó có thể được hiểu là "/ dev / tty" không phải là thiết bị đầu cuối kiểm soát, mà chỉ đề cập đến thiết bị đầu cuối kiểm soát nếu cùng một quá trình mở (3). Do đó, không vi phạm quy tắc "thiết bị đầu cuối có thể là ctty trong tối đa một phiên" [7].

Một hậu quả khác là khi tôi không có bất kỳ thiết bị đầu cuối điều khiển nào, ctermid không thất bại - sự thất bại đó được cho phép bởi thông số kỹ thuật [8] - vì vậy tôi chỉ có thể nhận thức được tình trạng của mình cho đến khi thất bại trong lần mở tiếp theo (3), Không sao vì thông số kỹ thuật cũng nói rằng việc gọi mở (3) trên đó không đảm bảo sẽ thành công.


Đây không phải là khả năng di động nhiều hơn psgiải pháp tôi đưa ra trong câu hỏi của mình, vì không phải tất cả các hệ điều hành đều có /prochệ thống tệp. Lưu ý rằng pschính nó sử dụng một đường dẫn đọc trên /proc/self/fd/2(hoạt động ngay cả khi lỗi tiêu chuẩn được chuyển hướng).
vinc17

1
chỉnh sửa. và ps readlink trên / Proc / * / fd / 2 không phải để tìm ctty, nhưng để tìm thông tin bổ sung để ánh xạ thiết bị đầu cuối số tới đường dẫn, xem liên kết [4] [5].
把 友情 留 在

1
Chỉnh sửa tuyệt vời. Về ctty; Tôi không thể nói cho vinc17, nhưng trong khi bạn có thể luôn luôn viết vào một nơi nào đó, chỉ có một tệp phải mở để giữ cho nhóm quy trình của bạn tồn tại.
mikeerv

1
@ vinc17 - nếu bạn có bất kỳ mô tả tập tin nào mở trên ctty của bạn thì bạn có thể đọc chúng với tty. stderrcó lẽ là tốt nhất bởi vì nó sẽ được mở r / w. Vì vậy tty <&2.
mikeerv

1
Rằng một thiết bị đầu cuối nhất định có thể là ctty trong tối đa một phiên không làm cho glibc không tuân thủ vì ctermid()luôn luôn quay trở lại "/dev/tty". Tên đó luôn luôn đề cập đến thiết bị đầu cuối kiểm soát của quá trình truy cập nó , thay đổi theo phiên. Thiết bị đầu cuối là phiên cụ thể, nhưng tên mà nó được truy cập không cần phải có.
PellMel

5

Thông số POSIX thực sự ngăn chặn các cược của nó trong đó Thiết bị đầu cuối kiểm soát có liên quan và do đó nó xác định:

  • Thiết bị đầu cuối điều khiển
    • Câu hỏi trong đó có thể có một số tệp đặc biệt đề cập đến thiết bị đầu cuối có nghĩa là không được giải quyết trong POSIX.1. Tên đường dẫn /dev/ttylà từ đồng nghĩa với thiết bị đầu cuối kiểm soát được liên kết với một quy trình.

Đó là trong danh sách Định nghĩa - và đó là tất cả ở đó. Nhưng trong Giao diện thiết bị đầu cuối chung , một số người khác nói:

  • Một thiết bị đầu cuối có thể thuộc về một quá trình như thiết bị đầu cuối kiểm soát của nó. Mỗi quá trình của một phiên có một thiết bị đầu cuối kiểm soát có cùng một thiết bị đầu cuối kiểm soát. Một thiết bị đầu cuối có thể là thiết bị đầu cuối kiểm soát tối đa một phiên. Thiết bị đầu cuối kiểm soát cho một phiên được phân bổ bởi người lãnh đạo phiên theo cách xác định thực hiện. Nếu một nhà lãnh đạo phiên không có thiết bị đầu cuối kiểm soát và mở tệp thiết bị đầu cuối chưa được liên kết với phiên mà không sử dụng tùy chọn O_NOCTTY (xem open ()), thì đó có phải là thiết bị đầu cuối xác định liệu thiết bị đầu cuối có trở thành thiết bị đầu cuối điều khiển của phiên không lãnh đạo.

  • Thiết bị đầu cuối điều khiển được kế thừa bởi một tiến trình con trong lệnh gọi hàm fork (). Một quá trình từ bỏ thiết bị đầu cuối kiểm soát của nó khi nó tạo ra một phiên mới vớisetsid()chức năng; các quy trình khác còn lại trong phiên cũ có thiết bị đầu cuối này khi thiết bị đầu cuối kiểm soát của chúng tiếp tục có thiết bị đầu cuối. Khi đóng bộ mô tả tệp cuối cùng trong hệ thống (có hoặc không có trong phiên hiện tại) được liên kết với thiết bị đầu cuối kiểm soát, không xác định được liệu tất cả các quy trình có thiết bị đầu cuối đó như thiết bị đầu cuối kiểm soát của chúng có dừng bất kỳ thiết bị đầu cuối kiểm soát nào không. Liệu và làm thế nào một nhà lãnh đạo phiên có thể yêu cầu thiết bị đầu cuối kiểm soát sau khi thiết bị đầu cuối kiểm soát đã bị từ bỏ theo cách này không được chỉ định. Một quy trình không từ bỏ thiết bị đầu cuối kiểm soát của nó chỉ bằng cách đóng tất cả các mô tả tệp được liên kết với thiết bị đầu cuối kiểm soát nếu các quy trình khác tiếp tục mở.

Có rất nhiều điều còn lại chưa được xác định - và thành thật mà nói tôi nghĩ nó có ý nghĩa. Mặc dù thiết bị đầu cuối là giao diện người dùng chính, nhưng trong một số trường hợp, nó cũng là một số thứ khác - như phần cứng thực tế, hoặc thậm chí là một loại máy in - nhưng trong nhiều trường hợp thực tế không có gì cả - giống như xtermmột trình giả lập . Thật khó để có được thông tin cụ thể ở đó - và tôi không nghĩ rằng dù sao thì nó cũng sẽ được Unix quan tâm, bởi vì các thiết bị đầu cuối làm được nhiều hơn so với Unix.

Dù sao, POSIX cũng khá iffy về cách psứng xử nơi ctty có liên quan.

Có công -atắc:

  • Viết thông tin cho tất cả các quá trình liên quan đến thiết bị đầu cuối. Việc triển khai có thể bỏ qua các nhà lãnh đạo phiên từ danh sách này.

Tuyệt quá. Lãnh đạo phiên có thể được bỏ qua. Điều đó không hữu ích lắm.

-t:

  • Viết thông tin cho các quá trình liên quan đến thiết bị đầu cuối được đưa ra trong danh sách thuật ngữ. Ứng dụng phải đảm bảo rằng danh sách thuật ngữ là một đối số duy nhất ở dạng <blank>danh sách hoặc được phân tách bằng dấu phẩy. Định danh thiết bị đầu cuối sẽ được cung cấp trong một định dạng xác định thực hiện .

... đó là một sự thất vọng khác. Nhưng nó tiếp tục nói điều này về các hệ thống XSI:

  • Trên các hệ thống tuân thủ XSI, chúng sẽ được cung cấp ở một trong hai dạng: tên tệp của thiết bị (ví dụ tty04:) hoặc, nếu tên tệp của thiết bị bắt đầu bằng tty, chỉ là mã định danh theo sau các ký tự tty (ví dụ 04:) .

Điều đó tốt hơn một chút, nhưng không phải là một con đường. Ngoài ra trên các hệ thống XSI còn có công -dtắc:

  • Viết thông tin cho tất cả các quy trình, ngoại trừ các nhà lãnh đạo phiên.

... ít nhất là rõ ràng. Bạn có thể chỉ định công -otắc utput cũng như với ttychuỗi định dạng, nhưng, như bạn đã lưu ý, định dạng đầu ra của nó được xác định theo thực hiện. Tuy nhiên, tôi nghĩ rằng nó là tốt như nó được. Tôi nghĩ rằng - với rất nhiều công việc - các công tắc trên kết hợp với một số tiện ích khác có thể giúp bạn có một sân bóng khá tốt. Thành thật mà nói, tôi không biết khi nào / nó phá vỡ cho bạn như thế nào - và tôi không thể tưởng tượng được một tình huống sẽ xảy ra. Nhưng, tôi nghĩ có lẽ nếu chúng ta thêm fuserfindchúng ta có thể xác minh đường dẫn.

exec 2<>/dev/null
ctty=$(sh -c 'ps -p "$$" -o tty=' <&2)
sid=$(sh -c 'ps -Ao pid= -o tty=|
      grep '"$ctty$"' | 
      grep -Fv "$(ps -do pid=)"'  <&2)
find / -type c -name "*${ctty##*/}*" \
       -exec fuser -uv {} \; 2>&1  |
grep ".*$ctty.*${sid%%"$ctty"*}"

Các /dev/nullcông cụ chỉ để cho thấy rằng nó có thể hoạt động khi không có mạng con tìm kiếm nào có bất kỳ 0,1,2 nào được kết nối với ctty. Dù sao, đó là bản in:

/dev/pts/3:          mikeserv   3342 F.... (mikeserv)zsh

Bây giờ ở trên có đường dẫn đầy đủ trên máy của tôi, và tôi tưởng tượng nó sẽ phù hợp với hầu hết mọi người trong hầu hết các trường hợp. Tôi cũng có thể tưởng tượng nó có thể thất bại. Nó chỉ là heuristic thô.

Điều này có thể thất bại vì nhiều lý do khác có thể, nhưng nếu bạn đang ở trong một hệ thống cho phép người lãnh đạo phiên từ bỏ tất cả các mô tả cho ctty và vẫn duy trì bên cạnh như thông số kỹ thuật cho phép, thì điều này chắc chắn sẽ không có ích. Điều đó nói rằng, tôi nghĩ rằng điều này có thể có được một ước tính khá tốt trong hầu hết các trường hợp.

Tất nhiên, điều dễ nhất để làm nếu bạn có bất kỳ mô tả nào được kết nối với ctty của bạn chỉ là ...

tty <&2

...hoặc tương tự.

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.