1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 #include "common.h"
4
5 #include <sys/types.h>
6 #include <sys/wait.h>
7 #include <signal.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <getopt.h>
12 #include <stdbool.h>
13 #include <fcntl.h>
14
15 #include <glib.h>
16
17 #include "utils.h"
18 #include "log.h"
19 #include "seafile-controller.h"
20
21 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
22 #include <sys/sysctl.h>
23 #include <sys/types.h>
24 #include <sys/user.h>
25 #include <limits.h>
26
27 #ifndef WITH_PROC_FS
28 #define WITH_PROC_FS g_file_test("/proc/curproc", G_FILE_TEST_EXISTS)
29 #endif
30
31 static char *command_name = NULL;
32 #endif
33
34 #define CHECK_PROCESS_INTERVAL 10 /* every 10 seconds */
35
36 #if defined(__sun)
37 #define PROC_SELF_PATH "/proc/self/path/a.out"
38 #else
39 #define PROC_SELF_PATH "/proc/self/exe"
40 #endif
41
42 SeafileController *ctl;
43
44 static char *controller_pidfile = NULL;
45
46 char *bin_dir = NULL;
47 char *installpath = NULL;
48 char *topdir = NULL;
49
50 char *seafile_ld_library_path = NULL;
51
52 static const char *short_opts = "hvftc:d:l:g:G:P:F:";
53 static const struct option long_opts[] = {
54 { "help", no_argument, NULL, 'h', },
55 { "version", no_argument, NULL, 'v', },
56 { "foreground", no_argument, NULL, 'f', },
57 { "test", no_argument, NULL, 't', },
58 { "config-dir", required_argument, NULL, 'c', },
59 { "seafile-dir", required_argument, NULL, 'd', },
60 { "central-config-dir", required_argument, NULL, 'F' },
61 { "logdir", required_argument, NULL, 'l', },
62 { "ccnet-debug-level", required_argument, NULL, 'g' },
63 { "seafile-debug-level", required_argument, NULL, 'G' },
64 { "pidfile", required_argument, NULL, 'P' },
65 { NULL, 0, NULL, 0, },
66 };
67
68 static void controller_exit (int code) __attribute__((noreturn));
69
70 static int read_seafdav_config();
71
72 static void
controller_exit(int code)73 controller_exit (int code)
74 {
75 if (code != 0) {
76 seaf_warning ("seaf-controller exited with code %d\n", code);
77 }
78 exit(code);
79 }
80
81 //
82 // Utility functions Start
83 //
84
85 /* returns the pid of the newly created process */
86 static int
spawn_process(char * argv[],bool is_python_process)87 spawn_process (char *argv[], bool is_python_process)
88 {
89 char **ptr = argv;
90 GString *buf = g_string_new(argv[0]);
91 while (*(++ptr)) {
92 g_string_append_printf (buf, " %s", *ptr);
93 }
94 seaf_message ("spawn_process: %s\n", buf->str);
95 g_string_free (buf, TRUE);
96
97 int pipefd[2] = {0, 0};
98 if (is_python_process) {
99 if (pipe(pipefd) < 0) {
100 seaf_warning("Failed to create pipe.\n");
101 }
102 fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
103 }
104
105 pid_t pid = fork();
106
107 if (pid == 0) {
108 if (is_python_process) {
109 if (pipefd[0] > 0 && pipefd[1] > 0) {
110 close(pipefd[0]);
111 dup2(pipefd[1], 2);
112 }
113 }
114 /* child process */
115 execvp (argv[0], argv);
116 seaf_warning ("failed to execvp %s\n", argv[0]);
117
118 if (pipefd[1] > 0) {
119 close(pipefd[1]);
120 }
121
122 exit(-1);
123 } else {
124 /* controller */
125 if (pid == -1)
126 seaf_warning ("error when fork %s: %s\n", argv[0], strerror(errno));
127 else
128 seaf_message ("spawned %s, pid %d\n", argv[0], pid);
129
130 if (is_python_process) {
131 char child_stderr[1024] = {0};
132 if (pipefd[0] > 0 && pipefd[1] > 0){
133 close(pipefd[1]);
134 sleep(1);
135 while (read(pipefd[0], child_stderr, sizeof(child_stderr)) > 0)
136 seaf_warning("%s", child_stderr);
137 close(pipefd[0]);
138 }
139 }
140 return (int)pid;
141 }
142 }
143
144 #define PID_ERROR_ENOENT 0
145 #define PID_ERROR_OTHER -1
146
147 /**
148 * @return
149 * - pid if successfully opened and read the file
150 * - PID_ERROR_ENOENT if file not exists,
151 * - PID_ERROR_OTHER if other errors
152 */
153 static int
read_pid_from_pidfile(const char * pidfile)154 read_pid_from_pidfile (const char *pidfile)
155 {
156 FILE *pf = g_fopen (pidfile, "r");
157 if (!pf) {
158 if (errno == ENOENT) {
159 return PID_ERROR_ENOENT;
160 } else {
161 return PID_ERROR_OTHER;
162 }
163 }
164
165 int pid = PID_ERROR_OTHER;
166 if (fscanf (pf, "%d", &pid) < 0) {
167 seaf_warning ("bad pidfile format: %s\n", pidfile);
168 fclose(pf);
169 return PID_ERROR_OTHER;
170 }
171
172 fclose(pf);
173
174 return pid;
175 }
176
177 static void
kill_by_force(int which)178 kill_by_force (int which)
179 {
180 if (which < 0 || which >= N_PID)
181 return;
182
183 char *pidfile = ctl->pidfile[which];
184 int pid = read_pid_from_pidfile(pidfile);
185 if (pid > 0) {
186 // if SIGKILL send success, then remove related pid file
187 if (kill ((pid_t)pid, SIGKILL) == 0) {
188 g_unlink (pidfile);
189 }
190 }
191 }
192
193 //
194 // Utility functions End
195 //
196
197 static int
start_seaf_server()198 start_seaf_server ()
199 {
200 if (!ctl->config_dir || !ctl->seafile_dir)
201 return -1;
202
203 seaf_message ("starting seaf-server ...\n");
204 static char *logfile = NULL;
205 if (logfile == NULL) {
206 logfile = g_build_filename (ctl->logdir, "seafile.log", NULL);
207 }
208
209 char *argv[] = {
210 "seaf-server",
211 "-F", ctl->central_config_dir,
212 "-c", ctl->config_dir,
213 "-d", ctl->seafile_dir,
214 "-l", logfile,
215 "-P", ctl->pidfile[PID_SERVER],
216 "-p", ctl->rpc_pipe_path,
217 NULL};
218
219 int pid = spawn_process (argv, false);
220 if (pid <= 0) {
221 seaf_warning ("Failed to spawn seaf-server\n");
222 return -1;
223 }
224
225 return 0;
226 }
227
228 static const char *
get_python_executable()229 get_python_executable() {
230 static const char *python = NULL;
231 if (python != NULL) {
232 return python;
233 }
234
235 static const char *try_list[] = {
236 "python3"
237 };
238
239 int i;
240 for (i = 0; i < G_N_ELEMENTS(try_list); i++) {
241 char *binary = g_find_program_in_path (try_list[i]);
242 if (binary != NULL) {
243 python = binary;
244 break;
245 }
246 }
247
248 if (python == NULL) {
249 python = g_getenv ("PYTHON");
250 if (python == NULL) {
251 python = "python";
252 }
253 }
254
255 return python;
256 }
257
258 static void
init_seafile_path()259 init_seafile_path ()
260 {
261 GError *error = NULL;
262 #if defined(__linux__)
263 char *binary = g_file_read_link (PROC_SELF_PATH, &error);
264 #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
265 /*
266 * seafile.sh starts the process using abs path
267 */
268 char binary[_POSIX_PATH_MAX];
269 memset(binary, 0, _POSIX_PATH_MAX);
270 char * rc = realpath(command_name, binary);
271 if (!rc) {
272 seaf_warning ("failed to readpath: %s\n", binary);
273 return;
274 }
275 #endif
276 char *tmp = NULL;
277 if (error != NULL) {
278 seaf_warning ("failed to readlink: %s\n", error->message);
279 return;
280 }
281
282 bin_dir = g_path_get_dirname (binary);
283
284 tmp = g_path_get_dirname (bin_dir);
285 installpath = g_path_get_dirname (tmp);
286
287 topdir = g_path_get_dirname (installpath);
288
289 #if defined(__linux__)
290 g_free (binary);
291 #endif
292 g_free (tmp);
293 }
294
295 static void
setup_python_path()296 setup_python_path()
297 {
298 static GList *path_list = NULL;
299 if (path_list != NULL) {
300 /* Only setup once */
301 return;
302 }
303
304 /* Allow seafdav to access seahub_settings.py */
305 path_list = g_list_prepend (path_list, g_build_filename (topdir, "conf", NULL));
306
307 path_list = g_list_prepend (path_list,
308 g_build_filename (installpath, "seahub", NULL));
309
310 path_list = g_list_prepend (path_list,
311 g_build_filename (installpath, "seahub/thirdpart", NULL));
312
313 path_list = g_list_prepend (path_list,
314 g_build_filename (installpath, "seahub/seahub-extra", NULL));
315
316 path_list = g_list_prepend (path_list,
317 g_build_filename (installpath, "seahub/seahub-extra/thirdparts", NULL));
318
319 path_list = g_list_prepend (path_list,
320 g_build_filename (installpath, "seafile/lib/python3.8/site-packages", NULL));
321
322 path_list = g_list_prepend (path_list,
323 g_build_filename (installpath, "seafile/lib64/python3.8/site-packages", NULL));
324
325 path_list = g_list_reverse (path_list);
326
327 GList *ptr;
328 GString *new_pypath = g_string_new (g_getenv("PYTHONPATH"));
329
330 for (ptr = path_list; ptr != NULL; ptr = ptr->next) {
331 const char *path = (char *)ptr->data;
332
333 g_string_append_c (new_pypath, ':');
334 g_string_append (new_pypath, path);
335 }
336
337 g_setenv ("PYTHONPATH", g_string_free (new_pypath, FALSE), TRUE);
338
339 /* seaf_message ("PYTHONPATH is:\n\n%s\n", g_getenv ("PYTHONPATH")); */
340 }
341
342 static void
setup_env()343 setup_env ()
344 {
345 g_setenv ("CCNET_CONF_DIR", ctl->config_dir, TRUE);
346 g_setenv ("SEAFILE_CONF_DIR", ctl->seafile_dir, TRUE);
347 g_setenv ("SEAFILE_CENTRAL_CONF_DIR", ctl->central_config_dir, TRUE);
348 g_setenv ("SEAFILE_RPC_PIPE_PATH", ctl->rpc_pipe_path, TRUE);
349
350 char *seahub_dir = g_build_filename (installpath, "seahub", NULL);
351 char *seafdav_conf = g_build_filename (ctl->central_config_dir, "seafdav.conf", NULL);
352 g_setenv ("SEAHUB_DIR", seahub_dir, TRUE);
353 g_setenv ("SEAFDAV_CONF", seafdav_conf, TRUE);
354
355 setup_python_path();
356 }
357
358 static int
start_seafevents()359 start_seafevents() {
360 if (!ctl->has_seafevents)
361 return 0;
362
363 static char *seafevents_config_file = NULL;
364 static char *seafevents_log_file = NULL;
365
366 if (seafevents_config_file == NULL)
367 seafevents_config_file = g_build_filename (topdir,
368 "conf/seafevents.conf",
369 NULL);
370 if (seafevents_log_file == NULL)
371 seafevents_log_file = g_build_filename (ctl->logdir,
372 "seafevents.log",
373 NULL);
374
375 char *argv[] = {
376 (char *)get_python_executable(),
377 "-m", "seafevents.main",
378 "--config-file", seafevents_config_file,
379 "--logfile", seafevents_log_file,
380 "-P", ctl->pidfile[PID_SEAFEVENTS],
381 NULL
382 };
383
384 int pid = spawn_process (argv, true);
385
386 if (pid <= 0) {
387 seaf_warning ("Failed to spawn seafevents.\n");
388 return -1;
389 }
390
391 return 0;
392 }
393
394 static int
start_seafdav()395 start_seafdav() {
396 static char *seafdav_log_file = NULL;
397 if (seafdav_log_file == NULL)
398 seafdav_log_file = g_build_filename (ctl->logdir,
399 "seafdav.log",
400 NULL);
401
402 SeafDavConfig conf = ctl->seafdav_config;
403 char port[16];
404 snprintf (port, sizeof(port), "%d", conf.port);
405
406 char *argv[] = {
407 (char *)get_python_executable(),
408 "-m", "wsgidav.server.server_cli",
409 "--server", "gunicorn",
410 "--root", "/",
411 "--log-file", seafdav_log_file,
412 "--pid", ctl->pidfile[PID_SEAFDAV],
413 "--port", port,
414 "--host", conf.host,
415 NULL
416 };
417
418 int pid = spawn_process (argv, true);
419
420 if (pid <= 0) {
421 seaf_warning ("Failed to spawn seafdav\n");
422 return -1;
423 }
424
425 return 0;
426 }
427
428 static void
run_controller_loop()429 run_controller_loop ()
430 {
431 GMainLoop *mainloop = g_main_loop_new (NULL, FALSE);
432
433 g_main_loop_run (mainloop);
434 }
435
436 static gboolean
need_restart(int which)437 need_restart (int which)
438 {
439 if (which < 0 || which >= N_PID)
440 return FALSE;
441
442 int pid = read_pid_from_pidfile (ctl->pidfile[which]);
443 if (pid == PID_ERROR_ENOENT) {
444 seaf_warning ("pid file %s does not exist\n", ctl->pidfile[which]);
445 return TRUE;
446 } else if (pid == PID_ERROR_OTHER) {
447 seaf_warning ("failed to read pidfile %s: %s\n", ctl->pidfile[which], strerror(errno));
448 return FALSE;
449 } else {
450 char buf[256];
451 gboolean with_procfs;
452 #if defined(__linux__)
453 with_procfs = g_file_test("/proc/self", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
454 #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
455 with_procfs = g_file_test("/proc/curproc", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
456 #else
457 with_procfs = FALSE;
458 #endif
459 if (with_procfs) {
460 snprintf (buf, sizeof(buf), "/proc/%d", pid);
461 if (g_file_test (buf, G_FILE_TEST_IS_DIR)) {
462 return FALSE;
463 } else {
464 seaf_warning ("path /proc/%d doesn't exist, restart progress [%d]\n", pid, which);
465 return TRUE;
466 }
467
468 } else {
469 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
470 #ifdef __OpenBSD__
471 int min[6] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), 1};
472 #else
473 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
474 #endif
475 size_t len = sizeof(struct kinfo_proc);
476 struct kinfo_proc kp;
477 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &kp, &len, NULL, 0) != -1 &&
478 len == sizeof(struct kinfo_proc)) {
479 return FALSE;
480 } else {
481 return TRUE;
482 }
483 #else
484 return FALSE;
485 #endif
486 }
487 }
488 }
489
490 static gboolean
check_process(void * data)491 check_process (void *data)
492 {
493 if (need_restart(PID_SERVER)) {
494 seaf_message ("seaf-server need restart...\n");
495 start_seaf_server();
496 }
497
498 if (ctl->seafdav_config.enabled) {
499 if (need_restart(PID_SEAFDAV)) {
500 seaf_message ("seafdav need restart...\n");
501 start_seafdav ();
502 }
503 }
504
505 if (ctl->has_seafevents && need_restart(PID_SEAFEVENTS)) {
506 seaf_message ("seafevents need restart...\n");
507 start_seafevents ();
508 }
509
510 return TRUE;
511 }
512
513 static void
start_process_monitor()514 start_process_monitor ()
515 {
516 ctl->check_process_timer = g_timeout_add (
517 CHECK_PROCESS_INTERVAL * 1000, check_process, NULL);
518 }
519
520 static int seaf_controller_start ();
521 /* This would also stop seaf-server & other components */
522 static void
stop_services()523 stop_services ()
524 {
525 seaf_message ("shutting down all services ...\n");
526
527 kill_by_force(PID_SERVER);
528 kill_by_force(PID_SEAFDAV);
529 if (ctl->has_seafevents)
530 kill_by_force(PID_SEAFEVENTS);
531 }
532
533 static void
init_pidfile_path(SeafileController * ctl)534 init_pidfile_path (SeafileController *ctl)
535 {
536 char *pid_dir = g_build_filename (topdir, "pids", NULL);
537 if (!g_file_test(pid_dir, G_FILE_TEST_EXISTS)) {
538 if (g_mkdir(pid_dir, 0777) < 0) {
539 seaf_warning("failed to create pid dir %s: %s", pid_dir, strerror(errno));
540 controller_exit(1);
541 }
542 }
543
544 ctl->pidfile[PID_SERVER] = g_build_filename (pid_dir, "seaf-server.pid", NULL);
545 ctl->pidfile[PID_SEAFDAV] = g_build_filename (pid_dir, "seafdav.pid", NULL);
546 ctl->pidfile[PID_SEAFEVENTS] = g_build_filename (pid_dir, "seafevents.pid", NULL);
547 }
548
549 static int
seaf_controller_init(SeafileController * ctl,char * central_config_dir,char * config_dir,char * seafile_dir,char * logdir)550 seaf_controller_init (SeafileController *ctl,
551 char *central_config_dir,
552 char *config_dir,
553 char *seafile_dir,
554 char *logdir)
555 {
556 init_seafile_path ();
557 if (!g_file_test (config_dir, G_FILE_TEST_IS_DIR)) {
558 seaf_warning ("invalid config_dir: %s\n", config_dir);
559 return -1;
560 }
561
562 if (!g_file_test (seafile_dir, G_FILE_TEST_IS_DIR)) {
563 seaf_warning ("invalid seafile_dir: %s\n", seafile_dir);
564 return -1;
565 }
566
567 if (logdir == NULL) {
568 char *topdir = g_path_get_dirname(config_dir);
569 logdir = g_build_filename (topdir, "logs", NULL);
570 if (checkdir_with_mkdir(logdir) < 0) {
571 fprintf (stderr, "failed to create log folder \"%s\": %s\n",
572 logdir, strerror(errno));
573 return -1;
574 }
575 g_free (topdir);
576 }
577
578 ctl->central_config_dir = central_config_dir;
579 ctl->config_dir = config_dir;
580 ctl->seafile_dir = seafile_dir;
581 ctl->rpc_pipe_path = g_build_filename (installpath, "runtime", NULL);
582 ctl->logdir = logdir;
583
584 if (read_seafdav_config() < 0) {
585 return -1;
586 }
587
588 char *seafevents_config_file = g_build_filename (topdir,
589 "conf/seafevents.conf",
590 NULL);
591
592 if (!g_file_test (seafevents_config_file, G_FILE_TEST_EXISTS)) {
593 seaf_message ("No seafevents.\n");
594 ctl->has_seafevents = FALSE;
595 } else {
596 ctl->has_seafevents = TRUE;
597 }
598 g_free (seafevents_config_file);
599
600 init_pidfile_path (ctl);
601 setup_env ();
602
603 return 0;
604 }
605
606 static int
seaf_controller_start()607 seaf_controller_start ()
608 {
609 if (start_seaf_server() < 0) {
610 seaf_warning ("Failed to start seaf server\n");
611 return -1;
612 }
613
614 start_process_monitor ();
615 return 0;
616 }
617
618 static int
write_controller_pidfile()619 write_controller_pidfile ()
620 {
621 if (!controller_pidfile)
622 return -1;
623
624 pid_t pid = getpid();
625
626 FILE *pidfile = g_fopen(controller_pidfile, "w");
627 if (!pidfile) {
628 seaf_warning ("Failed to fopen() pidfile %s: %s\n",
629 controller_pidfile, strerror(errno));
630 return -1;
631 }
632
633 char buf[32];
634 snprintf (buf, sizeof(buf), "%d\n", pid);
635 if (fputs(buf, pidfile) < 0) {
636 seaf_warning ("Failed to write pidfile %s: %s\n",
637 controller_pidfile, strerror(errno));
638 fclose (pidfile);
639 return -1;
640 }
641
642 fflush (pidfile);
643 fclose (pidfile);
644 return 0;
645 }
646
647 static void
remove_controller_pidfile()648 remove_controller_pidfile ()
649 {
650 if (controller_pidfile) {
651 g_unlink (controller_pidfile);
652 }
653 }
654
655 static void
sigint_handler(int signo)656 sigint_handler (int signo)
657 {
658 stop_services ();
659
660 remove_controller_pidfile();
661
662 signal (signo, SIG_DFL);
663 raise (signo);
664 }
665
666 static void
sigchld_handler(int signo)667 sigchld_handler (int signo)
668 {
669 waitpid (-1, NULL, WNOHANG);
670 }
671
672 static void
sigusr1_handler(int signo)673 sigusr1_handler (int signo)
674 {
675 seafile_log_reopen();
676 }
677
678 static void
set_signal_handlers()679 set_signal_handlers ()
680 {
681 signal (SIGINT, sigint_handler);
682 signal (SIGTERM, sigint_handler);
683 signal (SIGCHLD, sigchld_handler);
684 signal (SIGUSR1, sigusr1_handler);
685 signal (SIGPIPE, SIG_IGN);
686 }
687
688 static void
usage()689 usage ()
690 {
691 fprintf (stderr, "Usage: seafile-controller OPTIONS\n"
692 "OPTIONS:\n"
693 " -b, --bin-dir insert a directory in front of the PATH env\n"
694 " -c, --config-dir ccnet config dir\n"
695 " -d, --seafile-dir seafile dir\n"
696 );
697 }
698
699 /* seafile-controller -t is used to test whether config file is valid */
700 static void
test_config(const char * central_config_dir,const char * ccnet_dir,const char * seafile_dir)701 test_config (const char *central_config_dir,
702 const char *ccnet_dir,
703 const char *seafile_dir)
704 {
705 char buf[1024];
706 GError *error = NULL;
707 int retcode = 0;
708 char *child_stdout = NULL;
709 char *child_stderr = NULL;
710
711 snprintf (buf,
712 sizeof(buf),
713 "seaf-server -F \"%s\" -c \"%s\" -d \"%s\" -t -f",
714 central_config_dir,
715 ccnet_dir,
716 seafile_dir);
717
718 g_spawn_command_line_sync (buf,
719 &child_stdout,
720 &child_stderr,
721 &retcode,
722 &error);
723
724 if (error != NULL) {
725 fprintf (stderr,
726 "failed to run \"seaf-server -t\": %s\n",
727 error->message);
728 exit (1);
729 }
730
731 if (child_stdout) {
732 fputs (child_stdout, stdout);
733 }
734
735 if (child_stderr) {
736 fputs (child_stderr, stdout);
737 }
738
739 if (retcode != 0) {
740 fprintf (stderr,
741 "failed to run \"seaf-server -t\" [%d]\n", retcode);
742 exit (1);
743 }
744
745 exit(0);
746 }
747
748 static int
read_seafdav_config()749 read_seafdav_config()
750 {
751 int ret = 0;
752 char *seafdav_conf = NULL;
753 GKeyFile *key_file = NULL;
754 GError *error = NULL;
755
756 seafdav_conf = g_build_filename(ctl->central_config_dir, "seafdav.conf", NULL);
757 if (!g_file_test(seafdav_conf, G_FILE_TEST_EXISTS)) {
758 goto out;
759 }
760
761 key_file = g_key_file_new ();
762 if (!g_key_file_load_from_file (key_file, seafdav_conf,
763 G_KEY_FILE_KEEP_COMMENTS, NULL)) {
764 seaf_warning("Failed to load seafdav.conf\n");
765 ret = -1;
766 goto out;
767 }
768
769 /* enabled */
770 ctl->seafdav_config.enabled = g_key_file_get_boolean(key_file, "WEBDAV", "enabled", &error);
771 if (error != NULL) {
772 if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
773 seaf_message ("Error when reading WEBDAV.enabled, use default value 'false'\n");
774 }
775 ctl->seafdav_config.enabled = FALSE;
776 g_clear_error (&error);
777 goto out;
778 }
779
780 if (!ctl->seafdav_config.enabled) {
781 goto out;
782 }
783
784 /* host */
785 char *host = seaf_key_file_get_string (key_file, "WEBDAV", "host", &error);
786 if (error != NULL) {
787 g_clear_error(&error);
788 ctl->seafdav_config.host = g_strdup("0.0.0.0");
789 } else {
790 ctl->seafdav_config.host = host;
791 }
792
793 /* port */
794 ctl->seafdav_config.port = g_key_file_get_integer(key_file, "WEBDAV", "port", &error);
795 if (error != NULL) {
796 if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
797 seaf_message ("Error when reading WEBDAV.port, use deafult value 8080\n");
798 }
799 ctl->seafdav_config.port = 8080;
800 g_clear_error (&error);
801 }
802
803 if (ctl->seafdav_config.port <= 0 || ctl->seafdav_config.port > 65535) {
804 seaf_warning("Failed to load seafdav config: invalid port %d\n", ctl->seafdav_config.port);
805 ret = -1;
806 goto out;
807 }
808
809 out:
810 if (key_file) {
811 g_key_file_free (key_file);
812 }
813 g_free (seafdav_conf);
814
815 return ret;
816 }
817
818 static int
init_syslog_config()819 init_syslog_config ()
820 {
821 char *seafile_conf = g_build_filename (ctl->central_config_dir, "seafile.conf", NULL);
822 GKeyFile *key_file = g_key_file_new ();
823 int ret = 0;
824
825 if (!g_key_file_load_from_file (key_file, seafile_conf,
826 G_KEY_FILE_KEEP_COMMENTS, NULL)) {
827 seaf_warning("Failed to load seafile.conf.\n");
828 ret = -1;
829 goto out;
830 }
831
832 set_syslog_config (key_file);
833
834 out:
835 g_key_file_free (key_file);
836 g_free (seafile_conf);
837
838 return ret;
839 }
840
main(int argc,char ** argv)841 int main (int argc, char **argv)
842 {
843 if (argc <= 1) {
844 usage ();
845 exit (1);
846 }
847
848 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
849 command_name = argv[0];
850 #endif
851 char *config_dir = DEFAULT_CONFIG_DIR;
852 char *central_config_dir = NULL;
853 char *seafile_dir = NULL;
854 char *logdir = NULL;
855 char *ccnet_debug_level_str = "info";
856 char *seafile_debug_level_str = "debug";
857 int daemon_mode = 1;
858 gboolean test_conf = FALSE;
859
860 int c;
861 while ((c = getopt_long (argc, argv, short_opts,
862 long_opts, NULL)) != EOF)
863 {
864 switch (c) {
865 case 'h':
866 usage ();
867 exit(1);
868 break;
869 case 'v':
870 fprintf (stderr, "seafile-controller version 1.0\n");
871 break;
872 case 't':
873 test_conf = TRUE;
874 break;
875 case 'c':
876 config_dir = optarg;
877 break;
878 case 'F':
879 central_config_dir = g_strdup(optarg);
880 break;
881 case 'd':
882 seafile_dir = g_strdup(optarg);
883 break;
884 case 'f':
885 daemon_mode = 0;
886 break;
887 case 'l':
888 logdir = g_strdup(optarg);
889 break;
890 case 'g':
891 ccnet_debug_level_str = optarg;
892 break;
893 case 'G':
894 seafile_debug_level_str = optarg;
895 break;
896 case 'P':
897 controller_pidfile = optarg;
898 break;
899 default:
900 usage ();
901 exit (1);
902 }
903 }
904
905 #if !GLIB_CHECK_VERSION(2, 35, 0)
906 g_type_init();
907 #endif
908 #if !GLIB_CHECK_VERSION(2,32,0)
909 g_thread_init (NULL);
910 #endif
911
912 if (!seafile_dir) {
913 fprintf (stderr, "<seafile_dir> must be specified with --seafile-dir\n");
914 exit(1);
915 }
916
917 if (!central_config_dir) {
918 fprintf (stderr, "<central_config_dir> must be specified with --central-config-dir\n");
919 exit(1);
920 }
921
922 central_config_dir = ccnet_expand_path (central_config_dir);
923 config_dir = ccnet_expand_path (config_dir);
924 seafile_dir = ccnet_expand_path (seafile_dir);
925
926 if (test_conf) {
927 test_config (central_config_dir, config_dir, seafile_dir);
928 }
929
930 ctl = g_new0 (SeafileController, 1);
931 if (seaf_controller_init (ctl, central_config_dir, config_dir, seafile_dir, logdir) < 0) {
932 controller_exit(1);
933 }
934
935 char *logfile = g_build_filename (ctl->logdir, "controller.log", NULL);
936 if (seafile_log_init (logfile, ccnet_debug_level_str,
937 seafile_debug_level_str) < 0) {
938 seaf_warning ("Failed to init log.\n");
939 controller_exit (1);
940 }
941
942 if (init_syslog_config () < 0) {
943 controller_exit (1);
944 }
945
946 set_signal_handlers ();
947
948 if (seaf_controller_start () < 0)
949 controller_exit (1);
950
951 #ifndef WIN32
952 if (daemon_mode) {
953 #ifndef __APPLE__
954 daemon (1, 0);
955 #else /* __APPLE */
956 /* daemon is deprecated under APPLE
957 * use fork() instead
958 * */
959 switch (fork ()) {
960 case -1:
961 seaf_warning ("Failed to daemonize");
962 exit (-1);
963 break;
964 case 0:
965 /* all good*/
966 break;
967 default:
968 /* kill origin process */
969 exit (0);
970 }
971 #endif /* __APPLE */
972 }
973 #endif /* !WIN32 */
974
975 if (controller_pidfile == NULL) {
976 controller_pidfile = g_strdup(g_getenv ("SEAFILE_PIDFILE"));
977 }
978
979 if (controller_pidfile != NULL) {
980 if (write_controller_pidfile () < 0) {
981 seaf_warning ("Failed to write pidfile %s\n", controller_pidfile);
982 return -1;
983 }
984 }
985
986 run_controller_loop ();
987
988 return 0;
989 }
990
991