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