v23i034: Run a program under a pty session, Part04/06

Rich Salz rsalz at bbn.com
Thu Oct 11 00:16:54 AEST 1990


Submitted-by: Dan Bernstein <brnstnd at kramden.acf.nyu.edu>
Posting-number: Volume 23, Issue 34
Archive-name: pty/part04

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# Contents:  COPYRIGHT QUESTIONS TESTS patch/Makefile patch/README
#   sig.c slave.c texts.c util/biff.c util/sesslist.c util/sessuser.1
#   util/sessuser.c util/sessutil.c util/write.c util/xsessutil.c
# Wrapped by rsalz at litchi.bbn.com on Wed Oct 10 10:11:39 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 4 (of 6)."'
if test -f 'COPYRIGHT' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'COPYRIGHT'\"
else
  echo shar: Extracting \"'COPYRIGHT'\" \(2129 characters\)
  sed "s/^X//" >'COPYRIGHT' <<'END_OF_FILE'
Xpty version 3.001, August 21, 1990.
XCopyright (c) 1990, Daniel J. Bernstein.
XAll rights reserved.
X
XI want this program to be distributed freely in original form.
X
XOnce you've received a legal copy of this program, you can use it.
XForever. Nobody can take that right away from you. You can make changes
Xand backup copies for your use (or, if you're an organization, for the
Xuse of everyone in the organization). You can distribute patches (though
Xnot patched versions). You'd have all these rights even if I didn't tell
Xyou about them.
X
XCopyright law gives an author the exclusive right to copy and distribute his
Xworks. So that you don't have to worry about these legalities, I grant you the
Xright to make and distribute exact and complete copies of this program.
X
XOn the other hand, I don't want this program sold without my permission.
XUnless I give you permission, you may not charge for copies. You may charge for
Xdistribution---but only if you first warn the recipient that the code is free,
Xand tell him where you got it from.
X
XI don't want this program distributed without my name on it. I also don't
Xwant lots of different versions running around, so unless I give you permission
Xyou can't send out a modified version. It's perfectly all right to send other
Xpeople a description of how to make your changes (i.e., a patch), because then
Xeach recipient knows firsthand what patches he's installed, and I won't go
Xchasing ghosts. (An author has no right to control patches in any case.)
X
XIf you run an archive site: When you receive a patch supposedly from me, do you
Xapply it to the original package and repackage it? I encourage you to change
Xyour policy, if for no other reason than to give recipients a fallback in case
Xof buggy patches. If you're really set on this, how about including the patches
Xas separate, unapplied PATCHnn files inside the package? That's fine by me.
X
XIf you have questions about this program or about this notice, or if you
Xwould like additional rights beyond those granted above, or if you have
Xa patch that you don't mind sharing, please contact me on the Internet
Xat brnstnd at acf10.nyu.edu.
END_OF_FILE
  if test 2129 -ne `wc -c <'COPYRIGHT'`; then
    echo shar: \"'COPYRIGHT'\" unpacked with wrong size!
  fi
  # end of 'COPYRIGHT'
fi
if test -f 'QUESTIONS' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'QUESTIONS'\"
else
  echo shar: Extracting \"'QUESTIONS'\" \(4202 characters\)
  sed "s/^X//" >'QUESTIONS' <<'END_OF_FILE'
