Compare commits
59 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c78676ab9d | ||
|
|
2dec3ed145 | ||
|
|
c56e78a463 | ||
|
|
27785d0ad0 | ||
|
|
4dd6ed1ee2 | ||
|
|
5cad03cb3e | ||
|
|
f71dd556dc | ||
|
|
77ecc4318f | ||
|
|
99b2512789 | ||
|
|
4779ee4d1b | ||
|
|
96a64148fd | ||
|
|
6140c226db | ||
|
|
18ef8983aa | ||
|
|
734be37b6d | ||
|
|
9fea5075ab | ||
|
|
ae37de0e65 | ||
|
|
2a77dde6ee | ||
|
|
e070ca7887 | ||
|
|
5a023c3609 | ||
|
|
6377ad5281 | ||
|
|
649c7830b0 | ||
|
|
dba25a57de | ||
|
|
13af8206e3 | ||
|
|
9a36453bb1 | ||
|
|
a7752c4c78 | ||
|
|
06291f0a6e | ||
|
|
cd82c07579 | ||
|
|
de7a6be9fe | ||
|
|
98bcf9f673 | ||
|
|
0c4f2b7c45 | ||
|
|
2389ee61db | ||
|
|
def00abe60 | ||
|
|
e4df413036 | ||
|
|
dd2189ec4d | ||
|
|
f8c4d0cc16 | ||
|
|
723945af44 | ||
|
|
b7c292b5ff | ||
|
|
cc2ae25355 | ||
|
|
d1311a185a | ||
|
|
25d63bb99f | ||
|
|
2ad58dc07e | ||
|
|
418ab79b11 | ||
|
|
6ba17fa268 | ||
|
|
b207b90cba | ||
|
|
fb54103607 | ||
|
|
d2ae7c58c1 | ||
|
|
a827d886f4 | ||
|
|
5a5244e164 | ||
|
|
26dc5cab55 | ||
|
|
cddd3f3c74 | ||
|
|
277677350c | ||
|
|
fb54765c53 | ||
|
|
4bdde466e2 | ||
|
|
0f901f4f78 | ||
|
|
4d5ab6247d | ||
|
|
5d20128634 | ||
|
|
6c7eea2401 | ||
|
|
b39300c514 | ||
|
|
6421242e02 |
6 changed files with 489 additions and 213 deletions
|
|
@ -3,12 +3,8 @@ language: bash
|
|||
# Use container-based infrastructure for quicker build start-up
|
||||
sudo: false
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- debian-sid
|
||||
packages:
|
||||
- shellcheck
|
||||
before_script:
|
||||
- shellcheck --version
|
||||
|
||||
script:
|
||||
- shellcheck -e SC2034 duplicity-backup.sh duplicity-backup.conf.example
|
||||
|
|
|
|||
68
CHANGELOG
68
CHANGELOG
|
|
@ -1,3 +1,47 @@
|
|||
vX.X.X (unreleased)
|
||||
===================
|
||||
|
||||
v1.6.0 (2018-05-22)
|
||||
===================
|
||||
* Add support for Dropbox backend (by xmatthias)
|
||||
* Fix issue #177: bug in `--cleanup` action (thanks smcgrat)
|
||||
|
||||
v1.5.0 (2018-01-15)
|
||||
===================
|
||||
* Add support for B2 backend (by harrim4n)
|
||||
|
||||
v1.4.3 (2017-10-30)
|
||||
===================
|
||||
* Add support for Telegram notifications (by GerardRibas)
|
||||
|
||||
v1.4.2 (2017-10-30)
|
||||
===================
|
||||
* Remove VERSION file and hardcode it directly in the script. Fix issue #164 (thanks regelga)
|
||||
|
||||
v1.4.1 (2017-10-04)
|
||||
===================
|
||||
* Show program versions in output.
|
||||
|
||||
v1.4.0 (2017-09-24)
|
||||
===================
|
||||
* Add version check of duplicity to handle deprecation of --include-globbing-filelist
|
||||
* Bugfixes
|
||||
|
||||
v1.3.0 (2016-10-23)
|
||||
===================
|
||||
* Fix GPG error when backing up the script if no specific keyring is set up.
|
||||
* Attempt to fix issue #145 by adding a `GPG_OPTIONS` parameter.
|
||||
* Add `-h` / `--help` option to print usage and don't send email or notification when printing usage only
|
||||
* Rename repository from 'duplicity-backup' to 'duplicity-backup.sh'.
|
||||
|
||||
v1.2 (2016-09-10)
|
||||
=================
|
||||
* Changed: big rework of logging handling. Now done through I/O-redirection of file descriptors 1 to 5.
|
||||
* Fix: Add case for s-nail when using mailx.
|
||||
* Fix: Always exclude /proc from Source Disk Use Information.
|
||||
* Fix issue #140: Add --no-show-photos to --gpg-options.
|
||||
* Fix "line 89: 4: Bad file descriptor" when printing usage without config set up.
|
||||
|
||||
v1.1 (2016-09-03)
|
||||
===================
|
||||
* Fix and improve handling of INCLIST and EXCLIST (issue #128)
|
||||
|
|
@ -11,7 +55,8 @@ v1.1 (2016-09-03)
|
|||
================================
|
||||
Versionning and keeping a changelog up to date has been neglected between 2013-01-14 and 2016-08-31.
|
||||
|
||||
There were no official 0.9.x release, but an automatically generated list of changes that affected `duplicity-backup.sh` or `duplicity-backup.conf.example` is available in the file `CHANGELOG_0.9.x.md`.
|
||||
There were no official 0.9.x release, but an automatically generated list of changes that affected
|
||||
`duplicity-backup.sh` or `duplicity-backup.conf.example` is available in the file `CHANGELOG_0.9.x.md`.
|
||||
|
||||
0.8.3 (02 January 2013)
|
||||
======================
|
||||
|
|
@ -33,8 +78,10 @@ There were no official 0.9.x release, but an automatically generated list of cha
|
|||
|
||||
0.8 (05 August 2012)
|
||||
===================
|
||||
* Improved argument parsing. Now the script is insensitive to the order of appearance of the options and handles correctly optional options parameters
|
||||
* Re-added possibility to specify the config file on the command line, which is now the recommended way to do (facilitating script updates)
|
||||
* Improved argument parsing. Now the script is insensitive to the order of appearance of the options and handles
|
||||
correctly optional options parameters
|
||||
* Re-added possibility to specify the config file on the command line, which is now the recommended way to do
|
||||
(facilitating script updates)
|
||||
* Added dry-run command line option (-n or --dry-run)
|
||||
* Added many short versions of long options (-b, -f, -v, -l, -s)
|
||||
* Fix "unary operator expected warning" in some rare cases
|
||||
|
|
@ -54,12 +101,14 @@ Inclusion of two patches written by [shamer] + modified config file management.
|
|||
|
||||
* Added option to use ssmtp to send mail [shamer]
|
||||
* Added lock file to prevent running multiple instances simultaneously [shamer]
|
||||
* Modified config file management (no more specified on the command line, must be specified as an parameter at the beginning of the script)
|
||||
* Modified config file management (no more specified on the command line, must be specified as an parameter at the
|
||||
beginning of the script)
|
||||
* Fixed bad check_variables() behaviour when not using Amazon S3 storage backend without commenting AWS API keys
|
||||
|
||||
0.6 Version Six (4 May 2012)
|
||||
============================
|
||||
This is a rework of the script to include some github patches that were brought to the original script in order to make the script more generic than only Amazon S3 oriented and fix a few issues.
|
||||
This is a rework of the script to include some github patches that were brought to the original script in order to make
|
||||
the script more generic than only Amazon S3 oriented and fix a few issues.
|
||||
|
||||
* Added ability not to encrypt the backup [orkaa]
|
||||
* Added ability to use backup destination locations other than Amazon S3 [orkaa]
|
||||
|
|
@ -100,15 +149,18 @@ Version Three (01/31/09)
|
|||
* Added comment to explain why folks need to use 's3+' and not 's3:' for Amazon buckets
|
||||
* Used "unset" to remove the variables at end of the script
|
||||
* Fixed a problem when the backup folder on S3 was nested inside another bucket
|
||||
* Changed the PASSPHRASE field to default to the actual passphrase, so one can easily backup the entire script and not have to worry about the passphrase.
|
||||
* Added --backup-this-script option which will turn the script and the secret key into an encrypted tarball that can be kept somewhere safe for easy restores if the machine goes down.
|
||||
* Changed the PASSPHRASE field to default to the actual passphrase, so one can easily backup the entire script and
|
||||
not have to worry about the passphrase.
|
||||
* Added --backup-this-script option which will turn the script and the secret key into an encrypted tarball that can
|
||||
be kept somewhere safe for easy restores if the machine goes down.
|
||||
* Cleaned up the get_file_size function so it wouldn't run when it wasn't supposed to.
|
||||
|
||||
Version Two (12/03/08)
|
||||
======================
|
||||
|
||||
* added GPL license
|
||||
* changed the cleanup feature to automatically force a full backup after (n) number of days as well as automatically cleanup after (n) number of days
|
||||
* changed the cleanup feature to automatically force a full backup after (n) number of days as well as automatically
|
||||
cleanup after (n) number of days
|
||||
* added option to force cleanup after (n) number of full backups (rather than by days)
|
||||
* option to changed log file ownership
|
||||
* runtime checks for installed required software and write permissions on log directory
|
||||
|
|
|
|||
57
README.md
57
README.md
|
|
@ -1,4 +1,4 @@
|
|||
[](https://travis-ci.org/zertrin/duplicity-backup)
|
||||
[](https://travis-ci.org/zertrin/duplicity-backup.sh)
|
||||
|
||||
# duplicity-backup.sh
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ This means the following:
|
|||
|
||||
## Contributing
|
||||
|
||||
The development version of the code is available at https://github.com/zertrin/duplicity-backup in the `dev` branch. It is a bleeding-edge version with the latests changes that have not yet been tested a lot, but that's the best starting point to contribute.
|
||||
The development version of the code is available at https://github.com/zertrin/duplicity-backup.sh in the `dev` branch. It is a bleeding-edge version with the latest changes that have not yet been tested a lot, but that's the best starting point to contribute.
|
||||
|
||||
Pull requests are welcome! However please **always use individual feature branches for each pull request**. I may not accept a pull request from a master or dev branch.
|
||||
|
||||
|
|
@ -39,12 +39,12 @@ Here is how to do it:
|
|||
|
||||
Fork the repository first and then clone your fork on your machine:
|
||||
|
||||
git clone git@github.com:YOURNAME/duplicity-backup.git
|
||||
git clone git@github.com:YOURNAME/duplicity-backup.sh.git duplicity-backup
|
||||
cd duplicity-backup
|
||||
|
||||
Add a remote for the upstream repository:
|
||||
|
||||
git remote add upstream git@github.com:zertrin/duplicity-backup.git
|
||||
git remote add upstream git@github.com:zertrin/duplicity-backup.sh.git
|
||||
git fetch upstream
|
||||
|
||||
Create a new topic branch for the changes you want to make, based on the `dev` branch from upstream:
|
||||
|
|
@ -57,7 +57,7 @@ Make your changes, test them, commit them and push them to Github:
|
|||
|
||||
Open a Pull request from `YOURNAME:my-fix-1` to `zertrin:dev`.
|
||||
|
||||
If you want to open another pull request for another change which is independant of the previous one, just create another topic branch based on master (`git checkout -b my-fix-2 upstream/dev`)
|
||||
If you want to open another pull request for another change which is independent of the previous one, just create another topic branch based on master (`git checkout -b my-fix-2 upstream/dev`)
|
||||
|
||||
|
||||
## Installation
|
||||
|
|
@ -66,22 +66,25 @@ If you want to open another pull request for another change which is independant
|
|||
|
||||
You can clone the repository (which makes it easy to get future updates):
|
||||
|
||||
git clone https://github.com/zertrin/duplicity-backup.git duplicity-backup
|
||||
git clone https://github.com/zertrin/duplicity-backup.sh.git duplicity-backup
|
||||
|
||||
If you prefer the stable version do:
|
||||
If you prefer the stable (but old) version do:
|
||||
|
||||
git checkout stable
|
||||
|
||||
... or if you want the latest version (might still have bugs), then:
|
||||
... or if you want the normal version, then:
|
||||
|
||||
git checkout master
|
||||
|
||||
... or if you like living on the edge, you can stay at the development version which is automatically cloned.
|
||||
... or if you like living on the edge (or need the latest bugfixes), you can stay at the development version which is automatically cloned.
|
||||
|
||||
Or just download the ZIP file:
|
||||
|
||||
* For the stable branch: https://github.com/zertrin/duplicity-backup/archive/stable.zip
|
||||
* For the normal branch: https://github.com/zertrin/duplicity-backup/archive/master.zip
|
||||
| Version | Download link |
|
||||
|---------------|-------------------------------------------------------------------|
|
||||
| stable (old) | https://github.com/zertrin/duplicity-backup.sh/archive/stable.zip |
|
||||
| normal | https://github.com/zertrin/duplicity-backup.sh/archive/master.zip |
|
||||
| latest | https://github.com/zertrin/duplicity-backup.sh/archive/dev.zip |
|
||||
|
||||
### 2. Configure the script
|
||||
|
||||
|
|
@ -94,7 +97,7 @@ The script looks for its configuration by reading the path to the config file sp
|
|||
If no config file was given on the command line, the script will try to find the file specified in the `CONFIG` parameter at the beginning of the script (default: `duplicity-backup.conf` in the script's directory).
|
||||
|
||||
So be sure to either:
|
||||
* specify the configuration file path on the command line with the -c option **[recommended]**
|
||||
* specify the configuration file path on the command line with the `-c` option **[recommended]**
|
||||
* or to edit the `CONFIG` parameter in the script to match the actual location of your config file. **[deprecated]** _(will be removed in future versions of the script)_
|
||||
|
||||
NOTE: to ease future updates of the script, you may prefer NOT to edit the script at all and to specify systematically the path to your config file on the command line with the `-c` or `--config` option.
|
||||
|
|
@ -120,13 +123,13 @@ else just download again the ZIP archive an extract it over the existing folder.
|
|||
|
||||
Then compare the example config file (`duplicity-backup.conf.example`) with your modified version (for example `/etc/duplicity-backup.conf`) and adapt your copy to reflect the changes in the example file.
|
||||
|
||||
Thare are many ways to do so, here are some examples (adapt the path to your actual files):
|
||||
There are many ways to do so, here are some examples (adapt the path to your actual files):
|
||||
|
||||
diff duplicity-backup.conf.example /etc/duplicity-backup.conf
|
||||
vimdiff duplicity-backup.conf.example /etc/duplicity-backup.conf
|
||||
|
||||
|
||||
## Dependancies
|
||||
## Dependencies
|
||||
|
||||
* [duplicity](http://duplicity.nongnu.org/)
|
||||
* Basic utilities like: [bash](https://www.gnu.org/software/bash/), [which](http://unixhelp.ed.ac.uk/CGI/man-cgi?which), [find](https://www.gnu.org/software/findutils/) and [tee](http://linux.die.net/man/1/tee) (should already be available on most Linux systems)
|
||||
|
|
@ -136,6 +139,9 @@ Thare are many ways to do so, here are some examples (adapt the path to your act
|
|||
For the [Amazon S3](https://aws.amazon.com/s3/) storage backend *`optional`*
|
||||
* [s3cmd](http://s3tools.org/s3cmd) *`optional`*
|
||||
|
||||
For the [Backblaze B2](https://www.backblaze.com/b2) storage backend *`optional`*
|
||||
* [python-b2](https://pypi.python.org/pypi/b2) *`optional`*
|
||||
|
||||
For the [Google Cloud Storage](https://cloud.google.com/storage/) storage backend *`optional`*
|
||||
* [boto](https://github.com/boto/boto) (may already have been installed with duplicity)
|
||||
* [gsutil](https://cloud.google.com/storage/docs/gsutil) *`optional`*
|
||||
|
|
@ -144,10 +150,10 @@ For the [Google Cloud Storage](https://cloud.google.com/storage/) storage backen
|
|||
## Usage
|
||||
|
||||
duplicity-backup.sh [options]
|
||||
|
||||
|
||||
Options:
|
||||
-c, --config CONFIG_FILE specify the config file to use
|
||||
|
||||
|
||||
-b, --backup runs an incremental backup
|
||||
-f, --full forces a full backup
|
||||
-v, --verify verifies the backup
|
||||
|
|
@ -157,21 +163,23 @@ For the [Google Cloud Storage](https://cloud.google.com/storage/) storage backen
|
|||
> ACTIONS > cleanup for details)
|
||||
-l, --list-current-files lists the files currently backed up in the archive
|
||||
-s, --collection-status show all the backup sets in the archive
|
||||
|
||||
|
||||
--restore [PATH] restores the entire backup to [path]
|
||||
--restore-file [FILE_TO_RESTORE] [DESTINATION]
|
||||
restore a specific file
|
||||
--restore-dir [DIR_TO_RESTORE] [DESTINATION]
|
||||
restore a specific directory
|
||||
|
||||
|
||||
-t, --time TIME specify the time from which to restore or list files
|
||||
(see duplicity man page for the format)
|
||||
|
||||
|
||||
--backup-script automatically backup the script and secret key(s) to
|
||||
the current working directory
|
||||
|
||||
|
||||
-n, --dry-run perform a trial run with no changes made
|
||||
-d, --debug echo duplicity commands to logfile
|
||||
|
||||
-V, --version print version information about this script and duplicity
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
|
@ -244,14 +252,19 @@ Note that the commands `--restore-file` and `--restore-dir` are equivalent.
|
|||
|
||||
## Known issues
|
||||
|
||||
### GPG error if system locale is not english
|
||||
|
||||
If your system's locale is not english, an error can happen when duplicity is trying to encrypt the files with gpg. This problem concerns duplicity and has been reported upstream ([see bug report](https://bugs.launchpad.net/duplicity/+bug/510625)). A simple workaround is to set the following environement variable: `LANG=C`. For example: `LANG=C duplicity-backup.sh [-c config_file] ...` or in the cron `41 3 * * * LANG=C /absolute/path/to/duplicity-backup.sh -c /etc/duplicity-backup.conf -b`
|
||||
|
||||
### "/dev/fd/62: Operation not supported" errors on FreeBSD
|
||||
|
||||
See [issue #143](https://github.com/zertrin/duplicity-backup.sh/issues/143) for a fix.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
This script attempts to simplify the task of running a duplicity command; if you are having any problems with the script the first step is to determine if the script is generating an incorrect command or if duplicity itself is causing your error.
|
||||
|
||||
To see exactly what is happening when you run duplicity-backup, either pass the option `-d` or `--debug` on the command line, or head to the bottom of the configuration file and uncomment the `ECHO=$(which echo)` variable.
|
||||
To see exactly what is happening when you run duplicity-backup.sh, either pass the option `-d` or `--debug` on the command line, or head to the bottom of the configuration file and uncomment the `ECHO=$(which echo)` variable.
|
||||
|
||||
This will stop the script from running and will, instead, output the generated command into your log file. You can then check to see if what is being generated is causing an error or if it is duplicity causing you woe.
|
||||
|
||||
|
|
@ -264,5 +277,5 @@ You can also try the `-n` or `--dry-run` option. This will make duplicity to cal
|
|||
* Show backup-ed files in today incremental backup email
|
||||
|
||||
|
||||
###### Thanks to all the [contributors](https://github.com/zertrin/duplicity-backup/graphs/contributors) for their help.
|
||||
###### Thanks to all the [contributors](https://github.com/zertrin/duplicity-backup.sh/graphs/contributors) for their help.
|
||||
|
||||
|
|
|
|||
1
VERSION
1
VERSION
|
|
@ -1 +0,0 @@
|
|||
v1.1
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# Copyright (c) 2008-2010 Damon Timm.
|
||||
# Copyright (c) 2010 Mario Santagiuliana.
|
||||
# Copyright (c) 2012-2015 Marc Gallet.
|
||||
# Copyright (c) 2012-2018 Marc Gallet.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
|
|
@ -23,10 +23,10 @@
|
|||
# http://damontimm.com/code/dt-s3-backup (for the original program by Damon Timm)
|
||||
#
|
||||
# Latest code available at:
|
||||
# http://github.com/zertrin/duplicity-backup
|
||||
# http://github.com/zertrin/duplicity-backup.sh
|
||||
#
|
||||
# List of contributors:
|
||||
# https://github.com/zertrin/duplicity-backup/graphs/contributors
|
||||
# https://github.com/zertrin/duplicity-backup.sh/graphs/contributors
|
||||
#
|
||||
# ---------------------------------------------------------------------------- #
|
||||
|
||||
|
|
@ -75,7 +75,7 @@
|
|||
# This can be / or somewhere else -- I use /home/ because all the
|
||||
# directories that I want to backup start with /home/.
|
||||
#
|
||||
ROOT="/home"
|
||||
ROOT='/home'
|
||||
|
||||
# Set hostname for this duplicity instance, useful for e-mail reports
|
||||
#
|
||||
|
|
@ -108,13 +108,14 @@ DEST="s3+http://foobar-backup-bucket/backup-folder/"
|
|||
#DEST="ftpes://user[:password]@other.host[:port]/some_dir"
|
||||
#DEST="rsync://user@host.com[:port]//absolute_path"
|
||||
#DEST="scp://user[:password]@other.host[:port]/[/]some_dir"
|
||||
#DEST="ssh://user[:password]@other.host[:port]/[/]some_dir"
|
||||
#DEST="sftp://user[:password]@other.host[:port]/[/]some_dir"
|
||||
#DEST="file:///home/foobar_user_name/new-backup-test/"
|
||||
#DEST="imap[s]://user[:password]@host.com[/from_address_prefix]"
|
||||
#DEST="webdav[s]://user[:password]@other.host[:port]/some_dir"
|
||||
#DEST="gdocs://foobar_google_account/some_dir"
|
||||
#DEST="swift://foobar_swift_container/some_dir"
|
||||
#DEST="dpbx:///foobar_swift_container/some_dir"
|
||||
#DEST="b2://some_account_id[:some_application_key]@some_bucket_name/some_dir"
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
@ -128,7 +129,7 @@ DEST="s3+http://foobar-backup-bucket/backup-folder/"
|
|||
# setting it in the backend url (which might be readable in the operating
|
||||
# systems process listing to other users on the same machine)."
|
||||
#
|
||||
#FTP_PASSWORD="password"
|
||||
#FTP_PASSWORD='password'
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
@ -173,6 +174,13 @@ DEST="s3+http://foobar-backup-bucket/backup-folder/"
|
|||
#SWIFT_AUTHURL="foobar_swift_authurl"
|
||||
#SWIFT_AUTHVERSION="2"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# DROPBOX INFORMATION
|
||||
# ------------------------------------------------------------------------------
|
||||
# Uncomment these lines if you're using Dropbox
|
||||
#
|
||||
#DPBX_ACCESS_TOKEN="foobar_dropbox_access_token"
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# INCLUDE LIST OF DIRECTORIES
|
||||
|
|
@ -182,15 +190,15 @@ DEST="s3+http://foobar-backup-bucket/backup-folder/"
|
|||
#
|
||||
# Here is an example with multiple locations:
|
||||
#
|
||||
#INCLIST=( "/home/*/Documents" \
|
||||
# "/home/*/Projects" \
|
||||
# "/home/*/logs" \
|
||||
# "/home/www/mysql-backups" \
|
||||
#INCLIST=( '/home/*/Documents' \
|
||||
# '/home/*/Projects' \
|
||||
# '/home/*/logs' \
|
||||
# '/home/www/mysql-backups' \
|
||||
# )
|
||||
#
|
||||
# Simpler example with one location:
|
||||
|
||||
INCLIST=( "/home/foobar_user_name/Documents/" )
|
||||
INCLIST=( '/home/foobar_user_name/Documents/' )
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
@ -202,18 +210,18 @@ INCLIST=( "/home/foobar_user_name/Documents/" )
|
|||
#
|
||||
# Here is an example with multiple locations:
|
||||
#
|
||||
#EXCLIST=( "/home/*/Trash" \
|
||||
# "/home/*/Projects/Completed" \
|
||||
# "/**.DS_Store" \
|
||||
# "/**Icon?" \
|
||||
# "/**.AppleDouble" \
|
||||
#EXCLIST=( '/home/*/Trash' \
|
||||
# '/home/*/Projects/Completed' \
|
||||
# '/**.DS_Store' \
|
||||
# '/**Icon?' \
|
||||
# '/**.AppleDouble' \
|
||||
# )
|
||||
#
|
||||
# If you don't want to exclude anything, use EXCLIST=()
|
||||
#
|
||||
# Simpler example with one location. Adapt it to your needs.
|
||||
|
||||
EXCLIST=( "/home/foobar_user_name/Documents/foobar-to-exclude" )
|
||||
EXCLIST=( '/home/foobar_user_name/Documents/foobar-to-exclude' )
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
@ -260,9 +268,9 @@ ENCRYPTION='yes'
|
|||
# (your backups will be encrypted with this password) or is used
|
||||
# for the "GPG_SIGN_KEY" (see below).
|
||||
# Comment out if you aren't using encryption
|
||||
# Note: if you have a '$' in your passphrase, escape it with a '\'
|
||||
# Note: if you have a ' in your passphrase, escape it accordingly.
|
||||
|
||||
PASSPHRASE="foobar_gpg_passphrase"
|
||||
PASSPHRASE='foobar_gpg_passphrase'
|
||||
|
||||
# Specify which GPG keys you would like to use (even if you have only one).
|
||||
# If you are running this from a cron, it is highly recommended to create separate
|
||||
|
|
@ -292,6 +300,14 @@ GPG_SIGN_KEY="foobar_gpg_key"
|
|||
#
|
||||
#SECRET_KEYRING="/home/foobar_user_name/.gnupg/duplicity.gpg
|
||||
|
||||
# Here you can specify options that will be passed to GPG.
|
||||
# If you can, avoid using quotes here, as it hasn't been tested much yet.
|
||||
# You shouldn't need to remove the following default (--no-show-photos)
|
||||
# For example an user reported (GitHub issue #145) that since gnupg v2.1,
|
||||
# the option "--pinentry-mode loopback" is necessary,
|
||||
# then set GPG_OPTIONS="--no-show-photos --pinentry-mode loopback"
|
||||
GPG_OPTIONS="--no-show-photos"
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# STATIC BACKUP OPTIONS
|
||||
|
|
@ -411,7 +427,7 @@ MAIL="mailx" # default command for Linux mail
|
|||
# Third-party notification services. If NOTIFICATION_SERVICE is not provided, no
|
||||
# notifications will be sent.
|
||||
|
||||
# Possible values for NOTIFICATION_SERVICE are: slack, pushover, ifttt
|
||||
# Possible values for NOTIFICATION_SERVICE are: slack, pushover, ifttt, telegram
|
||||
NOTIFICATION_SERVICE=""
|
||||
NOTIFICATION_FAILURE_ONLY="yes" # send notifications only if there was an error while creating backup
|
||||
|
||||
|
|
@ -431,6 +447,10 @@ IFTTT_MAKER_EVENT="duplicity" # name the event to trigger at IFTTT Maker Channel
|
|||
IFTTT_HOOK_URL="https://maker.ifttt.com/trigger/$IFTTT_MAKER_EVENT/with/key/$IFTTT_KEY" # ONLY change this if IFTTT changes it
|
||||
IFTTT_VALUE2="" # general purpose value to pass to your maker channel (optional)
|
||||
|
||||
# Provider: Telegram
|
||||
TELEGRAM_CHATID="" #Generate a Telegram bot following guide: https://core.telegram.org/bots#3-how-do-i-create-a-bot
|
||||
TELEGRAM_KEY=""
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# TROUBLESHOOTING
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# Copyright (c) 2008-2010 Damon Timm.
|
||||
# Copyright (c) 2010 Mario Santagiuliana.
|
||||
# Copyright (c) 2012 Marc Gallet.
|
||||
# Copyright (c) 2012-2018 Marc Gallet.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
|
|
@ -23,7 +23,10 @@
|
|||
# http://damontimm.com/code/dt-s3-backup (for the original program by Damon Timm)
|
||||
#
|
||||
# Latest code available at:
|
||||
# http://github.com/zertrin/duplicity-backup
|
||||
# http://github.com/zertrin/duplicity-backup.sh
|
||||
#
|
||||
# List of contributors:
|
||||
# https://github.com/zertrin/duplicity-backup.sh/graphs/contributors
|
||||
#
|
||||
# ---------------------------------------------------------------------------- #
|
||||
|
||||
|
|
@ -42,6 +45,14 @@ CONFIG="duplicity-backup.conf"
|
|||
# Script Happens Below This Line - Shouldn't Require Editing #
|
||||
##############################################################
|
||||
|
||||
DBSH_VERSION="v1.6.0"
|
||||
|
||||
# make a backup of stdout and stderr for later
|
||||
exec 6>&1
|
||||
exec 7>&2
|
||||
|
||||
# ------------------------------------------------------------
|
||||
|
||||
usage(){
|
||||
echo "USAGE:
|
||||
$(basename "$0") [options]
|
||||
|
|
@ -71,10 +82,14 @@ echo "USAGE:
|
|||
--backup-script automatically backup the script and secret key(s) to
|
||||
the current working directory
|
||||
|
||||
-q, --quiet silence most of output messages, except errors and output
|
||||
that are intended for interactive usage. Silenced output
|
||||
is still logged in the logfile.
|
||||
|
||||
-n, --dry-run perform a trial run with no changes made
|
||||
-d, --debug echo duplicity commands to logfile
|
||||
|
||||
-V, --version print version information about this script and duplicity
|
||||
-h, --help print this help and exit
|
||||
|
||||
CURRENT SCRIPT VARIABLES:
|
||||
========================
|
||||
|
|
@ -83,7 +98,8 @@ echo "USAGE:
|
|||
EXCLIST (directories excluded) = ${EXCLIST[*]:0}
|
||||
ROOT (root directory of backup) = ${ROOT}
|
||||
LOGFILE (log file path) = ${LOGFILE}
|
||||
"
|
||||
" >&6
|
||||
USAGE=1
|
||||
}
|
||||
|
||||
DUPLICITY="$(which duplicity)"
|
||||
|
|
@ -93,20 +109,39 @@ if [ ! -x "${DUPLICITY}" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
DUPLICITY_VERSION=$(${DUPLICITY} --version)
|
||||
DUPLICITY_VERSION=${DUPLICITY_VERSION//[^0-9\.]/}
|
||||
|
||||
version_compare() {
|
||||
if [[ $1 =~ ^([0-9]+\.?)+$ && $2 =~ ^([0-9]+\.?)+$ ]]; then
|
||||
local l=(${1//./ }) r=(${2//./ }) s=${#l[@]}; [[ ${#r[@]} -gt ${#l[@]} ]] && s=${#r[@]}
|
||||
|
||||
for i in $(seq 0 $((s - 1))); do
|
||||
[[ ${l[$i]} -gt ${r[$i]} ]] && return 1
|
||||
[[ ${l[$i]} -lt ${r[$i]} ]] && return 2
|
||||
done
|
||||
|
||||
return 0
|
||||
else
|
||||
echo "Invalid version number given"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# set a flag if duplicity's version is lower than 0.7, for usage later in the script
|
||||
version_compare "${DUPLICITY_VERSION}" 0.7
|
||||
case $? in 2) LT07=1;; *) LT07=0;; esac
|
||||
|
||||
version(){
|
||||
# Read the version string from the file VERSION
|
||||
VERSION=$(<VERSION)
|
||||
|
||||
echo "duplicity-backup.sh ${VERSION}"
|
||||
${DUPLICITY} --version
|
||||
echo "duplicity-backup.sh ${DBSH_VERSION}"
|
||||
echo "duplicity ${DUPLICITY_VERSION}"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Some expensive argument parsing that allows the script to
|
||||
# be insensitive to the order of appearance of the options
|
||||
# and to handle correctly option parameters that are optional
|
||||
while getopts ":c:t:bfvelsndV-:" opt; do
|
||||
while getopts ":c:t:bfvelsqndhV-:" opt; do
|
||||
case $opt in
|
||||
# parse long options (a bit tricky because builtin getopts does not
|
||||
# manage long options and I don't want to impose GNU getopt dependancy)
|
||||
|
|
@ -152,12 +187,19 @@ while getopts ":c:t:bfvelsndV-:" opt; do
|
|||
OPTIND=$(( OPTIND + 1 )) # we found it, move forward in arg parsing
|
||||
fi
|
||||
;;
|
||||
quiet)
|
||||
QUIET=1
|
||||
;;
|
||||
dry-run)
|
||||
DRY_RUN="--dry-run "
|
||||
DRY_RUN="--dry-run"
|
||||
;;
|
||||
debug)
|
||||
ECHO=$(which echo)
|
||||
;;
|
||||
help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
version)
|
||||
version
|
||||
;;
|
||||
|
|
@ -175,8 +217,13 @@ while getopts ":c:t:bfvelsndV-:" opt; do
|
|||
e) COMMAND="cleanup";;
|
||||
l) COMMAND="list-current-files";;
|
||||
s) COMMAND="collection-status";;
|
||||
n) DRY_RUN="--dry-run ";; # dry run
|
||||
q) QUIET=1;;
|
||||
n) DRY_RUN="--dry-run";; # dry run
|
||||
d) ECHO=$(which echo);; # debug
|
||||
h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
V) version;;
|
||||
:)
|
||||
echo "Option -${OPTARG} requires an argument." >&2
|
||||
|
|
@ -188,8 +235,11 @@ while getopts ":c:t:bfvelsndV-:" opt; do
|
|||
;;
|
||||
esac
|
||||
done
|
||||
#echo "Options parsed. COMMAND=${COMMAND}" # for debugging
|
||||
|
||||
|
||||
# ---------------- Read config file if specified -----------------
|
||||
|
||||
# Read config file if specified
|
||||
if [ ! -z "${CONFIG}" ] && [ -f "${CONFIG}" ];
|
||||
then
|
||||
# shellcheck source=duplicity-backup.conf.example
|
||||
|
|
@ -200,7 +250,105 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
STATIC_OPTIONS="${DRY_RUN}${STATIC_OPTIONS}"
|
||||
# ----------------------- Setup logging ---------------------------
|
||||
|
||||
# Setup logging as soon as possible, in order to be able to perform i/o redirection
|
||||
|
||||
[[ ${LOGDIR} = "/home/foobar_user_name/logs/test2/" ]] && config_sanity_fail "LOGDIR must be configured"
|
||||
|
||||
# Ensure a trailing slash always exists in the log directory name
|
||||
LOGDIR="${LOGDIR%/}/"
|
||||
|
||||
LOGFILE="${LOGDIR}${LOG_FILE}"
|
||||
|
||||
if [ ! -d "${LOGDIR}" ]; then
|
||||
echo "Attempting to create log directory ${LOGDIR} ..."
|
||||
if ! mkdir -p "${LOGDIR}"; then
|
||||
echo "Log directory ${LOGDIR} could not be created by this user: ${USER}" >&2
|
||||
echo "Aborting..." >&2
|
||||
exit 1
|
||||
else
|
||||
echo "Directory ${LOGDIR} successfully created."
|
||||
fi
|
||||
echo "Attempting to change owner:group of ${LOGDIR} to ${LOG_FILE_OWNER} ..."
|
||||
if ! chown "${LOG_FILE_OWNER}" "${LOGDIR}"; then
|
||||
echo "User ${USER} could not change the owner:group of ${LOGDIR} to ${LOG_FILE_OWNER}" >&2
|
||||
echo "Aborting..." >&2
|
||||
exit 1
|
||||
else
|
||||
echo "Directory ${LOGDIR} successfully changed to owner:group of ${LOG_FILE_OWNER}"
|
||||
fi
|
||||
elif [ ! -w "${LOGDIR}" ]; then
|
||||
echo "Log directory ${LOGDIR} is not writeable by this user: ${USER}" >&2
|
||||
echo "Aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# -------------------- Setup I/O redirections --------------------
|
||||
# Magic from
|
||||
# http://superuser.com/questions/86915/force-bash-script-to-use-tee-without-piping-from-the-command-line
|
||||
#
|
||||
# ##### Redirection matrix in the case when quiet mode is ON #####
|
||||
#
|
||||
# QUIET mode ON | shown on screen | not shown on screen
|
||||
# ---------------+-----------------+----------------------
|
||||
# logged | fd2, fd3 | fd1, fd5
|
||||
# not logged | fd4 | -
|
||||
#
|
||||
# ##### Redirection matrix in the case when quiet mode is OFF #####
|
||||
#
|
||||
# QUIET mode OFF | shown on screen | not shown on screen
|
||||
# ---------------+-----------------+----------------------
|
||||
# logged | fd1, fd2, fd3 | fd5
|
||||
# not logged | fd4 | -
|
||||
#
|
||||
# fd1 is stdout and is always logged but only shown if not QUIET
|
||||
# fd2 is stderr and is always shown on screen and logged
|
||||
# fd3 is like stdout but always shown on screen (for interactive prompts)
|
||||
# fd4 is always shown on screen but never logged (for the usage text)
|
||||
# fd5 is never shown on screen but always logged (for delimiters in the log)
|
||||
#
|
||||
|
||||
# fd2 and fd3 are always logged and shown on screen via tee
|
||||
# for fd2 (original stderr) the output of tee needs to be redirected to stderr
|
||||
exec 2> >(tee -ia "${LOGFILE}" >&2)
|
||||
# create fd3 as a redirection to stdout and the logfile via tee
|
||||
exec 3> >(tee -ia "${LOGFILE}")
|
||||
|
||||
# create fd4 as a copy of stdout, but that won't be redirected to tee
|
||||
# so that it is always shown and never logged
|
||||
exec 4>&1
|
||||
|
||||
# create fd5 as a direct redirection to the logfile
|
||||
# so that the content is never shown on screen but always logged
|
||||
exec 5>> "${LOGFILE}"
|
||||
|
||||
# finally we modify stdout (fd1) to always being logged (like fd3 and fd5)
|
||||
# but only being shown on screen if quiet mode is not active
|
||||
if [[ ${QUIET} == 1 ]]; then
|
||||
# Quiet mode: stdout not shown on screen but still logged via fd5
|
||||
exec 1>&5
|
||||
else
|
||||
# Normal mode: stdout shown on screen and logged via fd3
|
||||
exec 1>&3
|
||||
fi
|
||||
|
||||
# tests for debugging the magic
|
||||
#echo "redirected to fd1"
|
||||
#echo "redirected to fd2" >&2
|
||||
#echo "redirected to fd3" >&3
|
||||
#echo "redirected to fd4" >&4
|
||||
#echo "redirected to fd5" >&5
|
||||
|
||||
# ------------------------- Setting up variables ------------------------
|
||||
|
||||
if [ -n "${DRY_RUN}" ]; then
|
||||
STATIC_OPTIONS="${DRY_RUN} ${STATIC_OPTIONS}"
|
||||
fi
|
||||
|
||||
if [ -n "${STORAGECLASS}" ]; then
|
||||
STATIC_OPTIONS="${STATIC_OPTIONS} ${STORAGECLASS}"
|
||||
fi
|
||||
|
||||
SIGN_PASSPHRASE=${PASSPHRASE}
|
||||
|
||||
|
|
@ -212,6 +360,7 @@ export SWIFT_USERNAME
|
|||
export SWIFT_PASSWORD
|
||||
export SWIFT_AUTHURL
|
||||
export SWIFT_AUTHVERSION
|
||||
export DPBX_ACCESS_TOKEN
|
||||
export PASSPHRASE
|
||||
export SIGN_PASSPHRASE
|
||||
|
||||
|
|
@ -223,24 +372,20 @@ if [[ -n "${TMPDIR}" ]]; then
|
|||
export TMPDIR
|
||||
fi
|
||||
|
||||
# Ensure a trailing slash always exists in the log directory name
|
||||
LOGDIR="${LOGDIR%/}/"
|
||||
|
||||
LOGFILE="${LOGDIR}${LOG_FILE}"
|
||||
|
||||
# File to use as a lock. The lock is used to insure that only one instance of
|
||||
# the script is running at a time.
|
||||
LOCKFILE=${LOGDIR}backup.lock
|
||||
|
||||
if [ "${ENCRYPTION}" = "yes" ]; then
|
||||
ENCRYPT="--gpg-options \"${GPG_OPTIONS}\""
|
||||
if [ ! -z "${GPG_ENC_KEY}" ] && [ ! -z "${GPG_SIGN_KEY}" ]; then
|
||||
if [ "${HIDE_KEY_ID}" = "yes" ]; then
|
||||
ENCRYPT="--hidden-encrypt-key=${GPG_ENC_KEY}"
|
||||
ENCRYPT="${ENCRYPT} --hidden-encrypt-key=${GPG_ENC_KEY}"
|
||||
if [ "${COMMAND}" != "restore" ] && [ "${COMMAND}" != "restore-file" ] && [ "${COMMAND}" != "restore-dir" ]; then
|
||||
ENCRYPT="${ENCRYPT} --sign-key=${GPG_SIGN_KEY}"
|
||||
fi
|
||||
else
|
||||
ENCRYPT="--encrypt-key=${GPG_ENC_KEY} --sign-key=${GPG_SIGN_KEY}"
|
||||
ENCRYPT="${ENCRYPT} --encrypt-key=${GPG_ENC_KEY} --sign-key=${GPG_SIGN_KEY}"
|
||||
fi
|
||||
if [ ! -z "${SECRET_KEYRING}" ]; then
|
||||
KEYRING="--secret-keyring ${SECRET_KEYRING}"
|
||||
|
|
@ -265,6 +410,9 @@ NO_S3CMD_CFG="WARNING: s3cmd is not configured, run 's3cmd --configure' \
|
|||
in order to retrieve remote file size information. Remote file \
|
||||
size information unavailable."
|
||||
|
||||
NO_B2CMD="WARNING: b2 not found in PATH, remote file size information \
|
||||
unavailable. Is the python-b2 package installed?"
|
||||
|
||||
README_TXT="In case you've long forgotten, this is a backup script that you used to backup some files (most likely remotely at Amazon S3). In order to restore these files, you first need to import your GPG private(s) key(s) (if you haven't already). The key(s) is/are in this directory and the following command(s) should do the trick:\n\nIf you were using the same key for encryption and signature:\n gpg --allow-secret-key-import --import duplicity-backup-encryption-and-sign-secret.key.txt\nOr if you were using two separate keys for encryption and signature:\n gpg --allow-secret-key-import --import duplicity-backup-encryption-secret.key.txt\n gpg --allow-secret-key-import --import duplicity-backup-sign-secret.key.txt\n\nAfter your key(s) has/have been succesfully imported, you should be able to restore your files.\n\nGood luck!"
|
||||
|
||||
if [ "$(echo "${DEST}" | cut -c 1,2)" = "gs" ]; then
|
||||
|
|
@ -307,11 +455,28 @@ else
|
|||
DEST_IS_S3=false
|
||||
fi
|
||||
|
||||
if [ "$(echo "${DEST}" | cut -c 1,4)" = "dpbx" ]; then
|
||||
DEST_IS_DPBX=true
|
||||
else
|
||||
DEST_IS_DPBX=false
|
||||
fi
|
||||
|
||||
if [ "$(echo "${DEST}" | cut -c 1,2)" = "b2" ]; then
|
||||
DEST_IS_B2=true
|
||||
B2CMD="$(which b2)"
|
||||
if [ ! -x "${B2CMD}" ]; then
|
||||
echo "${NO_B2CMD}"; B2CMD_AVAIL=false
|
||||
fi
|
||||
else
|
||||
DEST_IS_B2=false
|
||||
fi
|
||||
|
||||
config_sanity_fail()
|
||||
{
|
||||
EXPLANATION=$1
|
||||
CONFIG_VAR_MSG="Oops!! ${0} was unable to run!\nWe are missing one or more important variables in the configuration file.\nCheck your configuration because it appears that something has not been set yet."
|
||||
echo -e "${CONFIG_VAR_MSG}\n ${EXPLANATION}."
|
||||
echo -e "${CONFIG_VAR_MSG}\n ${EXPLANATION}." >&2
|
||||
echo -e "--------------------- END ---------------------\n" >&5
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
|
@ -325,40 +490,15 @@ check_variables ()
|
|||
${GPG_SIGN_KEY} = "foobar_gpg_key" || \
|
||||
${PASSPHRASE} = "foobar_gpg_passphrase")) ]] && \
|
||||
config_sanity_fail "ENCRYPTION is set to 'yes', but GPG_ENC_KEY, GPG_SIGN_KEY, or PASSPHRASE have not been configured"
|
||||
[[ ${LOGDIR} = "/home/foobar_user_name/logs/test2/" ]] && config_sanity_fail "LOGDIR must be configured"
|
||||
[[ ( ${DEST_IS_S3} = true && (${AWS_ACCESS_KEY_ID} = "foobar_aws_key_id" || ${AWS_SECRET_ACCESS_KEY} = "foobar_aws_access_key" )) ]] && \
|
||||
config_sanity_fail "An s3 DEST has been specified, but AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY have not been configured"
|
||||
[[ ( ${DEST_IS_GS} = true && (${GS_ACCESS_KEY_ID} = "foobar_gcs_key_id" || ${GS_SECRET_ACCESS_KEY} = "foobar_gcs_secret_id" )) ]] && \
|
||||
config_sanity_fail "A Google Cloud Storage DEST has been specified, but GS_ACCESS_KEY_ID or GS_SECRET_ACCESS_KEY have not been configured"
|
||||
[[ ( ${DEST_IS_DPBX} = true && (${DPBX_ACCESS_TOKEN} = "foobar_dropbox_access_token" )) ]] && \
|
||||
config_sanity_fail "A Dropbox DEST has been specified, but DPBX_ACCESS_TOKEN has not been configured"
|
||||
[[ ! -z "${INCEXCFILE}" && ! -f ${INCEXCFILE} ]] && config_sanity_fail "The specified INCEXCFILE ${INCEXCFILE} does not exists"
|
||||
}
|
||||
|
||||
check_logdir()
|
||||
{
|
||||
if [ ! -d "${LOGDIR}" ]; then
|
||||
echo "Attempting to create log directory ${LOGDIR} ..."
|
||||
if ! mkdir -p "${LOGDIR}"; then
|
||||
echo "Log directory ${LOGDIR} could not be created by this user: ${USER}"
|
||||
echo "Aborting..."
|
||||
exit 1
|
||||
else
|
||||
echo "Directory ${LOGDIR} successfully created."
|
||||
fi
|
||||
echo "Attempting to change owner:group of ${LOGDIR} to ${LOG_FILE_OWNER} ..."
|
||||
if ! chown "${LOG_FILE_OWNER}" "${LOGDIR}"; then
|
||||
echo "User ${USER} could not change the owner:group of ${LOGDIR} to ${LOG_FILE_OWNER}"
|
||||
echo "Aborting..."
|
||||
exit 1
|
||||
else
|
||||
echo "Directory ${LOGDIR} successfully changed to owner:group of ${LOG_FILE_OWNER}"
|
||||
fi
|
||||
elif [ ! -w "${LOGDIR}" ]; then
|
||||
echo "Log directory ${LOGDIR} is not writeable by this user: ${USER}"
|
||||
echo "Aborting..."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
mailcmd_sendmail() {
|
||||
# based on http://linux.die.net/man/8/sendmail.sendmail
|
||||
echo -e "From: ${EMAIL_FROM}\nSubject: ${EMAIL_SUBJECT}\n" | cat - "${LOGFILE}" | ${MAILCMD} "${EMAIL_TO}"
|
||||
|
|
@ -396,9 +536,9 @@ email_logfile()
|
|||
MAILCMD_BASENAME=${MAILCMD_REALPATH##*/}
|
||||
|
||||
if [ ! -x "${MAILCMD}" ]; then
|
||||
echo -e "Email couldn't be sent. ${MAIL} not available." >> "${LOGFILE}"
|
||||
echo -e "Email couldn't be sent. ${MAIL} not available." >&2
|
||||
else
|
||||
EMAIL_SUBJECT=${EMAIL_SUBJECT:="duplicity-backup ${BACKUP_STATUS:-"ERROR"} [${HOSTNAME}] ${LOG_FILE}"}
|
||||
EMAIL_SUBJECT=${EMAIL_SUBJECT:="duplicity-backup ${BACKUP_STATUS:-"ERROR"} (${HOSTNAME}) ${LOG_FILE}"}
|
||||
case ${MAIL} in
|
||||
ssmtp)
|
||||
mailcmd_ssmtp;;
|
||||
|
|
@ -410,6 +550,8 @@ email_logfile()
|
|||
mailcmd_bsd_mailx;;
|
||||
heirloom-mailx)
|
||||
mailcmd_heirloom_mailx;;
|
||||
s-nail)
|
||||
mailcmd_nail;;
|
||||
*)
|
||||
mailcmd_else;;
|
||||
esac
|
||||
|
|
@ -422,43 +564,56 @@ email_logfile()
|
|||
mailcmd_else;;
|
||||
esac
|
||||
|
||||
echo -e "Email notification sent to ${EMAIL_TO} using ${MAIL}" >> "${LOGFILE}"
|
||||
echo -e "Email notification sent to ${EMAIL_TO} using ${MAIL}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
send_notification()
|
||||
{
|
||||
NOTIFICATION_CONTENT="duplicity-backup ${BACKUP_STATUS:-"ERROR"} [${HOSTNAME}] - \`${LOGFILE}\`"
|
||||
if [ ! -z "${NOTIFICATION_SERVICE}" ]; then
|
||||
echo "-----------[ Notification Request ]-----------"
|
||||
NOTIFICATION_CONTENT="duplicity-backup ${BACKUP_STATUS:-"ERROR"} [${HOSTNAME}] - \`${LOGFILE}\`"
|
||||
|
||||
if [ "${NOTIFICATION_SERVICE}" = "slack" ]; then
|
||||
curl -X POST -H 'Content-type: application/json' --data "{\"text\": \"${NOTIFICATION_CONTENT}\", \"channel\": \"${SLACK_CHANNEL}\", \"username\": \"${SLACK_USERNAME}\", \"icon_emoji\": \":${SLACK_EMOJI}:\"}" "${SLACK_HOOK_URL}"
|
||||
echo -e "Slack notification sent to channel ${SLACK_CHANNEL}" >> "${LOGFILE}"
|
||||
elif [ "${NOTIFICATION_SERVICE}" = "ifttt" ]; then
|
||||
curl -X POST -H 'Content-type: application/json' --data "{\"value1\": \"${NOTIFICATION_CONTENT}\", \"value2\": \"${IFTTT_VALUE2}\"}" "${IFTTT_HOOK_URL}"
|
||||
echo -e "IFTTT notification sent to Maker channel event ${IFTTT_EVENT}" >> "${LOGFILE}"
|
||||
elif [ "${NOTIFICATION_SERVICE}" = "pushover" ]; then
|
||||
curl -s \
|
||||
-F "token=${PUSHOVER_TOKEN}" \
|
||||
-F "user=${PUSHOVER_USER}" \
|
||||
-F "message=${NOTIFICATION_CONTENT}" \
|
||||
https://api.pushover.net/1/messages
|
||||
echo -e "Pushover notification sent" >> "${LOGFILE}"
|
||||
elif [ "${NOTIFICATION_SERVICE}" = "telegram" ]; then
|
||||
curl -s --max-time 10 -d "chat_id=${TELEGRAM_CHATID}&disable_web_page_preview=1&text=${NOTIFICATION_CONTENT}" "https://api.telegram.org/bot${TELEGRAM_KEY}/sendMessage" >/dev/null
|
||||
fi
|
||||
|
||||
echo -e "\n----------------------------------------------\n"
|
||||
|
||||
if [ "${NOTIFICATION_SERVICE}" = "slack" ]; then
|
||||
echo -e "Slack notification sent to channel ${SLACK_CHANNEL}"
|
||||
elif [ "${NOTIFICATION_SERVICE}" = "ifttt" ]; then
|
||||
echo -e "IFTTT notification sent to Maker channel event ${IFTTT_EVENT}"
|
||||
elif [ "${NOTIFICATION_SERVICE}" = "pushover" ]; then
|
||||
echo -e "Pushover notification sent"
|
||||
elif [ "${NOTIFICATION_SERVICE}" = "telegram" ]; then
|
||||
echo -e "Telegram notification sent"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
get_lock()
|
||||
{
|
||||
echo "Attempting to acquire lock ${LOCKFILE}" >> "${LOGFILE}"
|
||||
echo "Attempting to acquire lock ${LOCKFILE}" >&5
|
||||
if ( set -o noclobber; echo "$$" > "${LOCKFILE}" ) 2> /dev/null; then
|
||||
# The lock succeeded. Create a signal handler to remove the lock file when the process terminates.
|
||||
trap 'EXITCODE=$?; echo "Removing lock. Exit code: ${EXITCODE}" >>${LOGFILE}; rm -f "${LOCKFILE}"' 0
|
||||
echo "successfully acquired lock." >> "${LOGFILE}"
|
||||
trap 'EXITCODE=$?; echo "Removing lock. Exit code: ${EXITCODE}" >> ${LOGFILE}; rm -f "${LOCKFILE}"' EXIT
|
||||
echo "successfully acquired lock." >&5
|
||||
else
|
||||
# Write lock acquisition errors to log file and stderr
|
||||
echo "lock failed, could not acquire ${LOCKFILE}" | tee -a "${LOGFILE}" >&2
|
||||
echo "lock held by $(cat "${LOCKFILE}")" | tee -a "${LOGFILE}" >&2
|
||||
echo "lock failed, could not acquire ${LOCKFILE}" >&2
|
||||
echo "lock held by $(cat "${LOCKFILE}")" >&2
|
||||
email_logfile
|
||||
send_notification
|
||||
exit 2
|
||||
|
|
@ -467,7 +622,9 @@ get_lock()
|
|||
|
||||
get_source_file_size()
|
||||
{
|
||||
echo "-----------[ Source Disk Use Information ]-----------" >> "${LOGFILE}"
|
||||
echo "-----------[ Source Disk Use Information ]-----------"
|
||||
|
||||
# FIXME: doesn't work properly with include/exclude-filelists (issue #101)
|
||||
|
||||
# Patches to support spaces in paths-
|
||||
# Remove space as a field separator temporarily
|
||||
|
|
@ -479,7 +636,7 @@ get_source_file_size()
|
|||
DUEXCFLAG="-I -"
|
||||
;;
|
||||
OpenBSD)
|
||||
echo "WARNING: OpenBSD du does not support exclusion, sizes may be off" >> "${LOGFILE}"
|
||||
echo "WARNING: OpenBSD du does not support exclusion, sizes may be off"
|
||||
DUEXCFLAG=""
|
||||
;;
|
||||
*)
|
||||
|
|
@ -487,6 +644,9 @@ get_source_file_size()
|
|||
;;
|
||||
esac
|
||||
|
||||
# always exclude /proc
|
||||
DUEXCLIST="/proc\n"
|
||||
|
||||
for exclude in "${EXCLIST[@]}"; do
|
||||
DUEXCLIST="${DUEXCLIST}${exclude}\n"
|
||||
done
|
||||
|
|
@ -501,11 +661,10 @@ get_source_file_size()
|
|||
for include in "${DUINCLIST[@]}"; do
|
||||
echo -e "${DUEXCLIST}" | \
|
||||
du -hs ${DUEXCFLAG} "${include}" | \
|
||||
awk '{ FS="\t"; $0=$0; print $1"\t"$2 }' \
|
||||
>> "${LOGFILE}"
|
||||
awk '{ FS="\t"; $0=$0; print $1"\t"$2 }'
|
||||
done
|
||||
|
||||
echo >> "${LOGFILE}"
|
||||
echo
|
||||
|
||||
# Restore IFS
|
||||
IFS=$OLDIFS
|
||||
|
|
@ -513,7 +672,7 @@ get_source_file_size()
|
|||
|
||||
get_remote_file_size()
|
||||
{
|
||||
echo "---------[ Destination Disk Use Information ]--------" >> "${LOGFILE}"
|
||||
echo "---------[ Destination Disk Use Information ]--------"
|
||||
FRIENDLY_TYPE_NAME=""
|
||||
dest_type=$(echo "${DEST}" | cut -c 1,2)
|
||||
case $dest_type in
|
||||
|
|
@ -524,12 +683,12 @@ get_remote_file_size()
|
|||
TMPDEST="${DEST%/${TMPDEST}}"
|
||||
ssh_opt=$(echo "${STATIC_OPTIONS}" |awk -vo="--ssh-options=" '{s=index($0,o); if (s) {s=substr($0,s+length(o)); m=substr(s,0,1); for (i=2; i < length(s); i++) { if (substr(s,i,1) == m && substr(s,i-1,1) != "\\\\") break; } print substr(s,2,i-2)}}')
|
||||
|
||||
SIZE=$(${TMPDEST%://*} "${ssh_opt}" "${TMPDEST#*//}" du -hs "${DEST#${TMPDEST}/}" | awk '{print $1}') 2>> "${LOGFILE}"
|
||||
EMAIL_SUBJECT="${EMAIL_SUBJECT} ${SIZE} $(${TMPDEST%://*} "${ssh_opt}" "${TMPDEST#*//}" df -hP "${DEST#${TMPDEST}/}" | awk '{tmp=$5 " used"}END{print tmp}')" 2>> "${LOGFILE}"
|
||||
SIZE=$(${TMPDEST%://*} "${ssh_opt}" "${TMPDEST#*//}" du -hs "${DEST#${TMPDEST}/}" | awk '{print $1}')
|
||||
EMAIL_SUBJECT="${EMAIL_SUBJECT} ${SIZE} $(${TMPDEST%://*} "${ssh_opt}" "${TMPDEST#*//}" df -hP "${DEST#${TMPDEST}/}" | awk '{tmp=$5 " used"}END{print tmp}')"
|
||||
;;
|
||||
"fi")
|
||||
FRIENDLY_TYPE_NAME="File"
|
||||
TMPDEST=$(echo "${DEST}" | cut -c 6-)
|
||||
TMPDEST="${DEST#file://*}"
|
||||
SIZE=$(du -hs "${TMPDEST}" | awk '{print $1}')
|
||||
;;
|
||||
"gs")
|
||||
|
|
@ -543,7 +702,7 @@ get_remote_file_size()
|
|||
"s3")
|
||||
FRIENDLY_TYPE_NAME="Amazon S3"
|
||||
if ${S3CMD_AVAIL} ; then
|
||||
TMPDEST=$(echo "${DEST}" | cut -c 11-)
|
||||
TMPDEST=$(echo "${DEST}" | cut -f 3- -d /)
|
||||
dest_scheme=$(echo "${DEST}" | cut -f -1 -d :)
|
||||
if [ "$dest_scheme" = "s3" ]; then
|
||||
# Strip off the host name, too.
|
||||
|
|
@ -558,6 +717,33 @@ get_remote_file_size()
|
|||
fi
|
||||
fi
|
||||
;;
|
||||
"b2")
|
||||
FRIENDLY_TYPE_NAME="Backblaze B2"
|
||||
if ${B2CMD_AVAIL}; then
|
||||
if [[ -n ${FTP_PASSWORD} ]]; then
|
||||
APP_KEY=${FTP_PASSWORD}
|
||||
else
|
||||
APP_KEY=$(echo "${DEST}" | cut -d":" -f 3 | cut -d"@" -f 1)
|
||||
fi
|
||||
ACC_ID=$(echo "${DEST}" | cut -d"/" -f 3 | cut -d"@" -f 1 | cut -d ":" -f 1)
|
||||
BUCKET=$(echo "${DEST}" | cut -d"@" -f2 | cut -d"/" -f1)
|
||||
if [[ -z ${APP_KEY} ]] || [[ -z ${ACC_ID} ]]; then
|
||||
SIZE="-b2 authentication wrong-"
|
||||
return
|
||||
fi
|
||||
if [[ -z ${BUCKET} ]]; then
|
||||
SIZE="-b2 bucket wrong-"
|
||||
return
|
||||
fi
|
||||
if [[ $(${B2CMD} authorize-account "${ACC_ID}" "${APP_KEY}" >/dev/null 2>&1) -ne 0 ]]; then
|
||||
SIZE="-b2 authentication wrong-"
|
||||
return
|
||||
fi
|
||||
SIZE=$(${B2CMD} ls --long "${BUCKET}" | awk '{ print $5 }' | paste -sd+ | bc | numfmt --to=iec)
|
||||
else
|
||||
SIZE="-b2 not found in PATH-"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# not yet available for the other backends
|
||||
FRIENDLY_TYPE_NAME=""
|
||||
|
|
@ -565,12 +751,12 @@ get_remote_file_size()
|
|||
esac
|
||||
|
||||
if [[ ${FRIENDLY_TYPE_NAME} ]] ; then
|
||||
echo -e "${SIZE}\t${FRIENDLY_TYPE_NAME} type backend" >> "${LOGFILE}"
|
||||
echo -e "${SIZE}\t${FRIENDLY_TYPE_NAME} type backend"
|
||||
else
|
||||
echo "Destination disk use information is currently only available for the following storage backends:" >> "${LOGFILE}"
|
||||
echo "File, SSH, Amazon S3 and Google Cloud" >> "${LOGFILE}"
|
||||
echo "Destination disk use information is currently only available for the following storage backends:"
|
||||
echo "File, SSH, Amazon S3, Google Cloud and Backblaze B2"
|
||||
fi
|
||||
echo >> "${LOGFILE}"
|
||||
echo
|
||||
}
|
||||
|
||||
include_exclude()
|
||||
|
|
@ -604,7 +790,11 @@ include_exclude()
|
|||
|
||||
# Include/Exclude globbing filelist
|
||||
if [ "${INCEXCFILE}" != '' ]; then
|
||||
TMP=" --include-globbing-filelist '${INCEXCFILE}'"
|
||||
if [ ${LT07} -eq 1 ]; then
|
||||
TMP=" --include-globbing-filelist '${INCEXCFILE}'"
|
||||
else
|
||||
TMP=" --include-filelist '${INCEXCFILE}'"
|
||||
fi
|
||||
INCLUDE=${INCLUDE}${TMP}
|
||||
fi
|
||||
|
||||
|
|
@ -622,27 +812,27 @@ include_exclude()
|
|||
|
||||
duplicity_cleanup()
|
||||
{
|
||||
echo "----------------[ Duplicity Cleanup ]----------------" >> "${LOGFILE}"
|
||||
echo "----------------[ Duplicity Cleanup ]----------------"
|
||||
if [[ "${CLEAN_UP_TYPE}" != "none" && ! -z ${CLEAN_UP_TYPE} && ! -z ${CLEAN_UP_VARIABLE} ]]; then
|
||||
{
|
||||
eval "${ECHO}" "${DUPLICITY}" "${CLEAN_UP_TYPE}" "${CLEAN_UP_VARIABLE}" "${STATIC_OPTIONS}" --force \
|
||||
"${ENCRYPT}" \
|
||||
"${DEST}" >> "${LOGFILE}"
|
||||
"${DEST}"
|
||||
} || {
|
||||
BACKUP_ERROR=1
|
||||
}
|
||||
echo >> "${LOGFILE}"
|
||||
echo
|
||||
fi
|
||||
if [ ! -z "${REMOVE_INCREMENTALS_OLDER_THAN}" ] && [[ ${REMOVE_INCREMENTALS_OLDER_THAN} =~ ^[0-9]+$ ]]; then
|
||||
{
|
||||
eval "${ECHO}" "${DUPLICITY}" remove-all-inc-of-but-n-full "${REMOVE_INCREMENTALS_OLDER_THAN}" \
|
||||
"${STATIC_OPTIONS}" --force \
|
||||
"${ENCRYPT}" \
|
||||
"${DEST}" >> "${LOGFILE}"
|
||||
"${DEST}"
|
||||
} || {
|
||||
BACKUP_ERROR=1
|
||||
}
|
||||
echo >> "${LOGFILE}"
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -650,13 +840,11 @@ duplicity_backup()
|
|||
{
|
||||
{
|
||||
eval "${ECHO}" "${DUPLICITY}" "${OPTION}" "${VERBOSITY}" "${STATIC_OPTIONS}" \
|
||||
"${STORAGECLASS}" \
|
||||
"${ENCRYPT}" \
|
||||
"${EXCLUDE}" \
|
||||
"${INCLUDE}" \
|
||||
"${EXCLUDEROOT}" \
|
||||
"${ROOT}" "${DEST}" \
|
||||
>> "${LOGFILE}"
|
||||
"${ROOT}" "${DEST}"
|
||||
} || {
|
||||
BACKUP_ERROR=1
|
||||
}
|
||||
|
|
@ -666,8 +854,8 @@ duplicity_cleanup_failed()
|
|||
{
|
||||
{
|
||||
eval "${ECHO}" "${DUPLICITY}" "${OPTION}" "${VERBOSITY}" "${STATIC_OPTIONS}" \
|
||||
"${DEST}" \
|
||||
>> "${LOGFILE}"
|
||||
"${ENCRYPT}" \
|
||||
"${DEST}"
|
||||
} || {
|
||||
BACKUP_ERROR=1
|
||||
}
|
||||
|
|
@ -676,9 +864,9 @@ duplicity_cleanup_failed()
|
|||
setup_passphrase()
|
||||
{
|
||||
if [ ! -z "${GPG_ENC_KEY}" ] && [ ! -z "${GPG_SIGN_KEY}" ] && [ "${GPG_ENC_KEY}" != "${GPG_SIGN_KEY}" ]; then
|
||||
echo -n "Please provide the passphrase for decryption (GPG key 0x${GPG_ENC_KEY}): "
|
||||
echo -n "Please provide the passphrase for decryption (GPG key 0x${GPG_ENC_KEY}): " >&3
|
||||
builtin read -s -r ENCPASSPHRASE
|
||||
echo -ne "\n"
|
||||
echo -ne "\n" >&3
|
||||
PASSPHRASE=${ENCPASSPHRASE}
|
||||
export PASSPHRASE
|
||||
fi
|
||||
|
|
@ -688,24 +876,6 @@ get_file_sizes()
|
|||
{
|
||||
get_source_file_size
|
||||
get_remote_file_size
|
||||
|
||||
case $(uname) in
|
||||
FreeBSD|Darwin|DragonFly)
|
||||
sed -i '' -e '/^--*$/d' "${LOGFILE}"
|
||||
;;
|
||||
OpenBSD)
|
||||
ed -s "${LOGFILE}" <<-"EOF"
|
||||
g/^--*$/d
|
||||
w
|
||||
q
|
||||
EOF
|
||||
;;
|
||||
*)
|
||||
sed -i -e '/^--*$/d' "${LOGFILE}"
|
||||
;;
|
||||
esac
|
||||
|
||||
[[ -n "${LOG_FILE_OWNER}" ]] && chown "${LOG_FILE_OWNER}" "${LOGFILE}"
|
||||
}
|
||||
|
||||
backup_this_script()
|
||||
|
|
@ -720,35 +890,36 @@ backup_this_script()
|
|||
TMPFILENAME=${TMPDIR}.tar.gpg
|
||||
README=${TMPDIR}/README
|
||||
|
||||
echo "You are backing up: "
|
||||
echo " 1. ${SCRIPTPATH}"
|
||||
echo "You are backing up: " >&3
|
||||
echo " 1. ${SCRIPTPATH}" >&3
|
||||
|
||||
if [ ! -z "${GPG_ENC_KEY}" ] && [ ! -z "${GPG_SIGN_KEY}" ]; then
|
||||
if [ "${GPG_ENC_KEY}" = "${GPG_SIGN_KEY}" ]; then
|
||||
echo " 2. GPG Secret encryption and sign key: ${GPG_ENC_KEY}"
|
||||
echo " 2. GPG Secret encryption and sign key: ${GPG_ENC_KEY}" >&3
|
||||
else
|
||||
echo " 2. GPG Secret encryption key: ${GPG_ENC_KEY} and GPG secret sign key: ${GPG_SIGN_KEY}"
|
||||
echo " 2. GPG Secret encryption key: ${GPG_ENC_KEY} and GPG secret sign key: ${GPG_SIGN_KEY}" >&3
|
||||
fi
|
||||
else
|
||||
echo " 2. GPG Secret encryption and sign key: none (symmetric encryption)"
|
||||
echo " 2. GPG Secret encryption and sign key: none (symmetric encryption)" >&3
|
||||
fi
|
||||
|
||||
if [ ! -z "${CONFIG}" ] && [ -f "${CONFIG}" ];
|
||||
then
|
||||
echo " 3. Config file: ${CONFIG}"
|
||||
echo " 3. Config file: ${CONFIG}" >&3
|
||||
fi
|
||||
|
||||
if [ ! -z "${INCEXCFILE}" ] && [ -f "${INCEXCFILE}" ];
|
||||
then
|
||||
echo " 4. Include/Exclude globbing file: ${INCEXCFILE}"
|
||||
echo " 4. Include/Exclude globbing file: ${INCEXCFILE}" >&3
|
||||
fi
|
||||
|
||||
echo "Backup tarball will be encrypted and saved to: $(pwd)/${TMPFILENAME}"
|
||||
echo
|
||||
echo ">> Are you sure you want to do that ('yes' to continue)?"
|
||||
echo "Backup tarball will be encrypted and saved to: $(pwd)/${TMPFILENAME}" >&3
|
||||
echo >&3
|
||||
echo ">> Are you sure you want to do that ('yes' to continue)?" >&3
|
||||
read -r ANSWER
|
||||
if [ "${ANSWER}" != "yes" ]; then
|
||||
echo "You said << ${ANSWER} >> so I am exiting now."
|
||||
echo "You said << ${ANSWER} >> so I am exiting now." >&3
|
||||
echo -e "--------------------- END ---------------------\n" >&5
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -769,27 +940,38 @@ backup_this_script()
|
|||
GPG_TTY=$(tty)
|
||||
export GPG_TTY
|
||||
if [ "${GPG_ENC_KEY}" = "${GPG_SIGN_KEY}" ]; then
|
||||
gpg -a --export-secret-keys "${KEYRING}" "${GPG_ENC_KEY}" > "${TMPDIR}"/duplicity-backup-encryption-and-sign-secret.key.txt
|
||||
# shellcheck disable=SC2086
|
||||
gpg -a --export-secret-keys ${KEYRING} ${GPG_ENC_KEY} > "${TMPDIR}"/duplicity-backup-encryption-and-sign-secret.key.txt
|
||||
else
|
||||
gpg -a --export-secret-keys "${KEYRING}" "${GPG_ENC_KEY}" > "${TMPDIR}"/duplicity-backup-encryption-secret.key.txt
|
||||
gpg -a --export-secret-keys "${KEYRING}" "${GPG_SIGN_KEY}" > "${TMPDIR}"/duplicity-backup-sign-secret.key.txt
|
||||
# shellcheck disable=SC2086
|
||||
gpg -a --export-secret-keys ${KEYRING} ${GPG_ENC_KEY} > "${TMPDIR}"/duplicity-backup-encryption-secret.key.txt
|
||||
# shellcheck disable=SC2086
|
||||
gpg -a --export-secret-keys ${KEYRING} ${GPG_SIGN_KEY} > "${TMPDIR}"/duplicity-backup-sign-secret.key.txt
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${README_TXT}" > "${README}"
|
||||
echo "Encrypting tarball, choose a password you'll remember..."
|
||||
echo "Encrypting tarball, choose a password you'll remember..." >&3
|
||||
tar -cf - "${TMPDIR}" | gpg -aco "${TMPFILENAME}"
|
||||
rm -Rf "${TMPDIR}"
|
||||
echo -e "\nIMPORTANT!!"
|
||||
echo ">> To restore these files, run the following (remember your password):"
|
||||
echo "gpg -d ${TMPFILENAME} | tar -xf -"
|
||||
echo -e "\nYou may want to write the above down and save it with the file."
|
||||
echo -e "\nIMPORTANT!!" >&3
|
||||
echo ">> To restore these files, run the following (remember your password):" >&3
|
||||
echo "gpg -d ${TMPFILENAME} | tar -xf -" >&3
|
||||
echo -e "\nYou may want to write the above down and save it with the file." >&3
|
||||
}
|
||||
|
||||
check_variables
|
||||
check_logdir
|
||||
# ##################################################
|
||||
# #### end of functions definition ####
|
||||
# ##################################################
|
||||
|
||||
echo -e "-------- START DUPLICITY-BACKUP SCRIPT for ${HOSTNAME} --------\n" >> "${LOGFILE}"
|
||||
check_variables
|
||||
|
||||
echo -e "-------- START DUPLICITY-BACKUP SCRIPT for ${HOSTNAME} --------\n" >&5
|
||||
|
||||
echo -e "-------[ Program versions ]-------"
|
||||
echo -e "duplicity-backup.sh ${DBSH_VERSION}"
|
||||
echo -e "duplicity ${DUPLICITY_VERSION}"
|
||||
echo -e "----------------------------------\n"
|
||||
|
||||
get_lock
|
||||
|
||||
|
|
@ -800,7 +982,7 @@ EXCLUDEROOT=
|
|||
case "${COMMAND}" in
|
||||
"backup-script")
|
||||
backup_this_script
|
||||
exit
|
||||
exit 0
|
||||
;;
|
||||
|
||||
"full")
|
||||
|
|
@ -817,11 +999,12 @@ case "${COMMAND}" in
|
|||
DEST=${OLDROOT}
|
||||
OPTION="verify"
|
||||
|
||||
echo -e "-------[ Verifying Source & Destination ]-------\n" >> "${LOGFILE}"
|
||||
echo -e "-------[ Verifying Source & Destination ]-------\n"
|
||||
include_exclude
|
||||
setup_passphrase
|
||||
echo -e "Attempting to verify now ..."
|
||||
echo -e "Attempting to verify now ...\n" >&3
|
||||
duplicity_backup
|
||||
echo
|
||||
|
||||
OLDROOT=${ROOT}
|
||||
ROOT=${DEST}
|
||||
|
|
@ -829,21 +1012,21 @@ case "${COMMAND}" in
|
|||
|
||||
get_file_sizes
|
||||
|
||||
echo -e "Verify complete. Check the log file for results:\n>> ${LOGFILE}"
|
||||
echo -e "Verify complete.\n" >&3
|
||||
;;
|
||||
|
||||
"cleanup")
|
||||
OPTION="cleanup"
|
||||
|
||||
if [ -z "${DRY_RUN}" ]; then
|
||||
STATIC_OPTIONS="--force"
|
||||
STATIC_OPTIONS="${STATIC_OPTIONS} --force"
|
||||
fi
|
||||
|
||||
echo -e "-------[ Cleaning up Destination ]-------\n" >> "${LOGFILE}"
|
||||
echo -e "-------[ Cleaning up Destination ]-------\n"
|
||||
setup_passphrase
|
||||
duplicity_cleanup_failed
|
||||
|
||||
echo -e "Cleanup complete." >> "${LOGFILE}"
|
||||
echo -e "Cleanup complete."
|
||||
;;
|
||||
|
||||
"restore")
|
||||
|
|
@ -854,15 +1037,16 @@ case "${COMMAND}" in
|
|||
fi
|
||||
|
||||
if [[ ! "${RESTORE_DEST}" ]]; then
|
||||
echo "Please provide a destination path (eg, /home/user/dir):"
|
||||
echo "Please provide a destination path (eg, /home/user/dir):" >&3
|
||||
read -r -e NEWDESTINATION
|
||||
DEST=${NEWDESTINATION}
|
||||
echo ">> You will restore from ${ROOT} to ${DEST}"
|
||||
echo "Are you sure you want to do that ('yes' to continue)?"
|
||||
echo ">> You will restore from ${ROOT} to ${DEST}" >&3
|
||||
echo "Are you sure you want to do that ('yes' to continue)?" >&3
|
||||
read -r ANSWER
|
||||
if [[ "${ANSWER}" != "yes" ]]; then
|
||||
echo "You said << ${ANSWER} >> so I am exiting now."
|
||||
echo -e "User aborted restore process ...\n" >> "${LOGFILE}"
|
||||
echo "You said << ${ANSWER} >> so I am exiting now." >&3
|
||||
echo -e "User aborted restore process ...\n" >&2
|
||||
echo -e "--------------------- END ---------------------\n" >&5
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
|
|
@ -870,7 +1054,7 @@ case "${COMMAND}" in
|
|||
fi
|
||||
|
||||
setup_passphrase
|
||||
echo "Attempting to restore now ..."
|
||||
echo "Attempting to restore now ..." >&3
|
||||
duplicity_backup
|
||||
;;
|
||||
|
||||
|
|
@ -883,8 +1067,8 @@ case "${COMMAND}" in
|
|||
fi
|
||||
|
||||
if [[ ! "${FILE_TO_RESTORE}" ]]; then
|
||||
echo "Which file or directory do you want to restore?"
|
||||
echo "(give the path relative to the root of the backup eg, mail/letter.txt):"
|
||||
echo "Which file or directory do you want to restore?" >&3
|
||||
echo "(give the path relative to the root of the backup eg, mail/letter.txt):" >&3
|
||||
read -r -e FILE_TO_RESTORE
|
||||
echo
|
||||
fi
|
||||
|
|
@ -895,14 +1079,15 @@ case "${COMMAND}" in
|
|||
DEST=$(basename "${FILE_TO_RESTORE}")
|
||||
fi
|
||||
|
||||
echo -e "YOU ARE ABOUT TO..."
|
||||
echo -e ">> RESTORE: ${FILE_TO_RESTORE}"
|
||||
echo -e ">> TO: ${DEST}"
|
||||
echo -e "\nAre you sure you want to do that ('yes' to continue)?"
|
||||
echo -e "YOU ARE ABOUT TO..." >&3
|
||||
echo -e ">> RESTORE: ${FILE_TO_RESTORE}" >&3
|
||||
echo -e ">> TO: ${DEST}" >&3
|
||||
echo -e "\nAre you sure you want to do that ('yes' to continue)?" >&3
|
||||
read -r ANSWER
|
||||
if [ "${ANSWER}" != "yes" ]; then
|
||||
echo "You said << ${ANSWER} >> so I am exiting now."
|
||||
echo -e "--------------------- END ---------------------\n" >> "${LOGFILE}"
|
||||
echo "You said << ${ANSWER} >> so I am exiting now." >&3
|
||||
echo -e "User aborted restore process ...\n" >&2
|
||||
echo -e "--------------------- END ---------------------\n" >&5
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -910,7 +1095,7 @@ case "${COMMAND}" in
|
|||
DEST="'${DEST}'"
|
||||
|
||||
setup_passphrase
|
||||
echo "Restoring now ..."
|
||||
echo "Restoring now ..." >&3
|
||||
#use INCLUDE variable without creating another one
|
||||
INCLUDE="--file-to-restore ${FILE_TO_RESTORE}"
|
||||
duplicity_backup
|
||||
|
|
@ -926,8 +1111,7 @@ case "${COMMAND}" in
|
|||
eval \
|
||||
"${DUPLICITY}" "${OPTION}" "${VERBOSITY}" "${STATIC_OPTIONS}" \
|
||||
${ENCRYPT} \
|
||||
"${DEST}" | tee -a "${LOGFILE}"
|
||||
echo -e "--------------------- END ---------------------\n" >> "${LOGFILE}"
|
||||
"${DEST}"
|
||||
;;
|
||||
|
||||
"collection-status")
|
||||
|
|
@ -936,8 +1120,7 @@ case "${COMMAND}" in
|
|||
eval \
|
||||
"${DUPLICITY}" "${OPTION}" "${VERBOSITY}" "${STATIC_OPTIONS}" \
|
||||
${ENCRYPT} \
|
||||
"${DEST}" | tee -a "${LOGFILE}"
|
||||
echo -e "--------------------- END ---------------------\n" >> "${LOGFILE}"
|
||||
"${DEST}"
|
||||
;;
|
||||
|
||||
"backup")
|
||||
|
|
@ -948,12 +1131,16 @@ case "${COMMAND}" in
|
|||
;;
|
||||
|
||||
*)
|
||||
echo -e "[Only show $(basename "$0") usage options]\n" >> "${LOGFILE}"
|
||||
echo -e "[Only show $(basename "$0") usage options]\n"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
echo -e "--------- END DUPLICITY-BACKUP SCRIPT ---------\n" >> "${LOGFILE}"
|
||||
echo -e "--------- END DUPLICITY-BACKUP SCRIPT ---------\n" >&5
|
||||
|
||||
if [ "${USAGE}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${BACKUP_ERROR}" ]; then
|
||||
BACKUP_STATUS="ERROR"
|
||||
|
|
@ -979,8 +1166,17 @@ unset AWS_ACCESS_KEY_ID
|
|||
unset AWS_SECRET_ACCESS_KEY
|
||||
unset GS_ACCESS_KEY_ID
|
||||
unset GS_SECRET_ACCESS_KEY
|
||||
unset SWIFT_USERNAME
|
||||
unset SWIFT_PASSWORD
|
||||
unset SWIFT_AUTHURL
|
||||
unset SWIFT_AUTHVERSION
|
||||
unset DPBX_ACCESS_TOKEN
|
||||
unset PASSPHRASE
|
||||
unset SIGN_PASSPHRASE
|
||||
unset FTP_PASSWORD
|
||||
|
||||
# restore stdout and stderr to their original values
|
||||
# and close the other fd
|
||||
exec 1>&6 2>&7 3>&- 4>&- 5>&- 6>&- 7>&-
|
||||
|
||||
# vim: set tabstop=2 shiftwidth=2 sts=2 autoindent smartindent:
|
||||
|
|
|
|||
Loading…
Reference in a new issue