miniupnpd 1.9 (20160113)
[tomato.git] / release / src / router / transmission / daemon / daemon.c
blob0d783c27b5ab18f9cb101a18b8610d448ac78131
1 /*
2 * This file Copyright (C) 2008-2014 Mnemosyne LLC
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
7 * $Id: daemon.c 14270 2014-05-05 21:08:30Z jordan $
8 */
10 #include <errno.h>
11 #include <stdio.h> /* printf */
12 #include <stdlib.h> /* exit, atoi */
14 #include <fcntl.h> /* open */
15 #include <signal.h>
16 #ifdef HAVE_SYSLOG
17 #include <syslog.h>
18 #endif
19 #include <unistd.h> /* daemon */
21 #include <event2/buffer.h>
22 #include <event2/event.h>
24 #include <libtransmission/transmission.h>
25 #include <libtransmission/tr-getopt.h>
26 #include <libtransmission/log.h>
27 #include <libtransmission/utils.h>
28 #include <libtransmission/variant.h>
29 #include <libtransmission/version.h>
31 #ifdef USE_SYSTEMD_DAEMON
32 #include <systemd/sd-daemon.h>
33 #else
34 static void sd_notify (int status UNUSED, const char * str UNUSED) { }
35 static void sd_notifyf (int status UNUSED, const char * fmt UNUSED, ...) { }
36 #endif
38 #include "watch.h"
40 #define MY_NAME "transmission-daemon"
42 #define MEM_K 1024
43 #define MEM_K_STR "KiB"
44 #define MEM_M_STR "MiB"
45 #define MEM_G_STR "GiB"
46 #define MEM_T_STR "TiB"
48 #define DISK_K 1000
49 #define DISK_B_STR "B"
50 #define DISK_K_STR "kB"
51 #define DISK_M_STR "MB"
52 #define DISK_G_STR "GB"
53 #define DISK_T_STR "TB"
55 #define SPEED_K 1000
56 #define SPEED_B_STR "B/s"
57 #define SPEED_K_STR "kB/s"
58 #define SPEED_M_STR "MB/s"
59 #define SPEED_G_STR "GB/s"
60 #define SPEED_T_STR "TB/s"
62 #define LOGFILE_MODE_STR "a+"
64 static bool paused = false;
65 static bool seenHUP = false;
66 static const char *logfileName = NULL;
67 static FILE *logfile = NULL;
68 static tr_session * mySession = NULL;
69 static tr_quark key_pidfile = 0;
70 static struct event_base *ev_base = NULL;
72 /***
73 **** Config File
74 ***/
76 static const char *
77 getUsage (void)
79 return "Transmission " LONG_VERSION_STRING
80 " http://www.transmissionbt.com/\n"
81 "A fast and easy BitTorrent client\n"
82 "\n"
83 MY_NAME " is a headless Transmission session\n"
84 "that can be controlled via transmission-remote\n"
85 "or the web interface.\n"
86 "\n"
87 "Usage: " MY_NAME " [options]";
90 static const struct tr_option options[] =
93 { 'a', "allowed", "Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a", 1, "<list>" },
94 { 'b', "blocklist", "Enable peer blocklists", "b", 0, NULL },
95 { 'B', "no-blocklist", "Disable peer blocklists", "B", 0, NULL },
96 { 'c', "watch-dir", "Where to watch for new .torrent files", "c", 1, "<directory>" },
97 { 'C', "no-watch-dir", "Disable the watch-dir", "C", 0, NULL },
98 { 941, "incomplete-dir", "Where to store new torrents until they're complete", NULL, 1, "<directory>" },
99 { 942, "no-incomplete-dir", "Don't store incomplete torrents in a different location", NULL, 0, NULL },
100 { 'd', "dump-settings", "Dump the settings and exit", "d", 0, NULL },
101 { 'e', "logfile", "Dump the log messages to this filename", "e", 1, "<filename>" },
102 { 'f', "foreground", "Run in the foreground instead of daemonizing", "f", 0, NULL },
103 { 'g', "config-dir", "Where to look for configuration files", "g", 1, "<path>" },
104 { 'p', "port", "RPC port (Default: " TR_DEFAULT_RPC_PORT_STR ")", "p", 1, "<port>" },
105 { 't', "auth", "Require authentication", "t", 0, NULL },
106 { 'T', "no-auth", "Don't require authentication", "T", 0, NULL },
107 { 'u', "username", "Set username for authentication", "u", 1, "<username>" },
108 { 'v', "password", "Set password for authentication", "v", 1, "<password>" },
109 { 'V', "version", "Show version number and exit", "V", 0, NULL },
110 { 810, "log-error", "Show error messages", NULL, 0, NULL },
111 { 811, "log-info", "Show error and info messages", NULL, 0, NULL },
112 { 812, "log-debug", "Show error, info, and debug messages", NULL, 0, NULL },
113 { 'w', "download-dir", "Where to save downloaded data", "w", 1, "<path>" },
114 { 800, "paused", "Pause all torrents on startup", NULL, 0, NULL },
115 { 'o', "dht", "Enable distributed hash tables (DHT)", "o", 0, NULL },
116 { 'O', "no-dht", "Disable distributed hash tables (DHT)", "O", 0, NULL },
117 { 'y', "lpd", "Enable local peer discovery (LPD)", "y", 0, NULL },
118 { 'Y', "no-lpd", "Disable local peer discovery (LPD)", "Y", 0, NULL },
119 { 830, "utp", "Enable uTP for peer connections", NULL, 0, NULL },
120 { 831, "no-utp", "Disable uTP for peer connections", NULL, 0, NULL },
121 { 'P', "peerport", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "P", 1, "<port>" },
122 { 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", 0, NULL },
123 { 'M', "no-portmap", "Disable portmapping", "M", 0, NULL },
124 { 'L', "peerlimit-global", "Maximum overall number of peers (Default: " TR_DEFAULT_PEER_LIMIT_GLOBAL_STR ")", "L", 1, "<limit>" },
125 { 'l', "peerlimit-torrent", "Maximum number of peers per torrent (Default: " TR_DEFAULT_PEER_LIMIT_TORRENT_STR ")", "l", 1, "<limit>" },
126 { 910, "encryption-required", "Encrypt all peer connections", "er", 0, NULL },
127 { 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", 0, NULL },
128 { 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", 0, NULL },
129 { 'i', "bind-address-ipv4", "Where to listen for peer connections", "i", 1, "<ipv4 addr>" },
130 { 'I', "bind-address-ipv6", "Where to listen for peer connections", "I", 1, "<ipv6 addr>" },
131 { 'r', "rpc-bind-address", "Where to listen for RPC connections", "r", 1, "<ipv4 addr>" },
132 { 953, "global-seedratio", "All torrents, unless overridden by a per-torrent setting, should seed until a specific ratio", "gsr", 1, "ratio" },
133 { 954, "no-global-seedratio", "All torrents, unless overridden by a per-torrent setting, should seed regardless of ratio", "GSR", 0, NULL },
134 { 'x', "pid-file", "Enable PID file", "x", 1, "<pid-file>" },
135 { 0, NULL, NULL, NULL, 0, NULL }
138 static void
139 showUsage (void)
141 tr_getopt_usage (MY_NAME, getUsage (), options);
142 exit (0);
145 static void
146 gotsig (int sig)
148 switch (sig)
150 case SIGHUP:
152 if (!mySession)
154 tr_logAddInfo ("Deferring reload until session is fully started.");
155 seenHUP = true;
157 else
159 tr_variant settings;
160 const char * configDir;
162 /* reopen the logfile to allow for log rotation */
163 if (logfileName) {
164 logfile = freopen (logfileName, LOGFILE_MODE_STR, logfile);
165 if (!logfile)
166 fprintf (stderr, "Couldn't reopen \"%s\": %s\n", logfileName, tr_strerror (errno));
169 configDir = tr_sessionGetConfigDir (mySession);
170 tr_logAddInfo ("Reloading settings from \"%s\"", configDir);
171 tr_variantInitDict (&settings, 0);
172 tr_variantDictAddBool (&settings, TR_KEY_rpc_enabled, true);
173 tr_sessionLoadSettings (&settings, configDir, MY_NAME);
174 tr_sessionSet (mySession, &settings);
175 tr_variantFree (&settings);
176 tr_sessionReloadBlocklists (mySession);
178 break;
181 default:
182 tr_logAddError ("Unexpected signal (%d) in daemon, closing.", sig);
183 /* no break */
185 case SIGINT:
186 case SIGTERM:
187 event_base_loopexit(ev_base, NULL);
188 break;
192 #if defined (WIN32)
193 #define USE_NO_DAEMON
194 #elif !defined (HAVE_DAEMON) || defined (__UCLIBC__)
195 #define USE_TR_DAEMON
196 #else
197 #define USE_OS_DAEMON
198 #endif
200 static int
201 tr_daemon (int nochdir, int noclose)
203 #if defined (USE_OS_DAEMON)
205 return daemon (nochdir, noclose);
207 #elif defined (USE_TR_DAEMON)
209 /* this is loosely based off of glibc's daemon () implementation
210 * http://sourceware.org/git/?p=glibc.git;a=blob_plain;f=misc/daemon.c */
212 switch (fork ()) {
213 case -1: return -1;
214 case 0: break;
215 default: _exit (0);
218 if (setsid () == -1)
219 return -1;
221 if (!nochdir)
222 chdir ("/");
224 if (!noclose) {
225 int fd = open ("/dev/null", O_RDWR, 0);
226 dup2 (fd, STDIN_FILENO);
227 dup2 (fd, STDOUT_FILENO);
228 dup2 (fd, STDERR_FILENO);
229 close (fd);
232 return 0;
234 #else /* USE_NO_DAEMON */
235 return 0;
236 #endif
239 static const char*
240 getConfigDir (int argc, const char ** argv)
242 int c;
243 const char * configDir = NULL;
244 const char * optarg;
245 const int ind = tr_optind;
247 while ((c = tr_getopt (getUsage (), argc, argv, options, &optarg))) {
248 if (c == 'g') {
249 configDir = optarg;
250 break;
254 tr_optind = ind;
256 if (configDir == NULL)
257 configDir = tr_getDefaultConfigDir (MY_NAME);
259 return configDir;
262 static void
263 onFileAdded (tr_session * session, const char * dir, const char * file)
265 char * filename = tr_buildPath (dir, file, NULL);
266 tr_ctor * ctor = tr_ctorNew (session);
267 int err = tr_ctorSetMetainfoFromFile (ctor, filename);
269 if (!err)
271 tr_torrentNew (ctor, &err, NULL);
273 if (err == TR_PARSE_ERR)
274 tr_logAddError ("Error parsing .torrent file \"%s\"", file);
275 else
277 bool trash = false;
278 int test = tr_ctorGetDeleteSource (ctor, &trash);
280 tr_logAddInfo ("Parsing .torrent file successful \"%s\"", file);
282 if (!test && trash)
284 tr_logAddInfo ("Deleting input .torrent file \"%s\"", file);
285 if (tr_remove (filename))
286 tr_logAddError ("Error deleting .torrent file: %s", tr_strerror (errno));
288 else
290 char * new_filename = tr_strdup_printf ("%s.added", filename);
291 tr_rename (filename, new_filename);
292 tr_free (new_filename);
297 tr_ctorFree (ctor);
298 tr_free (filename);
301 static void
302 printMessage (FILE * logfile, int level, const char * name, const char * message, const char * file, int line)
304 if (logfile != NULL)
306 char timestr[64];
307 tr_logGetTimeStr (timestr, sizeof (timestr));
308 if (name)
309 fprintf (logfile, "[%s] %s %s (%s:%d)\n", timestr, name, message, file, line);
310 else
311 fprintf (logfile, "[%s] %s (%s:%d)\n", timestr, message, file, line);
313 #ifdef HAVE_SYSLOG
314 else /* daemon... write to syslog */
316 int priority;
318 /* figure out the syslog priority */
319 switch (level) {
320 case TR_LOG_ERROR: priority = LOG_ERR; break;
321 case TR_LOG_DEBUG: priority = LOG_DEBUG; break;
322 default: priority = LOG_INFO; break;
325 if (name)
326 syslog (priority, "%s %s (%s:%d)", name, message, file, line);
327 else
328 syslog (priority, "%s (%s:%d)", message, file, line);
330 #endif
333 static void
334 pumpLogMessages (FILE * logfile)
336 const tr_log_message * l;
337 tr_log_message * list = tr_logGetQueue ();
339 for (l=list; l!=NULL; l=l->next)
340 printMessage (logfile, l->level, l->name, l->message, l->file, l->line);
342 if (logfile != NULL)
343 fflush (logfile);
345 tr_logFreeQueue (list);
348 static void
349 reportStatus (void)
351 const double up = tr_sessionGetRawSpeed_KBps (mySession, TR_UP);
352 const double dn = tr_sessionGetRawSpeed_KBps (mySession, TR_DOWN);
354 if (up>0 || dn>0)
355 sd_notifyf (0, "STATUS=Uploading %.2f KBps, Downloading %.2f KBps.\n", up, dn);
356 else
357 sd_notify (0, "STATUS=Idle.\n");
360 static void
361 periodicUpdate (evutil_socket_t fd UNUSED, short what UNUSED, void *watchdir)
363 dtr_watchdir_update (watchdir);
365 pumpLogMessages (logfile);
367 reportStatus ();
370 static tr_rpc_callback_status
371 on_rpc_callback (tr_session * session UNUSED,
372 tr_rpc_callback_type type,
373 struct tr_torrent * tor UNUSED,
374 void * user_data UNUSED)
376 if (type == TR_RPC_SESSION_CLOSE)
377 event_base_loopexit(ev_base, NULL);
378 return TR_RPC_OK;
382 main (int argc, char ** argv)
384 int c;
385 const char * optarg;
386 tr_variant settings;
387 bool boolVal;
388 bool loaded;
389 bool foreground = false;
390 bool dumpSettings = false;
391 const char * configDir = NULL;
392 const char * pid_filename;
393 dtr_watchdir * watchdir = NULL;
394 bool pidfile_created = false;
395 tr_session * session = NULL;
396 struct event *status_ev;
398 key_pidfile = tr_quark_new ("pidfile", 7);
400 signal (SIGINT, gotsig);
401 signal (SIGTERM, gotsig);
402 #ifndef WIN32
403 signal (SIGHUP, gotsig);
404 #endif
406 /* load settings from defaults + config file */
407 tr_variantInitDict (&settings, 0);
408 tr_variantDictAddBool (&settings, TR_KEY_rpc_enabled, true);
409 configDir = getConfigDir (argc, (const char**)argv);
410 loaded = tr_sessionLoadSettings (&settings, configDir, MY_NAME);
412 /* overwrite settings from the comamndline */
413 tr_optind = 1;
414 while ((c = tr_getopt (getUsage (), argc, (const char**)argv, options, &optarg))) {
415 switch (c) {
416 case 'a': tr_variantDictAddStr (&settings, TR_KEY_rpc_whitelist, optarg);
417 tr_variantDictAddBool (&settings, TR_KEY_rpc_whitelist_enabled, true);
418 break;
419 case 'b': tr_variantDictAddBool (&settings, TR_KEY_blocklist_enabled, true);
420 break;
421 case 'B': tr_variantDictAddBool (&settings, TR_KEY_blocklist_enabled, false);
422 break;
423 case 'c': tr_variantDictAddStr (&settings, TR_KEY_watch_dir, optarg);
424 tr_variantDictAddBool (&settings, TR_KEY_watch_dir_enabled, true);
425 break;
426 case 'C': tr_variantDictAddBool (&settings, TR_KEY_watch_dir_enabled, false);
427 break;
428 case 941: tr_variantDictAddStr (&settings, TR_KEY_incomplete_dir, optarg);
429 tr_variantDictAddBool (&settings, TR_KEY_incomplete_dir_enabled, true);
430 break;
431 case 942: tr_variantDictAddBool (&settings, TR_KEY_incomplete_dir_enabled, false);
432 break;
433 case 'd': dumpSettings = true;
434 break;
435 case 'e': logfile = fopen (optarg, LOGFILE_MODE_STR);
436 if (logfile)
437 logfileName = optarg;
438 else
439 fprintf (stderr, "Couldn't open \"%s\": %s\n", optarg, tr_strerror (errno));
440 break;
441 case 'f': foreground = true;
442 break;
443 case 'g': /* handled above */
444 break;
445 case 'V': /* version */
446 fprintf (stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING);
447 exit (0);
448 case 'o': tr_variantDictAddBool (&settings, TR_KEY_dht_enabled, true);
449 break;
450 case 'O': tr_variantDictAddBool (&settings, TR_KEY_dht_enabled, false);
451 break;
452 case 'p': tr_variantDictAddInt (&settings, TR_KEY_rpc_port, atoi (optarg));
453 break;
454 case 't': tr_variantDictAddBool (&settings, TR_KEY_rpc_authentication_required, true);
455 break;
456 case 'T': tr_variantDictAddBool (&settings, TR_KEY_rpc_authentication_required, false);
457 break;
458 case 'u': tr_variantDictAddStr (&settings, TR_KEY_rpc_username, optarg);
459 break;
460 case 'v': tr_variantDictAddStr (&settings, TR_KEY_rpc_password, optarg);
461 break;
462 case 'w': tr_variantDictAddStr (&settings, TR_KEY_download_dir, optarg);
463 break;
464 case 'P': tr_variantDictAddInt (&settings, TR_KEY_peer_port, atoi (optarg));
465 break;
466 case 'm': tr_variantDictAddBool (&settings, TR_KEY_port_forwarding_enabled, true);
467 break;
468 case 'M': tr_variantDictAddBool (&settings, TR_KEY_port_forwarding_enabled, false);
469 break;
470 case 'L': tr_variantDictAddInt (&settings, TR_KEY_peer_limit_global, atoi (optarg));
471 break;
472 case 'l': tr_variantDictAddInt (&settings, TR_KEY_peer_limit_per_torrent, atoi (optarg));
473 break;
474 case 800: paused = true;
475 break;
476 case 910: tr_variantDictAddInt (&settings, TR_KEY_encryption, TR_ENCRYPTION_REQUIRED);
477 break;
478 case 911: tr_variantDictAddInt (&settings, TR_KEY_encryption, TR_ENCRYPTION_PREFERRED);
479 break;
480 case 912: tr_variantDictAddInt (&settings, TR_KEY_encryption, TR_CLEAR_PREFERRED);
481 break;
482 case 'i': tr_variantDictAddStr (&settings, TR_KEY_bind_address_ipv4, optarg);
483 break;
484 case 'I': tr_variantDictAddStr (&settings, TR_KEY_bind_address_ipv6, optarg);
485 break;
486 case 'r': tr_variantDictAddStr (&settings, TR_KEY_rpc_bind_address, optarg);
487 break;
488 case 953: tr_variantDictAddReal (&settings, TR_KEY_ratio_limit, atof (optarg));
489 tr_variantDictAddBool (&settings, TR_KEY_ratio_limit_enabled, true);
490 break;
491 case 954: tr_variantDictAddBool (&settings, TR_KEY_ratio_limit_enabled, false);
492 break;
493 case 'x': tr_variantDictAddStr (&settings, key_pidfile, optarg);
494 break;
495 case 'y': tr_variantDictAddBool (&settings, TR_KEY_lpd_enabled, true);
496 break;
497 case 'Y': tr_variantDictAddBool (&settings, TR_KEY_lpd_enabled, false);
498 break;
499 case 810: tr_variantDictAddInt (&settings, TR_KEY_message_level, TR_LOG_ERROR);
500 break;
501 case 811: tr_variantDictAddInt (&settings, TR_KEY_message_level, TR_LOG_INFO);
502 break;
503 case 812: tr_variantDictAddInt (&settings, TR_KEY_message_level, TR_LOG_DEBUG);
504 break;
505 case 830: tr_variantDictAddBool (&settings, TR_KEY_utp_enabled, true);
506 break;
507 case 831: tr_variantDictAddBool (&settings, TR_KEY_utp_enabled, false);
508 break;
509 default: showUsage ();
510 break;
514 if (foreground && !logfile)
515 logfile = stderr;
517 if (!loaded)
519 printMessage (logfile, TR_LOG_ERROR, MY_NAME, "Error loading config file -- exiting.", __FILE__, __LINE__);
520 return -1;
523 if (dumpSettings)
525 char * str = tr_variantToStr (&settings, TR_VARIANT_FMT_JSON, NULL);
526 fprintf (stderr, "%s", str);
527 tr_free (str);
528 return 0;
531 if (!foreground && tr_daemon (true, false) < 0)
533 char buf[256];
534 tr_snprintf (buf, sizeof (buf), "Failed to daemonize: %s", tr_strerror (errno));
535 printMessage (logfile, TR_LOG_ERROR, MY_NAME, buf, __FILE__, __LINE__);
536 exit (1);
539 sd_notifyf (0, "MAINPID=%d\n", (int)getpid());
541 /* setup event state */
542 ev_base = event_base_new();
543 if (ev_base == NULL)
545 char buf[256];
546 tr_snprintf(buf, sizeof(buf), "Failed to init daemon event state: %s", tr_strerror(errno));
547 printMessage (logfile, TR_LOG_ERROR, MY_NAME, buf, __FILE__, __LINE__);
548 exit (1);
551 /* start the session */
552 tr_formatter_mem_init (MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR);
553 tr_formatter_size_init (DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR);
554 tr_formatter_speed_init (SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR);
555 session = tr_sessionInit ("daemon", configDir, true, &settings);
556 tr_sessionSetRPCCallback (session, on_rpc_callback, NULL);
557 tr_logAddNamedInfo (NULL, "Using settings from \"%s\"", configDir);
558 tr_sessionSaveSettings (session, configDir, &settings);
560 pid_filename = NULL;
561 tr_variantDictFindStr (&settings, key_pidfile, &pid_filename, NULL);
562 if (pid_filename && *pid_filename)
564 FILE * fp = fopen (pid_filename, "w+");
565 if (fp != NULL)
567 fprintf (fp, "%d", (int)getpid ());
568 fclose (fp);
569 tr_logAddInfo ("Saved pidfile \"%s\"", pid_filename);
570 pidfile_created = true;
572 else
573 tr_logAddError ("Unable to save pidfile \"%s\": %s", pid_filename, tr_strerror (errno));
576 if (tr_variantDictFindBool (&settings, TR_KEY_rpc_authentication_required, &boolVal) && boolVal)
577 tr_logAddNamedInfo (MY_NAME, "requiring authentication");
579 mySession = session;
581 /* If we got a SIGHUP during startup, process that now. */
582 if (seenHUP)
583 gotsig (SIGHUP);
585 /* maybe add a watchdir */
587 const char * dir;
589 if (tr_variantDictFindBool (&settings, TR_KEY_watch_dir_enabled, &boolVal)
590 && boolVal
591 && tr_variantDictFindStr (&settings, TR_KEY_watch_dir, &dir, NULL)
592 && dir
593 && *dir)
595 tr_logAddInfo ("Watching \"%s\" for new .torrent files", dir);
596 watchdir = dtr_watchdir_new (mySession, dir, onFileAdded);
600 /* load the torrents */
602 tr_torrent ** torrents;
603 tr_ctor * ctor = tr_ctorNew (mySession);
604 if (paused)
605 tr_ctorSetPaused (ctor, TR_FORCE, true);
606 torrents = tr_sessionLoadTorrents (mySession, ctor, NULL);
607 tr_free (torrents);
608 tr_ctorFree (ctor);
611 #ifdef HAVE_SYSLOG
612 if (!foreground)
613 openlog (MY_NAME, LOG_CONS|LOG_PID, LOG_DAEMON);
614 #endif
616 /* Create new timer event to report daemon status */
618 struct timeval one_sec = { 1, 0 };
619 status_ev = event_new(ev_base, -1, EV_PERSIST, &periodicUpdate, watchdir);
620 if (status_ev == NULL)
622 tr_logAddError("Failed to create status event %s", tr_strerror(errno));
623 goto cleanup;
625 if (event_add(status_ev, &one_sec) == -1)
627 tr_logAddError("Failed to add status event %s", tr_strerror(errno));
628 goto cleanup;
632 sd_notify( 0, "READY=1\n" );
634 /* Run daemon event loop */
635 if (event_base_dispatch(ev_base) == -1)
637 tr_logAddError("Failed to launch daemon event loop: %s", tr_strerror(errno));
638 goto cleanup;
641 cleanup:
642 sd_notify( 0, "STATUS=Closing transmission session...\n" );
643 printf ("Closing transmission session...");
645 if (status_ev)
647 event_del(status_ev);
648 event_free(status_ev);
650 event_base_free(ev_base);
652 tr_sessionSaveSettings (mySession, configDir, &settings);
653 dtr_watchdir_free (watchdir);
654 tr_sessionClose (mySession);
655 pumpLogMessages (logfile);
656 printf (" done.\n");
658 /* shutdown */
659 #if HAVE_SYSLOG
660 if (!foreground)
662 syslog (LOG_INFO, "%s", "Closing session");
663 closelog ();
665 #endif
667 /* cleanup */
668 if (pidfile_created)
669 tr_remove (pid_filename);
670 tr_variantFree (&settings);
671 sd_notify (0, "STATUS=\n");
672 return 0;