1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 #include "common.h"
4 
5 #ifdef WIN32
6 #include <windows.h>
7 #include <wincrypt.h>
8 #endif
9 
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <getopt.h>
15 #include <signal.h>
16 
17 #include <glib.h>
18 #include <glib-object.h>
19 #include <curl/curl.h>
20 #include <event2/thread.h>
21 
22 #ifdef HAVE_BREAKPAD_SUPPORT
23 #include <c_bpwrapper.h>
24 #endif // HAVE_BREAKPAD_SUPPORT
25 
26 #include <searpc.h>
27 #include <searpc-named-pipe-transport.h>
28 
29 #include "seafile-session.h"
30 #include "seafile-rpc.h"
31 #include "log.h"
32 #include "utils.h"
33 #include "vc-utils.h"
34 #include "seafile-config.h"
35 #ifndef USE_GPL_CRYPTO
36 #include "curl-init.h"
37 #endif
38 
39 #include "cdc/cdc.h"
40 
41 #ifndef SEAFILE_CLIENT_VERSION
42 #define SEAFILE_CLIENT_VERSION PACKAGE_VERSION
43 #endif
44 
45 
46 SeafileSession *seaf;
47 
48 static const char *short_options = "hvc:d:w:l:D:bg:G:";
49 static struct option long_options[] = {
50     { "help", no_argument, NULL, 'h', },
51     { "version", no_argument, NULL, 'v', },
52     { "config-file", required_argument, NULL, 'c' },
53     { "seafdir", required_argument, NULL, 'd' },
54     { "daemon", no_argument, NULL, 'b' },
55     { "debug", required_argument, NULL, 'D' },
56     { "worktree", required_argument, NULL, 'w' },
57     { "log", required_argument, NULL, 'l' },
58     { "ccnet-debug-level", required_argument, NULL, 'g' },
59     { "seafile-debug-level", required_argument, NULL, 'G' },
60     { NULL, 0, NULL, 0, },
61 };
62 
usage()63 static void usage ()
64 {
65     fprintf (stderr, "usage: seaf-daemon [-c config_dir] [-d seafile_dir] [-w worktree_dir] [--daemon]\n");
66 }
67 
68 #include <searpc.h>
69 #include "searpc-signature.h"
70 #include "searpc-marshal.h"
71 
72 #define SEAFILE_SOCKET_NAME "seafile.sock"
73 
74 static void
register_rpc_service()75 register_rpc_service ()
76 {
77     searpc_server_init (register_marshals);
78 
79     searpc_create_service ("seafile-rpcserver");
80     searpc_create_service ("seafile-threaded-rpcserver");
81 
82     /* seafile-rpcserver */
83     searpc_server_register_function ("seafile-rpcserver",
84                                      seafile_sync_error_id_to_str,
85                                      "seafile_sync_error_id_to_str",
86                                      searpc_signature_string__int());
87 
88     searpc_server_register_function ("seafile-rpcserver",
89                                      seafile_get_config,
90                                      "seafile_get_config",
91                                      searpc_signature_string__string());
92 
93     searpc_server_register_function ("seafile-rpcserver",
94                                      seafile_set_config,
95                                      "seafile_set_config",
96                                      searpc_signature_int__string_string());
97 
98     searpc_server_register_function ("seafile-rpcserver",
99                                      seafile_get_config_int,
100                                      "seafile_get_config_int",
101                                      searpc_signature_int__string());
102 
103     searpc_server_register_function ("seafile-rpcserver",
104                                      seafile_set_config_int,
105                                      "seafile_set_config_int",
106                                      searpc_signature_int__string_int());
107 
108     searpc_server_register_function ("seafile-rpcserver",
109                                      seafile_set_upload_rate_limit,
110                                      "seafile_set_upload_rate_limit",
111                                      searpc_signature_int__int());
112 
113     searpc_server_register_function ("seafile-rpcserver",
114                                      seafile_set_download_rate_limit,
115                                      "seafile_set_download_rate_limit",
116                                      searpc_signature_int__int());
117 
118     searpc_server_register_function ("seafile-rpcserver",
119                                      seafile_unsync_repos_by_account,
120                                      "seafile_unsync_repos_by_account",
121                                      searpc_signature_int__string_string());
122 
123     searpc_server_register_function ("seafile-rpcserver",
124                                      seafile_remove_repo_tokens_by_account,
125                                      "seafile_remove_repo_tokens_by_account",
126                                      searpc_signature_int__string_string());
127 
128     searpc_server_register_function ("seafile-rpcserver",
129                                      seafile_set_repo_token,
130                                      "seafile_set_repo_token",
131                                      searpc_signature_int__string_string());
132 
133     searpc_server_register_function ("seafile-rpcserver",
134                                      seafile_get_upload_rate,
135                                      "seafile_get_upload_rate",
136                                      searpc_signature_int__void());
137 
138     searpc_server_register_function ("seafile-rpcserver",
139                                      seafile_get_download_rate,
140                                      "seafile_get_download_rate",
141                                      searpc_signature_int__void());
142 
143     searpc_server_register_function ("seafile-rpcserver",
144                                      seafile_destroy_repo,
145                                      "seafile_destroy_repo",
146                                      searpc_signature_int__string());
147 
148     searpc_server_register_function ("seafile-rpcserver",
149                                      seafile_set_repo_property,
150                                      "seafile_set_repo_property",
151                                      searpc_signature_int__string_string_string());
152     searpc_server_register_function ("seafile-rpcserver",
153                                      seafile_get_repo_property,
154                                      "seafile_get_repo_property",
155                                      searpc_signature_string__string_string());
156 
157     searpc_server_register_function ("seafile-rpcserver",
158                                      seafile_update_repos_server_host,
159                                      "seafile_update_repos_server_host",
160                                      searpc_signature_int__string_string());
161 
162     searpc_server_register_function ("seafile-rpcserver",
163                                      seafile_disable_auto_sync,
164                                      "seafile_disable_auto_sync",
165                                      searpc_signature_int__void());
166 
167     searpc_server_register_function ("seafile-rpcserver",
168                                      seafile_enable_auto_sync,
169                                      "seafile_enable_auto_sync",
170                                      searpc_signature_int__void());
171 
172     searpc_server_register_function ("seafile-rpcserver",
173                                      seafile_is_auto_sync_enabled,
174                                      "seafile_is_auto_sync_enabled",
175                                      searpc_signature_int__void());
176 
177     searpc_server_register_function ("seafile-rpcserver",
178                                      seafile_gen_default_worktree,
179                                      "gen_default_worktree",
180                                      searpc_signature_string__string_string());
181     searpc_server_register_function ("seafile-rpcserver",
182                                      seafile_check_path_for_clone,
183                                      "seafile_check_path_for_clone",
184                                      searpc_signature_int__string());
185 
186     /* clone means sync with existing folder, download means sync to a new folder. */
187     searpc_server_register_function ("seafile-rpcserver",
188                                      seafile_clone,
189                                      "seafile_clone",
190         searpc_signature_string__string_int_string_string_string_string_string_string_string_int_string());
191     searpc_server_register_function ("seafile-rpcserver",
192                                      seafile_download,
193                                      "seafile_download",
194         searpc_signature_string__string_int_string_string_string_string_string_string_string_int_string());
195 
196     searpc_server_register_function ("seafile-rpcserver",
197                                      seafile_cancel_clone_task,
198                                      "seafile_cancel_clone_task",
199                                      searpc_signature_int__string());
200     searpc_server_register_function ("seafile-rpcserver",
201                                      seafile_get_clone_tasks,
202                                      "seafile_get_clone_tasks",
203                                      searpc_signature_objlist__void());
204     searpc_server_register_function ("seafile-rpcserver",
205                                      seafile_sync,
206                                      "seafile_sync",
207                                      searpc_signature_int__string_string());
208     searpc_server_register_function ("seafile-rpcserver",
209                                      seafile_get_repo_list,
210                                      "seafile_get_repo_list",
211                                      searpc_signature_objlist__int_int());
212     searpc_server_register_function ("seafile-rpcserver",
213                                      seafile_get_repo,
214                                      "seafile_get_repo",
215                                      searpc_signature_object__string());
216 
217     searpc_server_register_function ("seafile-rpcserver",
218                                      seafile_get_repo_sync_task,
219                                      "seafile_get_repo_sync_task",
220                                      searpc_signature_object__string());
221 
222     searpc_server_register_function ("seafile-rpcserver",
223                                      seafile_find_transfer_task,
224                                      "seafile_find_transfer_task",
225                                      searpc_signature_object__string());
226 
227     searpc_server_register_function ("seafile-rpcserver",
228                                      seafile_get_path_sync_status,
229                                      "seafile_get_path_sync_status",
230                                      searpc_signature_string__string_string_int());
231 
232     searpc_server_register_function ("seafile-rpcserver",
233                                      seafile_mark_file_locked,
234                                      "seafile_mark_file_locked",
235                                      searpc_signature_int__string_string());
236 
237     searpc_server_register_function ("seafile-rpcserver",
238                                      seafile_mark_file_unlocked,
239                                      "seafile_mark_file_unlocked",
240                                      searpc_signature_int__string_string());
241 
242     searpc_server_register_function ("seafile-rpcserver",
243                                      seafile_generate_magic_and_random_key,
244                                      "seafile_generate_magic_and_random_key",
245                                      searpc_signature_object__int_string_string());
246 
247     searpc_server_register_function ("seafile-rpcserver",
248                                      seafile_get_server_property,
249                                      "seafile_get_server_property",
250                                      searpc_signature_string__string_string());
251 
252     searpc_server_register_function ("seafile-rpcserver",
253                                      seafile_set_server_property,
254                                      "seafile_set_server_property",
255                                      searpc_signature_int__string_string_string());
256 
257     searpc_server_register_function ("seafile-rpcserver",
258                                      seafile_get_file_sync_errors,
259                                      "seafile_get_file_sync_errors",
260                                      searpc_signature_objlist__int_int());
261 
262     searpc_server_register_function ("seafile-rpcserver",
263                                      seafile_del_file_sync_error_by_id,
264                                      "seafile_del_file_sync_error_by_id",
265                                      searpc_signature_int__int());
266 
267     searpc_server_register_function ("seafile-rpcserver",
268                                      seafile_get_sync_notification,
269                                      "seafile_get_sync_notification",
270                                      searpc_signature_json__void());
271 
272     searpc_server_register_function ("seafile-rpcserver",
273                                      seafile_shutdown,
274                                      "seafile_shutdown",
275                                      searpc_signature_int__void());
276 
277     /* Need to run in a thread since diff may take long. */
278     searpc_server_register_function ("seafile-threaded-rpcserver",
279                                      seafile_diff,
280                                      "seafile_diff",
281                                      searpc_signature_objlist__string_string_string_int());
282 }
283 
284 #ifdef WIN32
b64encode(const char * input)285 char *b64encode(const char *input)
286 {
287     char buf[32767] = {0};
288     DWORD retlen = 32767;
289     CryptBinaryToString((BYTE*) input, strlen(input), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, buf, &retlen);
290     return strdup(buf);
291 }
292 #endif
293 
294 static int
start_searpc_server()295 start_searpc_server ()
296 {
297     register_rpc_service ();
298 
299 #ifdef WIN32
300     DWORD bufCharCount = 32767;
301     char userNameBuf[bufCharCount];
302     if (GetUserName(userNameBuf, &bufCharCount) == 0) {
303         seaf_warning ("Failed to get user name, GLE=%lu, required size is %lu\n",
304                       GetLastError(), bufCharCount);
305         return -1;
306     }
307 
308     char *path = g_strdup_printf("\\\\.\\pipe\\seafile_%s", b64encode(userNameBuf));
309 #else
310     char *path = g_build_filename (seaf->seaf_dir, SEAFILE_SOCKET_NAME, NULL);
311 #endif
312 
313     SearpcNamedPipeServer *server = searpc_create_named_pipe_server (path);
314     if (!server) {
315         seaf_warning ("Failed to create named pipe server.\n");
316         g_free (path);
317         return -1;
318     }
319 
320     seaf->rpc_socket_path = path;
321 
322     return searpc_named_pipe_server_start (server);
323 }
324 
325 
326 #ifndef WIN32
327 static void
set_signal_handlers(SeafileSession * session)328 set_signal_handlers (SeafileSession *session)
329 {
330     signal (SIGPIPE, SIG_IGN);
331 }
332 #endif
333 
334 #ifdef WIN32
335 /* Get the commandline arguments in unicode, then convert them to utf8  */
336 static char **
get_argv_utf8(int * argc)337 get_argv_utf8 (int *argc)
338 {
339     int i = 0;
340     char **argv = NULL;
341     const wchar_t *cmdline = NULL;
342     wchar_t **argv_w = NULL;
343 
344     cmdline = GetCommandLineW();
345     argv_w = CommandLineToArgvW (cmdline, argc);
346     if (!argv_w) {
347         printf("failed to CommandLineToArgvW(), GLE=%lu\n", GetLastError());
348         return NULL;
349     }
350 
351     argv = (char **)malloc (sizeof(char*) * (*argc));
352     for (i = 0; i < *argc; i++) {
353         argv[i] = wchar_to_utf8 (argv_w[i]);
354     }
355 
356     return argv;
357 }
358 #endif
359 
360 int
main(int argc,char ** argv)361 main (int argc, char **argv)
362 {
363 #ifdef HAVE_BREAKPAD_SUPPORT
364 #ifdef WIN32
365 #define DUMPS_DIR "~/ccnet/logs/dumps/"
366 #else
367 #define DUMPS_DIR "~/.ccnet/logs/dumps/"
368 #endif
369     const char *dump_dir = ccnet_expand_path(DUMPS_DIR);
370     checkdir_with_mkdir(dump_dir);
371     CBPWrapperExceptionHandler bp_exception_handler = newCBPWrapperExceptionHandler(dump_dir);
372 #endif
373 
374 #ifdef WIN32
375 #define DEFAULT_CONFIG_DIR "~/ccnet"
376 #else
377 #define DEFAULT_CONFIG_DIR "~/.ccnet"
378 #endif
379 
380     int c;
381     char *config_dir = DEFAULT_CONFIG_DIR;
382     char *seafile_dir = NULL;
383     char *worktree_dir = NULL;
384     char *logfile = NULL;
385     const char *debug_str = NULL;
386     int daemon_mode = 0;
387     char *ccnet_debug_level_str = "info";
388     char *seafile_debug_level_str = "debug";
389 
390 #ifdef WIN32
391     LoadLibraryA ("exchndl.dll");
392 
393     argv = get_argv_utf8 (&argc);
394 #endif
395 
396     while ((c = getopt_long (argc, argv, short_options,
397                              long_options, NULL)) != EOF)
398     {
399         switch (c) {
400         case 'h':
401             usage();
402             exit (1);
403             break;
404         case 'v':
405             exit (1);
406             break;
407         case 'c':
408             config_dir = optarg;
409             break;
410         case 'd':
411             seafile_dir = g_strdup(optarg);
412             break;
413         case 'b':
414             daemon_mode = 1;
415             break;
416         case 'D':
417             debug_str = optarg;
418             break;
419         case 'w':
420             worktree_dir = g_strdup(optarg);
421             break;
422         case 'l':
423             logfile = g_strdup(optarg);
424             break;
425         case 'g':
426             ccnet_debug_level_str = optarg;
427             break;
428         case 'G':
429             seafile_debug_level_str = optarg;
430             break;
431         default:
432             usage ();
433             exit (1);
434         }
435     }
436 
437     argc -= optind;
438     argv += optind;
439 
440 #ifndef WIN32
441     if (daemon_mode) {
442 #ifndef __APPLE__
443         daemon (1, 0);
444 #else   /* __APPLE */
445         /* daemon is deprecated under APPLE
446          * use fork() instead
447          * */
448         switch (fork ()) {
449           case -1:
450               seaf_warning ("Failed to daemonize");
451               exit (-1);
452               break;
453           case 0:
454               /* all good*/
455               break;
456           default:
457               /* kill origin process */
458               exit (0);
459         }
460 #endif  /* __APPLE */
461     }
462 #endif /* !WIN32 */
463 
464     cdc_init ();
465 
466     curl_global_init (CURL_GLOBAL_ALL);
467 
468 #if !GLIB_CHECK_VERSION(2, 35, 0)
469     g_type_init();
470 #endif
471 #if !GLIB_CHECK_VERSION(2, 31, 0)
472     g_thread_init(NULL);
473 #endif
474 
475 #ifndef WIN32
476     /* init multithreading support for libevent.because struct event_base is not thread safe. */
477     evthread_use_pthreads();
478 #endif
479 
480     if (!debug_str)
481         debug_str = g_getenv("SEAFILE_DEBUG");
482     seafile_debug_set_flags_string (debug_str);
483 
484     if (logfile == NULL)
485         logfile = g_build_filename (config_dir, "logs", "seafile.log", NULL);
486     if (seafile_log_init (logfile, ccnet_debug_level_str,
487                           seafile_debug_level_str) < 0) {
488         seaf_warning ("Failed to init log.\n");
489         exit (1);
490     }
491 
492     /* init seafile */
493     if (seafile_dir == NULL)
494         seafile_dir = g_build_filename (config_dir, "seafile-data", NULL);
495     if (worktree_dir == NULL)
496         worktree_dir = g_build_filename (g_get_home_dir(), "seafile", NULL);
497 
498     seaf = seafile_session_new (seafile_dir, worktree_dir, config_dir);
499     if (!seaf) {
500         seaf_warning ("Failed to create seafile session.\n");
501         exit (1);
502     }
503 
504     seaf_message ("starting seafile client "SEAFILE_CLIENT_VERSION"\n");
505 #if defined(SEAFILE_SOURCE_COMMIT_ID)
506     seaf_message ("seafile source code version "SEAFILE_SOURCE_COMMIT_ID"\n");
507 #endif
508 
509     g_free (seafile_dir);
510     g_free (worktree_dir);
511     g_free (logfile);
512 
513 #ifndef WIN32
514     set_signal_handlers (seaf);
515 #else
516     WSADATA wsadata;
517     WSAStartup (0x0101, &wsadata);
518 #endif
519 
520 #ifndef USE_GPL_CRYPTO
521     seafile_curl_init();
522 #endif
523     seafile_session_prepare (seaf);
524     seafile_session_start (seaf);
525 
526     if (start_searpc_server () < 0) {
527         seaf_warning ("Failed to start searpc server.\n");
528         exit (1);
529     }
530 
531     seaf_message ("rpc server started.\n");
532 
533 
534     seafile_session_config_set_string (seaf, "wktree", seaf->worktree_dir);
535 
536     event_base_loop (seaf->ev_base, 0);
537 
538 #ifndef USE_GPL_CRYPTO
539     seafile_curl_deinit();
540 #endif
541 
542     return 0;
543 }
544