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.7 (Berkeley) 08/19/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 if (debug) 398 print_service("REDO", sep); 399 } else { 400 sep = enter(cp); 401 if (debug) 402 print_service("ADD ", sep); 403 } 404 sep->se_checked = 1; 405 sp = getservbyname(sep->se_service, sep->se_proto); 406 if (sp == 0) { 407 syslog(LOG_ERR, "%s/%s: unknown service", 408 sep->se_service, sep->se_proto); 409 continue; 410 } 411 if (sp->s_port != sep->se_ctrladdr.sin_port) { 412 sep->se_ctrladdr.sin_port = sp->s_port; 413 if (sep->se_fd != -1) 414 (void) close(sep->se_fd); 415 sep->se_fd = -1; 416 } 417 if (sep->se_fd == -1) 418 setup(sep); 419 } 420 endconfig(); 421 /* 422 * Purge anything not looked at above. 423 */ 424 omask = sigblock(SIGBLOCK); 425 sepp = &servtab; 426 while (sep = *sepp) { 427 if (sep->se_checked) { 428 sepp = &sep->se_next; 429 continue; 430 } 431 *sepp = sep->se_next; 432 if (sep->se_fd != -1) { 433 FD_CLR(sep->se_fd, &allsock); 434 nsock--; 435 (void) close(sep->se_fd); 436 } 437 if (debug) 438 print_service("FREE", sep); 439 freeconfig(sep); 440 free((char *)sep); 441 } 442 (void) sigsetmask(omask); 443 } 444 445 retry() 446 { 447 register struct servtab *sep; 448 449 timingout = 0; 450 for (sep = servtab; sep; sep = sep->se_next) 451 if (sep->se_fd == -1) 452 setup(sep); 453 } 454 455 setup(sep) 456 register struct servtab *sep; 457 { 458 int on = 1; 459 460 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 461 syslog(LOG_ERR, "%s/%s: socket: %m", 462 sep->se_service, sep->se_proto); 463 return; 464 } 465 #define turnon(fd, opt) \ 466 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 467 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 468 turnon(sep->se_fd, SO_DEBUG) < 0) 469 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 470 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 471 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 472 #undef turnon 473 if (bind(sep->se_fd, &sep->se_ctrladdr, 474 sizeof (sep->se_ctrladdr)) < 0) { 475 syslog(LOG_ERR, "%s/%s: bind: %m", 476 sep->se_service, sep->se_proto); 477 (void) close(sep->se_fd); 478 sep->se_fd = -1; 479 if (!timingout) { 480 timingout = 1; 481 alarm(RETRYTIME); 482 } 483 return; 484 } 485 if (sep->se_socktype == SOCK_STREAM) 486 listen(sep->se_fd, 10); 487 FD_SET(sep->se_fd, &allsock); 488 nsock++; 489 if (sep->se_fd > maxsock) 490 maxsock = sep->se_fd; 491 } 492 493 struct servtab * 494 enter(cp) 495 struct servtab *cp; 496 { 497 register struct servtab *sep; 498 int omask; 499 char *strdup(); 500 501 sep = (struct servtab *)malloc(sizeof (*sep)); 502 if (sep == (struct servtab *)0) { 503 syslog(LOG_ERR, "Out of memory."); 504 exit(-1); 505 } 506 *sep = *cp; 507 sep->se_fd = -1; 508 omask = sigblock(SIGBLOCK); 509 sep->se_next = servtab; 510 servtab = sep; 511 sigsetmask(omask); 512 return (sep); 513 } 514 515 FILE *fconfig = NULL; 516 struct servtab serv; 517 char line[256]; 518 char *skip(), *nextline(); 519 520 setconfig() 521 { 522 523 if (fconfig != NULL) { 524 fseek(fconfig, 0L, L_SET); 525 return (1); 526 } 527 fconfig = fopen(CONFIG, "r"); 528 return (fconfig != NULL); 529 } 530 531 endconfig() 532 { 533 534 if (fconfig == NULL) 535 return; 536 fclose(fconfig); 537 fconfig = NULL; 538 } 539 540 struct servtab * 541 getconfigent() 542 { 543 register struct servtab *sep = &serv; 544 char *cp, *arg; 545 int argc; 546 547 more: 548 while ((cp = nextline(fconfig)) && *cp == '#') 549 ; 550 if (cp == NULL) 551 return ((struct servtab *)0); 552 sep->se_service = strdup(skip(&cp)); 553 arg = skip(&cp); 554 if (strcmp(arg, "stream") == 0) 555 sep->se_socktype = SOCK_STREAM; 556 else if (strcmp(arg, "dgram") == 0) 557 sep->se_socktype = SOCK_DGRAM; 558 else if (strcmp(arg, "rdm") == 0) 559 sep->se_socktype = SOCK_RDM; 560 else if (strcmp(arg, "seqpacket") == 0) 561 sep->se_socktype = SOCK_SEQPACKET; 562 else if (strcmp(arg, "raw") == 0) 563 sep->se_socktype = SOCK_RAW; 564 else 565 sep->se_socktype = -1; 566 sep->se_proto = strdup(skip(&cp)); 567 arg = skip(&cp); 568 sep->se_wait = strcmp(arg, "wait") == 0; 569 sep->se_user = strdup(skip(&cp)); 570 sep->se_server = strdup(skip(&cp)); 571 if (strcmp(sep->se_server, "internal") == 0) { 572 register struct biltin *bi; 573 574 for (bi = biltins; bi->bi_service; bi++) 575 if (bi->bi_socktype == sep->se_socktype && 576 strcmp(bi->bi_service, sep->se_service) == 0) 577 break; 578 if (bi->bi_service == 0) { 579 syslog(LOG_ERR, "internal service %s unknown\n", 580 sep->se_service); 581 goto more; 582 } 583 sep->se_bi = bi; 584 sep->se_wait = bi->bi_wait; 585 } else 586 sep->se_bi = NULL; 587 argc = 0; 588 for (arg = skip(&cp); cp; arg = skip(&cp)) 589 if (argc < MAXARGV) 590 sep->se_argv[argc++] = strdup(arg); 591 while (argc <= MAXARGV) 592 sep->se_argv[argc++] = NULL; 593 return (sep); 594 } 595 596 freeconfig(cp) 597 register struct servtab *cp; 598 { 599 int i; 600 601 if (cp->se_service) 602 free(cp->se_service); 603 if (cp->se_proto) 604 free(cp->se_proto); 605 if (cp->se_user) 606 free(cp->se_user); 607 if (cp->se_server) 608 free(cp->se_server); 609 for (i = 0; i < MAXARGV; i++) 610 if (cp->se_argv[i]) 611 free(cp->se_argv[i]); 612 } 613 614 char * 615 skip(cpp) 616 char **cpp; 617 { 618 register char *cp = *cpp; 619 char *start; 620 621 again: 622 while (*cp == ' ' || *cp == '\t') 623 cp++; 624 if (*cp == '\0') { 625 char c; 626 627 c = getc(fconfig); 628 ungetc(c, fconfig); 629 if (c == ' ' || c == '\t') 630 if (cp = nextline(fconfig)) 631 goto again; 632 *cpp = (char *)0; 633 return ((char *)0); 634 } 635 start = cp; 636 while (*cp && *cp != ' ' && *cp != '\t') 637 cp++; 638 if (*cp != '\0') 639 *cp++ = '\0'; 640 *cpp = cp; 641 return (start); 642 } 643 644 char * 645 nextline(fd) 646 FILE *fd; 647 { 648 char *cp; 649 650 if (fgets(line, sizeof (line), fd) == NULL) 651 return ((char *)0); 652 cp = index(line, '\n'); 653 if (cp) 654 *cp = '\0'; 655 return (line); 656 } 657 658 char * 659 strdup(cp) 660 char *cp; 661 { 662 char *new; 663 664 if (cp == NULL) 665 cp = ""; 666 new = malloc((unsigned)(strlen(cp) + 1)); 667 if (new == (char *)0) { 668 syslog(LOG_ERR, "Out of memory."); 669 exit(-1); 670 } 671 strcpy(new, cp); 672 return (new); 673 } 674 675 setproctitle(a, s) 676 char *a; 677 int s; 678 { 679 int size; 680 register char *cp; 681 struct sockaddr_in sin; 682 char buf[80]; 683 684 cp = Argv[0]; 685 size = sizeof(sin); 686 if (getpeername(s, &sin, &size) == 0) 687 sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 688 else 689 sprintf(buf, "-%s", a); 690 strncpy(cp, buf, LastArg - cp); 691 cp += strlen(cp); 692 while (cp < LastArg) 693 *cp++ = ' '; 694 } 695 696 /* 697 * Internet services provided internally by inetd: 698 */ 699 700 /* ARGSUSED */ 701 echo_stream(s, sep) /* Echo service -- echo data back */ 702 int s; 703 struct servtab *sep; 704 { 705 char buffer[BUFSIZ]; 706 int i; 707 708 setproctitle("echo", s); 709 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 710 write(s, buffer, i) > 0) 711 ; 712 exit(0); 713 } 714 715 /* ARGSUSED */ 716 echo_dg(s, sep) /* Echo service -- echo data back */ 717 int s; 718 struct servtab *sep; 719 { 720 char buffer[BUFSIZ]; 721 int i, size; 722 struct sockaddr sa; 723 724 size = sizeof(sa); 725 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 726 return; 727 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 728 } 729 730 /* ARGSUSED */ 731 discard_stream(s, sep) /* Discard service -- ignore data */ 732 int s; 733 struct servtab *sep; 734 { 735 char buffer[BUFSIZ]; 736 737 setproctitle("discard", s); 738 while (1) { 739 while (read(s, buffer, sizeof(buffer)) > 0) 740 ; 741 if (errno != EINTR) 742 break; 743 } 744 exit(0); 745 } 746 747 /* ARGSUSED */ 748 discard_dg(s, sep) /* Discard service -- ignore data */ 749 int s; 750 struct servtab *sep; 751 { 752 char buffer[BUFSIZ]; 753 754 (void) read(s, buffer, sizeof(buffer)); 755 } 756 757 #include <ctype.h> 758 #define LINESIZ 72 759 char ring[128]; 760 char *endring; 761 762 initring() 763 { 764 register int i; 765 766 endring = ring; 767 768 for (i = 0; i <= 128; ++i) 769 if (isprint(i)) 770 *endring++ = i; 771 } 772 773 /* ARGSUSED */ 774 chargen_stream(s, sep) /* Character generator */ 775 int s; 776 struct servtab *sep; 777 { 778 char text[LINESIZ+2]; 779 register int i; 780 register char *rp, *rs, *dp; 781 782 setproctitle("discard", s); 783 if (endring == 0) 784 initring(); 785 786 for (rs = ring; ; ++rs) { 787 if (rs >= endring) 788 rs = ring; 789 rp = rs; 790 dp = text; 791 i = MIN(LINESIZ, endring - rp); 792 bcopy(rp, dp, i); 793 dp += i; 794 if ((rp += i) >= endring) 795 rp = ring; 796 if (i < LINESIZ) { 797 i = LINESIZ - i; 798 bcopy(rp, dp, i); 799 dp += i; 800 if ((rp += i) >= endring) 801 rp = ring; 802 } 803 *dp++ = '\r'; 804 *dp++ = '\n'; 805 806 if (write(s, text, dp - text) != dp - text) 807 break; 808 } 809 exit(0); 810 } 811 812 /* ARGSUSED */ 813 chargen_dg(s, sep) /* Character generator */ 814 int s; 815 struct servtab *sep; 816 { 817 char text[LINESIZ+2]; 818 register int i; 819 register char *rp; 820 static char *rs = ring; 821 struct sockaddr sa; 822 int size; 823 824 if (endring == 0) 825 initring(); 826 827 size = sizeof(sa); 828 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 829 return; 830 rp = rs; 831 if (rs++ >= endring) 832 rs = ring; 833 i = MIN(LINESIZ - 2, endring - rp); 834 bcopy(rp, text, i); 835 if ((rp += i) >= endring) 836 rp = ring; 837 if (i < LINESIZ - 2) { 838 bcopy(rp, text, i); 839 if ((rp += i) >= endring) 840 rp = ring; 841 } 842 text[LINESIZ - 2] = '\r'; 843 text[LINESIZ - 1] = '\n'; 844 845 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 846 } 847 848 /* 849 * Return a machine readable date and time, in the form of the 850 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 851 * returns the number of seconds since midnight, Jan 1, 1970, 852 * we must add 2208988800 seconds to this figure to make up for 853 * some seventy years Bell Labs was asleep. 854 */ 855 856 long 857 machtime() 858 { 859 struct timeval tv; 860 861 if (gettimeofday(&tv, (struct timezone *)0) < 0) { 862 fprintf(stderr, "Unable to get time of day\n"); 863 return (0L); 864 } 865 return (htonl((long)tv.tv_sec + 2208988800)); 866 } 867 868 /* ARGSUSED */ 869 machtime_stream(s, sep) 870 int s; 871 struct servtab *sep; 872 { 873 long result; 874 875 result = machtime(); 876 (void) write(s, (char *) &result, sizeof(result)); 877 } 878 879 /* ARGSUSED */ 880 machtime_dg(s, sep) 881 int s; 882 struct servtab *sep; 883 { 884 long result; 885 struct sockaddr sa; 886 int size; 887 888 size = sizeof(sa); 889 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 890 return; 891 result = machtime(); 892 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 893 } 894 895 /* ARGSUSED */ 896 daytime_stream(s, sep) /* Return human-readable time of day */ 897 int s; 898 struct servtab *sep; 899 { 900 char buffer[256]; 901 time_t time(), clock; 902 char *ctime(); 903 904 clock = time((time_t *) 0); 905 906 sprintf(buffer, "%s\r", ctime(&clock)); 907 (void) write(s, buffer, strlen(buffer)); 908 } 909 910 /* ARGSUSED */ 911 daytime_dg(s, sep) /* Return human-readable time of day */ 912 int s; 913 struct servtab *sep; 914 { 915 char buffer[256]; 916 time_t time(), clock; 917 struct sockaddr sa; 918 int size; 919 char *ctime(); 920 921 clock = time((time_t *) 0); 922 923 size = sizeof(sa); 924 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 925 return; 926 sprintf(buffer, "%s\r", ctime(&clock)); 927 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 928 } 929 930 /* 931 * print_service: 932 * Dump relevant information to stderr 933 */ 934 print_service(action, sep) 935 char *action; 936 struct servtab *sep; 937 { 938 fprintf(stderr, 939 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 940 action, sep->se_service, sep->se_proto, 941 sep->se_wait, sep->se_user, sep->se_bi, sep->se_server); 942 } 943