1 /* miniudpserv: something like an inetd for the "make check" target of utftpd */
2 
3 /*
4  * Copyright (C) 1999 Uwe Ohse
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include "config.h"
22 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25 #include <signal.h>
26 #include <fcntl.h>
27 
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <netdb.h>
31 #ifdef HAVE_ARPA_INET_H
32 #include <arpa/inet.h>
33 #endif
34 
35 #include <syslog.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include "uogetopt.h"
41 #include "timselsysdep.h"
42 #include "nonblock.h"
43 #include "str2num.h"
44 #include "uostr.h"
45 #include "uoio.h"
46 #include "cdb.h"
47 #include "sys/wait.h"
48 #include "str_ulong.h"
49 
50 #ifndef errno
51 extern int errno;
52 #endif
53 
54 int peer;
55 int nullfd;
56 
57 static char *argv0;
58 
59 static uogetopt_t myopts[] =
60 {
61 	{0, 0, 0, 0, 0, 0, 0}
62 };
63 
64 static void
usage(void)65 usage(void)
66 {write(2,argv0,strlen(argv0));write(2,": use the --help option for usage infomation\n",47); _exit(1); }
67 
68 static int
eat(int fd)69 eat(int fd)
70 {
71 	char buf[1];
72 	recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) 0, 0);
73 	return 0;
74 }
75 
76 int
main(int argc,char ** argv)77 main (int argc, char **argv)
78 {
79 	unsigned long ul;
80 	fd_set set;
81 	struct sockaddr_in s_in;
82 
83 #ifdef HAVE_LIBEFENCE
84     /* hack around efence :-) */
85 	{int fd,fd2;void *waste;
86 	 if (-1==(fd=open("/dev/null",O_WRONLY))) _exit(1);
87 	 if (-1==(fd2=dup(2))) _exit(1);
88 	 if (-1==(dup2(fd,2))) _exit(1);
89 	 waste=malloc(1);
90 	 if (-1==(dup2(fd2,2))) _exit(1);
91 	 close(fd); close(fd2);
92 	}
93 #endif
94 
95 	argv0 = strrchr (argv[0], '/');
96 	if (!argv0++)
97 		argv0 = argv[0];
98 	nullfd = open ("/dev/null", O_RDWR);
99 	if (nullfd == -1) { syslog (LOG_ERR, "cannot open /dev/null: %s", strerror (errno)); _exit (1); }
100 	uogetopt ("miniudpserv", PACKAGE, VERSION, &argc, argv, uogetopt_out, 0, myopts, "usage: miniudpserv host port program ...");
101 	if (argc<4) usage();
102 
103 	openlog ("miniudpserv", LOG_PID | LOG_NDELAY, LOG_DAEMON);
104 
105 	memset (&s_in, 0, sizeof (s_in));
106 	s_in.sin_family = AF_INET;
107 	if (0 == inet_aton (argv[1], &s_in.sin_addr)) { syslog (LOG_ERR, "%s: not a valid in_addr", argv[1]); _exit (1); }
108 	if (-1 == str2ulong (argv[2], &ul, 0) || ul == 0 || ul > 65535)
109 		{ syslog (LOG_ERR, "%s: not a valid port number", argv[2]); _exit (1); }
110 	s_in.sin_port = htons (((short) ul));
111 
112 	peer = socket (AF_INET, SOCK_DGRAM, 0);
113 	if (peer < 0) { syslog (LOG_ERR, "socket: %s", strerror (errno)); _exit (1); }
114 	if (bind (peer, (struct sockaddr *) &s_in, sizeof (s_in)) < 0) { syslog (LOG_ERR, "bind: %s", strerror (errno)); _exit (1); }
115 
116 	FD_ZERO(&set);
117 	while (1) {
118 		char buf[1];
119 		pid_t pid;
120 		socklen_t len;
121 		len = sizeof(s_in);
122 		FD_SET(peer,&set);
123 		if (-1==select(peer+1,&set,0,0,0)) { syslog(LOG_ERR,"select: %s",strerror(errno)); _exit(1); }
124 #ifdef MSG_PEEK
125 		if (recvfrom(peer, buf, sizeof(buf), MSG_PEEK, (struct sockaddr *) & s_in, &len) < 0) {
126 			/* uh? */
127 			syslog(LOG_WARNING,"recvfrom(MSG_PEEK): %s",strerror(errno));
128 			continue;
129 		}
130 		syslog(LOG_INFO,"packet from %s",inet_ntoa(s_in.sin_addr));
131 #endif
132 		pid=fork();
133 		if (pid==-1) {
134 			syslog(LOG_ERR,"cannot fork: %s",strerror(errno));
135 			eat(peer);
136 		} else if (pid==0) {
137 			/* child */
138 			if (dup2(peer,0) != 0) { syslog(LOG_ERR,"cannot dup2 socket->stdin: %s",strerror(errno)); _exit(1); }
139 			argv+=3;
140 			execvp(*argv,argv);
141 			syslog(LOG_ERR,"execvp %s: %s",*argv,strerror(errno));
142 			eat(peer);
143 			_exit(1);
144 		} else {
145 			waitpid(pid,0,0);
146 		}
147 	}
148 	_exit (0);
149 }
150