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
chargen_stream defined in line 1021; used 1 times
close_sep defined in line 657; used 3 times
config defined in line 494; used 2 times
daytime_dg defined in line 1154; used 1 times
daytime_stream defined in line 1139; used 1 times
discard_dg defined in line 993; used 1 times
discard_stream defined in line 974; used 1 times
echo_dg defined in line 958; used 1 times
echo_stream defined in line 942; used 1 times
endconfig defined in line 713; used 1 times
enter defined in line 676; used 1 times
freeconfig defined in line 821; used 2 times
getconfigent defined in line 722; used 1 times
getline defined in line 1194; used 1 times
initring defined in line 1008; used 2 times
machtime defined in line 1094; used 2 times
machtime_dg defined in line 1122; used 1 times
machtime_stream defined in line 1110; used 1 times
main defined in line 231; never used
newstr defined in line 903; used 6 times
nextline defined in line 889; used 2 times
print_service defined in line 1177; used 3 times
reapchild defined in line 463; used 1 times
retry defined in line 591; used 1 times
setconfig defined in line 701; used 1 times
setproctitle defined in line 914; used 3 times
setup defined in line 603; used 2 times
skip defined in line 859; used 4 times
sskip defined in line 845; used 5 times
tcpmux defined in line 1223; used 3 times

Defined variables

Argv defined in line 228; used 2 times
CONFIG defined in line 227; used 6 times
LastArg defined in line 229; used 3 times
allsock defined in line 124; used 5 times
biltins defined in line 200; used 1 times
copyright defined in line 35; never used
debug defined in line 122; used 17 times
endring defined in line 1006; used 8 times
line defined in line 699; used 4 times
maxsock defined in line 123; used 5 times
nsock defined in line 123; used 6 times
options defined in line 125; used 2 times
ring defined in line 1005; used 8 times
sccsid defined in line 39; never used
serv defined in line 698; used 1 times
servtab defined in line 147; used 10 times
sp defined in line 128; used 4 times
timingout defined in line 126; used 5 times
toomany defined in line 127; used 2 times

Defined struct's

biltin defined in line 194; used 3 times
servtab defined in line 130; used 98 times

Defined macros

BUFSIZE defined in line 939; used 4 times
CNT_INTVL defined in line 116; used 1 times
DUMMYSIZE defined in line 297; used 3 times
ISMUX defined in line 152; used 4 times
ISMUXPLUS defined in line 154; used 1 times
LINESIZ defined in line 1004; used 12 times
LINE_MAX defined in line 165; used 1 times
MAXARGV defined in line 139; used 5 times
MAX_SERV_LEN defined in line 1219; used 2 times
MUXPLUS_TYPE defined in line 151; used 3 times
MUX_LEN defined in line 729; used 2 times
MUX_TYPE defined in line 150; used 2 times
NORM_TYPE defined in line 149; used 1 times
NUMINT defined in line 226; never used
OFFSET defined in line 1104; used 2 times
RETRYTIME defined in line 117; used 2 times
SEEK_SET defined in line 164; used 1 times
SIGBLOCK defined in line 119; used 6 times
SWAP defined in line 532; used 3 times
TOOMANY defined in line 115; used 1 times
__P defined in line 162; used 26 times
memmove defined in line 163; used 6 times
strwrite defined in line 1221; used 4 times
turnon defined in line 618; used 3 times
Last modified: 1996-11-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6876
Valid CSS Valid XHTML 1.0 Strict