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