home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / suprsrv.shr < prev    next >
Text File  |  1990-06-29  |  34KB  |  1,535 lines

  1. #!/bin/sh
  2. # shar:    Shell Archiver  (v1.22)
  3. #
  4. #    Run the following text with /bin/sh to create:
  5. #      MANIFEST
  6. #      Makefile
  7. #      NOTES
  8. #      client.1
  9. #      client.c
  10. #      common.h
  11. #      server.1
  12. #      server.c
  13. #      socket.c
  14. #      supersrv.8
  15. #      supersrv.c
  16. #
  17. sed 's/^X//' << 'SHAR_EOF' > MANIFEST &&
  18. XThis shar file should contain:
  19. X
  20. XMANIFEST    This file
  21. XMakefile    To build everything
  22. XNOTES        Various implementation notes, wish list, etc.
  23. Xclient.1    Manual page for the client program
  24. Xclient.c    The client program
  25. Xcommon.h    Definitions common to all three programs
  26. Xserver.1    Manual page for the server program
  27. Xserver.c    The server program
  28. Xsocket.c    Various blackbox IPC routines used by everything
  29. Xsupersrv.8    Manual page for the supersrv program
  30. Xsupersrv.c    The supersrv program
  31. SHAR_EOF
  32. chmod 0600 MANIFEST || echo "restore of MANIFEST fails"
  33. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  34. X#
  35. X# SuperServer 1.2
  36. X#
  37. X# by Steven Grimm, koreth@ebay.sun.com
  38. X#
  39. X
  40. XCFLAGS = -O
  41. X
  42. XSUPERO = supersrv.o socket.o
  43. XSERVERO = server.o socket.o
  44. XCLIO = client.o socket.o
  45. X
  46. Xall: supersrv server client
  47. X
  48. Xsupersrv: $(SUPERO)
  49. X    $(CC) $(CFLAGS) $(SUPERO) -o $@
  50. X
  51. Xserver: $(SERVERO)
  52. X    $(CC) $(CFLAGS) $(SERVERO) -o $@
  53. X
  54. Xclient: $(CLIO)
  55. X    $(CC) $(CFLAGS) $(CLIO) -o $@
  56. X
  57. Xclean:
  58. X    /bin/rm -f $(SUPERO) $(SERVERO) $(CLIO) supersrv server client core
  59. X
  60. Xinstall: all
  61. X    install -s -c -m 755 supersrv /usr/local
  62. X    install -s -c -m 755 server /usr/local
  63. X    install -s -c -m 755 client /usr/local
  64. SHAR_EOF
  65. chmod 0600 Makefile || echo "restore of Makefile fails"
  66. sed 's/^X//' << 'SHAR_EOF' > NOTES &&
  67. XVERSION 1.2 CHANGES:
  68. X
  69. XServer has a builtin "QUIT" service, which causes it to disconnect from
  70. Xsupersrv and die.  When a server REGISTERs with supersrv, supersrv tells
  71. Xall servers offering services from the same user to QUIT.  This allows
  72. Xusers to run server without worrying about multiple servers sticking
  73. Xaround.
  74. X
  75. XClient no longer needs a LIST argument; if no service name is given,
  76. XLIST is assumed.
  77. X
  78. XVERSION 1.1 CHANGES:
  79. X
  80. XMinor bug fixes of little consequence.
  81. X
  82. XVERSION 1.0:
  83. X
  84. XThis program allows individual users to set up network services without
  85. Xhaving to worry about the intricacies of socket I/O.  It is similar in
  86. Xfunction to the "rsh" program, but restricts the commands which can be
  87. Xexecuted by remote users.  No .rhosts or password is required, since
  88. Xthe remote user can only execute commands from a specified (presumably
  89. Xsafe) list.
  90. X
  91. XThe service programs think they're talking to a pipe (because they are).
  92. XStdin and stdout are redirected to the pipe; stderr is mapped to stdout.
  93. XShell scripts can be offered as network services, but make sure you have
  94. Xexecute permission on them and that the line "#!/bin/sh" (or csh, or
  95. Xwhatever shell you're using) appears at the top of the file, or UNIX won't
  96. Xrecognize it as an executable-format file.
  97. X
  98. XThe server consists of two layers.  The bottom layer (subserver) is
  99. Xexecuted by a user when he wants to advertise services.  It reads a
  100. Xconfiguration file from the user's home directory, which contains a
  101. Xlist of service names and full path specifications.  It then checks for
  102. Xthe existence of the top layer (the super-server), and runs the
  103. Xsuperserver program if it was not already active.  In any case, the
  104. Xserver connects to the superserver, registers its service-names, and
  105. Xawaits a request.
  106. X
  107. XThe superserver accepts connections from remote locations, usually
  108. Xinitiated with the "client" program.  It reads a line of input from the
  109. Xclient program, which specifies the name of the desired service.  If
  110. Xone of the subservers has advertised the requested service, the
  111. Xsuperserver forks off a child process.  The child writes the name of
  112. Xthe requested service to the appropriate subserver, then acts as a
  113. Xmailman, shuffling bytes between the remote user and the subserver
  114. Xuntil one of them disconnects.  Meanwhile, the parent superserver
  115. Xwaits for another connection, and the whole bloody mess starts over.
  116. X
  117. XThe client-supersrv handshaking looks like this (all lines are newline-
  118. Xterminated, so you could talk to supersrv with telnet, for instance):
  119. X
  120. Xclient                supersrv
  121. X------                --------
  122. X                welcome message
  123. Xservice name
  124. Xusername (or empty line)
  125. Xarg1
  126. Xarg2
  127. Xarg3
  128. X .
  129. X .
  130. X .
  131. Xargn
  132. Xblank line
  133. X
  134. X
  135. XIf a superserver process is killed, all its subservers try to restart
  136. Xit until one of them succeeds.  If a server process is killed, the
  137. Xsuperserver removes all its services from the listing.  Some braindamaged
  138. XBSD implementations can take up to five minutes to figure out that a
  139. Xprocess has died and that its socket addresses are no longer in use, so
  140. Xkilling a superserver might result in a short interruption of service.
  141. X
  142. XSending a HUP signal to a server causes it to reload its database.
  143. X
  144. X
  145. XWish list:
  146. X
  147. X    If exec-ing a program fails because of an invalid file format, we
  148. Xshould try to run the program from sh, since it's probably a script without
  149. Xthe #!/bin/sh at the top.
  150. X
  151. X    Some form of logging would be nice, so people can tell who's
  152. Xusing which services.
  153. X
  154. X    Signal-passing and standard error support a la rsh would be neat, too.
  155. X
  156. X    Support for interactive programs by automatically allocating a pty
  157. Xbefore running a program would be helpful.  Some form of environment passing
  158. Xwould also need to be implemented for programs that use termcap.
  159. X
  160. XIf you have questions, comments, bug reports, large amounts of excess cash,
  161. Xhorny women, etc., send a letter to koreth@ebay.sun.com.
  162. X
  163. SHAR_EOF
  164. chmod 0600 NOTES || echo "restore of NOTES fails"
  165. sed 's/^X//' << 'SHAR_EOF' > client.1 &&
  166. X.TH CLIENT 1 "15 February 1990"
  167. X.SH NAME
  168. Xclient \- use a network service, version 1.2
  169. X.SH SYNOPSIS
  170. X.B client
  171. X[
  172. X.B \-u
  173. X.I username
  174. X]
  175. X.I host
  176. X[
  177. X.I servicename
  178. X[
  179. X.I arguments
  180. X] ]
  181. X.SH DESCRIPTION
  182. X.I Client
  183. Xinterfaces with services offered through
  184. X.IR server (1).
  185. XSpecify the hostname and service; the service must be offered
  186. Xby someone on the appropriate host.  To get a list of services
  187. Xoffered on 
  188. X.I host,
  189. Xomit the
  190. X.I servicename
  191. Xand
  192. X.I arguments.
  193. XAny
  194. X.I arguments
  195. Xafter the
  196. X.I servicename
  197. Xare passed to the service.  Be careful of passing
  198. Xfilenames, as remote machines generally can't read files on the
  199. Xlocal host.
  200. X.SH OPTIONS
  201. X.IP \-u
  202. XIf two services of the same name are offered by different users,
  203. Xuse the
  204. X.I \-u
  205. Xoption to select the desired user.  If this flag is not given,
  206. Xthe client will pick the first service whose name matches the
  207. Xrequested one.
  208. X.SH EXAMPLES
  209. X.ft C
  210. X% client ssyx.ucsc.edu fortune -l
  211. X.ft R
  212. X.PP
  213. XThis connects to machine "ssyx.ucsc.edu" and prints out a long
  214. Xfortune.
  215. X.sp 1
  216. X.ft C
  217. X% client -u geek doofus.foo.bar
  218. X.ft R
  219. X.PP
  220. XThis lists all services offered by user "geek" on host
  221. X"doofus.foo.bar".
  222. X.SH "SEE ALSO"
  223. Xrsh(1), server(1), supersrv(8)
  224. X.SH DIAGNOSTICS
  225. XIf no services are offered on a host,
  226. X.I client
  227. Xsays "No services on \fIhostname\fR."  This sometimes means that the
  228. X.IR supersrv (8)
  229. Xprocess on that host has died; if this is the case, then services will
  230. Xappear again in a short time.
  231. X.SH AUTHOR
  232. XSteven Grimm (koreth@ebay.sun.com, sun!ebay!koreth)
  233. SHAR_EOF
  234. chmod 0600 client.1 || echo "restore of client.1 fails"
  235. sed 's/^X//' << 'SHAR_EOF' > client.c &&
  236. X#include "common.h"
  237. X
  238. X/*
  239. X** Use the "server" and "supersrv" programs.
  240. X**
  241. X** 1.2: LIST argument is no longer necessary to list services.
  242. X*/
  243. X
  244. Xmain(argc, argv)
  245. Xchar **argv;
  246. X{
  247. X    int thirty;
  248. X    char c, user[16];
  249. X    int fd, i;
  250. X
  251. X    if (argc < 2)
  252. X    {
  253. Xusage:
  254. X        fprintf(stderr, "usage: %s [-u user] host [cmd [parms]]\n",
  255. X                    argv[0]);
  256. X        exit(-1);
  257. X    }
  258. X
  259. X    user[0] = 0;
  260. X
  261. X    if (argv[1][0] == '-')
  262. X        switch(argv[1][1])
  263. X        {
  264. X        case 'u':
  265. X            strncpy(user, argv[2], 15);
  266. X            user[15] = 0;
  267. X            argv += 2;
  268. X            argc -= 2;
  269. X            if (argc < 2)
  270. X                goto usage;
  271. X            break;
  272. X        default:
  273. X            fprintf(stderr, "-%c flag unknown\n", argv[1][1]);
  274. X            break;
  275. X        }
  276. X
  277. X    thirty = 30;
  278. X
  279. X    fd = clientsock(argv[1], SUPERPORT);
  280. X    if (fd < 0)
  281. X    {
  282. X        switch(fd) {
  283. X        case -9999:
  284. X            fprintf(stderr, "%s: host unknown\n", argv[1]);
  285. X            break;
  286. X        case -ECONNREFUSED:
  287. X            fprintf(stderr, "No services on %s\n", argv[1]);
  288. X            break;
  289. X        default:
  290. X            perror("clientsock");
  291. X            break;
  292. X        }
  293. X        exit(-1);
  294. X    }
  295. X
  296. X    setsockopt(fd, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  297. X
  298. X    do
  299. X        read(fd, &c, 1);
  300. X    while (c != '\n');
  301. X
  302. X    if (argc == 2)
  303. X        writeln(fd, "LIST");
  304. X    else
  305. X        writeln(fd, argv[2]);
  306. X    writeln(fd, user);
  307. X
  308. X    if (argc > 3)
  309. X        for (i=3; i<argc; i++)
  310. X            writeln(fd, argv[i]);
  311. X
  312. X    writeln(fd, "");
  313. X
  314. X    shuffle(fd);
  315. X
  316. X    fcntl(0, F_SETFL, 0);
  317. X    close(fd);
  318. X}
  319. X
  320. Xwriteln(fd, string)
  321. Xint fd;
  322. Xchar *string;
  323. X{
  324. X    write(fd, string, strlen(string));
  325. X    write(fd, "\n", 1);
  326. X}
  327. X
  328. X/*
  329. X * Shuffle bytes between stdin/out and the socket.  This forks off
  330. X * once so that one process handles dataflow in each direction (that's
  331. X * how rsh does it, and it makes the code a lot prettier...)
  332. X */
  333. Xshuffle(subsrv)
  334. Xint subsrv;        /* this will probably always be 3... */
  335. X{
  336. X    fd_set reed, tread, other;
  337. X    int pid, numread, buf[BUFSIZ];
  338. X
  339. X    pid = fork();
  340. X    if (pid < 0)
  341. X    {
  342. X        perror("fork");
  343. X        close(subsrv);
  344. X        exit(-1);
  345. X    }
  346. X
  347. X    FD_ZERO(&reed);
  348. X    FD_ZERO(&other);
  349. X
  350. X    if (!pid)
  351. X    {
  352. X        close(1);
  353. X        close(2);
  354. X
  355. X        while (1)
  356. X        {
  357. X            numread = read(0, buf, sizeof(buf));
  358. X            if (numread <= 0)
  359. X                break;
  360. X            write(subsrv, buf, numread);
  361. X        }
  362. X        shutdown(subsrv, 1);
  363. X        close(subsrv);
  364. X        exit(0);
  365. X    }
  366. X    else
  367. X    {
  368. X        close(0);
  369. X        close(2);
  370. X
  371. X        while (1)
  372. X        {
  373. X            numread = read(subsrv, buf, sizeof(buf));
  374. X            if (numread <= 0)
  375. X                break;
  376. X            write(1, buf, numread);
  377. X        }
  378. X
  379. X        close(subsrv);
  380. X        kill(pid, SIGKILL);
  381. X    }
  382. X}
  383. X
  384. SHAR_EOF
  385. chmod 0600 client.c || echo "restore of client.c fails"
  386. sed 's/^X//' << 'SHAR_EOF' > common.h &&
  387. X/*
  388. X * Common.h
  389. X *
  390. X * Definitions common to both the sub- and superserver.
  391. X */
  392. X
  393. X/*
  394. X * Common include files
  395. X */
  396. X#include <stdio.h>
  397. X#include <signal.h>
  398. X#include <errno.h>
  399. X#include <fcntl.h>
  400. X#include <sys/param.h>
  401. X#include <sys/ioctl.h>
  402. X#include <sys/time.h>
  403. X#include <sys/socket.h>
  404. X
  405. X/*
  406. X * This is the port number that the superserver listens on.
  407. X */
  408. X#define SUPERPORT    3502
  409. X
  410. X/*
  411. X * Common external variables.
  412. X */
  413. Xextern int errno;
  414. X
  415. SHAR_EOF
  416. chmod 0600 common.h || echo "restore of common.h fails"
  417. sed 's/^X//' << 'SHAR_EOF' > server.1 &&
  418. X.TH SERVER 1 "14 July 1988"
  419. X.SH NAME
  420. Xserver \- offer network services, version 1.2
  421. X.SH SYNOPSIS
  422. X.B server
  423. X.SH DESCRIPTION
  424. X.I Server
  425. Xallows users to offer services to other users, possibly on remote
  426. Xhosts.  Any program (or shell script) that a user has execute permission
  427. Xon can be offered as a service.  The program
  428. X.IR client (1)
  429. Xis then used to run the services, optionally passing arguments or input.
  430. X.PP
  431. XIf a server is the first to start up on a machine, the super-server
  432. X.IR supersrv (8)
  433. Xis automatically started by
  434. X.I server,
  435. Xwhich then tells
  436. X.I supersrv
  437. Xwhich services the user wants to offer.
  438. X.I Server
  439. Xlooks for a file called
  440. X.I .services
  441. Xin the user's home directory, which consists of a list of service names
  442. Xand pathnames.
  443. X.PP
  444. XTo change the services being offered, run
  445. X.I server
  446. Xagain.  The old
  447. X.I server
  448. Xwill die, and the new one will take its place.  Killing a
  449. X.I server
  450. Xprocess results in the services it offered being removed from
  451. X.IR supersrv 's
  452. Xlist of services.
  453. X.SH EXAMPLE
  454. X.nf
  455. X.ft C
  456. X% cat .services
  457. Xfortune /usr/games/fortune
  458. Xw       /usr/ucb/w
  459. Xwho     /bin/who
  460. Xcrash   /g/f/v/foobar/kill-the-system
  461. X% server
  462. X%
  463. X.ft R
  464. X.SH DISCUSSION
  465. XMost programs should work without any problems as services.  The service
  466. Xthinks it's talking to a pipe; interactive programs work as long as they
  467. Xdon't attempt to set any special terminal modes or use
  468. X.IR termcap (3)
  469. Xor
  470. X.IR curses (3)
  471. Xto try to update the client's screen.  These restrictions are the same as
  472. Xthose of
  473. X.IR rsh (1);
  474. X.IR client (1)
  475. Xis similar to
  476. X.I rsh
  477. Xexcept that security is handled differently.
  478. X.PP
  479. XIf
  480. X.I supersrv
  481. Xgoes away (usually as a result of a kill command from a user who hasn't
  482. Xread this or doesn't know why there's an extra process running next to his
  483. Xserver), all the
  484. X.I server
  485. Xprocesses on the system will keep trying to restart
  486. X.I supersrv
  487. Xuntil one of them succeeds.  Since it can take a while for TCP ports to
  488. Xclear after their binding process has died on some implementations of
  489. XBSD, killing a
  490. X.I supersrv
  491. Xmay result in a short interruption of service.
  492. X.SH FILES
  493. X.TS
  494. X$HOME/.services    services list
  495. X.TE
  496. X.SH "SEE ALSO"
  497. Xclient(1), supersrv(8)
  498. X.SH BUGS
  499. X.PP
  500. XShell scripts offered as services must have the line "#!/bin/sh" (or csh,
  501. Xor whatever shell is being used) at the top, or
  502. X.I server
  503. Xwon't be able to execute them.
  504. X.SH AUTHOR
  505. XSteven Grimm (koreth@ebay.sun.com, ...!sun!ebay!koreth)
  506. SHAR_EOF
  507. chmod 0600 server.1 || echo "restore of server.1 fails"
  508. sed 's/^X//' << 'SHAR_EOF' > server.c &&
  509. X#include "common.h"
  510. X#include <sys/file.h>
  511. X#include <pwd.h>
  512. X
  513. X/*
  514. X * SubServer main module.
  515. X *
  516. X * 1.2: Starting up a new server kills the old one.
  517. X * 1.1: Some small bug fixes.
  518. X */
  519. X
  520. X#define    RCFILE    "/.services"    /* File to grab services from */
  521. X
  522. Xchar *getenv();
  523. X
  524. X/*
  525. X * This linked list structure is used to keep track of the
  526. X * services we're offering.
  527. X */
  528. Xstruct service {
  529. X    char    name[20];        /* Service name */
  530. X    char    path[MAXPATHLEN];    /* Service path */
  531. X    struct service *next;        /* Next element... */
  532. X} *list;
  533. X
  534. X/*
  535. X * Read in a services file and set up the linked list of
  536. X * services.  Test each service to be sure we can offer it.
  537. X * Returns 0 if there are no services offered.
  538. X */
  539. Xgetservices()
  540. X{
  541. X    FILE    *fp;
  542. X    char    filename[MAXPATHLEN], *home;
  543. X
  544. X    home = getenv("HOME");
  545. X    if (! home)
  546. X    {
  547. X        fprintf(stderr, "no home directory\n");
  548. X        return(0);
  549. X    }
  550. X
  551. X    strcpy(filename, home);
  552. X    strcat(filename, RCFILE);
  553. X
  554. X    fp = fopen(filename, "r");
  555. X    if (! fp)
  556. X    {
  557. X        perror("couldn't open services file");
  558. X        return(0);
  559. X    }
  560. X
  561. X    list = NULL;
  562. X
  563. X    while (! feof(fp))
  564. X    {
  565. X        char    servname[20], format[20];
  566. X
  567. X        servname[0] = 0;
  568. X        sprintf(format, "%%20s\t%%%d[^\n]", MAXPATHLEN);
  569. X        fscanf(fp, format, servname, filename);
  570. X        getc(fp);
  571. X        
  572. X        if (servname[0] && filename[0])
  573. X        {
  574. X            struct service *temp;
  575. X
  576. X            if (access(filename, X_OK))
  577. X            {
  578. X                fprintf(stderr, "warning: can't execute %s\n",
  579. X                    filename);
  580. X                continue;
  581. X            }
  582. X
  583. X            temp = (struct service *) malloc(sizeof(struct service));
  584. X            strcpy(temp->name, servname);
  585. X            strcpy(temp->path, filename);
  586. X            temp->next = list;
  587. X            list = temp;
  588. X        }
  589. X    }
  590. X    fclose(fp);
  591. X    return 1;
  592. X}
  593. X
  594. X
  595. X/*
  596. X * Reap children.
  597. X */
  598. Xsigchld()
  599. X{
  600. X    return wait(0);
  601. X}
  602. X
  603. Xint    fd;
  604. X
  605. X/*
  606. X * Reload the database.
  607. X * We do this by killing the old list element by element then calling
  608. X * getservices(), and closing the socket file descriptor so the main
  609. X * loop will have to reregister our services.
  610. X */
  611. Xreload()
  612. X{
  613. X    struct service *cur, *next;
  614. X
  615. X    cur = list;
  616. X    while (cur)
  617. X    {
  618. X        next = cur->next;
  619. X        free(cur);
  620. X        cur = next;
  621. X    }
  622. X
  623. X    if (! getservices())
  624. X        exit(-1);
  625. X    close(fd);
  626. X    fd = -1;    /* prevent another close... */
  627. X}
  628. X
  629. Xmain(argc, argv, envp)
  630. Xchar **argv, **envp;
  631. X{
  632. X    int thirty;
  633. X    struct service *cur;
  634. X    struct passwd *pw;
  635. X    char    service[80], user[16];
  636. X
  637. X    if (! getservices())
  638. X        exit(0);
  639. X
  640. X    if (fork())
  641. X        exit(0);
  642. X
  643. X    fd = open("/dev/tty", O_RDWR);
  644. X    if (fd >= 0)
  645. X    {
  646. X        ioctl(fd, TIOCNOTTY, 0);
  647. X        close(fd);
  648. X    }
  649. X    else
  650. X        printf("warning: couldn't disassociate from tty\n");
  651. X
  652. X/*
  653. X * Handle signals.  We want to reap children, so we should handle SIGCHLDs;
  654. X * we also want to let the user reload his services database, which we do
  655. X * with SIGHUP.
  656. X */
  657. X    signal(SIGCHLD, sigchld);
  658. X    signal(SIGHUP, reload);
  659. X
  660. X    thirty = 30;
  661. X
  662. X    pw = getpwuid(getuid());
  663. X    if (pw == NULL)
  664. X    {
  665. X        printf("warning: couldn't get UID\n");
  666. X        user[0] = '\n';
  667. X        user[1] = '\0';
  668. X    }
  669. X    else
  670. X    {
  671. X        strncpy(user, pw->pw_name, sizeof(user)-2);
  672. X        user[sizeof(user)-1] = '\0';
  673. X        strcat(user, "\n");
  674. X    }
  675. X
  676. X    close(0);
  677. X    close(1);
  678. X    close(2);
  679. X    
  680. X    while (1)
  681. X    {
  682. X        char c;
  683. X
  684. X        fd = clientsock("localhost", SUPERPORT);
  685. X        if (fd < 0)
  686. X            if (errno == ECONNREFUSED)
  687. X            {
  688. X                start_super(argv[0], envp);
  689. X/*
  690. X * Give the superserver time to fire up.
  691. X */
  692. X                sleep(5);
  693. X                continue;
  694. X            }
  695. X            else
  696. X            {
  697. X                perror("superserver connect");
  698. X                exit(-1);
  699. X            }
  700. X
  701. X        thirty = 30;
  702. X        setsockopt(fd, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  703. X        c = 0;
  704. X        do
  705. X            if (read(fd, &c, 1) < 0 && errno != EINTR)
  706. X                break;
  707. X        while (c != '\n');
  708. X
  709. X        if (c != '\n')
  710. X            continue;
  711. X
  712. X        write(fd, "REGISTER\n", 9);
  713. X        write(fd, user, strlen(user));
  714. X
  715. X        for (cur = list; cur; cur = cur->next)
  716. X        {
  717. X            write(fd, cur->name, strlen(cur->name));
  718. X            write(fd, "\n", 1);
  719. X        }
  720. X        write(fd, "\n", 1);
  721. X
  722. X        service[0] = 0;
  723. X        if (read(fd, service, 20) < 0 && errno != EBADF && errno != EINTR)
  724. X        {
  725. X            perror("read");
  726. X            exit(-1);
  727. X        }
  728. X
  729. X        if (service[0])
  730. X            do_service(service, fd, envp);
  731. X        if (fd >= 0)
  732. X            close(fd);
  733. X    }
  734. X}
  735. X
  736. X
  737. X/*
  738. X * Provide the service.  Fork off and keep reading parameters until
  739. X * they are terminated by an empty line, then pass them to the program
  740. X * specified by the service.
  741. X */
  742. Xdo_service(service, fd, envp)
  743. Xchar *service;
  744. Xint fd;
  745. Xchar **envp;
  746. X{
  747. X    struct service *cur;
  748. X    char    *argv[256], input[256];
  749. X    int    curarg = 0, index = 0, thirty = 60;
  750. X
  751. X/*
  752. X * If we're told to quit by the superserver, do so -- our owner has probably
  753. X * run another server.
  754. X */
  755. X    if (! strcmp(service, "QUIT"))
  756. X    {
  757. X        close(fd);
  758. X        exit(0);
  759. X    }
  760. X
  761. X    if (fork())
  762. X        return;
  763. X
  764. X    argv[curarg++] = service;
  765. X
  766. X    while (1) {
  767. X        read(fd, &input[index], 1);
  768. X        if (input[index] == '\r')
  769. X            continue;
  770. X        if (input[index] == '\n')
  771. X        {
  772. X            if (! index)
  773. X                break;
  774. X
  775. X            argv[curarg] = (char *)malloc(index+1);
  776. X            bcopy(input, argv[curarg], index);
  777. X            argv[curarg][index] = 0;
  778. X
  779. X            index = 0;
  780. X            curarg++;
  781. X        }
  782. X        else
  783. X            index++;
  784. X    }
  785. X
  786. X    dup2(fd, 0);
  787. X    dup2(fd, 1);
  788. X    dup2(fd, 2);
  789. X    setsockopt(0, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  790. X    setsockopt(1, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  791. X    setsockopt(2, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  792. X    if (fd > 2)
  793. X        close(fd);
  794. X
  795. X    argv[curarg] = NULL;
  796. X
  797. X    for (cur = list; cur; cur = cur->next)
  798. X        if (! strcmp(cur->name, service))
  799. X            break;
  800. X
  801. X    if (! cur)        /* service not there */
  802. X        exit(0);
  803. X
  804. X    execve(cur->path, argv, envp);
  805. X    perror("execve");
  806. X    exit(0);
  807. X}
  808. X
  809. Xchar *superv[] = { "/bin/sh", "-c", "supersrv", NULL };
  810. X
  811. Xstart_super(argv0, envp)
  812. Xchar *argv0, **envp;
  813. X{
  814. X    char *lastslash, argcopy[MAXPATHLEN], *rindex();
  815. X
  816. X    strcpy(argcopy, argv0);
  817. X/*
  818. X * If a path was given, try to find the superserver in the
  819. X * same directory as the subserver...
  820. X */
  821. X    if (lastslash = rindex(argcopy, '/'))
  822. X    {
  823. X        char path[MAXPATHLEN];
  824. X
  825. X        *lastslash = 0;
  826. X        strcpy(path, argcopy);
  827. X        strcat(path, "/supersrv");
  828. X        if (! access(path, X_OK))
  829. X        {
  830. X            if (! fork())
  831. X                execve(path, superv+2, envp);
  832. X            return;
  833. X        }
  834. X    }
  835. X
  836. X/*
  837. X * Otherwise, start up a shell to scan along the user's
  838. X * $PATH.
  839. X */
  840. X    if (! fork())
  841. X        execve(superv[0], superv, envp);
  842. X}
  843. X
  844. SHAR_EOF
  845. chmod 0600 server.c || echo "restore of server.c fails"
  846. sed 's/^X//' << 'SHAR_EOF' > socket.c &&
  847. X/*
  848. X** SOCKET.C
  849. X**
  850. X** Written by Steven Grimm (koreth@ssyx.ucsc.edu) on 11-26-87 (Thanksgiving)
  851. X** Please distribute widely, but leave my name here.
  852. X**
  853. X** Various black-box routines for socket manipulation, so I don't have to
  854. X** remember all the structure elements.
  855. X** Of course, I still have to remember how to call these routines.
  856. X*/
  857. X
  858. X#include <sys/types.h>
  859. X#include <sys/time.h>
  860. X#include <sys/socket.h>
  861. X#include <netinet/in.h>
  862. X#include <netdb.h>
  863. X#include <stdio.h>
  864. X
  865. X#ifndef FD_SET        /* for 4.2BSD */
  866. X#define FD_SETSIZE      (sizeof(fd_set) * 8)
  867. X#define FD_SET(n, p)    (((fd_set *) (p))->fds_bits[0] |= (1 << ((n) % 32)))
  868. X#define FD_CLR(n, p)    (((fd_set *) (p))->fds_bits[0] &= ~(1 << ((n) % 32)))
  869. X#define FD_ISSET(n, p)  (((fd_set *) (p))->fds_bits[0] & (1 << ((n) % 32)))
  870. X#define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
  871. X#endif
  872. X
  873. Xextern int errno;
  874. X
  875. X/*
  876. X** serversock()
  877. X**
  878. X** Creates an internet socket, binds it to an address, and prepares it for
  879. X** subsequent accept() calls by calling listen().
  880. X**
  881. X** Input: port number desired, or 0 for a random one
  882. X** Output: file descriptor of socket, or a negative error
  883. X*/
  884. Xint serversock(port)
  885. Xint port;
  886. X{
  887. X    int    sock, x;
  888. X    struct    sockaddr_in server;
  889. X
  890. X    sock = socket(AF_INET, SOCK_STREAM, 0);
  891. X    if (sock < 0)
  892. X        return -errno;
  893. X
  894. X    bzero(&server, sizeof(server));
  895. X    server.sin_family = AF_INET;
  896. X    server.sin_addr.s_addr = INADDR_ANY;
  897. X    server.sin_port = htons(port);
  898. X
  899. X    x = bind(sock, &server, sizeof(server));
  900. X    if (x < 0)
  901. X    {
  902. X        close(sock);
  903. X        return -errno;
  904. X    }
  905. X
  906. X    listen(sock, 5);
  907. X
  908. X    return sock;
  909. X}
  910. X
  911. X/*
  912. X** portnum()
  913. X**
  914. X** Returns the internet port number for a socket.
  915. X**
  916. X** Input: file descriptor of socket
  917. X** Output: inet port number
  918. X*/
  919. Xint portnum(fd)
  920. Xint fd;
  921. X{
  922. X    int    length, err;
  923. X    struct    sockaddr_in address;
  924. X
  925. X    length = sizeof(address);
  926. X    err = getsockname(fd, &address, &length);
  927. X    if (err < 0)
  928. X        return -errno;
  929. X
  930. X    return ntohs(address.sin_port);
  931. X}
  932. X
  933. X/*
  934. X** clientsock()
  935. X**
  936. X** Returns a connected client socket.
  937. X**
  938. X** Input: host name and port number to connect to
  939. X** Output: file descriptor of CONNECTED socket, or a negative error (-9999
  940. X**         if the hostname was bad).
  941. X*/
  942. Xint clientsock(host, port)
  943. Xchar *host;
  944. Xint port;
  945. X{
  946. X    int    sock;
  947. X    struct    sockaddr_in server;
  948. X    struct    hostent *hp, *gethostbyname();
  949. X
  950. X    hp = gethostbyname(host);
  951. X    if (hp == NULL)
  952. X        return -9999;
  953. X
  954. X    sock = socket(AF_INET, SOCK_STREAM, 0);
  955. X    if (sock < 0)
  956. X        return -errno;
  957. X
  958. X    bzero(&server, sizeof(server));
  959. X    server.sin_family = AF_INET;
  960. X    bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
  961. X    server.sin_port = htons(port);
  962. X
  963. X    if (connect(sock, &server, sizeof(server)) < 0)
  964. X    {
  965. X        close(sock);
  966. X        return -errno;
  967. X    }
  968. X
  969. X    return sock;
  970. X}
  971. X
  972. X/*
  973. X** readable()
  974. X**
  975. X** Poll a socket for pending input.  Returns immediately.  This is a front-end
  976. X** to waitread() below.
  977. X**
  978. X** Input: file descriptor to poll
  979. X** Output: 1 if data is available for reading
  980. X*/
  981. Xreadable(fd)
  982. Xint fd;
  983. X{
  984. X    return(waitread(fd, 0));
  985. X}
  986. X
  987. X/*
  988. X** waitread()
  989. X**
  990. X** Wait for data on a file descriptor for a little while.
  991. X**
  992. X** Input: file descriptor to watch
  993. X**      how long to wait, in seconds, before returning
  994. X** Output: 1 if data was available
  995. X**       0 if the timer expired or a signal occurred.
  996. X*/
  997. Xwaitread(fd, time)
  998. Xint fd, time;
  999. X{
  1000. X    fd_set readbits, other;
  1001. X    struct timeval timer;
  1002. X    int ret;
  1003. X
  1004. X    timerclear(&timer);
  1005. X    timer.tv_sec = time;
  1006. X    FD_ZERO(&readbits);
  1007. X    FD_ZERO(&other);
  1008. X    FD_SET(fd, &readbits);
  1009. X
  1010. X    ret = select(fd+1, &readbits, &other, &other, &timer);
  1011. X    if (FD_ISSET(fd, &readbits))
  1012. X        return 1;
  1013. X    return 0;
  1014. X}
  1015. X
  1016. SHAR_EOF
  1017. chmod 0600 socket.c || echo "restore of socket.c fails"
  1018. sed 's/^X//' << 'SHAR_EOF' > supersrv.8 &&
  1019. X.TH SUPERSRV 8 "July 14, 1988"
  1020. X.SH NAME
  1021. Xsupersrv \- manage network services, version 1.2
  1022. X.SH SYNOPSIS
  1023. X.B supersrv
  1024. X.SH DESCRIPTION
  1025. X.I Supersrv
  1026. Xkeeps track of which services (see
  1027. X.IR server (1))
  1028. Xare offered on a host.  It is automatically started by
  1029. X.I server
  1030. Xif it isn't already running; users should never have to run
  1031. X.I supersrv
  1032. Xexplicitly.
  1033. X.SH DISCUSSION
  1034. XThe superserver accepts connections from remote locations, usually
  1035. Xinitiated with the "telnet" program.  It reads a line of input from the
  1036. Xclient program, which specifies the name of the desired service.  If
  1037. Xone of the subservers has advertised the requested service, the
  1038. Xsuperserver forks off a child process.  The child writes the name of
  1039. Xthe requested service to the appropriate subserver, then acts as a
  1040. Xmailman, shuffling bytes between the remote user and the subserver
  1041. Xuntil one of them disconnects.  Meanwhile, the parent superserver
  1042. Xwaits for another connection, and the whole bloody mess starts over.
  1043. X.PP
  1044. XIf a superserver process is killed, all its subservers try to restart
  1045. Xit until one of them succeeds.
  1046. X.PP
  1047. X.I Supersrv
  1048. Xlistens on port number 3502; it's possible to request services via
  1049. Xthe
  1050. X.IR telnet (1)
  1051. Xprogram, though the
  1052. X.IR client (1)
  1053. Xinterface is preferred.  The fields sent by
  1054. X.I client,
  1055. Xterminated by newlines, are:
  1056. X.PP
  1057. Xservice name or LIST
  1058. X.br
  1059. Xusername to request service from (blank for any)
  1060. X.br
  1061. Xcommand line arguments, one per line (optional)
  1062. X.br
  1063. Xterminating blank line
  1064. X.PP
  1065. XThus, a session could look like this:
  1066. X.PP
  1067. X%
  1068. X.B telnet ucsco.ucsc.edu 3502
  1069. X.br
  1070. XTrying...
  1071. X.br
  1072. XConnected to UCSCO.UCSC.EDU.
  1073. X.br
  1074. XSuperServer -- enter service desired.
  1075. X.br
  1076. X.B webster <newline>
  1077. X.br
  1078. X.B <newline>
  1079. X.br
  1080. X.B topiary <newline>
  1081. X.br
  1082. X.B <newline>
  1083. X.br
  1084. X.IP 1.
  1085. Xto.pi.ary \\'to--pe--.er-e-\\ aj [L topiarius, fr. topia ornamental
  1086. Xgardening, irreg. fr. Gk topo]s place : of, relating to, or being the
  1087. Xpractice or art of training, cutting, and trimming trees or shrubs into odd
  1088. Xor ornamental shapes; also : characterized by such work
  1089. X.IP 2.
  1090. Xtopiary n : topiary art or gardening; also : a topiary garden
  1091. X.PP
  1092. XConnection closed by foreign host.
  1093. X.PP
  1094. XNote:
  1095. X.I supersrv
  1096. Xshould be placed in a directory that is in users' search paths, as
  1097. X.I server
  1098. Xneeds to find it.
  1099. X.PP
  1100. XThree special service names,
  1101. X.BR LIST ,
  1102. X.BR QUIT ,
  1103. Xand
  1104. X.BR REGISTER ,
  1105. Xare reserved by
  1106. X.IR supersrv .
  1107. X.B LIST
  1108. Xlists the services currently being offered;
  1109. X.B REGISTER
  1110. Xis used by the
  1111. X.IR server (1)
  1112. Xprogram to register new services with
  1113. X.IR supersrv .
  1114. X.B QUIT
  1115. Xis passed from
  1116. X.I supersrv
  1117. Xto
  1118. X.I server
  1119. Xwhen another server is started by the same user, to tell the old one to die.
  1120. X.SH BUGS
  1121. XIt is possible for users to kill each others'
  1122. X.I server
  1123. Xprocesses by using the
  1124. X.B REGISTER
  1125. Xservice manually.  It is hoped that anyone with the skill to do this will also
  1126. Xhave the maturity to refrain from doing it.  This is probably naive.
  1127. X.SH "SEE ALSO"
  1128. Xserver(1), client(1)
  1129. X.SH AUTHOR
  1130. XSteven Grimm (koreth@ebay.sun.com, ...!sun!ebay!koreth)
  1131. SHAR_EOF
  1132. chmod 0600 supersrv.8 || echo "restore of supersrv.8 fails"
  1133. sed 's/^X//' << 'SHAR_EOF' > supersrv.c &&
  1134. X#include "common.h"
  1135. X
  1136. Xextern int errno;
  1137. X
  1138. X/*
  1139. X * SuperServer.
  1140. X *
  1141. X * 1.2: REGISTER handler sends QUIT to all old servers running with the same
  1142. X *      username.
  1143. X */
  1144. X
  1145. X#define WELCOME    "SuperServer -- enter service desired.\n"
  1146. X#define NOSERV    "Service not offered.\n"
  1147. X
  1148. Xint thirty;
  1149. X
  1150. X/*
  1151. X * This structure is used to keep the database of available services.
  1152. X */
  1153. Xstruct service {
  1154. X    char    name[20];    /* Service name */
  1155. X    int    fd;        /* File descriptor that offers it */
  1156. X    struct service *next;    /* Next service in list */
  1157. X} *list = (struct service *)0;
  1158. X
  1159. Xchar users[NOFILE][16];        /* user connected to each fd */
  1160. X
  1161. Xmain(argc, argv)
  1162. Xchar **argv;
  1163. X{
  1164. X    struct itimerval it;        /* Alarm! */
  1165. X    int    fd_so,            /* Socket() file descriptor */
  1166. X        fd_co;            /* Connected file descriptor */
  1167. X    short    portno;            /* Port number to listen on */
  1168. X    char    request[80];
  1169. X    extern int sigchld();
  1170. X
  1171. X/*
  1172. X * First things first: put ourselves in the background.
  1173. X */
  1174. X    if (fork())
  1175. X        exit(0);
  1176. X
  1177. X    portno = SUPERPORT;
  1178. X    thirty = 30;
  1179. X
  1180. X/*
  1181. X * Set up the server socket on the appropriate port number and listen on it.
  1182. X */
  1183. X    fd_so = serversock(portno);
  1184. X    if (fd_so < 0)
  1185. X    {
  1186. X        perror("serversock");
  1187. X        exit(-1);
  1188. X    }
  1189. X
  1190. X    (void)listen(fd_so, 5);
  1191. X    setsockopt(fd_so, SOL_SOCKET, SO_LINGER, &thirty, sizeof(thirty));
  1192. X    fcntl(fd_so, F_SETOWN, getpid());
  1193. X
  1194. X/*
  1195. X * And we'll need to accomodate child processes.
  1196. X */
  1197. X    signal(SIGCHLD, sigchld);
  1198. X/*
  1199. X * We will catch broken pipes in our main loop, so don't fuss with signals.
  1200. X */
  1201. X    signal(SIGPIPE, SIG_IGN);
  1202. X
  1203. X/*
  1204. X * Now keep accepting connections and interpreting them.
  1205. X */
  1206. X    while (1)
  1207. X    {
  1208. X        fd_co = getcon(fd_so);
  1209. X
  1210. X        if (fd_co < 0)
  1211. X        {
  1212. X            perror("accept");
  1213. X            exit(0);
  1214. X        }
  1215. X
  1216. X        fcntl(fd_co, F_SETOWN, getpid());
  1217. X        setsockopt(fd_co,SOL_SOCKET,SO_LINGER,&thirty, sizeof(thirty));
  1218. X
  1219. X        do {
  1220. X            write(fd_co, WELCOME, sizeof(WELCOME)-1);
  1221. X        } while (! getline(fd_co, request, sizeof(request)-1));
  1222. X
  1223. X        if (handle(fd_co, request))
  1224. X            close(fd_co);
  1225. X    }
  1226. X}
  1227. X
  1228. X/*
  1229. X * Get a connection, or handle a disconnected server.
  1230. X */
  1231. Xgetcon(old)
  1232. Xint old;
  1233. X{
  1234. X    struct    service *cur;
  1235. X    fd_set    reed, tread, other;
  1236. X    int    firstfd;
  1237. X
  1238. X    FD_ZERO(&reed);
  1239. X    FD_ZERO(&other);
  1240. X
  1241. X    for (cur = list; cur; cur = cur->next)
  1242. X        FD_SET(cur->fd, &reed);
  1243. X    FD_SET(old, &reed);
  1244. X
  1245. X    while (1)
  1246. X    {
  1247. X        tread = reed;
  1248. X        select(NOFILE, &tread, &other, &other, 0);
  1249. X        if (FD_ISSET(old, &tread))
  1250. X            break;
  1251. X        while (firstfd = ffs(tread))
  1252. X        {
  1253. X            killfd(--firstfd);
  1254. X            close(firstfd);
  1255. X            FD_CLR(firstfd, &tread);
  1256. X            FD_CLR(firstfd, &reed);
  1257. X        }
  1258. X    }
  1259. X    return( accept(old, 0, 0) );
  1260. X}
  1261. X
  1262. X
  1263. X/*
  1264. X * Get an input line from a file descriptor.  This is probably very slow.
  1265. X * Since it's only called once, though...
  1266. X */
  1267. Xgetline(fd, buf, len)
  1268. Xint fd, len;
  1269. Xchar *buf;
  1270. X{
  1271. X    int    index = 0;
  1272. X    char    c;
  1273. X
  1274. X    while (read(fd, &c, 1) == 1)
  1275. X    {
  1276. X        if (c == '\n')
  1277. X            break;
  1278. X
  1279. X        if (c == '\r')
  1280. X            continue;
  1281. X
  1282. X        if (index < len)
  1283. X            buf[index++] = c;
  1284. X    }
  1285. X
  1286. X    buf[index] = 0;
  1287. X    return index;
  1288. X}
  1289. X
  1290. X
  1291. X/*
  1292. X * Handle a user request.  This will either be "REGISTER" or some
  1293. X * user-defined function.
  1294. X */
  1295. Xhandle(fd, string)
  1296. Xint fd;
  1297. Xchar *string;
  1298. X{
  1299. X    struct service *cur;
  1300. X    char user[16];
  1301. X
  1302. X/*
  1303. X * If a subserver wants to register itself, grab service
  1304. X * names from it until it outputs an empty line.
  1305. X */
  1306. X    if (!strcmp(string, "REGISTER"))
  1307. X    {
  1308. X        char    name[20];
  1309. X        int    i;
  1310. X
  1311. X        if (! getline(fd, users[fd], 15))
  1312. X            return 1;
  1313. X
  1314. X/*
  1315. X * If this user already has servers connected, kill them off.
  1316. X */
  1317. X        for (i = 0; i < NOFILE; i++)
  1318. X            if (i != fd && ! strcmp(users[i], users[fd]))
  1319. X            {
  1320. X                killfd(i);
  1321. X                write(i, "QUIT\0xxxxxxxxxxxxxxx", 20);
  1322. X                close(i);
  1323. X                users[i][0] = '\0';
  1324. X            }
  1325. X
  1326. X        while (getline(fd, name, 19))
  1327. X        {
  1328. X            cur = (struct service *)malloc(sizeof(*cur));
  1329. X            strcpy(cur->name, name);
  1330. X            cur->fd = fd;
  1331. X            cur->next = list;
  1332. X            list = cur;
  1333. X        }
  1334. X        return 0;    /* Keep file descriptor open */
  1335. X    }
  1336. X
  1337. X    getline(fd, user, 15);
  1338. X
  1339. X    if (!strcmp(string, "LIST"))
  1340. X    {
  1341. X        char buf[80];
  1342. X
  1343. X        write(fd, "Username\tService\n--------\t-------\n", 34);
  1344. X
  1345. X        for (cur = list; cur; cur = cur->next)
  1346. X        {
  1347. X            if (user[0] && strcmp(user, users[cur->fd]))
  1348. X                continue;
  1349. X            sprintf(buf, "%-8s\t%s\n", users[cur->fd], cur->name);
  1350. X            write(fd, buf, strlen(buf));
  1351. X        }
  1352. X        return 1;
  1353. X    }
  1354. X
  1355. X    for (cur = list; cur; cur=cur->next)
  1356. X        if (! strcmp(string, cur->name))
  1357. X            if ((! user[0]) || (! strcmp(user, users[cur->fd])))
  1358. X                break;
  1359. X
  1360. X    if (! cur)
  1361. X    {
  1362. X        write(fd, NOSERV, sizeof(NOSERV));
  1363. X        return 1;
  1364. X    }
  1365. X
  1366. X    write(cur->fd, string, 20);
  1367. X
  1368. X    shuffle(cur->fd, fd);
  1369. X
  1370. X    return 1;
  1371. X}
  1372. X
  1373. Xsigchld()
  1374. X{
  1375. X    wait(0);
  1376. X}
  1377. X
  1378. X/*
  1379. X * Kill all entries in the linked list with a certain file
  1380. X * descriptor.
  1381. X */
  1382. Xkillfd(fd)
  1383. Xint fd;
  1384. X{
  1385. X    struct service *cur, *temp;
  1386. X
  1387. X    while (list && list->fd == fd)
  1388. X    {
  1389. X        temp = list->next;
  1390. X        free(list);
  1391. X        list = temp;
  1392. X    }
  1393. X
  1394. X    if (list)
  1395. X        for (cur = list; cur; cur = cur->next)
  1396. X            while (cur->next && cur->next->fd == fd)
  1397. X            {
  1398. X                temp = cur->next;
  1399. X                cur->next = cur->next->next;
  1400. X                free(temp);
  1401. X            }
  1402. X}
  1403. X
  1404. X
  1405. X/*
  1406. X * This is the kludgy part.  We want to effectively connect the
  1407. X * client and the appropriate subserver.  Since there's no way to
  1408. X * connect two sockets together, we have to fork off a child and
  1409. X * sit there shuffling bytes back and forth between the two file
  1410. X * descriptors.  When one of them shuts down, we shut the other one
  1411. X * down and die.
  1412. X *
  1413. X * For now, since only one client can be talking to each subserver
  1414. X * at a given time, we erase all the subserver's services from the
  1415. X * service list.  It will reconnect when it's done.
  1416. X */
  1417. X#ifndef MIN
  1418. X#define MIN(x,y)    (((x)>(y))?(y):(x))
  1419. X#endif
  1420. X
  1421. Xshuffle(subsrv, client)
  1422. Xint subsrv, client;
  1423. X{
  1424. X    int        fd;
  1425. X    fd_set        reed, rite, except;
  1426. X    extern void    quit();
  1427. X
  1428. X    killfd(subsrv);
  1429. X
  1430. X    if (fork())
  1431. X    {
  1432. X        close(subsrv);
  1433. X        return;
  1434. X    }
  1435. X
  1436. X    for (fd = 0; fd < NOFILE; fd++)
  1437. X        if (fd != client && fd != subsrv)
  1438. X            close(fd);
  1439. X
  1440. X    FD_ZERO(&reed);
  1441. X    FD_SET(client, &reed);
  1442. X    FD_SET(subsrv, &reed);
  1443. X    FD_ZERO(&rite);
  1444. X    except = reed;
  1445. X
  1446. X    fcntl(client, F_SETOWN, getpid());
  1447. X    fcntl(subsrv, F_SETOWN, getpid());
  1448. X/*    fcntl(client, F_SETFL, FNDELAY);
  1449. X    fcntl(subsrv, F_SETFL, FNDELAY);
  1450. X*/
  1451. X
  1452. X    signal(SIGURG, quit);
  1453. X    signal(SIGPIPE, quit);
  1454. X
  1455. X    while (1)
  1456. X    {
  1457. X        fd_set    tread, twrite, texcept;
  1458. X        int    numbytes, bsize, numread, zero = 0;
  1459. X        char    buf[4096];
  1460. X
  1461. X        tread = reed;
  1462. X        twrite = rite;
  1463. X        texcept = except;
  1464. X
  1465. X        select(NOFILE, &tread, &twrite, &texcept, (void *)0);
  1466. X
  1467. X        if (FD_ISSET(subsrv, &tread))
  1468. X        {
  1469. X            ioctl(subsrv, FIONREAD, &numbytes);
  1470. X            bsize = MIN(numbytes, sizeof(buf));
  1471. X            numread = read(subsrv, buf, bsize);
  1472. X            if (numread < 0 && errno != EWOULDBLOCK)
  1473. X            {
  1474. X                perror("subsrv");
  1475. X                exit(0);
  1476. X            }
  1477. X            if (! numread)
  1478. X            {
  1479. X                shutdown(client, 1);
  1480. X                shutdown(subsrv, 0);
  1481. X                FD_CLR(subsrv, &reed);
  1482. X            }
  1483. X            else
  1484. X                write(client, buf, numread);
  1485. X        }
  1486. X
  1487. X        if (FD_ISSET(client, &tread))
  1488. X        {
  1489. X            ioctl(client, FIONREAD, &numbytes);
  1490. X            bsize = MIN(numbytes, sizeof(buf));
  1491. X            numread = read(client, buf, bsize);
  1492. X            if (numread < 0 && errno != EWOULDBLOCK)
  1493. X            {
  1494. X                perror("client");
  1495. X                exit(0);
  1496. X            }
  1497. X            if (! numread)
  1498. X            {
  1499. X                shutdown(client, 0);
  1500. X                shutdown(subsrv, 1);
  1501. X                FD_CLR(client, &reed);
  1502. X            }
  1503. X            else
  1504. X                write(subsrv, buf, numread);
  1505. X        }
  1506. X
  1507. X/* If both sides were shut down, leave. */
  1508. X        if (! (FD_ISSET(client, &reed) || FD_ISSET(subsrv, &reed)))
  1509. X        {
  1510. X            close(client);
  1511. X            close(subsrv);
  1512. X            exit(0);
  1513. X        }
  1514. X
  1515. X        if (FD_ISSET(client, &texcept) || FD_ISSET(subsrv, &texcept))
  1516. X        {
  1517. X            close(client);
  1518. X            close(subsrv);
  1519. X            exit(0);
  1520. X        }
  1521. X    }
  1522. X}
  1523. X
  1524. Xvoid quit()
  1525. X{
  1526. X    exit(0);
  1527. X}
  1528. X
  1529. SHAR_EOF
  1530. chmod 0600 supersrv.c || echo "restore of supersrv.c fails"
  1531. exit 0
  1532.  
  1533.  
  1534.  
  1535.