fix(bklog):Fix debug and status messages
[EVA-2020-02.git] / exec / bklog
CommitLineData
6cbe7c0a
SBS
1#!/bin/bash
2# Desc: Compresses, encrypts, and writes stdin every 5 seconds
3
5938a598
SBS
4#==BEGIN Define script parameters==
5#===BEGIN Initialize variables===
adf766fc 6
5938a598 7# Logging Behavior parameters
c5da633d 8bufferTTL="300"; # Time-to-live (seconds) for each buffer round
adf766fc 9scriptTTL_TE="day"; # Time element at the end of which script terminates
c5da633d 10dirTmpDefault="/dev/shm"; # Default parent of working directory
5938a598
SBS
11
12# Script Metadata
5938a598 13scriptName="bklog"; # Define basename of script file.
a2c47ccf 14scriptVersion="0.1.23"; # Define version of script.
c5da633d
SBS
15scriptURL="https://gitlab.com/baltakatei/ninfacyzga-01"; # Define wesite hosting this script.
16scriptTimeStart="$(date +%Y%m%dT%H%M%S.%N)"; # YYYYmmddTHHMMSS.NNNNNNNNN
17scriptHostname=$(hostname); # Save hostname of system running this script.
18PATH="$HOME/.local/bin:$PATH"; # Add "$(systemd-path user-binaries)" path in case user apps saved there
19ageVersion="1.0.0-beta2"; # Define version of age (encryption program)
20ageURL="https://github.com/FiloSottile/age/releases/tag/v1.0.0-beta2"; # Define website hosting age.
5938a598
SBS
21
22# Arrays
c5da633d
SBS
23declare -a buffer # array for storing while read buffer
24declare -a argRecPubKeys # array for processArguments function
25declare -a recPubKeysValid # array for storing both '-r' and '-R' recipient pubkeys
c5da633d
SBS
26declare -a argProcStrings argProcFileExts # for storing buffer processing strings (ex: "gpsbabel -i nmea -f - -o gpx -F - ")
27declare -Ag appRollCall # Associative array for storing app status
28declare -Ag fileRollCall # Associative array for storing file status
29declare -Ag dirRollCall # Associative array for storing dir status
30declare -a procStrings procFileExts # Arrays for storing processing commands and resulting output file extensions
5938a598
SBS
31
32# Variables
c5da633d
SBS
33optionVerbose=""; optionEncrypt=""; dirOut=""; optionEncrypt=""; dir_tmp="";
34cmd_compress="";cmd_compress_suffix=""; cmd_encrypt=""; cmd_encrypt_suffix="";
5938a598
SBS
35
36#===END Initialize variables===
37
38#===BEGIN Declare local script functions===
6cbe7c0a
SBS
39yell() { echo "$0: $*" >&2; } #o Yell, Die, Try Three-Fingered Claw technique
40die() { yell "$*"; exit 111; } #o Ref/Attrib: https://stackoverflow.com/a/25515370
41try() { "$@" || die "cannot $*"; } #o
c5da633d
SBS
42processArguments() {
43 while [ ! $# -eq 0 ]; do # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
44 case "$1" in
fcefae4c 45 -v | --verbose) optionVerbose="true"; vbm "DEBUG :Verbose mode enabled.";; # Enable verbose mode.
c5da633d
SBS
46 -h | --help) showUsage; exit 1;; # Display usage.
47 --version) showVersion; exit 1;; # Show version
fcefae4c
SBS
48 -o | --output) if [ -d "$2" ]; then dirOut="$2"; vbm "DEBUG :dirOut:$dirOut"; shift; fi ;; # Define output directory.
49 -e | --encrypt) optionEncrypt="true"; vbm "DEBUG :Encrypted output mode enabled.";; # Enable encryption
236c8b97
SBS
50 -r | --recipient) optionRecArg="true"; argRecPubKeys+=("$2"); vbm "STATUS:pubkey added:""$2"; shift;; # Add recipients
51 -R | --recipient-dir) optionRecDir="true" && argRecDir="$2"; shift;; # Add recipient watch dir
fcefae4c 52 -c | --compress) optionCompress="true"; vbm "DEBUG :Compressed output mode enabled.";; # Enable compression
c5da633d
SBS
53 -z | --time-zone) try setTimeZoneEV "$2"; shift;; # Set timestamp timezone
54 -t | --temp-dir) optionTmpDir="true" && argTempDirPriority="$2"; shift;; # Set time zone
c5da633d
SBS
55 -b | --buffer-ttl) optionCustomBufferTTL="true" && argCustomBufferTTL="$2"; shift;; # Set custom buffer period (default: 300 seconds)
56 -B | --script-ttl) optionCustomScriptTTL_TE="true" && argCustomScriptTTL_TE="$2"; shift;; # Set custom script TTL (default: "day")
a2c47ccf 57 -p | --process-string) optionProcString="true" && argProcStrings+=("$2") && argProcFileExts+=("$3") && vbm "STATUS:file extension \"$3\" for output of processing string added:\"$2\""; shift; shift;;
fcefae4c
SBS
58 -l | --label) optionLabel="true" && argLabel="$2"; vbm "DEBUG :Custom label received:$argLabel"; shift;;
59 -w | --store-raw) optionStoreRaw="true" && argRawFileExt="$2"; vbm "DEBUG :Raw stdin file extension received:$argRawFileExt"; shift;;
60 -W | --no-store-raw) optionNoStoreRaw="true"; vbm "DEBUG :Option selected to not store raw stdin data."; shift;;
c5da633d
SBS
61 *) yell "ERROR: Unrecognized argument: $1"; yell "STATUS:All arguments:$*"; exit 1;; # Handle unrecognized options.
62 esac
63 shift
64 done
65} # Argument Processing
66vbm() {
67 # Description: Prints verbose message ("vbm") to stderr if optionVerbose is set to "true".
fcefae4c 68 # Usage: vbm "DEBUG :verbose message here"
c5da633d
SBS
69 # Version 0.1.2
70 # Input: arg1: string
71 # vars: optionVerbose
72 # Output: stderr
73 # Depends: bash 5.0.3, echo 8.30, date 8.30
74
75 if [ "$optionVerbose" = "true" ]; then
76 functionTime=$(date --iso-8601=ns); # Save current time in nano seconds.
77 echo "[$functionTime] ""$*" 1>&2; # Display argument text.
78 fi
79
80 # End function
81 return 0; # Function finished.
82} # Displays message if optionVerbose true
83checkapp() {
84 # Desc: If arg is a command, save result in assoc array 'appRollCall'
85 # Usage: checkapp arg1 arg2 arg3 ...
86 # Version: 0.1.1
87 # Input: global assoc. array 'appRollCall'
88 # Output: adds/updates key(value) to global assoc array 'appRollCall'
89 # Depends: bash 5.0.3
90 local returnState
91
92 #===Process Args===
93 for arg in "$@"; do
94 if command -v "$arg" 1>/dev/null 2>&1; then # Check if arg is a valid command
95 appRollCall[$arg]="true";
96 if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
97 else
98 appRollCall[$arg]="false"; returnState="false";
99 fi;
100 done;
101
102 #===Determine function return code===
103 if [ "$returnState" = "true" ]; then
104 return 0;
105 else
106 return 1;
107 fi;
108} # Check that app exists
109checkfile() {
110 # Desc: If arg is a file path, save result in assoc array 'fileRollCall'
111 # Usage: checkfile arg1 arg2 arg3 ...
112 # Version: 0.1.1
113 # Input: global assoc. array 'fileRollCall'
114 # Output: adds/updates key(value) to global assoc array 'fileRollCall';
115 # Output: returns 0 if app found, 1 otherwise
116 # Depends: bash 5.0.3
117 local returnState
118
119 #===Process Args===
120 for arg in "$@"; do
121 if [ -f "$arg" ]; then
122 fileRollCall["$arg"]="true";
123 if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
124 else
125 fileRollCall["$arg"]="false"; returnState="false";
126 fi;
127 done;
128
129 #===Determine function return code===
130 if [ "$returnState" = "true" ]; then
131 return 0;
132 else
133 return 1;
134 fi;
135} # Check that file exists
136checkdir() {
137 # Desc: If arg is a dir path, save result in assoc array 'dirRollCall'
138 # Usage: checkdir arg1 arg2 arg3 ...
139 # Version 0.1.1
140 # Input: global assoc. array 'dirRollCall'
141 # Output: adds/updates key(value) to global assoc array 'dirRollCall';
142 # Output: returns 0 if app found, 1 otherwise
143 # Depends: Bash 5.0.3
144 local returnState
145
146 #===Process Args===
147 for arg in "$@"; do
148 if [ -d "$arg" ]; then
149 dirRollCall["$arg"]="true";
150 if ! [ "$returnState" = "false" ]; then returnState="true"; fi
151 else
152 dirRollCall["$arg"]="false"; returnState="false";
153 fi
154 done
155
156 #===Determine function return code===
157 if [ "$returnState" = "true" ]; then
158 return 0;
159 else
160 return 1;
161 fi
162} # Check that dir exists
163displayMissing() {
164 # Desc: Displays missing apps, files, and dirs
165 # Usage: displayMissing
166 # Version 0.1.1
167 # Input: associative arrays: appRollCall, fileRollCall, dirRollCall
168 # Output: stderr: messages indicating missing apps, file, or dirs
169 # Depends: bash 5, checkAppFileDir()
170 local missingApps value appMissing missingFiles fileMissing
171 local missingDirs dirMissing
172
173 #==BEGIN Display errors==
174 #===BEGIN Display Missing Apps===
175 missingApps="Missing apps :";
fcefae4c 176 #for key in "${!appRollCall[@]}"; do echo "DEBUG :$key => ${appRollCall[$key]}"; done
c5da633d
SBS
177 for key in "${!appRollCall[@]}"; do
178 value="${appRollCall[$key]}";
179 if [ "$value" = "false" ]; then
fcefae4c 180 #echo "DEBUG :Missing apps: $key => $value";
c5da633d
SBS
181 missingApps="$missingApps""$key ";
182 appMissing="true";
183 fi;
184 done;
185 if [ "$appMissing" = "true" ]; then # Only indicate if an app is missing.
186 echo "$missingApps" 1>&2;
187 fi;
188 unset value;
189 #===END Display Missing Apps===
190
191 #===BEGIN Display Missing Files===
192 missingFiles="Missing files:";
fcefae4c 193 #for key in "${!fileRollCall[@]}"; do echo "DEBUG :$key => ${fileRollCall[$key]}"; done
c5da633d
SBS
194 for key in "${!fileRollCall[@]}"; do
195 value="${fileRollCall[$key]}";
196 if [ "$value" = "false" ]; then
fcefae4c 197 #echo "DEBUG :Missing files: $key => $value";
c5da633d
SBS
198 missingFiles="$missingFiles""$key ";
199 fileMissing="true";
200 fi;
201 done;
202 if [ "$fileMissing" = "true" ]; then # Only indicate if an app is missing.
203 echo "$missingFiles" 1>&2;
204 fi;
205 unset value;
206 #===END Display Missing Files===
207
208 #===BEGIN Display Missing Directories===
209 missingDirs="Missing dirs:";
fcefae4c 210 #for key in "${!dirRollCall[@]}"; do echo "DEBUG :$key => ${dirRollCall[$key]}"; done
c5da633d
SBS
211 for key in "${!dirRollCall[@]}"; do
212 value="${dirRollCall[$key]}";
213 if [ "$value" = "false" ]; then
fcefae4c 214 #echo "DEBUG :Missing dirs: $key => $value";
c5da633d
SBS
215 missingDirs="$missingDirs""$key ";
216 dirMissing="true";
217 fi;
218 done;
219 if [ "$dirMissing" = "true" ]; then # Only indicate if an dir is missing.
220 echo "$missingDirs" 1>&2;
221 fi;
222 unset value;
223 #===END Display Missing Directories===
224
225 #==END Display errors==
226} # Display missing apps, files, dirs
79bb6c16 227
7cebebc2
SBS
228appendArgTar(){
229 # Desc: Writes first argument to temporary file with arguments as options, then appends file to tar
230 # Usage: appendArgTar "$(echo "Data to be written.")" [name of file to be inserted] [tar path] [temp dir] ([cmd1] [cmd2] [cmd3] [cmd4]...)
231 # Version: 1.0.6
232 # Input: arg1: data to be written
233 # arg2: file name of file to be inserted into tar
234 # arg3: tar archive path (must exist first)
235 # arg4: temporary working dir
236 # arg5+: command strings (ex: "gpsbabel -i nmea -f - -o kml -F - ")
237 # Output: file written to disk
238 # Example: decrypt multiple large files in parallel
239 # appendArgTar "$(cat /tmp/largefile1.gpg)" "largefile1" $HOME/archive.tar /tmp "gpg --decrypt" &
240 # appendArgTar "$(cat /tmp/largefile2.gpg)" "largefile2" $HOME/archive.tar /tmp "gpg --decrypt" &
241 # appendArgTar "$(cat /tmp/largefile3.gpg)" "largefile3" $HOME/archive.tar /tmp "gpg --decrypt" &
242 # Depends: bash 5, tar 1, yell()
243 # Ref/Attrib: Using 'eval' to construct command strings https://askubuntu.com/a/476533
244
245 local fn fileName tarPath tmpDir cmd0 cmd1 cmd2 cmd3 cmd4
246
247 # Save function name
248 fn="${FUNCNAME[0]}";
249 #yell "DEBUG:STATUS:$fn:Finished appendArgTar()."
250
251 # Set file name
252 if ! [ -z "$2" ]; then fileName="$2"; else yell "ERROR:$fn:Not enough arguments."; exit 1; fi
253
254 # Check tar path is a file
255 if [ -f "$3" ]; then tarPath="$3"; else yell "ERROR:$fn:Tar archive arg not a file."; exit 1; fi
256
257 # Check temp dir arg
258 if ! [ -z "$4" ]; then tmpDir="$4"; else yell "ERROR:$fn:No temporary working dir set."; exit 1; fi
259
260 # Set command strings
261 if ! [ -z "$5" ]; then cmd1="$5"; else cmd1="cat "; fi # command string 1
262 if ! [ -z "$6" ]; then cmd2="$6"; else cmd2="cat "; fi # command string 2
263 if ! [ -z "$7" ]; then cmd3="$7"; else cmd3="cat "; fi # command string 3
264 if ! [ -z "$8" ]; then cmd4="$8"; else cmd4="cat "; fi # command string 4
265
266 # Input command
267 cmd0="echo \"\$1\""
268
269 # # Debug
270 # yell "DEBUG:STATUS:$fn:cmd0:$cmd0"
271 # yell "DEBUG:STATUS:$fn:cmd1:$cmd1"
272 # yell "DEBUG:STATUS:$fn:cmd2:$cmd2"
273 # yell "DEBUG:STATUS:$fn:cmd3:$cmd3"
274 # yell "DEBUG:STATUS:$fn:cmd4:$cmd4"
275 # yell "DEBUG:STATUS:$fn:fileName:$fileName"
276 # yell "DEBUG:STATUS:$fn:tarPath:$tarPath"
277 # yell "DEBUG:STATUS:$fn:tmpDir:$tmpDir"
278
279 # Write to temporary working dir
280 eval "$cmd0 | $cmd1 | $cmd2 | $cmd3 | $cmd4" > "$tmpDir"/"$fileName";
281
282 # Append to tar
283 try tar --append --directory="$tmpDir" --file="$tarPath" "$fileName";
284 #yell "DEBUG:STATUS:$fn:Finished appendArgTar()."
285} # Append Bash var to file appended to Tar archive
79bb6c16
SBS
286appendFileTar(){
287 # Desc: Appends [processed] file to tar
288 # Usage: appendFileTar [file path] [name of file to be inserted] [tar path] [temp dir] ([process cmd])
289 # Version: 2.0.1
290 # Input: arg1: path of file to be (processed and) written
291 # arg2: name to use for file inserted into tar
292 # arg3: tar archive path (must exist first)
293 # arg4: temporary working dir
294 # arg5: (optional) command string to process file (ex: "gpsbabel -i nmea -f - -o kml -F - ")
295 # Output: file written to disk
296 # Example: decrypt multiple large files in parallel
297 # appendFileTar /tmp/largefile1.gpg "largefile1" $HOME/archive.tar /tmp "gpg --decrypt" &
298 # appendFileTar /tmp/largefile2.gpg "largefile2" $HOME/archive.tar /tmp "gpg --decrypt" &
299 # appendFileTar /tmp/largefile3.gpg "largefile3" $HOME/archive.tar /tmp "gpg --decrypt" &
300 # Depends: bash 5.0.3, tar 1.30, cat 8.30, yell()
301 local fn fileName tarPath tmpDir
302
303 # Save function name
304 fn="${FUNCNAME[0]}";
fcefae4c 305 #yell "DEBUG :STATUS:$fn:Started appendFileTar()."
79bb6c16
SBS
306
307 # Set file name
308 if ! [ -z "$2" ]; then fileName="$2"; else yell "ERROR:$fn:Not enough arguments."; exit 1; fi
309 # Check tar path is a file
310 if [ -f "$3" ]; then tarPath="$3"; else yell "ERROR:$fn:Tar archive arg not a file:$3"; exit 1; fi
311 # Check temp dir arg
312 if ! [ -z "$4" ]; then tmpDir="$4"; else yell "ERROR:$fn:No temporary working dir set."; exit 1; fi
313 # Set command strings
314 if ! [ -z "$5" ]; then cmd1="$5"; else cmd1="cat "; fi # command string
315
316 # Input command string
317 cmd0="cat \"\$1\"";
318
319 # Write to temporary working dir
320 eval "$cmd0 | $cmd1" > "$tmpDir"/"$fileName";
321
322 # Append to tar
323 try tar --append --directory="$tmpDir" --file="$tarPath" "$fileName";
fcefae4c 324 #yell "DEBUG :STATUS:$fn:Finished appendFileTar()."
79bb6c16
SBS
325} # Append [processed] file to Tar archive
326checkAgePubkey() {
327 # Desc: Checks if string is an age-compatible pubkey
328 # Usage: checkAgePubkey [str pubkey]
329 # Version: 0.1.2
330 # Input: arg1: string
331 # Output: return code 0: string is age-compatible pubkey
332 # return code 1: string is NOT an age-compatible pubkey
333 # age stderr (ex: there is stderr if invalid string provided)
334 # Depends: age (v0.1.0-beta2; https://github.com/FiloSottile/age/releases/tag/v1.0.0-beta2 )
335
336 argPubkey="$1";
337
338 if echo "test" | age -a -r "$argPubkey" 1>/dev/null; then
339 return 0;
340 else
341 return 1;
342 fi;
343} # Check age pubkey
34711384
SBS
344checkMakeTar() {
345 # Desc: Checks that a valid tar archive exists, creates one otherwise
346 # Usage: checkMakeTar [ path ]
347 # Version: 1.0.2
348 # Input: arg1: path of tar archive
349 # Output: exit code 0 : tar readable
350 # exit code 1 : tar missing; created
351 # exit code 2 : tar not readable; moved; replaced
352 # Depends: bash 5, date 8, tar 1, try()
353 local pathTar returnFlag0 returnFlag1 returnFlag2
354 pathTar="$1";
355
356 # Check if file is a valid tar archive
357 if tar --list --file="$pathTar" 1>/dev/null 2>&1; then
358 ## T1: return success
359 returnFlag0="tar valid";
360 else
361 ## F1: Check if file exists
362 if [[ -f "$pathTar" ]]; then
363 ### T: Rename file
364 try mv "$pathTar" "$pathTar""--broken--""$(date +%Y%m%dT%H%M%S)" && \
365 returnFlag1="tar moved";
366 else
367 ### F: -
368 :
369 fi;
370 ## F2: Create tar archive, return 0
371 try tar --create --file="$pathTar" --files-from=/dev/null && \
372 returnFlag2="tar created";
373 fi;
374
375 # Determine function return code
376 if [[ "$returnFlag0" = "tar valid" ]]; then
377 return 0;
378 elif [[ "$returnFlag2" = "tar created" ]] && ! [[ "$returnFlag1" = "tar moved" ]]; then
379 return 1; # tar missing so created
380 elif [[ "$returnFlag2" = "tar created" ]] && [[ "$returnFlag1" = "tar moved" ]]; then
381 return 2; # tar not readable so moved; replaced
382 fi;
383} # checks if arg1 is tar; creates one otherwise
79bb6c16
SBS
384dateShort(){
385 # Desc: Date without separators (YYYYmmdd)
386 # Usage: dateShort ([str date])
387 # Version: 1.1.2
388 # Input: arg1: 'date'-parsable timestamp string (optional)
389 # Output: stdout: date (ISO-8601, no separators)
390 # Depends: bash 5.0.3, date 8.30, yell()
391 local argTime timeCurrent timeInput dateCurrentShort
392
393 argTime="$1";
394 # Get Current Time
395 timeCurrent="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
396 # Decide to parse current or supplied date
397 ## Check if time argument empty
398 if [[ -z "$argTime" ]]; then
399 ## T: Time argument empty, use current time
400 timeInput="$timeCurrent";
401 else
402 ## F: Time argument exists, validate time
403 if date --date="$argTime" 1>/dev/null 2>&1; then
404 ### T: Time argument is valid; use it
405 timeInput="$argTime";
406 else
407 ### F: Time argument not valid; exit
408 yell "ERROR:Invalid time argument supplied. Exiting."; exit 1;
409 fi;
410 fi;
411 # Construct and deliver separator-les date string
412 dateCurrentShort="$(date -d "$timeInput" +%Y%m%d)"; # Produce separator-less current date with resolution 1 day.
413 echo "$dateCurrentShort";
414} # Get YYYYmmdd
8681fe1b
SBS
415dateTimeShort(){
416 # Desc: Timestamp without separators (YYYYmmddTHHMMSS+zzzz)
417 # Usage: dateTimeShort ([str date])
418 # Version 1.1.1
419 # Input: arg1: 'date'-parsable timestamp string (optional)
420 # Output: stdout: timestamp (ISO-8601, no separators)
421 # Depends: yell
422 local argTime timeCurrent timeInput timeCurrentShort
423
424 argTime="$1";
425 # Get Current Time
426 timeCurrent="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
427 # Decide to parse current or supplied date
428 ## Check if time argument empty
429 if [[ -z "$argTime" ]]; then
430 ## T: Time argument empty, use current time
431 timeInput="$timeCurrent";
432 else
433 ## F: Time argument exists, validate time
434 if date --date="$argTime" 1>/dev/null 2>&1; then
435 ### T: Time argument is valid; use it
436 timeInput="$argTime";
437 else
438 ### F: Time argument not valid; exit
439 yell "ERROR:Invalid time argument supplied. Exiting."; exit 1;
440 fi
441 fi
442 # Construct and deliver separator-les date string
443 timeCurrentShort="$(date -d "$timeInput" +%Y%m%dT%H%M%S%z)";
444 echo "$timeCurrentShort";
445} # Get YYYYmmddTHHMMSS±zzzz
79bb6c16
SBS
446setTimeZoneEV(){
447 # Desc: Set time zone environment variable TZ
448 # Usage: setTimeZoneEV arg1
449 # Version 0.1.2
450 # Input: arg1: 'date'-compatible timezone string (ex: "America/New_York")
451 # TZDIR env var (optional; default: "/usr/share/zoneinfo")
452 # Output: exports TZ
453 # exit code 0 on success
454 # exit code 1 on incorrect number of arguments
455 # exit code 2 if unable to validate arg1
456 # Depends: yell(), printenv 8.30, bash 5.0.3
457 # Tested on: Debian 10
458 local tzDir returnState argTimeZone
459
460 argTimeZone="$1"
461 if ! [[ $# -eq 1 ]]; then
462 yell "ERROR:Invalid argument count.";
463 return 1;
464 fi
465
466 # Read TZDIR env var if available
467 if printenv TZDIR 1>/dev/null 2>&1; then
468 tzDir="$(printenv TZDIR)";
469 else
470 tzDir="/usr/share/zoneinfo";
471 fi
472
473 # Validate TZ string
474 if ! [[ -f "$tzDir"/"$argTimeZone" ]]; then
475 yell "ERROR:Invalid time zone argument.";
476 return 2;
477 else
478 # Export ARG1 as TZ environment variable
479 TZ="$argTimeZone" && export TZ && returnState="true";
480 fi
481
482 # Determine function return code
483 if [ "$returnState" = "true" ]; then
484 return 0;
485 fi
486} # Exports TZ environment variable
c5da633d
SBS
487showVersion() {
488 yell "$scriptVersion"
489} # Display script version.
4e4707fb
SBS
490timeDuration(){
491 # Desc: Given seconds, output ISO-8601 duration string
492 # Ref/Attrib: ISO-8601:2004(E), §4.4.4.2 Representations of time intervals by duration and context information
493 # Note: "1 month" ("P1M") is assumed to be "30 days" (see ISO-8601:2004(E), §2.2.1.2)
494 # Usage: timeDuration [1:seconds] ([2:precision])
495 # Version: 1.0.4
496 # Input: arg1: seconds as base 10 integer >= 0 (ex: 3601)
497 # arg2: precision level (optional; default=2)
498 # Output: stdout: ISO-8601 duration string (ex: "P1H1S", "P2Y10M15DT10H30M20S")
499 # exit code 0: success
500 # exit code 1: error_input
501 # exit code 2: error_unknown
502 # Example: 'timeDuration 111111 3' yields 'P1DT6H51M'
503 # Depends: date 8, bash 5, yell,
504 local argSeconds argPrecision precision returnState remainder
505 local fullYears fullMonths fullDays fullHours fullMinutes fullSeconds
506 local hasYears hasMonths hasDays hasHours hasMinutes hasSeconds
507 local witherPrecision output
508 local displayYears displayMonths displayDays displayHours displayMinutes displaySeconds
509
510 argSeconds="$1"; # read arg1 (seconds)
511 argPrecision="$2"; # read arg2 (precision)
512 precision=2; # set default precision
513
514 # Check that between one and two arguments is supplied
515 if ! { [[ $# -ge 1 ]] && [[ $# -le 2 ]]; }; then
516 yell "ERROR:Invalid number of arguments:$# . Exiting.";
517 returnState="error_input"; fi
518
519 # Check that argSeconds provided
520 if [[ $# -ge 1 ]]; then
521 ## Check that argSeconds is a positive integer
522 if [[ "$argSeconds" =~ ^[[:digit:]]+$ ]]; then
523 :
524 else
525 yell "ERROR:argSeconds not a digit.";
526 returnState="error_input";
527 fi
528 else
529 yell "ERROR:No argument provided. Exiting.";
530 exit 1;
531 fi
532
533 # Consider whether argPrecision was provided
534 if [[ $# -eq 2 ]]; then
535 # Check that argPrecision is a positive integer
536 if [[ "$argPrecision" =~ ^[[:digit:]]+$ ]] && [[ "$argPrecision" -gt 0 ]]; then
537 precision="$argPrecision";
538 else
539 yell "ERROR:argPrecision not a positive integer. (is $argPrecision ). Leaving early.";
540 returnState="error_input";
541 fi;
542 else
543 :
544 fi;
545
546 remainder="$argSeconds" ; # seconds
547 ## Calculate full years Y, update remainder
548 fullYears=$(( remainder / (365*24*60*60) ));
549 remainder=$(( remainder - (fullYears*365*24*60*60) ));
550 ## Calculate full months M, update remainder
551 fullMonths=$(( remainder / (30*24*60*60) ));
552 remainder=$(( remainder - (fullMonths*30*24*60*60) ));
553 ## Calculate full days D, update remainder
554 fullDays=$(( remainder / (24*60*60) ));
555 remainder=$(( remainder - (fullDays*24*60*60) ));
556 ## Calculate full hours H, update remainder
557 fullHours=$(( remainder / (60*60) ));
558 remainder=$(( remainder - (fullHours*60*60) ));
559 ## Calculate full minutes M, update remainder
560 fullMinutes=$(( remainder / (60) ));
561 remainder=$(( remainder - (fullMinutes*60) ));
562 ## Calculate full seconds S, update remainder
563 fullSeconds=$(( remainder / (1) ));
564 remainder=$(( remainder - (remainder*1) ));
565 ## Check which fields filled
566 if [[ $fullYears -gt 0 ]]; then hasYears="true"; else hasYears="false"; fi
567 if [[ $fullMonths -gt 0 ]]; then hasMonths="true"; else hasMonths="false"; fi
568 if [[ $fullDays -gt 0 ]]; then hasDays="true"; else hasDays="false"; fi
569 if [[ $fullHours -gt 0 ]]; then hasHours="true"; else hasHours="false"; fi
570 if [[ $fullMinutes -gt 0 ]]; then hasMinutes="true"; else hasMinutes="false"; fi
571 if [[ $fullSeconds -gt 0 ]]; then hasSeconds="true"; else hasSeconds="false"; fi
572
573 ## Determine which fields to display (see ISO-8601:2004 §4.4.3.2)
574 witherPrecision="false"
575
576 ### Years
577 if $hasYears && [[ $precision -gt 0 ]]; then
578 displayYears="true";
579 witherPrecision="true";
580 else
581 displayYears="false";
582 fi;
583 if $witherPrecision; then ((precision--)); fi;
584
585 ### Months
586 if $hasMonths && [[ $precision -gt 0 ]]; then
587 displayMonths="true";
588 witherPrecision="true";
589 else
590 displayMonths="false";
591 fi;
592 if $witherPrecision && [[ $precision -gt 0 ]]; then
593 displayMonths="true";
594 fi;
595 if $witherPrecision; then ((precision--)); fi;
596
597 ### Days
598 if $hasDays && [[ $precision -gt 0 ]]; then
599 displayDays="true";
600 witherPrecision="true";
601 else
602 displayDays="false";
603 fi;
604 if $witherPrecision && [[ $precision -gt 0 ]]; then
605 displayDays="true";
606 fi;
607 if $witherPrecision; then ((precision--)); fi;
608
609 ### Hours
610 if $hasHours && [[ $precision -gt 0 ]]; then
611 displayHours="true";
612 witherPrecision="true";
613 else
614 displayHours="false";
615 fi;
616 if $witherPrecision && [[ $precision -gt 0 ]]; then
617 displayHours="true";
618 fi;
619 if $witherPrecision; then ((precision--)); fi;
620
621 ### Minutes
622 if $hasMinutes && [[ $precision -gt 0 ]]; then
623 displayMinutes="true";
624 witherPrecision="true";
625 else
626 displayMinutes="false";
627 fi;
628 if $witherPrecision && [[ $precision -gt 0 ]]; then
629 displayMinutes="true";
630 fi;
631 if $witherPrecision; then ((precision--)); fi;
632
633 ### Seconds
634
635 if $hasSeconds && [[ $precision -gt 0 ]]; then
636 displaySeconds="true";
637 witherPrecision="true";
638 else
639 displaySeconds="false";
640 fi;
641 if $witherPrecision && [[ $precision -gt 0 ]]; then
642 displaySeconds="true";
643 fi;
644 if $witherPrecision; then ((precision--)); fi;
645
646 ## Determine whether or not the "T" separator is needed to separate date and time elements
647 if ( $displayHours || $displayMinutes || $displaySeconds); then
648 displayDateTime="true"; else displayDateTime="false"; fi
649
650 ## Construct duration output string
651 output="P"
652 if $displayYears; then
653 output=$output$fullYears"Y"; fi
654 if $displayMonths; then
655 output=$output$fullMonths"M"; fi
656 if $displayDays; then
657 output=$output$fullDays"D"; fi
658 if $displayDateTime; then
659 output=$output"T"; fi
660 if $displayHours; then
661 output=$output$fullHours"H"; fi
662 if $displayMinutes; then
663 output=$output$fullMinutes"M"; fi
664 if $displaySeconds; then
665 output=$output$fullSeconds"S"; fi
666
667 ## Output duration string to stdout
668 echo "$output" && returnState="true";
669
670 #===Determine function return code===
671 if [ "$returnState" = "true" ]; then
672 return 0;
673 elif [ "$returnState" = "error_input" ]; then
674 yell "ERROR:input";
675 return 1;
676 else
677 yell "ERROR:Unknown";
678 return 2;
679 fi
680
681} # Get duration (ex: PT10M4S )
34711384
SBS
682timeUntilNextDay(){
683 # Desc: Report seconds until next day.
684 # Version: 1.0.2
685 # Output: stdout: integer seconds until next day
686 # Output: exit code 0 if stdout > 0; 1 if stdout = 0; 2 if stdout < 0
687 # Usage: timeUntilNextDay
688 # Usage: if ! myTTL="$(timeUntilNextDay)"; then yell "ERROR in if statement"; exit 1; fi
689 # Depends: date 8, echo 8, yell, try
690
691 local returnState timeCurrent timeNextDay secondsUntilNextDay returnState
692 timeCurrent="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
693 timeNextDay="$(date -d "$timeCurrent next day" --iso-8601=date)"; # Produce timestamp of beginning of tomorrow with resolution of 1 second.
694 secondsUntilNextDay="$(( $(date +%s -d "$timeNextDay") - $(date +%s -d "$timeCurrent") ))" ; # Calculate seconds until closest future midnight (res. 1 second).
695 if [[ "$secondsUntilNextDay" -gt 0 ]]; then
696 returnState="true";
697 elif [[ "$secondsUntilNextDay" -eq 0 ]]; then
698 returnState="warning_zero";
699 yell "WARNING:Reported time until next day exactly zero.";
700 elif [[ "$secondsUntilNextDay" -lt 0 ]]; then
701 returnState="warning_negative";
702 yell "WARNING:Reported time until next day is negative.";
703 fi
704
705 try echo "$secondsUntilNextDay"; # Report
706
707 # Determine function return code
708 if [[ "$returnState" = "true" ]]; then
709 return 0;
710 elif [[ "$returnState" = "warning_zero" ]]; then
711 return 1;
712 elif [[ "$returnState" = "warning_negative" ]]; then
713 return 2;
714 fi
715} # Report seconds until next day
716timeUntilNextHour(){
717 # Desc: Report seconds until next hour
718 # Version 1.0.1
719 # Output: stdout: integer seconds until next hour
720 # Output: exit code 0 if stdout > 0; 1 if stdout = 0; 2 if stdout < 0
721 # Usage: timeUntilNextHour
722 # Usage: if ! myTTL="$(timeUntilNextHour)"; then yell "ERROR in if statement"; exit 1; fi
723
724 local returnState timeCurrent timeNextHour secondsUntilNextHour
725 timeCurrent="$(date --iso-8601=seconds)"; # Produce `date`-parsable current timestamp with resolution of 1 second.
726 timeNextHour="$(date -d "$timeCurrent next hour" --iso-8601=hours)"; # Produce `date`-parsable current time stamp with resolution of 1 second.
727 secondsUntilNextHour="$(( $(date +%s -d "$timeNextHour") - $(date +%s -d "$timeCurrent") ))"; # Calculate seconds until next hour (res. 1 second).
728 if [[ "$secondsUntilNextHour" -gt 0 ]]; then
729 returnState="true";
730 elif [[ "$secondsUntilNextHour" -eq 0 ]]; then
731 returnState="warning_zero";
732 yell "WARNING:Reported time until next hour exactly zero.";
733 elif [[ "$secondsUntilNextHour" -lt 0 ]]; then
734 returnState="warning_negative";
735 yell "WARNING:Reported time until next hour is negative.";
736 fi;
737
738 try echo "$secondsUntilNextHour"; # Report
739
740 # Determine function return code
741 if [[ "$returnState" = "true" ]]; then
742 return 0;
743 elif [[ "$returnState" = "warning_zero" ]]; then
744 return 1;
745 elif [[ "$returnState" = "warning_negative" ]]; then
746 return 2;
747 fi;
748} # Report seconds until next hour
be6ce8f4
SBS
749validateInput() {
750 # Desc: Validates Input
751 # Usage: validateInput [str input] [str input type]
752 # Version: 0.3.1
753 # Input: arg1: string to validate
754 # arg2: string specifying input type (ex:"ssh_pubkey")
755 # Output: return code 0: if input string matched specified string type
756 # Depends: bash 5, yell()
757
758 local fn argInput argType
759
760 # Save function name
761 fn="${FUNCNAME[0]}";
762
763 # Process arguments
764 argInput="$1";
765 argType="$2";
766 if [[ $# -gt 2 ]]; then yell "ERROR:$0:$fn:Too many arguments."; exit 1; fi;
767
768 # Check for blank
769 if [[ -z "$argInput" ]]; then return 1; fi
770
771 # Define input types
772 ## ssh_pubkey
773 ### Check for alnum/dash base64 (ex: "ssh-rsa AAAAB3NzaC1yc2EAAA")
774 if [[ "$argType" = "ssh_pubkey" ]]; then
775 if [[ "$argInput" =~ ^[[:alnum:]-]*[\ ]*[[:alnum:]+/=]*$ ]]; then
776 return 0; fi; fi;
777
778 ## age_pubkey
779 ### Check for age1[:bech32:]
780 if [[ "$argType" = "age_pubkey" ]]; then
781 if [[ "$argInput" =~ ^age1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]*$ ]]; then
782 return 0; fi; fi
783
784 ## integer
785 if [[ "$argType" = "integer" ]]; then
786 if [[ "$argInput" =~ ^[[:digit:]]*$ ]]; then
787 return 0; fi; fi;
788
789 ## time element (year, month, week, day, hour, minute, second)
790 if [[ "$argType" = "time_element" ]]; then
791 if [[ "$argInput" = "year" ]] || \
792 [[ "$argInput" = "month" ]] || \
793 [[ "$argInput" = "week" ]] || \
794 [[ "$argInput" = "day" ]] || \
795 [[ "$argInput" = "hour" ]] || \
796 [[ "$argInput" = "minute" ]] || \
797 [[ "$argInput" = "second" ]]; then
798 return 0; fi; fi;
799
800 # Return error if no condition matched.
801 return 1;
802} # Validates strings
79bb6c16 803
4e4707fb
SBS
804magicInitWorkingDir() {
805 # Desc: Determine temporary working directory from defaults or user input
806 # Usage: magicInitWorkingDir
807 # Input: vars: optionTmpDir, argTempDirPriority, dirTmpDefault
808 # Input: vars: scriptTimeStart
809 # Output: vars: dir_tmp
810 # Depends: bash 5.0.3, processArguments(), vbm(), yell()
811 # Parse '-t' option (user-specified temporary working dir)
812 ## Set dir_tmp_parent to user-specified value if specified
80fbd111 813 local fn dir_tmp_parent
6fe054b4 814
80fbd111
SBS
815 # Save function name
816 fn="${FUNCNAME[0]}";
817
818 vbm "STATUS:$fn:Starting magicInitWorkingDir() function.";
4e4707fb
SBS
819 if [[ "$optionTmpDir" = "true" ]]; then
820 if [[ -d "$argTempDirPriority" ]]; then
821 dir_tmp_parent="$argTempDirPriority";
822 else
80fbd111 823 yell "WARNING:$fn:Specified temporary working directory not valid:$argTempDirPriority";
4e4707fb
SBS
824 exit 1; # Exit since user requires a specific temp dir and it is not available.
825 fi;
826 else
827 ## Set dir_tmp_parent to default or fallback otherwise
828 if [[ -d "$dirTmpDefault" ]]; then
829 dir_tmp_parent="$dirTmpDefault";
830 elif [[ -d /tmp ]]; then
80fbd111 831 yell "WARNING:$fn:$dirTmpDefault not available. Falling back to /tmp .";
4e4707fb
SBS
832 dir_tmp_parent="/tmp";
833 else
80fbd111 834 yell "ERROR:$fn:No valid working directory available. Exiting.";
4e4707fb
SBS
835 exit 1;
836 fi;
837 fi;
838 ## Set dir_tmp using dir_tmp_parent and nonce (scriptTimeStart)
fcefae4c 839 dir_tmp="$dir_tmp_parent"/"$scriptTimeStart""..bkgpslog" && vbm "DEBUG :$fn:Set dir_tmp to:$dir_tmp"; # Note: removed at end of main().
80fbd111 840 vbm "STATUS:$fn:Finished magicInitWorkingDir() function.";
4e4707fb
SBS
841} # Sets working dir
842magicInitCheckTar() {
843 # Desc: Initializes or checks output tar
844 # input: vars: dirOut, bufferTTL, cmd_encrypt_suffix, cmd_compress_suffix
845 # input: vars: scriptHostname
846 # output: vars: pathout_tar
847 # depends: Bash 5.0.3, vbm(), dateShort(), checkMakeTar(), magicWriteVersion()
195dd3c3 848 local fn checkMakeTarES
4e4707fb 849
80fbd111
SBS
850 # Save function name
851 fn="${FUNCNAME[0]}";
852
853 vbm "STATUS:$fn:Starting magicInitCheckTar() function.";
4e4707fb
SBS
854 # Form pathout_tar
855 pathout_tar="$dirOut"/"$(dateShort "$(date --date="$bufferTTL seconds ago" --iso-8601=seconds)")".."$scriptHostname""$label""$cmd_compress_suffix""$cmd_encrypt_suffix".tar && \
80fbd111 856 vbm "STATUS:$fn:Set pathout_tar to:$pathout_tar";
4e4707fb 857 # Validate pathout_tar as tar.
195dd3c3 858 checkMakeTar "$pathout_tar"; checkMakeTarES="$?";
4e4707fb 859 ## Add VERSION file if checkMakeTar had to create a tar (exited 1) or replace one (exited 2)
195dd3c3
SBS
860 vbm "STATUS:$fn:exit status before magicWriteVersion:$checkMakeTarES"
861 if [[ "$checkMakeTarES" -eq 1 ]] || [[ "$checkMakeTarES" -eq 2 ]]; then magicWriteVersion; fi
80fbd111 862 vbm "STATUS:$fn:Finished magicInitCheckTar() function.";
4e4707fb
SBS
863} # Initialize tar, set pathout_tar
864magicParseCompressionArg() {
865 # Desc: Parses compression arguments specified by '-c' option
866 # Input: vars: optionCompress
867 # Output: cmd_compress, cmd_compress_suffix
868 # Depends: processArguments(), vbm(), checkapp(), gzip 1.9
80fbd111 869 local fn
6fe054b4 870
80fbd111
SBS
871 # Save function name
872 fn="${FUNCNAME[0]}";
873
874 vbm "STATUS:$fn:Starting magicParseCompressionArg() function.";
4e4707fb
SBS
875 if [[ "$optionCompress" = "true" ]]; then # Check if compression option active
876 if checkapp gzip; then # Check if gzip available
80fbd111
SBS
877 cmd_compress="gzip " && vbm "STATUS:$fn:cmd_compress:$cmd_compress";
878 cmd_compress_suffix=".gz" && vbm "STATUS:$fn:cmd_compress_suffix:$cmd_compress_suffix";
4e4707fb 879 else
80fbd111 880 yell "ERROR:$fn:Compression enabled but \"gzip\" not found. Exiting."; exit 1;
6fe054b4 881 fi;
4e4707fb 882 else
80fbd111
SBS
883 cmd_compress="tee /dev/null " && vbm "STATUS:$fn:cmd_compress:$cmd_compress";
884 cmd_compress_suffix="" && vbm "STATUS:$fn:cmd_compress_suffix:$cmd_compress_suffix";
fcefae4c 885 vbm "DEBUG :$fn:Compression not enabled.";
6fe054b4 886 fi;
a2c47ccf 887 vbm "STATUS:$fn:Finished magicParseCompressionArg() function.";
4e4707fb
SBS
888} # Form compression cmd string and filename suffix
889magicParseCustomTTL() {
890 # Desc: Set user-specified TTLs for buffer and script
891 # Usage: magicParseCustomTTL
892 # Input: vars: argCustomBufferTTL (integer), argCustomScriptTTL_TE (string)
893 # Input: vars: optionCustomBufferTTL, optionCustomScriptTTL_TE
894 # Input: vars: bufferTTL (integer), scriptTTL_TE (string)
895 # Output: bufferTTL (integer), scriptTTL_TE (string)
896 # Depends: Bash 5.0.3, yell(), vbm(), validateInput(), showUsage()
80fbd111
SBS
897 local fn
898
899 # Save function name
900 fn="${FUNCNAME[0]}";
4e4707fb 901
80fbd111 902 vbm "STATUS:$fn:Starting magicParseCustomTTL() function.";
4e4707fb
SBS
903 # React to '-b, --buffer-ttl' option
904 if [[ "$optionCustomBufferTTL" = "true" ]]; then
905 ## T: Check if argCustomBufferTTL is an integer
906 if validateInput "$argCustomBufferTTL" "integer"; then
907 ### T: argCustomBufferTTL is an integer
80fbd111 908 bufferTTL="$argCustomBufferTTL" && vbm "STATUS:$fn:Custom bufferTTL from -b:$bufferTTL";
4e4707fb
SBS
909 else
910 ### F: argcustomBufferTTL is not an integer
80fbd111 911 yell "ERROR:$fn:Invalid integer argument for custom buffer time-to-live."; showUsage; exit 1;
4e4707fb
SBS
912 fi;
913 ## F: do not change bufferTTL
914 fi;
915
916 # React to '-B, --script-ttl' option
917 if [[ "$optionCustomScriptTTL_TE" = "true" ]]; then
918 ## T: Check if argCustomScriptTTL is a time element (ex: "day", "hour")
919 if validateInput "$argCustomScriptTTL_TE" "time_element"; then
920 ### T: argCustomScriptTTL is a time element
80fbd111 921 scriptTTL_TE="$argCustomScriptTTL_TE" && vbm "STATUS:$fn:Custom scriptTTL_TE from -B:$scriptTTL_TE";
4e4707fb
SBS
922 else
923 ### F: argcustomScriptTTL is not a time element
80fbd111 924 yell "ERROR:$fn:Invalid time element argument for custom script time-to-live."; showUsage; exit 1;
4e4707fb
SBS
925 fi;
926 ## F: do not change scriptTTL_TE
6fe054b4 927 fi;
a2c47ccf 928 vbm "STATUS:$fn:Finished magicParseCustomTTL() function.";
4e4707fb
SBS
929} # Sets custom script or buffer TTL if specified
930magicParseLabel() {
931 # Desc: Parses -l option to set label
932 # In : optionLabel, argLabel
933 # Out: vars: label
934 # Depends: Bash 5.0.3, vbm(), yell()
80fbd111 935 local fn
4e4707fb 936
80fbd111
SBS
937 # Save function name
938 fn="${FUNCNAME[0]}";
939
940 vbm "STATUS:$fn:Started magicParseLabel() function.";
4e4707fb
SBS
941 # Do nothing if optionLabel not set to true.
942 if [[ ! "$optionLabel" = "true" ]]; then
80fbd111 943 vbm "STATUS:$fn:optionlabel not set to 'true'. Returning early.";
4e4707fb
SBS
944 return;
945 fi;
946 # Set label if optionLabel is true
947 if [[ "$optionLabel" = "true" ]]; then
948 label="_""$argLabel";
80fbd111 949 vbm "STATUS:$fn:Set label:$label";
4e4707fb 950 fi;
80fbd111 951 vbm "STATUS:$fn:Finished magicParseLabel() function.";
4e4707fb
SBS
952} # Set label used in output file name
953magicParseProcessStrings() {
954 # Desc: Processes user-supplied process strings into process commands for appendFileTar().
955 # Usage: magicParseProcessStrings
956 # In : vars: optionProcString optionNoStoreRaw optionStoreRaw argRawFileExt
957 # arry: argProcStrings, argProcFileExts
958 # Out: arry: procStrings, procFileExts
959 # Depends Bash 5.0.3, yell(), vbm()
80fbd111
SBS
960 local fn rawFileExt
961
962 # Save function name
963 fn="${FUNCNAME[0]}";
964
965 vbm "STATUS:$fn:Starting magicParseProcessStrings() function.";
966 vbm "STATUS:$fn:var:optionProcString:$optionProcString";
967 vbm "STATUS:$fn:var:optionNoStoreRaw:$optionNoStoreRaw";
968 vbm "STATUS:$fn:var:optionStoreRaw:$optionStoreRaw";
969 vbm "STATUS:$fn:var:argRawFileExt:$argRawFileExt";
970 vbm "STATUS:$fn:ary:argProcStrings:${argProcStrings[*]}";
971 vbm "STATUS:$fn:ary:argProcFileExts:${argProcFileExts[*]}"
4e4707fb
SBS
972 # Validate input
973 ## Validate argRawFileExt
974 if [[ "$argRawFileExt" =~ ^[.][[:alnum:]]*$ ]]; then
492d1a57
SBS
975 rawFileExt="$argRawFileExt" && \
976 vbm "DEBUG :$fn:Set rawFileExt to \"$argRawFileExt\"";
977 else
978 vbm "DEBUG :$fn:Validation failure for $argRawFileExt . Not set to rawFileExt.";
4e4707fb
SBS
979 fi;
980
981 # Add default stdin output file entries for procStrings, procFileExts
982 ## Check if user specified that no raw stdin be saved.
983 if [[ ! "$optionNoStoreRaw" = "true" ]]; then
984 ### T: --no-store-raw not set. Store raw. Append procStrings with cat.
492d1a57 985 vbm "DEBUG :$fn:--no-store-raw not set. Storing raw.";
4e4707fb 986 #### Append procStrings array
492d1a57
SBS
987 procStrings+=("cat ") && \
988 vbm "DEBUG :$fn:Appended \"cat \" to procStrings";
989 vbm "DEBUG :$fn:procStrings array:${procStrings[*]}";
4e4707fb
SBS
990 #### Check if --store-raw set.
991 if [[ "$optionStoreRaw" = "true" ]]; then
992 ##### T: --store-raw set. Append procFileExts with user-specified file ext
492d1a57
SBS
993 vbm "DEBUG :$fn:--store-raw set.";
994 procFileExts+=("$rawFileExt") && \
995 vbm "DEBUG :$fn:Appended $rawFileExt to procFileExts";
996 vbm "STATUS:$fn:procFileExts array:${procFileExts[*]}";
4e4707fb
SBS
997 else
998 ##### F: --store-raw not set. Append procFileExts with default ".stdin" file ext
999 ###### Append procFileExts array
492d1a57
SBS
1000 procFileExts+=(".stdin") && \
1001 vbm "DEBUG :$fn:Appended \".stdin\" to procFileExts";
1002 vbm "STATUS:$fn:procFileExts array:${procFileExts[*]}";
4e4707fb
SBS
1003 fi;
1004 else
1005 ### F: --no-store-raw set. Do not store raw.
1006 #### Do not append procStrings or procFileExts arrays.
492d1a57
SBS
1007 vbm "STATUS:$fn:--no-store-raw set. Not storing raw.";
1008 vbm "STATUS:$fn:procFileExts array:${procFileExts[*]}";
4e4707fb
SBS
1009 fi;
1010
1011 # Do nothing more if optionProcString not set to true.
1012 if [[ ! "$optionProcString" = "true" ]]; then
80fbd111 1013 vbm "STATUS:$fn:optionProcString not set to 'true'. Returning early.";
4e4707fb
SBS
1014 return; fi;
1015 # Validate input array indices
1016 ## Make sure that argProcStrings and argProcFileExts have same index counts
1017 if ! [[ "${#argProcStrings[@]}" -eq "${#argProcFileExts[@]}" ]]; then
80fbd111
SBS
1018 yell "ERROR:$fn:Mismatch in number of elements in arrays argProcStrings and argProcFileExts:${#argProcStrings[@]} DNE ${#argProcFileExts[@]}";
1019 yell "STATUS:$fn:argProcStrings:${argProcStrings[*]}"; yell "STATUS:$fn:argProcFileExts:${argProcFileExts[*]}"; exit 1; fi;
4e4707fb
SBS
1020 ## Make sure that no array elements are blank
1021 for element in "${argProcStrings[@]}"; do
80fbd111 1022 if [[ -z "$element" ]]; then yell "ERROR:$fn:Empty process string specified. Exiting."; exit 1; fi; done
4e4707fb 1023 for element in "${argProcFileExts[@]}"; do
80fbd111 1024 if [[ -z "$element" ]]; then yell "ERROR:$fn:Empty output file extension specified. Exiting."; exit 1; fi; done
4e4707fb
SBS
1025 ## Make sure that no process string starts with '-' (ex: if only one arg supplied after '-p' option)
1026 for element in "${argProcStrings[@]}"; do
61b243e0 1027 if [[ "$element" =~ ^[-][[:print:]]*$ ]] && [[ ! "$element" =~ ^[[:print:]]*$ ]]; then
80fbd111 1028 yell "ERROR:$fn:Illegal character '-' at start of process string element:\"$element\"";
4e4707fb 1029 exit 1; fi; done;
80fbd111 1030 vbm "STATUS:$fn:Quick check shows argProcStrings and argProcFileExts appear to have valid contents.";
5fb689c8 1031 vbm "STATUS:$fn:argProcStrings:${argProcStrings[*]}"
a2c47ccf 1032 vbm "STATUS:$fn:argProcFileExts:${argProcFileExts[*]}"
492d1a57
SBS
1033 procStrings+=("${argProcStrings[@]}"); # Export process command strings
1034 procFileExts+=("${argProcFileExts[@]}"); # Export process command strings
a2c47ccf
SBS
1035 vbm "STATUS:$fn:procStrings:${procStrings[*]}"
1036 vbm "STATUS:$fn:procFileExts:${procFileExts[*]}"
80fbd111 1037 vbm "STATUS:$fn:Finished magicParseProcessStrings() function.";
4e4707fb 1038} # Validate and save process strings and file extensions to arrays procStrings, procFileExts
236c8b97
SBS
1039magicParseRecipients() {
1040 # Desc: Parses recipient arguments specified by '-r' or '-R' options
1041 # Usage: magicParseRecipients
1042 # In : vars: optionEncrypt, optionRecArg, optionRecDir
1043 # arry: argRecPubKeys (-r), argRecDir (-R)
1044 # Out: vars: cmd_encrypt, cmd_encrypt_suffix
1045 # Depends: head 8.30, checkapp(), checkAgePubkey(), validateInput()
1046 local fn recipients recipientDir recFileLine updateRecipients
1047 local -a recPubKeysValid candRecPubKeysValid
c5da633d 1048
80fbd111
SBS
1049 # Save function name
1050 fn="${FUNCNAME[0]}";
236c8b97 1051 vbm "STATUS:$fn:Starting magicParseRecipients() function.";
80fbd111 1052
236c8b97
SBS
1053 # Catch illegal option combinations
1054 ## Catch case if '-e' is set but neither '-r' nor '-R' is set
1055 if [[ "$optionEncrypt" = "true" ]] && \
1056 ! { [[ "$optionRecArg" = "true" ]] || [[ "$optionRecDir" = "true" ]]; }; then
80fbd111 1057 yell "ERROR:$fn:\\'-e\\' set but no \\'-r\\' or \\'-R\\' set."; exit 1; fi;
236c8b97
SBS
1058 ## Catch case if '-r' or '-R' set but '-e' is not
1059 if [[ ! "$optionEncrypt" = "true" ]] && \
1060 { [[ "$optionRecArg" = "true" ]] || [[ "$optionRecDir" = "true" ]]; }; then
80fbd111 1061 yell "ERROR:$fn:\\'-r\\' or \\'-R\\' set but \\'-e\\' is not set."; exit 1; fi;
80fbd111 1062
236c8b97
SBS
1063 # Handle no encryption cases
1064 if [[ ! "$optionEncrypt" = "true" ]]; then
1065 cmd_encrypt="cat " && vbm "STATUS:$fn:cmd_encrypt:$cmd_encrypt";
1066 cmd_encrypt_suffix="" && vbm "STATUS:$fn:cmd_encrypt_suffix:$cmd_encrypt_suffix";
1067 vbm "DEBUG :$fn:Encryption not enabled.";
1068 return; fi;
1069
1070 # Handle encryption cases
1071 ## Check age availability
1072 if ! checkapp age; then yell "ERROR:$fn:age not available. Exiting."; exit 1; fi
1073 ## Parse '-r' options: validate and append pubkeys from argRecPubKeys to recPubKeysValid
1074 if [[ "$optionRecArg" = "true" ]]; then
1075 for pubkey in "${argRecPubKeys[@]}"; do # Validate recipient pubkey strings by forming test message
1076 vbm "DEBUG :$fn:Testing pubkey string:$pubkey";
1077 if checkAgePubkey "$pubkey" && \
1078 ( validateInput "$pubkey" "ssh_pubkey" || validateInput "$pubkey" "age_pubkey"); then
1079 #### Add validated pubkey to recPubKeysValid array
1080 recPubKeysValid+=("$pubkey") && \
1081 vbm "DEBUG :$fn:recPubkeysValid:pubkey added:$pubkey";
1082 else
1083 yell "ERROR:$fn:Exit code ""$?"". Invalid recipient pubkey string. Exiting."; exit 1;
1084 fi;
1085 done;
1086 vbm "STATUS:$fn:Finished processing argRecPubKeys array";
1087 vbm "DEBUG :$fn:Array of validated pubkeys:${recPubKeysValid[*]}";
1088 fi;
1089 ## Parse '-R' options: validate and append pubkeys in argRecDir to recPubKeysValid
1090 if [[ "$optionRecDir" = "true" ]]; then
1091 ### Check that argRecDir is a directory
c5da633d 1092 if [[ -d "$argRecDir" ]]; then
236c8b97
SBS
1093 recipientDir="$argRecDir" && \
1094 vbm "STATUS:$fn:Recipient watch directory detected:\"$recipientDir\"";
c5da633d
SBS
1095 #### Initialize variable indicating outcome of pubkey review
1096 unset updateRecipients
236c8b97
SBS
1097 #### Add existing recipients from '-r' option
1098 candRecPubKeysValid=("${recPubKeysValid[@]}");
c5da633d
SBS
1099 #### Parse files in recipientDir
1100 for file in "$recipientDir"/*; do
1101 ##### Read first line of each file
236c8b97
SBS
1102 recFileLine="$(head -n1 "$file")" && \
1103 vbm "STATUS:$fn:Checking if pubkey:\"$recFileLine\"";
c5da633d
SBS
1104 ##### check if first line is a valid pubkey
1105 if checkAgePubkey "$recFileLine" && \
1106 ( validateInput "$recFileLine" "ssh_pubkey" || validateInput "$recFileLine" "age_pubkey"); then
1107 ###### T: add candidate pubkey to candRecPubKeysValid
236c8b97
SBS
1108 candRecPubKeysValid+=("$recFileLine") && \
1109 vbm "STATUS:$fn:RecDir pubkey is valid pubkey:\"$recFileLine\"";
c5da633d
SBS
1110 else
1111 ###### F: throw warning;
236c8b97 1112 yell "ERROR:$fn:Invalid recipient file detected. Not modifying recipient list:$recFileLine";
c5da633d
SBS
1113 updateRecipients="false";
1114 fi;
1115 done
236c8b97 1116 #### Write candRecPubKeysValid array to recPubKeysValid if no invalid key detected
c5da633d 1117 if ! [[ "$updateRecipients" = "false" ]]; then
236c8b97
SBS
1118 recPubKeysValid=("${candRecPubKeysValid[@]}") && \
1119 vbm "STATUS:$fn:Wrote candRecPubkeysValid to recPubKeysValid:\"${recPubKeysValid[*]}\"";
c5da633d 1120 fi;
c5da633d
SBS
1121 fi;
1122 fi;
236c8b97
SBS
1123
1124 ## Form age recipient string from recPubKeysValid
1125 for pubkey in "${recPubKeysValid[@]}"; do
1126 recipients="$recipients""-r '$pubkey' ";
1127 vbm "STATUS:$fn:Added pubkey for forming age recipient string:""$pubkey";
1128 vbm "DEBUG :$fn:recipients:""$recipients";
1129 done;
1130
1131 ## Output cmd_encrypt, cmd_encrypt_suffix from recipients
1132 cmd_encrypt="age ""$recipients " && vbm "STATUS:$fn:cmd_encrypt:$cmd_encrypt";
1133 cmd_encrypt_suffix=".age" && vbm "STATUS:$fn:cmd_encrypt_suffix:$cmd_encrypt_suffix";
1134
1135 vbm "STATUS:$fn:Finished magicParseRecipients() function.";
1136} # Sets cmd_encrypt, cmd_encrypt_suffix from -r, -R args
c5da633d
SBS
1137magicSetScriptTTL() {
1138 #Desc: Sets script_TTL seconds from provided time_element string argument
1139 #Usage: magicSetScriptTTL [str time_element]
1140 #Input: arg1: string (Ex: scriptTTL_TE; "day" or "hour")
1141 #Output: var: scriptTTL (integer seconds)
1142 #Depends: timeUntilNextHour, timeUntilNextDay
80fbd111 1143 local fn argTimeElement
6fe054b4 1144
80fbd111
SBS
1145 # Save function name
1146 fn="${FUNCNAME[0]}";
1147
1148 vbm "STATUS:$fn:Starting magicSetScriptTTL() function.";
c5da633d
SBS
1149 argTimeElement="$1";
1150 if [[ "$argTimeElement" = "day" ]]; then
a2c47ccf
SBS
1151 # Set script lifespan to end at start of next day
1152 vbm "STATUS:$fn:Setting script lifespan to end at start of next day. argTimeElement:$argTimeElement";
c5da633d
SBS
1153 if ! scriptTTL="$(timeUntilNextDay)"; then # sets scriptTTL, then checks exit code
1154 if [[ "$scriptTTL" -eq 0 ]]; then
a2c47ccf
SBS
1155 ((scriptTTL++)); # Add 1 because 0 would cause 'timeout' to never timeout.
1156 vbm "STATUS:$fn:scriptTTL:$scriptTTL";
c5da633d 1157 else
80fbd111 1158 yell "ERROR:$fn:timeUntilNextDay exit code $?"; exit 1;
c5da633d
SBS
1159 fi;
1160 fi;
1161 elif [[ "$argTimeElement" = "hour" ]]; then
1162 # Set script lifespan to end at start of next hour
a2c47ccf 1163 vbm "STATUS:$fn:Setting script lifespan to end at start of next hour. argTimeElement:$argTimeElement";
c5da633d
SBS
1164 if ! scriptTTL="$(timeUntilNextHour)"; then # sets scriptTTL, then checks exit code
1165 if [[ "$scriptTTL" -eq 0 ]]; then
1166 ((scriptTTL++)); # Add 1 because 0 would cause 'timeout' to never timeout.
a2c47ccf 1167 vbm "STATUS:$fn:scriptTTL:$scriptTTL";
c5da633d 1168 else
80fbd111 1169 yell "ERROR:$fn:timeUntilNextHour exit code $?"; exit 1;
c5da633d
SBS
1170 fi;
1171 fi;
1172 else
80fbd111 1173 yell "ERROR:$fn:Invalid argument for setScriptTTL function:$argTimeElement"; exit 1;
c5da633d 1174 fi;
80fbd111 1175 vbm "STATUS:$fn:Finished magicSetScriptTTL() function.";
c5da633d 1176} # Set scriptTTL in seconds until next (day|hour).
c5da633d
SBS
1177magicWriteVersion() {
1178 # Desc: Appends time-stamped VERSION to pathout_tar
1179 # Usage: magicWriteVersion
1180 # Input: vars: pathout_tar, dir_tmp
1181 # Input: vars: scriptVersion, scriptURL, ageVersion, ageURL, scriptHostname
1182 # Input: array: recPubKeysValid
1183 # Output: appends tar (pathout_tar)
1184 # Depends: bash 5.0.3, dateTimeShort(), appendArgTar()
80fbd111 1185 local fn fileoutVersion contentVersion pubKeyIndex pubKeyIndex
6fe054b4 1186
80fbd111
SBS
1187 # Save function name
1188 fn="${FUNCNAME[0]}";
1189
1190 vbm "STATUS:$fn:Starting magicWriteVersion() function.";
c5da633d
SBS
1191 # Set VERSION file name
1192 fileoutVersion="$(dateTimeShort)..VERSION";
1193
1194 # Gather VERSION data in contentVersion
1195 contentVersion="scriptVersion=$scriptVersion";
1196 #contentVersion="$contentVersion""\\n";
1197 contentVersion="$contentVersion""\\n""scriptName=$scriptName";
1198 contentVersion="$contentVersion""\\n""scriptURL=$scriptURL";
1199 contentVersion="$contentVersion""\\n""ageVersion=$ageVersion";
1200 contentVersion="$contentVersion""\\n""ageURL=$ageURL";
1201 contentVersion="$contentVersion""\\n""date=$(date --iso-8601=seconds)";
1202 contentVersion="$contentVersion""\\n""hostname=$scriptHostname";
1203 ## Add list of recipient pubkeys
1204 for pubkey in "${recPubKeysValid[@]}"; do
1205 ((pubKeyIndex++))
1206 contentVersion="$contentVersion""\\n""PUBKEY_$pubKeyIndex=$pubkey";
1207 done
1208 ## Process newline escapes
1209 contentVersion="$(echo -e "$contentVersion")"
1210
1211 # Write contentVersion as file fileoutVersion and write-append to pathout_tar
80fbd111
SBS
1212 appendArgTar "$contentVersion" "$fileoutVersion" "$pathout_tar" "$dir_tmp" && \
1213 vbm "STATUS:$fn:Appended $fileoutVersion to $pathout_tar";
1214 vbm "STATUS:$fn:Finished magicWriteVersion() function.";
c5da633d 1215} # write version data to pathout_tar via appendArgTar()
5938a598 1216magicProcessWriteBuffer() {
c5da633d
SBS
1217 # Desc: process and write buffer
1218 # In : vars: bufferTTL bufferTTL_STR scriptHostname label dir_tmp SECONDS
1219 # : arry: buffer
1220 # Out: file:(pathout_tar)
1221 # Depends: Bash 5.0.3, date 8.30, yell(), vbm(), dateTimeShort(),
1222 ### Note: These arrays should all have the same number of elements:
1223 ### pathouts, fileouts, procFileExts, procStrings
1224
1225 local fn timeBufferStartLong timeBufferStart fileoutBasename
1226 local -a fileouts pathouts
1227 local writeCmd1 writeCmd2 writeCmd3 writeCmd4
1228
c5da633d
SBS
1229 # Debug:Get function name
1230 fn="${FUNCNAME[0]}";
80fbd111
SBS
1231
1232 vbm "STATUS:$fn:Started magicProcessWriteBuffer().";
b3dc68f6
SBS
1233 vbm "DEBUG :$fn:buffer array element count:${#buffer[@]}";
1234 vbm "DEBUG :$fn:buffer array first element:${buffer[0]}";
1235 vbm "DEBUG :$fn:buffer array last element :${buffer[-1]}";
1236
c5da633d
SBS
1237 # Determine file paths (time is start of buffer period)
1238 ## Calculate start time
1239 timeBufferStartLong="$(date --date="$bufferTTL seconds ago" --iso-8601=seconds)" && \
fcefae4c 1240 vbm "DEBUG :$fn:timeBufferStartLong:$timeBufferStartLong";
c5da633d 1241 timeBufferStart="$(dateTimeShort "$timeBufferStartLong" )" && \
fcefae4c 1242 vbm "DEBUG :$fn:timeBufferStart:$timeBufferStart"; # Note start time YYYYmmddTHHMMSS+zzzz (no separators)
c5da633d
SBS
1243 ## Set common basename
1244 fileoutBasename="$timeBufferStart""--""$bufferTTL_STR""..""$scriptHostname""$label" && \
80fbd111 1245 vbm "STATUS:$fn:Set fileoutBasename to:$fileoutBasename";
c5da633d
SBS
1246 ## Determine output file name array
1247 ### in: fileOutBasename cmd_compress_suffix cmd_encrypt_suffix procFileExts
1248 for fileExt in "${procFileExts[@]}"; do
1249 fileouts+=("$fileoutBasename""$fileExt""$cmd_compress_suffix""$cmd_encrypt_suffix") && \
80fbd111 1250 vbm "STATUS:$fn:Added $fileExt to fileouts:${fileouts[*]}";
c5da633d
SBS
1251 done;
1252 for fileName in "${fileouts[@]}"; do
1253 pathouts+=("$dir_tmp"/"$fileName") && \
80fbd111 1254 vbm "STATUS:$fn:Added $fileName to pathouts:${pathouts[*]}";
c5da633d
SBS
1255 done;
1256 ## Update pathout_tar
1257 magicInitCheckTar;
1258
1259 # Process and write buffers to dir_tmp
1260 ## Prepare command strings
1261 writeCmd1="printf \"%s\\\\n\" \"\${buffer[@]}\""; # printf "%s\\n" "${buffer[@]}"
1262 #writeCmd2="" # NOTE: Specified by parsing array procStrings
1263 writeCmd3="$cmd_compress";
1264 writeCmd4="$cmd_encrypt";
1265
1266 ## Process buffer and write to dir_tmp
3a5ef93a
SBS
1267 vbm "DEBUG :$fn:fileouts element count:${#fileouts[@]}";
1268 vbm "DEBUG :$fn:pathouts element count:${#pathouts[@]}";
1269 vbm "DEBUG :$fn:procStrings element count:${#pathouts[@]}";
1270 vbm "DEBUG :$fn:fileouts contents:${fileouts[*]}";
1271 vbm "DEBUG :$fn:pathouts contents:${pathouts[*]}";
1272 vbm "DEBUG :$fn:procStrings contents:${pathouts[*]}";
c5da633d 1273 for index in "${!pathouts[@]}"; do
21363b80
SBS
1274 writeCmd2="${procStrings[$index]}";
1275 writeCmdAll="$writeCmd1 | $writeCmd2 | $writeCmd3 | $writeCmd4" && vbm "STATUS:$fn:Assembled command:\"$writeCmdAll\"";
195dd3c3 1276 eval "$writeCmd1 | $writeCmd2 | $writeCmd3 | $writeCmd4" > "${pathouts[$index]}" && vbm "STATUS:$fn:Wrote command output to ${pathouts[$index]}";
c5da633d
SBS
1277 done;
1278
1279 # Append dir_tmp files to pathout_tar
1280 wait; # Wait to avoid collision with older magicProcessWriteBuffer() instances (see https://www.tldp.org/LDP/abs/html/x9644.html )
1281 for index in "${!pathouts[@]}"; do
7177fe18 1282 tar --append --directory="$dir_tmp" --file="$pathout_tar" "${fileouts[$index]}" && \
21363b80 1283 vbm "STATUS:$fn:Appended ${pathouts[$index]} to $pathout_tar";
3a5ef93a 1284 #appendFileTar "${pathouts[$index]}" "${fileouts[$index]}" "$pathout_tar" "$dir_tmp" && \
c5da633d
SBS
1285 done;
1286
1287 # Remove secured chunks from dir_tmp
1288 for path in "${pathouts[@]}"; do
a4bea612 1289 rm "$path" && vbm "STATUS:$fn:Removed:$path";
c5da633d
SBS
1290 done;
1291
80fbd111 1292 vbm "STATUS:$fn:Finished magicProcessWriteBuffer().";
5938a598 1293} # Process and Write buffer
236c8b97
SBS
1294showUsage() {
1295 cat <<'EOF'
1296 USAGE:
1297 cmd | bklog [ options ]
1298
1299 OPTIONS:
1300 -h, --help
1301 Display help information.
1302 --version
1303 Display script version.
1304 -v, --verbose
1305 Display debugging info.
1306 -e, --encrypt
1307 Encrypt output.
1308 -r, --recipient [ string pubkey ]
1309 Specify recipient. May be age or ssh pubkey.
1310 May be specified multiple times for multiple pubkeys.
1311 See https://github.com/FiloSottile/age
1312 -o, --output [ path dir ]
1313 Specify output directory to save logs. This option is required
1314 to save log data.
1315 -p, --process-string [ filter command ] [ output file extension]
1316 Specify how to create and name a processed version of the stdin.
1317 For example, if stdin is 'nmea' location data:
1318
1319 -p "gpsbabel -i nmea -f - -o gpx -F - " ".gpx"
1320
1321 This option would cause the stdin to 'bklog' to be piped into
1322 the 'gpsbabel' command, interpreted as 'nmea' data, converted
1323 into 'gpx' format, and then appended to the output tar file
1324 as a file with a '.gpx' extension.
1325 This option may be specified multiple times in order to output
1326 results of multiple different processing methods.
1327 -l, --label [ string ]
1328 Specify a label to be included in all output file names.
1329 Ex: 'location' if stdin is location data.
1330 -w, --store-raw [ file extension ]
1331 Specify file extension of file within output tar that contains
1332 raw stdin data. The default behavior is to always save raw stdin
1333 data in a '.stdin' file. Example usage when 'bklog' receives
1334 'nmea' data from 'gpspipe -r':
1335
1336 -w ".nmea"
1337
1338 Stdin data is saved in a '.nmea' file within the output tar.
1339 -W, --no-store-raw
1340 Do not store raw stdin in output tar.
1341 -c, --compress
1342 Compress output with gzip (before encryption if enabled).
1343 -z, --time-zone
1344 Specify time zone. (ex: "America/New_York")
1345 -t, --temp-dir [path dir]
1346 Specify parent directory for temporary working directory.
1347 Default: "/dev/shm"
1348 -R, --recipient-dir [path dir]
1349 Specify directory containing files whose first lines are
1350 to be interpreted as pubkey strings (see '-r' option). Only
1351 one directory may be specified.
1352 -b, --buffer-ttl [integer]
1353 Specify custom buffer period in seconds (default: 300 seconds)
1354 -B, --script-ttl [time element string]
1355 Specify custom script time-to-live in seconds (default: "day")
1356 Valid values: "day", "hour"
1357
1358 EXAMPLE: (bash script lines)
1359 $ gpspipe -r | /bin/bash bklog -v -e -c -z "UTC" -t "/dev/shm" \
1360 -r age1mrmfnwhtlprn4jquex0ukmwcm7y2nxlphuzgsgv8ew2k9mewy3rs8u7su5 \
1361 -r age1ala848kqrvxc88rzaauc6vc5v0fqrvef9dxyk79m0vjea3hagclswu0lgq \
1362 -R ~/.config/bklog/recipients -w ".nmea" -b 300 -B "day" \
1363 -o ~/Sync/Logs -l "location" \
1364 -p "gpsbabel -i nmea -f - -o gpx -F - " ".gpx" \
1365 -p "gpsbabel -i nmea -f - -o kml -F - " ".kml"
1366EOF
1367} # Display information on how to use this script.
4e4707fb 1368
5938a598 1369main() {
80fbd111
SBS
1370 # Desc: Main function
1371 # Usage: main "$@"
1372 # Inputs: many
1373 # Outputs: file (pathout_tar)
1374 # Depends: many
1375 local fn
1376
1377 # Debug:Get function name
1378 fn="${FUNCNAME[0]}";
1379
1380 vbm "STATUS:$fn:Started function main().";
c5da633d
SBS
1381 # Process arguments
1382 processArguments "$@";
1383 ## Determine working directory
1384 magicInitWorkingDir; # Sets dir_tmp from argTempDirPriority
1385 ## Set output encryption and compression option strings
236c8b97
SBS
1386 ### React to "-e", "-r", and "-R" (encryption recipients) options
1387 magicParseRecipients; # Update cmd_encrypt, cmd_encrypt_suffix
c5da633d
SBS
1388 ### React to "-c" ("compression") option
1389 magicParseCompressionArg; # Updates cmd_compress[_suffix]
1390 ## React to "-b" and "-B" (custom buffer and script TTL) options
1391 magicParseCustomTTL; # Sets custom scriptTTL_TE and/or bufferTTL if specified
1392 ## React to "-p" (user-supplied process command and file extension strings) options
1393 magicParseProcessStrings; # Sets arrays: procStrings, procFileExts
1394 ## React to "-l" (output file label) option
1395 magicParseLabel; # sets label (ex: "_location")
c5da633d
SBS
1396
1397 # Perform secondary setup operations
1398 ## Set script lifespan (scriptTTL from scriptTTL_TE)
1399 magicSetScriptTTL "$scriptTTL_TE";
1400 ## File name substring (ISO-8601 duration from bufferTTL)
fcefae4c 1401 bufferTTL_STR="$(timeDuration "$bufferTTL")" && vbm "DEBUG :$fn:bufferTTL_STR:$bufferTTL_STR";
c5da633d 1402 ## Init temp working dir
fcefae4c 1403 try mkdir "$dir_tmp" && vbm "DEBUG :$fn:Working dir created at dir_tmp:$dir_tmp";
c5da633d 1404 ## Initialize output tar (set pathout_tar)
195dd3c3
SBS
1405 magicInitCheckTar;
1406 ## Append VERSION file to tar
1407 magicWriteVersion;
c5da633d
SBS
1408
1409 # Check vital apps, files, dirs
1410 if ! checkapp tar && ! checkdir "$dirOut" "dir_tmp"; then
80fbd111 1411 yell "ERROR:$fn:Critical components missing.";
c5da633d
SBS
1412 displayMissing; yell "Exiting."; exit 1; fi
1413
1414 # MAIN LOOP: Run until script TTL seconds pass
5938a598 1415 bufferRound=0;
5938a598 1416 while [[ $SECONDS -lt "scriptTTL" ]]; do
80fbd111 1417 vbm "STATUS:$fn:Starting buffer round:$bufferRound";
c5da633d 1418 bufferTOD="$((SECONDS + bufferTTL))"; # Set buffer round time-of-death
5938a598
SBS
1419 # Consume stdin to fill buffer until buffer time-of-death (TOD) arrives
1420 while read -r -t "$bufferTTL" line && [[ $SECONDS -lt "$bufferTOD" ]]; do
1421 # Append line to buffer array
1422 buffer+=("$line");
5938a598 1423 done;
c5da633d 1424 # Create dir_tmp if missing
80fbd111
SBS
1425 if ! [[ -d "$dir_tmp" ]]; then
1426 yell "ERROR:$fn:dir_tmp existence failure:$dir_tmp";
fcefae4c 1427 try mkdir "$dir_tmp" && vbm "DEBUG :$fn:Working dir recreated dir_tmp:$dir_tmp"; fi
236c8b97
SBS
1428 # Update cmd_encrypt, cmd_encrypt_suffix
1429 magicParseRecipients;
5938a598
SBS
1430 # Export buffer to asynchronous processing.
1431 magicProcessWriteBuffer &
1432 unset buffer; # Clear buffer array for next bufferRound
1433 # Increment buffer round
1434 ((bufferRound++));
1435 done;
c5da633d
SBS
1436
1437 # Cleanup
1438 ## Remove dir_tmp
80fbd111 1439 try rm -r "$dir_tmp" && vbm "STATUS:$fn:Removed dir_tmp:$dir_tmp";
c5da633d 1440
80fbd111 1441 vbm "STATUS:$fn:Finished function main().";
c5da633d 1442} # Main function
6cbe7c0a 1443
5938a598
SBS
1444#===END Declare local script functions===
1445#==END Define script parameters==
1446
1447#==BEGIN Perform work and exit==
1448main "$@" # Run main function.
1449exit 0;
1450#==END Perform work and exit==
1451
1452# Author: Steven Baltakatei Sandoval;
6cbe7c0a 1453# License: GPLv3+