วิธีรับชื่อจริงของเทอร์มินัลการควบคุม?


13

เราจะได้รับชื่อจริงของเทอร์มินัลการควบคุมได้อย่างไร (ถ้ามีอีกหนึ่งข้อผิดพลาด) เป็นชื่อพา ธ

โดย "ชื่อจริง" ฉันหมายถึงไม่/dev/ttyซึ่งไม่สามารถใช้โดยกระบวนการอื่น ๆ เพื่ออ้างถึงเทอร์มินัลเดียวกัน ฉันชอบคำตอบเป็นรหัสเปลือกง่าย (เช่นตัวอย่างด้านล่าง) ถ้าเป็นไปได้มิฉะนั้นเป็นฟังก์ชั่น C

โปรดทราบว่าสิ่งนี้จะต้องใช้งานได้แม้ว่าจะมีการเปลี่ยนเส้นทางอินพุตมาตรฐานเพื่อให้ttyไม่สามารถใช้ยูทิลิตี้: หนึ่งจะได้รับnot a ttyข้อผิดพลาดในกรณีเช่นนี้เนื่องจากttyเพียงพิมพ์ชื่อไฟล์ของเทอร์มินัลที่เชื่อมต่อกับอินพุตมาตรฐาน

ภายใต้ Linux สามารถใช้:

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

แต่นี้ไม่ได้พกพาเป็นไปตาม POSIX, รูปแบบของชื่อสถานีเป็นที่ไม่ได้ระบุ

เกี่ยวกับฟังก์ชั่น C, ctermid (NULL)ส่งคืน/dev/ttyซึ่งไม่มีประโยชน์ที่นี่

หมายเหตุ:ตามzshเอกสารประกอบอย่างใดอย่างหนึ่งที่สามารถทำได้

zsh -c 'echo $TTY'

แต่ตอนนี้ (เวอร์ชั่น 5.0.7) ล้มเหลวเมื่อทั้งอินพุตมาตรฐานและเอาต์พุตมาตรฐานถูกเปลี่ยนเส้นทาง:

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

@mikeserv ฉันคิดว่าpsโซลูชันนี้ครอบคลุมระบบส่วนใหญ่ (และwhoไม่ได้ช่วยอะไรมากไปกว่านั้นps) อาจมีโค้ดเพิ่มอีกนิดเพื่อจัดการตัวระบุเพียงอย่างเดียว (เช่น "04") ฉันสงสัยว่ามีวิธีแก้ปัญหาแบบพกพามากขึ้นหรือไม่
vinc17

มันอาจจะเกี่ยวข้องกับเซตที่จับคู่ไว้แล้ว - bsd- style pty pair เก่า ๆอาจจะเป็นเช่นนั้น ไม่ใช่ ptys ทั้งหมดเป็น UNIX 98 ชนิด อย่างไรก็ตามจากman xterm: -Sccn ตัวเลือกนี้อนุญาตให้xtermใช้เป็นช่องทาง i / o สำหรับโปรแกรมที่มีอยู่ได้ ... ค่าตัวเลือกคือตัวอักษรสองสามตัวของชื่อ pty ที่จะใช้ในโหมดทาสรวมถึงหมายเลข fd ที่สืบทอดมา หากตัวเลือกมีอักขระ“ /” มันจะลบชื่อ pty ออกจาก fd
mikeserv

@mikeserv โปรดทราบว่าโซลูชันไม่สามารถใช้งานได้psจากbusybox (ซึ่งใช้โดย Android, BTW) แม้แต่ภายใต้ GNU / Linux คุณหมายถึง " xtermสามารถจัดการกับสิ่งนั้น04"
vinc17

busyboxไม่สอดคล้องกับ POSIX toyboxอย่างไรก็ตามทำได้ดีมาก
mikeserv

คำตอบ:


8

"สถานีควบคุม" aka ctty เป็น distincted จาก " กระบวนการขั้วมีปฏิสัมพันธ์กับ"

วิธีมาตรฐานในการรับเส้นทางของ ctty คือ ctermid (3) เมื่อเรียกสิ่งนี้ ใน freebsd ตั้งแต่รีลีส 10 จะพบพา ธ ที่แท้จริง [1] ในขณะที่การใช้งาน freebsd และglibcที่เก่ากว่า[2] จะส่งคืน "/ dev / tty" โดยไม่มีเงื่อนไข

