dar-backup 0.6.9__py3-none-any.whl → 0.6.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dar_backup/__about__.py +1 -1
- dar_backup/dar_backup.py +40 -29
- dar_backup/util.py +118 -0
- {dar_backup-0.6.9.dist-info → dar_backup-0.6.11.dist-info}/METADATA +333 -146
- dar_backup-0.6.11.dist-info/RECORD +14 -0
- dar_backup-0.6.9.dist-info/RECORD +0 -14
- {dar_backup-0.6.9.dist-info → dar_backup-0.6.11.dist-info}/WHEEL +0 -0
- {dar_backup-0.6.9.dist-info → dar_backup-0.6.11.dist-info}/entry_points.txt +0 -0
- {dar_backup-0.6.9.dist-info → dar_backup-0.6.11.dist-info}/licenses/LICENSE +0 -0
dar_backup/__about__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.6.
|
|
1
|
+
__version__ = "0.6.11"
|
dar_backup/dar_backup.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
-
import datetime
|
|
5
4
|
import filecmp
|
|
6
5
|
|
|
7
6
|
import os
|
|
@@ -81,30 +80,31 @@ def generic_backup(type: str, command: List[str], backup_file: str, backup_defin
|
|
|
81
80
|
raise BackupError(f"Unexpected error during backup: {e}") from e
|
|
82
81
|
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
def find_files_with_paths(
|
|
83
|
+
|
|
84
|
+
def find_files_with_paths(xml_root: ET.Element):
|
|
86
85
|
"""
|
|
87
|
-
|
|
86
|
+
Finds files within an XML element and returns a list of file paths with their sizes.
|
|
88
87
|
|
|
89
88
|
Args:
|
|
90
|
-
|
|
91
|
-
current_path (str, optional): The current path of the directory element. Defaults to "".
|
|
89
|
+
xml_root (Element): The root element of the XML.
|
|
92
90
|
|
|
93
91
|
Returns:
|
|
94
92
|
list: A list of tuples containing file paths and their sizes.
|
|
95
93
|
"""
|
|
96
|
-
logger.debug(
|
|
94
|
+
logger.debug("Generating list of tuples with file paths and sizes for File elements in dar xml output")
|
|
97
95
|
files = []
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
for
|
|
101
|
-
if
|
|
102
|
-
|
|
96
|
+
current_path = []
|
|
97
|
+
|
|
98
|
+
for elem in xml_root.iter():
|
|
99
|
+
if elem.tag == "directory":
|
|
100
|
+
current_path.append(elem.get('name'))
|
|
101
|
+
elif elem.tag == "file":
|
|
102
|
+
file_path = ("/".join(current_path + [elem.get('name')]), elem.get('size'))
|
|
103
103
|
files.append(file_path)
|
|
104
|
-
elif
|
|
105
|
-
|
|
106
|
-
return files
|
|
104
|
+
elif elem.tag == "directory" and elem.get('name') in current_path:
|
|
105
|
+
current_path.pop()
|
|
107
106
|
|
|
107
|
+
return files
|
|
108
108
|
|
|
109
109
|
|
|
110
110
|
def find_files_between_min_and_max_size(backed_up_files: list[(str, str)], config_settings: ConfigSettings):
|
|
@@ -238,20 +238,20 @@ def restore_backup(backup_name: str, config_settings: ConfigSettings, restore_di
|
|
|
238
238
|
restore_dir (str): The directory where the backup should be restored to.
|
|
239
239
|
selection (str, optional): A selection criteria to restore specific files or directories. Defaults to None.
|
|
240
240
|
"""
|
|
241
|
-
backup_file = os.path.join(config_settings.backup_dir, backup_name)
|
|
242
|
-
command = ['dar', '-x', backup_file, '-Q', '-D']
|
|
243
|
-
if restore_dir:
|
|
244
|
-
if not os.path.exists(restore_dir):
|
|
245
|
-
os.makedirs(restore_dir)
|
|
246
|
-
command.extend(['-R', restore_dir])
|
|
247
|
-
else:
|
|
248
|
-
raise RestoreError("Restore directory ('-R <dir>') not specified")
|
|
249
|
-
if selection:
|
|
250
|
-
selection_criteria = shlex.split(selection)
|
|
251
|
-
command.extend(selection_criteria)
|
|
252
|
-
command.extend(['-B', darrc, 'restore-options']) # the .darrc `restore-options` section
|
|
253
|
-
logger.info(f"Running restore command: {' '.join(map(shlex.quote, command))}")
|
|
254
241
|
try:
|
|
242
|
+
backup_file = os.path.join(config_settings.backup_dir, backup_name)
|
|
243
|
+
command = ['dar', '-x', backup_file, '-Q', '-D']
|
|
244
|
+
if restore_dir:
|
|
245
|
+
if not os.path.exists(restore_dir):
|
|
246
|
+
os.makedirs(restore_dir)
|
|
247
|
+
command.extend(['-R', restore_dir])
|
|
248
|
+
else:
|
|
249
|
+
raise RestoreError("Restore directory ('-R <dir>') not specified")
|
|
250
|
+
if selection:
|
|
251
|
+
selection_criteria = shlex.split(selection)
|
|
252
|
+
command.extend(selection_criteria)
|
|
253
|
+
command.extend(['-B', darrc, 'restore-options']) # the .darrc `restore-options` section
|
|
254
|
+
logger.info(f"Running restore command: {' '.join(map(shlex.quote, command))}")
|
|
255
255
|
process = run_command(command, config_settings.command_timeout_secs)
|
|
256
256
|
if process.returncode == 0:
|
|
257
257
|
logger.info(f"Restore completed successfully to: '{restore_dir}'")
|
|
@@ -260,6 +260,9 @@ def restore_backup(backup_name: str, config_settings: ConfigSettings, restore_di
|
|
|
260
260
|
raise RestoreError(str(process))
|
|
261
261
|
except subprocess.CalledProcessError as e:
|
|
262
262
|
raise RestoreError(f"Restore command failed: {e}") from e
|
|
263
|
+
except OSError as e:
|
|
264
|
+
logger.error(f"Failed to create restore directory: {e}")
|
|
265
|
+
raise RestoreError("Could not create restore directory")
|
|
263
266
|
except Exception as e:
|
|
264
267
|
raise RestoreError(f"Unexpected error during restore: {e}") from e
|
|
265
268
|
|
|
@@ -285,7 +288,7 @@ def get_backed_up_files(backup_name: str, backup_dir: str):
|
|
|
285
288
|
# Parse the XML data
|
|
286
289
|
root = ET.fromstring(process.stdout)
|
|
287
290
|
output = None # help gc
|
|
288
|
-
# Extract full paths and file size for all <
|
|
291
|
+
# Extract full paths and file size for all <file> elements
|
|
289
292
|
file_paths = find_files_with_paths(root)
|
|
290
293
|
root = None # help gc
|
|
291
294
|
logger.trace(str(process))
|
|
@@ -624,6 +627,14 @@ def main():
|
|
|
624
627
|
else:
|
|
625
628
|
logger.error(f"Supplied .darrc: '{args.darrc}' does not exist or is not a file")
|
|
626
629
|
|
|
630
|
+
if not args.config_file:
|
|
631
|
+
logger.error(f"Config file not specified, exiting")
|
|
632
|
+
sys.exit(1)
|
|
633
|
+
|
|
634
|
+
if not os.path.exists(args.config_file):
|
|
635
|
+
logger.error(f"Config file {args.config_file} does not exist.")
|
|
636
|
+
sys.exit(1)
|
|
637
|
+
|
|
627
638
|
|
|
628
639
|
try:
|
|
629
640
|
start_time=int(time())
|
dar_backup/util.py
CHANGED
|
@@ -14,6 +14,7 @@ import os
|
|
|
14
14
|
import re
|
|
15
15
|
import subprocess
|
|
16
16
|
import shlex
|
|
17
|
+
import shutil
|
|
17
18
|
import sys
|
|
18
19
|
import threading
|
|
19
20
|
import traceback
|
|
@@ -123,10 +124,113 @@ def _stream_reader(pipe, log_func, output_accumulator: List[str]):
|
|
|
123
124
|
log_func(stripped_line) # Log the output in real time
|
|
124
125
|
|
|
125
126
|
|
|
127
|
+
|
|
126
128
|
def run_command(command: List[str], timeout: int = 30) -> CommandResult:
|
|
127
129
|
"""
|
|
128
130
|
Executes a given command via subprocess, logs its output in real time, and returns the result.
|
|
129
131
|
|
|
132
|
+
Args:
|
|
133
|
+
command (list): The command to be executed, represented as a list of strings.
|
|
134
|
+
timeout (int): The maximum time in seconds to wait for the command to complete. Defaults to 30 seconds.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
A CommandResult NamedTuple with the following properties:
|
|
138
|
+
- process: subprocess.CompletedProcess
|
|
139
|
+
- stdout: str: The full standard output of the command.
|
|
140
|
+
- stderr: str: The full standard error of the command.
|
|
141
|
+
- returncode: int: The return code of the command.
|
|
142
|
+
- timeout: int: The timeout value in seconds used to run the command.
|
|
143
|
+
- command: list[str]: The command executed.
|
|
144
|
+
|
|
145
|
+
Logs:
|
|
146
|
+
- Logs standard output (`stdout`) in real-time at the INFO log level.
|
|
147
|
+
- Logs standard error (`stderr`) in real-time at the ERROR log level.
|
|
148
|
+
|
|
149
|
+
Raises:
|
|
150
|
+
subprocess.TimeoutExpired: If the command execution times out (see `timeout` parameter).
|
|
151
|
+
Exception: If other exceptions occur during command execution.
|
|
152
|
+
FileNotFoundError: If the command is not found.
|
|
153
|
+
|
|
154
|
+
Notes:
|
|
155
|
+
- While the command runs, its `stdout` and `stderr` streams are logged in real-time.
|
|
156
|
+
- The returned `stdout` and `stderr` capture the complete output, even though the output is also logged.
|
|
157
|
+
- The command is forcibly terminated if it exceeds the specified timeout.
|
|
158
|
+
"""
|
|
159
|
+
stdout_lines = [] # To accumulate stdout
|
|
160
|
+
stderr_lines = [] # To accumulate stderr
|
|
161
|
+
process = None # Track the process for cleanup
|
|
162
|
+
stdout_thread = None
|
|
163
|
+
stderr_thread = None
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
# Check if the command exists before executing
|
|
167
|
+
if not shutil.which(command[0]):
|
|
168
|
+
raise FileNotFoundError(f"Command not found: {command[0]}")
|
|
169
|
+
|
|
170
|
+
logger.debug(f"Running command: {command}")
|
|
171
|
+
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
172
|
+
|
|
173
|
+
# Start threads to read and log stdout and stderr
|
|
174
|
+
stdout_thread = threading.Thread(target=_stream_reader, args=(process.stdout, logger.info, stdout_lines))
|
|
175
|
+
stderr_thread = threading.Thread(target=_stream_reader, args=(process.stderr, logger.error, stderr_lines))
|
|
176
|
+
|
|
177
|
+
stdout_thread.start()
|
|
178
|
+
stderr_thread.start()
|
|
179
|
+
|
|
180
|
+
# Wait for process to complete or timeout
|
|
181
|
+
process.wait(timeout=timeout)
|
|
182
|
+
|
|
183
|
+
except FileNotFoundError as e:
|
|
184
|
+
logger.error(f"Command not found: {command[0]}")
|
|
185
|
+
return CommandResult(
|
|
186
|
+
process=None,
|
|
187
|
+
stdout="",
|
|
188
|
+
stderr=str(e),
|
|
189
|
+
returncode=127,
|
|
190
|
+
timeout=timeout,
|
|
191
|
+
command=command
|
|
192
|
+
)
|
|
193
|
+
except subprocess.TimeoutExpired:
|
|
194
|
+
if process:
|
|
195
|
+
process.terminate()
|
|
196
|
+
logger.error(f"Command: '{command}' timed out and was terminated.")
|
|
197
|
+
raise
|
|
198
|
+
except Exception as e:
|
|
199
|
+
logger.error(f"Error running command: {command}", exc_info=True)
|
|
200
|
+
raise
|
|
201
|
+
finally:
|
|
202
|
+
# Ensure threads are joined to clean up (only if they were started)
|
|
203
|
+
if stdout_thread and stdout_thread.is_alive():
|
|
204
|
+
stdout_thread.join()
|
|
205
|
+
if stderr_thread and stderr_thread.is_alive():
|
|
206
|
+
stderr_thread.join()
|
|
207
|
+
|
|
208
|
+
# Ensure process streams are closed
|
|
209
|
+
if process and process.stdout:
|
|
210
|
+
process.stdout.close()
|
|
211
|
+
if process and process.stderr:
|
|
212
|
+
process.stderr.close()
|
|
213
|
+
|
|
214
|
+
# Combine captured stdout and stderr lines into single strings
|
|
215
|
+
stdout = "\n".join(stdout_lines)
|
|
216
|
+
stderr = "\n".join(stderr_lines)
|
|
217
|
+
|
|
218
|
+
# Build the result object
|
|
219
|
+
result = CommandResult(
|
|
220
|
+
process=process,
|
|
221
|
+
stdout=stdout,
|
|
222
|
+
stderr=stderr,
|
|
223
|
+
returncode=process.returncode,
|
|
224
|
+
timeout=timeout,
|
|
225
|
+
command=command
|
|
226
|
+
)
|
|
227
|
+
logger.debug(f"Command result: {result}")
|
|
228
|
+
return result
|
|
229
|
+
|
|
230
|
+
def run_command2(command: List[str], timeout: int = 30) -> CommandResult:
|
|
231
|
+
"""
|
|
232
|
+
Executes a given command via subprocess, logs its output in real time, and returns the result.
|
|
233
|
+
|
|
130
234
|
Args:
|
|
131
235
|
command (list): The command to be executed, represented as a list of strings.
|
|
132
236
|
timeout (int): The maximum time in seconds to wait for the command to complete. Defaults to 30 seconds.
|
|
@@ -158,6 +262,10 @@ def run_command(command: List[str], timeout: int = 30) -> CommandResult:
|
|
|
158
262
|
process = None # Track the process for cleanup
|
|
159
263
|
|
|
160
264
|
try:
|
|
265
|
+
# Check if the command exists before executing
|
|
266
|
+
if not shutil.which(command[0]):
|
|
267
|
+
raise FileNotFoundError(f"Command not found: {command[0]}")
|
|
268
|
+
|
|
161
269
|
logger.debug(f"Running command: {command}")
|
|
162
270
|
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
163
271
|
|
|
@@ -171,6 +279,16 @@ def run_command(command: List[str], timeout: int = 30) -> CommandResult:
|
|
|
171
279
|
# Wait for process to complete or timeout
|
|
172
280
|
process.wait(timeout=timeout)
|
|
173
281
|
|
|
282
|
+
except FileNotFoundError as e:
|
|
283
|
+
logger.error(f"Command not found: {command[0]}")
|
|
284
|
+
return CommandResult(
|
|
285
|
+
process=None,
|
|
286
|
+
stdout="",
|
|
287
|
+
stderr=str(e),
|
|
288
|
+
returncode=127,
|
|
289
|
+
timeout=timeout,
|
|
290
|
+
command=command
|
|
291
|
+
)
|
|
174
292
|
except subprocess.TimeoutExpired:
|
|
175
293
|
if process:
|
|
176
294
|
process.terminate()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dar-backup
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.11
|
|
4
4
|
Summary: A script to do full, differential and incremental backups using dar. Some files are restored from the backups during verification, after which par2 redundancy files are created. The script also has a cleanup feature to remove old backups and par2 files.
|
|
5
5
|
Project-URL: Homepage, https://github.com/per2jensen/dar-backup/tree/main/v2
|
|
6
6
|
Project-URL: Changelog, https://github.com/per2jensen/dar-backup/blob/main/v2/Changelog.md
|
|
@@ -690,71 +690,123 @@ Classifier: Topic :: System :: Archiving :: Backup
|
|
|
690
690
|
Requires-Python: >=3.9
|
|
691
691
|
Description-Content-Type: text/markdown
|
|
692
692
|
|
|
693
|
-
# Full, differential or incremental backups using 'dar'
|
|
693
|
+
# Full, differential or incremental backups using 'dar'
|
|
694
694
|
|
|
695
|
-
The wonderful 'dar' [Disk Archiver]
|
|
695
|
+
The wonderful 'dar' [Disk Archiver](https://github.com/Edrusb/DAR) is used for
|
|
696
696
|
the heavy lifting, together with the par2 suite in these scripts.
|
|
697
697
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
698
|
+
## Table of Contents
|
|
699
|
+
|
|
700
|
+
- [Full, differential or incremental backups using 'dar'](#full-differential-or-incremental-backups-using-dar)
|
|
701
|
+
- [My use case](#my-use-case)
|
|
702
|
+
- [License](#license)
|
|
703
|
+
- [Status](#status)
|
|
704
|
+
- [Breaking change in version 0.6.0](#breaking-change-in-version-060)
|
|
705
|
+
- [Homepage - Github](#homepage---github)
|
|
706
|
+
- [Requirements](#requirements)
|
|
707
|
+
- [Config file](#config-file)
|
|
708
|
+
- [How to install & run](#how-to-run)
|
|
709
|
+
- [1 - config file](#1---config-file)
|
|
710
|
+
- [2 - backup definitions](#2---backup-definitions)
|
|
711
|
+
- [3 - installation](#3---installation)
|
|
712
|
+
- [4 - generate catalog databases](#4---generate-catalog-databases)
|
|
713
|
+
- [5 - do FULL backups](#5---do-full-backups)
|
|
714
|
+
- [6 - deactivate venv](#6---deactivate-venv)
|
|
715
|
+
- [.darrc](#darrc)
|
|
716
|
+
- [Systemctl examples](#systemctl-examples)
|
|
717
|
+
- [Service: dar-back --incremental-backup](#service-dar-back---incremental-backup)
|
|
718
|
+
- [Timer: dar-back --incremental-backup](#timer-dar-back---incremental-backup)
|
|
719
|
+
- [List contents of an archive](#list-contents-of-an-archive)
|
|
720
|
+
- [dar file selection examples](#dar-file-selection-exmaples)
|
|
721
|
+
- [Select a directory](#select-a-directory)
|
|
722
|
+
- [Select file dates in the directory](#select-file-dates-in-the-directory)
|
|
723
|
+
- [Exclude .xmp files from that date](#exclude-xmp-files-from-that-date)
|
|
724
|
+
- [Restoring](#restoring)
|
|
725
|
+
- [Default location for restores](#default-location-for-restores)
|
|
726
|
+
- [--restore-dir option](#--restore-dir-option)
|
|
727
|
+
- [A single file](#a-single-file)
|
|
728
|
+
- [A directory](#a-directory)
|
|
729
|
+
- [.NEF from a specific date](#nef-from-a-specific-date)
|
|
730
|
+
- [Restore test fails with exit code 4](#restore-test-fails-with-exit-code-4)
|
|
731
|
+
- [Restore test fails with exit code 5](#restore-test-fails-with-exit-code-5)
|
|
732
|
+
- [Par2](#par2)
|
|
733
|
+
- [Par2 to verify/repair](#par2-to-verifyrepair)
|
|
734
|
+
- [Par2 create redundancy files](#par2-create-redundancy-files)
|
|
735
|
+
- [Points of interest](#points-of-interest)
|
|
736
|
+
- [Merge FULL with DIFF, creating new FULL](#merge-full-with-diff-creating-new-full)
|
|
737
|
+
- [dar manager databases](#dar-manager-databases)
|
|
738
|
+
- [Performance tip due to par2](#performance-tip-due-to-par2)
|
|
739
|
+
- [.darrc sets -vd -vf (since v0.6.4)](#darrc-sets--vd--vf-since-v064)
|
|
740
|
+
- [Reference](#reference)
|
|
741
|
+
- [dar-backup.py](#dar-backuppy)
|
|
742
|
+
- [manager.py](#managerpy)
|
|
743
|
+
- [cleanup.py](#cleanuppy)
|
|
744
|
+
- [clean-log.py](#clean-logpy)
|
|
745
|
+
|
|
746
|
+
## My use case
|
|
747
|
+
|
|
748
|
+
I have cloud storage mounted on a directory within my home dir. The filesystem is [FUSE based](https://www.kernel.org/doc/html/latest/filesystems/fuse.html), which gives it a few special features
|
|
749
|
+
|
|
750
|
+
- a non-privileged user (me :-)) can perform a mount
|
|
751
|
+
- a privileged user cannot look into the filesystem --> a backup script running as root is not suitable
|
|
704
752
|
|
|
705
753
|
I needed the following:
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
-
|
|
710
|
-
|
|
711
|
-
|
|
754
|
+
|
|
755
|
+
- Backup my cloud storage to something local (cloud is convenient, but I want control over my backups)
|
|
756
|
+
- Backup primarily photos, video and different types of documents
|
|
757
|
+
- Have a simple non-complicated way of restoring, possibly years into the future. 'dar' fits that scenario with a single statically linked binary (kept with the archives). There is no need install/configure anything - restoring is simple and works well.
|
|
758
|
+
- During backup archives must be tested and a restore test (however small) performed
|
|
759
|
+
- Archives stored on a server with a reliable file system (easy to mount a directory over sshfs)
|
|
760
|
+
- Easy to verify archive's integrity, after being moved around.
|
|
712
761
|
|
|
713
762
|
I do not need the encryption features of dar, as all storage is already encrypted.
|
|
714
|
-
|
|
715
763
|
|
|
716
|
-
|
|
764
|
+
## License
|
|
717
765
|
|
|
718
766
|
These scripts are licensed under the GPLv3 license.
|
|
719
767
|
Read more here: https://www.gnu.org/licenses/gpl-3.0.en.html, or have a look at the ["LICENSE"](https://github.com/per2jensen/dar-backup/blob/main/LICENSE) file in this repository.
|
|
720
768
|
|
|
769
|
+
## Status
|
|
721
770
|
|
|
722
|
-
# Status
|
|
723
771
|
As of August 8, 2024 I am using the alpha versions of `dar-backup` (alpha-0.5.9 onwards) in my automated backup routine.
|
|
724
772
|
|
|
725
773
|
As of February 13, 2025, I have changed the status from alpha --> beta, as the featureset is in place and the alphas have worked well for a very long time.
|
|
726
774
|
|
|
727
|
-
|
|
728
|
-
**Breaking change in version 0.6.0**
|
|
775
|
+
### Breaking change in version 0.6.0
|
|
729
776
|
|
|
730
777
|
Version 0.6.0 and forwards requires the config variable *COMMAND_TIMEOUT_SECS* in the config file.
|
|
731
778
|
|
|
732
|
-
|
|
733
|
-
|
|
779
|
+
## Homepage - Github
|
|
780
|
+
|
|
781
|
+
This 'dar-backup' package lives at: https://github.com/per2jensen/dar-backup/tree/main/v2
|
|
734
782
|
|
|
735
783
|
This python version is v2 of dar-backup, the first is made in bash.
|
|
736
784
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
785
|
+
## Requirements
|
|
786
|
+
|
|
787
|
+
- dar
|
|
788
|
+
- par2
|
|
789
|
+
- python3 :-)
|
|
741
790
|
|
|
742
791
|
On Ubuntu, install the requirements this way:
|
|
743
|
-
|
|
792
|
+
|
|
793
|
+
```` bash
|
|
744
794
|
sudo apt install dar par2 python3
|
|
745
|
-
|
|
795
|
+
````
|
|
746
796
|
|
|
747
|
-
|
|
797
|
+
## Config file
|
|
748
798
|
|
|
749
799
|
The default configuration is expected here: ~/.config/dar-backup/dar-backup.conf
|
|
750
800
|
|
|
751
|
-
|
|
801
|
+
## How to run
|
|
802
|
+
|
|
803
|
+
### 1 - config file
|
|
752
804
|
|
|
753
|
-
## 1
|
|
754
805
|
Config file default location is $HOME/.config/dar-backup/dar-backup.conf
|
|
755
806
|
|
|
756
807
|
Example:
|
|
757
|
-
|
|
808
|
+
|
|
809
|
+
```` code
|
|
758
810
|
[MISC]
|
|
759
811
|
LOGFILE_LOCATION=/home/user/dar-backup.log
|
|
760
812
|
MAX_SIZE_VERIFICATION_MB = 20
|
|
@@ -791,9 +843,10 @@ ENABLED = True
|
|
|
791
843
|
# SCRIPT_2 = <something>
|
|
792
844
|
# ...
|
|
793
845
|
|
|
794
|
-
````
|
|
846
|
+
````
|
|
847
|
+
|
|
848
|
+
### 2 - backup definitions
|
|
795
849
|
|
|
796
|
-
## 2
|
|
797
850
|
Put your backup definitions in the directory $BACKUP.D_DIR (defined in the config file)
|
|
798
851
|
|
|
799
852
|
The name of the file is the `backup definition` name.
|
|
@@ -803,7 +856,8 @@ Make as many backup definitions as you need. Run them all in one go, or run one
|
|
|
803
856
|
The `dar` [documentation](http://dar.linux.free.fr/doc/man/dar.html#COMMANDS%20AND%20OPTIONS) has good information on file selection.
|
|
804
857
|
|
|
805
858
|
Example of backup definition for a home directory
|
|
806
|
-
|
|
859
|
+
|
|
860
|
+
```` code
|
|
807
861
|
|
|
808
862
|
# Switch to ordered selection mode, which means that the following
|
|
809
863
|
# options will be considered top to bottom
|
|
@@ -817,7 +871,7 @@ Example of backup definition for a home directory
|
|
|
817
871
|
# if you want to take a backup of /home/user/Documents only, uncomment next line
|
|
818
872
|
# -g Documents
|
|
819
873
|
|
|
820
|
-
# Some directories to exclude below the Root dir
|
|
874
|
+
# Some directories to exclude below the Root dir (here Root directory is `/home/user` as set in the -R option)
|
|
821
875
|
-P mnt
|
|
822
876
|
-P tmp
|
|
823
877
|
-P .cache
|
|
@@ -836,131 +890,93 @@ Example of backup definition for a home directory
|
|
|
836
890
|
# size of each slice in the archive
|
|
837
891
|
--slice 10G
|
|
838
892
|
|
|
839
|
-
# see https://github.com/per2jensen/dar-backup?tab=readme-ov-file#restore-test-exit-code-4
|
|
840
|
-
--comparison-field=ignore-owner
|
|
841
893
|
|
|
842
894
|
# bypass directores marked as cache directories
|
|
843
895
|
# http://dar.linux.free.fr/doc/Features.html
|
|
844
896
|
--cache-directory-tagging
|
|
845
|
-
````
|
|
897
|
+
````
|
|
846
898
|
|
|
899
|
+
### 3 - installation
|
|
847
900
|
|
|
848
|
-
## 3
|
|
849
901
|
Installation is currently in a venv. These commands are installed in the venv:
|
|
902
|
+
|
|
850
903
|
- dar-back
|
|
851
904
|
- cleanup
|
|
852
905
|
- manager
|
|
906
|
+
- clean-log
|
|
853
907
|
|
|
854
908
|
To install, create a venv and run pip:
|
|
855
|
-
|
|
909
|
+
|
|
910
|
+
```` bash
|
|
856
911
|
mkdir $HOME/tmp
|
|
857
912
|
cd $HOME/tmp
|
|
858
913
|
python3 -m venv venv # create the virtual environment
|
|
859
914
|
. venv/bin/activate # activate the virtual env
|
|
860
915
|
pip install dar-backup # run pip to install `dar-backup`
|
|
861
|
-
````
|
|
862
|
-
|
|
916
|
+
````
|
|
863
917
|
|
|
864
918
|
I have an alias in ~/.bashrc pointing to my venv:
|
|
865
|
-
|
|
919
|
+
|
|
920
|
+
```` bash
|
|
866
921
|
alias db=". ~/tmp/venv/bin/activate; dar-backup -v"
|
|
867
|
-
````
|
|
922
|
+
````
|
|
868
923
|
|
|
869
924
|
Typing `db` at the command line gives this
|
|
870
|
-
|
|
925
|
+
|
|
926
|
+
```` bash
|
|
871
927
|
(venv) user@machine:~$ db
|
|
872
|
-
dar-backup 0.
|
|
928
|
+
dar-backup 0.6.9
|
|
873
929
|
dar-backup.py source code is here: https://github.com/per2jensen/dar-backup
|
|
874
930
|
Licensed under GNU GENERAL PUBLIC LICENSE v3, see the supplied file "LICENSE" for details.
|
|
875
931
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW, not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
876
932
|
See section 15 and section 16 in the supplied "LICENSE" file.
|
|
877
933
|
````
|
|
878
934
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
usage: dar-backup [-h] [-F] [-D] [-I] [-d BACKUP_DEFINITION]
|
|
882
|
-
[--alternate-reference-archive ALTERNATE_REFERENCE_ARCHIVE] [-c CONFIG_FILE] [--darrc DARRC]
|
|
883
|
-
[--examples] [-l] [--list-contents LIST_CONTENTS] [--selection SELECTION] [-r RESTORE]
|
|
884
|
-
[--restore-dir RESTORE_DIR] [--verbose] [--log-level LOG_LEVEL] [--log-stdout]
|
|
885
|
-
[--do-not-compare] [-v]
|
|
886
|
-
|
|
887
|
-
Backup and verify using dar backup definitions.
|
|
888
|
-
|
|
889
|
-
options:
|
|
890
|
-
-h, --help show this help message and exit
|
|
891
|
-
-F, --full-backup Perform a full backup.
|
|
892
|
-
-D, --differential-backup
|
|
893
|
-
Perform differential backup.
|
|
894
|
-
-I, --incremental-backup
|
|
895
|
-
Perform incremental backup.
|
|
896
|
-
-d BACKUP_DEFINITION, --backup-definition BACKUP_DEFINITION
|
|
897
|
-
Specific 'recipe' to select directories and files.
|
|
898
|
-
--alternate-reference-archive ALTERNATE_REFERENCE_ARCHIVE
|
|
899
|
-
DIFF or INCR compared to specified archive.
|
|
900
|
-
-c CONFIG_FILE, --config-file CONFIG_FILE
|
|
901
|
-
Path to 'dar-backup.conf'
|
|
902
|
-
--darrc DARRC Optional path to .darrc
|
|
903
|
-
--examples Examples of using dar-backup.py.
|
|
904
|
-
-l, --list List available archives.
|
|
905
|
-
--list-contents LIST_CONTENTS
|
|
906
|
-
List the contents of the specified archive.
|
|
907
|
-
--selection SELECTION
|
|
908
|
-
dar file selection for listing/restoring specific files/directories.
|
|
909
|
-
-r RESTORE, --restore RESTORE
|
|
910
|
-
Restore specified archive.
|
|
911
|
-
--restore-dir RESTORE_DIR
|
|
912
|
-
Directory to restore files to.
|
|
913
|
-
--verbose Print various status messages to screen
|
|
914
|
-
--log-level LOG_LEVEL
|
|
915
|
-
`debug` or `trace`
|
|
916
|
-
--log-stdout also print log messages to stdout
|
|
917
|
-
--do-not-compare do not compare restores to file system
|
|
918
|
-
-v, --version Show version and license information.
|
|
919
|
-
````
|
|
920
|
-
|
|
921
|
-
## 4
|
|
935
|
+
### 4 - generate catalog databases
|
|
936
|
+
|
|
922
937
|
Generate the archive catalog database(s).
|
|
923
938
|
`dar-backup` expects the catalog databases to be in place, it does not automatically create them (by design)
|
|
924
939
|
|
|
925
|
-
````
|
|
926
|
-
manager --create-db
|
|
927
|
-
````
|
|
928
|
-
|
|
929
|
-
|
|
940
|
+
```` bash
|
|
941
|
+
manager --create-db
|
|
942
|
+
````
|
|
930
943
|
|
|
944
|
+
### 5 - do FULL backups
|
|
931
945
|
|
|
932
|
-
## 5
|
|
933
946
|
You are ready to do backups of all your backup definitions, if your backup definitions are
|
|
934
947
|
in place in BACKUP.D_DIR (see config file)
|
|
935
|
-
|
|
948
|
+
|
|
949
|
+
```` bash
|
|
936
950
|
dar-backup --full-backup
|
|
937
|
-
````
|
|
951
|
+
````
|
|
952
|
+
|
|
938
953
|
If you want to see dar-backup's log entries in the terminal, use the `--log-stdout` option. This is also useful if dar-backup is started by systemd.
|
|
939
954
|
|
|
940
955
|
If you want more log messages, use the `--log-level debug` option.
|
|
941
956
|
|
|
942
|
-
|
|
943
957
|
If you want a backup of a single definition, use the `-d <backup definition>` option. The definition's name is the filename of the definition in the `backup.d` config directory.
|
|
944
|
-
|
|
958
|
+
|
|
959
|
+
```` bash
|
|
945
960
|
dar-backup --full-backup -d <your backup definition>
|
|
946
961
|
````
|
|
947
962
|
|
|
948
|
-
|
|
963
|
+
### 6 - deactivate venv
|
|
949
964
|
|
|
950
|
-
Deactivate the virtual environment
|
|
951
|
-
|
|
965
|
+
Deactivate the virtual environment (venv)
|
|
966
|
+
|
|
967
|
+
```` bash
|
|
952
968
|
deactivate
|
|
953
969
|
````
|
|
954
970
|
|
|
971
|
+
## .darrc
|
|
955
972
|
|
|
956
|
-
# .darrc
|
|
957
973
|
The package includes a default `.darrc` file which configures `dar`.
|
|
958
974
|
|
|
959
975
|
You can override the default `.darrc` using the `--darrc` option.
|
|
960
976
|
|
|
961
977
|
The default `.darrc` contents are as follows:
|
|
962
978
|
|
|
963
|
-
````
|
|
979
|
+
```` code
|
|
964
980
|
# .darrc configuration file for `dar` as used by the `dar-backup` script.
|
|
965
981
|
# `dar-backup` lives here: https://github.com/per2jensen/dar-backup
|
|
966
982
|
|
|
@@ -998,19 +1014,21 @@ verbose:
|
|
|
998
1014
|
# -va
|
|
999
1015
|
|
|
1000
1016
|
|
|
1001
|
-
|
|
1017
|
+
restore-options:
|
|
1002
1018
|
# don't restore File Specific Attributes
|
|
1003
1019
|
#--fsa-scope none
|
|
1004
1020
|
|
|
1005
1021
|
# ignore owner, useful when used by a non-privileged user
|
|
1006
1022
|
--comparison-field=ignore-owner
|
|
1007
1023
|
|
|
1024
|
+
|
|
1025
|
+
# Exclude specific file types from compression
|
|
1026
|
+
compress-exclusion:
|
|
1027
|
+
|
|
1008
1028
|
# First setting case insensitive mode on:
|
|
1009
1029
|
-an
|
|
1010
1030
|
-ag
|
|
1011
1031
|
|
|
1012
|
-
# Exclude specific file types from compression
|
|
1013
|
-
compress-exclusion:
|
|
1014
1032
|
-Z "*.gz"
|
|
1015
1033
|
-Z "*.bz2"
|
|
1016
1034
|
-Z "*.xz"
|
|
@@ -1081,14 +1099,15 @@ compress-exclusion:
|
|
|
1081
1099
|
-acase
|
|
1082
1100
|
````
|
|
1083
1101
|
|
|
1084
|
-
|
|
1102
|
+
## Systemctl examples
|
|
1103
|
+
|
|
1085
1104
|
I have dar-backup scheduled to run via systemd --user settings.
|
|
1086
1105
|
|
|
1087
1106
|
The files are located in: ~/.config/systemd/user
|
|
1088
1107
|
|
|
1089
1108
|
Once the .service and .timer files are in place, timers must be enabled and started.
|
|
1090
1109
|
|
|
1091
|
-
````
|
|
1110
|
+
```` bash
|
|
1092
1111
|
systemctl --user enable dar-inc-backup.timer
|
|
1093
1112
|
systemctl --user start dar-inc-backup.timer
|
|
1094
1113
|
systemctl --user daemon-reload
|
|
@@ -1096,15 +1115,15 @@ systemctl --user daemon-reload
|
|
|
1096
1115
|
|
|
1097
1116
|
Verify your timers are set up as you want:
|
|
1098
1117
|
|
|
1099
|
-
````
|
|
1118
|
+
```` bash
|
|
1100
1119
|
systemctl --user list-timers
|
|
1101
1120
|
````
|
|
1102
1121
|
|
|
1103
|
-
|
|
1104
1122
|
## Service: dar-back --incremental-backup
|
|
1105
1123
|
|
|
1106
1124
|
File: dar-inc-backup.service
|
|
1107
|
-
|
|
1125
|
+
|
|
1126
|
+
```` code
|
|
1108
1127
|
[Unit]
|
|
1109
1128
|
Description=dar-backup INC
|
|
1110
1129
|
StartLimitIntervalSec=120
|
|
@@ -1119,7 +1138,8 @@ ExecStart=/bin/bash -c '. /home/user/programmer/dar-backup.py/venv/bin/activate
|
|
|
1119
1138
|
## Timer: dar-back --incremental-backup
|
|
1120
1139
|
|
|
1121
1140
|
File: dar-inc-backup.timer
|
|
1122
|
-
|
|
1141
|
+
|
|
1142
|
+
```` code
|
|
1123
1143
|
[Unit]
|
|
1124
1144
|
Description=dar-backup INC timer
|
|
1125
1145
|
|
|
@@ -1131,15 +1151,17 @@ Persistent=true
|
|
|
1131
1151
|
WantedBy=timers.target
|
|
1132
1152
|
````
|
|
1133
1153
|
|
|
1154
|
+
## list contents of an archive
|
|
1134
1155
|
|
|
1135
|
-
|
|
1136
|
-
```
|
|
1156
|
+
```` bash
|
|
1137
1157
|
. <the virtual evn>/bin/activate
|
|
1138
1158
|
dar-backup --list-contents example_FULL_2024-06-23 --selection "-X '*.xmp' -I '*2024-06-16*' -g home/pj/tmp/LUT-play"
|
|
1139
1159
|
deactivate
|
|
1140
|
-
|
|
1160
|
+
````
|
|
1161
|
+
|
|
1141
1162
|
gives
|
|
1142
|
-
|
|
1163
|
+
|
|
1164
|
+
``` code
|
|
1143
1165
|
[Data ][D][ EA ][FSA][Compr][S]| Permission | User | Group | Size | Date | filename
|
|
1144
1166
|
--------------------------------+------------+-------+-------+---------+-------------------------------+------------
|
|
1145
1167
|
[Saved][-] [-L-][ 0%][ ] drwxr-xr-x root root 113 Mio Sat May 11 16:16:48 2024 home
|
|
@@ -1149,17 +1171,17 @@ gives
|
|
|
1149
1171
|
[Saved][ ] [-L-][ 0%][X] -rw-rw-r-- pj pj 49 Mio Sun Jun 16 12:52:22 2024 home/pj/tmp/LUT-play/2024-06-16_12:52:22,15.NEF
|
|
1150
1172
|
```
|
|
1151
1173
|
|
|
1174
|
+
## dar file selection exmaples
|
|
1152
1175
|
|
|
1176
|
+
### select a directory
|
|
1153
1177
|
|
|
1154
|
-
|
|
1155
|
-
# dar file selection exmaples
|
|
1156
|
-
|
|
1157
|
-
## select a directory
|
|
1158
|
-
```
|
|
1178
|
+
``` bash
|
|
1159
1179
|
dar -l /tmp/example_FULL_2024-06-23 -g home/pj/tmp/LUT-play
|
|
1160
1180
|
```
|
|
1181
|
+
|
|
1161
1182
|
gives
|
|
1162
|
-
|
|
1183
|
+
|
|
1184
|
+
```` code
|
|
1163
1185
|
[Data ][D][ EA ][FSA][Compr][S]| Permission | User | Group | Size | Date | filename
|
|
1164
1186
|
--------------------------------+------------+-------+-------+---------+-------------------------------+------------
|
|
1165
1187
|
[Saved][-] [-L-][ 0%][ ] drwxr-xr-x root root 113 Mio Sat May 11 16:16:48 2024 home
|
|
@@ -1186,15 +1208,17 @@ gives
|
|
|
1186
1208
|
[Saved][ ] [-L-][ 92%][ ] -rw-rw-r-- pj pj 24 kio Sat Jun 22 21:51:15 2024 home/pj/tmp/LUT-play/2024-06-16_12:52:22,15_16.NEF.xmp
|
|
1187
1209
|
[Saved][ ] [-L-][ 92%][ ] -rw-rw-r-- pj pj 24 kio Sat Jun 22 21:50:48 2024 home/pj/tmp/LUT-play/2024-06-16_12:52:22,15_17.NEF.xmp
|
|
1188
1210
|
[Saved][ ] [-L-][ 92%][ ] -rw-rw-r-- pj pj 24 kio Sat Jun 22 21:50:19 2024 home/pj/tmp/LUT-play/2024-06-16_12:52:22,15_18.NEF.xmp
|
|
1189
|
-
|
|
1211
|
+
````
|
|
1190
1212
|
|
|
1213
|
+
### select file dates in the directory:
|
|
1191
1214
|
|
|
1192
|
-
|
|
1193
|
-
```
|
|
1215
|
+
``` bash
|
|
1194
1216
|
dar -l /tmp/example_FULL_2024-06-23 -I '*2024-06-16*' -g home/pj/tmp/LUT-play
|
|
1195
1217
|
```
|
|
1218
|
+
|
|
1196
1219
|
gives
|
|
1197
|
-
|
|
1220
|
+
|
|
1221
|
+
``` code
|
|
1198
1222
|
[Data ][D][ EA ][FSA][Compr][S]| Permission | User | Group | Size | Date | filename
|
|
1199
1223
|
--------------------------------+------------+-------+-------+---------+-------------------------------+------------
|
|
1200
1224
|
[Saved][-] [-L-][ 0%][ ] drwxr-xr-x root root 113 Mio Sat May 11 16:16:48 2024 home
|
|
@@ -1223,12 +1247,16 @@ gives
|
|
|
1223
1247
|
[Saved][ ] [-L-][ 92%][ ] -rw-rw-r-- pj pj 24 kio Sat Jun 22 21:50:19 2024 home/pj/tmp/LUT-play/2024-06-16_12:52:22,15_18.NEF.xmp
|
|
1224
1248
|
```
|
|
1225
1249
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1250
|
+
### exclude .xmp files from that date
|
|
1251
|
+
|
|
1252
|
+
``` bash
|
|
1228
1253
|
dar -l /tmp/example_FULL_2024-06-23 -X '*.xmp' -I '*2024-06-16*' -g home/pj/tmp/LUT-play
|
|
1254
|
+
|
|
1229
1255
|
```
|
|
1256
|
+
|
|
1230
1257
|
gives
|
|
1231
|
-
|
|
1258
|
+
|
|
1259
|
+
``` code
|
|
1232
1260
|
[Data ][D][ EA ][FSA][Compr][S]| Permission | User | Group | Size | Date | filename
|
|
1233
1261
|
--------------------------------+------------+-------+-------+---------+-------------------------------+------------
|
|
1234
1262
|
[Saved][-] [-L-][ 0%][ ] drwxr-xr-x root root 113 Mio Sat May 11 16:16:48 2024 home
|
|
@@ -1240,16 +1268,16 @@ gives
|
|
|
1240
1268
|
|
|
1241
1269
|
Nice :-)
|
|
1242
1270
|
|
|
1271
|
+
## Restoring
|
|
1243
1272
|
|
|
1273
|
+
### default location for restores
|
|
1244
1274
|
|
|
1245
|
-
# Restoring
|
|
1246
|
-
|
|
1247
|
-
## default location for restores
|
|
1248
1275
|
dar-backup will use the TEST_RESTORE_DIR location as the Root for restores, if the --restore-dir option has not been supplied.
|
|
1249
1276
|
|
|
1250
1277
|
See example below to see where files are restored to.
|
|
1251
1278
|
|
|
1252
|
-
|
|
1279
|
+
### --restore-dir option
|
|
1280
|
+
|
|
1253
1281
|
When the --restore-dir option is used for restoring, a directory must be supplied.
|
|
1254
1282
|
|
|
1255
1283
|
The directory supplied functions as the Root of the restore operation.
|
|
@@ -1257,41 +1285,200 @@ The directory supplied functions as the Root of the restore operation.
|
|
|
1257
1285
|
**Example**:
|
|
1258
1286
|
|
|
1259
1287
|
A backup has been taken using this backup definition:
|
|
1260
|
-
|
|
1288
|
+
|
|
1289
|
+
``` code
|
|
1261
1290
|
-R /
|
|
1262
1291
|
-g home/user/Documents
|
|
1263
1292
|
```
|
|
1264
1293
|
|
|
1265
1294
|
When restoring and using `/tmp` for --restore-dir, the restored files can be found in `/tmp/home/user/Documents`
|
|
1266
1295
|
|
|
1267
|
-
|
|
1268
|
-
|
|
1296
|
+
### a single file
|
|
1297
|
+
|
|
1298
|
+
``` code
|
|
1269
1299
|
. <the virtual env>/bin/activate
|
|
1270
1300
|
dar-backup --restore <archive_name> --selection "-g path/to/file"
|
|
1271
1301
|
deactivate
|
|
1302
|
+
|
|
1272
1303
|
```
|
|
1273
|
-
|
|
1274
|
-
|
|
1304
|
+
|
|
1305
|
+
### a directory
|
|
1306
|
+
|
|
1307
|
+
``` bash
|
|
1275
1308
|
. <the virtual env>/bin/activate
|
|
1276
1309
|
dar-backup --restore <archive_name> --selection "-g path/to/directory"
|
|
1277
1310
|
deactivate
|
|
1278
1311
|
```
|
|
1279
1312
|
|
|
1313
|
+
### .NEF from a specific date
|
|
1280
1314
|
|
|
1281
|
-
|
|
1282
|
-
```
|
|
1315
|
+
``` bash
|
|
1283
1316
|
. <the virtual env>/bin/activate
|
|
1284
1317
|
dar-backup --restore <archive_name> --selection "-X '*.xmp' -I '*2024-06-16*' -g home/pj/tmp/LUT-play"
|
|
1285
1318
|
deactivate
|
|
1286
1319
|
```
|
|
1287
1320
|
|
|
1321
|
+
### restore test fails with exit code 4
|
|
1288
1322
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1323
|
+
"dar" in newer versions emits a question about file ownership, which is "answered" with a "no" via the "-Q" option. That in turn leads to an error code 4.
|
|
1324
|
+
|
|
1325
|
+
Thus the dar option "--comparison-field=ignore-owner" has been placed in the supplied .darrc file (located in the virtual environment where dar-backup is installed).
|
|
1326
|
+
|
|
1327
|
+
This causes dar to restore without an error.
|
|
1328
|
+
|
|
1329
|
+
It is a good option when using dar as a non-privileged user.
|
|
1330
|
+
|
|
1331
|
+
### restore test fails with exit code 5
|
|
1332
|
+
|
|
1333
|
+
If exit code 5 is emitted on the restore test, FSA (File System specific Attributes) could be the cause.
|
|
1334
|
+
|
|
1335
|
+
That (might) occur if you backup a file stored on one type of filesystem, and restore it on another type.
|
|
1336
|
+
My home directory is on a btrfs filesystem, while /tmp (for the restore test) is on zfs.
|
|
1337
|
+
|
|
1338
|
+
The restore test can result in an exit code 5, due to the different filesystems used. In order to avoid the errors, the "option "--fsa-scope none" can be used. That will restult in FSA's not being restored.
|
|
1339
|
+
|
|
1340
|
+
If you need to use this option, un-comment it in the .darrc file (located in the virtual environment where dar-backup is installed)
|
|
1341
|
+
|
|
1342
|
+
## Par2
|
|
1343
|
+
|
|
1344
|
+
### Par2 to verify/repair
|
|
1345
|
+
|
|
1346
|
+
You can run a par2 verification on an archive like this:
|
|
1347
|
+
|
|
1348
|
+
```` bash
|
|
1349
|
+
for file in <archive>*.dar.par2; do
|
|
1350
|
+
par2 verify "$file"
|
|
1351
|
+
done
|
|
1352
|
+
````
|
|
1353
|
+
|
|
1354
|
+
if there are problems with a slice, try to repair it like this:
|
|
1355
|
+
|
|
1356
|
+
```` bash
|
|
1357
|
+
par2 repair <archive>.<slice number>.dar.par2
|
|
1358
|
+
````
|
|
1359
|
+
|
|
1360
|
+
### Par2 create redundancy files
|
|
1361
|
+
|
|
1362
|
+
If you have merged archives, you will need to create the .par2 redundency files manually.
|
|
1363
|
+
Here is an example
|
|
1364
|
+
|
|
1365
|
+
```` bash
|
|
1366
|
+
for file in <some-archive>_FULL_yyyy-mm-dd.*; do
|
|
1367
|
+
par2 c -r5 -n1 "$file"
|
|
1368
|
+
done
|
|
1369
|
+
````
|
|
1370
|
+
|
|
1371
|
+
where "c" is create, -r5 is 5% redundency and -n1 is 1 redundency file
|
|
1372
|
+
|
|
1373
|
+
## Points of interest
|
|
1374
|
+
|
|
1375
|
+
### Merge FULL with DIFF, creating new FULL
|
|
1376
|
+
|
|
1377
|
+
Over time, the DIFF archives become larger and larger. At some point one wishes to create a new FULL archive to do DIFF's on.
|
|
1378
|
+
One way to do that, is to let dar create a FULL archive from scratch, another is to merge a FULL archive with a DIFF, and from there do DIFF's until they once again gets too large for your taste.
|
|
1379
|
+
|
|
1380
|
+
I do backups of my homedir. Here it is shown how a FULL archive is merged with a DIFF, creating a new FULL archive.
|
|
1381
|
+
|
|
1382
|
+
```` bash
|
|
1383
|
+
dar --merge pj-homedir_FULL_2021-09-12 -A pj-homedir_FULL_2021-06-06 -@pj-homedir_DIFF_2021-08-29 -s 12G
|
|
1384
|
+
|
|
1385
|
+
# test the new FULL archive
|
|
1386
|
+
dar -t pj-homedir_FULL_2021-09-12
|
|
1387
|
+
|
|
1388
|
+
# create Par2 redundancy files
|
|
1389
|
+
for file in pj-homedir_FULL_yyyy-mm-dd.*.dar; do
|
|
1390
|
+
par2 c -r5 -n1 "$file"
|
|
1391
|
+
done
|
|
1392
|
+
|
|
1393
|
+
````
|
|
1394
|
+
|
|
1395
|
+
### dar manager databases
|
|
1396
|
+
|
|
1397
|
+
`dar-backup` now saves archive catalogs in dar catalog databases.
|
|
1398
|
+
|
|
1399
|
+
This makes it easier to restore to a given date when having many FULL, DIFF and INCR archives.
|
|
1400
|
+
|
|
1401
|
+
### Performance tip due to par2
|
|
1402
|
+
|
|
1403
|
+
This [dar benchmark page](https://dar.sourceforge.io/doc/benchmark.html) has an interesting note on the slice size.
|
|
1404
|
+
|
|
1405
|
+
Slice size should be smaller than available RAM, apparently a large performance hit can be avoided keeping the the par2 data in memory.
|
|
1406
|
+
|
|
1407
|
+
### .darrc sets -vd -vf (since v0.6.4)
|
|
1292
1408
|
|
|
1293
1409
|
These .darrc settings make `dar` print the current directory being processed (-vd) and some stats after (-vf)
|
|
1294
1410
|
This is very useful in very long running jobs to get an indication that the backup is proceeding normally.
|
|
1295
1411
|
|
|
1296
|
-
if --log-stdout is used the information would be picked up by systemd and logged by journald
|
|
1412
|
+
if --log-stdout is used the information would be picked up by systemd and logged by journald.½
|
|
1413
|
+
|
|
1414
|
+
The log file can get quite cluttered, if you want the clutter to be removed, run the `clean-log`script.
|
|
1415
|
+
|
|
1416
|
+
## Reference
|
|
1417
|
+
|
|
1418
|
+
### dar-backup.py
|
|
1419
|
+
|
|
1420
|
+
This script is responsible for managing the backup creation and validation process. It supports the following options:
|
|
1421
|
+
|
|
1422
|
+
``` code
|
|
1423
|
+
--full-backup Perform a full backup.
|
|
1424
|
+
--differential-backup Perform a differential backup.
|
|
1425
|
+
--incremental-backup Perform an incremental backup.
|
|
1426
|
+
--backup-definition <name> Specify the backup definition file.
|
|
1427
|
+
--alternate-reference-archive <file> Use a different archive for DIFF/INCR backups.
|
|
1428
|
+
--config-file <path> Specify the path to the configuration file.
|
|
1429
|
+
--darrc <path> Specify an optional path to .darrc.
|
|
1430
|
+
--examples Show examples of using dar-backup.py.
|
|
1431
|
+
--list List available backups.
|
|
1432
|
+
--list-contents <archive> List the contents of a specified archive.
|
|
1433
|
+
--selection <params> Define file selection for listing/restoring.
|
|
1434
|
+
--restore <archive> Restore a specified archive.
|
|
1435
|
+
--restore-dir <path> Directory to restore files to.
|
|
1436
|
+
--verbose Enable verbose output.
|
|
1437
|
+
--log-level <level> Set log level (debug, trace, etc.).
|
|
1438
|
+
--log-stdout Also print log messages to stdout.
|
|
1439
|
+
--do-not-compare Do not compare restores to file system.
|
|
1440
|
+
--version Show version and license information.
|
|
1441
|
+
```
|
|
1442
|
+
|
|
1443
|
+
### manager.py
|
|
1444
|
+
|
|
1445
|
+
This script manages `dar` databases and catalogs. Available options include:
|
|
1446
|
+
|
|
1447
|
+
``` code
|
|
1448
|
+
--create-db Create missing databases for all backup definitions.
|
|
1449
|
+
--alternate-archive-dir <path> Use this directory instead of BACKUP_DIR in the config file.
|
|
1450
|
+
--add-dir <path> Add all archive catalogs in this directory to databases.
|
|
1451
|
+
-d, --backup-def <name> Restrict to work only on this backup definition.
|
|
1452
|
+
--add-specific-archive <file> Add this archive to the catalog database.
|
|
1453
|
+
--remove-specific-archive <file> Remove this archive from the catalog database.
|
|
1454
|
+
-l, --list-catalogs List catalogs in databases for all backup definitions.
|
|
1455
|
+
--list-catalog-contents <num> List contents of a catalog by archive number.
|
|
1456
|
+
--list-archive-contents <file> List contents of an archive’s catalog.
|
|
1457
|
+
--find-file <file> Search catalogs for a specific file.
|
|
1458
|
+
--verbose Enable verbose output.
|
|
1459
|
+
--log-level <level> Set log level.
|
|
1460
|
+
```
|
|
1461
|
+
|
|
1462
|
+
### cleanup.py
|
|
1463
|
+
|
|
1464
|
+
This script cleans up old backups and manages storage. Supported options:
|
|
1465
|
+
|
|
1466
|
+
``` code
|
|
1467
|
+
--prune-older-than <days> Remove backups older than the specified number of days.
|
|
1468
|
+
--keep-last <num> Retain only the last <num> backups.
|
|
1469
|
+
--dry-run Show what would be deleted without actually deleting.
|
|
1470
|
+
--backup-dir <path> Specify the backup directory.
|
|
1471
|
+
--verbose Enable verbose output.
|
|
1472
|
+
--help Show this help message and exit.
|
|
1473
|
+
```
|
|
1474
|
+
|
|
1475
|
+
### clean-log.py
|
|
1297
1476
|
|
|
1477
|
+
This script removes excessive logging output from `dar` logs, improving readability and efficiency. Available options:
|
|
1478
|
+
|
|
1479
|
+
``` code
|
|
1480
|
+
-f, --file <path> Specify the log file(s) to be cleaned.
|
|
1481
|
+
-c, --config-file <path> Specify the configuration file (default: ~/.config/dar-backup/dar-backup.conf).
|
|
1482
|
+
--dry-run Show which lines would be removed without modifying the file.
|
|
1483
|
+
-v, --version Display version and licensing information.
|
|
1484
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
dar_backup/.darrc,sha256=-aerqivZmOsW_XBCh9IfbYTUvw0GkzDSr3Vx4GcNB1g,2113
|
|
2
|
+
dar_backup/__about__.py,sha256=WAW-bfIrNx18qYeBN4lihEQibyosiKElDt_p7DfZELo,22
|
|
3
|
+
dar_backup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
dar_backup/clean_log.py,sha256=VXKA2BMyQmaC6R08Bq9a3wP3mczdFb_moy6HkL-mnF8,5176
|
|
5
|
+
dar_backup/cleanup.py,sha256=9yEdRR84XPtEvBGc2QfwGBQl2tdTPttjetHeiSc_TsM,11419
|
|
6
|
+
dar_backup/config_settings.py,sha256=CBMUhLOOZ-x7CRdS3vBDk4TYaGqC4N1Ot8IMH-qPaI0,3617
|
|
7
|
+
dar_backup/dar_backup.py,sha256=o4DvaVsqWHb1PxHIXfdr2qyqW6KRRGNcrR2_CRbPy1I,32942
|
|
8
|
+
dar_backup/manager.py,sha256=HDa8eYF89QFhlBRR4EWRzzmswOW00S_w8ToZ5SARO_o,21359
|
|
9
|
+
dar_backup/util.py,sha256=E-sEBQZY1hmdeVx5xNE22zKQ0BXDee1eI9F1-w7Fq1Q,15756
|
|
10
|
+
dar_backup-0.6.11.dist-info/METADATA,sha256=N7ICBJQEVDC01tza9lRAkmOXCIAILoDrg-mrHG926f0,71626
|
|
11
|
+
dar_backup-0.6.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
12
|
+
dar_backup-0.6.11.dist-info/entry_points.txt,sha256=p6c4uQLjlTIVP1Od2iorGefrVUH0IWZdFRMl63mNaRg,164
|
|
13
|
+
dar_backup-0.6.11.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
14
|
+
dar_backup-0.6.11.dist-info/RECORD,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
dar_backup/.darrc,sha256=-aerqivZmOsW_XBCh9IfbYTUvw0GkzDSr3Vx4GcNB1g,2113
|
|
2
|
-
dar_backup/__about__.py,sha256=42fbYUSZonpHevrA9hTI2EzfgLNO9LBK95poG3HeDEQ,21
|
|
3
|
-
dar_backup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
dar_backup/clean_log.py,sha256=VXKA2BMyQmaC6R08Bq9a3wP3mczdFb_moy6HkL-mnF8,5176
|
|
5
|
-
dar_backup/cleanup.py,sha256=9yEdRR84XPtEvBGc2QfwGBQl2tdTPttjetHeiSc_TsM,11419
|
|
6
|
-
dar_backup/config_settings.py,sha256=CBMUhLOOZ-x7CRdS3vBDk4TYaGqC4N1Ot8IMH-qPaI0,3617
|
|
7
|
-
dar_backup/dar_backup.py,sha256=hDy7aXU-XiWOtW40Pxql441liNkSYKGU76eOwy8m7fU,32714
|
|
8
|
-
dar_backup/manager.py,sha256=HDa8eYF89QFhlBRR4EWRzzmswOW00S_w8ToZ5SARO_o,21359
|
|
9
|
-
dar_backup/util.py,sha256=SSSJYM9lQZfubhTUBlX1xDGWmCpYEF3ePARmlY544xM,11283
|
|
10
|
-
dar_backup-0.6.9.dist-info/METADATA,sha256=mqAzHZp_-X9pw8w77c4FA7QwXnKikkSodJ-oJnaFT3M,64610
|
|
11
|
-
dar_backup-0.6.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
12
|
-
dar_backup-0.6.9.dist-info/entry_points.txt,sha256=p6c4uQLjlTIVP1Od2iorGefrVUH0IWZdFRMl63mNaRg,164
|
|
13
|
-
dar_backup-0.6.9.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
14
|
-
dar_backup-0.6.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|