1: /* 2: * Copyright (c) 1983 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: char copyright[] = 9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: #endif not lint 12: 13: #ifndef lint 14: static char sccsid[] = "@(#)inetd.c 5.6 (Berkeley) 4/29/86"; 15: #endif not lint 16: 17: /* 18: * Inetd - Internet super-server 19: * 20: * This program invokes all internet services as needed. 21: * connection-oriented services are invoked each time a 22: * connection is made, by creating a process. This process 23: * is passed the connection as file descriptor 0 and is 24: * expected to do a getpeername to find out the source host 25: * and port. 26: * 27: * Datagram oriented services are invoked when a datagram 28: * arrives; a process is created and passed a pending message 29: * on file descriptor 0. Datagram servers may either connect 30: * to their peer, freeing up the original socket for inetd 31: * to receive further messages on, or ``take over the socket'', 32: * processing all arriving datagrams and, eventually, timing 33: * out. The first type of server is said to be ``multi-threaded''; 34: * the second type of server ``single-threaded''. 35: * 36: * Inetd uses a configuration file which is read at startup 37: * and, possibly, at some later time in response to a hangup signal. 38: * The configuration file is ``free format'' with fields given in the 39: * order shown below. Continuation lines for an entry must being with 40: * a space or tab. All fields must be present in each entry. 41: * 42: * service name must be in /etc/services 43: * socket type stream/dgram/raw/rdm/seqpacket 44: * protocol must be in /etc/protocols 45: * wait/nowait single-threaded/multi-threaded 46: * user user to run daemon as 47: * server program full path name 48: * server program arguments maximum of MAXARGS (5) 49: * 50: * Comment lines are indicated by a `#' in column 1. 51: */ 52: #include <sys/param.h> 53: #include <sys/stat.h> 54: #include <sys/ioctl.h> 55: #include <sys/socket.h> 56: #include <sys/file.h> 57: #include <sys/wait.h> 58: #include <sys/time.h> 59: #include <sys/resource.h> 60: 61: #include <netinet/in.h> 62: #include <arpa/inet.h> 63: 64: #include <errno.h> 65: #include <stdio.h> 66: #include <signal.h> 67: #include <netdb.h> 68: #include <syslog.h> 69: #include <pwd.h> 70: 71: #define TOOMANY 40 /* don't start more than TOOMANY */ 72: #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 73: #define RETRYTIME (60*10) /* retry after bind or server fail */ 74: 75: #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 76: 77: extern int errno; 78: 79: int reapchild(), retry(); 80: char *index(); 81: char *malloc(); 82: 83: int debug = 0; 84: int nsock, maxsock; 85: fd_set allsock; 86: int options; 87: int timingout; 88: struct servent *sp; 89: 90: struct servtab { 91: char *se_service; /* name of service */ 92: int se_socktype; /* type of socket to use */ 93: char *se_proto; /* protocol used */ 94: short se_wait; /* single threaded server */ 95: short se_checked; /* looked at during merge */ 96: char *se_user; /* user name to run as */ 97: struct biltin *se_bi; /* if built-in, description */ 98: char *se_server; /* server program */ 99: #define MAXARGV 5 100: char *se_argv[MAXARGV+1]; /* program arguments */ 101: int se_fd; /* open descriptor */ 102: struct sockaddr_in se_ctrladdr;/* bound address */ 103: int se_count; /* number started since se_time */ 104: struct timeval se_time; /* start of se_count */ 105: struct servtab *se_next; 106: } *servtab; 107: 108: int echo_stream(), discard_stream(), machtime_stream(); 109: int daytime_stream(), chargen_stream(); 110: int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg(); 111: 112: struct biltin { 113: char *bi_service; /* internally provided service name */ 114: int bi_socktype; /* type of socket supported */ 115: short bi_fork; /* 1 if should fork before call */ 116: short bi_wait; /* 1 if should wait for child */ 117: int (*bi_fn)(); /* function which performs it */ 118: } biltins[] = { 119: /* Echo received data */ 120: "echo", SOCK_STREAM, 1, 0, echo_stream, 121: "echo", SOCK_DGRAM, 0, 0, echo_dg, 122: 123: /* Internet /dev/null */ 124: "discard", SOCK_STREAM, 1, 0, discard_stream, 125: "discard", SOCK_DGRAM, 0, 0, discard_dg, 126: 127: /* Return 32 bit time since 1970 */ 128: "time", SOCK_STREAM, 0, 0, machtime_stream, 129: "time", SOCK_DGRAM, 0, 0, machtime_dg, 130: 131: /* Return human-readable time */ 132: "daytime", SOCK_STREAM, 0, 0, daytime_stream, 133: "daytime", SOCK_DGRAM, 0, 0, daytime_dg, 134: 135: /* Familiar character generator */ 136: "chargen", SOCK_STREAM, 1, 0, chargen_stream, 137: "chargen", SOCK_DGRAM, 0, 0, chargen_dg, 138: 0 139: }; 140: 141: #define NUMINT (sizeof(intab) / sizeof(struct inent)) 142: char *CONFIG = "/etc/inetd.conf"; 143: char **Argv; 144: char *LastArg; 145: 146: main(argc, argv, envp) 147: int argc; 148: char *argv[], *envp[]; 149: { 150: register struct servtab *sep; 151: register struct passwd *pwd; 152: char *cp, buf[50]; 153: int pid, i, dofork; 154: struct sigvec sv; 155: 156: Argv = argv; 157: if (envp == 0 || *envp == 0) 158: envp = argv; 159: while (*envp) 160: envp++; 161: LastArg = envp[-1] + strlen(envp[-1]); 162: argc--, argv++; 163: while (argc > 0 && *argv[0] == '-') { 164: for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 165: 166: case 'd': 167: debug = 1; 168: options |= SO_DEBUG; 169: break; 170: 171: default: 172: fprintf(stderr, 173: "inetd: Unknown flag -%c ignored.\n", *cp); 174: break; 175: } 176: nextopt: 177: argc--, argv++; 178: } 179: if (argc > 0) 180: CONFIG = argv[0]; 181: #ifndef DEBUG 182: if (fork()) 183: exit(0); 184: { int s; 185: for (s = 0; s < 10; s++) 186: (void) close(s); 187: } 188: (void) open("/", O_RDONLY); 189: (void) dup2(0, 1); 190: (void) dup2(0, 2); 191: { int tt = open("/dev/tty", O_RDWR); 192: if (tt > 0) { 193: ioctl(tt, TIOCNOTTY, (char *)0); 194: close(tt); 195: } 196: } 197: #endif 198: openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 199: bzero((char *)&sv, sizeof(sv)); 200: sv.sv_mask = SIGBLOCK; 201: sv.sv_handler = retry; 202: sigvec(SIGALRM, &sv, (struct sigvec *)0); 203: config(); 204: sv.sv_handler = config; 205: sigvec(SIGHUP, &sv, (struct sigvec *)0); 206: sv.sv_handler = reapchild; 207: sigvec(SIGCHLD, &sv, (struct sigvec *)0); 208: 209: for (;;) { 210: int s, ctrl, n; 211: fd_set readable; 212: 213: while (nsock == 0) 214: sigpause(0); 215: readable = allsock; 216: if ((n = select(maxsock + 1, &readable, (fd_set *)0, 217: (fd_set *)0, (struct timeval *)0)) <= 0) { 218: if (n < 0 && errno != EINTR) 219: syslog(LOG_WARNING, "select: %m\n"); 220: sleep(1); 221: continue; 222: } 223: for (sep = servtab; n && sep; sep = sep->se_next) 224: if (FD_ISSET(sep->se_fd, &readable)) { 225: n--; 226: if (debug) 227: fprintf(stderr, "someone wants %s\n", sep->se_service); 228: if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 229: ctrl = accept(sep->se_fd, (struct sockaddr *)0, 230: (int *)0); 231: if (debug) 232: fprintf(stderr, "accept, ctrl %d\n", ctrl); 233: if (ctrl < 0) { 234: if (errno == EINTR) 235: continue; 236: syslog(LOG_WARNING, "accept: %m"); 237: continue; 238: } 239: } else 240: ctrl = sep->se_fd; 241: (void) sigblock(SIGBLOCK); 242: pid = 0; 243: dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 244: if (dofork) { 245: if (sep->se_count++ == 0) 246: (void)gettimeofday(&sep->se_time, 247: (struct timezone *)0); 248: else if (sep->se_count >= TOOMANY) { 249: struct timeval now; 250: 251: (void)gettimeofday(&now, (struct timezone *)0); 252: if (now.tv_sec - sep->se_time.tv_sec > 253: CNT_INTVL) { 254: sep->se_time = now; 255: sep->se_count = 1; 256: } else { 257: syslog(LOG_ERR, 258: "%s/%s server failing (looping), service terminated\n", 259: sep->se_service, sep->se_proto); 260: FD_CLR(sep->se_fd, &allsock); 261: (void) close(sep->se_fd); 262: sep->se_fd = -1; 263: sep->se_count = 0; 264: nsock--; 265: sigsetmask(0); 266: if (!timingout) { 267: timingout = 1; 268: alarm(RETRYTIME); 269: } 270: continue; 271: } 272: } 273: pid = fork(); 274: } 275: if (pid < 0) { 276: if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 277: close(ctrl); 278: sigsetmask(0); 279: sleep(1); 280: continue; 281: } 282: if (pid && sep->se_wait) { 283: sep->se_wait = pid; 284: FD_CLR(sep->se_fd, &allsock); 285: nsock--; 286: } 287: sigsetmask(0); 288: if (pid == 0) { 289: #ifdef DEBUG 290: int tt; 291: 292: if (dofork && (tt = open("/dev/tty", O_RDWR)) > 0) { 293: ioctl(tt, TIOCNOTTY, 0); 294: close(tt); 295: } 296: #endif 297: if (dofork) 298: for (i = getdtablesize(); --i > 2; ) 299: if (i != ctrl) 300: close(i); 301: if (sep->se_bi) 302: (*sep->se_bi->bi_fn)(ctrl, sep); 303: else { 304: dup2(ctrl, 0); 305: close(ctrl); 306: dup2(0, 1); 307: dup2(0, 2); 308: if ((pwd = getpwnam(sep->se_user)) == NULL) { 309: syslog(LOG_ERR, 310: "getpwnam: %s: No such user", 311: sep->se_user); 312: if (sep->se_socktype != SOCK_STREAM) 313: recv(0, buf, sizeof (buf), 0); 314: _exit(1); 315: } 316: if (pwd->pw_uid) { 317: (void) setgid((gid_t)pwd->pw_gid); 318: initgroups(pwd->pw_name, pwd->pw_gid); 319: (void) setuid((uid_t)pwd->pw_uid); 320: } 321: if (debug) 322: fprintf(stderr, "%d execl %s\n", 323: getpid(), sep->se_server); 324: execv(sep->se_server, sep->se_argv); 325: if (sep->se_socktype != SOCK_STREAM) 326: recv(0, buf, sizeof (buf), 0); 327: syslog(LOG_ERR, "execv %s: %m", sep->se_server); 328: _exit(1); 329: } 330: } 331: if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 332: close(ctrl); 333: } 334: } 335: } 336: 337: reapchild() 338: { 339: union wait status; 340: int pid; 341: register struct servtab *sep; 342: 343: for (;;) { 344: pid = wait3(&status, WNOHANG, (struct rusage *)0); 345: if (pid <= 0) 346: break; 347: if (debug) 348: fprintf(stderr, "%d reaped\n", pid); 349: for (sep = servtab; sep; sep = sep->se_next) 350: if (sep->se_wait == pid) { 351: if (status.w_status) 352: syslog(LOG_WARNING, 353: "%s: exit status 0x%x", 354: sep->se_server, status); 355: if (debug) 356: fprintf(stderr, "restored %s, fd %d\n", 357: sep->se_service, sep->se_fd); 358: FD_SET(sep->se_fd, &allsock); 359: nsock++; 360: sep->se_wait = 1; 361: } 362: } 363: } 364: 365: config() 366: { 367: register struct servtab *sep, *cp, **sepp; 368: struct servtab *getconfigent(), *enter(); 369: int omask; 370: 371: if (!setconfig()) { 372: syslog(LOG_ERR, "%s: %m", CONFIG); 373: return; 374: } 375: for (sep = servtab; sep; sep = sep->se_next) 376: sep->se_checked = 0; 377: while (cp = getconfigent()) { 378: for (sep = servtab; sep; sep = sep->se_next) 379: if (strcmp(sep->se_service, cp->se_service) == 0 && 380: strcmp(sep->se_proto, cp->se_proto) == 0) 381: break; 382: if (sep != 0) { 383: int i; 384: 385: omask = sigblock(SIGBLOCK); 386: if (cp->se_bi == 0) 387: sep->se_wait = cp->se_wait; 388: #define SWAP(a, b) { char *c = a; a = b; b = c; } 389: if (cp->se_user) 390: SWAP(sep->se_user, cp->se_user); 391: if (cp->se_server) 392: SWAP(sep->se_server, cp->se_server); 393: for (i = 0; i < MAXARGV; i++) 394: SWAP(sep->se_argv[i], cp->se_argv[i]); 395: sigsetmask(omask); 396: freeconfig(cp); 397: } else 398: sep = enter(cp); 399: sep->se_checked = 1; 400: sp = getservbyname(sep->se_service, sep->se_proto); 401: if (sp == 0) { 402: syslog(LOG_ERR, "%s/%s: unknown service", 403: sep->se_service, sep->se_proto); 404: continue; 405: } 406: if (sp->s_port != sep->se_ctrladdr.sin_port) { 407: sep->se_ctrladdr.sin_port = sp->s_port; 408: if (sep->se_fd != -1) 409: (void) close(sep->se_fd); 410: sep->se_fd = -1; 411: } 412: if (sep->se_fd == -1) 413: setup(sep); 414: } 415: endconfig(); 416: /* 417: * Purge anything not looked at above. 418: */ 419: omask = sigblock(SIGBLOCK); 420: sepp = &servtab; 421: while (sep = *sepp) { 422: if (sep->se_checked) { 423: sepp = &sep->se_next; 424: continue; 425: } 426: *sepp = sep->se_next; 427: if (sep->se_fd != -1) { 428: FD_CLR(sep->se_fd, &allsock); 429: nsock--; 430: (void) close(sep->se_fd); 431: } 432: freeconfig(sep); 433: free((char *)sep); 434: } 435: (void) sigsetmask(omask); 436: } 437: 438: retry() 439: { 440: register struct servtab *sep; 441: 442: timingout = 0; 443: for (sep = servtab; sep; sep = sep->se_next) 444: if (sep->se_fd == -1) 445: setup(sep); 446: } 447: 448: setup(sep) 449: register struct servtab *sep; 450: { 451: int on = 1; 452: 453: if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 454: syslog(LOG_ERR, "%s/%s: socket: %m", 455: sep->se_service, sep->se_proto); 456: return; 457: } 458: #define turnon(fd, opt) \ 459: setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 460: if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 461: turnon(sep->se_fd, SO_DEBUG) < 0) 462: syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 463: if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 464: syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 465: #undef turnon 466: if (bind(sep->se_fd, &sep->se_ctrladdr, 467: sizeof (sep->se_ctrladdr)) < 0) { 468: syslog(LOG_ERR, "%s/%s: bind: %m", 469: sep->se_service, sep->se_proto); 470: (void) close(sep->se_fd); 471: sep->se_fd = -1; 472: if (!timingout) { 473: timingout = 1; 474: alarm(RETRYTIME); 475: } 476: return; 477: } 478: if (sep->se_socktype == SOCK_STREAM) 479: listen(sep->se_fd, 10); 480: FD_SET(sep->se_fd, &allsock); 481: nsock++; 482: if (sep->se_fd > maxsock) 483: maxsock = sep->se_fd; 484: } 485: 486: struct servtab * 487: enter(cp) 488: struct servtab *cp; 489: { 490: register struct servtab *sep; 491: int omask; 492: char *strdup(); 493: 494: sep = (struct servtab *)malloc(sizeof (*sep)); 495: if (sep == (struct servtab *)0) { 496: syslog(LOG_ERR, "Out of memory."); 497: exit(-1); 498: } 499: *sep = *cp; 500: sep->se_fd = -1; 501: omask = sigblock(SIGBLOCK); 502: sep->se_next = servtab; 503: servtab = sep; 504: sigsetmask(omask); 505: return (sep); 506: } 507: 508: FILE *fconfig = NULL; 509: struct servtab serv; 510: char line[256]; 511: char *skip(), *nextline(); 512: 513: setconfig() 514: { 515: 516: if (fconfig != NULL) { 517: fseek(fconfig, 0L, L_SET); 518: return (1); 519: } 520: fconfig = fopen(CONFIG, "r"); 521: return (fconfig != NULL); 522: } 523: 524: endconfig() 525: { 526: 527: if (fconfig == NULL) 528: return; 529: fclose(fconfig); 530: fconfig = NULL; 531: } 532: 533: struct servtab * 534: getconfigent() 535: { 536: register struct servtab *sep = &serv; 537: char *cp, *arg; 538: int argc; 539: 540: more: 541: while ((cp = nextline(fconfig)) && *cp == '#') 542: ; 543: if (cp == NULL) 544: return ((struct servtab *)0); 545: sep->se_service = strdup(skip(&cp)); 546: arg = skip(&cp); 547: if (strcmp(arg, "stream") == 0) 548: sep->se_socktype = SOCK_STREAM; 549: else if (strcmp(arg, "dgram") == 0) 550: sep->se_socktype = SOCK_DGRAM; 551: else if (strcmp(arg, "rdm") == 0) 552: sep->se_socktype = SOCK_RDM; 553: else if (strcmp(arg, "seqpacket") == 0) 554: sep->se_socktype = SOCK_SEQPACKET; 555: else if (strcmp(arg, "raw") == 0) 556: sep->se_socktype = SOCK_RAW; 557: else 558: sep->se_socktype = -1; 559: sep->se_proto = strdup(skip(&cp)); 560: arg = skip(&cp); 561: sep->se_wait = strcmp(arg, "wait") == 0; 562: sep->se_user = strdup(skip(&cp)); 563: sep->se_server = strdup(skip(&cp)); 564: if (strcmp(sep->se_server, "internal") == 0) { 565: register struct biltin *bi; 566: 567: for (bi = biltins; bi->bi_service; bi++) 568: if (bi->bi_socktype == sep->se_socktype && 569: strcmp(bi->bi_service, sep->se_service) == 0) 570: break; 571: if (bi->bi_service == 0) { 572: syslog(LOG_ERR, "internal service %s unknown\n", 573: sep->se_service); 574: goto more; 575: } 576: sep->se_bi = bi; 577: sep->se_wait = bi->bi_wait; 578: } 579: argc = 0; 580: for (arg = skip(&cp); cp; arg = skip(&cp)) 581: if (argc < MAXARGV) 582: sep->se_argv[argc++] = strdup(arg); 583: while (argc <= MAXARGV) 584: sep->se_argv[argc++] = NULL; 585: return (sep); 586: } 587: 588: freeconfig(cp) 589: register struct servtab *cp; 590: { 591: int i; 592: 593: if (cp->se_service) 594: free(cp->se_service); 595: if (cp->se_proto) 596: free(cp->se_proto); 597: if (cp->se_user) 598: free(cp->se_user); 599: if (cp->se_server) 600: free(cp->se_server); 601: for (i = 0; i < MAXARGV; i++) 602: if (cp->se_argv[i]) 603: free(cp->se_argv[i]); 604: } 605: 606: char * 607: skip(cpp) 608: char **cpp; 609: { 610: register char *cp = *cpp; 611: char *start; 612: 613: again: 614: while (*cp == ' ' || *cp == '\t') 615: cp++; 616: if (*cp == '\0') { 617: char c; 618: 619: c = getc(fconfig); 620: ungetc(c, fconfig); 621: if (c == ' ' || c == '\t') 622: if (cp = nextline(fconfig)) 623: goto again; 624: *cpp = (char *)0; 625: return ((char *)0); 626: } 627: start = cp; 628: while (*cp && *cp != ' ' && *cp != '\t') 629: cp++; 630: if (*cp != '\0') 631: *cp++ = '\0'; 632: *cpp = cp; 633: return (start); 634: } 635: 636: char * 637: nextline(fd) 638: FILE *fd; 639: { 640: char *cp; 641: 642: if (fgets(line, sizeof (line), fd) == NULL) 643: return ((char *)0); 644: cp = index(line, '\n'); 645: if (cp) 646: *cp = '\0'; 647: return (line); 648: } 649: 650: char * 651: strdup(cp) 652: char *cp; 653: { 654: char *new; 655: 656: if (cp == NULL) 657: cp = ""; 658: new = malloc((unsigned)(strlen(cp) + 1)); 659: if (new == (char *)0) { 660: syslog(LOG_ERR, "Out of memory."); 661: exit(-1); 662: } 663: strcpy(new, cp); 664: return (new); 665: } 666: 667: setproctitle(a, s) 668: char *a; 669: int s; 670: { 671: int size; 672: register char *cp; 673: struct sockaddr_in sin; 674: char buf[80]; 675: 676: cp = Argv[0]; 677: size = sizeof(sin); 678: if (getpeername(s, &sin, &size) == 0) 679: sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 680: else 681: sprintf(buf, "-%s", a); 682: strncpy(cp, buf, LastArg - cp); 683: cp += strlen(cp); 684: while (cp < LastArg) 685: *cp++ = ' '; 686: } 687: 688: /* 689: * Internet services provided internally by inetd: 690: */ 691: 692: /* ARGSUSED */ 693: echo_stream(s, sep) /* Echo service -- echo data back */ 694: int s; 695: struct servtab *sep; 696: { 697: char buffer[BUFSIZ]; 698: int i; 699: 700: setproctitle("echo", s); 701: while ((i = read(s, buffer, sizeof(buffer))) > 0 && 702: write(s, buffer, i) > 0) 703: ; 704: exit(0); 705: } 706: 707: /* ARGSUSED */ 708: echo_dg(s, sep) /* Echo service -- echo data back */ 709: int s; 710: struct servtab *sep; 711: { 712: char buffer[BUFSIZ]; 713: int i, size; 714: struct sockaddr sa; 715: 716: size = sizeof(sa); 717: if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 718: return; 719: (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 720: } 721: 722: /* ARGSUSED */ 723: discard_stream(s, sep) /* Discard service -- ignore data */ 724: int s; 725: struct servtab *sep; 726: { 727: char buffer[BUFSIZ]; 728: 729: setproctitle("discard", s); 730: while (1) { 731: while (read(s, buffer, sizeof(buffer)) > 0) 732: ; 733: if (errno != EINTR) 734: break; 735: } 736: exit(0); 737: } 738: 739: /* ARGSUSED */ 740: discard_dg(s, sep) /* Discard service -- ignore data */ 741: int s; 742: struct servtab *sep; 743: { 744: char buffer[BUFSIZ]; 745: 746: (void) read(s, buffer, sizeof(buffer)); 747: } 748: 749: #include <ctype.h> 750: #define LINESIZ 72 751: char ring[128]; 752: char *endring; 753: 754: initring() 755: { 756: register int i; 757: 758: endring = ring; 759: 760: for (i = 0; i <= 128; ++i) 761: if (isprint(i)) 762: *endring++ = i; 763: } 764: 765: /* ARGSUSED */ 766: chargen_stream(s, sep) /* Character generator */ 767: int s; 768: struct servtab *sep; 769: { 770: char text[LINESIZ+2]; 771: register int i; 772: register char *rp, *rs, *dp; 773: 774: setproctitle("discard", s); 775: if (endring == 0) 776: initring(); 777: 778: for (rs = ring; ; ++rs) { 779: if (rs >= endring) 780: rs = ring; 781: rp = rs; 782: dp = text; 783: i = MIN(LINESIZ, endring - rp); 784: bcopy(rp, dp, i); 785: dp += i; 786: if ((rp += i) >= endring) 787: rp = ring; 788: if (i < LINESIZ) { 789: i = LINESIZ - i; 790: bcopy(rp, dp, i); 791: dp += i; 792: if ((rp += i) >= endring) 793: rp = ring; 794: } 795: *dp++ = '\r'; 796: *dp++ = '\n'; 797: 798: if (write(s, text, dp - text) != dp - text) 799: break; 800: } 801: exit(0); 802: } 803: 804: /* ARGSUSED */ 805: chargen_dg(s, sep) /* Character generator */ 806: int s; 807: struct servtab *sep; 808: { 809: char text[LINESIZ+2]; 810: register int i; 811: register char *rp; 812: static char *rs = ring; 813: struct sockaddr sa; 814: int size; 815: 816: if (endring == 0) 817: initring(); 818: 819: size = sizeof(sa); 820: if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 821: return; 822: rp = rs; 823: if (rs++ >= endring) 824: rs = ring; 825: i = MIN(LINESIZ - 2, endring - rp); 826: bcopy(rp, text, i); 827: if ((rp += i) >= endring) 828: rp = ring; 829: if (i < LINESIZ - 2) { 830: bcopy(rp, text, i); 831: if ((rp += i) >= endring) 832: rp = ring; 833: } 834: text[LINESIZ - 2] = '\r'; 835: text[LINESIZ - 1] = '\n'; 836: 837: (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 838: } 839: 840: /* 841: * Return a machine readable date and time, in the form of the 842: * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 843: * returns the number of seconds since midnight, Jan 1, 1970, 844: * we must add 2208988800 seconds to this figure to make up for 845: * some seventy years Bell Labs was asleep. 846: */ 847: 848: long 849: machtime() 850: { 851: struct timeval tv; 852: 853: if (gettimeofday(&tv, (struct timezone *)0) < 0) { 854: fprintf(stderr, "Unable to get time of day\n"); 855: return (0L); 856: } 857: return (htonl((long)tv.tv_sec + 2208988800)); 858: } 859: 860: /* ARGSUSED */ 861: machtime_stream(s, sep) 862: int s; 863: struct servtab *sep; 864: { 865: long result; 866: 867: result = machtime(); 868: (void) write(s, (char *) &result, sizeof(result)); 869: } 870: 871: /* ARGSUSED */ 872: machtime_dg(s, sep) 873: int s; 874: struct servtab *sep; 875: { 876: long result; 877: struct sockaddr sa; 878: int size; 879: 880: size = sizeof(sa); 881: if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 882: return; 883: result = machtime(); 884: (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 885: } 886: 887: /* ARGSUSED */ 888: daytime_stream(s, sep) /* Return human-readable time of day */ 889: int s; 890: struct servtab *sep; 891: { 892: char buffer[256]; 893: time_t time(), clock; 894: char *ctime(); 895: 896: clock = time((time_t *) 0); 897: 898: sprintf(buffer, "%s\r", ctime(&clock)); 899: (void) write(s, buffer, strlen(buffer)); 900: } 901: 902: /* ARGSUSED */ 903: daytime_dg(s, sep) /* Return human-readable time of day */ 904: int s; 905: struct servtab *sep; 906: { 907: char buffer[256]; 908: time_t time(), clock; 909: struct sockaddr sa; 910: int size; 911: char *ctime(); 912: 913: clock = time((time_t *) 0); 914: 915: size = sizeof(sa); 916: if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 917: return; 918: sprintf(buffer, "%s\r", ctime(&clock)); 919: (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 920: }