# 2.11BSD#431 - /usr/src/usr.sbin/inetd/inetd.c

##### Functions

    chargen_dg        X
    chargen_stream    X
    close_sep         X
    config            X
    daytime_dg        X
    daytime_stream    X
    discard_dg        X
    discard_stream    X
    echo_dg           X
    echo_stream       X
    endconfig         X
    enter             X
    freeconfig        X
    getconfigent      X
    initring          X
    machtime          X
    machtime_dg       X
    machtime_stream   X
    main              X
    newstr            X
    nextline          X
    print_service     X
    reapchild         X
    retry             X
    setconfig         X
    setproctitle      X
    setup             X
    skip              X
    sskip             X
    tcpmux            X

##### Variables

    Argv              X
    CONFIG            X
    LastArg           X
    allsock           X
    biltins           X
    debug             X
    endring           X
    line              X
    maxsock           X
    nsock             X
    options           X
    ring              X
    serv              X
    servtab           X
    sp                X
    timingout         X
    toomany           X

##### Macros

    BUFSIZE           X
    CNT_INTVL         X
    DUMMYSIZE         X
    ISMUX             X
    ISMUXPLUS         X
    LINESIZ           X
    LINE_MAX          X
    MAXARGV           X
    MAX_SERV_LEN      X
    MUXPLUS_TYPE      X
    MUX_LEN           X
    MUX_TYPE          X
    NORM_TYPE         X
    NUMINT            X
    OFFSET            X
    RETRYTIME         X
    SEEK_SET          X
    SIGBLOCK          X
    SWAP              X
    TOOMANY           X
    __P               X
    memmove           X
    strwrite          X
    turnon            X

