2 # Desc: Utility for backing up and retrieving ots files
5 OTS_FCACHE_DIR
="$HOME/.cache/bkotslu/";
8 yell
() { echo "$0: $*" >&2; } # print script path and all args to stderr
9 die
() { yell
"$*"; exit 111; } # same as yell() but non-zero exit status
10 must
() { "$@" || die
"cannot $*"; } # runs args as command, reports args if command fails
12 # Description: Prints verbose message ("vbm") to stderr if opVerbose is set to "true".
13 # Usage: vbm "DEBUG :verbose message here"
18 # Depends: bash 5.1.16, GNU-coreutils 8.30 (echo, date)
20 if [ "$opVerbose" = "true" ]; then
21 functionTime
="$(date --iso-8601=ns)"; # Save current time in nano seconds.
22 echo "[$functionTime]:$0:""$*" 1>&2; # Display argument text.
26 return 0; # Function finished.
27 }; # Displays message if opVerbose true
29 # Desc: Display script usage information
34 # Depends: GNU-coreutils 8.30 (cat)
37 bkotslu [ options ] [FILE...]
41 Display help information.
43 Display script version.
45 Display debugging info.
47 Define input file path for file to add ots file to.
49 Define output directory path for storing ots backup files.
50 DEFAULT: $HOME/.cache/bkotslu/
52 Indicate end of options.
55 Hash foo.txt and lookup matching ots file
58 Archive ots files from home directory
62 }; # Display information on how to use this script.
64 # Desc: Displays script version and license information.
67 # Input: scriptVersion var containing version string
69 # Depends: vbm(), yell, GNU-coreutils 8.30
72 vbm
"DEBUG:showVersion function called."
76 Copyright (C) 2024 Steven Baltakatei Sandoval
77 License GPLv3: GNU GPL version 3
78 This is free software; you are free to change and redistribute it.
79 There is NO WARRANTY, to the extent permitted by law.
82 Copyright (C) 2020 Free Software Foundation, Inc.
83 License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
84 This is free software: you are free to change and redistribute it.
85 There is NO WARRANTY, to the extent permitted by law.
89 vbm
"DEBUG:showVersion function ended."
90 return 0; # Function finished.
91 }; # Display script version.
93 # Desc: Processes arguments provided to script.
94 # Usage: processArgs "$@"
96 # Input: "$@" (list of arguments provided to the function)
97 # Output: Sets following variables used by other functions:
98 # opVerbose Indicates verbose mode enable status. (ex: "true", "false")
99 # pathDirOut1 Path to output directory.
100 # pathDirIn1 Path to input directory.
101 # pathFileIn1 Path to input file.
102 # arrayPosArgs Array of remaining positional argments
104 # yell() Displays messages to stderr.
105 # vbm() Displays messsages to stderr if opVerbose set to "true".
106 # showUsage() Displays usage information about parent script.
107 # showVersion() Displays version about parent script.
108 # arrayPosArgs Global array for storing non-option positional arguments (i.e. arguments following the `--` option).
109 # External dependencies: bash (5.1.16), echo
111 # [1]: Marco Aurelio (2014-05-08). "echo that outputs to stderr". https://stackoverflow.com/a/23550347
112 # [2]: "Handling positional parameters" (2018-05-12). https://wiki.bash-hackers.org/scripting/posparams
114 # Initialize function
115 vbm
"DEBUG:processArgs function called."
118 if [ $# -le 0 ]; then yell
"FATAL:No arguments provided."; showUsage
; fi;
119 while [ ! $# -eq 0 ]; do # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
120 #yell "DEBUG:Starting processArgs while loop." # Debug stderr message. See [1].
121 #yell "DEBUG:Provided arguments are:""$*" # Debug stderr message. See [1].
123 -h |
--help) showUsage
; exit 1;; # Display usage.
124 --version) showVersion
; exit 1;; # Show version
125 -v |
--verbose) opVerbose
="true"; vbm
"DEBUG:Verbose mode enabled.";; # Enable verbose mode. See [1].
126 -i |
--input-file) # Define input file path
127 if [ -f "$2" ]; then # If $2 is file that exists, set pathFileIn1 to $2, pop $2.
129 vbm
"DEBUG:Input file pathFileIn1 set to:${pathFileIn1}";
132 die
"FATAL: Specified input file does not exist:$2";
134 -I |
--input-dir) # Define input directory path
135 if [ -d "$2" ]; then # If $2 is dir that exists, set pathDirIn1 to $2, pop $2.
137 vbm
"DEBUG:Input directory pathDirIn1 set to:${pathDirIn1}";
139 else # Display error if $2 is not a valid dir.
140 die
"FATAL:Specified input directory does not exist:$2";
142 -O |
--output-dir) # Define output directory path
143 if [ -d "$2" ]; then # If $2 is dir that exists, set pathDirOut1 to $2, pop $2
145 vbm
"DEBUG:Output directory pathDirOut1 set to:${pathDirOut1}";
148 die
"FATAL:Specified output directory is not valid:$2";
150 --) # End of all options. See [2].
153 vbm
"DEBUG:adding to arrayPosArgs:$arg";
154 arrayPosArgs
+=("$arg");
157 -*) showUsage
; die
"FATAL: Unrecognized option.";; # Display usage
158 *) showUsage
; die
"FATAL: Unrecognized argument.";; # Handle unrecognized options. See [1].
163 ## Identify ots file cache dir
164 if [[ -z "$pathDirOut1" ]]; then
165 vbm
"STATUS:No output directory for caching OTS files specified.";
166 pathDirOut1
="$OTS_FCACHE_DIR";
167 vbm
"STATUS:Assuming OTS files to be cached in:${pathDirOut1}";
169 ## Create cache dir if necessary
170 if [[ ! -d "$pathDirOut1" ]]; then
171 vbm
"STATUS:Creating OTS file cache directory:${pathDirOut1}";
172 must mkdir
-p "$pathDirOut1";
176 vbm
"DEBUG:processArgs function ended.";
177 return 0; # Function finished.
178 }; # Evaluate script options from positional arguments (ex: $1, $2, $3, etc.).
180 # Desc: Gets hash of an opentimestamp'd file from ots file
181 # Usage: get_ots_filehash FILE
182 # Example: get_ots_filehash foo.txt.ots
183 # Depends: ots 0.7.0, GNU grep 3.7, GNU Coreutils 8.32
184 # vbm() verbose output
186 # Input: arg1 OTS file path
187 # Output: stdout sha256 file hash (lowercase)
190 vbm
"DEBUG:Starting get_ots_filehash() on:$1";
191 if output
="$( "$
(which ots
)" info "$1" | \
192 grep -E "^File sha256
hash: " | \
194 sed -E -e 's/(^File sha256 hash: )([0-9a-f]+$)/\2/g'; )" && \
195 [[ -n "$output" ]]; then
196 vbm
"STATUS:Read file hash via ots from:$1";
197 printf "%s" "$output";
200 yell
"ERROR:Encountered problem getting file hash via ots from:$1";
203 }; # Gets hash of file from ots file
204 get_ots_oldestblock
() {
205 # Desc: Gets earliest Bitcoin block number from ots file
206 # Usage: get_ots_oldestblock FILE
207 # Example: get_ots_oldestblock foo.txt.ots
208 # Input: arg1 path OTS file path
209 # Output: stdout int Bitcoin block number
210 # Depends: OpenTimestamps 0.7.0, GNU grep 3.7, GNU Coreutils 8.32
215 vbm
"DEBUG:Starting get_ots_oldestblock() on:$1";
216 if output
="$( "$
(which ots
)" info "$1" | \
217 grep -E "verify BitcoinBlockHeaderAttestation\
([0-9]+\
)" | \
219 sed -E -e 's/(^ verify BitcoinBlockHeaderAttestation)\(([0-9]+)(\))/\2/g'; )" && \
220 [[ -n "$output" ]]; then
221 vbm
"STATUS:Retrieved Bitcoin block via ots from:$1";
222 printf "%s" "$output";
225 yell
"ERROR:Encountered problem getting Bitcoin block number via ots from:$1";
228 }; # Gets oldest Bitcoin block from ots file
230 # Desc: Scans and caches an OTS file for storing
231 if fhash
="$(must get_ots_filehash "$line")" && \
232 block
="$(must get_ots_oldestblock "$line")"; then
233 fout
="${fhash}_${block}.otsu"; # file name out
234 pout
="${pathDirOut1}/${fout}"; # file path out
235 vbm
"STATUS:Found OTS file at ${line} with hash ${fhash} and block ${block} and saving to ${pout}";
236 must
cp -n "$line" "$pout";
238 yell
"ERROR:Problem analyzing file with OpenTimestamps:${line}";
240 }; # Scans a single OTS file
246 # Scan provided dir for OTS files to cache.
247 if [[ -n "$pathDirIn1" ]]; then
248 while read -r line
; do
249 line
="$(readlink -f "$line")";
251 done < <(find "$pathDirIn1" -maxdepth "$MAX_FIND_DEPTH" -type f
-name "*.ots");
254 # Lookup OTS file from archive for provided file.
255 if [[ -n "$pathFileIn1" ]]; then