ps (1) จากแพ็คเกจ linux procps 3.2.8 อ่านรายการตัวเลขใน / proc / * / stat [3] จากนั้นหักชื่อพา ธ บางส่วนด้วยการเดา [4, 5] เนื่องจากไม่มีระบบรองรับ [6] .

แต่ถ้าเราไม่ได้สนใจอย่างเคร่งครัดใน ctty แต่ขั้วใด ๆ ที่เกี่ยวข้องกับ stdio, TTY (1) พิมพ์เส้นทางที่เชื่อมต่อกับขั้ว stdin ซึ่งเป็นเหมือนttyname(fileno(stdin))ใน c readlink /proc/self/fd/0และทางเลือกคือ


ความคิดที่สำคัญน้อยกว่าเกี่ยวกับพฤติกรรม "/ dev / tty" ที่ไม่มีเงื่อนไข: Specs เพียงพูดว่าสตริงที่ส่งคืนโดย ctermid "เมื่อใช้เป็นชื่อพา ธ อ้างถึงเทอร์มินัลการควบคุมปัจจุบัน" แทนที่จะตรงไปตรงมา "เป็นชื่อพา ธ ของปัจจุบัน เทอร์มินัลควบคุม ". มันอาจถูกตีความว่า "/ dev / tty" ไม่ใช่สถานีควบคุม แต่อ้างถึงสถานีควบคุมหากกระบวนการเดียวกันเปิด (3) ดังนั้นการไม่ละเมิดกฎ "เทอร์มินัลอาจเป็น ctty มากที่สุดหนึ่งเซสชัน" [7]

ผลที่ตามมาก็คือเมื่อฉันไม่มีเทอร์มินัลการควบคุม ctermid จะไม่ล้มเหลว - ความล้มเหลวดังกล่าวได้รับอนุญาตโดยสเป็ค [8] - ดังนั้นฉันสามารถรู้ได้ถึงความไม่มีตัวตนของฉันจนกว่าจะล้มเหลวในภายหลัง ซึ่งก็โอเคตั้งแต่สเปคก็บอกว่าการโทรแบบเปิด (3) นั้นไม่ได้รับประกันว่าจะประสบความสำเร็จ


นี่ไม่ใช่แบบพกพามากกว่าpsโซลูชันที่ฉันให้ไว้ในคำถามเนื่องจากระบบปฏิบัติการบาง/procระบบไม่มีระบบไฟล์ โปรดทราบว่าpsตัวเองใช้ readlink บน/proc/self/fd/2(ซึ่งใช้ได้แม้เป็นข้อผิดพลาดมาตรฐานถูกเปลี่ยนเส้นทาง)
vinc17

1
แก้ไข และ ps readlink บน / proc / * / fd / 2 ไม่พบ ctty แต่เพื่อค้นหาข้อมูลเพิ่มเติมเพื่อแมปเทอร์มินัลตัวเลขกับพา ธ ดูที่ลิงค์ [4] [5]
把友情留在无盐

1
แก้ไขที่ยอดเยี่ยม เกี่ยวกับ ctty ฉันไม่สามารถพูดเพื่อ vinc17 ได้ แต่ในขณะที่คุณสามารถเขียนไปยังที่อื่นได้ตลอดเวลามีเพียงไฟล์เดียวเท่านั้นที่ต้องเปิดอยู่เพื่อให้กระบวนการกลุ่มของคุณมีชีวิตอยู่
mikeserv

1
@ vinc17 - หากคุณเปิดไฟล์อธิบายใด ๆไว้บน ctty คุณก็สามารถอ่านมันttyได้ stderrน่าจะดีที่สุดเพราะสเป็คของมันจะเปิด r / w tty <&2ดังนั้น
mikeserv

1
ที่สถานีได้รับอาจจะ ctty สำหรับมากที่สุดคนหนึ่งเซสชั่นไม่ได้ทำให้ glibc ไม่สอดคล้องสำหรับด้านเสมอกลับมาctermid() "/dev/tty"ชื่อนั้นอ้างถึงเทอร์มินัลการควบคุมของกระบวนการเข้าถึงเสมอซึ่งจะแตกต่างกันไปตามเซสชัน เทอร์มินัลเป็นเฉพาะเซสชัน แต่ชื่อที่เข้าถึงไม่จำเป็นต้องเป็น
PellMel

