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