1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238#include <syslog.h>
239#include <sys/resource.h>
240#include <sys/socket.h>
241#include <sys/un.h>
242
243#include "libbb.h"
244#include "common_bufsiz.h"
245
246#if ENABLE_FEATURE_INETD_RPC
247# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
248# warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support"
249
250
251
252
253
254# endif
255# include <rpc/rpc.h>
256# include <rpc/pmap_clnt.h>
257#endif
258
259#if !BB_MMU
260
261
262#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
263#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0
264#endif
265
266#define CNT_INTERVAL 60
267#define RETRYTIME 60
268
269
270
271#ifndef RLIMIT_NOFILE
272#define RLIMIT_NOFILE RLIMIT_OFILE
273#endif
274
275#ifndef OPEN_MAX
276#define OPEN_MAX 64
277#endif
278
279
280#define FD_MARGIN 8
281
282#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD \
283 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO \
284 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN \
285 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME \
286 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
287# define INETD_BUILTINS_ENABLED
288#endif
289
290typedef struct servtab_t {
291
292 int se_fd;
293
294
295 char *se_local_hostname;
296 char *se_service;
297
298 char *se_proto;
299#if ENABLE_FEATURE_INETD_RPC
300 int se_rpcprog;
301 int se_rpcver_lo;
302 int se_rpcver_hi;
303#define is_rpc_service(sep) ((sep)->se_rpcver_lo != 0)
304#else
305#define is_rpc_service(sep) 0
306#endif
307 pid_t se_wait;
308
309 socktype_t se_socktype;
310 family_t se_family;
311
312 smallint se_proto_no;
313 smallint se_checked;
314 unsigned se_max;
315 unsigned se_count;
316 unsigned se_time;
317 char *se_user;
318 char *se_group;
319#ifdef INETD_BUILTINS_ENABLED
320 const struct builtin *se_builtin;
321#endif
322 struct servtab_t *se_next;
323 len_and_sockaddr *se_lsa;
324 char *se_program;
325#define MAXARGV 20
326 char *se_argv[MAXARGV + 1];
327} servtab_t;
328
329#ifdef INETD_BUILTINS_ENABLED
330
331#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
332static void FAST_FUNC echo_stream(int, servtab_t *);
333static void FAST_FUNC echo_dg(int, servtab_t *);
334#endif
335
336#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
337static void FAST_FUNC discard_stream(int, servtab_t *);
338static void FAST_FUNC discard_dg(int, servtab_t *);
339#endif
340
341#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
342static void FAST_FUNC machtime_stream(int, servtab_t *);
343static void FAST_FUNC machtime_dg(int, servtab_t *);
344#endif
345
346#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
347static void FAST_FUNC daytime_stream(int, servtab_t *);
348static void FAST_FUNC daytime_dg(int, servtab_t *);
349#endif
350
351#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
352static void FAST_FUNC chargen_stream(int, servtab_t *);
353static void FAST_FUNC chargen_dg(int, servtab_t *);
354#endif
355
356struct builtin {
357
358 char bi_service7[7];
359 uint8_t bi_fork;
360 void (*bi_stream_fn)(int, servtab_t *) FAST_FUNC;
361 void (*bi_dgram_fn)(int, servtab_t *) FAST_FUNC;
362};
363
364static const struct builtin builtins[] ALIGN_PTR = {
365#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
366 { "echo", 1, echo_stream, echo_dg },
367#endif
368#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
369 { "discard", 1, discard_stream, discard_dg },
370#endif
371#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
372 { "chargen", 1, chargen_stream, chargen_dg },
373#endif
374#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
375 { "time", 0, machtime_stream, machtime_dg },
376#endif
377#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
378 { "daytime", 0, daytime_stream, daytime_dg },
379#endif
380};
381#endif
382
383struct globals {
384 rlim_t rlim_ofile_cur;
385 struct rlimit rlim_ofile;
386 servtab_t *serv_list;
387 int global_queuelen;
388 int maxsock;
389
390
391 int prev_maxsock;
392 unsigned max_concurrency;
393 smallint alarm_armed;
394 uid_t real_uid;
395 const char *config_filename;
396 parser_t *parser;
397 char *default_local_hostname;
398#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
399 char *end_ring;
400 char *ring_pos;
401 char ring[128];
402#endif
403 fd_set allsock;
404
405 char line[256];
406} FIX_ALIASING;
407#define G (*(struct globals*)bb_common_bufsiz1)
408enum { LINE_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line) };
409#define rlim_ofile_cur (G.rlim_ofile_cur )
410#define rlim_ofile (G.rlim_ofile )
411#define serv_list (G.serv_list )
412#define global_queuelen (G.global_queuelen)
413#define maxsock (G.maxsock )
414#define prev_maxsock (G.prev_maxsock )
415#define max_concurrency (G.max_concurrency)
416#define alarm_armed (G.alarm_armed )
417#define real_uid (G.real_uid )
418#define config_filename (G.config_filename)
419#define parser (G.parser )
420#define default_local_hostname (G.default_local_hostname)
421#define first_ps_byte (G.first_ps_byte )
422#define last_ps_byte (G.last_ps_byte )
423#define end_ring (G.end_ring )
424#define ring_pos (G.ring_pos )
425#define ring (G.ring )
426#define allsock (G.allsock )
427#define line (G.line )
428#define INIT_G() do { \
429 setup_common_bufsiz(); \
430 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
431 rlim_ofile_cur = OPEN_MAX; \
432 global_queuelen = 128; \
433 config_filename = "/etc/inetd.conf"; \
434} while (0)
435
436#if 1
437# define dbg(...) ((void)0)
438#else
439# define dbg(...) \
440do { \
441 int dbg_fd = open("inetd_debug.log", O_WRONLY | O_CREAT | O_APPEND, 0666); \
442 if (dbg_fd >= 0) { \
443 fdprintf(dbg_fd, "%d: ", getpid()); \
444 fdprintf(dbg_fd, __VA_ARGS__); \
445 close(dbg_fd); \
446 } \
447} while (0)
448#endif
449
450static void maybe_close(int fd)
451{
452 if (fd >= 0) {
453 close(fd);
454 dbg("closed fd:%d\n", fd);
455 }
456}
457
458
459static len_and_sockaddr *xzalloc_lsa(int family)
460{
461 len_and_sockaddr *lsa;
462 int sz;
463
464 sz = sizeof(struct sockaddr_in);
465 if (family == AF_UNIX)
466 sz = sizeof(struct sockaddr_un);
467#if ENABLE_FEATURE_IPV6
468 if (family == AF_INET6)
469 sz = sizeof(struct sockaddr_in6);
470#endif
471 lsa = xzalloc(LSA_LEN_SIZE + sz);
472 lsa->len = sz;
473 lsa->u.sa.sa_family = family;
474 return lsa;
475}
476
477static void rearm_alarm(void)
478{
479 if (!alarm_armed) {
480 alarm_armed = 1;
481 alarm(RETRYTIME);
482 }
483}
484
485static void block_CHLD_HUP_ALRM(sigset_t *m)
486{
487 sigemptyset(m);
488 sigaddset(m, SIGCHLD);
489 sigaddset(m, SIGHUP);
490 sigaddset(m, SIGALRM);
491 sigprocmask2(SIG_BLOCK, m);
492}
493
494static void restore_sigmask(sigset_t *m)
495{
496 sigprocmask(SIG_SETMASK, m, NULL);
497}
498
499#if ENABLE_FEATURE_INETD_RPC
500static void register_rpc(servtab_t *sep)
501{
502 int n;
503 struct sockaddr_in ir_sin;
504
505 if (bb_getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, sizeof(ir_sin)) < 0) {
506
507 bb_simple_perror_msg("getsockname");
508 return;
509 }
510
511 for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
512 pmap_unset(sep->se_rpcprog, n);
513 if (!pmap_set(sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port)))
514 bb_perror_msg("%s %s: pmap_set(%u,%u,%u,%u)",
515 sep->se_service, sep->se_proto,
516 sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port));
517 }
518}
519
520static void unregister_rpc(servtab_t *sep)
521{
522 int n;
523
524 for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
525 if (!pmap_unset(sep->se_rpcprog, n))
526 bb_perror_msg("pmap_unset(%u,%u)", sep->se_rpcprog, n);
527 }
528}
529#endif
530
531static void bump_nofile(void)
532{
533 enum { FD_CHUNK = 32 };
534 struct rlimit rl;
535
536
537 getrlimit(RLIMIT_NOFILE, &rl);
538 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
539 rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
540 if (rl.rlim_cur <= rlim_ofile_cur) {
541 bb_error_msg("can't extend file limit, max = %d",
542 (int) rl.rlim_cur);
543 return;
544 }
545
546 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
547 bb_simple_perror_msg("setrlimit");
548 return;
549 }
550
551 rlim_ofile_cur = rl.rlim_cur;
552}
553
554static void remove_fd_from_set(int fd)
555{
556 if (fd >= 0) {
557 FD_CLR(fd, &allsock);
558 dbg("stopped listening on fd:%d\n", fd);
559 maxsock = -1;
560 dbg("maxsock:%d\n", maxsock);
561 }
562}
563
564static void add_fd_to_set(int fd)
565{
566 if (fd >= 0) {
567 FD_SET(fd, &allsock);
568 dbg("started listening on fd:%d\n", fd);
569 if (maxsock >= 0 && fd > maxsock) {
570 prev_maxsock = maxsock = fd;
571 dbg("maxsock:%d\n", maxsock);
572 if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN)
573 bump_nofile();
574 }
575 }
576}
577
578static void recalculate_maxsock(void)
579{
580 int fd = 0;
581
582
583
584 maxsock = 0;
585 while (fd <= prev_maxsock) {
586 if (FD_ISSET(fd, &allsock))
587 maxsock = fd;
588 fd++;
589 }
590 dbg("recalculated maxsock:%d\n", maxsock);
591 prev_maxsock = maxsock;
592 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
593 bump_nofile();
594}
595
596static void prepare_socket_fd(servtab_t *sep)
597{
598 int r, fd;
599
600 fd = socket(sep->se_family, sep->se_socktype, 0);
601 if (fd < 0) {
602 bb_simple_perror_msg("socket");
603 return;
604 }
605 setsockopt_reuseaddr(fd);
606
607#if ENABLE_FEATURE_INETD_RPC
608 if (is_rpc_service(sep)) {
609 struct passwd *pwd;
610
611
612
613 set_nport(&sep->se_lsa->u.sa, 0);
614
615
616
617 if (real_uid == 0 && sep->se_family == AF_INET
618 && (pwd = getpwnam(sep->se_user)) != NULL
619 && pwd->pw_uid == 0
620 ) {
621 r = bindresvport(fd, &sep->se_lsa->u.sin);
622 } else {
623 r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
624 }
625 if (r == 0) {
626 int saveerrno = errno;
627
628 getsockname(fd, &sep->se_lsa->u.sa, &sep->se_lsa->len);
629 errno = saveerrno;
630 }
631 } else
632#endif
633 {
634 if (sep->se_family == AF_UNIX) {
635 struct sockaddr_un *sun;
636 sun = (struct sockaddr_un*)&(sep->se_lsa->u.sa);
637 unlink(sun->sun_path);
638 }
639 r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
640 }
641 if (r < 0) {
642 bb_perror_msg("%s/%s: bind",
643 sep->se_service, sep->se_proto);
644 close(fd);
645 rearm_alarm();
646 return;
647 }
648
649 if (sep->se_socktype == SOCK_STREAM) {
650 listen(fd, global_queuelen);
651 dbg("new sep->se_fd:%d (stream)\n", fd);
652 } else {
653 dbg("new sep->se_fd:%d (!stream)\n", fd);
654 }
655
656 add_fd_to_set(fd);
657 sep->se_fd = fd;
658}
659
660static int reopen_config_file(void)
661{
662 free(default_local_hostname);
663 default_local_hostname = xstrdup("*");
664 if (parser != NULL)
665 config_close(parser);
666 parser = config_open(config_filename);
667 return (parser != NULL);
668}
669
670static void close_config_file(void)
671{
672 if (parser) {
673 config_close(parser);
674 parser = NULL;
675 }
676}
677
678static void free_servtab_strings(servtab_t *cp)
679{
680 int i;
681
682 free(cp->se_local_hostname);
683 free(cp->se_service);
684 free(cp->se_proto);
685 free(cp->se_user);
686 free(cp->se_group);
687 free(cp->se_lsa);
688 free(cp->se_program);
689 for (i = 0; i < MAXARGV; i++)
690 free(cp->se_argv[i]);
691}
692
693static servtab_t *new_servtab(void)
694{
695 servtab_t *newtab = xzalloc(sizeof(servtab_t));
696 newtab->se_fd = -1;
697 return newtab;
698}
699
700static servtab_t *dup_servtab(servtab_t *sep)
701{
702 servtab_t *newtab;
703 int argc;
704
705 newtab = new_servtab();
706 *newtab = *sep;
707
708 newtab->se_service = xstrdup(newtab->se_service);
709 newtab->se_proto = xstrdup(newtab->se_proto);
710 newtab->se_user = xstrdup(newtab->se_user);
711 newtab->se_group = xstrdup(newtab->se_group);
712 newtab->se_program = xstrdup(newtab->se_program);
713 for (argc = 0; argc <= MAXARGV; argc++)
714 newtab->se_argv[argc] = xstrdup(newtab->se_argv[argc]);
715
716
717
718
719 return newtab;
720}
721
722
723static NOINLINE servtab_t *parse_one_line(void)
724{
725 int argc;
726 char *token[6+MAXARGV];
727 char *p, *arg;
728 char *hostdelim;
729 servtab_t *sep;
730 servtab_t *nsep;
731 new:
732 sep = new_servtab();
733 more:
734 argc = config_read(parser, token, 6+MAXARGV, 1, "# \t", PARSE_NORMAL);
735 if (!argc) {
736 free(sep);
737 return NULL;
738 }
739
740
741
742 arg = token[0];
743 hostdelim = strrchr(arg, ':');
744 if (hostdelim) {
745 *hostdelim = '\0';
746 sep->se_local_hostname = xstrdup(arg);
747 arg = hostdelim + 1;
748 if (*arg == '\0' && argc == 1) {
749
750
751 free(default_local_hostname);
752 default_local_hostname = sep->se_local_hostname;
753
754
755 goto more;
756 }
757 } else
758 sep->se_local_hostname = xstrdup(default_local_hostname);
759
760
761 sep->se_service = xstrdup(arg);
762
763
764 if (argc < 6) {
765 parse_err:
766 bb_error_msg("parse error on line %u, line is ignored",
767 parser->lineno);
768
769
770
771 free_servtab_strings(sep);
772 free(sep);
773 goto new;
774 }
775
776 {
777 static const int8_t SOCK_xxx[] ALIGN1 = {
778 -1,
779 SOCK_STREAM, SOCK_DGRAM, SOCK_RDM,
780 SOCK_SEQPACKET, SOCK_RAW
781 };
782 sep->se_socktype = SOCK_xxx[1 + index_in_strings(
783 "stream""\0" "dgram""\0" "rdm""\0"
784 "seqpacket""\0" "raw""\0"
785 , token[1])];
786 }
787
788
789 sep->se_proto = arg = xstrdup(token[2]);
790 if (strcmp(arg, "unix") == 0) {
791 sep->se_family = AF_UNIX;
792 } else {
793 char *six;
794 sep->se_family = AF_INET;
795 six = last_char_is(arg, '6');
796 if (six) {
797#if ENABLE_FEATURE_IPV6
798 *six = '\0';
799 sep->se_family = AF_INET6;
800#else
801 bb_error_msg("%s: no support for IPv6", sep->se_proto);
802 goto parse_err;
803#endif
804 }
805 if (is_prefixed_with(arg, "rpc/")) {
806#if ENABLE_FEATURE_INETD_RPC
807 unsigned n;
808 arg += 4;
809 p = strchr(sep->se_service, '/');
810 if (p == NULL) {
811 bb_error_msg("no rpc version: '%s'", sep->se_service);
812 goto parse_err;
813 }
814 *p++ = '\0';
815 n = bb_strtou(p, &p, 10);
816 if (n > INT_MAX) {
817 bad_ver_spec:
818 bb_simple_error_msg("bad rpc version");
819 goto parse_err;
820 }
821 sep->se_rpcver_lo = sep->se_rpcver_hi = n;
822 if (*p == '-') {
823 p++;
824 n = bb_strtou(p, &p, 10);
825 if (n > INT_MAX || (int)n < sep->se_rpcver_lo)
826 goto bad_ver_spec;
827 sep->se_rpcver_hi = n;
828 }
829 if (*p != '\0')
830 goto bad_ver_spec;
831#else
832 bb_simple_error_msg("no support for rpc services");
833 goto parse_err;
834#endif
835 }
836
837 if (strcmp(arg, "tcp") == 0)
838 sep->se_proto_no = IPPROTO_TCP;
839 if (strcmp(arg, "udp") == 0)
840 sep->se_proto_no = IPPROTO_UDP;
841 if (six)
842 *six = '6';
843 if (!sep->se_proto_no)
844 goto parse_err;
845 }
846
847
848 arg = token[3];
849 sep->se_max = max_concurrency;
850 p = strchr(arg, '.');
851 if (p) {
852 *p++ = '\0';
853 sep->se_max = bb_strtou(p, NULL, 10);
854 if (errno)
855 goto parse_err;
856 }
857 sep->se_wait = (arg[0] != 'n' || arg[1] != 'o');
858 if (!sep->se_wait)
859 arg += 2;
860 if (strcmp(arg, "wait") != 0)
861 goto parse_err;
862
863
864 sep->se_user = xstrdup(token[4]);
865 arg = strchr(sep->se_user, '.');
866 if (arg == NULL)
867 arg = strchr(sep->se_user, ':');
868 if (arg) {
869 *arg++ = '\0';
870 sep->se_group = xstrdup(arg);
871 }
872
873
874 sep->se_program = xstrdup(token[5]);
875#ifdef INETD_BUILTINS_ENABLED
876 if (strcmp(sep->se_program, "internal") == 0
877 && strlen(sep->se_service) <= 7
878 && (sep->se_socktype == SOCK_STREAM
879 || sep->se_socktype == SOCK_DGRAM)
880 ) {
881 unsigned i;
882 for (i = 0; i < ARRAY_SIZE(builtins); i++)
883 if (strncmp(builtins[i].bi_service7, sep->se_service, 7) == 0)
884 goto found_bi;
885 bb_error_msg("unknown internal service %s", sep->se_service);
886 goto parse_err;
887 found_bi:
888 sep->se_builtin = &builtins[i];
889
890 if (sep->se_wait != (sep->se_socktype == SOCK_DGRAM))
891 goto parse_err;
892 }
893#endif
894 argc = 0;
895 while (argc < MAXARGV && (arg = token[6+argc]) != NULL)
896 sep->se_argv[argc++] = xstrdup(arg);
897
898
899
900
901 if (argc == 0)
902 sep->se_argv[0] = xstrdup(sep->se_program);
903
904
905 if (sep->se_socktype == SOCK_STREAM) {
906 if (sep->se_proto_no == IPPROTO_UDP)
907 goto parse_err;
908 }
909 if (sep->se_socktype == SOCK_DGRAM) {
910 if (sep->se_proto_no == IPPROTO_TCP)
911 goto parse_err;
912 }
913
914
915
916
917
918
919
920
921 while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) {
922 nsep = dup_servtab(sep);
923
924
925 *hostdelim++ = '\0';
926 nsep->se_local_hostname = xstrdup(hostdelim);
927 nsep->se_next = sep->se_next;
928 sep->se_next = nsep;
929 }
930
931
932
933
934
935 return sep;
936}
937
938static servtab_t *insert_in_servlist(servtab_t *cp)
939{
940 servtab_t *sep;
941 sigset_t omask;
942
943 sep = new_servtab();
944 *sep = *cp;
945 sep->se_fd = -1;
946#if ENABLE_FEATURE_INETD_RPC
947 sep->se_rpcprog = -1;
948#endif
949 block_CHLD_HUP_ALRM(&omask);
950 sep->se_next = serv_list;
951 serv_list = sep;
952 restore_sigmask(&omask);
953 return sep;
954}
955
956static int same_serv_addr_proto(servtab_t *old, servtab_t *new)
957{
958 if (strcmp(old->se_local_hostname, new->se_local_hostname) != 0)
959 return 0;
960 if (strcmp(old->se_service, new->se_service) != 0)
961 return 0;
962 if (strcmp(old->se_proto, new->se_proto) != 0)
963 return 0;
964 return 1;
965}
966
967static void reread_config_file(int sig UNUSED_PARAM)
968{
969 servtab_t *sep, *cp, **sepp;
970 len_and_sockaddr *lsa;
971 sigset_t omask;
972 unsigned n;
973 uint16_t port;
974 int save_errno = errno;
975
976 if (!reopen_config_file())
977 goto ret;
978 for (sep = serv_list; sep; sep = sep->se_next)
979 sep->se_checked = 0;
980
981 goto first_line;
982 while (1) {
983 if (cp == NULL) {
984 first_line:
985 cp = parse_one_line();
986 if (cp == NULL)
987 break;
988 }
989 for (sep = serv_list; sep; sep = sep->se_next)
990 if (same_serv_addr_proto(sep, cp))
991 goto equal_servtab;
992
993 sep = insert_in_servlist(cp);
994 goto after_check;
995 equal_servtab:
996 {
997 int i;
998
999 block_CHLD_HUP_ALRM(&omask);
1000#if ENABLE_FEATURE_INETD_RPC
1001 if (is_rpc_service(sep))
1002 unregister_rpc(sep);
1003 sep->se_rpcver_lo = cp->se_rpcver_lo;
1004 sep->se_rpcver_hi = cp->se_rpcver_hi;
1005#endif
1006 if (cp->se_wait == 0) {
1007
1008
1009
1010
1011
1012 add_fd_to_set(sep->se_fd);
1013 }
1014 sep->se_wait = cp->se_wait;
1015 sep->se_max = cp->se_max;
1016
1017#define SWAP(type, a, b) do { type c = (type)a; a = (type)b; b = (type)c; } while (0)
1018 SWAP(char*, sep->se_user, cp->se_user);
1019 SWAP(char*, sep->se_group, cp->se_group);
1020 SWAP(char*, sep->se_program, cp->se_program);
1021 for (i = 0; i < MAXARGV; i++)
1022 SWAP(char*, sep->se_argv[i], cp->se_argv[i]);
1023#undef SWAP
1024 restore_sigmask(&omask);
1025 free_servtab_strings(cp);
1026 }
1027 after_check:
1028
1029
1030 sep->se_checked = 1;
1031
1032
1033 switch (sep->se_family) {
1034 struct sockaddr_un *sun;
1035 case AF_UNIX:
1036 lsa = xzalloc_lsa(AF_UNIX);
1037 sun = (struct sockaddr_un*)&lsa->u.sa;
1038 safe_strncpy(sun->sun_path, sep->se_service, sizeof(sun->sun_path));
1039 break;
1040
1041 default:
1042 n = bb_strtou(sep->se_service, NULL, 10);
1043#if ENABLE_FEATURE_INETD_RPC
1044 if (is_rpc_service(sep)) {
1045 sep->se_rpcprog = n;
1046 if (errno) {
1047 struct rpcent *rp = getrpcbyname(sep->se_service);
1048 if (rp == NULL) {
1049 bb_error_msg("%s: unknown rpc service", sep->se_service);
1050 goto next_cp;
1051 }
1052 sep->se_rpcprog = rp->r_number;
1053 }
1054 if (sep->se_fd == -1)
1055 prepare_socket_fd(sep);
1056 if (sep->se_fd != -1)
1057 register_rpc(sep);
1058 goto next_cp;
1059 }
1060#endif
1061
1062 port = htons(n);
1063 if (errno || n > 0xffff) {
1064 char protoname[4];
1065 struct servent *sp;
1066
1067 safe_strncpy(protoname, sep->se_proto, 4);
1068 sp = getservbyname(sep->se_service, protoname);
1069 if (sp == NULL) {
1070 bb_error_msg("%s/%s: unknown service",
1071 sep->se_service, sep->se_proto);
1072 goto next_cp;
1073 }
1074 port = sp->s_port;
1075 }
1076 if (LONE_CHAR(sep->se_local_hostname, '*')) {
1077 lsa = xzalloc_lsa(sep->se_family);
1078 set_nport(&lsa->u.sa, port);
1079 } else {
1080 lsa = host_and_af2sockaddr(sep->se_local_hostname,
1081 ntohs(port), sep->se_family);
1082 if (!lsa) {
1083 bb_error_msg("%s/%s: unknown host '%s'",
1084 sep->se_service, sep->se_proto,
1085 sep->se_local_hostname);
1086 goto next_cp;
1087 }
1088 }
1089 break;
1090 }
1091
1092
1093 if (sep->se_lsa == NULL
1094 || lsa->len != sep->se_lsa->len
1095 || memcmp(&lsa->u.sa, &sep->se_lsa->u.sa, lsa->len) != 0
1096 ) {
1097 remove_fd_from_set(sep->se_fd);
1098 maybe_close(sep->se_fd);
1099 free(sep->se_lsa);
1100 sep->se_lsa = lsa;
1101 sep->se_fd = -1;
1102 } else {
1103 free(lsa);
1104 }
1105 if (sep->se_fd == -1)
1106 prepare_socket_fd(sep);
1107 next_cp:
1108 sep = cp->se_next;
1109 free(cp);
1110 cp = sep;
1111 }
1112 close_config_file();
1113
1114
1115
1116 block_CHLD_HUP_ALRM(&omask);
1117 sepp = &serv_list;
1118 while ((sep = *sepp) != NULL) {
1119 if (sep->se_checked) {
1120 sepp = &sep->se_next;
1121 continue;
1122 }
1123 *sepp = sep->se_next;
1124 remove_fd_from_set(sep->se_fd);
1125 maybe_close(sep->se_fd);
1126#if ENABLE_FEATURE_INETD_RPC
1127 if (is_rpc_service(sep))
1128 unregister_rpc(sep);
1129#endif
1130 if (sep->se_family == AF_UNIX)
1131 unlink(sep->se_service);
1132 free_servtab_strings(sep);
1133 free(sep);
1134 }
1135 restore_sigmask(&omask);
1136 ret:
1137 errno = save_errno;
1138}
1139
1140static void reap_child(int sig UNUSED_PARAM)
1141{
1142 pid_t pid;
1143 int status;
1144 servtab_t *sep;
1145 int save_errno = errno;
1146
1147 for (;;) {
1148 pid = wait_any_nohang(&status);
1149 if (pid <= 0)
1150 break;
1151 for (sep = serv_list; sep; sep = sep->se_next) {
1152 if (sep->se_wait != pid)
1153 continue;
1154
1155 if (WIFEXITED(status) && WEXITSTATUS(status))
1156 bb_error_msg("%s: exit status %u",
1157 sep->se_program, WEXITSTATUS(status));
1158 else if (WIFSIGNALED(status))
1159 bb_error_msg("%s: exit signal %u",
1160 sep->se_program, WTERMSIG(status));
1161 sep->se_wait = 1;
1162 add_fd_to_set(sep->se_fd);
1163 break;
1164 }
1165 }
1166 errno = save_errno;
1167}
1168
1169static void retry_network_setup(int sig UNUSED_PARAM)
1170{
1171 int save_errno = errno;
1172 servtab_t *sep;
1173
1174 alarm_armed = 0;
1175 for (sep = serv_list; sep; sep = sep->se_next) {
1176 if (sep->se_fd == -1) {
1177 prepare_socket_fd(sep);
1178#if ENABLE_FEATURE_INETD_RPC
1179 if (sep->se_fd != -1 && is_rpc_service(sep))
1180 register_rpc(sep);
1181#endif
1182 }
1183 }
1184 errno = save_errno;
1185}
1186
1187static void clean_up_and_exit(int sig UNUSED_PARAM)
1188{
1189 servtab_t *sep;
1190
1191
1192 for (sep = serv_list; sep; sep = sep->se_next) {
1193 if (sep->se_fd == -1)
1194 continue;
1195
1196 switch (sep->se_family) {
1197 case AF_UNIX:
1198 unlink(sep->se_service);
1199 break;
1200 default:
1201#if ENABLE_FEATURE_INETD_RPC
1202 if (sep->se_wait == 1 && is_rpc_service(sep))
1203 unregister_rpc(sep);
1204#endif
1205 break;
1206 }
1207 if (ENABLE_FEATURE_CLEAN_UP)
1208 close(sep->se_fd);
1209 }
1210 remove_pidfile_std_path_and_ext("inetd");
1211 exit(EXIT_SUCCESS);
1212}
1213
1214int inetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1215int inetd_main(int argc UNUSED_PARAM, char **argv)
1216{
1217 struct sigaction sa, saved_pipe_handler;
1218 servtab_t *sep, *sep2;
1219 struct passwd *pwd;
1220 struct group *grp = grp;
1221 int opt;
1222 pid_t pid;
1223 sigset_t omask;
1224
1225 INIT_G();
1226
1227 real_uid = getuid();
1228 if (real_uid != 0)
1229 config_filename = NULL;
1230
1231
1232 opt = getopt32(argv, "R:+feq:+", &max_concurrency, &global_queuelen);
1233 argv += optind;
1234
1235 if (argv[0])
1236 config_filename = argv[0];
1237 if (config_filename == NULL)
1238 bb_simple_error_msg_and_die("non-root must specify config file");
1239 if (!(opt & 2))
1240 bb_daemonize_or_rexec(0, argv - optind);
1241 else
1242 bb_sanitize_stdio();
1243 if (!(opt & 4)) {
1244
1245
1246
1247
1248
1249 openlog(applet_name, LOG_PID | LOG_NDELAY, LOG_DAEMON);
1250 logmode = LOGMODE_SYSLOG;
1251 }
1252
1253 if (real_uid == 0) {
1254
1255 gid_t gid = getgid();
1256 setgroups(1, &gid);
1257 }
1258
1259 write_pidfile_std_path_and_ext("inetd");
1260
1261
1262 getrlimit(RLIMIT_NOFILE, &rlim_ofile);
1263 rlim_ofile_cur = rlim_ofile.rlim_cur;
1264 if (rlim_ofile_cur == RLIM_INFINITY)
1265 rlim_ofile_cur = OPEN_MAX;
1266
1267 memset(&sa, 0, sizeof(sa));
1268
1269 sigaddset(&sa.sa_mask, SIGALRM);
1270 sigaddset(&sa.sa_mask, SIGCHLD);
1271 sigaddset(&sa.sa_mask, SIGHUP);
1272
1273
1274 sa.sa_handler = retry_network_setup;
1275 sigaction_set(SIGALRM, &sa);
1276
1277 sa.sa_handler = reread_config_file;
1278 sigaction_set(SIGHUP, &sa);
1279
1280 sa.sa_handler = reap_child;
1281 sigaction_set(SIGCHLD, &sa);
1282
1283 sa.sa_handler = clean_up_and_exit;
1284 sigaction_set(SIGTERM, &sa);
1285 sa.sa_handler = clean_up_and_exit;
1286 sigaction_set(SIGINT, &sa);
1287 sa.sa_handler = SIG_IGN;
1288 sigaction(SIGPIPE, &sa, &saved_pipe_handler);
1289
1290 reread_config_file(SIGHUP);
1291
1292 for (;;) {
1293 int ready_fd_cnt;
1294 int ctrl, accepted_fd, new_udp_fd;
1295 fd_set readable;
1296
1297 if (maxsock < 0)
1298 recalculate_maxsock();
1299
1300 readable = allsock;
1301
1302
1303
1304 ready_fd_cnt = select(maxsock + 1, &readable, NULL, NULL, NULL);
1305 if (ready_fd_cnt < 0) {
1306 if (errno != EINTR) {
1307 bb_simple_perror_msg("select");
1308 sleep1();
1309 }
1310 continue;
1311 }
1312 dbg("ready_fd_cnt:%d\n", ready_fd_cnt);
1313
1314 for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) {
1315 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
1316 continue;
1317
1318 dbg("ready fd:%d\n", sep->se_fd);
1319 ready_fd_cnt--;
1320 ctrl = sep->se_fd;
1321 accepted_fd = -1;
1322 new_udp_fd = -1;
1323 if (!sep->se_wait) {
1324 if (sep->se_socktype == SOCK_STREAM) {
1325 ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
1326 dbg("accepted_fd:%d\n", accepted_fd);
1327 if (ctrl < 0) {
1328 if (errno != EINTR)
1329 bb_perror_msg("accept (for %s)", sep->se_service);
1330 continue;
1331 }
1332 }
1333
1334 if (sep->se_socktype == SOCK_DGRAM
1335 && sep->se_family != AF_UNIX
1336 ) {
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346 new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
1347 dbg("new_udp_fd:%d\n", new_udp_fd);
1348 if (new_udp_fd < 0) {
1349 udp_err:
1350 recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
1351 continue;
1352 }
1353 setsockopt_reuseaddr(new_udp_fd);
1354
1355
1356
1357 if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
1358 dbg("bind(new_udp_fd) failed\n");
1359 close(new_udp_fd);
1360 goto udp_err;
1361 }
1362 dbg("bind(new_udp_fd) succeeded\n");
1363 }
1364 }
1365
1366 block_CHLD_HUP_ALRM(&omask);
1367 pid = 0;
1368#ifdef INETD_BUILTINS_ENABLED
1369
1370 if (sep->se_builtin == NULL
1371 || (sep->se_socktype == SOCK_STREAM
1372 && sep->se_builtin->bi_fork))
1373#endif
1374 {
1375 if (sep->se_max != 0) {
1376 if (++sep->se_count == 1)
1377 sep->se_time = monotonic_sec();
1378 else if (sep->se_count >= sep->se_max) {
1379 unsigned now = monotonic_sec();
1380
1381 if (now - sep->se_time <= CNT_INTERVAL) {
1382 bb_error_msg("%s/%s: too many connections, pausing",
1383 sep->se_service, sep->se_proto);
1384 remove_fd_from_set(sep->se_fd);
1385 close(sep->se_fd);
1386 sep->se_fd = -1;
1387 sep->se_count = 0;
1388 rearm_alarm();
1389 restore_sigmask(&omask);
1390 maybe_close(new_udp_fd);
1391 maybe_close(accepted_fd);
1392 continue;
1393 }
1394 sep->se_count = 0;
1395 }
1396 }
1397
1398
1399
1400#ifdef INETD_BUILTINS_ENABLED
1401 if (BB_MMU && sep->se_builtin)
1402 pid = fork();
1403 else
1404#endif
1405 pid = vfork();
1406
1407 if (pid < 0) {
1408 bb_simple_perror_msg("vfork"+1);
1409 sleep1();
1410 restore_sigmask(&omask);
1411 maybe_close(new_udp_fd);
1412 maybe_close(accepted_fd);
1413 continue;
1414 }
1415 if (pid == 0)
1416 pid--;
1417 }
1418
1419
1420 if (pid > 0) {
1421 if (sep->se_wait) {
1422
1423
1424 sep->se_wait = pid;
1425 remove_fd_from_set(sep->se_fd);
1426 }
1427 if (new_udp_fd >= 0) {
1428
1429
1430 xmove_fd(new_udp_fd, sep->se_fd);
1431 dbg("moved new_udp_fd:%d to sep->se_fd:%d\n", new_udp_fd, sep->se_fd);
1432 }
1433 restore_sigmask(&omask);
1434 maybe_close(accepted_fd);
1435 continue;
1436 }
1437
1438
1439#ifdef INETD_BUILTINS_ENABLED
1440 if (sep->se_builtin) {
1441 if (pid) {
1442 close(sep->se_fd);
1443 dbg("closed sep->se_fd:%d\n", sep->se_fd);
1444 logmode = LOGMODE_NONE;
1445 }
1446 restore_sigmask(&omask);
1447 if (sep->se_socktype == SOCK_STREAM)
1448 sep->se_builtin->bi_stream_fn(ctrl, sep);
1449 else
1450 sep->se_builtin->bi_dgram_fn(ctrl, sep);
1451 if (pid)
1452 _exit(EXIT_FAILURE);
1453 maybe_close(accepted_fd);
1454 continue;
1455 }
1456#endif
1457
1458 setsid();
1459
1460 if (new_udp_fd >= 0) {
1461 len_and_sockaddr *lsa;
1462 int r;
1463
1464 close(new_udp_fd);
1465 dbg("closed new_udp_fd:%d\n", new_udp_fd);
1466 lsa = xzalloc_lsa(sep->se_family);
1467
1468 r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
1469 &lsa->u.sa, &lsa->len);
1470 if (r < 0)
1471 goto do_exit1;
1472
1473
1474
1475 connect(ctrl, &lsa->u.sa, lsa->len);
1476 dbg("connected ctrl:%d to remote peer\n", ctrl);
1477 free(lsa);
1478 }
1479
1480 pwd = getpwnam(sep->se_user);
1481 if (pwd == NULL) {
1482 bb_error_msg("%s: no such %s", sep->se_user, "user");
1483 goto do_exit1;
1484 }
1485 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
1486 bb_error_msg("%s: no such %s", sep->se_group, "group");
1487 goto do_exit1;
1488 }
1489 if (real_uid != 0 && real_uid != pwd->pw_uid) {
1490
1491 bb_simple_error_msg("non-root must run services as himself");
1492 goto do_exit1;
1493 }
1494 if (pwd->pw_uid != real_uid) {
1495 if (sep->se_group)
1496 pwd->pw_gid = grp->gr_gid;
1497
1498 change_identity(pwd);
1499 } else if (sep->se_group) {
1500 xsetgid(grp->gr_gid);
1501 setgroups(1, &grp->gr_gid);
1502 }
1503 if (rlim_ofile.rlim_cur != rlim_ofile_cur)
1504 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
1505 bb_simple_perror_msg("setrlimit");
1506
1507
1508
1509
1510
1511 xmove_fd(ctrl, STDIN_FILENO);
1512 xdup2(STDIN_FILENO, STDOUT_FILENO);
1513 dbg("moved ctrl:%d to fd 0,1[,2]\n", ctrl);
1514
1515
1516
1517 if (!sep->se_wait)
1518 xdup2(STDIN_FILENO, STDERR_FILENO);
1519
1520
1521 for (sep2 = serv_list; sep2; sep2 = sep2->se_next)
1522 if (sep2->se_fd != ctrl)
1523 maybe_close(sep2->se_fd);
1524 sigaction_set(SIGPIPE, &saved_pipe_handler);
1525 restore_sigmask(&omask);
1526 dbg("execing:'%s'\n", sep->se_program);
1527 BB_EXECVP(sep->se_program, sep->se_argv);
1528 bb_perror_msg("can't execute '%s'", sep->se_program);
1529 do_exit1:
1530
1531 if (sep->se_socktype != SOCK_STREAM)
1532 recv(0, line, LINE_SIZE, MSG_DONTWAIT);
1533 _exit(EXIT_FAILURE);
1534 }
1535 }
1536}
1537
1538#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO \
1539 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
1540# if !BB_MMU
1541static const char *const cat_args[] = { "cat", NULL };
1542# endif
1543#endif
1544
1545
1546
1547
1548#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
1549
1550
1551static void FAST_FUNC echo_stream(int s, servtab_t *sep UNUSED_PARAM)
1552{
1553# if BB_MMU
1554 while (1) {
1555 ssize_t sz = safe_read(s, line, LINE_SIZE);
1556 if (sz <= 0)
1557 break;
1558 xwrite(s, line, sz);
1559 }
1560# else
1561
1562
1563 xmove_fd(s, STDIN_FILENO);
1564 xdup2(STDIN_FILENO, STDOUT_FILENO);
1565
1566 close(STDERR_FILENO);
1567 xopen(bb_dev_null, O_WRONLY);
1568 BB_EXECVP("cat", (char**)cat_args);
1569
1570# endif
1571}
1572static void FAST_FUNC echo_dg(int s, servtab_t *sep)
1573{
1574 enum { BUFSIZE = 12*1024 };
1575 char *buf = xmalloc(BUFSIZE);
1576 int sz;
1577 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1578
1579 lsa->len = sep->se_lsa->len;
1580
1581 sz = recvfrom(s, buf, BUFSIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len);
1582 if (sz > 0)
1583 sendto(s, buf, sz, 0, &lsa->u.sa, lsa->len);
1584 free(buf);
1585}
1586#endif
1587
1588
1589#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
1590
1591
1592static void FAST_FUNC discard_stream(int s, servtab_t *sep UNUSED_PARAM)
1593{
1594# if BB_MMU
1595 while (safe_read(s, line, LINE_SIZE) > 0)
1596 continue;
1597# else
1598
1599
1600 xmove_fd(s, STDIN_FILENO);
1601
1602 close(STDOUT_FILENO);
1603 xopen(bb_dev_null, O_WRONLY);
1604
1605 xdup2(STDOUT_FILENO, STDERR_FILENO);
1606 BB_EXECVP("cat", (char**)cat_args);
1607
1608# endif
1609}
1610
1611static void FAST_FUNC discard_dg(int s, servtab_t *sep UNUSED_PARAM)
1612{
1613
1614 recv(s, line, LINE_SIZE, MSG_DONTWAIT);
1615}
1616#endif
1617
1618
1619#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
1620#define LINESIZ 72
1621static void init_ring(void)
1622{
1623 int i;
1624
1625 end_ring = ring;
1626 for (i = ' '; i < 127; i++)
1627 *end_ring++ = i;
1628}
1629
1630
1631static void FAST_FUNC chargen_stream(int s, servtab_t *sep UNUSED_PARAM)
1632{
1633 char *rs;
1634 int len;
1635 char text[LINESIZ + 2];
1636
1637 if (!end_ring) {
1638 init_ring();
1639 rs = ring;
1640 }
1641
1642 text[LINESIZ] = '\r';
1643 text[LINESIZ + 1] = '\n';
1644 rs = ring;
1645 for (;;) {
1646 len = end_ring - rs;
1647 if (len >= LINESIZ)
1648 memmove(text, rs, LINESIZ);
1649 else {
1650 memmove(text, rs, len);
1651 memmove(text + len, ring, LINESIZ - len);
1652 }
1653 if (++rs == end_ring)
1654 rs = ring;
1655 xwrite(s, text, sizeof(text));
1656 }
1657}
1658
1659static void FAST_FUNC chargen_dg(int s, servtab_t *sep)
1660{
1661 int len;
1662 char text[LINESIZ + 2];
1663 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1664
1665
1666
1667 lsa->len = sep->se_lsa->len;
1668 if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1669 return;
1670
1671 if (!end_ring) {
1672 init_ring();
1673 ring_pos = ring;
1674 }
1675
1676 len = end_ring - ring_pos;
1677 if (len >= LINESIZ)
1678 memmove(text, ring_pos, LINESIZ);
1679 else {
1680 memmove(text, ring_pos, len);
1681 memmove(text + len, ring, LINESIZ - len);
1682 }
1683 if (++ring_pos == end_ring)
1684 ring_pos = ring;
1685 text[LINESIZ] = '\r';
1686 text[LINESIZ + 1] = '\n';
1687 sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len);
1688}
1689#endif
1690
1691
1692#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
1693
1694
1695
1696
1697
1698
1699
1700static NOINLINE uint32_t machtime(void)
1701{
1702 struct timeval tv;
1703
1704 xgettimeofday(&tv);
1705 return htonl((uint32_t)(tv.tv_sec + 2208988800U));
1706}
1707
1708static void FAST_FUNC machtime_stream(int s, servtab_t *sep UNUSED_PARAM)
1709{
1710 uint32_t result;
1711
1712 result = machtime();
1713 full_write(s, &result, sizeof(result));
1714}
1715static void FAST_FUNC machtime_dg(int s, servtab_t *sep)
1716{
1717 uint32_t result;
1718 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1719
1720 lsa->len = sep->se_lsa->len;
1721 if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1722 return;
1723
1724 result = machtime();
1725 sendto(s, &result, sizeof(result), 0, &lsa->u.sa, lsa->len);
1726}
1727#endif
1728
1729
1730#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
1731
1732
1733static void FAST_FUNC daytime_stream(int s, servtab_t *sep UNUSED_PARAM)
1734{
1735 time_t t;
1736
1737 time(&t);
1738 fdprintf(s, "%.24s\r\n", ctime(&t));
1739}
1740static void FAST_FUNC daytime_dg(int s, servtab_t *sep)
1741{
1742 time_t t;
1743 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1744
1745 lsa->len = sep->se_lsa->len;
1746 if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1747 return;
1748
1749 t = time(NULL);
1750 sprintf(line, "%.24s\r\n", ctime(&t));
1751 sendto(s, line, strlen(line), 0, &lsa->u.sa, lsa->len);
1752}
1753#endif
1754