1 /*
2 * This file Copyright (C) 2008-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 */
8
9 #include <errno.h>
10 #include <stdio.h> /* printf */
11 #include <stdlib.h> /* atoi */
12
13 #ifdef HAVE_SYSLOG
14 #include <syslog.h>
15 #endif
16
17 #ifdef _WIN32
18 #include <process.h> /* getpid */
19 #else
20 #include <unistd.h> /* getpid */
21 #endif
22
23 #include <event2/event.h>
24
25 #include <libtransmission/transmission.h>
26 #include <libtransmission/error.h>
27 #include <libtransmission/file.h>
28 #include <libtransmission/tr-getopt.h>
29 #include <libtransmission/log.h>
30 #include <libtransmission/utils.h>
31 #include <libtransmission/variant.h>
32 #include <libtransmission/version.h>
33 #include <libtransmission/watchdir.h>
34
35 #ifdef USE_SYSTEMD
36
37 #include <systemd/sd-daemon.h>
38
39 #else
40
sd_notify(int status UNUSED,char const * str UNUSED)41 static void sd_notify(int status UNUSED, char const* str UNUSED)
42 {
43 }
44
sd_notifyf(int status UNUSED,char const * fmt UNUSED,...)45 static void sd_notifyf(int status UNUSED, char const* fmt UNUSED, ...)
46 {
47 }
48
49 #endif
50
51 #include "daemon.h"
52
53 #define MY_NAME "transmission-daemon"
54
55 #define MEM_K 1024
56 #define MEM_K_STR "KiB"
57 #define MEM_M_STR "MiB"
58 #define MEM_G_STR "GiB"
59 #define MEM_T_STR "TiB"
60
61 #define DISK_K 1000
62 #define DISK_B_STR "B"
63 #define DISK_K_STR "kB"
64 #define DISK_M_STR "MB"
65 #define DISK_G_STR "GB"
66 #define DISK_T_STR "TB"
67
68 #define SPEED_K 1000
69 #define SPEED_B_STR "B/s"
70 #define SPEED_K_STR "kB/s"
71 #define SPEED_M_STR "MB/s"
72 #define SPEED_G_STR "GB/s"
73 #define SPEED_T_STR "TB/s"
74
75 static bool seenHUP = false;
76 static char const* logfileName = NULL;
77 static tr_sys_file_t logfile = TR_BAD_SYS_FILE;
78 static tr_session* mySession = NULL;
79 static tr_quark key_pidfile = 0;
80 static tr_quark key_watch_dir_force_generic = 0;
81 static struct event_base* ev_base = NULL;
82
83 /***
84 **** Config File
85 ***/
86
getUsage(void)87 static char const* getUsage(void)
88 {
89 return "Transmission " LONG_VERSION_STRING " https://transmissionbt.com/\n"
90 "A fast and easy BitTorrent client\n"
91 "\n"
92 MY_NAME " is a headless Transmission session\n"
93 "that can be controlled via transmission-remote\n"
94 "or the web interface.\n"
95 "\n"
96 "Usage: " MY_NAME " [options]";
97 }
98
99 static struct tr_option const options[] =
100 {
101 { 'a', "allowed", "Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a", true, "<list>" },
102 { 'b', "blocklist", "Enable peer blocklists", "b", false, NULL },
103 { 'B', "no-blocklist", "Disable peer blocklists", "B", false, NULL },
104 { 'c', "watch-dir", "Where to watch for new .torrent files", "c", true, "<directory>" },
105 { 'C', "no-watch-dir", "Disable the watch-dir", "C", false, NULL },
106 { 941, "incomplete-dir", "Where to store new torrents until they're complete", NULL, true, "<directory>" },
107 { 942, "no-incomplete-dir", "Don't store incomplete torrents in a different location", NULL, false, NULL },
108 { 'd', "dump-settings", "Dump the settings and exit", "d", false, NULL },
109 { 'e', "logfile", "Dump the log messages to this filename", "e", true, "<filename>" },
110 { 'f', "foreground", "Run in the foreground instead of daemonizing", "f", false, NULL },
111 { 'g', "config-dir", "Where to look for configuration files", "g", true, "<path>" },
112 { 'p', "port", "RPC port (Default: " TR_DEFAULT_RPC_PORT_STR ")", "p", true, "<port>" },
113 { 't', "auth", "Require authentication", "t", false, NULL },
114 { 'T', "no-auth", "Don't require authentication", "T", false, NULL },
115 { 'u', "username", "Set username for authentication", "u", true, "<username>" },
116 { 'v', "password", "Set password for authentication", "v", true, "<password>" },
117 { 'V', "version", "Show version number and exit", "V", false, NULL },
118 { 810, "log-error", "Show error messages", NULL, false, NULL },
119 { 811, "log-info", "Show error and info messages", NULL, false, NULL },
120 { 812, "log-debug", "Show error, info, and debug messages", NULL, false, NULL },
121 { 'w', "download-dir", "Where to save downloaded data", "w", true, "<path>" },
122 { 800, "paused", "Pause all torrents on startup", NULL, false, NULL },
123 { 'o', "dht", "Enable distributed hash tables (DHT)", "o", false, NULL },
124 { 'O', "no-dht", "Disable distributed hash tables (DHT)", "O", false, NULL },
125 { 'y', "lpd", "Enable local peer discovery (LPD)", "y", false, NULL },
126 { 'Y', "no-lpd", "Disable local peer discovery (LPD)", "Y", false, NULL },
127 { 830, "utp", "Enable uTP for peer connections", NULL, false, NULL },
128 { 831, "no-utp", "Disable uTP for peer connections", NULL, false, NULL },
129 { 'P', "peerport", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "P", true, "<port>" },
130 { 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", false, NULL },
131 { 'M', "no-portmap", "Disable portmapping", "M", false, NULL },
132 { 'L', "peerlimit-global", "Maximum overall number of peers (Default: " TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ")", "L", true,
133 "<limit>" },
134 { 'l', "peerlimit-torrent", "Maximum number of peers per torrent (Default: " TR_DEFAULT_PEER_LIMIT_TORRENT_STR ")", "l",
135 true, "<limit>" },
136 { 910, "encryption-required", "Encrypt all peer connections", "er", false, NULL },
137 { 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", false, NULL },
138 { 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", false, NULL },
139 { 'i', "bind-address-ipv4", "Where to listen for peer connections", "i", true, "<ipv4 addr>" },
140 { 'I', "bind-address-ipv6", "Where to listen for peer connections", "I", true, "<ipv6 addr>" },
141 { 'r', "rpc-bind-address", "Where to listen for RPC connections", "r", true, "<ip addr>" },
142 { 953, "global-seedratio", "All torrents, unless overridden by a per-torrent setting, should seed until a specific ratio",
143 "gsr", true, "ratio" },
144 { 954, "no-global-seedratio", "All torrents, unless overridden by a per-torrent setting, should seed regardless of ratio",
145 "GSR", false, NULL },
146 { 'x', "pid-file", "Enable PID file", "x", true, "<pid-file>" },
147 { 0, NULL, NULL, NULL, false, NULL }
148 };
149
reopen_log_file(char const * filename)150 static bool reopen_log_file(char const* filename)
151 {
152 tr_error* error = NULL;
153 tr_sys_file_t const old_log_file = logfile;
154 tr_sys_file_t const new_log_file = tr_sys_file_open(filename, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_APPEND,
155 0666, &error);
156
157 if (new_log_file == TR_BAD_SYS_FILE)
158 {
159 fprintf(stderr, "Couldn't (re)open log file \"%s\": %s\n", filename, error->message);
160 tr_error_free(error);
161 return false;
162 }
163
164 logfile = new_log_file;
165
166 if (old_log_file != TR_BAD_SYS_FILE)
167 {
168 tr_sys_file_close(old_log_file, NULL);
169 }
170
171 return true;
172 }
173
getConfigDir(int argc,char const * const * argv)174 static char const* getConfigDir(int argc, char const* const* argv)
175 {
176 int c;
177 char const* configDir = NULL;
178 char const* optarg;
179 int const ind = tr_optind;
180
181 while ((c = tr_getopt(getUsage(), argc, argv, options, &optarg)) != TR_OPT_DONE)
182 {
183 if (c == 'g')
184 {
185 configDir = optarg;
186 break;
187 }
188 }
189
190 tr_optind = ind;
191
192 if (configDir == NULL)
193 {
194 configDir = tr_getDefaultConfigDir(MY_NAME);
195 }
196
197 return configDir;
198 }
199
onFileAdded(tr_watchdir_t dir,char const * name,void * context)200 static tr_watchdir_status onFileAdded(tr_watchdir_t dir, char const* name, void* context)
201 {
202 tr_session* session = context;
203
204 if (!tr_str_has_suffix(name, ".torrent"))
205 {
206 return TR_WATCHDIR_IGNORE;
207 }
208
209 char* filename = tr_buildPath(tr_watchdir_get_path(dir), name, NULL);
210 tr_ctor* ctor = tr_ctorNew(session);
211 int err = tr_ctorSetMetainfoFromFile(ctor, filename);
212
213 if (err == 0)
214 {
215 tr_torrentNew(ctor, &err, NULL);
216
217 if (err == TR_PARSE_ERR)
218 {
219 tr_logAddError("Error parsing .torrent file \"%s\"", name);
220 }
221 else
222 {
223 bool trash = false;
224 bool const test = tr_ctorGetDeleteSource(ctor, &trash);
225
226 tr_logAddInfo("Parsing .torrent file successful \"%s\"", name);
227
228 if (test && trash)
229 {
230 tr_error* error = NULL;
231
232 tr_logAddInfo("Deleting input .torrent file \"%s\"", name);
233
234 if (!tr_sys_path_remove(filename, &error))
235 {
236 tr_logAddError("Error deleting .torrent file: %s", error->message);
237 tr_error_free(error);
238 }
239 }
240 else
241 {
242 char* new_filename = tr_strdup_printf("%s.added", filename);
243 tr_sys_path_rename(filename, new_filename, NULL);
244 tr_free(new_filename);
245 }
246 }
247 }
248 else
249 {
250 err = TR_PARSE_ERR;
251 }
252
253 tr_ctorFree(ctor);
254 tr_free(filename);
255
256 return err == TR_PARSE_ERR ? TR_WATCHDIR_RETRY : TR_WATCHDIR_ACCEPT;
257 }
258
printMessage(tr_sys_file_t logfile,int level,char const * name,char const * message,char const * file,int line)259 static void printMessage(tr_sys_file_t logfile, int level, char const* name, char const* message, char const* file, int line)
260 {
261 if (logfile != TR_BAD_SYS_FILE)
262 {
263 char timestr[64];
264 tr_logGetTimeStr(timestr, sizeof(timestr));
265
266 if (name != NULL)
267 {
268 tr_sys_file_write_fmt(logfile, "[%s] %s %s (%s:%d)" TR_NATIVE_EOL_STR, NULL, timestr, name, message, file, line);
269 }
270 else
271 {
272 tr_sys_file_write_fmt(logfile, "[%s] %s (%s:%d)" TR_NATIVE_EOL_STR, NULL, timestr, message, file, line);
273 }
274 }
275
276 #ifdef HAVE_SYSLOG
277
278 else /* daemon... write to syslog */
279 {
280 int priority;
281
282 /* figure out the syslog priority */
283 switch (level)
284 {
285 case TR_LOG_ERROR:
286 priority = LOG_ERR;
287 break;
288
289 case TR_LOG_DEBUG:
290 priority = LOG_DEBUG;
291 break;
292
293 default:
294 priority = LOG_INFO;
295 break;
296 }
297
298 if (name != NULL)
299 {
300 syslog(priority, "%s %s (%s:%d)", name, message, file, line);
301 }
302 else
303 {
304 syslog(priority, "%s (%s:%d)", message, file, line);
305 }
306 }
307
308 #else
309
310 (void)level;
311
312 #endif
313 }
314
pumpLogMessages(tr_sys_file_t logfile)315 static void pumpLogMessages(tr_sys_file_t logfile)
316 {
317 tr_log_message* list = tr_logGetQueue();
318
319 for (tr_log_message const* l = list; l != NULL; l = l->next)
320 {
321 printMessage(logfile, l->level, l->name, l->message, l->file, l->line);
322 }
323
324 if (logfile != TR_BAD_SYS_FILE)
325 {
326 tr_sys_file_flush(logfile, NULL);
327 }
328
329 tr_logFreeQueue(list);
330 }
331
reportStatus(void)332 static void reportStatus(void)
333 {
334 double const up = tr_sessionGetRawSpeed_KBps(mySession, TR_UP);
335 double const dn = tr_sessionGetRawSpeed_KBps(mySession, TR_DOWN);
336
337 if (up > 0 || dn > 0)
338 {
339 sd_notifyf(0, "STATUS=Uploading %.2f KBps, Downloading %.2f KBps.\n", up, dn);
340 }
341 else
342 {
343 sd_notify(0, "STATUS=Idle.\n");
344 }
345 }
346
periodicUpdate(evutil_socket_t fd UNUSED,short what UNUSED,void * context UNUSED)347 static void periodicUpdate(evutil_socket_t fd UNUSED, short what UNUSED, void* context UNUSED)
348 {
349 pumpLogMessages(logfile);
350 reportStatus();
351 }
352
on_rpc_callback(tr_session * session UNUSED,tr_rpc_callback_type type,struct tr_torrent * tor UNUSED,void * user_data UNUSED)353 static tr_rpc_callback_status on_rpc_callback(tr_session* session UNUSED, tr_rpc_callback_type type,
354 struct tr_torrent* tor UNUSED, void* user_data UNUSED)
355 {
356 if (type == TR_RPC_SESSION_CLOSE)
357 {
358 event_base_loopexit(ev_base, NULL);
359 }
360
361 return TR_RPC_OK;
362 }
363
parse_args(int argc,char const ** argv,tr_variant * settings,bool * paused,bool * dump_settings,bool * foreground,int * exit_code)364 static bool parse_args(int argc, char const** argv, tr_variant* settings, bool* paused, bool* dump_settings, bool* foreground,
365 int* exit_code)
366 {
367 int c;
368 char const* optarg;
369
370 *paused = false;
371 *dump_settings = false;
372 *foreground = false;
373
374 tr_optind = 1;
375
376 while ((c = tr_getopt(getUsage(), argc, argv, options, &optarg)) != TR_OPT_DONE)
377 {
378 switch (c)
379 {
380 case 'a':
381 tr_variantDictAddStr(settings, TR_KEY_rpc_whitelist, optarg);
382 tr_variantDictAddBool(settings, TR_KEY_rpc_whitelist_enabled, true);
383 break;
384
385 case 'b':
386 tr_variantDictAddBool(settings, TR_KEY_blocklist_enabled, true);
387 break;
388
389 case 'B':
390 tr_variantDictAddBool(settings, TR_KEY_blocklist_enabled, false);
391 break;
392
393 case 'c':
394 tr_variantDictAddStr(settings, TR_KEY_watch_dir, optarg);
395 tr_variantDictAddBool(settings, TR_KEY_watch_dir_enabled, true);
396 break;
397
398 case 'C':
399 tr_variantDictAddBool(settings, TR_KEY_watch_dir_enabled, false);
400 break;
401
402 case 941:
403 tr_variantDictAddStr(settings, TR_KEY_incomplete_dir, optarg);
404 tr_variantDictAddBool(settings, TR_KEY_incomplete_dir_enabled, true);
405 break;
406
407 case 942:
408 tr_variantDictAddBool(settings, TR_KEY_incomplete_dir_enabled, false);
409 break;
410
411 case 'd':
412 *dump_settings = true;
413 break;
414
415 case 'e':
416 if (reopen_log_file(optarg))
417 {
418 logfileName = optarg;
419 }
420
421 break;
422
423 case 'f':
424 *foreground = true;
425 break;
426
427 case 'g': /* handled above */
428 break;
429
430 case 'V': /* version */
431 fprintf(stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING);
432 *exit_code = 0;
433 return false;
434
435 case 'o':
436 tr_variantDictAddBool(settings, TR_KEY_dht_enabled, true);
437 break;
438
439 case 'O':
440 tr_variantDictAddBool(settings, TR_KEY_dht_enabled, false);
441 break;
442
443 case 'p':
444 tr_variantDictAddInt(settings, TR_KEY_rpc_port, atoi(optarg));
445 break;
446
447 case 't':
448 tr_variantDictAddBool(settings, TR_KEY_rpc_authentication_required, true);
449 break;
450
451 case 'T':
452 tr_variantDictAddBool(settings, TR_KEY_rpc_authentication_required, false);
453 break;
454
455 case 'u':
456 tr_variantDictAddStr(settings, TR_KEY_rpc_username, optarg);
457 break;
458
459 case 'v':
460 tr_variantDictAddStr(settings, TR_KEY_rpc_password, optarg);
461 break;
462
463 case 'w':
464 tr_variantDictAddStr(settings, TR_KEY_download_dir, optarg);
465 break;
466
467 case 'P':
468 tr_variantDictAddInt(settings, TR_KEY_peer_port, atoi(optarg));
469 break;
470
471 case 'm':
472 tr_variantDictAddBool(settings, TR_KEY_port_forwarding_enabled, true);
473 break;
474
475 case 'M':
476 tr_variantDictAddBool(settings, TR_KEY_port_forwarding_enabled, false);
477 break;
478
479 case 'L':
480 tr_variantDictAddInt(settings, TR_KEY_peer_limit_global, atoi(optarg));
481 break;
482
483 case 'l':
484 tr_variantDictAddInt(settings, TR_KEY_peer_limit_per_torrent, atoi(optarg));
485 break;
486
487 case 800:
488 *paused = true;
489 break;
490
491 case 910:
492 tr_variantDictAddInt(settings, TR_KEY_encryption, TR_ENCRYPTION_REQUIRED);
493 break;
494
495 case 911:
496 tr_variantDictAddInt(settings, TR_KEY_encryption, TR_ENCRYPTION_PREFERRED);
497 break;
498
499 case 912:
500 tr_variantDictAddInt(settings, TR_KEY_encryption, TR_CLEAR_PREFERRED);
501 break;
502
503 case 'i':
504 tr_variantDictAddStr(settings, TR_KEY_bind_address_ipv4, optarg);
505 break;
506
507 case 'I':
508 tr_variantDictAddStr(settings, TR_KEY_bind_address_ipv6, optarg);
509 break;
510
511 case 'r':
512 tr_variantDictAddStr(settings, TR_KEY_rpc_bind_address, optarg);
513 break;
514
515 case 953:
516 tr_variantDictAddReal(settings, TR_KEY_ratio_limit, atof(optarg));
517 tr_variantDictAddBool(settings, TR_KEY_ratio_limit_enabled, true);
518 break;
519
520 case 954:
521 tr_variantDictAddBool(settings, TR_KEY_ratio_limit_enabled, false);
522 break;
523
524 case 'x':
525 tr_variantDictAddStr(settings, key_pidfile, optarg);
526 break;
527
528 case 'y':
529 tr_variantDictAddBool(settings, TR_KEY_lpd_enabled, true);
530 break;
531
532 case 'Y':
533 tr_variantDictAddBool(settings, TR_KEY_lpd_enabled, false);
534 break;
535
536 case 810:
537 tr_variantDictAddInt(settings, TR_KEY_message_level, TR_LOG_ERROR);
538 break;
539
540 case 811:
541 tr_variantDictAddInt(settings, TR_KEY_message_level, TR_LOG_INFO);
542 break;
543
544 case 812:
545 tr_variantDictAddInt(settings, TR_KEY_message_level, TR_LOG_DEBUG);
546 break;
547
548 case 830:
549 tr_variantDictAddBool(settings, TR_KEY_utp_enabled, true);
550 break;
551
552 case 831:
553 tr_variantDictAddBool(settings, TR_KEY_utp_enabled, false);
554 break;
555
556 default:
557 tr_getopt_usage(MY_NAME, getUsage(), options);
558 *exit_code = 0;
559 return false;
560 }
561 }
562
563 return true;
564 }
565
566 struct daemon_data
567 {
568 tr_variant settings;
569 char const* configDir;
570 bool paused;
571 };
572
daemon_reconfigure(void * arg UNUSED)573 static void daemon_reconfigure(void* arg UNUSED)
574 {
575 if (mySession == NULL)
576 {
577 tr_logAddInfo("Deferring reload until session is fully started.");
578 seenHUP = true;
579 }
580 else
581 {
582 tr_variant settings;
583 char const* configDir;
584
585 /* reopen the logfile to allow for log rotation */
586 if (logfileName != NULL)
587 {
588 reopen_log_file(logfileName);
589 }
590
591 configDir = tr_sessionGetConfigDir(mySession);
592 tr_logAddInfo("Reloading settings from \"%s\"", configDir);
593 tr_variantInitDict(&settings, 0);
594 tr_variantDictAddBool(&settings, TR_KEY_rpc_enabled, true);
595 tr_sessionLoadSettings(&settings, configDir, MY_NAME);
596 tr_sessionSet(mySession, &settings);
597 tr_variantFree(&settings);
598 tr_sessionReloadBlocklists(mySession);
599 }
600 }
601
daemon_stop(void * arg UNUSED)602 static void daemon_stop(void* arg UNUSED)
603 {
604 event_base_loopexit(ev_base, NULL);
605 }
606
daemon_start(void * raw_arg,bool foreground)607 static int daemon_start(void* raw_arg, bool foreground)
608 {
609 bool boolVal;
610 char const* pid_filename;
611 bool pidfile_created = false;
612 tr_session* session = NULL;
613 struct event* status_ev = NULL;
614 tr_watchdir_t watchdir = NULL;
615
616 struct daemon_data* const arg = raw_arg;
617 tr_variant* const settings = &arg->settings;
618 char const* const configDir = arg->configDir;
619
620 #ifndef HAVE_SYSLOG
621 (void)foreground;
622 #endif
623
624 sd_notifyf(0, "MAINPID=%d\n", (int)getpid());
625
626 /* should go before libevent calls */
627 tr_net_init();
628
629 /* setup event state */
630 ev_base = event_base_new();
631
632 if (ev_base == NULL)
633 {
634 char buf[256];
635 tr_snprintf(buf, sizeof(buf), "Failed to init daemon event state: %s", tr_strerror(errno));
636 printMessage(logfile, TR_LOG_ERROR, MY_NAME, buf, __FILE__, __LINE__);
637 return 1;
638 }
639
640 /* start the session */
641 tr_formatter_mem_init(MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR);
642 tr_formatter_size_init(DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR);
643 tr_formatter_speed_init(SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR);
644 session = tr_sessionInit(configDir, true, settings);
645 tr_sessionSetRPCCallback(session, on_rpc_callback, NULL);
646 tr_logAddNamedInfo(NULL, "Using settings from \"%s\"", configDir);
647 tr_sessionSaveSettings(session, configDir, settings);
648
649 pid_filename = NULL;
650 tr_variantDictFindStr(settings, key_pidfile, &pid_filename, NULL);
651
652 if (!tr_str_is_empty(pid_filename))
653 {
654 tr_error* error = NULL;
655 tr_sys_file_t fp = tr_sys_file_open(pid_filename, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0666,
656 &error);
657
658 if (fp != TR_BAD_SYS_FILE)
659 {
660 tr_sys_file_write_fmt(fp, "%d", NULL, (int)getpid());
661 tr_sys_file_close(fp, NULL);
662 tr_logAddInfo("Saved pidfile \"%s\"", pid_filename);
663 pidfile_created = true;
664 }
665 else
666 {
667 tr_logAddError("Unable to save pidfile \"%s\": %s", pid_filename, error->message);
668 tr_error_free(error);
669 }
670 }
671
672 if (tr_variantDictFindBool(settings, TR_KEY_rpc_authentication_required, &boolVal) && boolVal)
673 {
674 tr_logAddNamedInfo(MY_NAME, "requiring authentication");
675 }
676
677 mySession = session;
678
679 /* If we got a SIGHUP during startup, process that now. */
680 if (seenHUP)
681 {
682 daemon_reconfigure(arg);
683 }
684
685 /* maybe add a watchdir */
686 if (tr_variantDictFindBool(settings, TR_KEY_watch_dir_enabled, &boolVal) && boolVal)
687 {
688 char const* dir;
689 bool force_generic;
690
691 if (!tr_variantDictFindBool(settings, key_watch_dir_force_generic, &force_generic))
692 {
693 force_generic = false;
694 }
695
696 if (tr_variantDictFindStr(settings, TR_KEY_watch_dir, &dir, NULL) && !tr_str_is_empty(dir))
697 {
698 tr_logAddInfo("Watching \"%s\" for new .torrent files", dir);
699
700 if ((watchdir = tr_watchdir_new(dir, &onFileAdded, mySession, ev_base, force_generic)) == NULL)
701 {
702 goto cleanup;
703 }
704 }
705 }
706
707 /* load the torrents */
708 {
709 tr_torrent** torrents;
710 tr_ctor* ctor = tr_ctorNew(mySession);
711
712 if (arg->paused)
713 {
714 tr_ctorSetPaused(ctor, TR_FORCE, true);
715 }
716
717 torrents = tr_sessionLoadTorrents(mySession, ctor, NULL);
718 tr_free(torrents);
719 tr_ctorFree(ctor);
720 }
721
722 #ifdef HAVE_SYSLOG
723
724 if (!foreground)
725 {
726 openlog(MY_NAME, LOG_CONS | LOG_PID, LOG_DAEMON);
727 }
728
729 #endif
730
731 /* Create new timer event to report daemon status */
732 {
733 struct timeval one_sec = { .tv_sec = 1, .tv_usec = 0 };
734 status_ev = event_new(ev_base, -1, EV_PERSIST, &periodicUpdate, NULL);
735
736 if (status_ev == NULL)
737 {
738 tr_logAddError("Failed to create status event %s", tr_strerror(errno));
739 goto cleanup;
740 }
741
742 if (event_add(status_ev, &one_sec) == -1)
743 {
744 tr_logAddError("Failed to add status event %s", tr_strerror(errno));
745 goto cleanup;
746 }
747 }
748
749 sd_notify(0, "READY=1\n");
750
751 /* Run daemon event loop */
752 if (event_base_dispatch(ev_base) == -1)
753 {
754 tr_logAddError("Failed to launch daemon event loop: %s", tr_strerror(errno));
755 goto cleanup;
756 }
757
758 cleanup:
759 sd_notify(0, "STATUS=Closing transmission session...\n");
760 printf("Closing transmission session...");
761
762 tr_watchdir_free(watchdir);
763
764 if (status_ev != NULL)
765 {
766 event_del(status_ev);
767 event_free(status_ev);
768 }
769
770 event_base_free(ev_base);
771
772 tr_sessionSaveSettings(mySession, configDir, settings);
773 tr_sessionClose(mySession);
774 pumpLogMessages(logfile);
775 printf(" done.\n");
776
777 /* shutdown */
778 #ifdef HAVE_SYSLOG
779
780 if (!foreground)
781 {
782 syslog(LOG_INFO, "%s", "Closing session");
783 closelog();
784 }
785
786 #endif
787
788 /* cleanup */
789 if (pidfile_created)
790 {
791 tr_sys_path_remove(pid_filename, NULL);
792 }
793
794 sd_notify(0, "STATUS=\n");
795
796 return 0;
797 }
798
init_daemon_data(int argc,char * argv[],struct daemon_data * data,bool * foreground,int * ret)799 static bool init_daemon_data(int argc, char* argv[], struct daemon_data* data, bool* foreground, int* ret)
800 {
801 data->configDir = getConfigDir(argc, (char const* const*)argv);
802
803 /* load settings from defaults + config file */
804 tr_variantInitDict(&data->settings, 0);
805 tr_variantDictAddBool(&data->settings, TR_KEY_rpc_enabled, true);
806 bool const loaded = tr_sessionLoadSettings(&data->settings, data->configDir, MY_NAME);
807
808 bool dumpSettings;
809
810 *ret = 0;
811
812 /* overwrite settings from the command line */
813 if (!parse_args(argc, (char const**)argv, &data->settings, &data->paused, &dumpSettings, foreground, ret))
814 {
815 goto exit_early;
816 }
817
818 if (*foreground && logfile == TR_BAD_SYS_FILE)
819 {
820 logfile = tr_sys_file_get_std(TR_STD_SYS_FILE_ERR, NULL);
821 }
822
823 if (!loaded)
824 {
825 printMessage(logfile, TR_LOG_ERROR, MY_NAME, "Error loading config file -- exiting.", __FILE__, __LINE__);
826 *ret = 1;
827 goto exit_early;
828 }
829
830 if (dumpSettings)
831 {
832 char* str = tr_variantToStr(&data->settings, TR_VARIANT_FMT_JSON, NULL);
833 fprintf(stderr, "%s", str);
834 tr_free(str);
835 goto exit_early;
836 }
837
838 return true;
839
840 exit_early:
841 tr_variantFree(&data->settings);
842 return false;
843 }
844
tr_main(int argc,char * argv[])845 int tr_main(int argc, char* argv[])
846 {
847 key_pidfile = tr_quark_new("pidfile", TR_BAD_SIZE);
848 key_watch_dir_force_generic = tr_quark_new("watch-dir-force-generic", TR_BAD_SIZE);
849
850 struct daemon_data data;
851 bool foreground;
852 int ret;
853
854 if (!init_daemon_data(argc, argv, &data, &foreground, &ret))
855 {
856 return ret;
857 }
858
859 dtr_callbacks const cb =
860 {
861 .on_start = &daemon_start,
862 .on_stop = &daemon_stop,
863 .on_reconfigure = &daemon_reconfigure,
864 };
865
866 tr_error* error = NULL;
867
868 if (!dtr_daemon(&cb, &data, foreground, &ret, &error))
869 {
870 char buf[256];
871 tr_snprintf(buf, sizeof(buf), "Failed to daemonize: %s", error->message);
872 printMessage(logfile, TR_LOG_ERROR, MY_NAME, buf, __FILE__, __LINE__);
873 tr_error_free(error);
874 }
875
876 tr_variantFree(&data.settings);
877 return ret;
878 }
879