Compare commits

...

59 commits
v1.1 ... dev

Author SHA1 Message Date
zertrin
c78676ab9d Try to fix travis CI 2018-05-22 11:59:24 +08:00
zertrin
2dec3ed145 Update README.md 2018-05-22 11:35:35 +08:00
zertrin
c56e78a463 Update changelog with release date for v1.6.0 2018-05-22 11:23:51 +08:00
zertrin
27785d0ad0 Update changelog and bump version to v1.6.0 2018-05-22 11:20:53 +08:00
zertrin
4dd6ed1ee2 Fix issue #177: bug in cleanup action 2018-05-22 11:10:06 +08:00
zertrin
5cad03cb3e
Merge pull request #175 from elisman/patch-1
Removed SSH backend scheme example
2018-02-27 10:10:22 +08:00
Elisei Rotaru
f71dd556dc
Removed SSH backend scheme example
Removed SSH backend scheme example as it is not supported anymore by duplicity. As of version v0.7.01 (2015/01/11) ssh is an unsupported backend scheme. Using it with a newer release throws an error (UnsupportedBackendScheme: scheme not supported in url).
2018-02-21 11:28:03 +01:00
zertrin
77ecc4318f
Update Changelog 2018-02-03 11:40:29 +01:00
zertrin
99b2512789
Merge pull request #174 from xmatthias/fix_swift
unset swift variables
2018-02-03 11:37:45 +01:00
zertrin
4779ee4d1b
Merge branch 'dev' into fix_swift 2018-02-03 11:37:07 +01:00
zertrin
96a64148fd
Merge pull request #173 from xmatthias/dropbox
introduce dropbox functionality
2018-02-03 11:36:20 +01:00
Matthias Voppichler
6140c226db unset swift variables 2018-01-31 22:52:28 +01:00
Matthias Voppichler
18ef8983aa introduce dropbox functionality 2018-01-31 22:34:06 +01:00
zertrin
734be37b6d Bump version to v1.5.0 2018-01-15 16:00:47 +08:00
zertrin
9fea5075ab
Merge pull request #170 from harrim4n/dev
Add support for B2 backend
2018-01-15 15:51:10 +08:00
harrim4n
ae37de0e65 fixed shellcheck errors 2017-12-23 20:01:22 +01:00
harrim4n
2a77dde6ee added support for B2 backend 2017-12-23 19:04:00 +01:00
zertrin
e070ca7887
Merge pull request #168 from arichiardi/fix-file-dest
Use regex for trimming file:// destinations
2017-11-14 22:34:33 +08:00
zertrin
5a023c3609
Merge pull request #167 from arichiardi/notification-separator
Add notification separator
2017-11-14 22:27:23 +08:00
Andrea Richiardi
6377ad5281 Use regex for trimming file:// destinations
A problem with cut was causing:

  $ DEST="file:///media/user/data"
  $ TMPDEST=$(echo "${DEST}" | cut -c 6-)
  $ echo $TMPDEST
  ///media/user/data