XI selected the questions below from articles posted to the USENET
Xnewsgroup comp.unix.questions. All the questions are reasonably easy to
Xanswer with pty and not too easy to answer with other widely available
Xtools. So I hope this file is useful, and I hope other software authors
Xadopt the QUESTIONS idea.
X
XOrganization: question, one-sentence answer, further details of
Xanswer, why the question normally poses a problem, and why the answer
Xgiven solves the problem.
X
X
X1. How to redirect telnet's input?
X
XRun pty telnet instead of telnet. Caveat: telnet stupidly flushes its
Xinput at connect time, so be careful not to flood it; instead do
Xsomething like % (sleep 5;echo help;echo quit) | pty telnet whatever 25.
X(Try it!) The five-second pause should be enough. For a more
Xsophisticated (and reliable) technique, see #4 below.
X
XThe problem here is that telnet wants to take its input from a terminal.
XMost other interactive applications (e.g., editors) feel the same way
Xabout stdin, stdout, and stderr. pty solves this by setting input,
Xoutput, and error all to the pseudo-terminal.
X
X
X2. How to redirect su's input?
X
Xpty su < input, of course. (I certainly don't recommend putting your
Xpassword in plaintext to be fed to su, but it can be done!) Note that
Xsome su's flush their input; solve this as in #1 above or #4 below.
X
XThe problem is that su opens /dev/tty for its input. Many other programs
Xuse /dev/tty explicitly for input and output; how do you redirect them?
Xpty solves this because a program under a pseudo-terminal refers to that
Xterminal when it opens /dev/tty.
X
X
X3. How to make sed 's/foo/bar/g' | more work?
X
Xpty -0 sed 's/foo/bar/g' | more. You can abbreviate pty -0 as condom.
X
XThe problem is that sed uses stdio. stdio checks whether its output is a
Xterminal; if not, it buffers a block of data inside the program. To see
Xthis in action, try the original % sed 's/foo/bar/g' | more; unless you
Xtype a lot of input, sed will keep buffering its output, so you'll never
Xsee anything.
X
Xpty solves the stdio buffer problem because a program under stdio does
Xhave a terminal (the pseudo-terminal) as output. So stdio buffers only a
Xline at a time.
X
X
X4. How to start a program, respond to its prompts, give the correct
X   replies, and catch the output?
X
XOn a machine with named pipes created by mknod foo p:
X
X  #!/bin/sh
X  # Generic reader-writer.
X  (umask 077;mknod input p;mknod output p)
X  pty -0 program args < input | pty -0 tee record > output &
X  exec 4>input 5<output
X  # Now read prompts from <&5 and write replies to >&4.
X  # A transcript is kept in record.
X
XAnother solution is to create two (unnamed) pipes, then stick pty
Xbetween them as above. This requires C code but is more portable.
X
XThe problems here are just the problems in #1-#3 above.
X
X
X5. How to fool rn into processing KILL files in the background?
X
Xpty -T rn &. This does have one deficiency: control characters like ^C,
X^Z, and so on affect pty rather than rn. (That's what -T does.) This
Xdoesn't matter for rn, but pty -T vi verylongfile definitely doesn't
Xwork the right way. To pass control characters through, start with
X
X  % pty -s sh -c 'sessname;disconnect;pty vi verylongfile'
X
X(pty -s can be abbreviated as sess.) Then watch the vi process with ps
Xor by typing pty -sT reconnect xx, watching, then pressing ^C, where xx
Xis the session name (pty extension). When you want to reconnect and pass
Xcontrol characters to vi, type % pty -s reconnect xx. From that point
Xit'll feel just like a normal vi.
X
XThe problem is that rn---like all character-based interactive
Xapplications---wants to change the tty mode to read one character at a
Xtime instead of one line at a time. The tty driver doesn't let it do
Xthis in the background. pty -T rn solves this because rn is really in
Xthe foreground under the pty.
X
X
X6. How to get terminal speed from shell script?
X
X"`pty stty speed`", assuming fd 0 or fd 2 is the tty.
X
XThe problem is that a straight `stty speed` pipes stty's output away
Xfrom your terminal and back into your shell. Many versions of stty
Xassume that their output points to the terminal, so they blow up. pty
Xsolves this because it copies information from the real terminal to the
Xpseudo-terminal.
END_OF_FILE
  if test 4202 -ne `wc -c <'QUESTIONS'`; then
    echo shar: \"'QUESTIONS'\" unpacked with wrong size!
  fi
  # end of 'QUESTIONS'
fi
if test -f 'TESTS' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'TESTS'\"
else
  echo shar: Extracting \"'TESTS'\" \(3657 characters\)
  sed "s/^X//" >'TESTS' <<'END_OF_FILE'
X#!/bin/sh
X# This is a shell script. Feed it to sh.
Xecho '
XHi, and welcome to the pty test script.
X
XAs in installation, I'\''m not actually going to do anything.
XI'\''ll just guide you through a few (non-comprehensive) tests.
X
XRemember: Like all software, pty comes without warranty, to the extent
Xpermitted by applicable law. Use it at your own risk.
X'
X
Xecho '----- Press return to continue. ' | tr -d '\012'; read contline
X
Xecho '
XFirst, just try % pty vi. You shouldn'\''t be able to tell the
Xdifference between this and a normal vi; stopping and restarting should
Xwork perfectly, as should normal typing.
X'
X
Xecho '----- Press return to continue. ' | tr -d '\012'; read contline
X
Xecho '
XNext, try % pty -0 tr \! \? | pty vi. This should work just like the
Xlast vi, with the following differences: 1. Stopping will require two
X^Zs, because csh idiotically doesn'\''t think a pipeline has stopped
Xwhen just its second component stops. 2. Exiting will require an extra
Xline to feed through tr, so that it gets a broken pipe; this is more
Xsensible than #1. 3. All exclamation points will be turned into question
Xmarks. This has obvious applications. :w /dev/null helps to escape.
X'
X
Xecho '----- Press return to continue. ' | tr -d '\012'; read contline
X
Xecho '
XContinuing along the lines of how to stick annoying programs into a
Xpipe, try % pty -0 sed '\''s/foo/bar/g'\'' | more. (Remember that sed outputs
Xeach line only after it receives the next.) Try the same thing without
Xpty.
X
XNote that pty -0 can be abbreviated as condom.
X'
X
Xecho '----- Press return to continue. ' | tr -d '\012'; read contline
X
Xecho '
XNext, try using the replacement script program. % script. Type various
Xcommands; try logging on to another terminal and using talk; observe
Xthat you'\''re listed in /etc/utmp. Try the clones of tty, mesg, biff,
Xu, wall, who, lock. (Try them under a non-pty session too.)
X'
X
Xecho '----- Press return to continue. ' | tr -d '\012'; read contline
X
Xecho '
XMuch of the fun of pty is in disconnecting and reconnecting sessions.
XIf you'\''re ambitious, try % sess sh. ^Z will get you out and back in.
XTry sessname without an argument; try it with an argument. Try sesslist.
XFinally, try $ disconnect, and go on to the next part of this script.
X'
X
Xecho '----- Press return to continue. ' | tr -d '\012'; read contline
X
Xecho '
XAlthough it looks like your sh session has finished, it'\''s actually
Xsitting in limbo, waiting for you to reconnect. You can still see it
Xunder who, sesslist, or ps. Now try % sess reconnect q7  or whatever the
Xextension of the disconnected session is; you should be right back in.
X
XYou can try the same thing by actually hanging up your connection, then
Xlogging in again and reconnecting.
X'
X
Xecho '----- Press return to continue. ' | tr -d '\012'; read contline
X
Xecho '
XFor one final trick,
X% sess sh
X$ PS1=FOO.; disconnect
X% sess sh
X$ sesslist
X...
X$ PS1=BAR.; reconnect q7; disconnect
XFOO.reconnect p4; disconnect
XBAR.reconnect q7; disconnect
XFOO.echo Neat, flipping right back and forth!
X'
X
Xecho '----- Press return to continue. ' | tr -d '\012'; read contline
X
Xecho '
XThat'\''s it! Make sure the manual pages and programs are easily
Xaccessible. To repeat a note from INSTALL:
X
XIf you make it through installation and testing and get pty running,
Xplease send a note to the author, Dan Bernstein, on the Internet
Xat brnstnd at nyu.edu. Let him know your computer model, OS version, and
Xwhat changes you had to make. If you have any trouble, please also get
Xin touch with the author. If you have a different kind of system with
Xpseudo-terminal support that could use a pty port, the author would
Xlove to hear about it.
X
XThanks!
X'
END_OF_FILE
  if test 3657 -ne `wc -c <'TESTS'`; then
    echo shar: \"'TESTS'\" unpacked with wrong size!
  fi
  # end of 'TESTS'
fi
if test -f 'patch/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patch/Makefile'\"
else
  echo shar: Extracting \"'patch/Makefile'\" \(2813 characters\)
  sed "s/^X//" >'patch/Makefile' <<'END_OF_FILE'
Xtpat: tpat1
X
Xtpat1: igntt
X	echo '1. Get the new telnetd from ucbarpa.berkeley.edu:' 1>&2
X	echo 'This command will retrieve telnet.90.06.28.tar.Z.' 1>&2
X	echo 'To execute it, just press return.' 1>&2
X	echo 'To continue, just make tpat2 > /dev/null.' 1>&2
X	./igntt tiocsti 'ftp -n 128.32.130.11 < TELNET.FTP'
X
Xtpat2: igntt
X	echo '2. Unpack telnetd:' 1>&2
X	echo 'This is self-explanatory. You may want tar xvf to see a file list.' 1>&2
X	echo 'To continue, just make tpat3 > /dev/null.' 1>&2
X	if test -f telnet.90.06.28.tar.Z ;\
X	then ./igntt tiocsti 'uncompress < telnet.90.06.28.tar.Z | tar xf -' ;\
X	else echo 'Aack! telnet.90.06.28.tar.Z doesn'\''t exist!' ;\
X	fi
X
Xtpat3: igntt
X	echo '3. Apply these patches, and check that they'\''re safe:' 1>&2
X	echo 'If all goes well, you should see a flood of successful patch output.' 1>&2
X	echo 'The unifdefs are to check the safety of the patches;' 1>&2
X	echo 'as you will see, the patches do nothing with USEPTY undefined.' 1>&2
X	echo 'To continue, just make tpat4 > /dev/null.' 1>&2
X	if test -d telnet.90.06.28 ;\
X	then ./igntt tiocsti 'cd telnet.90.06.28/telnetd; ' \
X			     'patch < ../../telnetd.90.06.28.patch; ' \
X			     'unifdef -UUSEPTY sys_term.c | cmp - sys_term.c.orig; ' \
X			     'unifdef -UUSEPTY telnetd.c | cmp - telnetd.c.orig; ' \
X			     'unifdef -UUSEPTY pathnames.h | cmp - pathnames.h.orig; ' \
X			     'cd ../..' ;\
X	fi
X
Xtpat4: igntt
X	echo '4. Check the pty pathname and fix it if necessary:' 1>&2
X	echo 'Since there is no standard like /inst for where programs go,' 1>&2
X	echo 'you had better make sure telnetd's pathnames.h is correct.' 1>&2
X	echo 'To continue, just make tpat5 > /dev/null.' 1>&2
X	./igntt tiocsti 'grep PATH_PTY telnet.90.06.28/telnetd/pathnames.h'
X
Xtpat5: igntt
X	echo '5. Add sock.o and sock.h symlinks:' 1>&2
X	echo 'This is self-explanatory.' 1>&2
X	echo 'To continue, just make tpat6 > /dev/null.' 1>&2
X	./igntt tiocsti 'ln -s ../../../sock.{h,o} telnet.90.06.28/telnetd'
X
Xtpat6: igntt
X	echo '6. Preparing for compile: Edit Makefile and Makefile.generic.' 1>&2
X	echo 'You must at least add -DUSEPTY to CFLAGS and sock.o to OBJS' 1>&2
X	echo 'in Makefile.generic.' 1>&2
X	echo 'telnetd isn'\''t too high on the portability scale, so you' 1>&2
X	echo 'may have to make quite a few more changes.' 1>&2
X	echo 'Anyway, make tpat7 > /dev/null to continue.' 1>&2
X	./igntt tiocsti 'vi telnet.90.06.28/telnetd/Makefile.generic'
X
Xtpat7: igntt
X	echo '7. Compile!' 1>&2
X	echo 'As explained in the telnetd source documentation, you have' 1>&2
X	echo 'to provide the machine name to make. Under SunOS 4.0.3,' 1>&2
X	echo 'you can just press return here.' 1>&2
X	echo 'When and if this succeeds, go to step 8 of README.' 1>&2
X	./igntt tiocsti '( cd telnet.90.06.28/telnetd; (date;make sun4.0) >>&Makelog ) &'
X
Xigntt: igntt.c
X	cc -o igntt igntt.c
END_OF_FILE
  if test 2813 -ne `wc -c <'patch/Makefile'`; then
    echo shar: \"'patch/Makefile'\" unpacked with wrong size!
  fi
  # end of 'patch/Makefile'
fi
if test -f 'patch/README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patch/README'\"
else
  echo shar: Extracting \"'patch/README'\" \(4777 characters\)
  sed "s/^X//" >'patch/README' <<'END_OF_FILE'
XAt the moment, the only thing here is telnetd.90.06.28.patch. It's
Xpublic domain.
X
Xtelnetd.90.06.28.patch is a safe patch to the telnetd source in
Xtelnet.90.06.28 on ucbarpa.berkeley.edu (128.32.130.11). ``Safe'' means
Xthat every file compiles exactly the same if USEPTY is not defined;
Xyou can apply the patch without any worry of messing up your source.
X
XWhat follows is an outline of how to apply the patch and enable it. A
Xpatched telnetd uses pty to manage sessions, so that users can easily
Xdisconnect and reconnect login sessions. You *must* have compiled file
Xdescriptor passing into pty for this to work; telnetd needs to get the
Xpseudo-terminal descriptors from pty. Given fd passing, though, the
Xpatched telnetd gives you the *full* efficiency of the unpatched
Xversion, even for reconnected sessions!
X
X
XHere's what to do. If you have the tiocsti utility installed, try
X``make > /dev/null'' in this directory; or just read through these
Xinstructions. The usual warning: Like all software, this comes with
Xall warranties disclaimed, to the extent permitted by applicable law.
X
X
X1. Get the new telnetd:
X
X  % ftp -n 128.32.130.11 < TELNET.FTP
X
X2. Unpack it:
X
X  % uncompress < telnet.90.06.28.tar.Z | tar xf -
X
X3. Apply these patches, and check that they're safe:
X
X  % cd telnet.90.06.28/telnetd
X  % patch < ../../telnetd.90.06.28.patch
X  % unifdef -UUSEPTY sys_term.c | cmp - sys_term.c.orig
X  % unifdef -UUSEPTY telnetd.c | cmp - telnetd.c.orig
X  % unifdef -UUSEPTY pathnames.h | cmp - pathnames.h.orig
X  % cd ../..
X
X4. Check the pty pathname and fix it if necessary:
X
X  % grep PATH_PTY telnet.90.06.28/telnetd/pathnames.h
X
X5. Add sock.o and sock.h symlinks:
X
X  % ( cd telnet.90.06.28/telnetd; ln -s ../../../sock.{o,h} . )
X
X6. When you want to compile the patched version: Add sock.o to OBJS
X   and -DUSEPTY to CCOPTS in Makefile.generic. Change whatever else
X   necessary to get telnetd to compile.
X
X7. Compile! On a Sun 4 under SunOS 4.0.3, for example, you just
X   ``make sun4.0'' in the telnetd directory.
X
X8. If you actually survive telnetd's incompatibilities and get it to
X   compile, keep reading.
X
X
XThe reason this telnetd is so big is that it supports Linemode, a bold
Xattempt to cut the Internet load from all the fast typists in the world
Xby a third or even a half.
X
XIf you're bored, compile the telnet client as well.
X
X
XAnyway, the telnetd you just compiled supports pty. You probably don't
Xwant to replace your original telnetd, because if something goes wrong
Xthen you need to log in again. Also, your telnetd may have special
Xfeatures for your machine. Instead, take the gradual upgrade path: Put
Xtelnetd into /usr/local/telnetd.pty, add a new ``tpt'' port to
X/etc/services, and add this line to /etc/inetd.conf:
X
Xtpt	stream	tcp	nowait	root	/usr/local/telnetd.pty	telnetd
X
X(On older machines, ``root'' wouldn't be there; imitate the telnet line
Xto figure out the right format. If you have the better interface of
Xattachport, use it instead.) kill -HUP the inetd process so that it will
Xreread inetd.conf.
X
X
XNow try connecting to the tpt port rather than 23 (instead of telnet X,
Xdo telnet X tpt). You should end up talking to the new telnetd, a clean
Xlogin, and (best of all) a pty session. (The most common problem: Lines
Xdon't appear until after you press return. This means that your old
Xtelnet doesn't support Linemode; type ``^]mo ch'' to fix it. Also send
Xcomplaints about the incompatibilities to dab at cray.com.) If the
Xconnection hangs for more than a second or produces weird results,
Xyou're probably out of luck; pty's author would appreciate hearing about
Xyour experiences.
X
XIf all goes well (whew!) you can log in normally, just as if you're
Xconnected to the old telnetd. Once you're in a shell, try using the pty
Xutilities, as if you were under sess. You should find that the commands
Xfail unless you're root, because that session was started by root rather
Xthan you. (This points out a failure in the telnetd-login-utmp model.)
XTo gain control of the session, type ``sessuser'' and pray. If nothing
Xgoes wrong, you can then disconnect the session, set up a reconnect to
Xanother one, use sessname and sesslist, etc. Yahoo! Tell your users!
XReplace your old telnetd with the new one! Add sessuser to the default
X.cshrc! And please send a note to brnstnd at nyu.edu about your success.
X
X
XNote that many popular versions of login use an annoying heuristic to
Xsave a few microseconds in updating /etc/utmp. The result is, first,
Xthat there's a race condition that can break down /etc/utmp on heavily
Xloaded machines; and second, that login and pty have different views of
X/etc/utmp. For this reason, pty is invoked with -xR to search for ptys
Xin order. You may even want to make -xR default (by setting flagxrandom
Xto 0 in pty's globals.c). Sigh.
END_OF_FILE
  if test 4777 -ne `wc -c <'patch/README'`; then
    echo shar: \"'patch/README'\" unpacked with wrong size!
  fi
  # end of 'patch/README'
fi
if test -f 'sig.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sig.c'\"
else
  echo shar: Extracting \"'sig.c'\" \(4549 characters\)
  sed "s/^X//" >'sig.c' <<'END_OF_FILE'
X/* Copyright 1990, Daniel J. Bernstein. All rights reserved. */
X
X#include "config.h"
X#include <sys/time.h>
X#include "sig.h"
X
X/* This is a stripped-down signal library, with automatic critical */
X/* sections around every signal handler. As long as no signal handler */
X/* has to pause waiting for another signal, this works beautifully */
X/* and prevents all races. */
X
Xstatic int queued[SIGNUM];
Xstatic int quo[SIGNUM];
Xstatic sig_syshandler orig[SIGNUM];
Xstatic sig_handler handler[SIGNUM];
X
Xstatic sig_syshandler signalv(s,h)
Xregister sig_num s;
Xregister sig_syshandler h;
X{
X return signal(s,h);
X}
X
Xstatic int crit = 0;
X
Xstatic void handle(i)
Xregister sig_num i;
X{
X if (crit)
X   queued[i] = 1;
X else
X  {
X   register int q;
X   register sig_num j;
X
X   crit = 1; (void) handler[i](i); queued[i] = 0; crit = 0;
X   do for (j = q = 0;j < SIGNUM;j++) if (queued[j])
X	{
X	 crit = q = 1;
X	 if (j != i) (void) handler[j](j);
X	 queued[j] = 0; crit = 0;
X	}
X   while (q);
X  }
X}
X
X/* To see why handle() works: First, crit can be considered a local
Xvariable, because handle() is the only routine that modifies it, and
Xhandle() always leaves crit the same. Second, crit is 1 while any
Xhandler is called, and then any simultaneous handle()s will simply
Xqueue. Hence handlers are mutually exclusive. Third, when handle() is
Xcalled with crit == 0, it can only exit after going through an entire j
Xloop with no queued[]s true. Fourth, if all queued[]s are false through
Xthat j loop, then crit is not set by handle() during that loop. Finally,
Xif crit is 0, handle() will exit with no queued signals: this is true by
Xinduction from the previous observations. */
X
X
X/* There is unfortunately no guarantee that a signal handler as */
X/* passed to signal() will receive its signal number as its first */
X/* argument. We do make that guarantee. */
X
X#define HAN(s,h) SIGRET_TYPE h() { handle(s); }
X
XHAN(0,han0);   HAN(1,han1);   HAN(2,han2);   HAN(3,han3);
XHAN(4,han4);   HAN(5,han5);   HAN(6,han6);   HAN(7,han7);
XHAN(8,han8);   HAN(9,han9);   HAN(10,han10); HAN(11,han11);
XHAN(12,han12); HAN(13,han13); HAN(14,han14); HAN(15,han15);
XHAN(16,han16); HAN(17,han17); HAN(18,han18); HAN(19,han19);
XHAN(20,han20); HAN(21,han21); HAN(22,han22); HAN(23,han23);
XHAN(24,han24); HAN(25,han25); HAN(26,han26); HAN(27,han27);
XHAN(28,han28); HAN(29,han29); HAN(30,han30); HAN(31,han31);
X
Xstatic sig_syshandler han[32] =
X  { han0 ,han1 ,han2 ,han3 ,han4 ,han5 ,han6 ,han7 ,
X    han8 ,han9 ,han10,han11,han12,han13,han14,han15,
X    han16,han17,han18,han19,han20,han21,han22,han23,
X    han24,han25,han26,han27,han28,han29,han30,han31
X  } ;
X
X#define QUE(s,h) SIGRET_TYPE h() { quo[s] = 1; }
X
XQUE(0,que0);   QUE(1,que1);   QUE(2,que2);   QUE(3,que3);
XQUE(4,que4);   QUE(5,que5);   QUE(6,que6);   QUE(7,que7);
XQUE(8,que8);   QUE(9,que9);   QUE(10,que10); QUE(11,que11);
XQUE(12,que12); QUE(13,que13); QUE(14,que14); QUE(15,que15);
XQUE(16,que16); QUE(17,que17); QUE(18,que18); QUE(19,que19);
XQUE(20,que20); QUE(21,que21); QUE(22,que22); QUE(23,que23);
XQUE(24,que24); QUE(25,que25); QUE(26,que26); QUE(27,que27);
XQUE(28,que28); QUE(29,que29); QUE(30,que30); QUE(31,que31);
X
Xstatic sig_syshandler que[32] =
X  { que0 ,que1 ,que2 ,que3 ,que4 ,que5 ,que6 ,que7 ,
X    que8 ,que9 ,que10,que11,que12,que13,que14,que15,
X    que16,que17,que18,que19,que20,que21,que22,que23,
X    que24,que25,que26,que27,que28,que29,que30,que31
X  } ;
X
X
Xvoid sig_init()
X{
X sig_num i;
X
X for (i = 0;i < SIGNUM;i++)
X   quo[i] = 0;
X for (i = 0;i < SIGNUM;i++)
X   orig[i] = signalv(i,que[i]);
X}
X
Xvoid sig_restore()
X{
X sig_num i;
X
X for (i = 0;i < SIGNUM;i++)
X   (void) signalv(i,orig[i]);
X}
X
Xvoid sig_handle(s)
Xsig_num s;
X{
X if (quo[s])
X   han[s]();
X (void) signalv(s,han[s]);
X quo[s] = 0;
X}
X
Xvoid sig_ignore(s)
Xsig_num s;
X{
X (void) signalv(s,SIG_IGN);
X}
X
Xvoid sig_default(s)
Xsig_num s;
X{
X (void) signalv(s,SIG_DFL);
X}
X
Xvoid sig_sethandler(s,h)
Xsig_num s;
Xsig_handler h;
X{
X handler[s] = h;
X}
X
X#ifdef SIGINTERRUPT
Xvoid sig_interrupt()
X{
X register sig_num s;
X
X for (s = 0;s < SIGNUM;s++)
X   (void) siginterrupt(s,1);
X}
X#endif
X
Xvoid sig_startring()
X{
X struct itimerval it;
X
X it.it_value.tv_sec = it.it_interval.tv_sec = 0;
X it.it_value.tv_usec = it.it_interval.tv_usec = 10000;
X (void) setitimer(ITIMER_REAL,&it,(struct itimerval *) 0);
X}
X
Xvoid sig_stopring()
X{
X struct itimerval it;
X
X it.it_value.tv_sec = it.it_interval.tv_sec = 0;
X it.it_value.tv_usec = it.it_interval.tv_usec = 0;
X (void) setitimer(ITIMER_REAL,&it,(struct itimerval *) 0);
X}
X
X/*ARGSUSED*/
Xvoid nothing(i)
Xsig_num i;
X{
X ; /* that's right, absolutely nothing. */
X}
END_OF_FILE
  if test 4549 -ne `wc -c <'sig.c'`; then
    echo shar: \"'sig.c'\" unpacked with wrong size!
  fi
  # end of 'sig.c'
fi
if test -f 'slave.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'slave.c'\"
else
  echo shar: Extracting \"'slave.c'\" \(2687 characters\)
  sed "s/^X//" >'slave.c' <<'END_OF_FILE'
X/* Copyright 1990, Daniel J. Bernstein. All rights reserved. */
X
X#include "file.h"
X#include "config.h"
X#include "pty.h"
X#include "tty.h"
X#include "err.h"
X#include "sig.h"
X#include "slave.h"
X#include "logs.h"
X
Xvoid slave(fnsty,arg)
Xchar *fnsty;
Xchar **arg;
X{
X sig_ignore(SIGTTOU);
X sig_ignore(SIGTTIN);
X
X if (fdtty > -1)
X  {
X   (void) tty_dissoc(fdtty); /* must succeed */
X   (void) close(fdtty);
X  }
X if (fdre > -1)
X   (void) close(fdre);
X (void) close(fdin);
X (void) close(fdout);
X (void) close(fdmty);
X (void) close(fdsty);
X (void) close(0);
X (void) close(1);
X if (flagsameerr < 2)
X   (void) close(2);
X if (flagsameerr < 1)
X  {
X   (void) close(3);
X   for (fdout = getdtablesize();fdout > 3;fdout--)
X     (void) close(fdout);
X  }
X
X if (open(fnsty,O_RDONLY) != 0)
X   fatalerrp(1,"pty: fatal: cannot reopen pty for input",errno);
X if (open(fnsty,O_WRONLY) != 1)
X     fatalerrp(1,"pty: fatal: cannot reopen pty for output",errno);
X if (flagsameerr < 2)
X   if (open(fnsty,(flagxerrwo ? O_WRONLY : O_RDWR)) != 2)
X     fatalerrp(1,"pty: fatal: cannot reopen pty for stderr",errno);
X if (flagsameerr < 1)
X   if (open("/dev/tty",O_RDWR) != 3)
X     fatalerrp(1,"pty: fatal: cannot reopen pty for /dev/tty",errno);
X
X if ((fdtty = open("/dev/tty",O_RDWR)) == -1)
X   fatalerrp(1,"pty: fatal: cannot reopen pty for temporary /dev/tty",errno);
X
X if (setpgrp(0,getpid()) == -1)
X   fatalerr(1,"pty: fatal: cannot set process group\n");
X if (tty_setpgrp(fdtty,getpid()) == -1)
X   fatalerrp(1,"pty: fatal: cannot set pty process group",errno);
X if (tty_setmodes(fdtty,&tmopty) == -1)
X   fatalerr(1,"pty: fatal: cannot set pty modes\n");
X if (flagxexcl)
X   if (tty_setexcl(fdtty) == -1)
X     fatalerr(1,"pty: fatal: cannot set exclusive use on pty\n");
X
X (void) fchmod(0,USEDPTYMODE);
X
X if (flagxchown)
X   (void) fchown(0,uid,PTYGROUP);
X
X (void) close(fdtty);
X
X date = now(); /* could use original date instead */
X
X if (flagxutmp)
X  {
X   if (flagverbose)
X     warnerr2("%s","pty: writing utmp entry\n");
X   if (utmp(fnsty + PTYUTMP_OFFSET,username,PTYUTMP_HOST,date) == -1)
X     warnerr2("pty: warning: cannot write %s utmp entry\n",fnsty);
X  }
X
X if (flagxwtmp)
X  {
X   if (flagverbose)
X     warnerr2("%s","pty: writing wtmp entry\n");
X   if (wtmp(fnsty + PTYWTMP_OFFSET,username,PTYWTMP_HOST,date) == -1)
X     warnerr2("pty: warning: cannot write %s wtmp entry\n",fnsty);
X  }
X
X if (setreuid(uid,uid) == -1)
X   /* We absolutely refuse to exec while setuid. */
X   fatalerrp(1,"pty: fatal: cannot setreuid",errno);
X
X sig_restore();
X if (flagverbose)
X   warnerr2("pty: executing program %s\n",arg[0]);
X (void) execvp(arg[0],arg);
X fatalerr2p(1,"pty: fatal: cannot execute %s",arg[0],errno);
X /*NOTREACHED*/
X}
END_OF_FILE
  if test 2687 -ne `wc -c <'slave.c'`; then
    echo shar: \"'slave.c'\" unpacked with wrong size!
  fi
  # end of 'slave.c'
fi
if test -f 'texts.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'texts.c'\"
else
  echo shar: Extracting \"'texts.c'\" \(3819 characters\)
  sed "s/^X//" >'texts.c' <<'END_OF_FILE'
X/* Copyright 1990, Daniel J. Bernstein. All rights reserved. */
X
X#include "config.h"
X#include "texts.h"
X
Xchar *ptyauthor[] = {
X"pty was written by Daniel J. Bernstein." ,
X"Internet address: brnstnd at acf10.nyu.edu." ,
X0 } ;
X
Xchar *ptyversion[] = {
X"pty version 3.001, August 21, 1990." ,
X"Copyright (c) 1990, Daniel J. Bernstein." ,
X"All rights reserved." ,
X0 } ;
X
Xchar *ptycopyright[] = {
X"pty version 3.001, August 21, 1990." ,
X"Copyright (c) 1990, Daniel J. Bernstein." ,
X"All rights reserved." ,
X"" ,
X"I want this program to be distributed freely in original form." ,
X"" ,
X"Once you've received a legal copy of this program, you can use it." ,
X"Forever. Nobody can take that right away from you. You can make changes" ,
X"and backup copies for your use (or, if you're an organization, for the" ,
X"use of everyone in the organization). You can distribute patches (though" ,
X"not patched versions). You'd have all these rights even if I didn't tell" ,
X"you about them." ,
X"" ,
X"I do grant you further rights, as detailed in the source package. Don't" ,
X"worry about them unless you're planning to distribute further copies." ,
X"" ,
X"If you have questions about this program or about this notice, or if you" ,
X"would like additional rights beyond those granted above, or if you have" ,
X"a patch that you don't mind sharing, please contact me on the Internet" ,
X"at brnstnd at acf10.nyu.edu." ,
X0 } ;
X
Xchar *ptywarranty[] = {
X"Daniel J. Bernstein disclaims all warranties to the extent permitted" ,
X"by applicable law. He is not and shall not be liable for any damages" ,
X"arising from the use of this program. This disclaimer shall be governed" ,
X"by the laws of the state of New York." ,
X"" ,
X"In other words, use this program at your own risk." ,
X"" ,
X"If you have questions about this program or about this disclaimer of" ,
X"warranty, please feel free to contact me at brnstnd at acf10.nyu.edu on" ,
X"the Internet." ,
X0 } ;
X
Xchar *ptyusage[] = {
X"Usage: pty [ -qQve3EdDjJsStT0FACHUVW ] [ -fn ] [ -p[cCdDeEnNrRsS0] ]" ,
X"           [ -x[cCeEnNoOrRsSuUwWxX ] program [ arg ... ]" ,
X"Help:  pty -H" ,
X0 } ;
X
Xchar *ptyhelp[] = {
X"pty runs a program under a pseudo-terminal session." ,
X"pty -ACHUVW: print authorship notice, copyright notice, this notice," ,
X"             short usage summary, version number, disclaimer of warranty" ,
X"pty [-qQve3EdDjJsStT0F] [-fn] [-p[cCdDeEnNrRsS0]] [-x[cCeEnNoOrRsSuUwWxX]]" ,
X"  program [arg...]: run program under a pseudo-terminal" ,
X"Options processed l to r. Capitals turn things off. Here + means default." ,
X"-q: quiet (nothing on stderr)   -e: leave fds 2 & 3    0=eSTp0  p0=pcrEN" ,
X"+Q: normal level of verbosity   -3: leave fd 3 only    d=dJT D=Djt    d=>T" ,
X"-v: complain about everything   +E: 2 & 3 both->pty    s=sxu S=SxU    s=>E" ,
X"-d: we are detached    +j: job control    +t: change orig tty to char mode" ,
X"+D: we have ctrl tty   -J: ignore stops   -T: leave orig tty alone" ,
X"-s: session (allow disconnect & reconnect)   -fn: pass pty fds up fd n" ,
X"+S: no session: disconnect will send HUP     +F: no -f" ,
X"-p[cCdDeEnNrRsS]: set pty modes; defaults taken from original tty if -D" ,
X"  c: cbreak, character mode  +n: change return to newline  +e: echo" ,
X" +d: new line discipline      r: raw, no keyboard signals  +s: screen, crt" ,
X"-x[cCeEnNoOrRsSuUwWxX]: security/experimental/extended, may be restricted" ,
X"  c: change pty owner   e: pty's stderr write-only       x: set TIOCEXCL" ,
X" +s: setuid, safer     +n: check if anyone has pty open  u: use /etc/utmp" ,
X" +r: pick random pty    o: skip if anyone has pty open   w: use /etc/wtmp" ,
X"If you have questions about or suggestions for pty, please feel free" ,
X"to contact the author, Daniel J. Bernstein, at brnstnd at acf10.nyu.edu" ,
X"on the Internet." ,
X0 } ;
X/* I still can't believe ptyhelp fits. :-) */
END_OF_FILE
  if test 3819 -ne `wc -c <'texts.c'`; then
    echo shar: \"'texts.c'\" unpacked with wrong size!
  fi
  # end of 'texts.c'
fi
if test -f 'util/biff.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util/biff.c'\"
else
  echo shar: Extracting \"'util/biff.c'\" \(1038 characters\)
  sed "s/^X//" >'util/biff.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include "sessutil.h"
Xextern unsigned short getuid();
X
X#define FOO (void) fstat(0,&st); \
Xif (which) (void) fchmod(0,(int) (st.st_mode | 0100)); \
Xelse (void) fchmod(0,(int) (st.st_mode & ~0100));
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X struct stat st;
X struct pty_session ps;
X int uid;
X int which;
X
X uid = getuid();
X
X if (argc == 1)
X  {
X   (void) setreuid(uid,uid);
X   (void) fstat(0,&st);
X   if (st.st_mode & 0100)
X     (void) printf("is y\n");
X   else
X     (void) printf("is n\n");
X  }
X else
X  {
X   switch(argv[1][0])
X    {
X     case 'y': which = 1; break;
X     case 'n': which = 0; break;
X     default: (void) fprintf(stderr,"usage: biff [y] [n]\n"); exit(1);
X    }
X   if (pty_get_sess(0,uid,&ps) == -1)
X    {
X     (void) setreuid(uid,uid);
X     FOO
X    }
X   else
X     if (ps.uid != uid)
X       (void) fprintf(stderr,"not your session\n");
X     else
X      {
X       FOO
X       (void) setreuid(uid,uid);
X       FOO
X      }
X  }
X (void) exit(0);
X}
END_OF_FILE
  if test 1038 -ne `wc -c <'util/biff.c'`; then
    echo shar: \"'util/biff.c'\" unpacked with wrong size!
  fi
  # end of 'util/biff.c'
fi
if test -f 'util/sesslist.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util/sesslist.c'\"
else
  echo shar: Extracting \"'util/sesslist.c'\" \(2102 characters\)
  sed "s/^X//" >'util/sesslist.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <sys/types.h>
X#include <sys/file.h>
X#ifdef BSD
X#include <limits.h>
X#endif
X#include <sys/dir.h>
X#include <stdio.h>
X#include "sessutil.h"
Xextern unsigned short getuid();
X
Xmain()
X{
X int uid;
X DIR *dirp;
X struct direct *dp;
X int fd;
X int intbuf[100];
X char *buf = (char *) intbuf;
X int r;
X
X uid = getuid();
X
X if (pty_sessdir(uid) == -1)
X  {
X   (void) fputs("sesslist: fatal: cannot change to session directory\n",stderr);
X   (void) exit(1);
X  }
X dirp = opendir(".");
X while (dp = readdir(dirp))
X  {
X   if (!strncmp(dp->d_name,"re.",3))
X     (void) printf("session %s disconnected\n",dp->d_name + 3);
X   else if (!strncmp(dp->d_name,"sess.",5))
X    {
X     if ((fd = open(dp->d_name,O_RDONLY)) == -1)
X       (void) fprintf(stderr,
X	      "sesslist: warning: cannot open %s\n",dp->d_name);
X     else
X      {
X       r = read(fd,buf,99); /* anything up to sizeof(intbuf) - 1 */
X       if (r < 4 * sizeof(int))
X         (void) fprintf(stderr,
X	        "sesslist: warning: cannot read %s\n",dp->d_name);
X       else if (r == 4 * sizeof(int))
X	 (void) printf("session %s sigler %d master %d slave %d\n",
X		dp->d_name + 5,intbuf[1],intbuf[2],intbuf[3]);
X       else
X	{
X	 buf[r] = '\0';
X	 (void) printf("session %s sigler %d master %d slave %d: %s\n",
X		dp->d_name + 5,intbuf[1],intbuf[2],intbuf[3],
X		buf + 4 * sizeof(int));
X	}
X       (void) close(fd);
X      }
X    }
X   else if (!strncmp(dp->d_name,"sig.",4))
X    {
X     if ((fd = open(dp->d_name,O_RDONLY)) == -1)
X       (void) fprintf(stderr,
X	      "sesslist: warning: cannot open %s\n",dp->d_name);
X     else
X      {
X       r = read(fd,buf,99);
X       if (r < 9)
X         (void) fprintf(stderr,
X	        "sesslist: warning: cannot read %s\n",dp->d_name);
X       else
X	{
X	 buf[r] = '\0';
X	 (void) printf("session %s will drop into session %s\n",
X		dp->d_name + 4,buf + 8);
X	}
X       (void) close(fd);
X      }
X    }
X   else if (!strncmp(dp->d_name,".",1))
X     ;
X   else if (!strncmp(dp->d_name,"..",2))
X     ;
X   else
X     (void) fprintf(stderr,
X	    "sesslist: warning: unknown file type %s\n",dp->d_name);
X  }
X (void) exit(0);
X}
END_OF_FILE
  if test 2102 -ne `wc -c <'util/sesslist.c'`; then
    echo shar: \"'util/sesslist.c'\" unpacked with wrong size!
  fi
  # end of 'util/sesslist.c'
fi
if test -f 'util/sessuser.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util/sessuser.1'\"
else
  echo shar: Extracting \"'util/sessuser.1'\" \(2006 characters\)
  sed "s/^X//" >'util/sessuser.1' <<'END_OF_FILE'
X.TH sessuser 1
X.SH NAME
Xsessuser \- rectify ownership of current pty session
X.SH SYNOPSIS
X.B sessuser
X.SH DESCRIPTION
X.I sessuser
Xtransfers ownership of the current pty session
Xto the user who owns the actual pseudo-terminal file.
X.PP
X.I sessuser
Xis useful in adapting
X.I pty
Xto old, inconsistent models of logging in.
XAn incoming user should be forced to type 
Xa correct password before the login process
Xeven touches a terminal;
Xhe should be given a tty
Xonly after his identity is established.
XInstead,
Xusers are given terminals
X(as root)
Xfirst.
XWhen
Xthese obsolete programs are modified
Xto let
X.I pty
Xallocate a pseudo-terminal,
Xtheir order of operations is still the same,
Xand
X.I pty
Xstill thinks the session is owned by root.
XHowever,
Xthe login program
Xdoes change the ownership of the
Xpseudo-terminal file to the user.
X.I sessuser
Xcommunicates this change to
Xthe
X.I pty
Xmanager,
Xso that
X.I sesslist,
X.I sessname,
X.I sesskill,
X.I disconnect,
Xand 
X.I reconnect
Xwill work.
X.PP
X.I xsessuser
Xis just like
X.I sessuser
Xbut applies to sessions started with
X.B\-xS.
XIt should never be needed, but it is
Xprovided for consistency.
X.SH DIAGNOSTICS
X.TP
X.I cannot find session
XThe standard input to
X.I sessuser
Xis not a session owned by
Xthe effective uid of
X.I sessuser.
X.TP
X.I cannot stat tty
XThis cannot happen.
X.TP
X.I you don't own tty
XYou don't own the pseudo-terminal file.
X.TP
X.I not child of session slave
XThe parent to
X.I sessuser
Xis not the head process in the session.
X.TP
X.I cannot find your username
XYou're not listed in
X/etc/passwd.
X.TP
X.I cannot open /etc/utmp
XSelf-explanatory.
X.TP
X.I cannot set session
X.I sessuser
Xis unable to record the
Xchange in session ownership.
X.TP
X.I cannot communicate new user
X.I sessuser
Xis unable to communicate with
Xthe pseudo-terminal
Xmanager.
X.SH RESTRICTIONS
X.I sessuser
Xrequires that the session be
Xlisted in
X/etc/utmp.
XIf it is not,
Xor if it is not listed under
Xthe correct username,
X.I sessuser
Xwill exit silently
Xwith exit code 1.
X.SH "SEE ALSO"
Xpty(1),
Xsess(1)
END_OF_FILE
  if test 2006 -ne `wc -c <'util/sessuser.1'`; then
    echo shar: \"'util/sessuser.1'\" unpacked with wrong size!
  fi
  # end of 'util/sessuser.1'
fi
if test -f 'util/sessuser.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util/sessuser.c'\"
else
  echo shar: Extracting \"'util/sessuser.c'\" \(1872 characters\)
  sed "s/^X//" >'util/sessuser.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <utmp.h>
X#include <pwd.h>
X#include <signal.h>
X#include <strings.h>
X#include "sessutil.h"
Xextern unsigned short getuid();
Xextern unsigned short geteuid();
X#define PTYUTMP_FILE "/etc/utmp"
X
Xmain()
X{
X struct pty_session ps;
X int uid;
X int euid;
X register FILE *fi;
X struct utmp ut;
X struct stat st;
X struct passwd *pw;
X char *username;
X
X uid = getuid();
X euid = geteuid();
X
X if (pty_get_sess(0,euid,&ps) == -1) /* i.e., as root */
X  {
X   (void) fputs("sessuser: fatal: cannot find session\n",stderr);
X   (void) exit(1);
X  }
X if (fstat(0,&st) == -1)
X  {
X   (void) fputs("sessuser: fatal: cannot stat tty\n",stderr);
X   (void) exit(1);
X  }
X if (st.st_uid != uid)
X  {
X   (void) fputs("sessuser: fatal: you don't own tty\n",stderr);
X   (void) exit(1);
X  }
X if (ps.slavepid != getppid())
X  {
X   (void) fputs("sessuser: fatal: not child of session slave\n",stderr);
X   (void) exit(1);
X  }
X if (!(pw = getpwuid(uid)))
X  {
X   (void) fputs("sessuser: fatal: cannot find your username\n",stderr);
X   (void) exit(1);
X  }
X username = pw->pw_name;
X if (!(fi = fopen(PTYUTMP_FILE,"r")))
X  {
X   (void) perror("sessuser: fatal: cannot open /etc/utmp");
X   (void) exit(1);
X  }
X else
X   while (fread((char *) &ut,sizeof(ut),1,fi))
X     if ((ut.ut_line[3] == ps.ext1) && (ut.ut_line[4] == ps.ext2)
X       &&(ut.ut_line[5] == '\0'))
X       if (!strncmp(ut.ut_name,username,8))
X	{
X	 ps.uid = uid;
X	 if (pty_set_sess(0,uid,&ps) == -1)
X	  {
X           (void) fputs("sessuser: fatal: cannot set session\n",stderr);
X           (void) exit(1);
X	  }
X	 if (kill(ps.masterpid,SIGUSR2) == -1)
X	  {
X           (void) fputs("sessuser: fatal: cannot communicate new user\n",stderr);
X           (void) exit(1);
X	  }
X	 (void) fchown(0,euid,-1);
X	 (void) exit(0);
X	}
X       else
X	 (void) exit(1);
X (void) exit(1);
X}
END_OF_FILE
  if test 1872 -ne `wc -c <'util/sessuser.c'`; then
    echo shar: \"'util/sessuser.c'\" unpacked with wrong size!
  fi
  # end of 'util/sessuser.c'
fi
if test -f 'util/sessutil.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util/sessutil.c'\"
else
  echo shar: Extracting \"'util/sessutil.c'\" \(3786 characters\)
  sed "s/^X//" >'util/sessutil.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include "sessutil.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#ifdef BSD
X#include <limits.h>
X#endif
X#include <stdio.h>
Xextern char *ttyname();
Xextern long lseek();
X
X/* Will have to change ttyn indices if DEVSTY changes. */
X
Xint pty_sessdir(uid)
Xint uid;
X{
X char foo[50];
X
X (void) sprintf(foo,"/usr/etc/pty/%d",uid);
X return chdir(foo);
X}
X
Xint pty_get_sess(fd,uid,ps)
Xint fd;
Xint uid;
Xstruct pty_session *ps;
X{
X char *ttyn;
X
X if (ttyn = ttyname(fd))
X   return pty_get_sessbyext(ttyn[8],ttyn[9],uid,ps);
X return -1;
X}
X
Xint pty_get_sessbyext(ext1,ext2,uid,ps)
Xchar ext1;
Xchar ext2;
Xint uid;
Xstruct pty_session *ps;
X{
X char foo[50];
X int fdsess;
X
X ps->ext1 = ext1;
X ps->ext2 = ext2;
X (void) sprintf(foo,"/usr/etc/pty/%d/sess.%c%c",uid,ps->ext1,ps->ext2);
X if ((fdsess = open(foo,O_RDONLY)) != -1)
X  {
X   if ((read(fdsess,(char *) &ps->uid,sizeof(int)) == sizeof(int))
X     &&(read(fdsess,(char *) &ps->siglerpid,sizeof(int)) == sizeof(int))
X     &&(read(fdsess,(char *) &ps->masterpid,sizeof(int)) == sizeof(int))
X     &&(read(fdsess,(char *) &ps->slavepid,sizeof(int)) == sizeof(int)))
X    {
X     (void) close(fdsess);
X     return 0;
X    }
X   (void) close(fdsess);
X  }
X return -1;
X}
X
Xint pty_set_sess(fd,uid,ps)
Xint fd;
Xint uid;
Xstruct pty_session *ps;
X{
X char *ttyn;
X char foo[50];
X int fdsess;
X
X if (ttyn = ttyname(fd))
X  {
X   ps->ext1 = ttyn[8];
X   ps->ext2 = ttyn[9];
X   (void) sprintf(foo,"/usr/etc/pty/%d/sess.%c%c",uid,ps->ext1,ps->ext2);
X   if ((fdsess = open(foo,O_WRONLY)) != -1)
X    {
X     if ((write(fdsess,(char *) &ps->uid,sizeof(int)) == sizeof(int))
X       &&(write(fdsess,(char *) &ps->siglerpid,sizeof(int)) == sizeof(int))
X       &&(write(fdsess,(char *) &ps->masterpid,sizeof(int)) == sizeof(int))
X       &&(write(fdsess,(char *) &ps->slavepid,sizeof(int)) == sizeof(int)))
X      {
X       (void) close(fdsess);
X       return 0;
X      }
X     (void) close(fdsess);
X    }
X  }
X return -1;
X}
X
Xint pty_get_sessname(fd,uid,buf,len)
Xint fd;
Xint uid;
Xchar *buf;
Xint len;
X{
X char *ttyn;
X char foo[50];
X int fdsess;
X int r;
X
X if (ttyn = ttyname(fd))
X  {
X   (void) sprintf(foo,"/usr/etc/pty/%d/sess.%c%c",uid,ttyn[8],ttyn[9]);
X   if ((fdsess = open(foo,O_RDONLY)) != -1)
X    {
X     if (lseek(fdsess,(long) (4 * sizeof(int)),0) != (long) -1)
X       if ((r = read(fdsess,buf,len - 1)) > 0)
X	{ /* could make that != -1. This way, default session is unnamed. */
X	 buf[r] = '\0';
X	 (void) close(fdsess);
X	 return 0;
X	}
X     (void) close(fdsess);
X    }
X  }
X return -1;
X}
X
Xint pty_set_sessname(fd,uid,buf,len)
Xint fd;
Xint uid;
Xchar *buf;
Xint len;
X{
X char *ttyn;
X char foo[50];
X int fdsess;
X
X if (ttyn = ttyname(fd))
X  {
X   (void) sprintf(foo,"/usr/etc/pty/%d/sess.%c%c",uid,ttyn[8],ttyn[9]);
X   if ((fdsess = open(foo,O_WRONLY)) != -1)
X    {
X     if (lseek(fdsess,(long) (4 * sizeof(int)),0) != (long) -1)
X       if (write(fdsess,buf,len) != -1)
X	{
X	 (void) close(fdsess);
X	 return 0;
X	}
X     (void) close(fdsess);
X    }
X  }
X return -1;
X}
X
Xint pty_get_rebyext(ext1,ext2,uid)
Xchar ext1;
Xchar ext2;
Xint uid;
X{
X char foo[50];
X struct stat st;
X
X (void) sprintf(foo,"/usr/etc/pty/%d/re.%c%c",uid,ext1,ext2);
X return stat(foo,&st);
X}
X
Xint pty_set_sig(ext1,ext2,uid,ps)
Xchar ext1;
Xchar ext2;
Xint uid;
Xstruct pty_session *ps;
X{
X char foo[50];
X int fdsig;
X
X (void) sprintf(foo,"/usr/etc/pty/%d/sig.%c%c",uid,ps->ext1,ps->ext2);
X if ((fdsig = open(foo,O_WRONLY | O_CREAT | O_TRUNC,0600)) != -1)
X  {
X   (void) sprintf(foo,"/dev/tty%c%c",ext1,ext2);
X   if (write(fdsig,foo,11) == 11)
X    {
X     (void) close(fdsig);
X     return 0;
X    }
X   (void) close(fdsig);
X  }
X return -1;
X}
X
Xint pty_unset_sig(uid,ps)
Xint uid;
Xstruct pty_session *ps;
X{
X char foo[50];
X
X (void) sprintf(foo,"/usr/etc/pty/%d/sig.%c%c",uid,ps->ext1,ps->ext2);
X return unlink(foo);
X}
END_OF_FILE
  if test 3786 -ne `wc -c <'util/sessutil.c'`; then
    echo shar: \"'util/sessutil.c'\" unpacked with wrong size!
  fi
  # end of 'util/sessutil.c'
fi
if test -f 'util/write.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util/write.c'\"
else
  echo shar: Extracting \"'util/write.c'\" \(2728 characters\)
  sed "s/^X//" >'util/write.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include <sys/types.h>
X#include <sys/timeb.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#ifdef BSD
X#include <limits.h>
X#endif
X#include <stdio.h>
X#include <strings.h>
X#include <utmp.h>
X#include <pwd.h>
X#include <time.h>
X#include <ctype.h>
Xextern unsigned short getuid();
Xextern char *ttyname();
Xextern long time();
X#define PTYUTMP_FILE "/etc/utmp"
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{ 
X register FILE *fi;
X struct utmp ut;
X char line[9];
X int lines = 0;
X char fntty[30];
X int fd;
X struct stat st;
X char buf[500];
X int offset;
X char *username;
X struct passwd *pw;
X char hostname[64];
X char *ttyn;
X long t;
X struct tm *tm;
X char *s;
X
X if (argc < 2)
X  {
X   (void) fprintf(stderr,"Usage: write user [ttyname]\n");
X   (void) exit(1);
X  }
X
X if (!(pw = getpwuid((int) getuid())))
X  {
X   (void) fprintf(stderr,"write: who are you?\n");
X   (void) exit(1);
X  }
X username = pw->pw_name;
X
X (void) gethostname(hostname,sizeof(hostname));
X
X if (!(ttyn = ttyname(2)))
X  {
X   (void) fprintf(stderr,"write: Can't find your tty\n");
X   (void) exit(1);
X  }
X
X t = time((long *) 0);
X tm = localtime(&t);
X
X if (fi = fopen(PTYUTMP_FILE,"r"))
X   while (fread((char *) &ut,sizeof(ut),1,fi))
X     if (!strncmp(ut.ut_name,argv[1],8))
X       if ((argc == 2) || (!strncmp(ut.ut_line,argv[2],8)))
X	 if (!lines)
X	  {
X	   (void) strncpy(line,ut.ut_line,8);
X	   line[8] = '\0';
X	   lines = 1;
X	  }
X	 else
X	   lines++;
X if (!lines)
X  {
X   if (argc == 2)
X     (void) fprintf(stderr,"write: %s not logged in\n",argv[1]);
X   else
X     (void) fprintf(stderr,"write: %s not logged in on tty %s\n",
X		    argv[1],argv[2]);
X   (void) exit(1);
X  }
X if (lines > 1)
X   (void) fprintf(stderr,
X   "write: %s logged in more than once ... writing to %s\n",
X   argv[1],line);
X
X (void) sprintf(fntty,"/dev/%s",line);
X if ((fd = open(fntty,O_WRONLY)) == -1)
X  {
X   (void) fprintf(stderr,"write: Permission denied\n");
X   (void) exit(1);
X  }
X
X (void) sprintf(buf,"\nMessage from %s@%s on %s at %d:%02d ...\n",
X		username,hostname,ttyn + 5,tm->tm_hour,tm->tm_min);
X (void) write(fd,buf,strlen(buf));
X
X (void) sprintf(buf,"%s: ",username);
X offset = strlen(buf);
X
X while (fgets(buf + offset,sizeof(buf) - offset,stdin))
X  {
X   (void) fstat(fd,&st);
X   if (!(st.st_mode & 0020))
X    {
X     (void) fprintf(stderr,"write: Permission denied\n");
X     (void) exit(1);
X    }
X   for (s = buf;*s;s++)
X     if (((!isascii(*s) || !isprint(*s))) && (*s != '\n'))
X       *s = '^';
X   (void) write(fd,buf,strlen(buf));
X   (void) sleep(1);
X  }
X
X t = time((long *) 0);
X tm = localtime(&t);
X (void) sprintf(buf,"End of message from %s@%s on %s at %d:%02d\n",
X		username,hostname,ttyn + 5,tm->tm_hour,tm->tm_min);
X (void) write(fd,buf,strlen(buf));
X
X (void) exit(0);
X}
END_OF_FILE
  echo shar: 1 control character may be missing from \"'util/write.c'\"
  if test 2728 -ne `wc -c <'util/write.c'`; then
    echo shar: \"'util/write.c'\" unpacked with wrong size!
  fi
  # end of 'util/write.c'
fi
if test -f 'util/xsessutil.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util/xsessutil.c'\"
else
  echo shar: Extracting \"'util/xsessutil.c'\" \(4232 characters\)
  sed "s/^X//" >'util/xsessutil.c' <<'END_OF_FILE'
X/* Public domain. */
X
X#include "sessutil.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#ifdef BSD
X#include <limits.h>
X#endif
X#include <stdio.h>
Xextern char *ttyname();
Xextern long lseek();
Xextern char *getenv();
X
X/* Will have to change ttyn indices if DEVSTY changes. */
X
Xint pty_sessdir(uid)
Xint uid;
X{
X char foo[50];
X char *ho;
X
X if (!(ho = getenv("HOME")))
X   return -1;
X (void) sprintf(foo,"%s/.pty/%d",ho,uid);
X return chdir(foo);
X}
X
Xint pty_get_sess(fd,uid,ps)
Xint fd;
Xint uid;
Xstruct pty_session *ps;
X{
X char *ttyn;
X
X if (ttyn = ttyname(fd))
X   return pty_get_sessbyext(ttyn[8],ttyn[9],uid,ps);
X return -1;
X}
X
Xint pty_get_sessbyext(ext1,ext2,uid,ps)
Xchar ext1;
Xchar ext2;
Xint uid;
Xstruct pty_session *ps;
X{
X char foo[50];
X int fdsess;
X char *ho;
X
X if (!(ho = getenv("HOME")))
X   return -1;
X
X ps->ext1 = ext1;
X ps->ext2 = ext2;
X (void) sprintf(foo,"%s/.pty/%d/sess.%c%c",ho,uid,ps->ext1,ps->ext2);
X if ((fdsess = open(foo,O_RDONLY)) != -1)
X  {
X   if ((read(fdsess,(char *) &ps->uid,sizeof(int)) == sizeof(int))
X     &&(read(fdsess,(char *) &ps->siglerpid,sizeof(int)) == sizeof(int))
X     &&(read(fdsess,(char *) &ps->masterpid,sizeof(int)) == sizeof(int))
X     &&(read(fdsess,(char *) &ps->slavepid,sizeof(int)) == sizeof(int)))
X    {
X     (void) close(fdsess);
X     return 0;
X    }
X   (void) close(fdsess);
X  }
X return -1;
X}
X
Xint pty_set_sess(fd,uid,ps)
Xint fd;
Xint uid;
Xstruct pty_session *ps;
X{
X char *ttyn;
X char foo[50];
X int fdsess;
X char *ho;
X
X if (!(ho = getenv("HOME")))
X   return -1;
X
X if (ttyn = ttyname(fd))
X  {
X   ps->ext1 = ttyn[8];
X   ps->ext2 = ttyn[9];
X   (void) sprintf(foo,"%s/.pty/%d/sess.%c%c",ho,uid,ps->ext1,ps->ext2);
X   if ((fdsess = open(foo,O_WRONLY)) != -1)
X    {
X     if ((write(fdsess,(char *) &ps->uid,sizeof(int)) == sizeof(int))
X       &&(write(fdsess,(char *) &ps->siglerpid,sizeof(int)) == sizeof(int))
X       &&(write(fdsess,(char *) &ps->masterpid,sizeof(int)) == sizeof(int))
X       &&(write(fdsess,(char *) &ps->slavepid,sizeof(int)) == sizeof(int)))
X      {
X       (void) close(fdsess);
X       return 0;
X      }
X     (void) close(fdsess);
X    }
X  }
X return -1;
X}
X
Xint pty_get_sessname(fd,uid,buf,len)
Xint fd;
Xint uid;
Xchar *buf;
Xint len;
X{
X char *ttyn;
X char foo[50];
X int fdsess;
X int r;
X char *ho;
X
X if (!(ho = getenv("HOME")))
X   return -1;
X
X if (ttyn = ttyname(fd))
X  {
X   (void) sprintf(foo,"%s/.pty/%d/sess.%c%c",ho,uid,ttyn[8],ttyn[9]);
X   if ((fdsess = open(foo,O_RDONLY)) != -1)
X    {
X     if (lseek(fdsess,(long) (4 * sizeof(int)),0) != (long) -1)
X       if ((r = read(fdsess,buf,len - 1)) > 0)
X	{ /* could make that != -1. This way, default session is unnamed. */
X	 buf[r] = '\0';
X	 (void) close(fdsess);
X	 return 0;
X	}
X     (void) close(fdsess);
X    }
X  }
X return -1;
X}
X
Xint pty_set_sessname(fd,uid,buf,len)
Xint fd;
Xint uid;
Xchar *buf;
Xint len;
X{
X char *ttyn;
X char foo[50];
X int fdsess;
X char *ho;
X
X if (!(ho = getenv("HOME")))
X   return -1;
X
X if (ttyn = ttyname(fd))
X  {
X   (void) sprintf(foo,"%s/.pty/%d/sess.%c%c",ho,uid,ttyn[8],ttyn[9]);
X   if ((fdsess = open(foo,O_WRONLY)) != -1)
X    {
X     if (lseek(fdsess,(long) (4 * sizeof(int)),0) != (long) -1)
X       if (write(fdsess,buf,len) != -1)
X	{
X	 (void) close(fdsess);
X	 return 0;
X	}
X     (void) close(fdsess);
X    }
X  }
X return -1;
X}
X
Xint pty_get_rebyext(ext1,ext2,uid)
Xchar ext1;
Xchar ext2;
Xint uid;
X{
X char foo[50];
X struct stat st;
X char *ho;
X
X if (!(ho = getenv("HOME")))
X   return -1;
X
X (void) sprintf(foo,"%s/.pty/%d/re.%c%c",ho,uid,ext1,ext2);
X return stat(foo,&st);
X}
X
Xint pty_set_sig(ext1,ext2,uid,ps)
Xchar ext1;
Xchar ext2;
Xint uid;
Xstruct pty_session *ps;
X{
X char foo[50];
X int fdsig;
X char *ho;
X
X if (!(ho = getenv("HOME")))
X   return -1;
X
X (void) sprintf(foo,"%s/.pty/%d/sig.%c%c",ho,uid,ps->ext1,ps->ext2);
X if ((fdsig = open(foo,O_WRONLY | O_CREAT | O_TRUNC,0600)) != -1)
X  {
X   (void) sprintf(foo,"/dev/tty%c%c",ext1,ext2);
X   if (write(fdsig,foo,11) == 11)
X    {
X     (void) close(fdsig);
X     return 0;
X    }
X   (void) close(fdsig);
X  }
X return -1;
X}
X
Xint pty_unset_sig(uid,ps)
Xint uid;
Xstruct pty_session *ps;
X{
X char foo[50];
X char *ho;
X
X if (!(ho = getenv("HOME")))
X   return -1;
X
X (void) sprintf(foo,"%s/.pty/%d/sig.%c%c",ho,uid,ps->ext1,ps->ext2);
X return unlink(foo);
X}
END_OF_FILE
  if test 4232 -ne `wc -c <'util/xsessutil.c'`; then
    echo shar: \"'util/xsessutil.c'\" unpacked with wrong size!
  fi
  # end of 'util/xsessutil.c'
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0
exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list