home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / pty4 / part05 / QUESTIONS < prev    next >
Encoding:
Text File  |  1992-02-18  |  8.0 KB  |  207 lines

  1. I selected the questions below from articles posted to the USENET
  2. newsgroup comp.unix.questions. All the questions are reasonably easy to
  3. answer with pty and not too easy to answer with other widely available
  4. tools. So I hope this file is useful, and I hope other software authors
  5. adopt the QUESTIONS idea.
  6.  
  7.  
  8.  
  9. 1. How do I redirect telnet's input?
  10.  
  11. Answer: Run pty telnet instead of telnet.
  12.  
  13. Long answer: Be careful---as soon as telnet successfully connects to the
  14. remote host, it flushes its input. So if you do something like
  15.  
  16.    (echo help; echo quit) | pty telnet whatever 25
  17.  
  18. telnet will read ``help'' and ``quit'', then after a second or two
  19. connect to the host, then flush the input. It won't get any input after
  20. that. An easy solution is to delay the input a few seconds:
  21.  
  22.    (sleep 5; echo help; echo quit) | pty telnet whatever 25
  23.  
  24. (Try it!) For a more robust solution, see question #4 below.
  25.  
  26. Why this was a problem: UNIX beginners learn that they can feed input to
  27. programs with redirection or with pipes. They're often surprised to see
  28. that this doesn't work:
  29.  
  30.    (echo help; echo quit) | telnet whatever 25
  31.  
  32. telnet, like many other utilities, considers itself an ``interactive''
  33. program. It assumes that it's talking to a user's terminal directly, so
  34. that it can put the terminal into character-at-a-time mode. If you
  35. redirect its input, it won't be able to find the terminal, and it'll
  36. complain or do weird things. Similar comments apply to editors, like vi.
  37.  
  38. Why the answer solves the problem: pty creates a pseudo-terminal---
  39. something which looks like a normal terminal but is under pty's control.
  40. pty runs telnet under the pseudo-terminal and forwards all input and
  41. output. Now telnet works, because it sees the pseudo-terminal and thinks
  42. it's talking to the user.
  43.  
  44.  
  45.  
  46. 2. How do I redirect passwd's input?
  47.  
  48. Answer: pty passwd.
  49.  
  50. Long answer: Like telnet, passwd flushes its input, so you probably want
  51. to do something like
  52.  
  53.    (sleep 5; echo oldpassword; sleep 5; echo newpassword; \
  54.      sleep 5; echo newpassword) | pty passwd
  55.  
  56. A better solution appears in #4 below. If you're using passwd as a
  57. system administrator to change somebody else's password, you want
  58.  
  59.    (sleep 5; echo password; sleep 5; echo password) | pty passwd shmoe
  60.  
  61. I certainly don't recommend keeping passwords visible in shell scripts,
  62. but if you ever need to do this, you can. In single-user mode this is
  63. reasonably safe.
  64.  
  65. Why this was a problem: passwd is even more insistent than telnet on
  66. talking to a user directly. So it opens /dev/tty for its input. Some
  67. other programs open /dev/tty for both input and output. This avoids any
  68. redirection you might have put into place.
  69.  
  70. Why the answer solves the problem: As before, pty creates a
  71. pseudo-terminal for passwd to talk to. When passwd opens /dev/tty, it
  72. gets the pseudo-terminal. All the redirection is outside pty, safe from
  73. passwd's tampering.
  74.  
  75.  
  76.  
  77. 3. Why doesn't tr '[A-Z]' '[a-z]' | cat -t print anything I type?
  78.  
  79. Answer: Do  nobuf tr '[A-Z]' '[a-z]' | cat -t.
  80.  
  81. Long answer: You can use pty -0 (also known as condom, or, if you're not
  82. in such a picturesque mood, as ttyprotect) in place of nobuf, but nobuf
  83. invokes pty carefully so that EOF on the input will be passed through to
  84. tr. The effect of this pipeline is to change all uppercase letters into
  85. lowercase, then print control characters visibly (e.g., ^H instead of
  86. backspace).
  87.  
  88. Why this was a problem: The original pipeline, without nobuf, doesn't
  89. seem to produce any output. What happens is that tr says ``Oh, I say.
  90. My output is going into a pipe! I guess there's no point in sending
  91. output as fast as possible. So I'll build up a buffer of output, say up
  92. to 8192 characters, before I send any of it.'' In fact, any program
  93. which uses stdio will do the same thing. The problem is that the guess
  94. is wrong---you don't want 8192 characters held inside tr. You want each
  95. line sent through without any buffering.
  96.  
  97. Why the answer solves the problem: Once again, nobuf (really pty)
  98. creates a pseudo-terminal and runs tr inside it. Then tr (really stdio)
  99. says ``Oh, I say. My output is going into a terminal! I'll bet there's a
  100. user watching every word. So I'll send each line as soon as I'm done
  101. with it.'' And it does.
  102.  
  103.  
  104.  
  105. 4. How do I start a program, respond to its prompts, give the correct
  106.    replies, and catch the output---all from a script?
  107.  
  108. If you're good at shell programming, you might have already figured out
  109. most of this. Let's say you're on a machine (like a Sun) which can
  110. create named pipes with mknod foo p. You might try to automate a telnet
  111. session, keeping a record in a file, like this:
  112.  
  113.   #!/bin/sh
  114.   (umask 077; mknod input p; mknod output p)
  115.   telnet foo < input | tee record > output &
  116.   exec 4>input 5<output
  117.   waitfor login: <&5 2>/dev/null
  118.   echo 'username' >&4
  119.   waitfor Password: <&5 2>/dev/null
  120.   echo 'password' >&4
  121.   # etc.
  122.  
  123. (waitfor reads its input, character by character, until its first
  124. argument matches the most recent characters as a literal string.)
  125.  
  126. This almost works. sh can handle this sort of automation without
  127. trouble. The only problem is that telnet is interactive. That's where
  128. pty comes in. This works:
  129.  
  130.   #!/bin/sh
  131.   (umask 077; mknod input p; mknod output p)
  132.   pty -0 telnet foo < input | nobuf tee record > output &
  133.   exec 4>input 5<output
  134.   waitfor login: <&5 2>/dev/null
  135.   echo 'username' >&4
  136.   waitfor Password: <&5 2>/dev/null
  137.   echo 'password' >&4
  138.   # etc.
  139.  
  140. On machines without named pipes, you'll have to create (unnamed) pipes
  141. in C. But whatever method of automation you use, pty will let you apply
  142. that method to an interactive program.
  143.  
  144.  
  145.  
  146. 5. How do I get rn to process KILL files in the background?
  147.  
  148. Answer:
  149.  
  150.    % sess -R sh -c 'sessname; rn' &
  151.    [1] 20417        < the shell prints this >
  152.    session pf       < this comes from sessname >
  153.    < rn produces output in the background, and you can do something else. >
  154.    < ... >
  155.    < when you want to put it back into the foreground: >
  156.    % %1
  157.    sess -R sh -c 'sessname; rn'         < the shell prints this >
  158.    ^C
  159.    % sess reconnect pf
  160.    < now it's just as if rn had started in the foreground. >
  161.  
  162. sess is an abbreviation for ``pty -s''. It starts a _session_ which you
  163. can disconnect and reconnect. Later on, when you put it into the
  164. background and type ^C, it stays disconnected in the background. Then
  165. you can start a new session and reconnect to it.
  166.  
  167. -R means ``don't read.'' It's a lot like rsh -n. It tells pty not to
  168. read anything from the keyboard. When you start ``sess reconnect pf'',
  169. you don't specify -R, so pty does take keyboard input.
  170.  
  171. Why this was a problem: rn is yet another ``interactive'' program. It
  172. insists on being in the foreground before it does anything else.
  173. Unfortunately, after you put it into the foreground, it might spend ten
  174. minutes processing KILL files!
  175.  
  176. Why the answer solves the problem: Once again, pty creates a
  177. pseudo-terminal for rn. Under that pseudo-terminal, rn is in the
  178. foreground, so it will happily process KILL files.
  179.  
  180.  
  181. 6. How do I get the terminal speed from a shell script?
  182.  
  183. Answer: Under sh, speed="`pty stty speed`".
  184.  
  185. Why this was a problem: When you type ``stty speed'', most versions of
  186. stty will look for the terminal on stdout, get the speed of that
  187. terminal, and print the result on stderr. So if you try
  188.  
  189.    speed="`stty speed`"
  190.  
  191. from sh, two things go wrong. The first is that sh is reading stty's
  192. output, so when stty looks for the terminal, it'll find only a pipe. The
  193. second is that when stty prints the result, it goes to stderr, which sh
  194. isn't paying attention to.
  195.  
  196. Other versions of stty look for the terminal on stdin or stderr, and
  197. print the result to stdout. So even if you kludge around the first
  198. problem by moving file descriptors around, chances are your code will
  199. mysteriously blow up on the next machine.
  200.  
  201. Why the answer solves the problem: pty creates a pseudo-terminal for
  202. stty, with exactly the same characteristics (including speed) as the
  203. original tty. It doesn't matter whether stty looks at stdin or stdout or
  204. stderr. It'll just see the pseudo-tty. It also doesn't matter whether
  205. stty prints its result to stdout or stderr. pty will collect both
  206. results into its stdout for the shell.
  207.