5

POSIX spec ป้องกันความเสี่ยงของการเดิมพันในส่วนที่เกี่ยวข้องกับเทอร์มินัลการควบคุมและกำหนด:

  • เทอร์มินัลการควบคุม
    • คำถามที่อาจหมายถึงไฟล์พิเศษหลายไฟล์ที่อ้างถึงเทอร์มินัลไม่ได้อยู่ใน POSIX.1 ชื่อพา ธ/dev/ttyคือคำพ้องความหมายสำหรับเทอร์มินัลการควบคุมที่เกี่ยวข้องกับกระบวนการ

ที่อยู่ในรายการคำจำกัดความ - และนั่นคือทั้งหมดที่มี แต่ในGeneral Terminal Interfaceบางคนกล่าวว่า:

  • เทอร์มินัลอาจเป็นของกระบวนการในฐานะเทอร์มินัลการควบคุม แต่ละกระบวนการของเซสชันที่มีเทอร์มินัลการควบคุมมีเทอร์มินัลการควบคุมเดียวกัน เทอร์มินัลอาจเป็นเทอร์มินัลการควบคุมได้ไม่เกินหนึ่งเซสชัน เทอร์มินัลการควบคุมสำหรับเซสชันได้รับการจัดสรรโดยผู้นำเซสชันในลักษณะที่กำหนดไว้ในการนำไปปฏิบัติ หากผู้นำเซสชันไม่มีเทอร์มินัลการควบคุมและเปิดไฟล์อุปกรณ์เทอร์มินัลที่ไม่ได้เชื่อมโยงกับเซสชันโดยไม่ใช้ตัวเลือก O_NOCTTY (ดู open ()) จะมีการกำหนดการนำไปใช้งานไม่ว่าจะกลายเป็นเทอร์มินัล หัวหน้า.

  • เทอร์มินัลการควบคุมนั้นสืบทอดโดยกระบวนการลูกในระหว่างการเรียกใช้ฟังก์ชัน fork () กระบวนการเลิกใช้เทอร์มินัลการควบคุมเมื่อสร้างเซสชันใหม่ด้วยsetsid()ฟังก์ชั่น; กระบวนการอื่นที่เหลืออยู่ในเซสชันเก่าที่มีเทอร์มินัลนี้เนื่องจากเทอร์มินัลการควบคุมของพวกเขายังคงมีอยู่ เมื่อปิดตัวอธิบายไฟล์สุดท้ายในระบบ (หรือไม่ว่าจะอยู่ในเซสชันปัจจุบัน) ที่เชื่อมโยงกับเทอร์มินัลการควบคุมจะไม่มีการระบุว่ากระบวนการทั้งหมดที่มีเทอร์มินัลนั้นเป็นเทอร์มินัลการควบคุม ไม่ว่าผู้นำเซสชันจะสามารถเรียกคืนเทอร์มินัลการควบคุมได้อีกหรือไม่หลังจากที่เทอร์มินัลการควบคุมถูกปล่อยออกมาในรูปแบบนี้จะไม่มีการระบุ กระบวนการไม่ยกเลิกการควบคุมเทอร์มินัลเพียงแค่ปิดไฟล์ descriptors ทั้งหมดที่เชื่อมโยงกับเทอร์มินัลการควบคุมหากกระบวนการอื่นยังคงเปิดอยู่

มีหลายสิ่งที่เหลือไม่ระบุ - และโดยสุจริตฉันคิดว่ามันสมเหตุสมผล แม้ว่าเทอร์มินัลจะเป็นส่วนต่อประสานผู้ใช้ที่สำคัญ แต่ยังมีสิ่งอื่น ๆ อีกมากมายในบางกรณีเช่นฮาร์ดแวร์จริงหรือแม้กระทั่งเครื่องพิมพ์ชนิดหนึ่ง แต่ในหลาย ๆ กรณีมันแทบไม่มีอะไรเลย - xtermซึ่งเป็นเพียงอีมูเลเตอร์ . เป็นการยากที่จะระบุเฉพาะเจาะจง - และฉันไม่คิดว่ามันจะเป็นประโยชน์กับ Unix มากนักเนื่องจากเทอร์มินัลทำมากกว่า Unix

อย่างไรก็ตาม POSIX ก็ยังค่อนข้างแน่นอนว่าpsควรทำอย่างไรในกรณีที่ ctty เกี่ยวข้อง

