Code:
$ cat mysrc/u_inetd.c
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <signal.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#define P_EEXIT fprintf(stderr,"Abnormal exit at %s:%d\n",__FILE__,__LINE__),exit(1)
int main( int argc, char **argv ){
int i, s, ns, loa, t_on = 1, ka = 10, only1 = 0, maxbuf=65535 ;
union {
struct sockaddr sa ;
struct sockaddr_in sin ;
} u ;
struct sigaction siga ;
u.sin.sin_port = 0 ;
u.sin.sin_addr.s_addr = INADDR_ANY ;
for ( i = 1 ; i < argc ; i++ ){
if ( !strcmp( argv[i], "-l" )){
u.sin.sin_addr.s_addr = INADDR_LOOPBACK ;
} else if ( !strcmp( argv[i], "-o" )){
only1 = 1 ;
} else if ( u.sin.sin_port == 0 ){
if ( 1 > atoi( argv[i] )){
break ;
}
u.sin.sin_port = atoi( argv[i] );
}
else /* must be command */
break ;
}
if ( u.sin.sin_port == 0
|| i == argc ){
printf(
"Usage: %s [ -l ] [ -o ] <port> <cmd> [<cmd args>]\n"
"\n"
"Listens on port for tcp connections, and for every connection,\n"
" runs <cmd> with any <cmd args>\n"
" and with the socket as stdin and stdout (but stderr is preserved)\n"
" under the user's id. (Be careful!)\n"
"\n"
"The -l option restricts connections to clients on the same host\n"
" for greater security.\n"
"The -o option restricts the server to only one (1) service at a time\n"
" for commands that need exclusive control of a resource,\n"
" by waiting for child termination. This can result in a hung server.\n"
"The <cmd> must be exec() compatible, so if it is not a sh shell script,\n"
" make sure to have '#!<full_path_of_interpreter> [ <one_arg> ]' as line 1.\n"
"\n",
argv[0] );
exit( 1 );
}
/* ensure that no fd's are open that are not needed,
as sh does not allow >&## */
for ( s = 0 ; s < 128 ; s++ ){
if ( s != 2 )
close( s );
}
if ( 0 > ( s = socket( PF_INET, SOCK_STREAM, NULL ))){
perror( "socket( PF_INET, SOCK_STREAM, NULL )" );
P_EEXIT ;
}
u.sin.sin_family = AF_INET ;
if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY, (char *)&t_on, sizeof(int))){
perror( "setsockopt( s, IPPROTO_TCP, TCP_NODELAY, (char *)&t_on, sizeof(int))" );
P_EEXIT ;
}
if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&t_on,
sizeof(int))){
perror( "setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&t_on, sizeof(int) )" );
P_EEXIT ;
}
if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (char*)&ka,
sizeof(int))){
perror( "setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (char*)&ka, sizeof(int) )" );
P_EEXIT ;
}
if ( setsockopt( s, SOL_SOCKET, SO_RCVBUF, (char *)&maxbuf, sizeof(int))){
perror( "setsockopt( s, IPPROTO_TCP, SO_RCVBUF, (char *)&maxbuf, sizeof(int))" );
P_EEXIT ;
}
if ( setsockopt( s, SOL_SOCKET, SO_SNDBUF, (char *)&maxbuf, sizeof(int))){
perror( "setsockopt( s, IPPROTO_TCP, SO_SNDBUF, (char *)&maxbuf, sizeof(int))" );
P_EEXIT ;
}
if ( bind( s, &u.sa, sizeof(u.sa))){
perror( "bind()" );
P_EEXIT ;
}
if ( listen( s, 256 )){
perror( "listen( s, 256 )" );
P_EEXIT ;
}
siga.sa_handler = NULL ;
sigemptyset( &siga.sa_mask );
siga.sa_flags = SA_NOCLDWAIT ;
sigaction( SIGCHLD, &siga, NULL );
next:
loa = sizeof(u.sa);
if ( 0 > ( ns = accept( s, &u.sa, &loa ))){
if ( errno == EINTR
|| errno == EAGAIN ){
goto next ;
}
perror( "accept( s, &u.sa, sizeof(u.sa) )" );
P_EEXIT ;
}
refork:
switch ( fork()){
case -1 :
sleep( 1 );
goto refork ;
case 0 :
break ;
default: /* Parent */
close( ns );
if ( only1 ){
do {
wait( NULL );
} while ( errno != ECHILD );
}
goto next ;
}
/* child */
close(s);
do {
s = dup(ns);
} while ( s < 1 && s >= 0 );
if ( ns > 2 ){
close(ns);
}
execvp( argv[i], argv + i );
/* should never get here */
perror( "execvp( argv[i], argv + i )" );
P_EEXIT ;
}