239 |
#ifdef INETD_BUILTINS_ENABLED |
#ifdef INETD_BUILTINS_ENABLED |
240 |
/* Echo received data */ |
/* Echo received data */ |
241 |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO |
242 |
static void echo_stream(int, servtab_t *); |
static void FAST_FUNC echo_stream(int, servtab_t *); |
243 |
static void echo_dg(int, servtab_t *); |
static void FAST_FUNC echo_dg(int, servtab_t *); |
244 |
#endif |
#endif |
245 |
/* Internet /dev/null */ |
/* Internet /dev/null */ |
246 |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD |
247 |
static void discard_stream(int, servtab_t *); |
static void FAST_FUNC discard_stream(int, servtab_t *); |
248 |
static void discard_dg(int, servtab_t *); |
static void FAST_FUNC discard_dg(int, servtab_t *); |
249 |
#endif |
#endif |
250 |
/* Return 32 bit time since 1900 */ |
/* Return 32 bit time since 1900 */ |
251 |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME |
252 |
static void machtime_stream(int, servtab_t *); |
static void FAST_FUNC machtime_stream(int, servtab_t *); |
253 |
static void machtime_dg(int, servtab_t *); |
static void FAST_FUNC machtime_dg(int, servtab_t *); |
254 |
#endif |
#endif |
255 |
/* Return human-readable time */ |
/* Return human-readable time */ |
256 |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME |
257 |
static void daytime_stream(int, servtab_t *); |
static void FAST_FUNC daytime_stream(int, servtab_t *); |
258 |
static void daytime_dg(int, servtab_t *); |
static void FAST_FUNC daytime_dg(int, servtab_t *); |
259 |
#endif |
#endif |
260 |
/* Familiar character generator */ |
/* Familiar character generator */ |
261 |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN |
262 |
static void chargen_stream(int, servtab_t *); |
static void FAST_FUNC chargen_stream(int, servtab_t *); |
263 |
static void chargen_dg(int, servtab_t *); |
static void FAST_FUNC chargen_dg(int, servtab_t *); |
264 |
#endif |
#endif |
265 |
|
|
266 |
struct builtin { |
struct builtin { |
267 |
/* NB: not necessarily NUL terminated */ |
/* NB: not necessarily NUL terminated */ |
268 |
char bi_service7[7]; /* internally provided service name */ |
char bi_service7[7]; /* internally provided service name */ |
269 |
uint8_t bi_fork; /* 1 if stream fn should run in child */ |
uint8_t bi_fork; /* 1 if stream fn should run in child */ |
270 |
void (*bi_stream_fn)(int, servtab_t *); |
void (*bi_stream_fn)(int, servtab_t *) FAST_FUNC; |
271 |
void (*bi_dgram_fn)(int, servtab_t *); |
void (*bi_dgram_fn)(int, servtab_t *) FAST_FUNC; |
272 |
}; |
}; |
273 |
|
|
274 |
static const struct builtin builtins[] = { |
static const struct builtin builtins[] = { |
658 |
} |
} |
659 |
|
|
660 |
{ |
{ |
661 |
static int8_t SOCK_xxx[] ALIGN1 = { |
static const int8_t SOCK_xxx[] ALIGN1 = { |
662 |
-1, |
-1, |
663 |
SOCK_STREAM, SOCK_DGRAM, SOCK_RDM, |
SOCK_STREAM, SOCK_DGRAM, SOCK_RDM, |
664 |
SOCK_SEQPACKET, SOCK_RAW |
SOCK_SEQPACKET, SOCK_RAW |
1031 |
continue; |
continue; |
1032 |
/* One of our "wait" services */ |
/* One of our "wait" services */ |
1033 |
if (WIFEXITED(status) && WEXITSTATUS(status)) |
if (WIFEXITED(status) && WEXITSTATUS(status)) |
1034 |
bb_error_msg("%s: exit status 0x%x", |
bb_error_msg("%s: exit status %u", |
1035 |
sep->se_program, WEXITSTATUS(status)); |
sep->se_program, WEXITSTATUS(status)); |
1036 |
else if (WIFSIGNALED(status)) |
else if (WIFSIGNALED(status)) |
1037 |
bb_error_msg("%s: exit signal 0x%x", |
bb_error_msg("%s: exit signal %u", |
1038 |
sep->se_program, WTERMSIG(status)); |
sep->se_program, WTERMSIG(status)); |
1039 |
sep->se_wait = 1; |
sep->se_wait = 1; |
1040 |
add_fd_to_set(sep->se_fd); |
add_fd_to_set(sep->se_fd); |
1119 |
else |
else |
1120 |
bb_sanitize_stdio(); |
bb_sanitize_stdio(); |
1121 |
if (!(opt & 4)) { |
if (!(opt & 4)) { |
1122 |
openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON); |
/* LOG_NDELAY: connect to syslog daemon NOW. |
1123 |
|
* Otherwise, we may open syslog socket |
1124 |
|
* in vforked child, making opened fds and syslog() |
1125 |
|
* internal state inconsistent. |
1126 |
|
* This was observed to leak file descriptors. */ |
1127 |
|
openlog(applet_name, LOG_PID | LOG_NDELAY, LOG_DAEMON); |
1128 |
logmode = LOGMODE_SYSLOG; |
logmode = LOGMODE_SYSLOG; |
1129 |
} |
} |
1130 |
|
|
1304 |
if (sep->se_builtin) { |
if (sep->se_builtin) { |
1305 |
if (pid) { /* "pid" is -1: we did vfork */ |
if (pid) { /* "pid" is -1: we did vfork */ |
1306 |
close(sep->se_fd); /* listening socket */ |
close(sep->se_fd); /* listening socket */ |
1307 |
logmode = 0; /* make xwrite etc silent */ |
logmode = LOGMODE_NONE; /* make xwrite etc silent */ |
1308 |
} |
} |
1309 |
restore_sigmask(&omask); |
restore_sigmask(&omask); |
1310 |
if (sep->se_socktype == SOCK_STREAM) |
if (sep->se_socktype == SOCK_STREAM) |
1360 |
if (rlim_ofile.rlim_cur != rlim_ofile_cur) |
if (rlim_ofile.rlim_cur != rlim_ofile_cur) |
1361 |
if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) |
if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) |
1362 |
bb_perror_msg("setrlimit"); |
bb_perror_msg("setrlimit"); |
1363 |
closelog(); |
|
1364 |
xmove_fd(ctrl, 0); |
/* closelog(); - WRONG. we are after vfork, |
1365 |
xdup2(0, 1); |
* this may confuse syslog() internal state. |
1366 |
xdup2(0, 2); |
* Let's hope libc sets syslog fd to CLOEXEC... |
1367 |
/* NB: among others, this loop closes listening socket |
*/ |
1368 |
|
xmove_fd(ctrl, STDIN_FILENO); |
1369 |
|
xdup2(STDIN_FILENO, STDOUT_FILENO); |
1370 |
|
/* manpages of inetd I managed to find either say |
1371 |
|
* that stderr is also redirected to the network, |
1372 |
|
* or do not talk about redirection at all (!) */ |
1373 |
|
if (!sep->se_wait) /* only for usual "tcp nowait" */ |
1374 |
|
xdup2(STDIN_FILENO, STDERR_FILENO); |
1375 |
|
/* NB: among others, this loop closes listening sockets |
1376 |
* for nowait stream children */ |
* for nowait stream children */ |
1377 |
for (sep2 = serv_list; sep2; sep2 = sep2->se_next) |
for (sep2 = serv_list; sep2; sep2 = sep2->se_next) |
1378 |
maybe_close(sep2->se_fd); |
if (sep2->se_fd != ctrl) |
1379 |
|
maybe_close(sep2->se_fd); |
1380 |
sigaction_set(SIGPIPE, &saved_pipe_handler); |
sigaction_set(SIGPIPE, &saved_pipe_handler); |
1381 |
restore_sigmask(&omask); |
restore_sigmask(&omask); |
1382 |
BB_EXECVP(sep->se_program, sep->se_argv); |
BB_EXECVP(sep->se_program, sep->se_argv); |
1400 |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO |
1401 |
/* Echo service -- echo data back. */ |
/* Echo service -- echo data back. */ |
1402 |
/* ARGSUSED */ |
/* ARGSUSED */ |
1403 |
static void echo_stream(int s, servtab_t *sep UNUSED_PARAM) |
static void FAST_FUNC echo_stream(int s, servtab_t *sep UNUSED_PARAM) |
1404 |
{ |
{ |
1405 |
#if BB_MMU |
#if BB_MMU |
1406 |
while (1) { |
while (1) { |
1421 |
/* on failure we return to main, which does exit(EXIT_FAILURE) */ |
/* on failure we return to main, which does exit(EXIT_FAILURE) */ |
1422 |
#endif |
#endif |
1423 |
} |
} |
1424 |
static void echo_dg(int s, servtab_t *sep) |
static void FAST_FUNC echo_dg(int s, servtab_t *sep) |
1425 |
{ |
{ |
1426 |
enum { BUFSIZE = 12*1024 }; /* for jumbo sized packets! :) */ |
enum { BUFSIZE = 12*1024 }; /* for jumbo sized packets! :) */ |
1427 |
char *buf = xmalloc(BUFSIZE); /* too big for stack */ |
char *buf = xmalloc(BUFSIZE); /* too big for stack */ |
1441 |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD |
1442 |
/* Discard service -- ignore data. */ |
/* Discard service -- ignore data. */ |
1443 |
/* ARGSUSED */ |
/* ARGSUSED */ |
1444 |
static void discard_stream(int s, servtab_t *sep UNUSED_PARAM) |
static void FAST_FUNC discard_stream(int s, servtab_t *sep UNUSED_PARAM) |
1445 |
{ |
{ |
1446 |
#if BB_MMU |
#if BB_MMU |
1447 |
while (safe_read(s, line, LINE_SIZE) > 0) |
while (safe_read(s, line, LINE_SIZE) > 0) |
1460 |
#endif |
#endif |
1461 |
} |
} |
1462 |
/* ARGSUSED */ |
/* ARGSUSED */ |
1463 |
static void discard_dg(int s, servtab_t *sep UNUSED_PARAM) |
static void FAST_FUNC discard_dg(int s, servtab_t *sep UNUSED_PARAM) |
1464 |
{ |
{ |
1465 |
/* dgram builtins are non-forking - DONT BLOCK! */ |
/* dgram builtins are non-forking - DONT BLOCK! */ |
1466 |
recv(s, line, LINE_SIZE, MSG_DONTWAIT); |
recv(s, line, LINE_SIZE, MSG_DONTWAIT); |
1475 |
int i; |
int i; |
1476 |
|
|
1477 |
end_ring = ring; |
end_ring = ring; |
1478 |
for (i = 0; i <= 128; ++i) |
for (i = ' '; i < 127; i++) |
1479 |
if (isprint(i)) |
*end_ring++ = i; |
|
*end_ring++ = i; |
|
1480 |
} |
} |
1481 |
/* Character generator. MMU arches only. */ |
/* Character generator. MMU arches only. */ |
1482 |
/* ARGSUSED */ |
/* ARGSUSED */ |
1483 |
static void chargen_stream(int s, servtab_t *sep UNUSED_PARAM) |
static void FAST_FUNC chargen_stream(int s, servtab_t *sep UNUSED_PARAM) |
1484 |
{ |
{ |
1485 |
char *rs; |
char *rs; |
1486 |
int len; |
int len; |
1508 |
} |
} |
1509 |
} |
} |
1510 |
/* ARGSUSED */ |
/* ARGSUSED */ |
1511 |
static void chargen_dg(int s, servtab_t *sep) |
static void FAST_FUNC chargen_dg(int s, servtab_t *sep) |
1512 |
{ |
{ |
1513 |
int len; |
int len; |
1514 |
char text[LINESIZ + 2]; |
char text[LINESIZ + 2]; |
1557 |
return htonl((uint32_t)(tv.tv_sec + 2208988800)); |
return htonl((uint32_t)(tv.tv_sec + 2208988800)); |
1558 |
} |
} |
1559 |
/* ARGSUSED */ |
/* ARGSUSED */ |
1560 |
static void machtime_stream(int s, servtab_t *sep UNUSED_PARAM) |
static void FAST_FUNC machtime_stream(int s, servtab_t *sep UNUSED_PARAM) |
1561 |
{ |
{ |
1562 |
uint32_t result; |
uint32_t result; |
1563 |
|
|
1564 |
result = machtime(); |
result = machtime(); |
1565 |
full_write(s, &result, sizeof(result)); |
full_write(s, &result, sizeof(result)); |
1566 |
} |
} |
1567 |
static void machtime_dg(int s, servtab_t *sep) |
static void FAST_FUNC machtime_dg(int s, servtab_t *sep) |
1568 |
{ |
{ |
1569 |
uint32_t result; |
uint32_t result; |
1570 |
len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len); |
len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len); |
1582 |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME |
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME |
1583 |
/* Return human-readable time of day */ |
/* Return human-readable time of day */ |
1584 |
/* ARGSUSED */ |
/* ARGSUSED */ |
1585 |
static void daytime_stream(int s, servtab_t *sep UNUSED_PARAM) |
static void FAST_FUNC daytime_stream(int s, servtab_t *sep UNUSED_PARAM) |
1586 |
{ |
{ |
1587 |
time_t t; |
time_t t; |
1588 |
|
|
1589 |
t = time(NULL); |
t = time(NULL); |
1590 |
fdprintf(s, "%.24s\r\n", ctime(&t)); |
fdprintf(s, "%.24s\r\n", ctime(&t)); |
1591 |
} |
} |
1592 |
static void daytime_dg(int s, servtab_t *sep) |
static void FAST_FUNC daytime_dg(int s, servtab_t *sep) |
1593 |
{ |
{ |
1594 |
time_t t; |
time_t t; |
1595 |
len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len); |
len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len); |