มี-aสวิตช์:

  • เขียนข้อมูลสำหรับกระบวนการทั้งหมดที่เกี่ยวข้องกับเทอร์มินัล การใช้งานอาจละเว้นผู้นำเซสชันจากรายการนี้

ยิ่งใหญ่ ผู้นำเซสชันอาจถูกละเว้น นั่นไม่เป็นประโยชน์มาก

และ-t:

  • เขียนข้อมูลสำหรับกระบวนการที่เกี่ยวข้องกับเทอร์มินัลที่กำหนดในคำศัพท์ แอปพลิเคชันจะต้องทำให้แน่ใจว่า termlist เป็นอาร์กิวเมนต์เดี่ยวในรูปแบบของรายการ<blank>หรือคั่นด้วยเครื่องหมายจุลภาค ตัวระบุเทอร์มินัลจะได้รับในรูปแบบที่กำหนดการนำไปปฏิบัติ

... ซึ่งเป็นอีกสิ่งที่ทำให้ผิดหวัง แต่มันจะพูดเกี่ยวกับระบบ XSI ต่อไปนี้:

  • ในระบบ XSI สอดคล้องพวกเขาจะได้รับในหนึ่งในสองรูปแบบ: ชื่อไฟล์ของอุปกรณ์ (ตัวอย่างเช่นtty04) หรือหากอุปกรณ์ของชื่อไฟล์ที่เริ่มต้นด้วยttyเพียงแค่ระบุต่อไปนี้ตัวอักษรtty (ตัวอย่าง04 )

มันดีกว่านิดหน่อย แต่ไม่ใช่เส้นทาง นอกจากนี้ในระบบ XSI ยังมี-dสวิตช์อีกด้วย:

  • เขียนข้อมูลสำหรับกระบวนการทั้งหมดยกเว้นผู้นำเซสชัน

... ซึ่งอย่างน้อยก็ชัดเจน คุณสามารถระบุ-oสวิตช์ utput ได้เช่นกันกับttyสตริงรูปแบบ แต่ตามที่คุณได้ระบุไว้รูปแบบเอาท์พุทจะถูกกำหนดโดยการนำไปใช้งาน ถึงกระนั้นฉันคิดว่ามันดีเท่าที่จะได้รับ ฉันคิดว่า - ด้วยการทำงานมากมาย - สวิตช์ด้านบนประกอบกับระบบสาธารณูปโภคอื่น ๆ จะช่วยให้คุณได้สนามเบสบอลที่ดี พูดตามตรงฉันไม่ทราบว่ามันจะหยุดพักเมื่อไรและฉันไม่สามารถจินตนาการถึงสถานการณ์ที่จะเกิดขึ้นได้ แต่ฉันคิดว่าน่าจะเป็นถ้าเราเพิ่มfuserและfindเราสามารถตรวจสอบเส้นทาง

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"*}"

/dev/nullสิ่งที่เป็นเพียงเพื่อแสดงให้เห็นว่ามันจะทำงานเมื่อไม่มี subshells ค้นหามีใด ๆ ของ 0,1,2 เชื่อมต่อกับ ctty อย่างไรก็ตามที่พิมพ์:

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

ตอนนี้ได้รับเส้นทางเต็มบนเครื่องของฉันและฉันคิดว่ามันจะสำหรับคนส่วนใหญ่ในกรณีส่วนใหญ่ ฉันสามารถจินตนาการได้ว่ามันอาจล้มเหลว มันเป็นแค่ฮิวริสติกหยาบ

สิ่งนี้อาจล้มเหลวด้วยเหตุผลอื่น ๆ อีกมากมาย แต่ถ้าคุณอยู่ในระบบที่อนุญาตให้ผู้นำเซสชันเลิกใช้ descriptor ทั้งหมดไปที่ ctty และยังคง sid อยู่ตามที่ spec อนุญาตดังนั้นนี่จะไม่ช่วยได้แน่นอน ที่กล่าวว่าฉันคิดว่านี่อาจได้รับการประเมินที่ดีในกรณีส่วนใหญ่

ของหลักสูตรที่ง่ายที่สุดในสิ่งที่จะทำอย่างไรถ้าคุณมีใดอธิบายเชื่อมต่อกับ ctty ของคุณเป็นเพียง ...

tty <&2

... หรือคล้ายกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.