Use gcore for creating core dump on segfault
[capablanca.git] / lasker-2.2.3 / src / ficsmain.c
1 /*
2    Copyright (c) 1993 Richard V. Nash.
3    Copyright (c) 2000 Dan Papasian
4    Copyright (C) Andrew Tridgell 2002
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 /*
22   ficsmain.c is a minimal wrapper around chessd.so. By keeping this module to a
23   minimum size we can reload nearly all the chess server functionality on a 'areload'
24   command. 
25 */
26
27
28 #include "includes.h"
29
30 /* handle used to talk to chessd.so */
31 static void *chessd_so_handle;
32
33 static void usage();
34 static void main_event_loop(void);
35
36 unsigned chessd_reload_flag;
37
38 /* 
39    load a function from chessd.so 
40    this is the core of the runtime reload functionality
41 */
42 static void *chessd_function(const char *name)
43 {
44         void *sym;
45
46         if (!chessd_so_handle) {
47                 chessd_so_handle = dlopen(LIB_DIR "/chessd.so", RTLD_LAZY);
48                 if (!chessd_so_handle) {
49                         fprintf(stderr, "CHESSD: Failed to load chessd.so !! (%s)\n",
50                                 dlerror());
51                         exit(1);
52                 }
53         }
54
55         sym = dlsym(chessd_so_handle, name);
56         if (!sym) {
57                 fprintf(stderr, "CHESSD: Failed to find symbol %s in chessd.so !!\n",
58                         name);
59                 exit(1);
60         }
61
62         return sym;
63 }
64
65
66 static void usage()
67 {
68         fprintf(stderr,  "Usage: chessd -p port [-f] [-T timeseal_decoder] [-R rootdir]\n");
69         fprintf(stderr,  "PORT_NUMBER is 5000 by default\n");
70         exit(1);
71 }
72
73 static int daemonize(void)
74 {
75         pid_t pid;
76         if ((pid = fork()) == -1) 
77                 return -1;
78         else if (pid != 0)
79                 exit(0);
80         if (setsid() == -1)
81                 return -1;
82         return 0;
83 }
84
85 static void main_event_loop(void) 
86 {
87         void (*select_loop)(void ) = chessd_function("select_loop");
88
89         while (1) {
90                 select_loop();
91
92                 /* check the reload flag */
93                 if (chessd_reload_flag) {
94                         void (*reload_close)(void ) = chessd_function("reload_close");
95                         void (*reload_open)(void );
96
97                         chessd_reload_flag = 0;
98
99                         fprintf(stderr, "CHESSD: Reloading server code!\n");
100
101                         /* free up local vars */
102                         reload_close();
103
104                         /* close the handle to the shared lib */
105                         dlclose(chessd_so_handle);
106                         chessd_so_handle = NULL;
107
108                         /* re-initialise local variables */
109                         reload_open = chessd_function("reload_open");
110                         reload_open();
111                         select_loop = chessd_function("select_loop");
112                 }
113         }
114 }
115
116 static void TerminateServer(int sig)
117 {
118         void (*output_shut_mess)(void ) = chessd_function("output_shut_mess");
119         void (*TerminateCleanup)(void ) = chessd_function("TerminateCleanup");
120         void (*net_close)(void ) = chessd_function("net_close");
121
122         fprintf(stderr,  "CHESSD: Received signal %d\n", sig);
123         output_shut_mess();
124         TerminateCleanup();
125         net_close();
126         exit(1);
127 }
128
129 static void BrokenPipe(int sig)
130 {
131         signal(SIGPIPE, BrokenPipe);
132         fprintf(stderr,  "CHESSD: Pipe signal\n");
133 }
134
135
136 /* this assumes we are setuid root to start */
137 static void do_chroot(const char *dir)
138 {
139         int i;
140         uid_t uid = getuid();
141         uid_t euid = geteuid();
142         struct rlimit rlp;
143
144         if (euid != 0 || setuid(0) != 0) {
145                 fprintf(stderr, "Must be setuid root to use -R\n");
146                 exit(1);
147         }
148         if (chroot(dir) != 0 || chdir("/") != 0) {
149                 perror("chroot");
150                 exit(1);
151         }
152         if (setuid(uid) != 0) {
153                 perror("setuid");
154                 exit(1);
155         }
156
157         /* close all extraneous file descriptors */
158         for (i=0;i<3;i++) close(i);
159         open("stdin.log", O_RDWR|O_CREAT|O_TRUNC, 0644);
160         open("stdout.log", O_WRONLY|O_CREAT|O_TRUNC, 0644);
161         open("stderr.log", O_WRONLY|O_CREAT|O_TRUNC, 0644);
162
163         /* reestabish core limits */
164         getrlimit(RLIMIT_CORE, &rlp );
165         rlp.rlim_cur = MAX(64*1024*1024, rlp.rlim_max);
166         setrlimit( RLIMIT_CORE, &rlp );
167 }
168
169 /*
170   give a decent backtrace on segv
171 */
172 static void segv_handler(int sig)
173 {
174         char cmd[100];
175         snprintf(cmd, sizeof(cmd), "gcore -o /home/mics/chessd/core %d", (int)getpid());
176         system(cmd);
177         _exit(1);
178 }
179
180 int main(int argc, char *argv[])
181 {
182         int i, foreground, port;
183         void (*timeseal_init)(const char * ) = chessd_function("timeseal_init");
184         int (*net_init)(int ) = chessd_function("net_init");
185         void (*initial_load)(void ) = chessd_function("initial_load");
186
187         port = DEFAULT_PORT;
188         foreground = 0;
189
190         /* enable malloc checking in libc */
191         setenv("MALLOC_CHECK_", "2", 1);
192         
193         while((i = getopt(argc, argv, "p:fR:T:")) != -1) {
194                 switch(i) {
195                 case 'p':
196                         port = atoi(optarg);
197                         break;
198                 case 'f':
199                         foreground = 1;
200                         break;
201                 case 'T':
202                         timeseal_init(optarg);
203                         break;
204                 case 'R':
205                         do_chroot(optarg);
206                         break;
207                 default:
208                         usage();
209                 }
210         }
211    
212         if (!foreground && daemonize()){
213                 printf("Problem with Daemonization - Aborting\n");
214                 exit(1);
215         }  
216
217         signal(SIGTERM, TerminateServer);
218         signal(SIGSEGV, segv_handler);
219         signal(SIGBUS, segv_handler);
220         signal(SIGINT, TerminateServer);
221         signal(SIGPIPE, BrokenPipe);
222
223         if (net_init(port)) {
224                 fprintf(stderr, "CHESSD: Network initialize failed on port %d.\n", port);
225                 exit(1);
226         }
227         fprintf(stderr,  "CHESSD: Initialized on port %d\n", port);
228
229         initial_load();
230         
231         main_event_loop();
232         /* will never get here - uses TerminateServer */
233         
234         return 0;
235 }