1 /**
2 * Copyright (C) 2008 Happy Fish / YuQing
3 *
4 * FastDFS may be copied only under the terms of the GNU General
5 * Public License V3, which may be found in the FastDFS source kit.
6 * Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
7 **/
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <signal.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <pthread.h>
23 #include "fastcommon/shared_func.h"
24 #include "fastcommon/pthread_func.h"
25 #include "fastcommon/process_ctrl.h"
26 #include "fastcommon/logger.h"
27 #include "fdfs_global.h"
28 #include "fastcommon/base64.h"
29 #include "fastcommon/sockopt.h"
30 #include "fastcommon/sched_thread.h"
31 #include "tracker_types.h"
32 #include "tracker_mem.h"
33 #include "tracker_service.h"
34 #include "tracker_global.h"
35 #include "tracker_proto.h"
36 #include "tracker_func.h"
37 #include "tracker_status.h"
38 #include "tracker_relationship.h"
39 
40 #ifdef WITH_HTTPD
41 #include "tracker_httpd.h"
42 #include "tracker_http_check.h"
43 #endif
44 
45 #if defined(DEBUG_FLAG)
46 #include "tracker_dump.h"
47 #endif
48 
49 static bool bTerminateFlag = false;
50 static bool bAcceptEndFlag = false;
51 
52 static char bind_addr[IP_ADDRESS_SIZE];
53 
54 static void sigQuitHandler(int sig);
55 static void sigHupHandler(int sig);
56 static void sigUsrHandler(int sig);
57 static void sigAlarmHandler(int sig);
58 
59 #if defined(DEBUG_FLAG)
60 /*
61 #if defined(OS_LINUX)
62 static void sigSegvHandler(int signum, siginfo_t *info, void *ptr);
63 #endif
64 */
65 
66 static void sigDumpHandler(int sig);
67 #endif
68 
69 #define SCHEDULE_ENTRIES_COUNT 5
70 
usage(const char * program)71 static void usage(const char *program)
72 {
73 	fprintf(stderr, "FastDFS server v%d.%02d\n"
74             "Usage: %s <config_file> [start | stop | restart]\n",
75             g_fdfs_version.major, g_fdfs_version.minor,
76             program);
77 }
78 
main(int argc,char * argv[])79 int main(int argc, char *argv[])
80 {
81 	char *conf_filename;
82 	int result;
83 	int wait_count;
84 	int sock;
85 	pthread_t schedule_tid;
86 	struct sigaction act;
87 	ScheduleEntry scheduleEntries[SCHEDULE_ENTRIES_COUNT];
88 	ScheduleArray scheduleArray;
89 	char pidFilename[MAX_PATH_SIZE];
90 	bool stop;
91 
92 	if (argc < 2)
93 	{
94 		usage(argv[0]);
95 		return 1;
96 	}
97 
98 	g_current_time = time(NULL);
99 	g_up_time = g_current_time;
100 	srand(g_up_time);
101 
102 	log_init2();
103 
104 	conf_filename = argv[1];
105     if (!fileExists(conf_filename))
106     {
107         if (starts_with(conf_filename, "-"))
108         {
109             usage(argv[0]);
110             return 0;
111         }
112     }
113 	if ((result=get_base_path_from_conf_file(conf_filename,
114 		g_fdfs_base_path, sizeof(g_fdfs_base_path))) != 0)
115 	{
116 		log_destroy();
117 		return result;
118 	}
119 
120 	snprintf(pidFilename, sizeof(pidFilename),
121 		"%s/data/fdfs_trackerd.pid", g_fdfs_base_path);
122 	if ((result=process_action(pidFilename, argv[2], &stop)) != 0)
123 	{
124 		if (result == EINVAL)
125 		{
126 			usage(argv[0]);
127 		}
128 		log_destroy();
129 		return result;
130 	}
131 	if (stop)
132 	{
133 		log_destroy();
134 		return 0;
135 	}
136 
137 #if defined(DEBUG_FLAG) && defined(OS_LINUX)
138 	if (getExeAbsoluteFilename(argv[0], g_exe_name, \
139 		sizeof(g_exe_name)) == NULL)
140 	{
141 		logCrit("exit abnormally!\n");
142 		log_destroy();
143 		return errno != 0 ? errno : ENOENT;
144 	}
145 #endif
146 
147 	memset(bind_addr, 0, sizeof(bind_addr));
148 	if ((result=tracker_load_from_conf_file(conf_filename, \
149 			bind_addr, sizeof(bind_addr))) != 0)
150 	{
151 		logCrit("exit abnormally!\n");
152 		log_destroy();
153 		return result;
154 	}
155 
156 	if ((result=tracker_load_status_from_file(&g_tracker_last_status)) != 0)
157 	{
158 		logCrit("exit abnormally!\n");
159 		log_destroy();
160 		return result;
161 	}
162 
163 	base64_init_ex(&g_base64_context, 0, '-', '_', '.');
164 	if ((result=set_rand_seed()) != 0)
165 	{
166 		logCrit("file: "__FILE__", line: %d, " \
167 			"set_rand_seed fail, program exit!", __LINE__);
168 		return result;
169 	}
170 
171 	if ((result=tracker_mem_init()) != 0)
172 	{
173 		logCrit("exit abnormally!\n");
174 		log_destroy();
175 		return result;
176 	}
177 
178 	sock = socketServer(bind_addr, g_server_port, &result);
179 	if (sock < 0)
180 	{
181 		logCrit("exit abnormally!\n");
182 		log_destroy();
183 		return result;
184 	}
185 
186 	if ((result=tcpsetserveropt(sock, g_fdfs_network_timeout)) != 0)
187 	{
188 		logCrit("exit abnormally!\n");
189 		log_destroy();
190 		return result;
191 	}
192 
193 	daemon_init(false);
194 	umask(0);
195 
196 	if ((result=write_to_pid_file(pidFilename)) != 0)
197 	{
198 		log_destroy();
199 		return result;
200 	}
201 
202 	if ((result=tracker_service_init()) != 0)
203 	{
204 		logCrit("exit abnormally!\n");
205 		log_destroy();
206 		return result;
207 	}
208 
209 	memset(&act, 0, sizeof(act));
210 	sigemptyset(&act.sa_mask);
211 
212 	act.sa_handler = sigUsrHandler;
213 	if(sigaction(SIGUSR1, &act, NULL) < 0 || \
214 		sigaction(SIGUSR2, &act, NULL) < 0)
215 	{
216 		logCrit("file: "__FILE__", line: %d, " \
217 			"call sigaction fail, errno: %d, error info: %s", \
218 			__LINE__, errno, STRERROR(errno));
219 		logCrit("exit abnormally!\n");
220 		return errno;
221 	}
222 
223 	act.sa_handler = sigHupHandler;
224 	if(sigaction(SIGHUP, &act, NULL) < 0)
225 	{
226 		logCrit("file: "__FILE__", line: %d, " \
227 			"call sigaction fail, errno: %d, error info: %s", \
228 			__LINE__, errno, STRERROR(errno));
229 		logCrit("exit abnormally!\n");
230 		return errno;
231 	}
232 
233 	act.sa_handler = SIG_IGN;
234 	if(sigaction(SIGPIPE, &act, NULL) < 0)
235 	{
236 		logCrit("file: "__FILE__", line: %d, " \
237 			"call sigaction fail, errno: %d, error info: %s", \
238 			__LINE__, errno, STRERROR(errno));
239 		logCrit("exit abnormally!\n");
240 		return errno;
241 	}
242 
243 	act.sa_handler = sigQuitHandler;
244 	if(sigaction(SIGINT, &act, NULL) < 0 || \
245 		sigaction(SIGTERM, &act, NULL) < 0 || \
246 		sigaction(SIGQUIT, &act, NULL) < 0)
247 	{
248 		logCrit("file: "__FILE__", line: %d, " \
249 			"call sigaction fail, errno: %d, error info: %s", \
250 			__LINE__, errno, STRERROR(errno));
251 		logCrit("exit abnormally!\n");
252 		return errno;
253 	}
254 
255 #if defined(DEBUG_FLAG)
256 /*
257 #if defined(OS_LINUX)
258 	memset(&act, 0, sizeof(act));
259 	sigemptyset(&act.sa_mask);
260         act.sa_sigaction = sigSegvHandler;
261         act.sa_flags = SA_SIGINFO;
262         if (sigaction(SIGSEGV, &act, NULL) < 0 || \
263         	sigaction(SIGABRT, &act, NULL) < 0)
264 	{
265 		logCrit("file: "__FILE__", line: %d, " \
266 			"call sigaction fail, errno: %d, error info: %s", \
267 			__LINE__, errno, STRERROR(errno));
268 		logCrit("exit abnormally!\n");
269 		return errno;
270 	}
271 #endif
272 */
273 
274 	memset(&act, 0, sizeof(act));
275 	sigemptyset(&act.sa_mask);
276 	act.sa_handler = sigDumpHandler;
277 	if(sigaction(SIGUSR1, &act, NULL) < 0 || \
278 		sigaction(SIGUSR2, &act, NULL) < 0)
279 	{
280 		logCrit("file: "__FILE__", line: %d, " \
281 			"call sigaction fail, errno: %d, error info: %s", \
282 			__LINE__, errno, STRERROR(errno));
283 		logCrit("exit abnormally!\n");
284 		return errno;
285 	}
286 #endif
287 
288 #ifdef WITH_HTTPD
289 	if (!g_http_params.disabled)
290 	{
291 		if ((result=tracker_httpd_start(bind_addr)) != 0)
292 		{
293 			logCrit("file: "__FILE__", line: %d, " \
294 				"tracker_httpd_start fail, program exit!", \
295 				__LINE__);
296 			return result;
297 		}
298 
299 	}
300 
301 	if ((result=tracker_http_check_start()) != 0)
302 	{
303 		logCrit("file: "__FILE__", line: %d, " \
304 			"tracker_http_check_start fail, " \
305 			"program exit!", __LINE__);
306 		return result;
307 	}
308 #endif
309 
310 	if ((result=set_run_by(g_run_by_group, g_run_by_user)) != 0)
311 	{
312 		logCrit("exit abnormally!\n");
313 		log_destroy();
314 		return result;
315 	}
316 
317 	scheduleArray.entries = scheduleEntries;
318 	scheduleArray.count = 0;
319 	memset(scheduleEntries, 0, sizeof(scheduleEntries));
320 
321 	INIT_SCHEDULE_ENTRY(scheduleEntries[scheduleArray.count],
322 		scheduleArray.count + 1, TIME_NONE, TIME_NONE, TIME_NONE,
323 		g_sync_log_buff_interval, log_sync_func, &g_log_context);
324 	scheduleArray.count++;
325 
326 	INIT_SCHEDULE_ENTRY(scheduleEntries[scheduleArray.count],
327 		scheduleArray.count + 1, TIME_NONE, TIME_NONE, TIME_NONE,
328 		g_check_active_interval, tracker_mem_check_alive, NULL);
329 	scheduleArray.count++;
330 
331 	INIT_SCHEDULE_ENTRY(scheduleEntries[scheduleArray.count],
332 		scheduleArray.count + 1, 0, 0, 0,
333 		TRACKER_SYNC_STATUS_FILE_INTERVAL,
334 		tracker_write_status_to_file, NULL);
335 	scheduleArray.count++;
336 
337 	if (g_rotate_error_log)
338 	{
339 		INIT_SCHEDULE_ENTRY_EX(scheduleEntries[scheduleArray.count],
340 			scheduleArray.count + 1, g_error_log_rotate_time,
341 			24 * 3600, log_notify_rotate, &g_log_context);
342 		scheduleArray.count++;
343 
344 		if (g_log_file_keep_days > 0)
345 		{
346 			log_set_keep_days(&g_log_context, g_log_file_keep_days);
347 
348 			INIT_SCHEDULE_ENTRY(scheduleEntries[scheduleArray.count],
349 				scheduleArray.count + 1, 1, 0, 0, 24 * 3600,
350 				log_delete_old_files, &g_log_context);
351 			scheduleArray.count++;
352 		}
353 	}
354 
355 	if ((result=sched_start(&scheduleArray, &schedule_tid, \
356 		g_thread_stack_size, (bool * volatile)&g_continue_flag)) != 0)
357 	{
358 		logCrit("exit abnormally!\n");
359 		log_destroy();
360 		return result;
361 	}
362 
363 	if ((result=tracker_relationship_init()) != 0)
364 	{
365 		logCrit("exit abnormally!\n");
366 		log_destroy();
367 		return result;
368 	}
369 
370 	log_set_cache(true);
371 
372 	bTerminateFlag = false;
373 	bAcceptEndFlag = false;
374 
375 	tracker_accept_loop(sock);
376 	bAcceptEndFlag = true;
377 	if (g_schedule_flag)
378 	{
379 		pthread_kill(schedule_tid, SIGINT);
380 	}
381 	tracker_terminate_threads();
382 
383 #ifdef WITH_HTTPD
384 	if (g_http_check_flag)
385 	{
386 		tracker_http_check_stop();
387 	}
388 
389 	while (g_http_check_flag)
390 	{
391 		usleep(50000);
392 	}
393 #endif
394 
395 	wait_count = 0;
396 	while ((g_tracker_thread_count != 0) || g_schedule_flag)
397 	{
398 
399 /*
400 #if defined(DEBUG_FLAG) && defined(OS_LINUX)
401 		if (bSegmentFault)
402 		{
403 			sleep(5);
404 			break;
405 		}
406 #endif
407 */
408 
409 		usleep(10000);
410 		if (++wait_count > 3000)
411 		{
412 			logWarning("waiting timeout, exit!");
413 			break;
414 		}
415 	}
416 
417 	tracker_mem_destroy();
418 	tracker_service_destroy();
419 	tracker_relationship_destroy();
420 
421 	logInfo("exit normally.\n");
422 	log_destroy();
423 
424 	delete_pid_file(pidFilename);
425 	return 0;
426 }
427 
428 #if defined(DEBUG_FLAG)
sigDumpHandler(int sig)429 static void sigDumpHandler(int sig)
430 {
431 	static bool bDumpFlag = false;
432 	char filename[256];
433 
434 	if (bDumpFlag)
435 	{
436 		return;
437 	}
438 
439 	bDumpFlag = true;
440 
441 	snprintf(filename, sizeof(filename),
442 		"%s/logs/tracker_dump.log", g_fdfs_base_path);
443 	fdfs_dump_tracker_global_vars_to_file(filename);
444 
445 	bDumpFlag = false;
446 }
447 
448 #endif
449 
sigQuitHandler(int sig)450 static void sigQuitHandler(int sig)
451 {
452 	if (!bTerminateFlag)
453 	{
454         tcp_set_try_again_when_interrupt(false);
455 		set_timer(1, 1, sigAlarmHandler);
456 
457 		bTerminateFlag = true;
458 		g_continue_flag = false;
459 		logCrit("file: "__FILE__", line: %d, " \
460 			"catch signal %d, program exiting...", \
461 			__LINE__, sig);
462 	}
463 }
464 
sigHupHandler(int sig)465 static void sigHupHandler(int sig)
466 {
467 	if (g_rotate_error_log)
468 	{
469 		g_log_context.rotate_immediately = true;
470 	}
471 
472 	logInfo("file: "__FILE__", line: %d, " \
473 		"catch signal %d, rotate log", __LINE__, sig);
474 }
475 
sigAlarmHandler(int sig)476 static void sigAlarmHandler(int sig)
477 {
478 	ConnectionInfo server;
479 
480 	if (bAcceptEndFlag)
481 	{
482 		return;
483 	}
484 
485 	logDebug("file: "__FILE__", line: %d, " \
486 		"signal server to quit...", __LINE__);
487 
488 	if (*bind_addr != '\0')
489 	{
490 		strcpy(server.ip_addr, bind_addr);
491 	}
492 	else
493 	{
494 		strcpy(server.ip_addr, "127.0.0.1");
495 	}
496 	server.port = g_server_port;
497 	server.sock = -1;
498 
499 	if (conn_pool_connect_server(&server, g_fdfs_connect_timeout) != 0)
500 	{
501 		return;
502 	}
503 
504 	fdfs_quit(&server);
505 	conn_pool_disconnect_server(&server);
506 
507 	logDebug("file: "__FILE__", line: %d, " \
508 		"signal server to quit done", __LINE__);
509 }
510 
sigUsrHandler(int sig)511 static void sigUsrHandler(int sig)
512 {
513 	logInfo("file: "__FILE__", line: %d, " \
514 		"catch signal %d, ignore it", __LINE__, sig);
515 }
516 
517