1 static  const char rcsid[] = "$Id: main.c,v 1.20 2005/05/04 03:56:40 dengxf Exp $";
2 
3 /*
4  * Copyright (c) 2003-2004 Deng XueFeng <dsnofe@hotmail.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *    This product includes software developed by Deng XueFeng.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY DENG XUEFENG AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <signal.h>
39 #include <syslog.h>
40 #include <stdarg.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <sys/types.h>
46 #include <sys/time.h>
47 #include <sys/wait.h>
48 #include <sys/resource.h>
49 
50 #include "plcat.h"
51 #include "mylog.h"
52 #include "listen.h"
53 #include "pop3d.h"
54 #include "mydaemon.h"
55 #include "cfg.h"
56 #include "sig.h"
57 
58 static int quit_flag = 0;
59 
60 static char config_file[] = "/usr/local/etc/mps/pop3d.conf";
61 static char pid_file[] = "/var/run/mps.pid";
62 static int *pop3dpid = NULL;
63 
64 int pop3d_port = 110;
65 int max_errs = 5;
66 int multi_process = 5;
67 int max_backlog = 32;
68 int max_client = 1000;
69 int max_timeout = 10 * 1000;
70 char serv_ip[16] = "";
71 
72 int debug_flag = 0;
73 int pop3d_fd = 0;
74 int cur_process = 0;
75 
76 extern int errno;
77 
close_child(void)78 static void close_child(void)
79 {
80     kill(0, SIGINT);
81 }
82 
sig_stop_handler(int signo)83 static void sig_stop_handler(int signo)
84 {
85     quit_flag = 1;
86     INFO("[INFO]: Received SIG%s and EXIT\n", sigs[signo-1]);
87     close_child();
88 }
89 
sig_exit_handler(int signo)90 static void sig_exit_handler(int signo)
91 {
92     INFO("[INFO]: Received SIG%s and EXIT\n", sigs[signo-1]);
93     exit(EXIT_FAILURE);
94 }
95 
sig_handler(int signo)96 static void sig_handler(int signo)
97 {
98     INFO("[INFO]: Received SIG%s\n", sigs[signo-1]);
99 }
100 
pop3d_child(int id)101 static int pop3d_child(int id)
102 {
103     int pid;
104 
105     pid = fork();
106     if (pid < 0) {
107         INFO("[INFO]: fork(2) Failed first time: %s", strerror(errno));
108         return (0);
109     } else if (pid == 0) {
110         signal(SIGINT, sig_exit_handler);
111         sleep(1);
112         pop3d(id);
113         return (1);
114     } else {
115         pop3dpid[id] = pid;
116         cur_process++;
117         return (1);
118     }
119 }
120 
get_id(int pid)121 static int get_id(int pid)
122 {
123     int i;
124 
125     i = 0;
126     while (i < multi_process) {
127         if (pop3dpid[i] == pid)
128             return (i);
129         i++;
130     }
131     INFO("[EXIT]: get_pid: failed get pid: %d\n", pid);
132     close_child();
133     return (multi_process);
134 }
135 
sig_chld_handler(int signo)136 void sig_chld_handler(int signo)
137 {
138     int id;
139     pid_t pid;
140 
141     INFO("[INFO]: Received SIG%s\n", sigs[signo-1]);
142     while((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
143         cur_process--;
144         if ((quit_flag == 0) && (debug_flag == 0)) {
145             id = get_id(pid);
146             pop3d_child(id);
147         }
148     }
149 }
150 
parse_conf(const char * cfg_file)151 static int parse_conf(const char *cfg_file)
152 {
153     char *value;
154 
155     if (init_conf(cfg_file) != 0)
156         return (-1);
157     if ((value = get_conf("Client_Max_Errors")) != NULL)
158         max_errs = atoi(value);
159     if ((value = get_conf("Client_Time_Out")) != NULL)
160         max_timeout = 1000 * atoi(value);
161     if ((value = get_conf("Per_Process_Max_Client")) != NULL)
162         max_client = atoi(value);
163     if ((value = get_conf("Multi_Process")) != NULL)
164         multi_process = atoi(value);
165     if ((value = get_conf("Max_Backlog")) != NULL)
166         max_backlog = atoi(value);
167     if ((value = get_conf("Server_Port")) != NULL)
168         pop3d_port = atoi(value);
169     if ((value = get_conf("Server_Address")) != NULL)
170         strncpy(serv_ip, value, sizeof(serv_ip));
171     if ((value = get_conf("Pid_File")) != NULL)
172         strncpy(pid_file, value, sizeof(pid_file));
173     close_conf();
174     return (0);
175 }
176 
delpid(void)177 static void delpid(void)
178 {
179     unlink(pid_file);
180 }
181 
savepid(void)182 static int savepid(void)
183 {
184     int fd;
185     int pid;
186     char str[12];
187 
188     fd = open(pid_file, O_WRONLY|O_CREAT|O_TRUNC, 0644);
189     if (fd < 0)
190         return (errno);
191     pid = getpid();
192     sprintf(str, "%d\n", pid);
193     if (write(fd, str, strlen(str)) != (int)strlen(str)) {
194         pid = errno;
195         close(fd);
196         return (pid);
197     }
198     close(fd);
199     return (0);
200 }
201 
checkpid(void)202 static int checkpid(void)
203 {
204     int fd;
205     int res;
206     int pid;
207     char str[12];
208 
209     fd = open(pid_file, O_RDONLY);
210     if (fd < 0)
211         return (-1);
212     if ((res = read(fd, str, sizeof(str))) <= 0) {
213         close(fd);
214         return (-1);
215     }
216     close(fd);
217     str[res - 1] = 0x00;
218     pid = atoi(str);
219     res = kill(pid, 0);
220     if (res != 0) {
221         INFO("[-ERR]: kill(2) Failed: %s\n", strerror(errno));
222         return (-1);
223     }
224     return (pid);
225 }
226 
myexit(void)227 static void myexit(void)
228 {
229     int res;
230 
231     res = checkpid();
232     if (res > 0) {
233         kill(res, SIGUSR1);
234         printf("[INFO] POP3D IS STOPPED\n");
235     } else
236         printf("[INFO] POP3D IS NOT RUNNING\n");
237 }
238 
usage(void)239 static void usage(void)
240 {
241     printf("Usage: mps [-c configfile] [-d] [-q]\n");
242     printf("       -c   Specified configfile, default is /usr/local/etc/mps/pop3d.conf\n");
243     printf("       -d   Debug Mod\n");
244     printf("       -q   Quit\n");
245     exit(EXIT_FAILURE);
246 }
247 
main(int argc,char ** argv)248 int main(int argc, char **argv)
249 {
250     char opt;
251     char cfg_file[256];
252     int err;
253     int i;
254 
255     (void) memset(cfg_file, 0, sizeof(config_file));
256     while ((opt = getopt(argc, argv, "c:dq")) != -1) {
257         switch(opt) {
258             case 'c':
259                 strlcpy(cfg_file, optarg, sizeof(cfg_file));
260                 cfg_file[255] = '\0';
261                 break;
262             case 'd':
263                 debug_flag = 1;
264                 break;
265             case 'q':
266                 quit_flag = 1;
267                 break;
268             default :
269                 usage();
270         }
271     }
272     if (cfg_file[0] == '\0')
273         strlcpy(cfg_file, config_file, sizeof(cfg_file));
274     if (parse_conf(cfg_file) != 0)
275         usage();
276     if (quit_flag == 1) {
277         myexit();
278         exit(EXIT_SUCCESS);
279     }
280     if (checkpid() > 0) {
281         printf("[INFO] POP3D IS RUNNING NOW\n");
282         exit(EXIT_SUCCESS);
283     }
284     if (atexit(delpid) != 0) {
285         INFO("[INFO]: Register delpid Failed: %s\n", strerror(errno));
286         exit(EXIT_SUCCESS);
287     }
288     delpid();
289     if (debug_flag == 1)
290         multi_process = 1;
291     else
292         mydaemon();
293     if ((i = savepid()) != 0) {
294         INFO("[INFO]: savepid() Failed: %s\n", strerror(i));
295         exit(EXIT_FAILURE);
296     } else
297         INFO("[INFO]: savepid() Successful\n");
298 
299     pop3dpid = malloc((multi_process+1) * sizeof(int));
300     if (pop3dpid == NULL) {
301         INFO("[-ERR]: malloc(3): %s\n", strerror(errno));
302         exit(EXIT_FAILURE);
303     }
304     memset(pop3dpid, 0, (multi_process+1) * sizeof(int));
305 
306     pop3d_fd = newlisten(&err, serv_ip, pop3d_port, 10, max_backlog);
307     switch (pop3d_fd) {
308         case ERROR_PORT:
309             INFO("-ERR INVALID PORT: [%d].\n", pop3d_port);
310             exit(EXIT_FAILURE);
311         case ERROR_IP:
312             INFO("-ERR INVALID IP ADDRESS: [%s].\n", serv_ip);
313             exit(EXIT_FAILURE);
314         case ERROR_SOCKET:
315             INFO("-ERR CREATE SOCKET FAILED: [%s].\n", strerror(err));
316             exit(EXIT_FAILURE);
317         case ERROR_REUSE:
318             INFO("-ERR SETSOCKOPT REUSEADDR FAILED: [%s].\n", strerror(err));
319             exit(EXIT_FAILURE);
320         case ERROR_LINGER:
321             INFO("-ERR SETSOCKOPT LINGER FAILED: [%s].\n", strerror(err));
322             exit(EXIT_FAILURE);
323         case ERROR_BIND:
324             INFO("-ERR BIND SOCKET FAILED: [%s].\n", strerror(err));
325             exit(EXIT_FAILURE);
326         case ERROR_LISTEN:
327             INFO("-ERR LISTEN SOCKET FAILED: [%s].\n", strerror(err));
328             exit(EXIT_FAILURE);
329         default:
330             break;
331     }
332     signal(SIGILL, sig_exit_handler);
333     signal(SIGABRT, sig_exit_handler);
334     signal(SIGFPE, sig_exit_handler);
335     signal(SIGBUS, sig_exit_handler);
336     signal(SIGPIPE, sig_handler);
337     signal(SIGTERM, sig_stop_handler);
338     signal(SIGQUIT, sig_stop_handler);
339     signal(SIGINT, sig_handler);
340     signal(SIGUSR1, sig_stop_handler);
341     signal(SIGUSR2, sig_stop_handler);
342     signal(SIGCHLD, sig_chld_handler);
343     if (debug_flag == 1) {
344         signal(SIGTERM, sig_exit_handler);
345         signal(SIGQUIT, sig_exit_handler);
346         signal(SIGINT, sig_exit_handler);
347         signal(SIGUSR1, sig_exit_handler);
348         signal(SIGUSR2, sig_exit_handler);
349         pop3d(0);
350         return (0);
351     }
352 
353     i = 0;
354     while (i < multi_process) {
355         if (pop3d_child(i) == 0) {
356             close_child();
357             goto WAIT_TO_EXIT;
358         }
359         i++;
360     }
361 WAIT_TO_EXIT:
362     while(1) {
363         sleep(30);
364         if (cur_process == 0)
365             break;
366     }
367     close(pop3d_fd);
368     INFO("EXIT SUCCESSFUL\n");
369     return (0);
370 }
371