have daemon and cli use tr-getopt too.

This commit is contained in:
Charles Kerr 2008-07-08 16:50:34 +00:00
parent 33c817cc1f
commit 1cd9f2351e
4 changed files with 170 additions and 193 deletions

View File

@ -26,70 +26,40 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <signal.h>
#include <libtransmission/transmission.h>
#include <libtransmission/bencode.h>
#include <libtransmission/makemeta.h>
#include <libtransmission/metainfo.h> /* tr_metainfoFree */
#include <libtransmission/tr-getopt.h>
#include <libtransmission/utils.h> /* tr_wait */
#include <libtransmission/web.h> /* tr_webRun */
#define MY_NAME "transmission-cli"
/* macro to shut up "unused parameter" warnings */
#ifdef __GNUC__
#define UNUSED __attribute__((unused))
#else
#define UNUSED
#endif
const char * USAGE =
"Usage: %s [-car[-m]] [-dfginpsuv] [-h] file.torrent [output-dir]\n\n"
"Options:\n"
" -h, --help Print this help and exit\n"
" -i, --info Print metainfo and exit\n"
" -s, --scrape Print counts of seeders/leechers and exit\n"
" -V, --version Print the version number and exit\n"
" -c, --create-from <file> Create torrent from the specified source file.\n"
" -a, --announce <url> Used in conjunction with -c.\n"
" -g, --config-dir <path> Where to look for configuration files\n"
" -o, --output-dir <path> Where to save downloaded data\n"
" -r, --private Used in conjunction with -c.\n"
" -m, --comment <text> Adds an optional comment when creating a torrent.\n"
" -d, --download <int> Max download rate (-1 = no limit, default = -1)\n"
" -f, --finish <script> Command you wish to run on completion\n"
" -n --nat-traversal Attempt NAT traversal using NAT-PMP or UPnP IGD\n"
" -p, --port <int> Port we should listen on (default = %d)\n"
" -t, --tos <int> Peer socket TOS (0 to 255, default = 8)\n"
" -u, --upload <int> Maximum upload rate (-1 = no limit, default = 20)\n"
" -v, --verbose <int> Verbose level (0 to 2, default = 0)\n"
" -y, --recheck Force a recheck of the torrent data\n";
static int showHelp = 0;
static int showInfo = 0;
static int showScrape = 0;
static int showVersion = 0;
static int isPrivate = 0;
static int verboseLevel = 0;
static int peerPort = TR_DEFAULT_PORT;
static int peerSocketTOS = TR_DEFAULT_PEER_SOCKET_TOS;
static int uploadLimit = 20;
static int downloadLimit = -1;
static char * torrentPath = NULL;
static int natTraversal = 0;
static int recheckData = 0;
static int verify = 0;
static sig_atomic_t gotsig = 0;
static sig_atomic_t manualUpdate = 0;
static char downloadDir[MAX_PATH_LENGTH] = { '\0' };
static char * finishCall = NULL;
static char * announce = NULL;
static char * configdir = NULL;
static char * sourceFile = NULL;
static char * comment = NULL;
static const char * torrentPath = NULL;
static const char * downloadDir = NULL;
static const char * finishCall = NULL;
static const char * announce = NULL;
static const char * configdir = NULL;
static const char * sourceFile = NULL;
static const char * comment = NULL;
static int parseCommandLine ( int argc, char ** argv );
static int parseCommandLine ( int argc, const char ** argv );
static void sigHandler ( int signal );
static char *
@ -171,34 +141,25 @@ main( int argc, char ** argv )
tr_handle * h;
tr_ctor * ctor;
tr_torrent * tor = NULL;
char cwd[MAX_PATH_LENGTH];
printf( "Transmission %s - http://www.transmissionbt.com/\n",
LONG_VERSION_STRING );
/* Get options */
if( parseCommandLine( argc, argv ) )
{
printf( USAGE, argv[0], TR_DEFAULT_PORT );
if( parseCommandLine( argc, (const char**)argv ) )
return EXIT_FAILURE;
/* Check the options for validity */
if( !torrentPath ) {
printf( "No torrent specified!\n" );
return EXIT_FAILURE;
}
if( showVersion )
return EXIT_SUCCESS;
if( showHelp )
{
printf( USAGE, argv[0], TR_DEFAULT_PORT );
return EXIT_SUCCESS;
}
if( peerPort < 1 || peerPort > 65535 )
{
if( peerPort < 1 || peerPort > 65535 ) {
printf( "Invalid port '%d'\n", peerPort );
return EXIT_FAILURE;
}
if( peerSocketTOS < 0 || peerSocketTOS > 255 )
{
if( peerSocketTOS < 0 || peerSocketTOS > 255 ) {
printf( "Invalid TOS '%d'\n", peerSocketTOS );
return EXIT_FAILURE;
}
@ -209,7 +170,14 @@ main( int argc, char ** argv )
peerPort = -1;
if( configdir == NULL )
configdir = strdup( tr_getDefaultConfigDir( ) );
configdir = tr_getDefaultConfigDir( );
/* if no download directory specified, use cwd instead */
if( !downloadDir ) {
getcwd( cwd, sizeof( cwd ) );
downloadDir = cwd;
}
/* Initialize libtransmission */
h = tr_sessionInitFull(
@ -246,7 +214,7 @@ main( int argc, char ** argv )
tr_metainfo_builder * builder = tr_metaInfoBuilderCreate( h, sourceFile );
tr_tracker_info ti;
ti.tier = 0;
ti.announce = announce;
ti.announce = (char*) announce;
tr_makeMetaInfo( builder, torrentPath, &ti, 1, comment, isPrivate );
while( !builder->isDone ) {
tr_wait( 1000 );
@ -384,9 +352,9 @@ main( int argc, char ** argv )
}
}
if( recheckData )
if( verify )
{
recheckData = 0;
verify = 0;
tr_torrentVerify( tor );
}
@ -456,89 +424,104 @@ cleanup:
return EXIT_SUCCESS;
}
static int
parseCommandLine( int argc, char ** argv )
/***
****
****
****
***/
static const char *
getUsage( void )
{
for( ;; )
return "A fast and easy BitTorrent client\n"
"\n"
"Usage: "MY_NAME" [options] <torrent-filename>";
}
const struct tr_option options[] = {
{ 'a', "announce", "When creating a new torrent, set its announce URL", "a", 1, "<url>" },
{ 'c', "comment", "When creating a new torrent, set its comment field", "c", 1, "<comment>" },
{ 'd', "downlimit", "Set the maxiumum download speed in KB/s", "d", 1, "<number>" },
{ 'D', "no-downlimit", "Don't limit the download speed", "D", 0, NULL },
{ 'f', "finish", "Set a script to run when the torrent finishes", "f", 1, "<script>" },
{ 'g', "config-dir", "Where to look for configuration files", "g", 1, "<path>" },
{ 'i', "info", "Show torrent details and exit", "i", 0, NULL },
{ 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", 0, NULL },
{ 'M', "no-portmap", "Disable portmapping", "M", 0, NULL },
{ 'n', "new", "Create a new torrent from a file or directory", "n", 1, "<path>" },
{ 'p', "port", "Port to listen for incoming peers (Default: "TR_DEFAULT_RPC_PORT_STR")", "p", 1, "<port>" },
{ 'r', "private", "When creating a new torrent, set its 'private' flag", "r", 0, NULL },
{ 's', "scrape", "Scrape the torrent and exit", "s", 0, NULL },
{ 't', "tos", "Peer socket TOS (0 to 255, default="TR_DEFAULT_PEER_SOCKET_TOS_STR")", "t", 1, "<number>"},
{ 'u', "uplimit", "Set the maxiumum upload speed in KB/s", "u", 1, "<number>" },
{ 'U', "no-uplimit", "Don't limit the upload speed", "U", 0, NULL },
{ 'v', "verify", "Verify the specified torrent", "v", 0, NULL },
{ 'w', "download-dir", "Where to save downloaded data", "w", 1, "<path>" },
{ 0, NULL, NULL, NULL, 0, NULL }
};
static void
showUsage( void )
{
tr_getopt_usage( MY_NAME, getUsage(), options );
exit( 0 );
}
static int
numarg( const char * arg )
{
char * end = NULL;
const long num = strtol( arg, &end, 10 );
if( *end ) {
fprintf( stderr, "Not a number: \"%s\"\n", arg );
showUsage( );
}
return num;
}
static int
parseCommandLine( int argc, const char ** argv )
{
int c;
const char * optarg;
while(( c = tr_getopt( getUsage(), argc, argv, options, &optarg )))
{
static const struct option long_options[] = {
{ "announce", required_argument, NULL, 'a' },
{ "create-from", required_argument, NULL, 'c' },
{ "download", required_argument, NULL, 'd' },
{ "finish", required_argument, NULL, 'f' },
{ "config-dir", required_argument, NULL, 'g' },
{ "help", no_argument, NULL, 'h' },
{ "info", no_argument, NULL, 'i' },
{ "comment", required_argument, NULL, 'm' },
{ "nat-traversal", no_argument, NULL, 'n' },
{ "output-dir", required_argument, NULL, 'o' },
{ "port", required_argument, NULL, 'p' },
{ "private", no_argument, NULL, 'r' },
{ "scrape", no_argument, NULL, 's' },
{ "tos", required_argument, NULL, 't' },
{ "upload", required_argument, NULL, 'u' },
{ "verbose", required_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ "recheck", no_argument, NULL, 'y' },
{ 0, 0, 0, 0} };
int optind = 0;
int c = getopt_long( argc, argv,
"a:c:d:f:g:him:no:p:rst:u:v:Vy",
long_options, &optind );
if( c < 0 )
{
break;
}
switch( c )
{
case 'a': announce = optarg; break;
case 'c': sourceFile = optarg; break;
case 'd': downloadLimit = atoi( optarg ); break;
case 'c': comment = optarg; break;
case 'd': downloadLimit = numarg( optarg ); break;
case 'D': downloadLimit = -1; break;
case 'f': finishCall = optarg; break;
case 'g': configdir = strdup( optarg ); break;
case 'h': showHelp = 1; break;
case 'g': configdir = optarg; break;
case 'i': showInfo = 1; break;
case 'm': comment = optarg; break;
case 'n': natTraversal = 1; break;
case 'o': tr_strlcpy( downloadDir, optarg, sizeof( downloadDir ) ); break;
case 'p': peerPort = atoi( optarg ); break;
case 'm': natTraversal = 1; break;
case 'M': natTraversal = 0; break;
case 'n': sourceFile = optarg; break;
case 'p': peerPort = numarg( optarg ); break;
case 'r': isPrivate = 1; break;
case 's': showScrape = 1; break;
case 't': peerSocketTOS = atoi( optarg ); break;
case 'u': uploadLimit = atoi( optarg ); break;
case 'v': verboseLevel = atoi( optarg ); break;
case 'V': showVersion = 1; break;
case 'y': recheckData = 1; break;
case 't': peerSocketTOS = numarg( optarg ); break;
case 'u': uploadLimit = numarg( optarg ); break;
case 'U': uploadLimit = -1; break;
case 'v': verify = 1; break;
case 'w': downloadDir = optarg; break;
case TR_OPT_UNK: torrentPath = optarg; break;
default: return 1;
}
}
if( !*downloadDir )
getcwd( downloadDir, sizeof( downloadDir ) );
if( showHelp || showVersion )
return 0;
if( optind >= argc )
return 1;
torrentPath = argv[optind];
return 0;
}
static void sigHandler( int signal )
static void
sigHandler( int signal )
{
switch( signal )
{
case SIGINT:
gotsig = 1;
break;
case SIGHUP:
manualUpdate = 1;
break;
default:
break;
case SIGINT: gotsig = 1; break;
case SIGHUP: manualUpdate = 1; break;
default: break;
}
}

View File

@ -17,13 +17,13 @@
#include <string.h> /* strcmp */
#include <fcntl.h> /* open */
#include <getopt.h>
#include <signal.h>
#include <unistd.h> /* daemon, getcwd */
#include <libtransmission/transmission.h>
#include <libtransmission/bencode.h>
#include <libtransmission/rpc.h>
#include <libtransmission/tr-getopt.h>
#include <libtransmission/utils.h>
#include <libtransmission/version.h>
@ -89,7 +89,6 @@ saveState( tr_session * s )
replaceInt( &d, KEY_DSPEED, tr_sessionGetSpeedLimit( s, TR_DOWN ) );
replaceInt( &d, KEY_DSPEED_ENABLED, tr_sessionIsSpeedLimitEnabled( s, TR_DOWN ) );
replaceInt( &d, KEY_USPEED, tr_sessionGetSpeedLimit( s, TR_UP ) );
fprintf( stderr, "session says its speed upload speed limit is %d\n", tr_sessionGetSpeedLimit( s, TR_UP ) );
replaceInt( &d, KEY_USPEED_ENABLED, tr_sessionIsSpeedLimitEnabled( s, TR_UP ) );
replaceInt( &d, KEY_ENCRYPTION, tr_sessionGetEncryption( s ) );
@ -213,66 +212,64 @@ session_init( const char * configDir, const char * downloadDir,
tr_bencFree( &state );
}
static void
daemonUsage( void )
static const char *
getUsage( void )
{
puts( "Usage: " MY_NAME " [options]\n"
"\n"
"Transmission "LONG_VERSION_STRING" http://www.transmissionbt.com/\n"
"A fast and easy BitTorrent client\n"
"\n"
" -a --acl <list> Access Control List. (Default: "TR_DEFAULT_RPC_ACL")\n"
" -b --blocklist Enable peer blocklists\n"
" -b0 --blocklist=0 Disable peer blocklists\n"
" -d --download-dir <dir> Where store downloaded data\n"
" -f --foreground Run in the foreground and log to stderr\n"
" -g --config-dir <dir> Where to look for torrents and "CONFIG_FILE"\n"
" -h --help Display this message and exit\n"
" -p --port=n Port to listen to for requests (Default: "TR_DEFAULT_RPC_PORT_STR")\n"
" -t --auth Require authentication\n"
" -t0 --auth=0 Don't require authentication\n"
" -u --username <user> Set username for authentication\n"
" -w --password <pass> Set password for authentication\n"
"\n"
MY_NAME" is a headless Transmission session\n"
"that can be controlled via transmission-remote or Clutch.\n" );
return "Transmission "LONG_VERSION_STRING" http://www.transmissionbt.com/\n"
"A fast and easy BitTorrent client\n"
"\n"
MY_NAME" is a headless Transmission session\n"
"that can be controlled via transmission-remote or Clutch.\n"
"\n"
"Usage: "MY_NAME" [options]";
}
const struct tr_option options[] = {
{ 'a', "acl", "Access Control List. (Default: "TR_DEFAULT_RPC_ACL")", "a", 1, "<list>" },
{ 'b', "blocklist", "Enable peer blocklists", "b", 0, NULL },
{ 'B', "no-blocklist", "Disable peer blocklists", "B", 0, NULL },
{ 'f', "foreground", "Run in the foreground instead of daemonizing", "f", 0, NULL },
{ 'g', "config-dir", "Where to look for configuration files", "g", 1, "<path>" },
{ 'p', "port", "Port to listen for incoming peers (Default: "TR_DEFAULT_RPC_PORT_STR")", "p", 1, "<port>" },
{ 't', "auth", "Requre authentication", "t", 0, NULL },
{ 'T', "no-auth", "Don't require authentication", "T", 0, NULL },
{ 'u', "username", "Set username for authentication", "u", 1, "<username>" },
{ 's', "password", "Set password for authentication", "s", 1, "<password>" },
{ 'w', "download-dir", "Where to save downloaded data", "w", 1, "<path>" },
{ 0, NULL, NULL, NULL, 0, NULL }
};
static void
showUsage( void )
{
tr_getopt_usage( MY_NAME, getUsage(), options );
exit( 0 );
}
static void
readargs( int argc, char ** argv,
int * nofork, char ** configDir, char ** downloadDir,
int * rpcPort, char ** acl, int * authRequired, char ** username, char ** password,
readargs( int argc, const char ** argv,
int * nofork, const char ** configDir, const char ** downloadDir,
int * rpcPort, const char ** acl, int * authRequired, const char ** username, const char ** password,
int * blocklistEnabled )
{
int opt;
char shortopts[] = "a:b::d:fg:hp:t::u:w:";
struct option longopts[] = {
{ "acl", required_argument, NULL, 'a' },
{ "blocklist", optional_argument, NULL, 'b' },
{ "download-dir", required_argument, NULL, 'd' },
{ "foreground", no_argument, NULL, 'f' },
{ "config-dir", required_argument, NULL, 'g' },
{ "help", no_argument, NULL, 'h' },
{ "port", required_argument, NULL, 'p' },
{ "auth", optional_argument, NULL, 't' },
{ "username", required_argument, NULL, 'u' },
{ "password", required_argument, NULL, 'w' },
{ NULL, 0, NULL, '\0' }
};
while((( opt = getopt_long( argc, argv, shortopts, longopts, NULL ))) != -1 ) {
switch( opt ) {
case 'a': *acl = tr_strdup( optarg ); break;
case 'b': *blocklistEnabled = optarg ? atoi(optarg)!=0 : TRUE; break;
case 'd': *downloadDir = tr_strdup( optarg ); break;
int c;
const char * optarg;
while(( c = tr_getopt( getUsage(), argc, argv, options, &optarg )))
{
switch( c )
{
case 'a': *acl = optarg; break;
case 'b': *blocklistEnabled = 1; break;
case 'B': *blocklistEnabled = 0; break;
case 'f': *nofork = 1; break;
case 'n': *authRequired = FALSE; break;
case 'g': *configDir = tr_strdup( optarg ); break;
case 't': *authRequired = optarg ? atoi(optarg)!=0 : TRUE; break;
case 'u': *username = tr_strdup( optarg ); break;
case 'w': *password = tr_strdup( optarg ); break;
case 'g': *configDir = optarg; break;
case 'p': *rpcPort = atoi( optarg ); break;
default: daemonUsage( ); break;
case 't': *authRequired = TRUE; break;
case 'T': *authRequired = FALSE; break;
case 'u': *username = optarg; break;
case 's': *password = optarg; break;
case 'w': *downloadDir = optarg; break;
default: showUsage( ); break;
}
}
}
@ -344,11 +341,11 @@ main( int argc, char ** argv )
int rpcPort = -1;
int authRequired = -1;
int blocklistEnabled = -1;
char * configDir = NULL;
char * downloadDir = NULL;
char * acl = NULL;
char * username = NULL;
char * password = NULL;
const char * configDir = NULL;
const char * downloadDir = NULL;
const char * acl = NULL;
const char * username = NULL;
const char * password = NULL;
signal( SIGINT, gotsig );
signal( SIGQUIT, gotsig );
@ -356,7 +353,7 @@ main( int argc, char ** argv )
signal( SIGPIPE, SIG_IGN );
signal( SIGHUP, SIG_IGN );
readargs( argc, argv, &nofork, &configDir, &downloadDir,
readargs( argc, (const char*)argv, &nofork, &configDir, &downloadDir,
&rpcPort, &acl, &authRequired, &username, &password,
&blocklistEnabled );
if( configDir == NULL )
@ -383,10 +380,5 @@ main( int argc, char ** argv )
tr_sessionClose( mySession );
printf( " done.\n" );
tr_free( configDir );
tr_free( downloadDir );
tr_free( username );
tr_free( password );
tr_free( acl );
return 0;
}

View File

@ -72,7 +72,7 @@ tr_getopt_usage( const char * progName,
description = "Usage: %s [options]";
printf( description, progName );
printf( "\n\n" );
printf( "Usage:\n" );
printf( "Options:\n" );
help.val = -1;
help.longName = "help";

View File

@ -115,6 +115,8 @@ tr_proxy_type;
/** @see tr_sessionInitFull */
#define TR_DEFAULT_PEER_SOCKET_TOS 8
/** @see tr_sessionInitFull */
#define TR_DEFAULT_PEER_SOCKET_TOS_STR "8"
/** @see tr_sessionInitFull */
#define TR_DEFAULT_BLOCKLIST_ENABLED 0
/** @see tr_sessionInitFull */
#define TR_DEFAULT_RPC_ENABLED 0