The fix uses a regex instead so that we trim away things correctly. It also seems somewhat more
readable.
2017-11-13 21:14:07 -08:00
Andrea Richiardi
649c7830b0 Add notification separator
The notification request is now isolated visually for better debugging.
2017-11-12 17:28:32 -08:00
zertrin
dba25a57de change example conf to use single quotes for passphrases and paths 2017-11-05 11:08:24 +08:00
zertrin
13af8206e3 Bump version to v1.4.3 2017-10-30 23:44:52 +08:00
zertrin
9a36453bb1 Merge branch 'GerardRibas-telegram-notifications' into dev 2017-10-30 23:35:47 +08:00
zertrin
a7752c4c78 Minor changes before merging PR adding Telegram notifications support 2017-10-30 23:34:45 +08:00
zertrin
06291f0a6e Merge branch 'telegram-notifications' of git://github.com/GerardRibas/duplicity-backup.sh into GerardRibas-telegram-notifications 2017-10-30 23:14:17 +08:00
zertrin
cd82c07579 Remove VERSION file and hardcode it directly in the script 2017-10-30 22:33:30 +08:00
Gerard Ribas Canals
de7a6be9fe Telegram Notifications 2017-10-13 10:17:01 +02:00
zertrin
98bcf9f673 Bump version to 1.4.1 2017-10-04 09:59:55 +08:00
zertrin
0c4f2b7c45 Improved version parsing. Fix bug on MacOS (thanks @ErebusBat) 2017-09-30 22:50:03 +08:00
zertrin
2389ee61db Fix program version output when cwd is not the same as scriptdir 2017-09-29 12:16:20 +08:00
zertrin
def00abe60 Show program versions in output 2017-09-28 09:59:37 +08:00
zertrin
e4df413036 add link to issue #143 in Known issues section in the README 2017-09-24 14:35:38 +08:00
zertrin
dd2189ec4d Bump version to 1.4.0 2017-09-24 14:26:22 +08:00
zertrin
f8c4d0cc16 Add duplicity version check to handle deprecation of --include-globbing-filelist (fixes #136) 2017-09-24 14:23:36 +08:00
zertrin
723945af44 Merge pull request #157 from gunnarx/readme_spell
README.md: Fix some spelling errors
2017-06-06 15:15:28 +08:00
Gunnar Andersson
b7c292b5ff README.md: Fix some spelling errors 2017-06-05 08:31:32 +02:00
zertrin
cc2ae25355 Merge pull request #154 from dgibbs64/dev
[hostname] contains invalid character '[' in CentOS 7
2017-04-19 12:53:52 +08:00
zertrin
d1311a185a Merge pull request #156 from wtsi-hgi/fix/155-s3SchemeIdentification
Corrects cut of s3 protocol.
2017-04-19 12:53:25 +08:00
Colin Nolan
25d63bb99f Corrects cut of s3 protocol. 2017-04-18 09:36:32 +01:00
Daniel Gibbs
2ad58dc07e [hostname] contains invalid character '[' in CentOS 7
[hostname] contains invalid character '[' in CentOS 7 changed [ to (

See https://www.jethrocarr.com/2012/06/10/mailx-contains-invalid-character-2/

There may be a better way to resolve this however this quick fix works
2017-03-27 18:56:06 +01:00
zertrin
418ab79b11 Bump version to v1.3.0 2016-10-23 20:05:08 +02:00
zertrin
6ba17fa268 Rename repository from 'duplicity-backup' to 'duplicity-backup.sh' 2016-10-23 20:04:23 +02:00
zertrin
b207b90cba Add -h / --help option to print usage and don't send email or notification when printing usage only 2016-10-23 20:00:23 +02:00
zertrin
fb54103607 Attempt to fix issue #145 by adding a parameter 2016-10-23 19:39:32 +02:00
zertrin
d2ae7c58c1 Fix GPG error when backing up the script if no specific keyring is set up 2016-09-11 23:04:46 +02:00
zertrin
a827d886f4 Version v1.2 2016-09-10 14:56:35 +02:00
zertrin
5a5244e164 Fix "line 89: 4: Bad file descriptor" when printing usage without config set up 2016-09-10 14:56:05 +02:00
zertrin
26dc5cab55 Merge pull request #141 from arichiardi/fix-gpg-photo
Add --no-show-photos to --gpg-options
2016-09-09 16:55:02 +02:00
zertrin
cddd3f3c74 Merge pull request #137 from zertrin/rework-logging
Big rework of logging handling. Add a --quiet option to suppress most output
2016-09-09 16:54:47 +02:00
Andrea Richiardi
277677350c Add --no-show-photos to --gpg-options, fixes #140 2016-09-08 19:13:26 -07:00
zertrin
fb54765c53 Merge remote-tracking branch 'origin/dev' into rework-logging 2016-09-08 20:57:11 +02:00
zertrin
4bdde466e2 Merge pull request #138 from zertrin/fix-issue-135-s-nail
Add case for s-nail when using mailx
2016-09-06 11:40:09 +02:00
zertrin
0f901f4f78 Always exclude /proc from Source Disk Use Information 2016-09-05 01:40:52 +02:00
zertrin
4d5ab6247d Add case for s-nail when using mailx 2016-09-05 01:15:47 +02:00
zertrin
5d20128634 Improve some of the new comments about the new logging 2016-09-03 23:43:19 +02:00
zertrin
6c7eea2401 Big rework of logging handling. Add a --quiet option to suppress most output
To achieve the goals, I needed to dive into the arcane art of I/O
redirection in Bash. By playing correctly with the file descriptors and
tee, we can implement a sort of logging level system.
2016-09-03 23:26:54 +02:00
zertrin
b39300c514 Add --version option to README.md 2016-09-03 17:45:16 +02:00
zertrin
6421242e02 Wrap long lines in the CHANGELOG 2016-09-03 17:41:57 +02:00
6 changed files with 489 additions and 213 deletions

View file

@ -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

View file

@ -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

View file

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/zertrin/duplicity-backup.svg?branch=dev)](https://travis-ci.org/zertrin/duplicity-backup)
[![Build Status](https://travis-ci.org/zertrin/duplicity-backup.sh.svg?branch=dev)](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.

View file

@ -1 +0,0 @@
v1.1

View file

@ -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
# ------------------------------------------------------------------------------

View file

@ -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: