Changeset 14485


Ignore:
Timestamp:
Apr 4, 2015, 5:43:56 PM (6 years ago)
Author:
mikedld
Message:

#5910: Run daemon as a service on Windows

Factor out demonization implementation to platform-specific files.
Implement daemonization on Windows using service API. Improve *NIX
implementation by handling signals asynchronously to prevent potential
issues of running complex code inside the handler.

Location:
trunk/daemon
Files:
3 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/daemon/CMakeLists.txt

    r14353 r14485  
    1919)
    2020
    21 add_executable(${TR_NAME}-daemon
     21set(${PROJECT_NAME}_SOURCES
    2222    daemon.c
    2323    watch.c
     24)
     25
     26if(WIN32)
     27    list(APPEND ${PROJECT_NAME}_SOURCES daemon-win32.c)
     28else()
     29    list(APPEND ${PROJECT_NAME}_SOURCES daemon-posix.c)
     30endif()
     31
     32set(${PROJECT_NAME}_HEADERS
     33    daemon.h
    2434    watch.h
    2535)
     36
     37add_executable(${TR_NAME}-daemon ${${PROJECT_NAME}_SOURCES} ${${PROJECT_NAME}_HEADERS})
    2638
    2739set_target_properties(${TR_NAME}-daemon PROPERTIES
  • trunk/daemon/daemon.c

    r14480 r14485  
    1010#include <errno.h>
    1111#include <stdio.h> /* printf */
    12 #include <stdlib.h> /* exit, atoi */
    13 
    14 #include <signal.h>
     12#include <stdlib.h> /* atoi */
     13
    1514#ifdef HAVE_SYSLOG
    1615#include <syslog.h>
     
    2019 #include <process.h> /* getpid */
    2120#else
    22  #include <fcntl.h> /* open */
    23  #include <unistd.h> /* daemon */
     21 #include <unistd.h> /* getpid */
    2422#endif
    2523
     
    4341#endif
    4442
     43#include "daemon.h"
    4544#include "watch.h"
    4645
     
    6766#define SPEED_T_STR "TB/s"
    6867
    69 static bool paused = false;
    70 #ifdef SIGHUP
    7168static bool seenHUP = false;
    72 #endif
    7369static const char *logfileName = NULL;
    7470static tr_sys_file_t logfile = TR_BAD_SYS_FILE;
     
    143139};
    144140
    145 static void
    146 showUsage (void)
    147 {
    148     tr_getopt_usage (MY_NAME, getUsage (), options);
    149     exit (0);
    150 }
    151 
    152141static bool
    153142reopen_log_file (const char *filename)
     
    172161
    173162    return true;
    174 }
    175 
    176 static void
    177 gotsig (int sig)
    178 {
    179     switch (sig)
    180     {
    181 #ifdef SIGHUP
    182         case SIGHUP:
    183         {
    184             if (!mySession)
    185             {
    186                 tr_logAddInfo ("Deferring reload until session is fully started.");
    187                 seenHUP = true;
    188             }
    189             else
    190             {
    191                 tr_variant settings;
    192                 const char * configDir;
    193 
    194                 /* reopen the logfile to allow for log rotation */
    195                 if (logfileName != NULL)
    196                 {
    197                     reopen_log_file (logfileName);
    198                 }
    199 
    200                 configDir = tr_sessionGetConfigDir (mySession);
    201                 tr_logAddInfo ("Reloading settings from \"%s\"", configDir);
    202                 tr_variantInitDict (&settings, 0);
    203                 tr_variantDictAddBool (&settings, TR_KEY_rpc_enabled, true);
    204                 tr_sessionLoadSettings (&settings, configDir, MY_NAME);
    205                 tr_sessionSet (mySession, &settings);
    206                 tr_variantFree (&settings);
    207                 tr_sessionReloadBlocklists (mySession);
    208             }
    209             break;
    210         }
    211 #endif
    212 
    213         default:
    214             tr_logAddError ("Unexpected signal (%d) in daemon, closing.", sig);
    215             /* no break */
    216 
    217         case SIGINT:
    218         case SIGTERM:
    219             event_base_loopexit(ev_base, NULL);
    220             break;
    221     }
    222 }
    223 
    224 #if defined (_WIN32)
    225  #define USE_NO_DAEMON
    226 #elif !defined (HAVE_DAEMON) || defined (__UCLIBC__)
    227  #define USE_TR_DAEMON
    228 #else
    229  #define USE_OS_DAEMON
    230 #endif
    231 
    232 static int
    233 tr_daemon (int nochdir, int noclose)
    234 {
    235 #if defined (USE_OS_DAEMON)
    236 
    237     return daemon (nochdir, noclose);
    238 
    239 #elif defined (USE_TR_DAEMON)
    240 
    241     /* this is loosely based off of glibc's daemon () implementation
    242      * http://sourceware.org/git/?p=glibc.git;a=blob_plain;f=misc/daemon.c */
    243 
    244     switch (fork ()) {
    245         case -1: return -1;
    246         case 0: break;
    247         default: _exit (0);
    248     }
    249 
    250     if (setsid () == -1)
    251         return -1;
    252 
    253     if (!nochdir)
    254         chdir ("/");
    255 
    256     if (!noclose) {
    257         int fd = open ("/dev/null", O_RDWR, 0);
    258         dup2 (fd, STDIN_FILENO);
    259         dup2 (fd, STDOUT_FILENO);
    260         dup2 (fd, STDERR_FILENO);
    261         close (fd);
    262     }
    263 
    264     return 0;
    265 
    266 #else /* USE_NO_DAEMON */
    267 
    268     (void) nochdir;
    269     (void) noclose;
    270 
    271     return 0;
    272 
    273 #endif
    274163}
    275164
     
    425314}
    426315
    427 int
    428 main (int argc, char ** argv)
     316static bool
     317parse_args (int           argc,
     318            const char ** argv,
     319            tr_variant  * settings,
     320            bool        * paused,
     321            bool        * dump_settings,
     322            bool        * foreground,
     323            int         * exit_code)
    429324{
    430325    int c;
    431326    const char * optarg;
    432     tr_variant settings;
     327
     328    *paused = false;
     329    *dump_settings = false;
     330    *foreground = false;
     331
     332    tr_optind = 1;
     333    while ((c = tr_getopt (getUsage (), argc, argv, options, &optarg))) {
     334        switch (c) {
     335            case 'a': tr_variantDictAddStr  (settings, TR_KEY_rpc_whitelist, optarg);
     336                      tr_variantDictAddBool (settings, TR_KEY_rpc_whitelist_enabled, true);
     337                      break;
     338            case 'b': tr_variantDictAddBool (settings, TR_KEY_blocklist_enabled, true);
     339                      break;
     340            case 'B': tr_variantDictAddBool (settings, TR_KEY_blocklist_enabled, false);
     341                      break;
     342            case 'c': tr_variantDictAddStr  (settings, TR_KEY_watch_dir, optarg);
     343                      tr_variantDictAddBool (settings, TR_KEY_watch_dir_enabled, true);
     344                      break;
     345            case 'C': tr_variantDictAddBool (settings, TR_KEY_watch_dir_enabled, false);
     346                      break;
     347            case 941: tr_variantDictAddStr  (settings, TR_KEY_incomplete_dir, optarg);
     348                      tr_variantDictAddBool (settings, TR_KEY_incomplete_dir_enabled, true);
     349                      break;
     350            case 942: tr_variantDictAddBool (settings, TR_KEY_incomplete_dir_enabled, false);
     351                      break;
     352            case 'd': *dump_settings = true;
     353                      break;
     354            case 'e': if (reopen_log_file (optarg))
     355                          logfileName = optarg;
     356                      break;
     357            case 'f': *foreground = true;
     358                      break;
     359            case 'g': /* handled above */
     360                      break;
     361            case 'V': /* version */
     362                      fprintf (stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING);
     363                      *exit_code = 0;
     364                      return false;
     365            case 'o': tr_variantDictAddBool (settings, TR_KEY_dht_enabled, true);
     366                      break;
     367            case 'O': tr_variantDictAddBool (settings, TR_KEY_dht_enabled, false);
     368                      break;
     369            case 'p': tr_variantDictAddInt (settings, TR_KEY_rpc_port, atoi (optarg));
     370                      break;
     371            case 't': tr_variantDictAddBool (settings, TR_KEY_rpc_authentication_required, true);
     372                      break;
     373            case 'T': tr_variantDictAddBool (settings, TR_KEY_rpc_authentication_required, false);
     374                      break;
     375            case 'u': tr_variantDictAddStr (settings, TR_KEY_rpc_username, optarg);
     376                      break;
     377            case 'v': tr_variantDictAddStr (settings, TR_KEY_rpc_password, optarg);
     378                      break;
     379            case 'w': tr_variantDictAddStr (settings, TR_KEY_download_dir, optarg);
     380                      break;
     381            case 'P': tr_variantDictAddInt (settings, TR_KEY_peer_port, atoi (optarg));
     382                      break;
     383            case 'm': tr_variantDictAddBool (settings, TR_KEY_port_forwarding_enabled, true);
     384                      break;
     385            case 'M': tr_variantDictAddBool (settings, TR_KEY_port_forwarding_enabled, false);
     386                      break;
     387            case 'L': tr_variantDictAddInt (settings, TR_KEY_peer_limit_global, atoi (optarg));
     388                      break;
     389            case 'l': tr_variantDictAddInt (settings, TR_KEY_peer_limit_per_torrent, atoi (optarg));
     390                      break;
     391            case 800: *paused = true;
     392                      break;
     393            case 910: tr_variantDictAddInt (settings, TR_KEY_encryption, TR_ENCRYPTION_REQUIRED);
     394                      break;
     395            case 911: tr_variantDictAddInt (settings, TR_KEY_encryption, TR_ENCRYPTION_PREFERRED);
     396                      break;
     397            case 912: tr_variantDictAddInt (settings, TR_KEY_encryption, TR_CLEAR_PREFERRED);
     398                      break;
     399            case 'i': tr_variantDictAddStr (settings, TR_KEY_bind_address_ipv4, optarg);
     400                      break;
     401            case 'I': tr_variantDictAddStr (settings, TR_KEY_bind_address_ipv6, optarg);
     402                      break;
     403            case 'r': tr_variantDictAddStr (settings, TR_KEY_rpc_bind_address, optarg);
     404                      break;
     405            case 953: tr_variantDictAddReal (settings, TR_KEY_ratio_limit, atof (optarg));
     406                      tr_variantDictAddBool (settings, TR_KEY_ratio_limit_enabled, true);
     407                      break;
     408            case 954: tr_variantDictAddBool (settings, TR_KEY_ratio_limit_enabled, false);
     409                      break;
     410            case 'x': tr_variantDictAddStr (settings, key_pidfile, optarg);
     411                      break;
     412            case 'y': tr_variantDictAddBool (settings, TR_KEY_lpd_enabled, true);
     413                      break;
     414            case 'Y': tr_variantDictAddBool (settings, TR_KEY_lpd_enabled, false);
     415                      break;
     416            case 810: tr_variantDictAddInt (settings,  TR_KEY_message_level, TR_LOG_ERROR);
     417                      break;
     418            case 811: tr_variantDictAddInt (settings,  TR_KEY_message_level, TR_LOG_INFO);
     419                      break;
     420            case 812: tr_variantDictAddInt (settings,  TR_KEY_message_level, TR_LOG_DEBUG);
     421                      break;
     422            case 830: tr_variantDictAddBool (settings, TR_KEY_utp_enabled, true);
     423                      break;
     424            case 831: tr_variantDictAddBool (settings, TR_KEY_utp_enabled, false);
     425                      break;
     426            default:  tr_getopt_usage (MY_NAME, getUsage (), options);
     427                      *exit_code = 0;
     428                      return false;
     429        }
     430    }
     431
     432    return true;
     433}
     434
     435struct daemon_data
     436{
     437  tr_variant   settings;
     438  const char * configDir;
     439  bool         paused;
     440};
     441
     442static void
     443daemon_reconfigure (void * arg UNUSED)
     444{
     445    if (!mySession)
     446    {
     447        tr_logAddInfo ("Deferring reload until session is fully started.");
     448        seenHUP = true;
     449    }
     450    else
     451    {
     452        tr_variant settings;
     453        const char * configDir;
     454
     455        /* reopen the logfile to allow for log rotation */
     456        if (logfileName != NULL)
     457            reopen_log_file (logfileName);
     458
     459        configDir = tr_sessionGetConfigDir (mySession);
     460        tr_logAddInfo ("Reloading settings from \"%s\"", configDir);
     461        tr_variantInitDict (&settings, 0);
     462        tr_variantDictAddBool (&settings, TR_KEY_rpc_enabled, true);
     463        tr_sessionLoadSettings (&settings, configDir, MY_NAME);
     464        tr_sessionSet (mySession, &settings);
     465        tr_variantFree (&settings);
     466        tr_sessionReloadBlocklists (mySession);
     467    }
     468}
     469
     470static void
     471daemon_stop (void * arg UNUSED)
     472{
     473    event_base_loopexit (ev_base, NULL);
     474}
     475
     476static int
     477daemon_start (void * raw_arg,
     478              bool   foreground)
     479{
    433480    bool boolVal;
    434     bool loaded;
    435     bool foreground = false;
    436     bool dumpSettings = false;
    437     const char * configDir = NULL;
    438481    const char * pid_filename;
    439482    dtr_watchdir * watchdir = NULL;
     
    442485    struct event *status_ev;
    443486
    444 #ifdef _WIN32
    445     tr_win32_make_args_utf8 (&argc, &argv);
     487    struct daemon_data * const arg = raw_arg;
     488    tr_variant * const settings = &arg->settings;
     489    const char * const configDir = arg->configDir;
     490
     491#ifndef HAVE_SYSLOG
     492    (void) foreground;
    446493#endif
    447 
    448     key_pidfile = tr_quark_new ("pidfile",  7);
    449 
    450     signal (SIGINT, gotsig);
    451     signal (SIGTERM, gotsig);
    452 #ifdef SIGHUP
    453     signal (SIGHUP, gotsig);
    454 #endif
    455 
    456     /* load settings from defaults + config file */
    457     tr_variantInitDict (&settings, 0);
    458     tr_variantDictAddBool (&settings, TR_KEY_rpc_enabled, true);
    459     configDir = getConfigDir (argc, (const char**)argv);
    460     loaded = tr_sessionLoadSettings (&settings, configDir, MY_NAME);
    461 
    462     /* overwrite settings from the comamndline */
    463     tr_optind = 1;
    464     while ((c = tr_getopt (getUsage (), argc, (const char**)argv, options, &optarg))) {
    465         switch (c) {
    466             case 'a': tr_variantDictAddStr  (&settings, TR_KEY_rpc_whitelist, optarg);
    467                       tr_variantDictAddBool (&settings, TR_KEY_rpc_whitelist_enabled, true);
    468                       break;
    469             case 'b': tr_variantDictAddBool (&settings, TR_KEY_blocklist_enabled, true);
    470                       break;
    471             case 'B': tr_variantDictAddBool (&settings, TR_KEY_blocklist_enabled, false);
    472                       break;
    473             case 'c': tr_variantDictAddStr  (&settings, TR_KEY_watch_dir, optarg);
    474                       tr_variantDictAddBool (&settings, TR_KEY_watch_dir_enabled, true);
    475                       break;
    476             case 'C': tr_variantDictAddBool (&settings, TR_KEY_watch_dir_enabled, false);
    477                       break;
    478             case 941: tr_variantDictAddStr  (&settings, TR_KEY_incomplete_dir, optarg);
    479                       tr_variantDictAddBool (&settings, TR_KEY_incomplete_dir_enabled, true);
    480                       break;
    481             case 942: tr_variantDictAddBool (&settings, TR_KEY_incomplete_dir_enabled, false);
    482                       break;
    483             case 'd': dumpSettings = true;
    484                       break;
    485             case 'e': if (reopen_log_file (optarg))
    486                           logfileName = optarg;
    487                       break;
    488             case 'f': foreground = true;
    489                       break;
    490             case 'g': /* handled above */
    491                       break;
    492             case 'V': /* version */
    493                       fprintf (stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING);
    494                       exit (0);
    495             case 'o': tr_variantDictAddBool (&settings, TR_KEY_dht_enabled, true);
    496                       break;
    497             case 'O': tr_variantDictAddBool (&settings, TR_KEY_dht_enabled, false);
    498                       break;
    499             case 'p': tr_variantDictAddInt (&settings, TR_KEY_rpc_port, atoi (optarg));
    500                       break;
    501             case 't': tr_variantDictAddBool (&settings, TR_KEY_rpc_authentication_required, true);
    502                       break;
    503             case 'T': tr_variantDictAddBool (&settings, TR_KEY_rpc_authentication_required, false);
    504                       break;
    505             case 'u': tr_variantDictAddStr (&settings, TR_KEY_rpc_username, optarg);
    506                       break;
    507             case 'v': tr_variantDictAddStr (&settings, TR_KEY_rpc_password, optarg);
    508                       break;
    509             case 'w': tr_variantDictAddStr (&settings, TR_KEY_download_dir, optarg);
    510                       break;
    511             case 'P': tr_variantDictAddInt (&settings, TR_KEY_peer_port, atoi (optarg));
    512                       break;
    513             case 'm': tr_variantDictAddBool (&settings, TR_KEY_port_forwarding_enabled, true);
    514                       break;
    515             case 'M': tr_variantDictAddBool (&settings, TR_KEY_port_forwarding_enabled, false);
    516                       break;
    517             case 'L': tr_variantDictAddInt (&settings, TR_KEY_peer_limit_global, atoi (optarg));
    518                       break;
    519             case 'l': tr_variantDictAddInt (&settings, TR_KEY_peer_limit_per_torrent, atoi (optarg));
    520                       break;
    521             case 800: paused = true;
    522                       break;
    523             case 910: tr_variantDictAddInt (&settings, TR_KEY_encryption, TR_ENCRYPTION_REQUIRED);
    524                       break;
    525             case 911: tr_variantDictAddInt (&settings, TR_KEY_encryption, TR_ENCRYPTION_PREFERRED);
    526                       break;
    527             case 912: tr_variantDictAddInt (&settings, TR_KEY_encryption, TR_CLEAR_PREFERRED);
    528                       break;
    529             case 'i': tr_variantDictAddStr (&settings, TR_KEY_bind_address_ipv4, optarg);
    530                       break;
    531             case 'I': tr_variantDictAddStr (&settings, TR_KEY_bind_address_ipv6, optarg);
    532                       break;
    533             case 'r': tr_variantDictAddStr (&settings, TR_KEY_rpc_bind_address, optarg);
    534                       break;
    535             case 953: tr_variantDictAddReal (&settings, TR_KEY_ratio_limit, atof (optarg));
    536                       tr_variantDictAddBool (&settings, TR_KEY_ratio_limit_enabled, true);
    537                       break;
    538             case 954: tr_variantDictAddBool (&settings, TR_KEY_ratio_limit_enabled, false);
    539                       break;
    540             case 'x': tr_variantDictAddStr (&settings, key_pidfile, optarg);
    541                       break;
    542             case 'y': tr_variantDictAddBool (&settings, TR_KEY_lpd_enabled, true);
    543                       break;
    544             case 'Y': tr_variantDictAddBool (&settings, TR_KEY_lpd_enabled, false);
    545                       break;
    546             case 810: tr_variantDictAddInt (&settings,  TR_KEY_message_level, TR_LOG_ERROR);
    547                       break;
    548             case 811: tr_variantDictAddInt (&settings,  TR_KEY_message_level, TR_LOG_INFO);
    549                       break;
    550             case 812: tr_variantDictAddInt (&settings,  TR_KEY_message_level, TR_LOG_DEBUG);
    551                       break;
    552             case 830: tr_variantDictAddBool (&settings, TR_KEY_utp_enabled, true);
    553                       break;
    554             case 831: tr_variantDictAddBool (&settings, TR_KEY_utp_enabled, false);
    555                       break;
    556             default:  showUsage ();
    557                       break;
    558         }
    559     }
    560 
    561     if (foreground && logfile == TR_BAD_SYS_FILE)
    562         logfile = tr_sys_file_get_std (TR_STD_SYS_FILE_ERR, NULL);
    563 
    564     if (!loaded)
    565     {
    566         printMessage (logfile, TR_LOG_ERROR, MY_NAME, "Error loading config file -- exiting.", __FILE__, __LINE__);
    567         return -1;
    568     }
    569 
    570     if (dumpSettings)
    571     {
    572         char * str = tr_variantToStr (&settings, TR_VARIANT_FMT_JSON, NULL);
    573         fprintf (stderr, "%s", str);
    574         tr_free (str);
    575         return 0;
    576     }
    577 
    578     if (!foreground && tr_daemon (true, false) < 0)
    579     {
    580         char buf[256];
    581         tr_snprintf (buf, sizeof (buf), "Failed to daemonize: %s", tr_strerror (errno));
    582         printMessage (logfile, TR_LOG_ERROR, MY_NAME, buf, __FILE__, __LINE__);
    583         exit (1);
    584     }
    585494
    586495    sd_notifyf (0, "MAINPID=%d\n", (int)getpid());
     
    593502        tr_snprintf(buf, sizeof(buf), "Failed to init daemon event state: %s", tr_strerror(errno));
    594503        printMessage (logfile, TR_LOG_ERROR, MY_NAME, buf, __FILE__, __LINE__);
    595         exit (1);
     504        return 1;
    596505    }
    597506
     
    600509    tr_formatter_size_init (DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR);
    601510    tr_formatter_speed_init (SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR);
    602     session = tr_sessionInit ("daemon", configDir, true, &settings);
     511    session = tr_sessionInit ("daemon", configDir, true, settings);
    603512    tr_sessionSetRPCCallback (session, on_rpc_callback, NULL);
    604513    tr_logAddNamedInfo (NULL, "Using settings from \"%s\"", configDir);
    605     tr_sessionSaveSettings (session, configDir, &settings);
     514    tr_sessionSaveSettings (session, configDir, settings);
    606515
    607516    pid_filename = NULL;
    608     tr_variantDictFindStr (&settings, key_pidfile, &pid_filename, NULL);
     517    tr_variantDictFindStr (settings, key_pidfile, &pid_filename, NULL);
    609518    if (pid_filename && *pid_filename)
    610519    {
     
    627536    }
    628537
    629     if (tr_variantDictFindBool (&settings, TR_KEY_rpc_authentication_required, &boolVal) && boolVal)
     538    if (tr_variantDictFindBool (settings, TR_KEY_rpc_authentication_required, &boolVal) && boolVal)
    630539        tr_logAddNamedInfo (MY_NAME, "requiring authentication");
    631540
    632541    mySession = session;
    633542
    634 #ifdef SIGHUP
    635543    /* If we got a SIGHUP during startup, process that now. */
    636544    if (seenHUP)
    637         gotsig (SIGHUP);
    638 #endif
     545        daemon_reconfigure (arg);
    639546
    640547    /* maybe add a watchdir */
     
    642549        const char * dir;
    643550
    644         if (tr_variantDictFindBool (&settings, TR_KEY_watch_dir_enabled, &boolVal)
     551        if (tr_variantDictFindBool (settings, TR_KEY_watch_dir_enabled, &boolVal)
    645552            && boolVal
    646             && tr_variantDictFindStr (&settings, TR_KEY_watch_dir, &dir, NULL)
     553            && tr_variantDictFindStr (settings, TR_KEY_watch_dir, &dir, NULL)
    647554            && dir
    648555            && *dir)
     
    657564        tr_torrent ** torrents;
    658565        tr_ctor * ctor = tr_ctorNew (mySession);
    659         if (paused)
     566        if (arg->paused)
    660567            tr_ctorSetPaused (ctor, TR_FORCE, true);
    661568        torrents = tr_sessionLoadTorrents (mySession, ctor, NULL);
     
    705612    event_base_free(ev_base);
    706613
    707     tr_sessionSaveSettings (mySession, configDir, &settings);
     614    tr_sessionSaveSettings (mySession, configDir, settings);
    708615    dtr_watchdir_free (watchdir);
    709616    tr_sessionClose (mySession);
     
    723630    if (pidfile_created)
    724631        tr_sys_path_remove (pid_filename, NULL);
    725     tr_variantFree (&settings);
     632
    726633    sd_notify (0, "STATUS=\n");
     634
    727635    return 0;
    728636}
     637
     638int
     639main (int     argc,
     640      char ** argv)
     641{
     642    const dtr_callbacks cb =
     643    {
     644        .on_start       = &daemon_start,
     645        .on_stop        = &daemon_stop,
     646        .on_reconfigure = &daemon_reconfigure,
     647    };
     648
     649    int ret;
     650    bool loaded, dumpSettings, foreground;
     651    tr_error * error = NULL;
     652
     653    struct daemon_data arg;
     654    tr_variant * const settings = &arg.settings;
     655    const char ** const configDir = &arg.configDir;
     656
     657#ifdef _WIN32
     658    tr_win32_make_args_utf8 (&argc, &argv);
     659#endif
     660
     661    key_pidfile = tr_quark_new ("pidfile",  7);
     662
     663    /* load settings from defaults + config file */
     664    tr_variantInitDict (settings, 0);
     665    tr_variantDictAddBool (settings, TR_KEY_rpc_enabled, true);
     666    *configDir = getConfigDir (argc, (const char**)argv);
     667    loaded = tr_sessionLoadSettings (settings, *configDir, MY_NAME);
     668
     669    /* overwrite settings from the comamndline */
     670    if (!parse_args (argc, (const char**) argv, settings, &arg.paused, &dumpSettings, &foreground, &ret))
     671        goto cleanup;
     672
     673    if (foreground && logfile == TR_BAD_SYS_FILE)
     674        logfile = tr_sys_file_get_std (TR_STD_SYS_FILE_ERR, NULL);
     675
     676    if (!loaded)
     677    {
     678        printMessage (logfile, TR_LOG_ERROR, MY_NAME, "Error loading config file -- exiting.", __FILE__, __LINE__);
     679        ret = 1;
     680        goto cleanup;
     681    }
     682
     683    if (dumpSettings)
     684    {
     685        char * str = tr_variantToStr (settings, TR_VARIANT_FMT_JSON, NULL);
     686        fprintf (stderr, "%s", str);
     687        tr_free (str);
     688        goto cleanup;
     689    }
     690
     691    if (!dtr_daemon (&cb, &arg, foreground, &ret, &error))
     692    {
     693        char buf[256];
     694        tr_snprintf (buf, sizeof (buf), "Failed to daemonize: %s", error->message);
     695        printMessage (logfile, TR_LOG_ERROR, MY_NAME, buf, __FILE__, __LINE__);
     696        tr_error_free (error);
     697    }
     698
     699cleanup:
     700    tr_variantFree (settings);
     701
     702    return ret;
     703}
Note: See TracChangeset for help on using the changeset viewer.