2013-02-27 14:25:14 +00:00
using System ;
2013-02-12 21:43:14 +00:00
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
2014-07-25 14:09:26 +02:00
using Duplicati.Library.Localization.Short ;
2013-02-12 21:43:14 +00:00
namespace Duplicati.Server
{
public class Program
{
/// <summary>
/// The path to the directory that contains the main executable
/// </summary>
2014-07-02 20:46:50 +02:00
public static readonly string StartupPath = Duplicati . Library . AutoUpdater . UpdaterManager . InstalledBaseDir ;
2013-02-12 21:43:14 +00:00
/// <summary>
/// The name of the environment variable that holds the path to the data folder used by Duplicati
/// </summary>
2014-07-02 20:46:50 +02:00
public static readonly string DATAFOLDER_ENV_NAME = Duplicati . Library . AutoUpdater . AutoUpdateSettings . AppName . ToUpper () + "_HOME" ;
2013-02-12 21:43:14 +00:00
/// <summary>
/// The environment variable that holdes the database key used to encrypt the SQLite database
/// </summary>
2014-07-02 20:46:50 +02:00
public static readonly string DB_KEY_ENV_NAME = Duplicati . Library . AutoUpdater . AutoUpdateSettings . AppName . ToUpper () + "_DB_KEY" ;
2013-02-12 21:43:14 +00:00
/// <summary>
/// Gets the folder where Duplicati data is stored
/// </summary>
public static string DATAFOLDER { get { return Library . Utility . Utility . AppendDirSeparator ( Environment . ExpandEnvironmentVariables ( "%" + DATAFOLDER_ENV_NAME + "%" ). TrimStart ( '"' ). TrimEnd ( '"' )); } }
2014-03-21 10:34:34 +01:00
/// <summary>
/// The single instance
/// </summary>
public static SingleInstance Instance = null ;
2013-02-12 21:43:14 +00:00
/// <summary>
/// A flag indicating if database encryption is in use
/// </summary>
public static bool UseDatabaseEncryption ;
/// <summary>
/// This is the only access to the database
/// </summary>
2013-11-23 14:26:36 +01:00
public static Database . Connection DataConnection ;
2013-02-12 21:43:14 +00:00
/// <summary>
/// This is the lock to be used before manipulating the shared resources
/// </summary>
public static object MainLock = new object ();
/// <summary>
/// This is the scheduling thread
/// </summary>
public static Scheduler Scheduler ;
/// <summary>
/// This is the working thread
/// </summary>
2014-03-17 15:27:25 +01:00
public static Duplicati . Library . Utility . WorkerThread < Runner . IRunnerData > WorkThread ;
2013-02-12 21:43:14 +00:00
2014-07-25 14:09:26 +02:00
/// <summary>
/// The thread running the ping-pong handler
/// </summary>
public static System . Threading . Thread PingPongThread ;
2013-02-12 21:43:14 +00:00
/// <summary>
/// The path to the file that contains the current database
/// </summary>
public static string DatabasePath ;
/// <summary>
/// The controller interface for pause/resume and throttle options
/// </summary>
public static LiveControls LiveControl ;
/// <summary>
/// The application exit event
/// </summary>
public static System . Threading . ManualResetEvent ApplicationExitEvent ;
/// <summary>
/// The webserver instance
/// </summary>
2014-06-27 13:23:05 +02:00
public static WebServer . Server WebServer ;
2014-06-30 11:31:06 +02:00
/// <summary>
/// The update poll thread.
/// </summary>
public static UpdatePollThread UpdatePoller ;
2013-02-12 21:43:14 +00:00
/// <summary>
/// An event that is set once the server is ready to respond to requests
/// </summary>
public static System . Threading . ManualResetEvent ServerStartedEvent = new System . Threading . ManualResetEvent ( false );
/// <summary>
/// The status event signaler, used to controll long polling of status updates
/// </summary>
public static EventPollNotify StatusEventNotifyer = new EventPollNotify ();
2014-03-10 00:16:53 +01:00
2013-02-12 21:43:14 +00:00
/// <summary>
2014-03-10 00:16:53 +01:00
/// A delegate method for creating a copy of the current progress state
2013-02-12 21:43:14 +00:00
/// </summary>
2014-06-27 13:23:05 +02:00
public static Func < Duplicati . Server . Serialization . Interface . IProgressEventData > GenerateProgressState ;
2013-02-12 21:43:14 +00:00
/// <summary>
/// An event ID that increases whenever the database is updated
/// </summary>
public static long LastDataUpdateID = 0 ;
2014-08-01 11:18:10 +02:00
/// <summary>
/// The log redirect handler
/// </summary>
public static LogWriteHandler LogHandler = new LogWriteHandler ();
2013-12-07 15:24:57 +01:00
public static int ServerPort
{
get
{
return WebServer . Port ;
}
}
2013-02-12 21:43:14 +00:00
2014-06-23 11:22:54 +02:00
public static bool IsFirstRun
{
get { return DataConnection . ApplicationSettings . IsFirstRun ; }
set { DataConnection . ApplicationSettings . IsFirstRun = value ; }
}
public static bool ServerPortChanged
{
get { return DataConnection . ApplicationSettings . ServerPortChanged ; }
set { DataConnection . ApplicationSettings . ServerPortChanged = value ; }
}
2013-02-12 21:43:14 +00:00
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
2014-06-26 22:37:58 +02:00
public static int Main ( string [] args )
{
2014-07-02 20:46:50 +02:00
return Duplicati . Library . AutoUpdater . UpdaterManager . RunFromMostRecent ( typeof ( Program ). GetMethod ( "RealMain" ), args , Duplicati . Library . AutoUpdater . AutoUpdateStrategy . Never );
2014-06-26 22:37:58 +02:00
}
public static void RealMain ( string [] args )
2013-02-12 21:43:14 +00:00
{
//If we are on Windows, append the bundled "win-tools" programs to the search path
//We add it last, to allow the user to override with other versions
if (! Library . Utility . Utility . IsClientLinux )
{
Environment . SetEnvironmentVariable ( "PATH" ,
Environment . GetEnvironmentVariable ( "PATH" ) +
System . IO . Path . PathSeparator . ToString () +
System . IO . Path . Combine (
System . IO . Path . GetDirectoryName ( System . Reflection . Assembly . GetExecutingAssembly (). Location ),
"win-tools" )
);
}
2013-02-27 14:25:14 +00:00
//If this executable is invoked directly, write to console, otherwise throw exceptions
bool writeConsole = System . Reflection . Assembly . GetEntryAssembly () == System . Reflection . Assembly . GetExecutingAssembly ();
2013-02-12 21:43:14 +00:00
//If we are on windows we encrypt the database by default
//We do not encrypt on Linux as most distros use a SQLite library without encryption support,
//Linux users can use an encrypted home folder, or install a SQLite library with encryption support
if (! Library . Utility . Utility . IsClientLinux && string . IsNullOrEmpty ( Environment . GetEnvironmentVariable ( DB_KEY_ENV_NAME )))
{
//Note that the password here is a default password and public knowledge
//
//The purpose of this is to prevent casual read of the database, as well
// as protect from harddisk string scans, not to protect from determined
// attacks.
//
//If you desire better security, start Duplicati once with the commandline option
// --unencrypted-database to decrypt the database.
//Then set the environment variable DUPLICATI_DB_KEY to the desired key,
// and run Duplicati again without the --unencrypted-database option
// to re-encrypt it with the new key
//
//If you change the key, please note that you need to supply the same
// key when restoring the setup, as the setup being backed up will
// be encrypted as well.
2014-07-02 20:46:50 +02:00
Environment . SetEnvironmentVariable ( DB_KEY_ENV_NAME , Library . AutoUpdater . AutoUpdateSettings . AppName + "_Key_42" );
2013-02-12 21:43:14 +00:00
}
//Find commandline options here for handling special startup cases
Dictionary < string , string > commandlineOptions = Duplicati . Library . Utility . CommandLineParser . ExtractOptions ( new List < string >( args ));
2014-07-25 14:09:26 +02:00
foreach ( string s in args )
2013-02-12 21:43:14 +00:00
if (
s . Equals ( "help" , StringComparison . InvariantCultureIgnoreCase ) ||
s . Equals ( "/help" , StringComparison . InvariantCultureIgnoreCase ) ||
s . Equals ( "usage" , StringComparison . InvariantCultureIgnoreCase ) ||
s . Equals ( "/usage" , StringComparison . InvariantCultureIgnoreCase ))
commandlineOptions [ "help" ] = "" ;
//If the commandline issues --help, just stop here
if ( commandlineOptions . ContainsKey ( "help" ))
{
2013-02-27 14:25:14 +00:00
if ( writeConsole )
{
Console . WriteLine ( Strings . Program . HelpDisplayDialog );
2014-07-25 14:09:26 +02:00
foreach ( Library . Interface . ICommandLineArgument arg in SupportedCommands )
2013-02-27 14:25:14 +00:00
Console . WriteLine ( Strings . Program . HelpDisplayFormat , arg . Name , arg . LongDescription );
2013-02-12 21:43:14 +00:00
2013-02-27 14:25:14 +00:00
return ;
}
else
{
throw new Exception ( "Server invoked with --help" );
}
2013-02-12 21:43:14 +00:00
}
#if DEBUG
//Log various information in the logfile
if (! commandlineOptions . ContainsKey ( "log-file" ))
{
commandlineOptions [ "log-file" ] = System . IO . Path . Combine ( StartupPath , "Duplicati.debug.log" );
commandlineOptions [ "log-level" ] = Duplicati . Library . Logging . LogMessageType . Profiling . ToString ();
}
#endif
//Set the %DUPLICATI_HOME% env variable, if it is not already set
if ( string . IsNullOrEmpty ( Environment . GetEnvironmentVariable ( DATAFOLDER_ENV_NAME )))
{
#if DEBUG
//debug mode uses a lock file located in the app folder
2014-07-02 20:46:50 +02:00
Environment . SetEnvironmentVariable ( DATAFOLDER_ENV_NAME , StartupPath );
2013-02-12 21:43:14 +00:00
#else
bool portableMode = commandlineOptions . ContainsKey ( "portable-mode" ) ? Library . Utility . Utility . ParseBool ( commandlineOptions [ "portable-mode" ], true ) : false ;
if ( portableMode )
{
//Portable mode uses a data folder in the application home dir
Environment . SetEnvironmentVariable ( DATAFOLDER_ENV_NAME , System . IO . Path . Combine ( StartupPath , "data" ));
}
else
{
//Normal release mode uses the systems "Application Data" folder
2014-07-18 22:58:56 +02:00
Environment . SetEnvironmentVariable ( DATAFOLDER_ENV_NAME , System . IO . Path . Combine ( System . Environment . GetFolderPath ( Environment . SpecialFolder . ApplicationData ), Library . AutoUpdater . AutoUpdateSettings . AppName ));
2013-02-12 21:43:14 +00:00
}
#endif
}
try
{
try
{
//This will also create Program.DATAFOLDER if it does not exist
2014-07-02 20:46:50 +02:00
Instance = new SingleInstance ( Duplicati . Library . AutoUpdater . AutoUpdateSettings . AppName , Program . DATAFOLDER );
2013-02-12 21:43:14 +00:00
}
catch ( Exception ex )
{
2013-02-27 14:25:14 +00:00
if ( writeConsole )
{
Console . WriteLine ( Strings . Program . StartupFailure , ex . ToString ());
return ;
}
else
{
throw new Exception ( Strings . Program . StartupFailure , ex );
}
2013-02-12 21:43:14 +00:00
}
2014-03-21 10:34:34 +01:00
if (! Instance . IsFirstInstance )
2013-02-12 21:43:14 +00:00
{
2013-02-27 14:25:14 +00:00
if ( writeConsole )
{
Console . WriteLine ( Strings . Program . AnotherInstanceDetected );
return ;
}
else
{
2014-03-21 10:34:34 +01:00
throw new SingleInstance . MultipleInstanceException ( Strings . Program . AnotherInstanceDetected );
2013-02-27 14:25:14 +00:00
}
2013-02-12 21:43:14 +00:00
}
2014-08-01 11:18:10 +02:00
// Setup the log redirect
Duplicati . Library . Logging . Log . CurrentLog = Program . LogHandler ;
2014-03-21 10:34:34 +01:00
if ( commandlineOptions . ContainsKey ( "log-file" ))
{
if ( System . IO . File . Exists ( commandlineOptions [ "log-file" ]))
System . IO . File . Delete ( commandlineOptions [ "log-file" ]);
2014-08-01 11:18:10 +02:00
var loglevel = Duplicati . Library . Logging . LogMessageType . Error ;
if ( commandlineOptions . ContainsKey ( "log-level" ))
Enum . TryParse < Duplicati . Library . Logging . LogMessageType >( commandlineOptions [ "log-level" ], true , out loglevel );
Program . LogHandler . SetServerFile ( commandlineOptions [ "log-file" ], loglevel );
2014-03-21 10:34:34 +01:00
}
2013-02-27 14:25:14 +00:00
2014-04-07 11:59:33 +02:00
Version sqliteVersion = new Version (( string ) Duplicati . Library . SQLiteHelper . SQLiteLoader . SQLiteConnectionType . GetProperty ( "SQLiteVersion" ). GetValue ( null , null ));
2013-02-12 21:43:14 +00:00
if ( sqliteVersion < new Version ( 3 , 6 , 3 ))
{
2013-02-27 14:25:14 +00:00
if ( writeConsole )
{
//The official Mono SQLite provider is also broken with less than 3.6.3
Console . WriteLine ( Strings . Program . WrongSQLiteVersion , sqliteVersion , "3.6.3" );
return ;
}
else
{
throw new Exception ( string . Format ( Strings . Program . WrongSQLiteVersion , sqliteVersion , "3.6.3" ));
}
2013-02-12 21:43:14 +00:00
}
//Create the connection instance
2014-04-07 11:59:33 +02:00
System . Data . IDbConnection con = ( System . Data . IDbConnection ) Activator . CreateInstance ( Duplicati . Library . SQLiteHelper . SQLiteLoader . SQLiteConnectionType );
2013-02-12 21:43:14 +00:00
try
{
2014-04-02 11:36:04 +02:00
DatabasePath = System . IO . Path . Combine ( Program . DATAFOLDER , "Duplicati-server.sqlite" );
2013-02-12 21:43:14 +00:00
if (! System . IO . Directory . Exists ( System . IO . Path . GetDirectoryName ( DatabasePath )))
System . IO . Directory . CreateDirectory ( System . IO . Path . GetDirectoryName ( DatabasePath ));
#if DEBUG
//Default is to not use encryption for debugging
Program . UseDatabaseEncryption = commandlineOptions . ContainsKey ( "unencrypted-database" ) ? ! Library . Utility . Utility . ParseBool ( commandlineOptions [ "unencrypted-database" ], true ) : false ;
#else
Program . UseDatabaseEncryption = commandlineOptions . ContainsKey ( "unencrypted-database" ) ? ! Library . Utility . Utility . ParseBool ( commandlineOptions [ "unencrypted-database" ], true ) : true ;
#endif
con . ConnectionString = "Data Source=" + DatabasePath ;
//Attempt to open the database, handling any encryption present
OpenDatabase ( con );
2014-04-07 11:59:33 +02:00
Duplicati . Library . SQLiteHelper . DatabaseUpgrader . UpgradeDatabase ( con , DatabasePath , typeof ( Duplicati . Server . Database . Connection ));
2013-02-12 21:43:14 +00:00
}
catch ( Exception ex )
{
//Unwrap the reflection exceptions
if ( ex is System . Reflection . TargetInvocationException && ex . InnerException != null )
ex = ex . InnerException ;
2013-02-27 14:25:14 +00:00
if ( writeConsole )
{
Console . WriteLine ( Strings . Program . DatabaseOpenError , ex . Message );
return ;
}
else
{
throw new Exception ( string . Format ( Strings . Program . DatabaseOpenError , ex . Message ), ex );
}
2013-02-12 21:43:14 +00:00
}
2013-11-23 14:26:36 +01:00
DataConnection = new Duplicati . Server . Database . Connection ( con );
2013-02-12 21:43:14 +00:00
2014-06-30 11:31:06 +02:00
if ( commandlineOptions . ContainsKey ( "webservice-password" ))
Program . DataConnection . ApplicationSettings . SetWebserverPassword ( commandlineOptions [ "webservice-password" ]);
2014-06-27 13:23:05 +02:00
2013-02-12 21:43:14 +00:00
ApplicationExitEvent = new System . Threading . ManualResetEvent ( false );
2014-07-02 20:46:50 +02:00
2014-07-25 14:09:26 +02:00
Duplicati . Library . AutoUpdater . UpdaterManager . OnError += ( Exception obj ) =>
{
2014-07-01 23:59:30 +02:00
Program . DataConnection . LogError ( null , "Error in updater" , obj );
};
2014-06-30 11:31:06 +02:00
UpdatePoller = new UpdatePollThread ();
2013-11-23 14:26:36 +01:00
LiveControl = new LiveControls ( DataConnection . ApplicationSettings );
2013-02-12 21:43:14 +00:00
LiveControl . StateChanged += new EventHandler ( LiveControl_StateChanged );
LiveControl . ThreadPriorityChanged += new EventHandler ( LiveControl_ThreadPriorityChanged );
LiveControl . ThrottleSpeedChanged += new EventHandler ( LiveControl_ThrottleSpeedChanged );
2014-07-25 14:09:26 +02:00
Program . WorkThread = new Duplicati . Library . Utility . WorkerThread < Runner . IRunnerData >(( x ) =>
{
Runner . Run ( x , true );
}, LiveControl . State == LiveControls . LiveControlState . Paused );
2013-11-25 09:14:09 +01:00
Program . Scheduler = new Scheduler ( WorkThread );
2013-02-12 21:43:14 +00:00
Program . WorkThread . StartingWork += new EventHandler ( SignalNewEvent );
Program . WorkThread . CompletedWork += new EventHandler ( SignalNewEvent );
Program . WorkThread . WorkQueueChanged += new EventHandler ( SignalNewEvent );
Program . Scheduler . NewSchedule += new EventHandler ( SignalNewEvent );
2014-06-27 13:23:05 +02:00
Program . WebServer = new WebServer . Server ( commandlineOptions );
2013-02-12 21:43:14 +00:00
2014-06-23 11:22:54 +02:00
if ( Program . WebServer . Port != DataConnection . ApplicationSettings . LastWebserverPort )
ServerPortChanged = true ;
DataConnection . ApplicationSettings . LastWebserverPort = Program . WebServer . Port ;
2014-07-25 14:09:26 +02:00
if ( Library . Utility . Utility . ParseBoolOption ( commandlineOptions , "ping-pong-keepalive" ))
{
Program . PingPongThread = new System . Threading . Thread ( PingPongMethod );
Program . PingPongThread . IsBackground = true ;
Program . PingPongThread . Start ();
}
2013-02-12 21:43:14 +00:00
ServerStartedEvent . Set ();
ApplicationExitEvent . WaitOne ();
}
2014-03-21 10:34:34 +01:00
catch ( SingleInstance . MultipleInstanceException mex )
{
System . Diagnostics . Trace . WriteLine ( string . Format ( Strings . Program . SeriousError , mex . ToString ()));
if ( writeConsole )
Console . WriteLine ( Strings . Program . SeriousError , mex . ToString ());
else
throw mex ;
}
2013-02-12 21:43:14 +00:00
catch ( Exception ex )
{
System . Diagnostics . Trace . WriteLine ( string . Format ( Strings . Program . SeriousError , ex . ToString ()));
2013-02-27 14:25:14 +00:00
if ( writeConsole )
Console . WriteLine ( Strings . Program . SeriousError , ex . ToString ());
else
throw new Exception ( string . Format ( Strings . Program . SeriousError , ex . ToString ()), ex );
2013-02-12 21:43:14 +00:00
}
2013-02-27 14:25:14 +00:00
finally
{
StatusEventNotifyer . SignalNewEvent ();
2013-02-12 21:43:14 +00:00
2014-06-30 11:31:06 +02:00
if ( UpdatePoller != null )
UpdatePoller . Terminate ();
2013-02-27 14:25:14 +00:00
if ( Scheduler != null )
Scheduler . Terminate ( true );
if ( WorkThread != null )
WorkThread . Terminate ( true );
2014-03-21 10:34:34 +01:00
if ( Instance != null )
Instance . Dispose ();
2013-02-12 21:43:14 +00:00
2014-07-25 14:09:26 +02:00
if ( PingPongThread != null )
try { PingPongThread . Abort (); }
catch { }
2014-08-01 11:18:10 +02:00
if ( LogHandler != null )
LogHandler . Dispose ();
2013-02-27 14:25:14 +00:00
}
2013-02-12 21:43:14 +00:00
}
private static void SignalNewEvent ( object sender , EventArgs e )
{
StatusEventNotifyer . SignalNewEvent ();
}
/// <summary>
/// Handles a change in the LiveControl and updates the Runner
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void LiveControl_ThreadPriorityChanged ( object sender , EventArgs e )
2013-05-05 17:54:59 +02:00
{
2013-02-12 21:43:14 +00:00
StatusEventNotifyer . SignalNewEvent ();
}
/// <summary>
/// Handles a change in the LiveControl and updates the Runner
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void LiveControl_ThrottleSpeedChanged ( object sender , EventArgs e )
{
StatusEventNotifyer . SignalNewEvent ();
}
/// <summary>
/// This event handler updates the trayicon menu with the current state of the runner.
/// </summary>
static void LiveControl_StateChanged ( object sender , EventArgs e )
{
switch ( LiveControl . State )
{
case LiveControls . LiveControlState . Paused :
2014-05-15 12:47:16 +02:00
{
WorkThread . Pause ();
var t = WorkThread . CurrentTask ;
if ( t != null )
t . Pause ();
break ;
}
2013-02-12 21:43:14 +00:00
case LiveControls . LiveControlState . Running :
2014-05-15 12:47:16 +02:00
{
WorkThread . Resume ();
var t = WorkThread . CurrentTask ;
if ( t != null )
t . Resume ();
break ;
}
2013-02-12 21:43:14 +00:00
}
StatusEventNotifyer . SignalNewEvent ();
}
/// <summary>
/// Returns a localized name for a task type
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
2014-06-27 13:23:05 +02:00
public static string LocalizeTaskType ( Duplicati . Server . Serialization . DuplicatiOperation type )
2013-02-12 21:43:14 +00:00
{
switch ( type )
{
2014-06-27 13:23:05 +02:00
case Duplicati . Server . Serialization . DuplicatiOperation . Backup :
2013-02-12 21:43:14 +00:00
return Strings . TaskType . FullBackup ;
2014-06-27 13:23:05 +02:00
case Duplicati . Server . Serialization . DuplicatiOperation . List :
2013-02-12 21:43:14 +00:00
return Strings . TaskType . IncrementalBackup ;
2014-06-27 13:23:05 +02:00
case Duplicati . Server . Serialization . DuplicatiOperation . Remove :
2013-02-12 21:43:14 +00:00
return Strings . TaskType . ListActualFiles ;
2014-06-27 13:23:05 +02:00
case Duplicati . Server . Serialization . DuplicatiOperation . Verify :
2013-02-12 21:43:14 +00:00
return Strings . TaskType . ListBackupEntries ;
2014-06-27 13:23:05 +02:00
case Duplicati . Server . Serialization . DuplicatiOperation . Restore :
2013-02-12 21:43:14 +00:00
return Strings . TaskType . ListBackups ;
default :
return type . ToString ();
}
}
/// <summary>
/// Helper method with logic to handle opening a database in possibly encrypted format
/// </summary>
/// <param name="con">The SQLite connection object</param>
internal static void OpenDatabase ( System . Data . IDbConnection con )
{
bool noEncryption = ! Program . UseDatabaseEncryption ;
string password = Environment . GetEnvironmentVariable ( DB_KEY_ENV_NAME );
System . Reflection . MethodInfo setPwdMethod = con . GetType (). GetMethod ( "SetPassword" , new Type [] { typeof ( string ) });
string attemptedPassword ;
if ( noEncryption || string . IsNullOrEmpty ( password ))
attemptedPassword = null ; //No encryption specified, attempt to open without
else
attemptedPassword = password ; //Encryption specified, attempt to open with
if ( setPwdMethod != null )
setPwdMethod . Invoke ( con , new object [] { attemptedPassword });
try
{
//Attempt to open in preferred state
con . Open ();
2014-07-20 09:15:33 +02:00
// Do a dummy query to make sure we have a working db
using ( var cmd = con . CreateCommand ())
{
cmd . CommandText = "SELECT COUNT(*) FROM SQLITE_MASTER" ;
cmd . ExecuteScalar ();
}
2013-02-12 21:43:14 +00:00
}
catch
{
try
{
//We can't try anything else without a password
if ( string . IsNullOrEmpty ( password ))
throw ;
//Open failed, now try the reverse
if ( attemptedPassword == null )
attemptedPassword = password ;
else
attemptedPassword = null ;
2014-07-20 09:15:33 +02:00
con . Close ();
2013-02-12 21:43:14 +00:00
setPwdMethod . Invoke ( con , new object [] { attemptedPassword });
con . Open ();
2014-07-20 09:15:33 +02:00
// Do a dummy query to make sure we have a working db
using ( var cmd = con . CreateCommand ())
{
cmd . CommandText = "SELECT COUNT(*) FROM SQLITE_MASTER" ;
cmd . ExecuteScalar ();
}
2013-02-12 21:43:14 +00:00
}
catch
{
2014-07-20 09:15:33 +02:00
try { con . Close (); }
catch { }
2013-02-12 21:43:14 +00:00
}
//If the db is not open now, it won't open
if ( con . State != System . Data . ConnectionState . Open )
throw ; //Report original error
//The open method succeeded with the non-default method, now change the password
System . Reflection . MethodInfo changePwdMethod = con . GetType (). GetMethod ( "ChangePassword" , new Type [] { typeof ( string ) });
changePwdMethod . Invoke ( con , new object [] { noEncryption ? null : password });
}
}
2014-07-25 14:09:26 +02:00
private static void PingPongMethod ()
{
var rd = new System . IO . StreamReader ( Console . OpenStandardInput ());
var wr = new System . IO . StreamWriter ( Console . OpenStandardOutput ());
while ( rd . ReadLine () != null )
{
wr . WriteLine ( "pong" );
wr . Flush ();
}
}
2013-02-12 21:43:14 +00:00
/// <summary>
/// Gets a list of all supported commandline options
/// </summary>
2014-04-02 11:34:33 +02:00
public static Library . Interface . ICommandLineArgument [] SupportedCommands
2013-02-12 21:43:14 +00:00
{
get
{
return new Duplicati . Library . Interface . ICommandLineArgument [] {
new Duplicati . Library . Interface . CommandLineArgument ( "help" , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Boolean , Strings . Program . HelpCommandDescription , Strings . Program . HelpCommandDescription ),
new Duplicati . Library . Interface . CommandLineArgument ( "unencrypted-database" , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Boolean , Strings . Program . UnencrypteddatabaseCommandDescription , Strings . Program . UnencrypteddatabaseCommandDescription ),
new Duplicati . Library . Interface . CommandLineArgument ( "portable-mode" , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Boolean , Strings . Program . PortablemodeCommandDescription , Strings . Program . PortablemodeCommandDescription ),
new Duplicati . Library . Interface . CommandLineArgument ( "log-file" , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Path , Strings . Program . LogfileCommandDescription , Strings . Program . LogfileCommandDescription ),
2014-06-27 13:23:05 +02:00
new Duplicati . Library . Interface . CommandLineArgument ( "log-level" , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Enumeration , Strings . Program . LoglevelCommandDescription , Strings . Program . LoglevelCommandDescription , "Warning" , null , Enum . GetNames ( typeof ( Duplicati . Library . Logging . LogMessageType ))),
new Duplicati . Library . Interface . CommandLineArgument ( Duplicati . Server . WebServer . Server . OPTION_WEBROOT , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Path , Strings . Program . WebserverWebrootDescription , Strings . Program . WebserverWebrootDescription , Duplicati . Server . WebServer . Server . DEFAULT_OPTION_WEBROOT ),
new Duplicati . Library . Interface . CommandLineArgument ( Duplicati . Server . WebServer . Server . OPTION_PORT , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . String , Strings . Program . WebserverPortDescription , Strings . Program . WebserverPortDescription , Duplicati . Server . WebServer . Server . DEFAULT_OPTION_PORT . ToString ()),
new Duplicati . Library . Interface . CommandLineArgument ( Duplicati . Server . WebServer . Server . OPTION_INTERFACE , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . String , Strings . Program . WebserverInterfaceDescription , Strings . Program . WebserverInterfaceDescription , Duplicati . Server . WebServer . Server . DEFAULT_OPTION_INTERFACE ),
2014-06-30 11:31:06 +02:00
new Duplicati . Library . Interface . CommandLineArgument ( "webservice-password" , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Password , Strings . Program . WebserverPasswordDescription , Strings . Program . WebserverPasswordDescription ),
2014-07-25 14:09:26 +02:00
new Duplicati . Library . Interface . CommandLineArgument ( "ping-pong-keepalive" , Duplicati . Library . Interface . CommandLineArgument . ArgumentType . Boolean , LC . L ( "Enables the ping-pong responder" ), LC . L ( "When running as a server, the service daemon must verify that the process is responding. If this option is enabled, the server reads stdin and writes a reply to each line read" )),
2013-02-12 21:43:14 +00:00
};
}
}
}
}