4
4
* This file is licensed by the GPL version 2. Works owned by the
5
5
* Transmission project are granted a special exemption to clause 2(b)
6
* so that the bulk of its code can remain under the MIT license.
6
* so that the bulk of its code can remain under the MIT license.
7
7
* This exemption does not extend to derived works not owned by
8
8
* the Transmission project.
10
* $Id: daemon.c 6489 2008-08-11 19:05:00Z charles $
10
* $Id: daemon.c 6978 2008-10-28 19:49:33Z charles $
13
13
#include <assert.h>
15
#include <stdio.h> /* printf */
15
#include <stdio.h> /* printf */
16
16
#include <stdlib.h> /* exit, atoi */
17
17
#include <string.h> /* strcmp */
19
19
#include <fcntl.h> /* open */
20
20
#include <signal.h>
21
#include <unistd.h> /* daemon, getcwd */
21
#include <unistd.h> /* daemon */
23
23
#include <libtransmission/transmission.h>
24
24
#include <libtransmission/bencode.h>
25
#include <libtransmission/rpc.h>
25
#include <libtransmission/rpcimpl.h>
26
26
#include <libtransmission/tr-getopt.h>
27
27
#include <libtransmission/utils.h>
28
28
#include <libtransmission/version.h>
30
30
#define MY_NAME "transmission-daemon"
32
static int closing = FALSE;
33
static tr_handle * mySession;
34
static char myConfigFilename[MAX_PATH_LENGTH];
36
#define KEY_BLOCKLIST "blocklist-enabled"
37
#define KEY_DOWNLOAD_DIR "download-dir"
38
#define KEY_ENCRYPTION "encryption"
39
#define KEY_PEER_LIMIT "max-peers-global"
40
#define KEY_PEER_PORT "peer-port"
41
#define KEY_PORT_FORWARDING "port-forwarding-enabled"
42
#define KEY_PEX_ENABLED "pex-enabled"
43
#define KEY_AUTH_REQUIRED "rpc-authentication-required"
44
#define KEY_USERNAME "rpc-username"
45
#define KEY_PASSWORD "rpc-password"
46
#define KEY_ACL "rpc-access-control-list"
47
#define KEY_RPC_PORT "rpc-port"
48
#define KEY_DSPEED "download-limit"
49
#define KEY_DSPEED_ENABLED "download-limit-enabled"
50
#define KEY_USPEED "upload-limit"
51
#define KEY_USPEED_ENABLED "upload-limit-enabled"
53
#define CONFIG_FILE "settings.json"
32
static int closing = FALSE;
33
static tr_session * mySession = NULL;
34
static char * myConfigFilename = NULL;
36
#define KEY_BLOCKLIST "blocklist-enabled"
37
#define KEY_DOWNLOAD_DIR "download-dir"
38
#define KEY_ENCRYPTION "encryption"
39
#define KEY_LAZY_BITFIELD "lazy-bitfield-enabled"
40
#define KEY_PEER_LIMIT "max-peers-global"
41
#define KEY_PEER_PORT "peer-port"
42
#define KEY_PORT_FORWARDING "port-forwarding-enabled"
43
#define KEY_PEX_ENABLED "pex-enabled"
44
#define KEY_AUTH_REQUIRED "rpc-authentication-required"
45
#define KEY_USERNAME "rpc-username"
46
#define KEY_PASSWORD "rpc-password"
47
#define KEY_WHITELIST "rpc-whitelist"
48
#define KEY_WHITELIST_ENABLED "rpc-whitelist-enabled"
49
#define KEY_RPC_PORT "rpc-port"
50
#define KEY_DSPEED "download-limit"
51
#define KEY_DSPEED_ENABLED "download-limit-enabled"
52
#define KEY_USPEED "upload-limit"
53
#define KEY_USPEED_ENABLED "upload-limit-enabled"
55
#define CONFIG_FILE "settings.json"
60
replaceInt( tr_benc * dict, const char * key, int64_t value )
62
replaceInt( tr_benc * dict,
62
66
tr_bencDictRemove( dict, key );
63
67
tr_bencDictAddInt( dict, key, value );
66
replaceStr( tr_benc * dict, const char * key, const char* value )
71
replaceStr( tr_benc * dict,
68
75
tr_bencDictRemove( dict, key );
69
76
tr_bencDictAddStr( dict, key, value );
72
80
saveState( tr_session * s )
78
87
if( tr_bencLoadJSONFile( myConfigFilename, &d ) )
79
88
tr_bencInitDict( &d, 16 );
81
90
replaceInt( &d, KEY_BLOCKLIST, tr_blocklistIsEnabled( s ) );
82
91
replaceStr( &d, KEY_DOWNLOAD_DIR, tr_sessionGetDownloadDir( s ) );
83
92
replaceInt( &d, KEY_PEER_LIMIT, tr_sessionGetPeerLimit( s ) );
84
93
replaceInt( &d, KEY_PEER_PORT, tr_sessionGetPeerPort( s ) );
85
replaceInt( &d, KEY_PORT_FORWARDING, tr_sessionIsPortForwardingEnabled( s ) );
94
replaceInt( &d, KEY_PORT_FORWARDING,
95
tr_sessionIsPortForwardingEnabled( s ) );
86
96
replaceInt( &d, KEY_PEX_ENABLED, tr_sessionIsPexEnabled( s ) );
87
replaceStr( &d, KEY_USERNAME, strs[n++] = tr_sessionGetRPCUsername( s ) );
88
replaceStr( &d, KEY_PASSWORD, strs[n++] = tr_sessionGetRPCPassword( s ) );
89
replaceStr( &d, KEY_ACL, strs[n++] = tr_sessionGetRPCACL( s ) );
97
replaceStr( &d, KEY_USERNAME, strs[n++] =
98
tr_sessionGetRPCUsername(
100
replaceStr( &d, KEY_PASSWORD, strs[n++] =
101
tr_sessionGetRPCPassword(
103
replaceStr( &d, KEY_WHITELIST, strs[n++] = tr_sessionGetRPCWhitelist( s ) );
90
104
replaceInt( &d, KEY_RPC_PORT, tr_sessionGetRPCPort( s ) );
91
105
replaceInt( &d, KEY_AUTH_REQUIRED, tr_sessionIsRPCPasswordEnabled( s ) );
92
replaceInt( &d, KEY_DSPEED, tr_sessionGetSpeedLimit( s, TR_DOWN ) );
93
replaceInt( &d, KEY_DSPEED_ENABLED, tr_sessionIsSpeedLimitEnabled( s, TR_DOWN ) );
106
replaceInt( &d, KEY_DSPEED,
107
tr_sessionGetSpeedLimit( s, TR_DOWN ) );
108
replaceInt( &d, KEY_DSPEED_ENABLED,
109
tr_sessionIsSpeedLimitEnabled( s, TR_DOWN ) );
94
110
replaceInt( &d, KEY_USPEED, tr_sessionGetSpeedLimit( s, TR_UP ) );
95
replaceInt( &d, KEY_USPEED_ENABLED, tr_sessionIsSpeedLimitEnabled( s, TR_UP ) );
111
replaceInt( &d, KEY_USPEED_ENABLED,
112
tr_sessionIsSpeedLimitEnabled( s, TR_UP ) );
96
113
replaceInt( &d, KEY_ENCRYPTION, tr_sessionGetEncryption( s ) );
98
115
tr_bencSaveJSONFile( myConfigFilename, &d );
99
116
tr_bencFree( &d );
100
117
tr_ninf( MY_NAME, "saved \"%s\"", myConfigFilename );
119
for( i = 0; i < n; ++i )
103
120
tr_free( strs[i] );
107
getConfigInt( tr_benc * dict,
124
getConfigInt( tr_benc * dict,
114
132
if( tr_bencDictFindInt( dict, key, &i ) )
164
190
**** If neither of those can be found, the TR_DEFAULT fields are used .
167
getcwd( mycwd, sizeof( mycwd ) );
193
mycwd = tr_getcwd( );
168
194
getConfigStr( dict, KEY_DOWNLOAD_DIR, &downloadDir, mycwd );
169
getConfigInt( dict, KEY_PEX_ENABLED, &pexEnabled, TR_DEFAULT_PEX_ENABLED );
170
getConfigInt( dict, KEY_PORT_FORWARDING, &fwdEnabled, TR_DEFAULT_PORT_FORWARDING_ENABLED );
171
getConfigInt( dict, KEY_PEER_PORT, &peerPort, TR_DEFAULT_PORT );
195
getConfigInt( dict, KEY_PEX_ENABLED, &pexEnabled,
196
TR_DEFAULT_PEX_ENABLED );
197
getConfigInt( dict, KEY_PORT_FORWARDING, &fwdEnabled,
198
TR_DEFAULT_PORT_FORWARDING_ENABLED );
199
getConfigInt( dict, KEY_PEER_PORT, &peerPort,
172
201
getConfigInt( dict, KEY_DSPEED, &downLimit, 100 );
173
202
getConfigInt( dict, KEY_DSPEED_ENABLED, &downLimited, FALSE );
174
203
getConfigInt( dict, KEY_USPEED, &upLimit, 100 );
175
204
getConfigInt( dict, KEY_USPEED_ENABLED, &upLimited, FALSE );
176
getConfigInt( dict, KEY_PEER_LIMIT, &peers, TR_DEFAULT_GLOBAL_PEER_LIMIT );
177
getConfigInt( dict, KEY_BLOCKLIST, &blocklistEnabled, TR_DEFAULT_BLOCKLIST_ENABLED );
178
getConfigInt( dict, KEY_RPC_PORT, &rpcPort, TR_DEFAULT_RPC_PORT );
179
getConfigStr( dict, KEY_ACL, &acl, TR_DEFAULT_RPC_ACL );
205
getConfigInt( dict, KEY_LAZY_BITFIELD, &useLazyBitfield,
206
TR_DEFAULT_LAZY_BITFIELD_ENABLED );
207
getConfigInt( dict, KEY_PEER_LIMIT, &peers,
208
TR_DEFAULT_GLOBAL_PEER_LIMIT );
209
getConfigInt( dict, KEY_BLOCKLIST, &blocklistEnabled,
210
TR_DEFAULT_BLOCKLIST_ENABLED );
211
getConfigInt( dict, KEY_RPC_PORT, &rpcPort,
212
TR_DEFAULT_RPC_PORT );
213
getConfigInt( dict, KEY_WHITELIST_ENABLED, &whitelistEnabled,
214
TR_DEFAULT_RPC_WHITELIST_ENABLED );
215
getConfigStr( dict, KEY_WHITELIST, &whitelist,
216
TR_DEFAULT_RPC_WHITELIST );
180
217
getConfigInt( dict, KEY_AUTH_REQUIRED, &authRequired, FALSE );
181
218
getConfigStr( dict, KEY_USERNAME, &username, NULL );
182
219
getConfigStr( dict, KEY_PASSWORD, &password, NULL );
183
getConfigInt( dict, KEY_ENCRYPTION, &encryption, TR_ENCRYPTION_PREFERRED );
220
getConfigInt( dict, KEY_ENCRYPTION, &encryption,
221
TR_DEFAULT_ENCRYPTION );
219
260
tr_bencFree( &state );
222
265
static const char *
225
return "Transmission "LONG_VERSION_STRING" http://www.transmissionbt.com/\n"
268
return "Transmission " LONG_VERSION_STRING
269
" http://www.transmissionbt.com/\n"
226
270
"A fast and easy BitTorrent client\n"
228
MY_NAME" is a headless Transmission session\n"
229
"that can be controlled via transmission-remote or Clutch.\n"
231
"Usage: "MY_NAME" [options]";
272
MY_NAME " is a headless Transmission session\n"
273
"that can be controlled via transmission-remote or Clutch.\n"
275
"Usage: " MY_NAME " [options]";
234
static const struct tr_option options[] = {
235
{ 'a', "acl", "Access Control List. (Default: "TR_DEFAULT_RPC_ACL")", "a", 1, "<list>" },
236
{ 'b', "blocklist", "Enable peer blocklists", "b", 0, NULL },
237
{ 'B', "no-blocklist", "Disable peer blocklists", "B", 0, NULL },
238
{ 'f', "foreground", "Run in the foreground instead of daemonizing", "f", 0, NULL },
239
{ 'g', "config-dir", "Where to look for configuration files", "g", 1, "<path>" },
240
{ 'p', "port", "RPC port (Default: "TR_DEFAULT_RPC_PORT_STR")", "p", 1, "<port>" },
241
{ 't', "auth", "Require authentication", "t", 0, NULL },
242
{ 'T', "no-auth", "Don't require authentication", "T", 0, NULL },
243
{ 'u', "username", "Set username for authentication", "u", 1, "<username>" },
244
{ 'v', "password", "Set password for authentication", "v", 1, "<password>" },
245
{ 'w', "download-dir", "Where to save downloaded data", "w", 1, "<path>" },
246
{ 0, NULL, NULL, NULL, 0, NULL }
278
static const struct tr_option options[] =
281
"Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a",
283
{ 'b', "blocklist", "Enable peer blocklists",
285
{ 'B', "no-blocklist", "Disable peer blocklists",
287
{ 'f', "foreground", "Run in the foreground instead of daemonizing",
289
{ 'g', "config-dir", "Where to look for configuration files",
292
"RPC port (Default: " TR_DEFAULT_RPC_PORT_STR ")", "p",
294
{ 't', "auth", "Require authentication",
296
{ 'T', "no-auth", "Don't require authentication",
298
{ 'u', "username", "Set username for authentication",
299
"u", 1, "<username>" },
300
{ 'v', "password", "Set password for authentication",
301
"v", 1, "<password>" },
302
{ 'w', "download-dir", "Where to save downloaded data",
250
309
showUsage( void )
252
tr_getopt_usage( MY_NAME, getUsage(), options );
311
tr_getopt_usage( MY_NAME, getUsage( ), options );
257
readargs( int argc, const char ** argv,
258
int * nofork, const char ** configDir, const char ** downloadDir,
259
int * rpcPort, const char ** acl,
260
int * authRequired, const char ** username, const char ** password,
261
int * blocklistEnabled )
319
const char ** configDir,
320
const char ** downloadDir,
322
const char ** whitelist,
324
const char ** username,
325
const char ** password,
326
int * blocklistEnabled )
264
329
const char * optarg;
265
while(( c = tr_getopt( getUsage(), argc, argv, options, &optarg )))
331
while( ( c = tr_getopt( getUsage( ), argc, argv, options, &optarg ) ) )
269
case 'a': *acl = optarg; break;
270
case 'b': *blocklistEnabled = 1; break;
271
case 'B': *blocklistEnabled = 0; break;
272
case 'f': *nofork = 1; break;
273
case 'g': *configDir = optarg; break;
274
case 'p': *rpcPort = atoi( optarg ); break;
275
case 't': *authRequired = TRUE; break;
276
case 'T': *authRequired = FALSE; break;
277
case 'u': *username = optarg; break;
278
case 'v': *password = optarg; break;
279
case 'w': *downloadDir = optarg; break;
280
default: showUsage( ); break;
336
*whitelist = optarg; break;
339
*blocklistEnabled = 1; break;
342
*blocklistEnabled = 0; break;
348
*configDir = optarg; break;
351
*rpcPort = atoi( optarg ); break;
354
*authRequired = TRUE; break;
357
*authRequired = FALSE; break;
360
*username = optarg; break;
363
*password = optarg; break;
366
*downloadDir = optarg; break;
291
#if !defined(HAVE_DAEMON)
380
#if !defined( WIN32 )
381
#if !defined( HAVE_DAEMON )
293
daemon( int nochdir, int noclose )
299
tr_nerr( MY_NAME, "Error daemonizing (fork)! %d - %s", errno, strerror(errno) );
306
tr_nerr( MY_NAME, "Error daemonizing (setsid)! %d - %s", errno, strerror(errno) );
314
tr_nerr( MY_NAME, "Error daemonizing (fork2)! %d - %s", errno, strerror(errno) );
320
if( !nochdir && 0 > chdir( "/" ) ) {
321
tr_nerr( MY_NAME, "Error daemonizing (chdir)! %d - %s", errno, strerror(errno) );
392
tr_nerr( MY_NAME, "Error daemonizing (fork)! %d - %s", errno,
403
tr_nerr( MY_NAME, "Error daemonizing (setsid)! %d - %s", errno,
415
tr_nerr( MY_NAME, "Error daemonizing (fork2)! %d - %s", errno,
424
if( !nochdir && 0 > chdir( "/" ) )
426
tr_nerr( MY_NAME, "Error daemonizing (chdir)! %d - %s", errno,
327
if((( fd = open("/dev/null", O_RDONLY))) != 0 ) {
435
if( ( ( fd = open( "/dev/null", O_RDONLY ) ) ) != 0 )
331
if((( fd = open("/dev/null", O_WRONLY))) != 1 ) {
440
if( ( ( fd = open( "/dev/null", O_WRONLY ) ) ) != 1 )
335
if((( fd = open("/dev/null", O_WRONLY))) != 2 ) {
445
if( ( ( fd = open( "/dev/null", O_WRONLY ) ) ) != 2 )
346
main( int argc, char ** argv )
350
int authRequired = -1;
351
int blocklistEnabled = -1;
352
char * freeme = NULL;
463
int authRequired = -1;
464
int blocklistEnabled = -1;
465
char * freeme = NULL;
353
466
const char * configDir = NULL;
354
467
const char * downloadDir = NULL;
355
const char * acl = NULL;
468
const char * whitelist = NULL;
356
469
const char * username = NULL;
357
470
const char * password = NULL;
359
472
signal( SIGINT, gotsig );
473
signal( SIGTERM, gotsig );
360
475
signal( SIGQUIT, gotsig );
361
signal( SIGTERM, gotsig );
362
476
signal( SIGPIPE, SIG_IGN );
363
477
signal( SIGHUP, SIG_IGN );
365
480
readargs( argc, (const char**)argv, &nofork, &configDir, &downloadDir,
366
&rpcPort, &acl, &authRequired, &username, &password,
481
&rpcPort, &whitelist, &authRequired, &username, &password,
367
482
&blocklistEnabled );
368
483
if( configDir == NULL )
369
configDir = freeme = tr_strdup_printf( "%s-daemon", tr_getDefaultConfigDir() );
370
tr_buildPath( myConfigFilename, sizeof( myConfigFilename ),
371
configDir, CONFIG_FILE, NULL );
484
configDir = getenv( "TRANSMISSION_HOME" );
485
if( configDir == NULL )
486
configDir = freeme = tr_strdup_printf( "%s-daemon",
487
tr_getDefaultConfigDir( ) );
488
myConfigFilename = tr_buildPath( configDir, CONFIG_FILE, NULL );
374
if( 0 > daemon( 1, 0 ) ) {
493
if( 0 > daemon( 1, 0 ) )
375
495
fprintf( stderr, "failed to daemonize: %s\n", strerror( errno ) );
380
501
session_init( configDir, downloadDir,
381
rpcPort, acl, authRequired, username, password,
502
rpcPort, whitelist, authRequired, username, password,
382
503
blocklistEnabled );
384
505
while( !closing )
506
tr_wait( 1000 ); /* sleep one second */
387
508
saveState( mySession );
388
509
printf( "Closing transmission session..." );