PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/Duplicati/Scheduler/RunBackup/RunBackup.cs

http://duplicati.googlecode.com/
C# | 274 lines | 180 code | 6 blank | 88 comment | 23 complexity | 251a35020ec5dc3802bc2c4848da8b4b MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-2.0, Apache-2.0, GPL-3.0, CC-BY-SA-3.0
  1. #region Disclaimer / License
  2. // Copyright (C) 2011, Kenneth Bergeron, IAP Worldwide Services, Inc
  3. // NOAA :: National Marine Fisheries Service
  4. //
  5. // This library is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU Lesser General Public
  7. // License as published by the Free Software Foundation; either
  8. // version 2.1 of the License, or (at your option) any later version.
  9. //
  10. // This library is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. // Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public
  16. // License along with this library; if not, write to the Free Software
  17. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. //
  19. #endregion
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Diagnostics;
  23. using System.Linq;
  24. // This is a x86 exe - If you are using Express, see this:
  25. // http://social.msdn.microsoft.com/Forums/en-US/Vsexpressvcs/thread/4650481d-b385-43f3-89c7-c07546a7f7cd
  26. //
  27. //[assembly: System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.RequestMinimum, Name = "FullTrust")]
  28. namespace Duplicati.Scheduler.RunBackup
  29. {
  30. class Program
  31. {
  32. /// <summary>
  33. /// The name of the mother package
  34. /// </summary>
  35. public const string Package = "Duplicati";
  36. /// <summary>
  37. /// Name of application
  38. /// </summary>
  39. public const string Name = "Duplicati.RunBackup";
  40. /// <summary>
  41. /// Root name of named pipe
  42. /// </summary>
  43. public const string PipeBaseName = "Duplicati.Pipe";
  44. /// <summary>
  45. /// Name of the Pipe client listener thread
  46. /// </summary>
  47. public const string ClientThreadName = "Duplicati.PipeClient";
  48. /// <summary>
  49. /// Where Monitor plugins live
  50. /// </summary>
  51. public static string StartupPath =
  52. System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
  53. /// <summary>
  54. /// Name of this job
  55. /// </summary>
  56. public static string Job = "<none>";
  57. /// <summary>
  58. /// If set via command line argument "DryRun", no backup is actually made; used for debug
  59. /// </summary>
  60. private static bool itsDryRun = false;
  61. /// <summary>
  62. /// This is basically a very small Duplicati command line that only supports backup.
  63. /// This is a console app; but compiled with 'forms' to get rid of the dreaded console window in xp.
  64. /// </summary>
  65. /// <param name="aArgs">Arguments are job name and XML file name</param>
  66. static void Main(string[] aArgs)
  67. {
  68. // Args as a handy list
  69. List<string> ArgList = new List<string>(aArgs);
  70. #if DEBUGUSER
  71. if (!Environment.UserInteractive)
  72. System.Threading.Thread.Sleep(20000); // Give time to attach debugger
  73. if (!Environment.UserName.EndsWith("\\User"))
  74. {
  75. // TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST
  76. Utility.Su.Impersonate("User", Environment.UserDomainName, "asd"); // TEST
  77. Environment.SetEnvironmentVariable("TMP", "C:\\temp"); // TEST
  78. }
  79. #endif
  80. if (ArgList.Count == 0)
  81. {
  82. System.Windows.Forms.MessageBox.Show("This program must be executed with a job name and should not be executed manually");
  83. return;
  84. }
  85. itsDryRun = ArgList.Contains("DryRun"); // Good for debugging
  86. if(itsDryRun) ArgList.Remove("DryRun");
  87. // The job name
  88. Job = ArgList[0];
  89. // Be nice
  90. System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.BelowNormal;
  91. // Get a log file
  92. string LogFile = Duplicati.Scheduler.Utility.Tools.LogFileName(Package);
  93. using (new Notifier()) // Attempt to put that little thingy in the tray
  94. // Create the log
  95. using (Duplicati.Library.Logging.AppendLog Log = new Duplicati.Library.Logging.AppendLog(LogFile, Job))
  96. {
  97. Duplicati.Library.Logging.Log.CurrentLog = Log;
  98. // Hard code level to info, deal with filters in the forms level
  99. Duplicati.Library.Logging.Log.LogLevel = Duplicati.Library.Logging.LogMessageType.Information;
  100. #if !DEBUG
  101. try
  102. #endif
  103. {
  104. // Load the history XML dataset
  105. using (Duplicati.Scheduler.Data.HistoryDataSet hds = new Duplicati.Scheduler.Data.HistoryDataSet())
  106. {
  107. hds.Load();
  108. // Create a new history record for this run
  109. Duplicati.Scheduler.Data.HistoryDataSet.HistoryRow HistoryRow = hds.History.AddHistoryRow(Job, DateTime.Now, "Backup", true, false, LogFile, new byte[0], string.Empty);
  110. // Actually run the job
  111. RunBackup(ArgList.ToArray(), HistoryRow);
  112. // Just clean out history
  113. foreach (Duplicati.Scheduler.Data.HistoryDataSet.HistoryRow Row in
  114. from Duplicati.Scheduler.Data.HistoryDataSet.HistoryRow qR in hds.History
  115. where !System.IO.File.Exists(qR.LogFileName) select qR)
  116. Row.Delete();
  117. hds.Save(); // Save the XML (later: make so the whole db need not be loaded (XMLReader)
  118. }
  119. }
  120. #if !DEBUG
  121. catch (Exception Ex) // Log error
  122. {
  123. Library.Logging.Log.WriteMessage(Ex.Message, Duplicati.Library.Logging.LogMessageType.Error);
  124. }
  125. #endif
  126. UpdateMonitors(LogFile);
  127. // All done, set the log file (filewathers are looking for AttributeChange)
  128. System.IO.File.SetAttributes(LogFile, System.IO.FileAttributes.ReadOnly);
  129. }
  130. }
  131. /// <summary>
  132. /// Update any Monitor plugins
  133. /// </summary>
  134. /// <param name="aLogFile"></param>
  135. private static void UpdateMonitors(string aLogFile)
  136. {
  137. // Each plugin
  138. foreach(string Plug in System.IO.Directory.GetFiles(StartupPath, "Duplicati.Scheduler.Monitor.*.dll"))
  139. {
  140. // Load the assembly, get the type, create an instance
  141. System.Reflection.Assembly Ass = System.Reflection.Assembly.LoadFile(Plug);
  142. Type ClassType = Ass.GetTypes().Where(qR=>qR.Name == "Plugin").First();
  143. Duplicati.Scheduler.Data.IMonitorPlugin Monitor = Activator.CreateInstance(ClassType, null) as Duplicati.Scheduler.Data.IMonitorPlugin;
  144. if (Monitor != null && (DisabledMonitors == null || !DisabledMonitors.Contains(Monitor.Name)))
  145. {
  146. // Tell big brother
  147. Exception phEx =
  148. #if !DEBUG
  149. Utility.Tools.TryCatch((Action)delegate()
  150. #else
  151. null;
  152. #endif
  153. {
  154. // Update the scheduler
  155. Monitor.UpdateScheduler(Duplicati.Scheduler.Data.SchedulerDataSet.DefaultPath());
  156. // Update the history
  157. Monitor.UpdateHistory(Duplicati.Scheduler.Data.HistoryDataSet.DefaultPath());
  158. // Update the log file
  159. Monitor.UpdateLog(System.IO.File.GetLastWriteTime(aLogFile), Duplicati.Library.Logging.AppendLog.LogFileToXML(aLogFile));
  160. }
  161. #if !DEBUG
  162. );
  163. #endif
  164. if (phEx != null)
  165. Library.Logging.Log.WriteMessage("Monitor Update failed "+Monitor.Name,
  166. Duplicati.Library.Logging.LogMessageType.Warning, phEx);
  167. }
  168. }
  169. }
  170. private static string[] DisabledMonitors = null;
  171. private static bool RunBackup(string[] args, Duplicati.Scheduler.Data.HistoryDataSet.HistoryRow aHistoryRow)
  172. {
  173. // Log the start
  174. Library.Logging.Log.WriteMessage(Name + " " + String.Join(" ", args) + (itsDryRun ? " DryRun as" : " as ") + Duplicati.Scheduler.Utility.User.UserName,
  175. Duplicati.Library.Logging.LogMessageType.Information);
  176. // See if the XML file name was on the command line
  177. string XML = (args.Length > 1) ? XML = args[1] : Duplicati.Scheduler.Data.SchedulerDataSet.DefaultPath();
  178. // Convert our options to Duplicati options
  179. Options BackupOptions = new Options(Job, XML);
  180. // Get disabled monitors
  181. DisabledMonitors = BackupOptions.DisabledMonitors;
  182. // Complain about any results from the drive mapping
  183. if (!string.IsNullOrEmpty(BackupOptions.MapResults))
  184. Library.Logging.Log.WriteMessage(BackupOptions.MapResults, Duplicati.Library.Logging.LogMessageType.Information);
  185. // Get the signature file temp
  186. Duplicati.Library.Utility.TempFolder SigTemp = new Duplicati.Library.Utility.TempFolder();
  187. string SigThingy = System.IO.Path.Combine(SigTemp, Duplicati.Scheduler.Data.SchedulerDataSet.DefaultName);
  188. if (Duplicati.Scheduler.Utility.Tools.NoException((Action)delegate() { System.IO.File.Copy(Duplicati.Scheduler.Data.SchedulerDataSet.DefaultPath(), SigThingy); }))
  189. BackupOptions["signature-control-files"] = SigThingy;
  190. // See if there is a pipe server listening, if so, connect to it for progress messages
  191. bool HasPipe = Duplicati.Scheduler.Utility.NamedPipeServerStream.ServerIsUp(
  192. Duplicati.Scheduler.Utility.NamedPipeServerStream.MakePipeName(PipeBaseName, Duplicati.Scheduler.Utility.User.UserName, System.IO.Pipes.PipeDirection.In));
  193. if (HasPipe) Pipe.Connecter();
  194. // Run the dern thing already
  195. string Result = "Not started";
  196. bool OK = false;
  197. if (itsDryRun)
  198. {
  199. OK = true;
  200. Result = "DryRun";
  201. if(HasPipe) TestProgress(5); // Just send fake progress
  202. }
  203. else
  204. {
  205. try
  206. {
  207. using (Duplicati.Library.Main.Interface i = new Duplicati.Library.Main.Interface(BackupOptions.Target, BackupOptions))
  208. {
  209. // Set our events if we have a pipe
  210. if (HasPipe)
  211. {
  212. i.OperationProgress += new Duplicati.Library.Main.OperationProgressEvent(Pipe.OperationProgress);
  213. i.OperationCompleted += new Duplicati.Library.Main.OperationProgressEvent(Pipe.OperationProgress);
  214. }
  215. Result = i.Backup(BackupOptions.Source);
  216. }
  217. OK = true;
  218. }
  219. catch (Exception Ex)
  220. {
  221. // Dang
  222. Result = "Error: " + Ex.Message;
  223. }
  224. }
  225. // Log the done.
  226. Library.Logging.Log.WriteMessage("Finished: "+(OK?"OK":Result), OK ? Duplicati.Library.Logging.LogMessageType.Information : Duplicati.Library.Logging.LogMessageType.Error);
  227. // Put deletions in the log, where they belong.
  228. // Deleting backup at 07/06/2011 06:05:21
  229. foreach(string Line in Result.Split('\n'))
  230. if (Line.StartsWith("Deleting backup at "))
  231. Library.Logging.Log.WriteMessage(Line, Duplicati.Library.Logging.LogMessageType.Information);
  232. // OK, made it, update the history
  233. aHistoryRow.Update("Backup", BackupOptions.Full, OK, Result, BackupOptions.Checksum, BackupOptions.CheckMod);
  234. LimitLogFiles(BackupOptions.LogFileMaxAgeDays); // zero has no effect.
  235. // woot
  236. return OK;
  237. }
  238. /// <summary>
  239. /// Delete old log files
  240. /// </summary>
  241. /// <param name="aMaxDays">Number of days to keep logs (0=always)</param>
  242. private static void LimitLogFiles(int aMaxDays)
  243. {
  244. if (aMaxDays <= 0) return;
  245. foreach (string Entry in System.IO.Directory.GetFiles(Duplicati.Scheduler.Utility.Tools.LogFileDirectory(Package), Duplicati.Scheduler.Utility.Tools.LogFileFilter))
  246. {
  247. if ((DateTime.Now - (new System.IO.FileInfo(Entry).LastWriteTime)).TotalDays > aMaxDays)
  248. Duplicati.Scheduler.Utility.Tools.TryCatch((Action)delegate()
  249. {
  250. System.IO.File.SetAttributes(Entry, System.IO.FileAttributes.Normal);
  251. System.IO.File.Delete(Entry);
  252. });
  253. }
  254. }
  255. private static void TestProgress(int aSeconds)
  256. {
  257. Job = "PipeTest";
  258. Debug.WriteLine(Job);
  259. for (int i = 0; i<aSeconds*2 ; i++)
  260. {
  261. int P = (i % 100);
  262. Pipe.OperationProgress(null, Duplicati.Library.Main.DuplicatiOperation.Backup, Duplicati.Library.Main.DuplicatiOperationMode.Backup,
  263. P, P, "test:" + P.ToString(), P.ToString());
  264. System.Threading.Thread.Sleep(500);
  265. }
  266. }
  267. }
  268. }