|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.