-
Notifications
You must be signed in to change notification settings - Fork 0
/
duply
executable file
·2377 lines (2101 loc) · 85.6 KB
/
duply
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env bash
#
################################################################################
# duply (grown out of ftplicity), is a shell front end to duplicity that #
# simplifies the usage by managing settings for backup jobs in profiles. #
# It supports executing multiple commands in a batch mode to enable single #
# line cron entries and executes pre/post backup scripts. #
# Since version 1.5.0 all duplicity backends are supported. Hence the name #
# changed from ftplicity to duply. #
# See http://duply.net or http://ftplicity.sourceforge.net/ for more info. #
# (c) 2006 Christiane Ruetten, Heise Zeitschriften Verlag, Germany #
# (c) 2008-2016 Edgar Soldin (changes since version 1.3) #
################################################################################
# LICENSE: #
# This program is licensed under GPLv2. #
# Please read the accompanying license information in gpl.txt. #
################################################################################
# TODO/IDEAS/KNOWN PROBLEMS:
# - possibility to restore time frames (incl. deleted files)
# realizable by listing each backup and restore from
# oldest to the newest, problem: not performant
# - search file in all backups function and show available
# versions with backups date (list old avail since 0.6.06)
# - edit profile opens conf file in vi
# - implement log-fd interpretation
# - add a duplicity option check against the options pending
# deprecation since 0.5.10 namely --time-separator
# --short-filenames
# --old-filenames
# - add 'exclude_<command>' list usage eg. exclude_verify
# - featreq 25: a download/install duplicity option
# - hint on install software if a piece is missing
# - import/export profile from/to .tgz function !!!
#
# CHANGELOG:
# 2.0.3 (29.08.2017)
# - bugfix: "line 2231: CMDS: bad array subscript"
# - bugfix 112: "env: illegal option -- u" on MacOSX
#
# 2.0.2 (23.05.2017)
# - bugfix: never insert creds into file:// targets
# - bugfix: avail profiles hint sometimes shortend the names by one char
# - bugfix 108: CMD_NEXT variable should ignore conditional commands (and, or)
# - export condition before/after next/prev command as CND_PREV,CND_NEXT now
# - bugfix 97: Unknown command should be ERROR, not WARNING
#
# 2.0.1 (16.11.2016)
# - bugfix 104: Duply 2.0 sets wrong archive dir, --name was always 'duply_'
#
# 2.0 (27.10.2016)
# made this a major version change, as we broke backward compatibility anyway
# (see last change in v1.10). got complaints that rightfully pointed out
# that should only come w/ a major version change. so, here we go ;)
# if your backend stops working w/ this version create a new profile and
# export the env vars needed as described in the comments of the conf file
# directly above the SOURCE setting.
# Changes:
# - making sure multi spaces in TARGET survive awk processing
# - new env var PROFILE exported to scripts
# - fix 102: expose a unique timestamp variable for pre/post scripts
# actually a featreq. exporting RUN_START nanosec unix timestamp
# - fix 101: GPG_AGENT_INFO is 'bogus' (thx Thomas Harning Jr.)
# - fix 96: duply cannot handle two consecutive spaces in paths
#
# 1.11.3 (29.5.2016)
# - fix wrong "WARNING: No running gpg-agent ..." when sign key was not set
#
# 1.11.2 (11.2.2016)
# - fix "gpg: unsafe" version print out
# - bugfix 91: v1.11 [r47] broke asymmetric encryption when using GPG_KEYS_ENC
# - bugfix 90: S3: TARGET_USER/PASS have no effect, added additional
# documentation about needed env vars to template conf file
#
# 1.11.1 (18.12.2015)
# - bugfix 89: "Duply has trouble with PYTHON-interpreter" on OSX homebrew
# - reverted duply's default PYTHON to 'python'
#
# 1.11 (24.11.2015)
# - remove obsolete --ssh-askpass routine
# - add PYTHON conf var to allow global override of used python interpreter
# - enforced usage of "python2" in PATH as default interpreter for internal
# use _and_ to run duplicity (setup.py changed the shebang to the fixed
# path /usr/bin/python until 0.7.05, which we circumvent this way)
# - featreq 36: support gpg-connect-agent as a means to detect if an agent is
# running (thx Thomas Harning Jr.), used gpg-agent for detection though
# - quotewrapped run_cmd parameters to protect it from spaces eg. in TMP path
# - key export routine respects gpg-agent usage now
#
# 1.10.1 (19.8.2015)
# - bugfix 86: Duply+Swift outputs warning
# - bugfix 87: Swift fails without BACKEND_URL
#
# 1.10 (31.7.2015)
# - featreq 37: busybox issues - fix awk, grep version detection,
# fix grep failure because --color=never switch is unsupported
# (thx Thomas Harning Jr. for reporting and helping to debug/fix it)
# - bugfix 81: --exclude-globbing-filelist is deprecated since 0.7.03
# (thx Joachim Wiedorn, also for maintaining the debian package)
# - implemented base-/dirname as bash functions
# - featreq 31 " Support for duplicity Azure backend " - ignored a
# contributed patch by Scott McKenzie and instead opted for removing almost
# all code that deals with special env vars required by backends.
# adding and modifying these results in too much overhead so i dropped this
# feature. the future alternative for users is to consult the duplicity
# manpage and add the needed export definitions to the conf file.
# appended a commented example to the template conf below the auth section.
#
# 1.9.2 (21.6.2015)
# - bugfix: exporting keys with gpg2.1 works now (thx Philip Jocks)
# - documented GPG_OPTS needed for gpg2.1 to conf template (thx Troy Engel)
# - bugfix 82: GREP_OPTIONS=--color=always disrupted time calculation
# - added GPG conf var (see conf template for details)
# - added grep version output as it is an integral needed binary
# - added PYTHONPATH printout in version output
#
# 1.9.1 (13.10.2014)
# - export CMD_ERR now for scripts to detect if CMD_PREV failed/succeeded
# - bugfix: CMD_PREV contained command even if it was skipped
#
# 1.9.0 (24.8.2014)
# - bugfix: env vars were not exported when external script was executable
# - rework GPG_KEY handling, allow virtually anything now (uid, keyid etc.)
# see gpg manpage, section "How to specify a user ID"
# let gpg complain when the delivered values are invalid for whatever reason
# - started to rework tmp space checking, exposed folder & writable check
# TODO: reimplement enough file space available checking
#
# 1.8.0 (13.7.2014)
# - add command verifyPath to expose 'verify --file-to-restore' action
# - add time parameter support to verify command
# - add section time formats to usage output
#
# 1.7.4 (24.6.2014)
# - remove ubuntu one support, service is discontinued
# - featreq 31: add authenticated swift (contributed by Justus Seifert)
#
# 1.7.3 (3.4.2014)
# - bugfix: test routines, gpg2 asked for passphrase although GPG_PW was set
#
# 1.7.2 (1.4.2014 "April,April")
# - bugfix: debian Bug#743190 "duply no longer allows restoration without
# gpg passphrase in conf file"
# GPG_AGENT_INFO env var is now needed to trigger --use-agent
# - bugfix: gpg keyenc test routines didn't work if GPG_PW was not set
#
# 1.7.1 (30.3.2014)
# - bugfix: purge-* commands renamed to purgeFull, purgeIncr due to
# incompatibility with new minus batch separator
#
# 1.7.0 (20.3.2014)
# - disabled gpg key id plausibility check, too many valid possibilities
# - featreq 7 "Halt if precondition fails":
# added and(+), or(-) batch command(separator) support
# - featreq 26 "pre/post script with shebang line":
# if a script is flagged executable it's executed in a subshell
# now as opposed to sourced to bash, which is the default
# - bugfix: do not check if dpbx, swift credentials are set anymore
# - bugfix: properly escape profile name, archdir if used as arguments
# - add DUPL_PRECMD conf setting for use with e.g. trickle
#
# 1.6.0 (1.1.2014)
# - support gs backend
# - support dropbox backend
# - add gpg-agent support to gpg test routines
# - autoenable --use-agent if passwords were not defined in config
# - GPG_OPTS are now honored everywhere, keyrings or complete gpg
# homedir can thus be configured to be located anywhere
# - always import both secret and public key if avail from config profile
# - new explanatory comments in initial exclude file
# - bugfix 7: Duply only imports one key at a time
#
# 1.5.11 (19.07.2013)
# - purge-incr command for remove-all-inc-of-but-n-full feature added
# patch provided by Moritz Augsburger, thanks!
# - documented version command in man page
#
# 1.5.10 (26.03.2013)
# - minor indent and documentation fixes
# - bugfix: exclude filter failed on ubuntu, mawk w/o posix char class support
# - bugfix: fix url_decoding generally and for python3
# - bugfix 3609075: wrong script results in status line (thx David Epping)
#
# 1.5.9 (22.11.2012)
# - bugfix 3588926: filter --exclude* params for restore/fetch ate too much
# - restore/fetch now also ignores --include* or --exclude='foobar'
#
# 1.5.8 (26.10.2012)
# - bugfix 3575487: implement proper cloud files support
#
# 1.5.7 (10.06.2012)
# - bugfix 3531450: Cannot use space in target URL (file:///) anymore
#
# 1.5.6 (24.5.2012)
# - commands purge, purge-full have no default value anymore for security
# reasons; instead max value can be given via cmd line or must be set
# in profile; else an error is shown.
# - minor man page modifications
#
# versioning scheme will be simplified to [major].[minor].[patch] version
# with the next version raise
#
# 1.5.5.5 (4.2.2012)
# - bugfix 3479605: SEL context confused profile folder's permission check
# - colon ':' in url passphrase got ignored, added python driven url_decoding
# for user & pass to better process special chars
#
# 1.5.5.4 (16.10.2011)
# - bugfix 3421268: SFTP passwords from conf ignored and always prompted for
# - add support for separate sign passphrase (needs duplicity 0.6.14+)
#
# 1.5.5.3 (1.10.2011)
# - bugfix 3416690: preview threw echo1 error
# - fix unknown cmds error usage & friends if more than 2 params were given
#
# 1.5.5.2 (23.9.2011)
# - bugfix 3409643: ssh key auth did ask for passphrase (--ssh-askpass ?)
# - bugfix: mawk does not support \W and did not split multikey definitions
# - all parameters should survive single (') and double (") quotes now
#
# 1.5.5.1 (7.6.2011)
# - featreq 3311881: add ftps as supported by duplicity 0.6.13 (thx mape2k)
# - bugfix 3312208: signing detection broke symmetric gpg test routine
#
# 1.5.5 (2.5.2011)
# - bugfix: fetch problem with space char in path, escape all params
# containing non word chars
# - list available profiles, if given profile cannot be found
# - added --use-agent configuration hint
# - bugfix 3174133: --exclude* params in conf DUPL_PARAMS broke
# fetch/restore
# - version command now prints out 'using installed' info
# - featreq 3166169: autotrust imported keys, based on code submitted by
# Martin Ellis - imported keys are now automagically trusted ultimately
# - new txt2man feature to create manpages for package maintainers
#
# 1.5.4.2 (6.1.2011)
# - new command changelog
# - bugfix 3109884: freebsd awk segfaulted on printf '%*', use print again
# - bugfix: freebsd awk hangs on 'awk -W version'
# - bugfix 3150244: mawk does not know '--version'
# - minor help text improvements
# - new env vars CMD_PREV,CMD_NEXT replacing CMD env var for scripts
#
# 1.5.4.1 (4.12.2010)
# - output awk, python, bash version now in prolog
# - shebang uses /usr/bin/env now for freebsd compatibility,
# bash not in /bin/bash
# - new --disable-encryption parameter,
# to override profile encr settings for one run
# - added exclude-if-present setting to conf template
# - bug 3126972: GPG_PW only needed for signing/symmetric encryption
# (even though duplicity still needs it)
#
# 1.5.4 (15.11.2010)
# - as of 1.5.3 already, new ARCH_DIR config option
# - multiple key support
# - ftplicity-Feature Requests-2994929: separate encryption and signing key
# - key signing of symmetric encryption possible (duplicity patch committed)
# - gpg tests disable switch
# - gpg tests now previewable and more intelligent
#
# 1.5.3 (1.11.2010)
# - bugfix 3056628: improve busybox compatibility, grep did not have -m param
# - bugfix 2995408: allow empty password for PGP key
# - bugfix 2996459: Duply erroneously escapes '-' symbol in username
# - url_encode function is now pythonized
# - rsync uses FTP_PASSWORD now if duplicity 0.6.10+ , else issue warning
# - feature 3059262: Make pre and post aware of parameters,
# internal parameters + CMD of pre or post
#
# 1.5.2.3 (16.4.2010)
# - bugfix: date again, should now work virtually anywhere
#
# 1.5.2.2 (3.4.2010)
# - minor bugfix: duplicity 0.6.8b version string now parsable
# - added INSTALL.txt
#
# 1.5.2.1 (23.3.2010)
# - bugfix: date formatting is awked now and should work on all platforms
#
# 1.5.2 (2.3.2010)
# - bugfix: errors print to STD_ERR now, failed tasks print an error message
# - added --name=duply_<profile> for duplicity 0.6.01+ to name cache folder
# - simplified & cleaned profileless commands, removed second instance
# - generalized separator time routines
# - added support for --no-encryption (GPG_KEY='disabled'), see conf examples
# - minor fixes
#
# 1.5.1.5 (5.2.2010)
# - bugfix: added special handling of credentials for rsync, imap(s)
#
# 1.5.1.4 (7.1.2010)
# - bugfix: nsecs defaults now to zeroes if date does not deliver [0-9]{9}
# - check if ncftp binary is available if url protocol is ftp
# - bugfix: duplicity output is now printed to screen directly to resolve
# 'mem alloc problem' bug report
# - bugfix: passwords will not be in the url anymore to solve the 'duply shows
# sensitive data in process listing' bug report
#
# 1.5.1.3 (24.12.2009) 'merry xmas'
# - bugfix: gpg pass now apostrophed to allow space and friends
# - bugfix: credentials are now url encoded to allow special chars in them
# a note about url encoding has been added to the conf template
#
# 1.5.1.2 (1.11.2009)
# - bugfix: open parenthesis in password broke duplicity execution
# - bugfix: ssh/scp backend does not always need credentials e.g. key auth
#
# 1.5.1.1 (21.09.2009)
# - bugfix: fixed s3[+http] TARGET_PASS not needed routine
# - bugfix: TYPO in duply 1.5.1 prohibited the use of /etc/duply
# see https://sourceforge.net/tracker/index.php?func=detail&
# aid=2864410&group_id=217745&atid=1041147
#
# 1.5.1 (21.09.2009) - duply (fka. ftplicity)
# - first things first: ftplicity (being able to support all backends since
# some time) will be called duply (fka. ftplicity) from now on. The addendum
# is for the time being to circumvent confusion.
# - bugfix: exit code is 1 (error) not 0 (success), if at least on duplicity
# command failed
# - s3[+http] now supported natively by translating user/pass to access_key/
# secret_key environment variables needed by duplicity s3 boto backend
# - bugfix: additional output lines do not confuse version check anymore
# - list command supports now age parameter (patch by stefan on feature
# request tracker)
# - bugfix: option/param pairs are now correctly passed on to duplicity
# - bugfix: s3[+http] needs no TARGET_PASS if command is read only
#
# 1.5.0.2 (31.07.1009)
# - bugfix: insert password in target url didn't work with debian mawk
# related to previous bug report
#
# 1.5.0.1 (23.07.2009)
# - bugfix: gawk gensub dependency raised an error on debian's default mawk
# replaced with match/substr command combination (bug report)
# https://sf.net/tracker/?func=detail&atid=1041147&aid=2825388&
# group_id=217745
#
# 1.5.0 (01.07.2009)
# - removed ftp limitation, all duplicity backends should work now
# - bugfix: date for separator failed on openwrt busybox date, added a
# detecting workaround, milliseconds are not available w/ busybox date
#
# 1.4.2.1 (14.05.2009)
# - bugfix: free temp space detection failed with lvm, fixed awk parse routine
#
# 1.4.2 (22.04.2009)
# - gpg keys are now exported as gpgkey.[id].asc , the suffix reflects the
# armored ascii nature, the id helps if the key is switched for some reason
# im/export routines are updated accordingly (import is backward compatible
# to the old profile/gpgkey files)
# - profile argument is treated as path if it contains slashes
# (for details see usage)
# - non-ftplicity options (all but --preview currently) are now passed
# on to duplicity
# - removed need for stat in secure_conf, it is ls based now
# - added profile folder readable check
# - added gpg version & home info output
# - awk utility availability is now checked, because it was mandatory already
# - tmp space is now checked on writability and space requirement
# test fails on less than 25MB or configured $VOLSIZE,
# test warns if there is less than two times $VOLSIZE because
# that's required for --asynchronous-upload option
# - gpg functionality is tested now before executing duplicity
# test drive contains encryption, decryption, comparison, cleanup
# this is meant to detect non trusted or other gpg errors early
# - added possibility of doing symmetric encryption with duplicity
# set GPG_KEY="" or simply comment it out
# - added hints in config template on the depreciation of
# --short-filenames, --time-separator duplicity options
#
# new versioning scheme 1.4.2b => 1.4.2,
# beta b's are replaced by a patch count number e.g. 1.4.2.1 will be assigned
# to the first bug fixing version and 1.4.2.2 to the second and so on
# also the releases will now have a release date formatted (Day.Month.Year)
#
# 1.4.1b1 - bugfix: ftplicity changed filesystem permission of a folder
# named exactly as the profile if existing in executing dir
# - improved plausibility checking of config and profile folder
# - secure_conf only acts if needed and prints a warning now
#
# 1.4.1b - introduce status (duplicity collection-status) command
# - pre/post script output printed always now, not only on errors
# - new config parameter GPG_OPTS to pass gpg options
# added examples & comments to profile template conf
# - reworked separator times, added duration display
# - added --preview switch, to preview generated command lines
# - disabled MAX_AGE, MAX_FULL_BACKUPS, VERBOSITY in generated
# profiles because they have reasonable defaults now if not set
#
# 1.4.0b1 - bugfix: incr forces incremental backups on duplicity,
# therefore backup translates to pre_bkp_post now
# - bugfix: new command bkp, which represents duplicity's
# default action (incr or full if full_if_older matches
# or no earlier backup chain is found)
#
# new versioning scheme 1.4 => 1.4.0, added new minor revision number
# this is meant to slow down the rapid version growing but still keep
# versions cleanly separated.
# only additional features will raise the new minor revision number.
# all releases start as beta, each bugfix release will raise the beta
# count, usually new features arrive before a version 'ripes' to stable
#
# 1.4.0b
# 1.4b - added startup info on version, time, selected profile
# - added time output to separation lines
# - introduced: command purge-full implements duplicity's
# remove-all-but-n-full functionality (patch by unknown),
# uses config variable $MAX_FULL_BACKUPS (default = 1)
# - purge config var $MAX_AGE defaults to 1M (month) now
# - command full does not execute pre/post anymore
# use batch command pre_full_post if needed
# - introduced batch mode cmd1_cmd2_etc
# (in turn removed the bvp command)
# - unknown/undefined command issues a warning/error now
# - bugfix: version check works with 0.4.2 and older now
# 1.3b3 - introduced pre/post commands to execute/debug scripts
# - introduced bvp (backup, verify, purge)
# - bugfix: removed need for awk gensub, now mawk compatible
# 1.3b2 - removed pre/post need executable bit set
# - profiles now under ~/.ftplicity as folders
# - root can keep profiles in /etc/ftplicity, folder must be
# created by hand, existing profiles must be moved there
# - removed ftplicity in path requirement
# - bugfix: bash < v.3 did not know '=~'
# - bugfix: purge works again
# 1.3 - introduces multiple profiles support
# - modified some script errors/docs
# - reordered gpg key check import routine
# - added 'gpg key id not set' check
# - added error_gpg (adds how to setup gpg key howto)
# - bugfix: duplicity 0.4.4RC4+ parameter syntax changed
# - duplicity_version_check routine introduced
# - added time separator, shortnames, volsize, full_if_older
# duplicity options to config file (inspired by stevie
# from http://weareroot.de)
# 1.1.1 - bugfix: encryption reactivated
# 1.1 - introduced config directory
# 1.0 - first release
################################################################################
# utility functions overriding binaries
# wrap grep to override possible env set GREP_OPTIONS=--color=always
function grep {
command env "GREP_OPTIONS=" grep "$@"
}
# implement basename in plain bash
function basename {
local stripped="${1%/}"
echo "${stripped##*/}"
}
# implement dirname in plain bash
function dirname {
echo ${1%/*}
}
# implement basic which in plain bash
function which {
type -p "$@"
}
# check availability of executables via file name or file paths
function lookup {
local bin="$1"
# look for file names in path via bash hash OR
# look for executables at given relative/absolute location
( [ "${bin##*/}" == "$bin" ] && hash "$bin" 2>/dev/null ) || [ -x "$bin" ]
}
# important definitions #######################################################
ME_LONG="$0"
ME="$(basename $0)"
ME_NAME="${ME%%.*}"
ME_VERSION="2.0.3"
ME_WEBSITE="http://duply.net"
# default config values
DEFAULT_SOURCE='/path/of/source'
DEFAULT_TARGET='scheme://user[:password]@host[:port]/[/]path'
DEFAULT_TARGET_USER='_backend_username_'
DEFAULT_TARGET_PASS='_backend_password_'
DEFAULT_GPG='gpg'
DEFAULT_GPG_KEY='_KEY_ID_'
DEFAULT_GPG_PW='_GPG_PASSWORD_'
DEFAULT_PYTHON='python'
# function definitions ##########################
function set_config { # sets global config vars
local CONFHOME_COMPAT="$HOME/.ftplicity"
local CONFHOME="$HOME/.duply"
local CONFHOME_ETC_COMPAT="/etc/ftplicity"
local CONFHOME_ETC="/etc/duply"
# confdir can be delivered as path (must contain /)
if [ `echo $FTPLCFG | grep /` ] ; then
CONFDIR=$(readlink -f $FTPLCFG 2>/dev/null || \
( echo $FTPLCFG|grep -v '^/' 1>/dev/null 2>&1 \
&& echo $(pwd)/${FTPLCFG} ) || \
echo ${FTPLCFG})
# or DEFAULT in home/.duply folder (NEW)
elif [ -d "${CONFHOME}" ]; then
CONFDIR="${CONFHOME}/${FTPLCFG}"
# or in home/.ftplicity folder (OLD)
elif [ -d "${CONFHOME_COMPAT}" ]; then
CONFDIR="${CONFHOME_COMPAT}/${FTPLCFG}"
warning_oldhome "${CONFHOME_COMPAT}" "${CONFHOME}"
# root can put profiles under /etc/duply (NEW) if path exists
elif [ -d "${CONFHOME_ETC}" ] && [ "$EUID" -eq 0 ]; then
CONFDIR="${CONFHOME_ETC}/${FTPLCFG}"
# root can keep profiles under /etc/ftplicity (OLD) if path exists
elif [ -d "${CONFHOME_ETC_COMPAT}" ] && [ "$EUID" -eq 0 ]; then
CONFDIR="${CONFHOME_ETC_COMPAT}/${FTPLCFG}"
warning_oldhome "${CONFHOME_ETC_COMPAT}" "${CONFHOME_ETC}"
# hmm no profile folder there, then use default for error later
else
CONFDIR="${CONFHOME}/${FTPLCFG}" # continue, will fail later in main
fi
# remove trailing slash, get profile name etc.
CONFDIR="${CONFDIR%/}"
PROFILE="${CONFDIR##*/}"
CONF="$CONFDIR/conf"
PRE="$CONFDIR/pre"
POST="$CONFDIR/post"
EXCLUDE="$CONFDIR/exclude"
KEYFILE="$CONFDIR/gpgkey.asc"
}
function version_info { # print version information
cat <<END
$ME_NAME version $ME_VERSION
($ME_WEBSITE)
END
}
function version_info_using {
cat <<END
$(version_info)
$(using_info)
END
}
function python_binary {
echo "${PYTHON-$DEFAULT_PYTHON}"
}
function using_info {
lookup duplicity && duplicity_version_get
local NOTFOUND="MISSING"
# freebsd awk (--version only), debian mawk (-W version only), deliver '' so awk does not wait for input
local AWK_VERSION=$( lookup awk && (awk --version 2>/dev/null || awk -W version 2>&1) | awk 'NR<=2&&tolower($0)~/(busybox|awk)/{success=1;print;exit} END{if(success<1) print "unknown"}' || echo "$NOTFOUND" )
local GREP_VERSION=$( lookup grep && grep --version 2>&1 | awk 'NR<=2&&tolower($0)~/(busybox|grep.*[0-9]+\.[0-9]+)/{success=1;print;exit} END{if(success<1) print "unknown"}' || echo "$NOTFOUND" )
local PYTHON_RUNNER=$(python_binary)
local PYTHON_VERSION=$(lookup "$PYTHON_RUNNER" && "$PYTHON_RUNNER" -V 2>&1| awk '{print tolower($0);exit}' || echo "'$PYTHON_RUNNER' $NOTFOUND" )
local GPG_INFO=$(gpg_avail && gpg --version 2>&1| awk '/^gpg.*[0-9\.]+$/&&length(v)<1{v=$1" "$3}/^Home:/{h=" ("$0")"}END{print v""h}' || echo "gpg $NOTFOUND")
local BASH_VERSION=$(bash --version | awk 'NR==1{IGNORECASE=1;sub(/GNU bash, version[ ]+/,"",$0);print $0}')
echo -e "Using installed duplicity version ${DUPL_VERSION:-$NOTFOUND}\
${PYTHON_VERSION+, $PYTHON_VERSION${PYTHONPATH:+ 'PYTHONPATH=$PYTHONPATH'}}\
${GPG_INFO:+, $GPG_INFO}${AWK_VERSION:+, awk '${AWK_VERSION}'}${GREP_VERSION:+, grep '${GREP_VERSION}'}\
${BASH_VERSION:+, bash '${BASH_VERSION}'}."
}
function usage_info { # print usage information
cat <<USAGE_EOF
VERSION:
$(version_info)
DESCRIPTION:
Duply deals as a wrapper for the mighty duplicity magic.
It simplifies running duplicity with cron or on command line by:
- keeping recurring settings in profiles per backup job
- enabling batch operations eg. backup_verify+purge
- executing pre/post scripts (different actions possible
depending on previous or next command or it's exit status)
- precondition checking for flawless duplicity operation
For each backup job one configuration profile must be created.
The profile folder will be stored under '~/.${ME_NAME}/<profile>'
(where ~ is the current users home directory).
Hint:
If the folder '/etc/${ME_NAME}' exists, the profiles for the super
user root will be searched & created there.
USAGE:
first time usage (profile creation):
$ME <profile> create
general usage in single or batch mode (see EXAMPLES):
$ME <profile> <command>[[_|+|-]<command>[_|+|-]...] [<options> ...]
For batches the conditional separators can also be written as pseudo commands
and(+), or(-). See SEPARATORS for details.
Non $ME options are passed on to duplicity (see OPTIONS).
All conf parameters can also be defined in the environment instead.
PROFILE:
Indicated by a path or a profile name (<profile>), which is resolved
to '~/.${ME_NAME}/<profile>' (~ expands to environment variable \$HOME).
Superuser root can place profiles under '/etc/${ME_NAME}'. Simply create
the folder manually before running $ME_NAME as superuser.
Note:
Already existing profiles in root's home folder will cease to work
unless they are moved to the new location manually.
example 1: $ME humbug backup
Alternatively a _path_ might be used e.g. useful for quick testing,
restoring or exotic locations. Shell expansion should work as usual.
Hint:
The path must contain at least one path separator '/',
e.g. './test' instead of only 'test'.
example 2: $ME ~/.${ME_NAME}/humbug backup
SEPARATORS:
_ (underscore)
neutral separator
+ (plus sign), _and_
conditional AND
the next command will only be executed if the previous succeeded
- (minus sign), _or_
conditional OR
the next command will only be executed if the previous failed
example:
'pre+bkp-verify_post' translates to 'pre_and_bkp_or_verify_post'
COMMANDS:
usage get usage help text
and/or pseudo commands for better batch cmd readability (see SEPARATORS)
create creates a configuration profile
backup backup with pre/post script execution (batch: pre_bkp_post),
full (if full_if_older matches or no earlier backup is found)
incremental (in all other cases)
pre/post execute '<profile>/$(basename "$PRE")', '<profile>/$(basename "$POST")' scripts
bkp as above but without executing pre/post scripts
full force full backup
incr force incremental backup
list [<age>]
list all files in backup (as it was at <age>, default: now)
status prints backup sets and chains currently in repository
verify [<age>] [--compare-data]
list files changed, since age if given
verifyPath <rel_path_in_bkp> <local_path> [<age>] [--compare-data]
list changes of a file or folder path in backup compared to a
local path, since age if given
restore <target_path> [<age>]
restore the complete backup to <target_path> [as it was at <age>]
fetch <src_path> <target_path> [<age>]
fetch single file/folder from backup [as it was at <age>]
purge [<max_age>] [--force]
list outdated backup files (older than \$MAX_AGE)
[use --force to actually delete these files]
purgeFull [<max_full_backups>] [--force]
list outdated backup files (\$MAX_FULL_BACKUPS being the number of
full backups and associated incrementals to keep, counting in
reverse chronological order)
[use --force to actually delete these files]
purgeIncr [<max_fulls_with_incrs>] [--force]
list outdated incremental backups (\$MAX_FULLS_WITH_INCRS being
the number of full backups which associated incrementals will be
kept, counting in reverse chronological order)
[use --force to actually delete these files]
cleanup [--force]
list broken backup chain files archives (e.g. after unfinished run)
[use --force to actually delete these files]
changelog print changelog / todo list
txt2man feature for package maintainers - create a manpage based on the
usage output. download txt2man from http://mvertes.free.fr/, put
it in the PATH and run '$ME txt2man' to create a man page.
version show version information of $ME_NAME and needed programs
OPTIONS:
--force passed to duplicity (see commands: purge, purge-full, cleanup)
--preview do nothing but print out generated duplicity command lines
--disable-encryption
disable encryption, overrides profile settings
TIME FORMATS:
For all time related parameters like age, max_age etc.
Refer to the duplicity manpage for all available formats. Here some examples:
2002-01-25T07:00:00+02:00 (full date time format string)
2002/3/5 (date string YYYY/MM/DD)
12D (interval, 12 days ago)
1h78m (interval, 1 hour 78 minutes ago)
PRE/POST SCRIPTS:
Some useful internal duply variables are exported to the scripts.
PROFILE, CONFDIR, SOURCE, TARGET_URL_<PROT|HOSTPATH|USER|PASS>,
GPG_<KEYS_ENC|KEY_SIGN|PW>, CMD_<PREV|NEXT>, CMD_ERR, RUN_START,
CND_<PREV|NEXT> (condition before/after next/prev command)
The CMD_* variables were introduced to allow different actions according to
the command the scripts were attached to e.g. 'pre_bkp_post_pre_verify_post'
will call the pre script two times, with CMD_NEXT variable set to 'bkp'
on the first and to 'verify' on the second run.
CMD_ERR holds the exit code of the CMD_PREV .
EXAMPLES:
create profile 'humbug':
$ME humbug create (don't forget to edit this new conf file)
backup 'humbug' now:
$ME humbug backup
list available backup sets of profile 'humbug':
$ME humbug status
list and delete outdated backups of 'humbug':
$ME humbug purge --force
restore latest backup of 'humbug' to /mnt/restore:
$ME humbug restore /mnt/restore
restore /etc/passwd of 'humbug' from 4 days ago to /root/pw:
$ME humbug fetch etc/passwd /root/pw 4D
(see "duplicity manpage", section TIME FORMATS)
a one line batch job on 'humbug' for cron execution:
$ME humbug backup_verify_purge --force
batch job to run a full backup with pre/post scripts:
$ME humbug pre_full_post
FILES:
in profile folder '~/.${ME_NAME}/<profile>' or '/etc/${ME_NAME}'
conf profile configuration file
pre,post pre/post scripts (see above for details)
gpgkey.*.asc exported GPG key files
exclude a globbing list of included or excluded files/folders
(see "duplicity manpage", section FILE SELECTION)
$(hint_profile)
SEE ALSO:
duplicity man page:
duplicity(1) or http://duplicity.nongnu.org/duplicity.1.html
USAGE_EOF
}
# to check call 'duply txt2man | man -l -'
function usage_txt2man {
usage_info | \
awk '/^^[^[:lower:][:space:]][^[:lower:]]+$/{gsub(/[^[:upper:]]/," ",$0)}{print}' |\
txt2man -t"$(toupper "${ME_NAME}")" -s1 -r"${ME_NAME}-${ME_VERSION}" -v'User Manuals'
}
function changelog {
cat $ME_LONG | awk '/^#####/{on=on+1}(on==3){sub(/^#( )?/,"",$0);print}'
}
function create_config {
if [ ! -d "$CONFDIR" ] ; then
mkdir -p "$CONFDIR" || error "Couldn't create config '$CONFDIR'."
# create initial config file
cat <<EOF >"$CONF"
# gpg encryption settings, simple settings:
# GPG_KEY='disabled' - disables encryption alltogether
# GPG_KEY='<key1>[,<key2>]'; GPG_PW='pass' - encrypt with keys,
# sign if secret key of key1 is available use GPG_PW for sign & decrypt
# Note: you can specify keys via all methods described in gpg manpage,
# section "How to specify a user ID", escape commas (,) via backslash (\)
# e.g. 'Mueller, Horst', 'Bernd' -> 'Mueller\, Horst, Bernd'
# as they are used to separate the entries
# GPG_PW='passphrase' - symmetric encryption using passphrase only
GPG_KEY='${DEFAULT_GPG_KEY}'
GPG_PW='${DEFAULT_GPG_PW}'
# gpg encryption settings in detail (extended settings)
# the above settings translate to the following more specific settings
# GPG_KEYS_ENC='<keyid1>[,<keyid2>,...]' - list of pubkeys to encrypt to
# GPG_KEY_SIGN='<keyid1>|disabled' - a secret key for signing
# GPG_PW='<passphrase>' - needed for signing, decryption and symmetric
# encryption. If you want to deliver different passphrases for e.g.
# several keys or symmetric encryption plus key signing you can use
# gpg-agent. Simply make sure that GPG_AGENT_INFO is set in environment.
# also see "A NOTE ON SYMMETRIC ENCRYPTION AND SIGNING" in duplicity manpage
# notes on en/decryption
# private key and passphrase will only be needed for decryption or signing.
# decryption happens on restore and incrementals (compare archdir contents).
# for security reasons it makes sense to separate the signing key from the
# encryption keys. https://answers.launchpad.net/duplicity/+question/107216
#GPG_KEYS_ENC='<pubkey1>,<pubkey2>,...'
#GPG_KEY_SIGN='<prvkey>'
# set if signing key passphrase differs from encryption (key) passphrase
# NOTE: available since duplicity 0.6.14, translates to SIGN_PASSPHRASE
#GPG_PW_SIGN='<signpass>'
# uncomment and set a file path or name force duply to use this gpg executable
# available in duplicity 0.7.04 and above (currently unreleased 06/2015)
#GPG='/usr/local/gpg-2.1/bin/gpg'
# gpg options passed from duplicity to gpg process (default='')
# e.g. "--trust-model pgp|classic|direct|always"
# or "--compress-algo=bzip2 --bzip2-compress-level=9"
# or "--personal-cipher-preferences AES256,AES192,AES..."
# or "--homedir ~/.duply" - keep keyring and gpg settings duply specific
# or "--pinentry-mode loopback" - needed for GPG 2.1+ _and_
# also enable allow-loopback-pinentry in your .gnupg/gpg-agent.conf
#GPG_OPTS=''
# disable preliminary tests with the following setting
#GPG_TEST='disabled'
# backend, credentials & location of the backup target (URL-Format)
# generic syntax is
# scheme://[user[:password]@]host[:port]/[/]path
# eg.
# sftp://bob:[email protected]//home/bob/dupbkp
# for details and available backends see duplicity manpage, section URL Format
# http://duplicity.nongnu.org/duplicity.1.html#sect7
# BE AWARE:
# some backends (cloudfiles, S3 etc.) need additional env vars to be set to
# work properly, read after the TARGET definition for more details.
# ATTENTION:
# characters other than A-Za-z0-9.-_.~ in the URL have to be
# replaced by their url encoded pendants, see
# http://en.wikipedia.org/wiki/Url_encoding
# if you define the credentials as TARGET_USER, TARGET_PASS below $ME
# will try to url_encode them for you if the need arises.
TARGET='${DEFAULT_TARGET}'
# optionally the username/password can be defined as extra variables
# setting them here _and_ in TARGET results in an error
# ATTENTION:
# there are backends that do not support the user/pass auth scheme.
# prominent examples are S3, Azure, Cloudfiles. when in doubt consult the
# duplicity manpage. usually there is a NOTE section explaining if and which
# env vars should be set.
#TARGET_USER='${DEFAULT_TARGET_USER}'
#TARGET_PASS='${DEFAULT_TARGET_PASS}'
# eg. for cloud files backend it might look like this (uncomment for use!)
#export CLOUDFILES_USERNAME='someuser'
#export CLOUDFILES_APIKEY='somekey'
#export CLOUDFILES_AUTHURL ='someurl'
# the following is an incomplete list (<backend>: comma separated env vars list)
# Azure: AZURE_ACCOUNT_NAME, AZURE_ACCOUNT_KEY
# Cloudfiles: CLOUDFILES_USERNAME, CLOUDFILES_APIKEY, CLOUDFILES_AUTHURL
# Google Cloud Storage: GS_ACCESS_KEY_ID, GS_SECRET_ACCESS_KEY
# Pydrive: GOOGLE_DRIVE_ACCOUNT_KEY, GOOGLE_DRIVE_SETTINGS
# S3: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
# Swift: SWIFT_USERNAME, SWIFT_PASSWORD, SWIFT_AUTHURL,
# SWIFT_TENANTNAME OR SWIFT_PREAUTHURL, SWIFT_PREAUTHTOKEN
# base directory to backup
SOURCE='${DEFAULT_SOURCE}'
# a command that runs duplicity e.g.
# shape bandwidth use via trickle
# "trickle -s -u 640 -d 5120" # 5Mb up, 40Mb down"
#DUPL_PRECMD=""
# override the used python interpreter, defaults to "python"
# e.g. "python2" or "/usr/bin/python2.7"
#PYTHON="python"
# exclude folders containing exclusion file (since duplicity 0.5.14)
# Uncomment the following two lines to enable this setting.
#FILENAME='.duplicity-ignore'
#DUPL_PARAMS="\$DUPL_PARAMS --exclude-if-present '\$FILENAME'"
# Time frame for old backups to keep, Used for the "purge" command.
# see duplicity man page, chapter TIME_FORMATS)
#MAX_AGE=1M
# Number of full backups to keep. Used for the "purge-full" command.
# See duplicity man page, action "remove-all-but-n-full".
#MAX_FULL_BACKUPS=1
# Number of full backups for which incrementals will be kept for.
# Used for the "purge-incr" command.
# See duplicity man page, action "remove-all-inc-of-but-n-full".
#MAX_FULLS_WITH_INCRS=1
# activates duplicity --full-if-older-than option (since duplicity v0.4.4.RC3)
# forces a full backup if last full backup reaches a specified age, for the
# format of MAX_FULLBKP_AGE see duplicity man page, chapter TIME_FORMATS
# Uncomment the following two lines to enable this setting.
#MAX_FULLBKP_AGE=1M
#DUPL_PARAMS="\$DUPL_PARAMS --full-if-older-than \$MAX_FULLBKP_AGE "
# sets duplicity --volsize option (available since v0.4.3.RC7)
# set the size of backup chunks to VOLSIZE MB instead of the default 25MB.
# VOLSIZE must be number of MB's to set the volume size to.
# Uncomment the following two lines to enable this setting.
#VOLSIZE=50
#DUPL_PARAMS="\$DUPL_PARAMS --volsize \$VOLSIZE "
# verbosity of output (error 0, warning 1-2, notice 3-4, info 5-8, debug 9)
# default is 4, if not set
#VERBOSITY=5
# temporary file space. at least the size of the biggest file in backup
# for a successful restoration process. (default is '/tmp', if not set)
#TEMP_DIR=/tmp
# Modifies archive-dir option (since 0.6.0) Defines a folder that holds
# unencrypted meta data of the backup, enabling new incrementals without the
# need to decrypt backend metadata first. If empty or deleted somehow, the
# private key and it's password are needed.
# NOTE: This is confidential data. Put it somewhere safe. It can grow quite
# big over time so you might want to put it not in the home dir.
# default '~/.cache/duplicity/duply_<profile>/'
# if set '\${ARCH_DIR}/<profile>'
#ARCH_DIR=/some/space/safe/.duply-cache
# DEPRECATED setting
# sets duplicity --time-separator option (since v0.4.4.RC2) to allow users
# to change the time separator from ':' to another character that will work
# on their system. HINT: For Windows SMB shares, use --time-separator='_'.
# NOTE: '-' is not valid as it conflicts with date separator.
# ATTENTION: only use this with duplicity < 0.5.10, since then default file
# naming is compatible and this option is pending depreciation
#DUPL_PARAMS="\$DUPL_PARAMS --time-separator _ "
# DEPRECATED setting
# activates duplicity --short-filenames option, when uploading to a file
# system that can't have filenames longer than 30 characters (e.g. Mac OS 8)
# or have problems with ':' as part of the filename (e.g. Microsoft Windows)
# ATTENTION: only use this with duplicity < 0.5.10, later versions default file
# naming is compatible and this option is pending depreciation
#DUPL_PARAMS="\$DUPL_PARAMS --short-filenames "
# more duplicity command line options can be added in the following way
# don't forget to leave a separating space char at the end
#DUPL_PARAMS="\$DUPL_PARAMS --put_your_options_here "
EOF
# create initial exclude file
cat <<EOF >"$EXCLUDE"
# although called exclude, this file is actually a globbing file list
# duplicity accepts some globbing patterns, even including ones here
# here is an example, this incl. only 'dir/bar' except it's subfolder 'foo'
# - dir/bar/foo
# + dir/bar
# - **
# for more details see duplicity manpage, section File Selection
# http://duplicity.nongnu.org/duplicity.1.html#sect9
EOF
# Hints on first usage
cat <<EOF
Congratulations. You just created the profile '$FTPLCFG'.
The initial config file has been created as
'$CONF'.
You should now adjust this config file to your needs.
$(hint_profile)
EOF
fi
}
# used in usage AND create_config
function hint_profile {
cat <<EOF
IMPORTANT:
Copy the _whole_ profile folder after the first backup to a safe place.
It contains everything needed to restore your backups. You will need
it if you have to restore the backup from another system (e.g. after a
system crash). Keep access to these files restricted as they contain
_all_ informations (gpg data, ftp data) to access and modify your backups.
Repeat this step after _all_ configuration changes. Some configuration
options are crucial for restoration.
EOF
}
function separator {
echo "--- $@ ---"
}
function inform {
echo -e "\nINFO:\n\n$@\n"
}
function warning {
echo -e "\nWARNING:\n\n$@\n"
}
function warning_oldhome {
local old=$1 new=$2
warning " ftplicity changed name to duply since you created your profiles.
Please rename the old folder
'$old'
to
'$new'
and this warning will disappear.
If you decide not to do so profiles will _only_ work from the old location."
}