##### struct's

    biltin            X
    servtab           X

       1: /*
       2:  * Copyright (c) 1983, 1991, 1993, 1994
       3:  *	The Regents of the University of California.  All rights reserved.
       4:  *
       5:  * Redistribution and use in source and binary forms, with or without
       6:  * modification, are permitted provided that the following conditions
       7:  * are met:
       8:  * 1. Redistributions of source code must retain the above copyright
       9:  *    notice, this list of conditions and the following disclaimer.
      10:  * 2. Redistributions in binary form must reproduce the above copyright
      11:  *    notice, this list of conditions and the following disclaimer in the
      12:  *    documentation and/or other materials provided with the distribution.
      13:  * 3. All advertising materials mentioning features or use of this software
      14:  *    must display the following acknowledgement:
      15:  *	This product includes software developed by the University of
      16:  *	California, Berkeley and its contributors.
      17:  * 4. Neither the name of the University nor the names of its contributors
      18:  *    may be used to endorse or promote products derived from this software
      19:  *    without specific prior written permission.
      20:  *
      21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31:  * SUCH DAMAGE.
      32:  */
      33:
      34: #if !defined(lint) && defined(DOSCCS)
      35: static char copyright[] =
      36: "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
      37: 	The Regents of the University of California.  All rights reserved.\n";
      38:
      39: static char sccsid[] = "@(#)inetd.c	8.4.1 (2.11BSD) 1996/10/30";
      40: #endif /* not lint */
      41:
      42: /*
      43:  * Inetd - Internet super-server
      44:  *
      45:  * This program invokes all internet services as needed.  Connection-oriented
      46:  * services are invoked each time a connection is made, by creating a process.
      47:  * This process is passed the connection as file descriptor 0 and is expected
      48:  * to do a getpeername to find out the source host and port.
      49:  *
      50:  * Datagram oriented services are invoked when a datagram
      51:  * arrives; a process is created and passed a pending message
      52:  * on file descriptor 0.  Datagram servers may either connect
      53:  * to their peer, freeing up the original socket for inetd
      54:  * to receive further messages on, or ``take over the socket'',
      55:  * processing all arriving datagrams and, eventually, timing
      56:  * out.	 The first type of server is said to be ``multi-threaded'';
      57:  * the second type of server ``single-threaded''.
      58:  *
      59:  * Inetd uses a configuration file which is read at startup
      60:  * and, possibly, at some later time in response to a hangup signal.
      61:  * The configuration file is ``free format'' with fields given in the
      62:  * order shown below.  Continuation lines for an entry must being with
      63:  * a space or tab.  All fields must be present in each entry.
      64:  *
      65:  *	service name			must be in /etc/services or must
      66:  *					name a tcpmux service
      67:  *	socket type			stream/dgram/raw/rdm/seqpacket
      68:  *	protocol			must be in /etc/protocols
      69:  *	wait/nowait			single-threaded/multi-threaded
      70:  *	user				user to run daemon as
      71:  *	server program			full path name
      72:  *	server program arguments	maximum of MAXARGS (20)
      73:  *
      74:  * TCP services without official port numbers are handled with the
      75:  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
      76:  * requests. When a connection is made from a foreign host, the service
      77:  * requested is passed to tcpmux, which looks it up in the servtab list
      78:  * and returns the proper entry for the service. Tcpmux returns a
      79:  * negative reply if the service doesn't exist, otherwise the invoked
      80:  * server is expected to return the positive reply if the service type in
      81:  * inetd.conf file has the prefix "tcpmux/". If the service type has the
      82:  * prefix "tcpmux/+", tcpmux will return the positive reply for the
      83:  * process; this is for compatibility with older server code, and also
      84:  * allows you to invoke programs that use stdin/stdout without putting any
      85:  * special server code in them. Services that use tcpmux are "nowait"
      86:  * because they do not have a well-known port and hence cannot listen
      87:  * for new requests.
      88:  *
      89:  * Comment lines are indicated by a `#' in column 1.
      90:  */
      91: #include <sys/param.h>
      92: #include <sys/stat.h>
      93: #include <sys/ioctl.h>
      94: #include <sys/socket.h>
      95: #include <sys/wait.h>
      96: #include <sys/time.h>
      97: #include <sys/resource.h>
      98:
      99: #include <netinet/in.h>
     100: #include <arpa/inet.h>
     101:
     102: #include <errno.h>
     103: #include <fcntl.h>
     104: #include <netdb.h>
     105: #include <pwd.h>
     106: #include <signal.h>
     107: #include <stdio.h>
     108: #include <stdlib.h>
     109: #include <string.h>
     110: #include <syslog.h>
     111: #include <unistd.h>
     112:
     113: #include "pathnames.h"
     114:
     115: #define TOOMANY     40      /* don't start more than TOOMANY */
     116: #define CNT_INTVL   60      /* servers in CNT_INTVL sec. */
     117: #define RETRYTIME   (60*10)     /* retry after bind or server fail */
     118:
     119: #define SIGBLOCK    (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
     120:
     121:
     122: int debug = 0;
     123: int nsock, maxsock;
     124: fd_set  allsock;
     125: int options;
     126: int timingout;
     127: int toomany = TOOMANY;
     128: struct  servent *sp;
     129:
     130: struct  servtab {
     131:     char    *se_service;        /* name of service */
     132:     int se_socktype;        /* type of socket to use */
     133:     char    *se_proto;      /* protocol used */
     134:     short   se_wait;        /* single threaded server */
     135:     short   se_checked;     /* looked at during merge */
     136:     char    *se_user;       /* user name to run as */
     137:     struct  biltin *se_bi;      /* if built-in, description */
     138:     char    *se_server;     /* server program */
     139: #define MAXARGV 20
     140:     char    *se_argv[MAXARGV+1];    /* program arguments */
     141:     int se_fd;          /* open descriptor */
     142:     int se_type;        /* type */
     143:     struct  sockaddr_in se_ctrladdr;/* bound address */
     144:     int se_count;       /* number started since se_time */
     145:     struct  timeval se_time;    /* start of se_count */
     146:     struct  servtab *se_next;
     147: } *servtab;
     148:
     149: #define NORM_TYPE   0
     150: #define MUX_TYPE    1
     151: #define MUXPLUS_TYPE    2
     152: #define ISMUX(sep)  (((sep)->se_type == MUX_TYPE) || \
     153:              ((sep)->se_type == MUXPLUS_TYPE))
     154: #define ISMUXPLUS(sep)  ((sep)->se_type == MUXPLUS_TYPE)
     155:
     156: /*
     157:  * These four definitions are not present (yet) in 2.11BSD.
     158:  * Adding 'register' declarations, using a long 'ltmpint' and declaring a
     159:  * couple signal functions 'int' rather than 'void' were the only changes
     160:  * necessary to port the program.
     161: */
     162: #define __P(x)  ()
     163: #define memmove(dst,src,len)    bcopy(src,dst,len)
     164: #define SEEK_SET    0   /* L_SET */
     165: #define LINE_MAX    1024    /* we don't have this in syslimits.h */
     166:
     167: void        chargen_dg __P((int, struct servtab *));
     168: void        chargen_stream __P((int, struct servtab *));
     169: void        close_sep __P((struct servtab *));
     170: int     config __P((int));
     171: void        daytime_dg __P((int, struct servtab *));
     172: void        daytime_stream __P((int, struct servtab *));
     173: void        discard_dg __P((int, struct servtab *));
     174: void        discard_stream __P((int, struct servtab *));
     175: void        echo_dg __P((int, struct servtab *));
     176: void        echo_stream __P((int, struct servtab *));
     177: void        endconfig __P((void));
     178: struct servtab *enter __P((struct servtab *));
     179: void        freeconfig __P((struct servtab *));
     180: struct servtab *getconfigent __P((void));
     181: void        machtime_dg __P((int, struct servtab *));
     182: void        machtime_stream __P((int, struct servtab *));
     183: char           *newstr __P((char *));
     184: char           *nextline __P((FILE *));
     185: void        print_service __P((char *, struct servtab *));
     186: int     reapchild __P((int));
     187: int     retry __P((int));
     188: int     setconfig __P((void));
     189: void        setup __P((struct servtab *));
     190: char           *sskip __P((char **));
     191: char           *skip __P((char **));
     192: struct servtab *tcpmux __P((int));
     193:
     194: struct biltin {
     195:     char    *bi_service;        /* internally provided service name */
     196:     int bi_socktype;        /* type of socket supported */
     197:     short   bi_fork;        /* 1 if should fork before call */
     198:     short   bi_wait;        /* 1 if should wait for child */
     199:     void    (*bi_fn)();     /* function which performs it */
     200: } biltins[] = {
     201:     /* Echo received data */
     202:     { "echo",   SOCK_STREAM,    1, 0,   echo_stream },
     203:     { "echo",   SOCK_DGRAM, 0, 0,   echo_dg },
     204:
     205:     /* Internet /dev/null */
     206:     { "discard",    SOCK_STREAM,    1, 0,   discard_stream },
     207:     { "discard",    SOCK_DGRAM, 0, 0,   discard_dg },
     208:
     209:     /* Return 32 bit time since 1970 */
     210:     { "time",   SOCK_STREAM,    0, 0,   machtime_stream },
     211:     { "time",   SOCK_DGRAM, 0, 0,   machtime_dg },
     212:
     213:     /* Return human-readable time */
     214:     { "daytime",    SOCK_STREAM,    0, 0,   daytime_stream },
     215:     { "daytime",    SOCK_DGRAM, 0, 0,   daytime_dg },
     216:
     217:     /* Familiar character generator */
     218:     { "chargen",    SOCK_STREAM,    1, 0,   chargen_stream },
     219:     { "chargen",    SOCK_DGRAM, 0, 0,   chargen_dg },
     220:
     221:     { "tcpmux", SOCK_STREAM,    1, 0,   (void (*)())tcpmux },
     222:
     223:     { NULL }
     224: };
     225:
     226: #define NUMINT  (sizeof(intab) / sizeof(struct inent))
     227: char    *CONFIG = _PATH_INETDCONF;
     228: char    **Argv;
     229: char    *LastArg;
     230:
     231: int
     232: main(argc, argv, envp)
     233:     int argc;
     234:     char *argv[], *envp[];
     235: {
     236:     register struct servtab *sep;
     237:     register struct passwd *pwd;
     238:     struct sigvec sv;
     239:     int tmpint, ch, dofork;
     240:     long ltmpint;
     241:     pid_t pid;
     242:     char buf[50];
     243:
     244:     Argv = argv;
     245:     if (envp == 0 || *envp == 0)
     246:         envp = argv;
     247:     while (*envp)
     248:         envp++;
     249:     LastArg = envp[-1] + strlen(envp[-1]);
     250:
     251:     openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
     252:
     253:     while ((ch = getopt(argc, argv, "dR:")) != EOF)
     254:         switch(ch) {
     255:         case 'd':
     256:             debug = 1;
     257:             options |= SO_DEBUG;
     258:             break;
     259:         case 'R': { /* invocation rate */
     260:             char *p;
     261:
     262:             ltmpint = strtol(optarg, &p, 0);
     263:             if (ltmpint < 1 || ltmpint > 32767L || *p)
     264:                 syslog(LOG_ERR,
     265:                      "-R %s: bad value for service invocation rate",
     266:                     optarg);
     267:             else
     268:                 toomany = (int)ltmpint;
     269:             break;
     270:         }
     271:         case '?':
     272:         default:
     273:             syslog(LOG_ERR,
     274:                 "usage: inetd [-d] [-R rate] [conf-file]");
     275:             exit(1);
     276:         }
     277:     argc -= optind;
     278:     argv += optind;
     279:
     280:     if (argc > 0)
     281:         CONFIG = argv[0];
     282:     if (debug == 0) {
     283:         daemon(0, 0);
     284:     }
     285:     memset(&sv, 0, sizeof(sv));
     286:     sv.sv_mask = SIGBLOCK;
     287:     sv.sv_handler = retry;
     288:     sigvec(SIGALRM, &sv, (struct sigvec *)0);
     289:     config(SIGHUP);
     290:     sv.sv_handler = config;
     291:     sigvec(SIGHUP, &sv, (struct sigvec *)0);
     292:     sv.sv_handler = reapchild;
     293:     sigvec(SIGCHLD, &sv, (struct sigvec *)0);
     294:
     295:     {
     296:         /* space for daemons to overwrite environment for ps */
     297: #define DUMMYSIZE   100
     298:         char dummy[DUMMYSIZE];
     299:
     300:         (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1);
     301:         dummy[DUMMYSIZE - 1] = '\0';
     302:         (void)setenv("inetd_dummy", dummy, 1);
     303:     }
     304:
     305:     for (;;) {
     306:         int n, ctrl;
     307:         fd_set readable;
     308:
     309:         if (nsock == 0) {
     310:         (void) sigblock(SIGBLOCK);
     311:         while (nsock == 0)
     312:             sigpause(0L);
     313:         (void) sigsetmask(0L);
     314:         }
     315:         readable = allsock;
     316:         if ((n = select(maxsock + 1, &readable, (fd_set *)0,
     317:         (fd_set *)0, (struct timeval *)0)) <= 0) {
     318:             if (n < 0 && errno != EINTR)
     319:             syslog(LOG_WARNING, "select: %m");
     320:             sleep(1);
     321:             continue;
     322:         }
     323:         for (sep = servtab; n && sep; sep = sep->se_next)
     324:             if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
     325:             n--;
     326:             if (debug)
     327:                 fprintf(stderr, "someone wants %s\n",
     328:                 sep->se_service);
     329:             if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
     330:                 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
     331:                 (int *)0);
     332:                 if (debug)
     333:                     fprintf(stderr, "accept, ctrl %d\n", ctrl);
     334:                 if (ctrl < 0) {
     335:                     if (errno != EINTR)
     336:                         syslog(LOG_WARNING,
     337:                         "accept (for %s): %m",
     338:                         sep->se_service);
     339:                     continue;
     340:                 }
     341:                 /*
     342: 			     * Call tcpmux to find the real service to exec.
     343: 			     */
     344:                 if (sep->se_bi &&
     345:                 sep->se_bi->bi_fn == (void (*)()) tcpmux) {
     346:                     sep = tcpmux(ctrl);
     347:                     if (sep == NULL) {
     348:                         close(ctrl);
     349:                         continue;
     350:                     }
     351:                 }
     352:             } else
     353:                 ctrl = sep->se_fd;
     354:             (void) sigblock(SIGBLOCK);
     355:             pid = 0;
     356:             dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
     357:             if (dofork) {
     358:                 if (sep->se_count++ == 0)
     359:                 (void)gettimeofday(&sep->se_time,
     360:                     (struct timezone *)0);
     361:                 else if (sep->se_count >= toomany) {
     362:                 struct timeval now;
     363:
     364:                 (void)gettimeofday(&now, (struct timezone *)0);
     365:                 if (now.tv_sec - sep->se_time.tv_sec >
     366:                     CNT_INTVL) {
     367:                     sep->se_time = now;
     368:                     sep->se_count = 1;
     369:                 } else {
     370:                     syslog(LOG_ERR,
     371:             "%s/%s server failing (looping), service terminated",
     372:                         sep->se_service, sep->se_proto);
     373:                     close_sep(sep);
     374:                     sigsetmask(0L);
     375:                     if (!timingout) {
     376:                         timingout = 1;
     377:                         alarm(RETRYTIME);
     378:                     }
     379:                     continue;
     380:                 }
     381:                 }
     382:                 pid = fork();
     383:             }
     384:             if (pid < 0) {
     385:                 syslog(LOG_ERR, "fork: %m");
     386:                 if (!sep->se_wait &&
     387:                 sep->se_socktype == SOCK_STREAM)
     388:                     close(ctrl);
     389:                 sigsetmask(0L);
     390:                 sleep(1);
     391:                 continue;
     392:             }
     393:             if (pid && sep->se_wait) {
     394:                 sep->se_wait = pid;
     395:                 if (sep->se_fd >= 0) {
     396:                 FD_CLR(sep->se_fd, &allsock);
     397:                     nsock--;
     398:                 }
     399:             }
     400:             sigsetmask(0L);
     401:             if (pid == 0) {
     402: #ifndef pdp11
     403:                 if (debug && dofork)
     404:                 setsid();
     405: #endif
     406:                 if (dofork) {
     407:                 if (debug)
     408:                     fprintf(stderr, "+ Closing from %d\n",
     409:                         maxsock);
     410:                 for (tmpint = maxsock; tmpint > 2; tmpint--)
     411:                     if (tmpint != ctrl)
     412:                         close(tmpint);
     413:                 }
     414:                 if (sep->se_bi)
     415:                 (*sep->se_bi->bi_fn)(ctrl, sep);
     416:                 else {
     417:                 if (debug)
     418:                     fprintf(stderr, "%d execl %s\n",
     419:                         getpid(), sep->se_server);
     420:                 dup2(ctrl, 0);
     421:                 close(ctrl);
     422:                 dup2(0, 1);
     423:                 dup2(0, 2);
     424:                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
     425:                     syslog(LOG_ERR,
     426:                         "%s/%s: %s: No such user",
     427:                         sep->se_service, sep->se_proto,
     428:                         sep->se_user);
     429:                     if (sep->se_socktype != SOCK_STREAM)
     430:                         recv(0, buf, sizeof (buf), 0);
     431:                     _exit(1);
     432:                 }
     433:                 if (pwd->pw_uid) {
     434:                     if (setgid(pwd->pw_gid) < 0) {
     435:                         syslog(LOG_ERR,
     436:                           "%s: can't set gid %d: %m",
     437:                           sep->se_service, pwd->pw_gid);
     438:                         _exit(1);
     439:                     }
     440:                     (void) initgroups(pwd->pw_name,
     441:                             pwd->pw_gid);
     442:                     if (setuid(pwd->pw_uid) < 0) {
     443:                         syslog(LOG_ERR,
     444:                           "%s: can't set uid %d: %m",
     445:                           sep->se_service, pwd->pw_uid);
     446:                         _exit(1);
     447:                     }
     448:                 }
     449:                 execv(sep->se_server, sep->se_argv);
     450:                 if (sep->se_socktype != SOCK_STREAM)
     451:                     recv(0, buf, sizeof (buf), 0);
     452:                 syslog(LOG_ERR,
     453:                     "cannot execute %s: %m", sep->se_server);
     454:                 _exit(1);
     455:                 }
     456:             }
     457:             if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     458:                 close(ctrl);
     459:         }
     460:     }
     461: }
     462:
     463: int
     464: reapchild(signo)
     465:     int signo;
     466: {
     467:     int status;
     468:     pid_t pid;
     469:     register struct servtab *sep;
     470:
     471:     for (;;) {
     472:         pid = wait3(&status, WNOHANG, (struct rusage *)0);
     473:         if (pid <= 0)
     474:             break;
     475:         if (debug)
     476:             fprintf(stderr, "%d reaped, status %#x\n",
     477:                 pid, status);
     478:         for (sep = servtab; sep; sep = sep->se_next)
     479:             if (sep->se_wait == pid) {
     480:                 if (status)
     481:                     syslog(LOG_WARNING,
     482:                         "%s: exit status 0x%x",
     483:                         sep->se_server, status);
     484:                 if (debug)
     485:                     fprintf(stderr, "restored %s, fd %d\n",
     486:                         sep->se_service, sep->se_fd);
     487:                 FD_SET(sep->se_fd, &allsock);
     488:                 nsock++;
     489:                 sep->se_wait = 1;
     490:             }
     491:     }
     492: }
     493:
     494: int
     495: config(signo)
     496:     int signo;
     497: {
     498:     register struct servtab *sep, *cp;
     499:     struct servtab **sepp;
     500:     long omask;
     501:
     502:     if (!setconfig()) {
     503:         syslog(LOG_ERR, "%s: %m", CONFIG);
     504:         return;
     505:     }
     506:     for (sep = servtab; sep; sep = sep->se_next)
     507:         sep->se_checked = 0;
     508:     while (cp = getconfigent()) {
     509:         if (getpwnam(cp->se_user) == NULL) {
     510:             syslog(LOG_ERR,
     511:                 "%s/%s: No such user '%s', service ignored",
     512:                 cp->se_service, cp->se_proto, cp->se_user);
     513:             continue;
     514:         }
     515:         for (sep = servtab; sep; sep = sep->se_next)
     516:             if (strcmp(sep->se_service, cp->se_service) == 0 &&
     517:                 strcmp(sep->se_proto, cp->se_proto) == 0)
     518:                 break;
     519:         if (sep != 0) {
     520:             int i;
     521:
     522:             omask = sigblock(SIGBLOCK);
     523:             /*
     524: 			 * sep->se_wait may be holding the pid of a daemon
     525: 			 * that we're waiting for.  If so, don't overwrite
     526: 			 * it unless the config file explicitly says don't
     527: 			 * wait.
     528: 			 */
     529:             if (cp->se_bi == 0 &&
     530:                 (sep->se_wait == 1 || cp->se_wait == 0))
     531:                 sep->se_wait = cp->se_wait;
     532: #define SWAP(a, b) { char *c = a; a = b; b = c; }
     533:             if (cp->se_user)
     534:                 SWAP(sep->se_user, cp->se_user);
     535:             if (cp->se_server)
     536:                 SWAP(sep->se_server, cp->se_server);
     537:             for (i = 0; i < MAXARGV; i++)
     538:                 SWAP(sep->se_argv[i], cp->se_argv[i]);
     539:             sigsetmask(omask);
     540:             freeconfig(cp);
     541:             if (debug)
     542:                 print_service("REDO", sep);
     543:         } else {
     544:             sep = enter(cp);
     545:             if (debug)
     546:                 print_service("ADD ", sep);
     547:         }
     548:         sep->se_checked = 1;
     549:         if (ISMUX(sep)) {
     550:             sep->se_fd = -1;
     551:             continue;
     552:         }
     553:         sp = getservbyname(sep->se_service, sep->se_proto);
     554:         if (sp == 0) {
     555:             syslog(LOG_ERR, "%s/%s: unknown service",
     556:                 sep->se_service, sep->se_proto);
     557:             sep->se_checked = 0;
     558:             continue;
     559:         }
     560:         if (sp->s_port != sep->se_ctrladdr.sin_port) {
     561:             sep->se_ctrladdr.sin_family = AF_INET;
     562:             sep->se_ctrladdr.sin_port = sp->s_port;
     563:             if (sep->se_fd >= 0)
     564:                 close_sep(sep);
     565:         }
     566:         if (sep->se_fd == -1)
     567:             setup(sep);
     568:     }
     569:     endconfig();
     570:     /*
     571: 	 * Purge anything not looked at above.
     572: 	 */
     573:     omask = sigblock(SIGBLOCK);
     574:     sepp = &servtab;
     575:     while (sep = *sepp) {
     576:         if (sep->se_checked) {
     577:             sepp = &sep->se_next;
     578:             continue;
     579:         }
     580:         *sepp = sep->se_next;
     581:         if (sep->se_fd >= 0)
     582:             close_sep(sep);
     583:         if (debug)
     584:             print_service("FREE", sep);
     585:         freeconfig(sep);
     586:         free((char *)sep);
     587:     }
     588:     (void) sigsetmask(omask);
     589: }
     590:
     591: int
     592: retry(signo)
     593:     int signo;
     594: {
     595:     register struct servtab *sep;
     596:
     597:     timingout = 0;
     598:     for (sep = servtab; sep; sep = sep->se_next)
     599:         if (sep->se_fd == -1)
     600:             setup(sep);
     601: }
     602:
     603: void
     604: setup(sep)
     605:     register struct servtab *sep;
     606: {
     607:     int on = 1;
     608:
     609:     if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
     610:         if (debug)
     611:             fprintf(stderr, "socket failed on %s/%s: %s\n",
     612:                 sep->se_service, sep->se_proto,
     613:                 strerror(errno));
     614:         syslog(LOG_ERR, "%s/%s: socket: %m",
     615:             sep->se_service, sep->se_proto);
     616:         return;
     617:     }
     618: #define turnon(fd, opt) \
     619: setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
     620:     if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
     621:         turnon(sep->se_fd, SO_DEBUG) < 0)
     622:         syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
     623:     if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
     624:         syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
     625: #undef turnon
     626:     if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
     627:         sizeof (sep->se_ctrladdr)) < 0) {
     628:         if (debug)
     629:             fprintf(stderr, "bind failed on %s/%s: %s\n",
     630:                 sep->se_service, sep->se_proto,
     631:                 strerror(errno));
     632:         syslog(LOG_ERR, "%s/%s: bind: %m",
     633:             sep->se_service, sep->se_proto);
     634:         (void) close(sep->se_fd);
     635:         sep->se_fd = -1;
     636:         if (!timingout) {
     637:             timingout = 1;
     638:             alarm(RETRYTIME);
     639:         }
     640:         return;
     641:     }
     642:     if (sep->se_socktype == SOCK_STREAM)
     643:         listen(sep->se_fd, 10);
     644:     FD_SET(sep->se_fd, &allsock);
     645:     nsock++;
     646:     if (sep->se_fd > maxsock)
     647:         maxsock = sep->se_fd;
     648:     if (debug) {
     649:         fprintf(stderr, "registered %s on %d\n",
     650:             sep->se_server, sep->se_fd);
     651:     }
     652: }
     653:
     654: /*
     655:  * Finish with a service and its socket.
     656:  */
     657: void
     658: close_sep(sep)
     659:     register struct servtab *sep;
     660: {
     661:     if (sep->se_fd >= 0) {
     662:         nsock--;
     663:         FD_CLR(sep->se_fd, &allsock);
     664:         (void) close(sep->se_fd);
     665:         sep->se_fd = -1;
     666:     }
     667:     sep->se_count = 0;
     668:     /*
     669: 	 * Don't keep the pid of this running deamon: when reapchild()
     670: 	 * reaps this pid, it would erroneously increment nsock.
     671: 	 */
     672:     if (sep->se_wait > 1)
     673:         sep->se_wait = 1;
     674: }
     675:
     676: struct servtab *
     677: enter(cp)
     678:     struct servtab *cp;
     679: {
     680:     register struct servtab *sep;
     681:     long omask;
     682:
     683:     sep = (struct servtab *)malloc(sizeof (*sep));
     684:     if (sep == (struct servtab *)0) {
     685:         syslog(LOG_ERR, "Out of memory.");
     686:         exit(-1);
     687:     }
     688:     *sep = *cp;
     689:     sep->se_fd = -1;
     690:     omask = sigblock(SIGBLOCK);
     691:     sep->se_next = servtab;
     692:     servtab = sep;
     693:     sigsetmask(omask);
     694:     return (sep);
     695: }
     696:
     697: FILE    *fconfig = NULL;
     698: struct  servtab serv;
     699: char    line[LINE_MAX];
     700:
     701: int
     702: setconfig()
     703: {
     704:
     705:     if (fconfig != NULL) {
     706:         fseek(fconfig, 0L, SEEK_SET);
     707:         return (1);
     708:     }
     709:     fconfig = fopen(CONFIG, "r");
     710:     return (fconfig != NULL);
     711: }
     712:
     713: void
     714: endconfig()
     715: {
     716:     if (fconfig) {
     717:         (void) fclose(fconfig);
     718:         fconfig = NULL;
     719:     }
     720: }
     721:
     722: struct servtab *
     723: getconfigent()
     724: {
     725:     register struct servtab *sep = &serv;
     726:     int argc;
     727:     char *cp, *arg;
     728:     static char TCPMUX_TOKEN[] = "tcpmux/";
     729: #define MUX_LEN     (sizeof(TCPMUX_TOKEN)-1)
     730:
     731: more:
     732:     while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
     733:         ;
     734:     if (cp == NULL)
     735:         return ((struct servtab *)0);
     736:     /*
     737: 	 * clear the static buffer, since some fields (se_ctrladdr,
     738: 	 * for example) don't get initialized here.
     739: 	 */
     740:     memset((caddr_t)sep, 0, sizeof *sep);
     741:     arg = skip(&cp);
     742:     if (cp == NULL) {
     743:         /* got an empty line containing just blanks/tabs. */
     744:         goto more;
     745:     }
     746:     if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
     747:         char *c = arg + MUX_LEN;
     748:         if (*c == '+') {
     749:             sep->se_type = MUXPLUS_TYPE;
     750:             c++;
     751:         } else
     752:             sep->se_type = MUX_TYPE;
     753:         sep->se_service = newstr(c);
     754:     } else {
     755:         sep->se_service = newstr(arg);
     756:         sep->se_type = NORM_TYPE;
     757:     }
     758:     arg = sskip(&cp);
     759:     if (strcmp(arg, "stream") == 0)
     760:         sep->se_socktype = SOCK_STREAM;
     761:     else if (strcmp(arg, "dgram") == 0)
     762:         sep->se_socktype = SOCK_DGRAM;
     763:     else if (strcmp(arg, "rdm") == 0)
     764:         sep->se_socktype = SOCK_RDM;
     765:     else if (strcmp(arg, "seqpacket") == 0)
     766:         sep->se_socktype = SOCK_SEQPACKET;
     767:     else if (strcmp(arg, "raw") == 0)
     768:         sep->se_socktype = SOCK_RAW;
     769:     else
     770:         sep->se_socktype = -1;
     771:     sep->se_proto = newstr(sskip(&cp));
     772:     arg = sskip(&cp);
     773:     sep->se_wait = strcmp(arg, "wait") == 0;
     774:     if (ISMUX(sep)) {
     775:         /*
     776: 		 * Silently enforce "nowait" for TCPMUX services since
     777: 		 * they don't have an assigned port to listen on.
     778: 		 */
     779:         sep->se_wait = 0;
     780:
     781:         if (strcmp(sep->se_proto, "tcp")) {
     782:             syslog(LOG_ERR,
     783:                 "%s: bad protocol for tcpmux service %s",
     784:                 CONFIG, sep->se_service);
     785:             goto more;
     786:         }
     787:         if (sep->se_socktype != SOCK_STREAM) {
     788:             syslog(LOG_ERR,
     789:                 "%s: bad socket type for tcpmux service %s",
     790:                 CONFIG, sep->se_service);
     791:             goto more;
     792:         }
     793:     }
     794:     sep->se_user = newstr(sskip(&cp));
     795:     sep->se_server = newstr(sskip(&cp));
     796:     if (strcmp(sep->se_server, "internal") == 0) {
     797:         struct biltin *bi;
     798:
     799:         for (bi = biltins; bi->bi_service; bi++)
     800:             if (bi->bi_socktype == sep->se_socktype &&
     801:                 strcmp(bi->bi_service, sep->se_service) == 0)
     802:                 break;
     803:         if (bi->bi_service == 0) {
     804:             syslog(LOG_ERR, "internal service %s unknown",
     805:                 sep->se_service);
     806:             goto more;
     807:         }
     808:         sep->se_bi = bi;
     809:         sep->se_wait = bi->bi_wait;
     810:     } else
     811:         sep->se_bi = NULL;
     812:     argc = 0;
     813:     for (arg = skip(&cp); cp; arg = skip(&cp))
     814:         if (argc < MAXARGV)
     815:             sep->se_argv[argc++] = newstr(arg);
     816:     while (argc <= MAXARGV)
     817:         sep->se_argv[argc++] = NULL;
     818:     return (sep);
     819: }
     820:
     821: void
     822: freeconfig(cp)
     823:     register struct servtab *cp;
     824: {
     825:     int i;
     826:
     827:     if (cp->se_service)
     828:         free(cp->se_service);
     829:     if (cp->se_proto)
     830:         free(cp->se_proto);
     831:     if (cp->se_user)
     832:         free(cp->se_user);
     833:     if (cp->se_server)
     834:         free(cp->se_server);
     835:     for (i = 0; i < MAXARGV; i++)
     836:         if (cp->se_argv[i])
     837:             free(cp->se_argv[i]);
     838: }
     839:
     840:
     841: /*
     842:  * Safe skip - if skip returns null, log a syntax error in the
     843:  * configuration file and exit.
     844:  */
     845: char *
     846: sskip(cpp)
     847:     char **cpp;
     848: {
     849:     register char *cp;
     850:
     851:     cp = skip(cpp);
     852:     if (cp == NULL) {
     853:         syslog(LOG_ERR, "%s: syntax error", CONFIG);
     854:         exit(-1);
     855:     }
     856:     return (cp);
     857: }
     858:
     859: char *
     860: skip(cpp)
     861:     char **cpp;
     862: {
     863:     register char *cp = *cpp;
     864:     char *start;
     865:
     866: again:
     867:     while (*cp == ' ' || *cp == '\t')
     868:         cp++;
     869:     if (*cp == '\0') {
     870:         int c;
     871:
     872:         c = getc(fconfig);
     873:         (void) ungetc(c, fconfig);
     874:         if (c == ' ' || c == '\t')
     875:             if (cp = nextline(fconfig))
     876:                 goto again;
     877:         *cpp = (char *)0;
     878:         return ((char *)0);
     879:     }
     880:     start = cp;
     881:     while (*cp && *cp != ' ' && *cp != '\t')
     882:         cp++;
     883:     if (*cp != '\0')
     884:         *cp++ = '\0';
     885:     *cpp = cp;
     886:     return (start);
     887: }
     888:
     889: char *
     890: nextline(fd)
     891:     FILE *fd;
     892: {
     893:     register char *cp;
     894:
     895:     if (fgets(line, sizeof (line), fd) == NULL)
     896:         return ((char *)0);
     897:     cp = strchr(line, '\n');
     898:     if (cp)
     899:         *cp = '\0';
     900:     return (line);
     901: }
     902:
     903: char *
     904: newstr(cp)
     905:     register char *cp;
     906: {
     907:     if (cp = strdup(cp ? cp : ""))
     908:         return (cp);
     909:     syslog(LOG_ERR, "strdup: %m");
     910:     exit(-1);
     911:     /* NOTREACHED */
     912: }
     913:
     914: void
     915: setproctitle(a, s)
     916:     char *a;
     917:     int s;
     918: {
     919:     int size;
     920:     register char *cp;
     921:     struct sockaddr_in sin;
     922:     char buf[80];
     923:
     924:     cp = Argv[0];
     925:     size = sizeof(sin);
     926:     if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
     927:         (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
     928:     else
     929:         (void) sprintf(buf, "-%s", a);
     930:     strncpy(cp, buf, LastArg - cp);
     931:     cp += strlen(cp);
     932:     while (cp < LastArg)
     933:         *cp++ = ' ';
     934: }
     935:
     936: /*
     937:  * Internet services provided internally by inetd:
     938:  */
     939: #define BUFSIZE 8192
     940:
     941: /* ARGSUSED */
     942: void
     943: echo_stream(s, sep)     /* Echo service -- echo data back */
     944:     int s;
     945:     struct servtab *sep;
     946: {
     947:     char buffer[BUFSIZE];
     948:     int i;
     949:
     950:     setproctitle(sep->se_service, s);
     951:     while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
     952:         write(s, buffer, i) > 0)
     953:         ;
     954:     exit(0);
     955: }
     956:
     957: /* ARGSUSED */
     958: void
     959: echo_dg(s, sep)         /* Echo service -- echo data back */
     960:     int s;
     961:     struct servtab *sep;
     962: {
     963:     char buffer[BUFSIZE];
     964:     int i, size;
     965:     struct sockaddr sa;
     966:
     967:     size = sizeof(sa);
     968:     if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
     969:         return;
     970:     (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
     971: }
     972:
     973: /* ARGSUSED */
     974: void
     975: discard_stream(s, sep)      /* Discard service -- ignore data */
     976:     int s;
     977:     struct servtab *sep;
     978: {
     979:     int ret;
     980:     char buffer[BUFSIZE];
     981:
     982:     setproctitle(sep->se_service, s);
     983:     while (1) {
     984:         while ((ret = read(s, buffer, sizeof(buffer))) > 0)
     985:             ;
     986:         if (ret == 0 || errno != EINTR)
     987:             break;
     988:     }
     989:     exit(0);
     990: }
     991:
     992: /* ARGSUSED */
     993: void
     994: discard_dg(s, sep)      /* Discard service -- ignore data */
     995:     int s;
     996:     struct servtab *sep;
     997: {
     998:     char buffer[BUFSIZE];
     999:
    1000:     (void) read(s, buffer, sizeof(buffer));
    1001: }
    1002:
    1003: #include <ctype.h>
    1004: #define LINESIZ 72
    1005: char ring[128];
    1006: char *endring;
    1007:
    1008: void
    1009: initring()
    1010: {
    1011:     register int i;
    1012:
    1013:     endring = ring;
    1014:
    1015:     for (i = 0; i <= 128; ++i)
    1016:         if (isprint(i))
    1017:             *endring++ = i;
    1018: }
    1019:
    1020: /* ARGSUSED */
    1021: void
    1022: chargen_stream(s, sep)      /* Character generator */
    1023:     int s;
    1024:     struct servtab *sep;
    1025: {
    1026:     int len;
    1027:     char *rs, text[LINESIZ+2];
    1028:
    1029:     setproctitle(sep->se_service, s);
    1030:
    1031:     if (!endring) {
    1032:         initring();
    1033:         rs = ring;
    1034:     }
    1035:
    1036:     text[LINESIZ] = '\r';
    1037:     text[LINESIZ + 1] = '\n';
    1038:     for (rs = ring;;) {
    1039:         if ((len = endring - rs) >= LINESIZ)
    1040:             memmove(text, rs, LINESIZ);
    1041:         else {
    1042:             memmove(text, rs, len);
    1043:             memmove(text + len, ring, LINESIZ - len);
    1044:         }
    1045:         if (++rs == endring)
    1046:             rs = ring;
    1047:         if (write(s, text, sizeof(text)) != sizeof(text))
    1048:             break;
    1049:     }
    1050:     exit(0);
    1051: }
    1052:
    1053: /* ARGSUSED */
    1054: void
    1055: chargen_dg(s, sep)      /* Character generator */
    1056:     int s;
    1057:     struct servtab *sep;
    1058: {
    1059:     struct sockaddr sa;
    1060:     static char *rs;
    1061:     int len, size;
    1062:     char text[LINESIZ+2];
    1063:
    1064:     if (endring == 0) {
    1065:         initring();
    1066:         rs = ring;
    1067:     }
    1068:
    1069:     size = sizeof(sa);
    1070:     if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
    1071:         return;
    1072:
    1073:     if ((len = endring - rs) >= LINESIZ)
    1074:         memmove(text, rs, LINESIZ);
    1075:     else {
    1076:         memmove(text, rs, len);
    1077:         memmove(text + len, ring, LINESIZ - len);
    1078:     }
    1079:     if (++rs == endring)
    1080:         rs = ring;
    1081:     text[LINESIZ] = '\r';
    1082:     text[LINESIZ + 1] = '\n';
    1083:     (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
    1084: }
    1085:
    1086: /*
    1087:  * Return a machine readable date and time, in the form of the
    1088:  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
    1089:  * returns the number of seconds since midnight, Jan 1, 1970,
    1090:  * we must add 2208988800 seconds to this figure to make up for
    1091:  * some seventy years Bell Labs was asleep.
    1092:  */
    1093:
    1094: long
    1095: machtime()
    1096: {
    1097:     struct timeval tv;
    1098:
    1099:     if (gettimeofday(&tv, (struct timezone *)0) < 0) {
    1100:         if (debug)
    1101:             fprintf(stderr, "Unable to get time of day\n");
    1102:         return (0L);
    1103:     }
    1104: #define OFFSET ((u_long)25567 * 24*60*60)
    1105:     return (htonl((long)(tv.tv_sec + OFFSET)));
    1106: #undef OFFSET
    1107: }
    1108:
    1109: /* ARGSUSED */
    1110: void
    1111: machtime_stream(s, sep)
    1112:     int s;
    1113:     struct servtab *sep;
    1114: {
    1115:     long result;
    1116:
    1117:     result = machtime();
    1118:     (void) write(s, (char *) &result, sizeof(result));
    1119: }
    1120:
    1121: /* ARGSUSED */
    1122: void
    1123: machtime_dg(s, sep)
    1124:     int s;
    1125:     struct servtab *sep;
    1126: {
    1127:     long result;
    1128:     struct sockaddr sa;
    1129:     int size;
    1130:
    1131:     size = sizeof(sa);
    1132:     if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
    1133:         return;
    1134:     result = machtime();
    1135:     (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
    1136: }
    1137:
    1138: /* ARGSUSED */
    1139: void
    1140: daytime_stream(s, sep)      /* Return human-readable time of day */
    1141:     int s;
    1142:     struct servtab *sep;
    1143: {
    1144:     char buffer[256];
    1145:     time_t clock;
    1146:
    1147:     clock = time((time_t *) 0);
    1148:
    1149:     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
    1150:     (void) write(s, buffer, strlen(buffer));
    1151: }
    1152:
    1153: /* ARGSUSED */
    1154: void
    1155: daytime_dg(s, sep)      /* Return human-readable time of day */
    1156:     int s;
    1157:     struct servtab *sep;
    1158: {
    1159:     char buffer[256];
    1160:     time_t clock;
    1161:     struct sockaddr sa;
    1162:     int size;
    1163:
    1164:     clock = time((time_t *) 0);
    1165:
    1166:     size = sizeof(sa);
    1167:     if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
    1168:         return;
    1169:     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
    1170:     (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
    1171: }
    1172:
    1173: /*
    1174:  * print_service:
    1175:  *	Dump relevant information to stderr
    1176:  */
    1177: void
    1178: print_service(action, sep)
    1179:     char *action;
    1180:     struct servtab *sep;
    1181: {
    1182:     fprintf(stderr,
    1183:         "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
    1184:         action, sep->se_service, sep->se_proto,
    1185:         sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
    1186: }
    1187:
    1188: /*
    1189:  *  Based on TCPMUX.C by Mark K. Lottor November 1988
    1190:  *  sri-nic::ps:<mkl>tcpmux.c
    1191:  */
    1192:
    1193:
    1194: static int      /* # of characters upto \r,\n or \0 */
    1195: getline(fd, buf, len)
    1196:     int fd;
    1197:     register char *buf;
    1198:     int len;
    1199: {
    1200:     int count = 0;
    1201:     register int n;
    1202:
    1203:     do {
    1204:         n = read(fd, buf, len-count);
    1205:         if (n == 0)
    1206:             return (count);
    1207:         if (n < 0)
    1208:             return (-1);
    1209:         while (--n >= 0) {
    1210:             if (*buf == '\r' || *buf == '\n' || *buf == '\0')
    1211:                 return (count);
    1212:             count++;
    1213:             buf++;
    1214:         }
    1215:     } while (count < len);
    1216:     return (count);
    1217: }
    1218:
    1219: #define MAX_SERV_LEN    (256+2)     /* 2 bytes for \r\n */
    1220:
    1221: #define strwrite(fd, buf)   (void) write(fd, buf, sizeof(buf)-1)
    1222:
    1223: struct servtab *
    1224: tcpmux(s)
    1225:     int s;
    1226: {
    1227:     register struct servtab *sep;
    1228:     char service[MAX_SERV_LEN+1];
    1229:     int len;
    1230:
    1231:     /* Get requested service name */
    1232:     if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
    1233:         strwrite(s, "-Error reading service name\r\n");
    1234:         return (NULL);
    1235:     }
    1236:     service[len] = '\0';
    1237:
    1238:     if (debug)
    1239:         fprintf(stderr, "tcpmux: someone wants %s\n", service);
    1240:
    1241:     /*
    1242: 	 * Help is a required command, and lists available services,
    1243: 	 * one per line.
    1244: 	 */
    1245:     if (!strcasecmp(service, "help")) {
    1246:         for (sep = servtab; sep; sep = sep->se_next) {
    1247:             if (!ISMUX(sep))
    1248:                 continue;
    1249:             (void)write(s,sep->se_service,strlen(sep->se_service));
    1250:             strwrite(s, "\r\n");
    1251:         }
    1252:         return (NULL);
    1253:     }
    1254:
    1255:     /* Try matching a service in inetd.conf with the request */
    1256:     for (sep = servtab; sep; sep = sep->se_next) {
    1257:         if (!ISMUX(sep))
    1258:             continue;
    1259:         if (!strcasecmp(service, sep->se_service)) {
    1260:             if (ISMUXPLUS(sep)) {
    1261:                 strwrite(s, "+Go\r\n");
    1262:             }
    1263:             return (sep);
    1264:         }
    1265:     }
    1266:     strwrite(s, "-Service not available\r\n");
    1267:     return (NULL);
    1268: }

#### Defined functions

chargen_dg defined in line 1054; used 1 times

- in line 219

chargen_stream defined in line 1021; used 1 times

- in line 218

close_sep defined in line 657; used 3 times

- in line 373, 564, 582

config defined in line 494; used 2 times

- in line 289-290(2)

daytime_dg defined in line 1154; used 1 times

- in line 215

daytime_stream defined in line 1139; used 1 times

- in line 214

discard_dg defined in line 993; used 1 times

- in line 207

discard_stream defined in line 974; used 1 times

- in line 206

echo_dg defined in line 958; used 1 times

- in line 203

echo_stream defined in line 942; used 1 times

- in line 202

endconfig defined in line 713; used 1 times

- in line 569

enter defined in line 676; used 1 times

- in line 544

freeconfig defined in line 821; used 2 times

- in line 540, 585

getconfigent defined in line 722; used 1 times

- in line 508

getline defined in line 1194; used 1 times

- in line 1232

initring defined in line 1008; used 2 times

- in line 1032, 1065

machtime defined in line 1094; used 2 times

- in line 1117, 1134

machtime_dg defined in line 1122; used 1 times

- in line 211

machtime_stream defined in line 1110; used 1 times

- in line 210

main defined in line 231; never used
newstr defined in line 903; used 6 times

- in line 753-755(2), 771, 794-795(2), 815

nextline defined in line 889; used 2 times

- in line 732, 875

print_service defined in line 1177; used 3 times

- in line 542-546(2), 584

reapchild defined in line 463; used 1 times

- in line 292

retry defined in line 591; used 1 times

- in line 287

setconfig defined in line 701; used 1 times

- in line 502

setproctitle defined in line 914; used 3 times

- in line 950, 982, 1029

setup defined in line 603; used 2 times

- in line 567, 600

skip defined in line 859; used 4 times

- in line 741, 813(2), 851

sskip defined in line 845; used 5 times

- in line 758, 771-772(2), 794-795(2)

tcpmux defined in line 1223; used 3 times

- in line 221, 345-346(2)

#### Defined variables

Argv defined in line 228; used 2 times

- in line 244, 924

CONFIG defined in line 227; used 6 times

- in line 281, 503, 709, 784, 790, 853

LastArg defined in line 229; used 3 times

- in line 249, 930-932(2)

allsock defined in line 124; used 5 times

- in line 315, 396, 487, 644, 663

biltins defined in line 200; used 1 times

- in line 799

copyright defined in line 35; never used
debug defined in line 122; used 17 times

- in line 256, 282, 326, 332, 403-407(2), 417, 475, 484, 541-545(2), 583, 610, 628, 648, 1100, 1238

endring defined in line 1006; used 8 times

- in line 1013-1017(2), 1031, 1039, 1045, 1064, 1073, 1079

line defined in line 699; used 4 times

- in line 895-900(4)

maxsock defined in line 123; used 5 times

- in line 316, 409-410(2), 646-647(2)

nsock defined in line 123; used 6 times

- in line 309-311(2), 397, 488, 645, 662

options defined in line 125; used 2 times

- in line 257, 620

ring defined in line 1005; used 8 times

- in line 1013, 1033-1046(4), 1066, 1077-1080(2)

sccsid defined in line 39; never used
serv defined in line 698; used 1 times

- in line 725

servtab defined in line 147; used 10 times

- in line 323, 478, 506, 515, 574, 598, 691-692(2), 1246, 1256

sp defined in line 128; used 4 times

- in line 553-554(2), 560-562(2)

timingout defined in line 126; used 5 times

- in line 375-376(2), 597, 636-637(2)

toomany defined in line 127; used 2 times

- in line 268, 361

#### Defined struct's

biltin defined in line 194; used 3 times

- in line 137, 797(2)

servtab defined in line 130; used 98 times

- in line 146(2), 167-192(36), 236(2), 469(2), 498-499(4), 595(2), 605(2), 659(2), 676-684(10), 698(2), 722-725(4), 735(2), 823(2), 945(2), 961(2), 977(2), 996(2), 1024(2), 1057(2), 1113(2), 1125(2), 1142(2), 1157(2), 1180(2), 1223-1227(4)

#### Defined macros

BUFSIZE defined in line 939; used 4 times

- in line 947, 963, 980, 998

CNT_INTVL defined in line 116; used 1 times

- in line 366

DUMMYSIZE defined in line 297; used 3 times

- in line 298-301(3)

ISMUX defined in line 152; used 4 times

- in line 549, 774, 1247, 1257

ISMUXPLUS defined in line 154; used 1 times

- in line 1260

LINESIZ defined in line 1004; used 12 times

- in line 1027, 1036-1043(5), 1062, 1073-1082(5)

LINE_MAX defined in line 165; used 1 times

- in line 699

MAXARGV defined in line 139; used 5 times

- in line 140, 537, 814-816(2), 835

MAX_SERV_LEN defined in line 1219; used 2 times

- in line 1228-1232(2)

MUXPLUS_TYPE defined in line 151; used 3 times

- in line 153-154(2), 749

MUX_LEN defined in line 729; used 2 times

- in line 746-747(2)

MUX_TYPE defined in line 150; used 2 times

- in line 152, 752

NORM_TYPE defined in line 149; used 1 times

- in line 756

NUMINT defined in line 226; never used
OFFSET defined in line 1104; used 2 times

- in line 1105-1106(2)

RETRYTIME defined in line 117; used 2 times

- in line 377, 638

SEEK_SET defined in line 164; used 1 times

- in line 706

SIGBLOCK defined in line 119; used 6 times

- in line 286, 310, 354, 522, 573, 690

SWAP defined in line 532; used 3 times

- in line 534-538(3)

TOOMANY defined in line 115; used 1 times

- in line 127

__P defined in line 162; used 26 times

- in line 167-192(26)

memmove defined in line 163; used 6 times

- in line 1040-1043(3), 1074-1077(3)

strwrite defined in line 1221; used 4 times

- in line 1233, 1250, 1261-1266(2)

turnon defined in line 618; used 3 times

- in line 621-625(3)

Last modified: 1996-11-14 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3959 |