feat(bkgpslog):Add additional validation for age pubkeys
[EVA-2020-02.git] / exec / bkgpslog
CommitLineData
032f4b05
SBS
1#!/bin/bash
2
8fbca23d
SBS
3# Desc: Records gps data until midnight
4# Author: Steven Baltakatei Sandoval; License: GPLv3+
aa2a49f1 5# Usage: bkgpslog -o [output dir]
032f4b05 6
8fbca23d 7#==BEGIN Define script parameters==
6c30388f 8## Logging Behavior parameters
3fd6a69e 9BUFFER_TTL="300"; # time between file writes
6c30388f 10SCRIPT_TTL="day"; # (day|hour)
aa2a49f1
SBS
11#### TZ="UTC"; export TZ; # Default time zone; overridden by '--time-zone=[str]' option
12DIR_TMP_DEFAULT="/dev/shm"; # Default parent of working directory
6c30388f 13
aa2a49f1
SBS
14SCRIPT_TIME_START=$(date +%Y%m%dT%H%M%S.%N);
15PATH="$HOME/.local/bin:$PATH"; # Add "$(systemd-path user-binaries)" path in case apps saved there
16SCRIPT_HOSTNAME=$(hostname); # Save hostname of system running this script.
d6ba4173 17SCRIPT_VERSION="0.3.8"; # Define version of script.
ff22a93f
SBS
18SCRIPT_NAME="bkgpslog"; # Define basename of script file.
19SCRIPT_URL="https://gitlab.com/baltakatei/ninfacyzga-01"; # Define wesite hosting this script.
20AGE_VERSION="1.0.0-beta2"; # Define version of age (encryption program)
21AGE_URL="https://github.com/FiloSottile/age/releases/tag/v1.0.0-beta2"; # Define website hosting age.
8fbca23d
SBS
22
23declare -Ag appRollCall # Associative array for storing app status
24declare -Ag fileRollCall # Associative array for storing file status
25declare -Ag dirRollCall # Associative array for storing dir status
17d49005 26declare -a recPubKeys # for processArguments function
77361307 27declare recipients # for main function
8fbca23d 28
cfc25c90
SBS
29## Initialize variables
30OPTION_VERBOSE=""; OPTION_ENCRYPT=""; OPTION_COMPRESS=""; OPTION_TMPDIR="";
31
8fbca23d
SBS
32#===BEGIN Declare local script functions===
33checkapp() {
34 # Desc: If arg is a command, save result in assoc array 'appRollCall'
35 # Usage: checkapp arg1 arg2 arg3 ...
36 # Input: global assoc. array 'appRollCall'
37 # Output: adds/updates key(value) to global assoc array 'appRollCall'
38 local returnState
39 #echo "DEBUG:$(date +%S.%N)..Starting checkapp function."
40 #echo "DEBUG:args: $@"
41 #echo "DEBUG:returnState:$returnState"
42
43 #===Process Args===
44 for arg in "$@"; do
45 #echo "DEBUG:processing arg:$arg"
0b3dde05 46 if command -v "$arg" 1>/dev/null 2>&1; then # Check if arg is a valid command
8fbca23d
SBS
47 appRollCall[$arg]="true";
48 #echo "DEBUG:appRollCall[$arg]:"${appRollCall[$arg]}
49 if ! [ "$returnState" = "false" ]; then returnState="true"; fi
50 else
51 appRollCall[$arg]="false"; returnState="false";
52 fi
53 done
54
55 #for key in "${!appRollCall[@]}"; do echo "DEBUG:$key => ${appRollCall[$key]}"; done
56 #echo "DEBUG:evaluating returnstate. returnState:"$returnState
57
58 #===Determine function return code===
59 if [ "$returnState" = "true" ]; then
60 #echo "DEBUG:checkapp returns true for $arg";
61 return 0;
62 else
63 #echo "DEBUG:checkapp returns false for $arg";
64 return 1;
65 fi
66} # Check that app exists
67checkfile() {
68 # Desc: If arg is a file path, save result in assoc array 'fileRollCall'
69 # Usage: checkfile arg1 arg2 arg3 ...
70 # Input: global assoc. array 'fileRollCall'
71 # Output: adds/updates key(value) to global assoc array 'fileRollCall';
72 # Output: returns 0 if app found, 1 otherwise
73 local returnState
74
75 #===Process Args===
76 for arg in "$@"; do
77 #echo "DEBUG:processing arg:$arg"
78 if [ -f "$arg" ]; then
79 fileRollCall["$arg"]="true";
80 #echo "DEBUG:fileRollCall[\"$arg\"]:"${fileRollCall["$arg"]}
81 if ! [ "$returnState" = "false" ]; then returnState="true"; fi
82 else
83 fileRollCall["$arg"]="false"; returnState="false";
84 fi
85 done
86
87 #for key in "${!fileRollCall[@]}"; do echo "DEBUG:fileRollCall key [$key] is:${fileRollCall[$key]}"; done
88 #echo "DEBUG:evaluating returnstate. returnState:"$returnState
89
90 #===Determine function return code===
91 if [ "$returnState" = "true" ]; then
92 #echo "DEBUG:checkapp returns true for $arg";
93 return 0;
94 else
95 #echo "DEBUG:checkapp returns false for $arg";
96 return 1;
97 fi
98} # Check that file exists
99checkdir() {
100 # Desc: If arg is a dir path, save result in assoc array 'dirRollCall'
101 # Usage: checkdir arg1 arg2 arg3 ...
102 # Input: global assoc. array 'dirRollCall'
103 # Output: adds/updates key(value) to global assoc array 'dirRollCall';
104 # Output: returns 0 if app found, 1 otherwise
105 local returnState
106
107 #===Process Args===
108 for arg in "$@"; do
109 #echo "DEBUG:processing arg:$arg"
110 if [ -d "$arg" ]; then
111 dirRollCall["$arg"]="true";
112 #echo "DEBUG:dirRollCall[\"$arg\"]:"${dirRollCall["$arg"]}
113 if ! [ "$returnState" = "false" ]; then returnState="true"; fi
bcf09dcc 114 elif [ "$arg" = "" ]; then
8fbca23d 115 dirRollCall["$arg"]="false"; returnState="false";
bcf09dcc
SBS
116 else
117 returnState="false";
8fbca23d
SBS
118 fi
119 done
120
121 #for key in "${!dirRollCall[@]}"; do echo "DEBUG:dirRollCall key [$key] is:${dirRollCall[$key]}"; done
122 #echo "DEBUG:evaluating returnstate. returnState:"$returnState
123
124 #===Determine function return code===
125 if [ "$returnState" = "true" ]; then
126 #echo "DEBUG:checkapp returns true for $arg";
127 return 0;
128 else
129 #echo "DEBUG:checkapp returns false for $arg";
130 return 1;
131 fi
132} # Check that dir exists
032f4b05 133
c609b9c8
SBS
134# Yell, Die, Try Three-Fingered Claw technique
135# Ref/Attrib: https://stackoverflow.com/a/25515370
136yell() { echo "$0: $*" >&2; }
137die() { yell "$*"; exit 111; }
138try() { "$@" || die "cannot $*"; }
139
032f4b05
SBS
140echoerr() {
141 echo "$@" 1>&2; # Define stderr echo function.
142} # Define stderr message function.
143showUsage() {
144 echoerr "USAGE:"
94e094d1 145 echoerr " bkgpslog [ options ]"
032f4b05
SBS
146 echoerr
147 echoerr "OPTIONS:"
148 echoerr " -h, --help"
149 echoerr " Display help information."
150 echoerr
151 echoerr " --version"
152 echoerr " Display script version."
153 echoerr
154 echoerr " -v, --verbose"
155 echoerr " Display debugging info."
156 echoerr
17d49005
SBS
157 echoerr " -e, --encrypt"
158 echoerr " Encrypt output."
159 echoerr
160 echoerr " -r, --recipient [ pubkey string ]"
f7f33d33
SBS
161 echoerr " Specify recipient. May be age or ssh pubkey."
162 echoerr " See https://github.com/FiloSottile/age"
17d49005 163 echoerr
032f4b05
SBS
164 echoerr " -o, --output [ directory ]"
165 echoerr " Specify output directory to save logs."
17d49005 166 echoerr
408a342b
SBS
167 echoerr " -c, --compress"
168 echoerr " Compress output with gzip (before encryption if enabled)."
169 echoerr
f7f33d33
SBS
170 echoerr " -z, --time-zone"
171 echoerr " Specify time zone. (ex: \"America/New_York\")"
172 echoerr
173 echoerr " -t, --temp-dir"
174 echoerr " Specify parent directory for temporary working directory."
175 echoerr " Default: \"/dev/shm\""
176 echoerr
17d49005 177 echoerr "EXAMPLE: (bash script lines)"
408a342b 178 echoerr "/bin/bash bkgpslog -e -c \\"
17d49005
SBS
179 echoerr "-r age1mrmfnwhtlprn4jquex0ukmwcm7y2nxlphuzgsgv8ew2k9mewy3rs8u7su5 \\"
180 echoerr "-r age1ala848kqrvxc88rzaauc6vc5v0fqrvef9dxyk79m0vjea3hagclswu0lgq \\"
181 echoerr "-o ~/Sync/Location"
032f4b05
SBS
182} # Display information on how to use this script.
183showVersion() {
184 echoerr "$SCRIPT_VERSION"
185} # Display script version.
186vbm() {
0b3dde05
SBS
187 # Usage: vbm "DEBUG:verbose message here"
188 # Description: Prints verbose message ("vbm") to stderr if OPTION_VERBOSE is set to "true".
189 # Input:
190 # - OPTION_VERBOSE variable set by processArguments function. (ex: "true", "false")
191 # - "$@" positional arguments fed to this function.
192 # Output: stderr
193 # Script function dependencies: echoerr
194 # External function dependencies: echo
195 # Last modified: 2020-04-11T23:57Z
196 # Last modified by: Steven Baltakatei Sandoval
197 # License: GPLv3+
198 # Ref./Attrib:
199
200 if [ "$OPTION_VERBOSE" = "true" ]; then
201 FUNCTION_TIME=$(date --iso-8601=ns); # Save current time in nano seconds.
202 echoerr "[$FUNCTION_TIME] ""$*"; # Display argument text.
032f4b05 203 fi
0b3dde05
SBS
204
205 # End function
206 return 0; # Function finished.
032f4b05
SBS
207} # Verbose message display function.
208processArguments() {
209 while [ ! $# -eq 0 ]; do # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
d6896d3b
SBS
210 #echoerr "DEBUG:Starting processArguments while loop."
211 #echoerr "DEBUG:Provided arguments are:""$*"
032f4b05 212 case "$1" in
c1bbf9f7 213 -h | --help) showUsage; exit 1;; # Display usage.
032f4b05 214 --version) showVersion; exit 1;; # Show version
c1bbf9f7 215 -v | --verbose) OPTION_VERBOSE="true"; vbm "DEBUG:Verbose mode enabled.";; # Enable verbose mode.
6c30388f 216 -o | --output) if [ -d "$2" ]; then DIR_OUT="$2"; vbm "DEBUG:DIR_OUT:$DIR_OUT"; shift; fi ;; # Define output directory.
17d49005
SBS
217 -e | --encrypt) OPTION_ENCRYPT="true"; vbm "DEBUG:Encrypted output mode enabled.";;
218 -r | --recipient) # Add 'age' recipient via public key string
405ce7df 219 recPubKeys+=("$2"); vbm "STATUS:pubkey added:""$2"; shift;;
408a342b 220 -c | --compress) OPTION_COMPRESS="true"; vbm "DEBUG:Compressed output mode enabled.";;
6a17e8e7
SBS
221 -z | --time-zone) try setTimeZoneEV "$2"; shift;;
222 -t | --temp-dir) OPTION_TMPDIR="true" && TMP_DIR_PRIORITY="$2"; shift;;
b0da06ca 223 *) echoerr "ERROR: Unrecognized argument: $1"; echoerr "STATUS:All arguments:$*"; exit 1;; # Handle unrecognized options.
032f4b05
SBS
224 esac
225 shift
226 done
227} # Argument Processing
6c30388f
SBS
228setTimeZoneEV(){
229 # Desc: Set time zone environment variable TZ
230 # Usage: setTimeZoneEV arg1
231 # Input: arg1: 'date'-compatible timezone string (ex: "America/New_York")
232 # TZDIR env var (optional; default: "/usr/share/zoneinfo")
233 # Output: exports TZ
234 # exit code 0 on success
235 # exit code 1 on incorrect number of arguments
236 # exit code 2 if unable to validate arg1
237 # Depends: yell, printenv, bash 5
238 # Tested on: Debian 10
239 ARG1="$1"
240 local tzDir returnState
241 if ! [[ $# -eq 1 ]]; then
242 yell "ERROR:Invalid argument count.";
243 return 1;
244 fi
245
246 # Read TZDIR env var if available
247 if printenv TZDIR 1>/dev/null 2>&1; then
248 tzDir="$(printenv TZDIR)";
249 else
250 tzDir="/usr/share/zoneinfo";
251 fi
252
253 # Validate TZ string
254 if ! [[ -f "$tzDir"/"$ARG1" ]]; then
255 yell "ERROR:Invalid time zone argument.";
256 return 2;
257 else
258 # Export ARG1 as TZ environment variable
259 TZ="$ARG1" && export TZ && returnState="true";
260 fi
261
262 # Determine function return code
263 if [ "$returnState" = "true" ]; then
264 return 0;
265 fi
266} # Exports TZ environment variable
c2aaff78
SBS
267timeUntilNextDay(){
268 # Desc: Report seconds until next day.
3395ae22 269 # Version: 1.0.0
c2aaff78 270 # Output: stdout: integer seconds until next day
8fbca23d 271 # Output: exit code 0 if stdout > 0; 1 if stdout = 0; 2 if stdout < 0
c2aaff78
SBS
272 # Usage: timeUntilNextDay
273 # Usage: if ! myTTL="$(timeUntilNextDay)"; then yell "ERROR in if statement"; exit 1; fi
3395ae22
SBS
274 # Depends: date 8, echo 8, yell, try
275
c2aaff78 276 local returnState TIME_CURRENT TIME_NEXT_DAY SECONDS_UNTIL_NEXT_DAY
3395ae22 277
8fbca23d 278 TIME_CURRENT="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
c2aaff78
SBS
279 TIME_NEXT_DAY="$(date -d "$TIME_CURRENT next day" --iso-8601=date)"; # Produce timestamp of beginning of tomorrow with resolution of 1 second.
280 SECONDS_UNTIL_NEXT_DAY="$(( $(date +%s -d "$TIME_NEXT_DAY") - $(date +%s -d "$TIME_CURRENT") ))" ; # Calculate seconds until closest future midnight (res. 1 second).
281 if [[ "$SECONDS_UNTIL_NEXT_DAY" -gt 0 ]]; then
282 returnState="true";
283 elif [[ "$SECONDS_UNTIL_NEXT_DAY" -eq 0 ]]; then
3395ae22 284 returnState="warning_zero";
c2aaff78
SBS
285 yell "WARNING:Reported time until next day exactly zero.";
286 elif [[ "$SECONDS_UNTIL_NEXT_DAY" -lt 0 ]]; then
3395ae22 287 returnState="warning_negative";
c2aaff78
SBS
288 yell "WARNING:Reported time until next day is negative.";
289 fi
290
291 try echo "$SECONDS_UNTIL_NEXT_DAY"; # Report
292
3395ae22 293 # Determine function return code
c2aaff78
SBS
294 if [[ "$returnState" = "true" ]]; then
295 return 0;
3395ae22 296 elif [[ "$returnState" = "warning_zero" ]]; then
c2aaff78 297 return 1;
3395ae22 298 elif [[ "$returnState" = "warning_negative" ]]; then
c2aaff78
SBS
299 return 2;
300 fi
301} # Report seconds until next day
302timeUntilNextHour(){
303 # Desc: Report seconds until next hour
3395ae22 304 # Version 1.0.0
c2aaff78
SBS
305 # Output: stdout: integer seconds until next hour
306 # Output: exit code 0 if stdout > 0; 1 if stdout = 0; 2 if stdout < 0
307 # Usage: timeUntilNextHour
308 # Usage: if ! myTTL="$(timeUntilNextHour)"; then yell "ERROR in if statement"; exit 1; fi
3395ae22 309
c2aaff78
SBS
310 local returnState TIME_CURRENT TIME_NEXT_HOUR SECONDS_UNTIL_NEXT_HOUR
311 TIME_CURRENT="$(date --iso-8601=seconds)"; # Produce `date`-parsable current timestamp with resolution of 1 second.
312 TIME_NEXT_HOUR="$(date -d "$TIME_CURRENT next hour" --iso-8601=hours)"; # Produce `date`-parsable current time stamp with resolution of 1 second.
313 SECONDS_UNTIL_NEXT_HOUR="$(( $(date +%s -d "$TIME_NEXT_HOUR") - $(date +%s -d "$TIME_CURRENT") ))"; # Calculate seconds until next hour (res. 1 second).
314 if [[ "$SECONDS_UNTIL_NEXT_HOUR" -gt 0 ]]; then
8fbca23d 315 returnState="true";
c2aaff78 316 elif [[ "$SECONDS_UNTIL_NEXT_HOUR" -eq 0 ]]; then
3395ae22 317 returnState="warning_zero";
c2aaff78
SBS
318 yell "WARNING:Reported time until next hour exactly zero.";
319 elif [[ "$SECONDS_UNTIL_NEXT_HOUR" -lt 0 ]]; then
3395ae22 320 returnState="warning_negative";
c2aaff78 321 yell "WARNING:Reported time until next hour is negative.";
8fbca23d 322 fi
032f4b05 323
c2aaff78 324 try echo "$SECONDS_UNTIL_NEXT_HOUR"; # Report
8fbca23d 325
3395ae22 326 # Determine function return code
8fbca23d
SBS
327 if [[ "$returnState" = "true" ]]; then
328 return 0;
3395ae22 329 elif [[ "$returnState" = "warning_zero" ]]; then
8fbca23d 330 return 1;
3395ae22 331 elif [[ "$returnState" = "warning_negative" ]]; then
8fbca23d
SBS
332 return 2;
333 fi
c2aaff78 334} # Report seconds until next hour
8fbca23d
SBS
335dateTimeShort(){
336 # Desc: Timestamp without separators (YYYYmmddTHHMMSS+zzzz)
e47e8048
SBS
337 # Usage: dateTimeShort ([str date])
338 # Version 1.1.0
339 # Input: arg1: 'date'-parsable timestamp string (optional)
8fbca23d 340 # Output: stdout: timestamp (ISO-8601, no separators)
e47e8048 341 # Depends: yell
c2aaff78 342 local TIME_CURRENT TIME_CURRENT_SHORT
e47e8048
SBS
343
344 argTime="$1";
345 # Get Current Time
8fbca23d 346 TIME_CURRENT="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
e47e8048
SBS
347 # Decide to parse current or supplied date
348 ## Check if time argument empty
349 if [[ -z "$argTime" ]]; then
350 ## T: Time argument empty, use current time
351 TIME_INPUT="$TIME_CURRENT";
352 else
353 ## F: Time argument exists, validate time
354 if date --date="$argTime" 1>/dev/null 2>&1; then
355 ### T: Time argument is valid; use it
356 TIME_INPUT="$argTime";
357 else
358 ### F: Time argument not valid; exit
359 yell "ERROR:Invalid time argument supplied. Exiting."; exit 1;
360 fi
361 fi
362 # Construct and deliver separator-les date string
363 TIME_CURRENT_SHORT="$(date -d "$TIME_INPUT" +%Y%m%dT%H%M%S%z)";
8fbca23d 364 echo "$TIME_CURRENT_SHORT";
6c30388f
SBS
365} # Get YYYYmmddTHHMMSS±zzzz
366dateShort(){
367 # Desc: Date without separators (YYYYmmdd)
e47e8048
SBS
368 # Usage: dateShort ([str date])
369 # Version: 1.1.0
370 # Input: arg1: 'date'-parsable timestamp string (optional)
6c30388f 371 # Output: stdout: date (ISO-8601, no separators)
e47e8048 372 # Depends: yell
6c30388f 373 local TIME_CURRENT DATE_CURRENT_SHORT
e47e8048
SBS
374
375 argTime="$1";
376 # Get Current Time
6c30388f 377 TIME_CURRENT="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
e47e8048
SBS
378 # Decide to parse current or supplied date
379 ## Check if time argument empty
380 if [[ -z "$argTime" ]]; then
381 ## T: Time argument empty, use current time
382 TIME_INPUT="$TIME_CURRENT";
383 else
384 ## F: Time argument exists, validate time
385 if date --date="$argTime" 1>/dev/null 2>&1; then
386 ### T: Time argument is valid; use it
387 TIME_INPUT="$argTime";
388 else
389 ### F: Time argument not valid; exit
390 yell "ERROR:Invalid time argument supplied. Exiting."; exit 1;
391 fi
392 fi
393 # Construct and deliver separator-les date string
394 DATE_CURRENT_SHORT="$(date -d "$TIME_INPUT" +%Y%m%d)"; # Produce separator-less current date with resolution 1 day.
6c30388f
SBS
395 echo "$DATE_CURRENT_SHORT";
396} # Get YYYYmmdd
397timeDuration(){
a7b4a273 398 # Desc: Given seconds, output ISO-8601 duration string
6c30388f
SBS
399 # Ref/Attrib: ISO-8601:2004(E), §4.4.4.2 Representations of time intervals by duration and context information
400 # Note: "1 month" ("P1M") is assumed to be "30 days" (see ISO-8601:2004(E), §2.2.1.2)
a7b4a273
SBS
401 # Usage: timeDuration [1:seconds] ([2:precision])
402 # Version: 1.0.3
6c30388f
SBS
403 # Input: arg1: seconds as base 10 integer >= 0 (ex: 3601)
404 # arg2: precision level (optional; default=2)
405 # Output: stdout: ISO-8601 duration string (ex: "P1H1S", "P2Y10M15DT10H30M20S")
a7b4a273
SBS
406 # exit code 0: success
407 # exit code 1: error_input
408 # exit code 2: error_unknown
6c30388f 409 # Example: 'timeDuration 111111 3' yields 'P1DT6H51M'
3395ae22 410 # Depends: date 8 (gnucoreutils), yell,
a7b4a273 411 local returnState argSeconds argPrecision remainder precision witherPrecision
3395ae22
SBS
412 local fullYears fullMonths fullDays fullHours fullMinutes fullSeconds
413 local displayYears displayMonths displayDays displayHours displayMinutes displaySeconds
414 local hasYears hasMonths hasDays hasHours hasMinutes hasSeconds
415
a7b4a273
SBS
416 argSeconds="$1"; # read arg1 (seconds)
417 argPrecision="$2"; # read arg2 (precision)
6c30388f 418 precision=2; # set default precision
6c30388f
SBS
419
420 # Check that between one and two arguments is supplied
421 if ! { [[ $# -ge 1 ]] && [[ $# -le 2 ]]; }; then
422 yell "ERROR:Invalid number of arguments:$# . Exiting.";
a7b4a273 423 returnState="error_input"; fi
6c30388f 424
a7b4a273 425 # Check that argSeconds provided
6c30388f 426 if [[ $# -ge 1 ]]; then
a7b4a273
SBS
427 ## Check that argSeconds is a positive integer
428 if [[ "$argSeconds" =~ ^[[:digit:]]+$ ]]; then
3395ae22 429 :
6c30388f 430 else
a7b4a273
SBS
431 yell "ERROR:argSeconds not a digit.";
432 returnState="error_input";
6c30388f
SBS
433 fi
434 else
435 yell "ERROR:No argument provided. Exiting.";
436 exit 1;
437 fi
438
a7b4a273 439 # Consider whether argPrecision was provided
6c30388f 440 if [[ $# -eq 2 ]]; then
a7b4a273
SBS
441 # Check that argPrecision is a positive integer
442 if [[ "$argPrecision" =~ ^[[:digit:]]+$ ]] && [[ "$argPrecision" -gt 0 ]]; then
443 precision="$argPrecision";
6c30388f 444 else
a7b4a273
SBS
445 yell "ERROR:argPrecision not a positive integer. (is $argPrecision ). Leaving early.";
446 returnState="error_input";
6c30388f
SBS
447 fi;
448 else
3395ae22 449 :
6c30388f
SBS
450 fi;
451
a7b4a273 452 remainder="$argSeconds" ; # seconds
6c30388f
SBS
453 ## Calculate full years Y, update remainder
454 fullYears=$(( remainder / (365*24*60*60) ));
455 remainder=$(( remainder - (fullYears*365*24*60*60) ));
456 ## Calculate full months M, update remainder
457 fullMonths=$(( remainder / (30*24*60*60) ));
458 remainder=$(( remainder - (fullMonths*30*24*60*60) ));
459 ## Calculate full days D, update remainder
460 fullDays=$(( remainder / (24*60*60) ));
461 remainder=$(( remainder - (fullDays*24*60*60) ));
462 ## Calculate full hours H, update remainder
463 fullHours=$(( remainder / (60*60) ));
464 remainder=$(( remainder - (fullHours*60*60) ));
465 ## Calculate full minutes M, update remainder
466 fullMinutes=$(( remainder / (60) ));
467 remainder=$(( remainder - (fullMinutes*60) ));
468 ## Calculate full seconds S, update remainder
469 fullSeconds=$(( remainder / (1) ));
470 remainder=$(( remainder - (remainder*1) ));
471 ## Check which fields filled
472 if [[ $fullYears -gt 0 ]]; then hasYears="true"; else hasYears="false"; fi
473 if [[ $fullMonths -gt 0 ]]; then hasMonths="true"; else hasMonths="false"; fi
474 if [[ $fullDays -gt 0 ]]; then hasDays="true"; else hasDays="false"; fi
475 if [[ $fullHours -gt 0 ]]; then hasHours="true"; else hasHours="false"; fi
476 if [[ $fullMinutes -gt 0 ]]; then hasMinutes="true"; else hasMinutes="false"; fi
477 if [[ $fullSeconds -gt 0 ]]; then hasSeconds="true"; else hasSeconds="false"; fi
478
479 ## Determine which fields to display (see ISO-8601:2004 §4.4.3.2)
480 witherPrecision="false"
481
482 ### Years
483 if $hasYears && [[ $precision -gt 0 ]]; then
484 displayYears="true";
485 witherPrecision="true";
486 else
487 displayYears="false";
488 fi;
489 if $witherPrecision; then ((precision--)); fi;
490
491 ### Months
492 if $hasMonths && [[ $precision -gt 0 ]]; then
493 displayMonths="true";
494 witherPrecision="true";
495 else
496 displayMonths="false";
497 fi;
498 if $witherPrecision && [[ $precision -gt 0 ]]; then
499 displayMonths="true";
500 fi;
501 if $witherPrecision; then ((precision--)); fi;
502
503 ### Days
504 if $hasDays && [[ $precision -gt 0 ]]; then
505 displayDays="true";
506 witherPrecision="true";
507 else
508 displayDays="false";
509 fi;
510 if $witherPrecision && [[ $precision -gt 0 ]]; then
511 displayDays="true";
512 fi;
513 if $witherPrecision; then ((precision--)); fi;
514
515 ### Hours
516 if $hasHours && [[ $precision -gt 0 ]]; then
517 displayHours="true";
518 witherPrecision="true";
519 else
520 displayHours="false";
521 fi;
522 if $witherPrecision && [[ $precision -gt 0 ]]; then
523 displayHours="true";
524 fi;
525 if $witherPrecision; then ((precision--)); fi;
526
527 ### Minutes
528 if $hasMinutes && [[ $precision -gt 0 ]]; then
529 displayMinutes="true";
530 witherPrecision="true";
531 else
532 displayMinutes="false";
533 fi;
534 if $witherPrecision && [[ $precision -gt 0 ]]; then
535 displayMinutes="true";
536 fi;
537 if $witherPrecision; then ((precision--)); fi;
538
539 ### Seconds
540
541 if $hasSeconds && [[ $precision -gt 0 ]]; then
542 displaySeconds="true";
543 witherPrecision="true";
544 else
545 displaySeconds="false";
546 fi;
547 if $witherPrecision && [[ $precision -gt 0 ]]; then
548 displaySeconds="true";
549 fi;
550 if $witherPrecision; then ((precision--)); fi;
551
6c30388f
SBS
552 ## Determine whether or not the "T" separator is needed to separate date and time elements
553 if ( $displayHours || $displayMinutes || $displaySeconds); then
554 displayDateTime="true"; else displayDateTime="false"; fi
555
556 ## Construct duration output string
557 OUTPUT="P"
558 if $displayYears; then
559 OUTPUT=$OUTPUT$fullYears"Y"; fi
560 if $displayMonths; then
561 OUTPUT=$OUTPUT$fullMonths"M"; fi
562 if $displayDays; then
563 OUTPUT=$OUTPUT$fullDays"D"; fi
564 if $displayDateTime; then
565 OUTPUT=$OUTPUT"T"; fi
566 if $displayHours; then
567 OUTPUT=$OUTPUT$fullHours"H"; fi
568 if $displayMinutes; then
569 OUTPUT=$OUTPUT$fullMinutes"M"; fi
570 if $displaySeconds; then
571 OUTPUT=$OUTPUT$fullSeconds"S"; fi
572
573 ## Output duration string to stdout
a7b4a273 574 echo "$OUTPUT" && returnState="true";
6c30388f
SBS
575
576 #===Determine function return code===
577 if [ "$returnState" = "true" ]; then
578 return 0;
a7b4a273
SBS
579 elif [ "$returnState" = "error_input" ]; then
580 yell "ERROR:input";
6c30388f 581 return 1;
a7b4a273
SBS
582 else
583 yell "ERROR:Unknown";
584 return 2;
6c30388f
SBS
585 fi
586
587} # Get duration (ex: PT10M4S )
588displayMissing() {
589 # Desc: Displays missing apps, files, and dirs
590 # Usage: displayMissing
591 # Input: associative arrays: appRollCall, fileRollCall, dirRollCall
592 # Output: stderr messages
593 #==BEGIN Display errors==
594 #===BEGIN Display Missing Apps===
595 missingApps="Missing apps :"
596 #for key in "${!appRollCall[@]}"; do echo "DEBUG:$key => ${appRollCall[$key]}"; done
597 for key in "${!appRollCall[@]}"; do
598 value="${appRollCall[$key]}"
599 if [ "$value" = "false" ]; then
600 #echo "DEBUG:Missing apps: $key => $value";
601 missingApps="$missingApps""$key "
602 appMissing="true"
603 fi
604 done
605 if [ "$appMissing" = "true" ]; then # Only indicate if an app is missing.
606 echo "$missingApps" 1>&2;
607 fi
608 #===END Display Missing Apps===
609
610 #===BEGIN Display Missing Files===
611 missingFiles="Missing files:"
612 #for key in "${!fileRollCall[@]}"; do echo "DEBUG:$key => ${fileRollCall[$key]}"; done
613 for key in "${!fileRollCall[@]}"; do
614 value="${fileRollCall[$key]}"
615 if [ "$value" = "false" ]; then
616 #echo "DEBUG:Missing files: $key => $value";
617 missingFiles="$missingFiles""$key "
618 fileMissing="true"
619 fi
620 done
621 if [ "$fileMissing" = "true" ]; then # Only indicate if an app is missing.
622 echo "$missingFiles" 1>&2;
623 fi
624 #===END Display Missing Files===
625
626 #===BEGIN Display Missing Directories===
627 missingDirs="Missing dirs:"
628 #for key in "${!dirRollCall[@]}"; do echo "DEBUG:$key => ${dirRollCall[$key]}"; done
629 for key in "${!dirRollCall[@]}"; do
630 value="${dirRollCall[$key]}"
631 if [ "$value" = "false" ]; then
632 #echo "DEBUG:Missing dirs: $key => $value";
633 missingDirs="$missingDirs""$key "
634 dirMissing="true"
635 fi
636 done
637 if [ "$dirMissing" = "true" ]; then # Only indicate if an dir is missing.
638 echo "$missingDirs" 1>&2;
639 fi
640 #===END Display Missing Directories===
641
642 #==END Display errors==
643} # Display missing apps, files, dirs
644setScriptTTL() {
645 #Desc: Sets script TTL
646 #Usage: setScriptTTL arg1
647 #Input: arg1: "day" or "hour"
648 #Output: scriptTTL
649 #Depends: timeUntilNextHour or timeUntilNextDay
650 local ARG1
651 ARG1="$1"
652 if [[ "$ARG1" = "day" ]]; then
653 # Set script lifespan to end at start of next day
654 if ! scriptTTL="$(timeUntilNextDay)"; then
655 if [[ "$scriptTTL" -eq 0 ]]; then
656 ((scriptTTL++)); # Add 1 because 0 would cause 'timeout' to never timeout.
657 else
658 yell "ERROR: timeUntilNextDay exit code $?"; exit 1;
659 fi;
660 fi;
661 elif [[ "$ARG1" = "hour" ]]; then
662 # Set script lifespan to end at start of next hour
663 if ! scriptTTL="$(timeUntilNextHour)"; then
664 if [[ "$scriptTTL" -eq 0 ]]; then
665 ((scriptTTL++)); # Add 1 because 0 would cause 'timeout' to never timeout.
666 else
667 yell "ERROR: timeUntilNextHour exit code $?"; exit 1;
668 fi;
669 fi;
670 else
671 yell "ERROR:Invalid argument for setScriptTTL function."; exit 1;
672 fi
673} # Seconds until next (day|hour).
f6fb18bd
SBS
674checkMakeTar() {
675 # Desc: Checks that a valid tar archive exists, creates one otherwise
676 # Usage: checkMakeTar [ path ]
2fc10824 677 # Version: 1.0.1
f6fb18bd 678 # Input: arg1: path of tar archive
2fc10824
SBS
679 # Output: exit code 0 : tar readable
680 # exit code 1 : tar missing; created
681 # exit code 2 : tar not readable; moved; replaced
f6fb18bd 682 # Depends: try, tar, date
2fc10824
SBS
683 local PATH_TAR returnFlag0 returnFlag1 returnFlag2
684 PATH_TAR="$1"
f6fb18bd
SBS
685
686 # Check if file is a valid tar archive
687 if tar --list --file="$PATH_TAR" 1>/dev/null 2>&1; then
688 ## T1: return success
2fc10824 689 returnFlag0="tar valid";
f6fb18bd
SBS
690 else
691 ## F1: Check if file exists
692 if [[ -f "$PATH_TAR" ]]; then
693 ### T: Rename file
2fc10824
SBS
694 try mv "$PATH_TAR" "$PATH_TAR""--broken--""$(date +%Y%m%dT%H%M%S)" && \
695 returnFlag1="tar moved";
f6fb18bd
SBS
696 else
697 ### F: -
698 :
699 fi
700 ## F2: Create tar archive, return 0
2fc10824
SBS
701 try tar --create --file="$PATH_TAR" --files-from=/dev/null && \
702 returnFlag2="tar created";
703 fi
704
705 # Determine function return code
706 if [[ "$returnFlag0" = "tar valid" ]]; then
f6fb18bd 707 return 0;
2fc10824
SBS
708 elif [[ "$returnFlag2" = "tar created" ]] && ! [[ "$returnFlag1" = "tar moved" ]]; then
709 return 1; # tar missing so created
710 elif [[ "$returnFlag2" = "tar created" ]] && [[ "$returnFlag1" = "tar moved" ]]; then
711 return 2; # tar not readable so moved; replaced
f6fb18bd
SBS
712 fi
713} # checks if arg1 is tar; creates one otherwise
66af6225
SBS
714appendArgTar(){
715 # Desc: Writes first argument to temporary file with arguments as options, then appends file to tar
e47e8048 716 # Usage: appendArgTar "$(echo "Data to be written.")" [name of file to be inserted] [tar path] [temp dir] ([cmd1] [cmd2] [cmd3] [cmd4]...)
f665ce95 717 # Version: 1.0.3
66af6225
SBS
718 # Input: arg1: data to be written
719 # arg2: file name of file to be inserted into tar
720 # arg3: tar archive path (must exist first)
721 # arg4: temporary working dir
722 # arg5+: command strings (ex: "gpsbabel -i nmea -f - -o kml -F - ")
723 # Output: file written to disk
724 # Example: decrypt multiple large files in parallel
725 # appendArgTar "$(cat /tmp/largefile1.gpg)" "largefile1" $HOME/archive.tar /tmp "gpg --decrypt" &
726 # appendArgTar "$(cat /tmp/largefile2.gpg)" "largefile2" $HOME/archive.tar /tmp "gpg --decrypt" &
727 # appendArgTar "$(cat /tmp/largefile3.gpg)" "largefile3" $HOME/archive.tar /tmp "gpg --decrypt" &
66af6225 728 # Depends: bash 5
f665ce95 729 # Ref/Attrib: Using 'eval' to construct command strings https://askubuntu.com/a/476533
66af6225 730
d9fe1eba 731 # Save function name
d7138c7f
SBS
732 local FN="${FUNCNAME[0]}";
733 #yell "DEBUG:STATUS:$FN:Finished appendArgTar()."
d9fe1eba 734
66af6225 735 # Set file name
d9fe1eba 736 if ! [ -z "$2" ]; then FILENAME="$2"; else yell "ERROR:$FN:Not enough arguments."; exit 1; fi
66af6225
SBS
737
738 # Check tar path is a file
d9fe1eba 739 if [ -f "$3" ]; then TAR_PATH="$3"; else yell "ERROR:$FN:Tar archive arg not a file."; exit 1; fi
66af6225
SBS
740
741 # Check temp dir arg
d9fe1eba 742 if ! [ -z "$4" ]; then TMP_DIR="$4"; else yell "ERROR:$FN:No temporary working dir set."; exit 1; fi
66af6225
SBS
743
744 # Set command strings
745 if ! [ -z "$5" ]; then CMD1="$5"; else CMD1="tee /dev/null "; fi # command string 1
746 if ! [ -z "$6" ]; then CMD2="$6"; else CMD2="tee /dev/null "; fi # command string 2
747 if ! [ -z "$7" ]; then CMD3="$7"; else CMD3="tee /dev/null "; fi # command string 3
748 if ! [ -z "$8" ]; then CMD4="$8"; else CMD4="tee /dev/null "; fi # command string 4
749
f665ce95
SBS
750 # Input command
751 CMD0="echo \"\$1\""
752
d7138c7f 753 # # Debug
f665ce95 754 # yell "DEBUG:STATUS:$FN:CMD0:$CMD0"
d7138c7f
SBS
755 # yell "DEBUG:STATUS:$FN:CMD1:$CMD1"
756 # yell "DEBUG:STATUS:$FN:CMD2:$CMD2"
757 # yell "DEBUG:STATUS:$FN:CMD3:$CMD3"
758 # yell "DEBUG:STATUS:$FN:CMD4:$CMD4"
759 # yell "DEBUG:STATUS:$FN:FILENAME:$FILENAME"
760 # yell "DEBUG:STATUS:$FN:TAR_PATH:$TAR_PATH"
761 # yell "DEBUG:STATUS:$FN:TMP_DIR:$TMP_DIR"
762
66af6225 763 # Write to temporary working dir
f665ce95 764 eval "$CMD0"" | ""$CMD1"" | ""$CMD2"" | ""$CMD3"" | ""$CMD4" > "$TMP_DIR"/"$FILENAME";
66af6225
SBS
765
766 # Append to tar
767 try tar --append --directory="$TMP_DIR" --file="$TAR_PATH" "$FILENAME";
d7138c7f 768 #yell "DEBUG:STATUS:$FN:Finished appendArgTar()."
66af6225 769} # Append Bash var to file appended to Tar archive
e47e8048
SBS
770appendFileTar(){
771 # Desc: Processes first file and then appends to tar
772 # Usage: appendFileTar [file path] [name of file to be inserted] [tar path] [temp dir] ([cmd1] [cmd2] [cmd3] [cmd4]...)
f665ce95 773 # Version: 1.0.2
e47e8048
SBS
774 # Input: arg1: path of file to be (processed and) written
775 # arg2: name to use for file inserted into tar
776 # arg3: tar archive path (must exist first)
777 # arg4: temporary working dir
778 # arg5+: command strings (ex: "gpsbabel -i nmea -f - -o kml -F - ")
779 # Output: file written to disk
780 # Example: decrypt multiple large files in parallel
781 # appendFileTar /tmp/largefile1.gpg "largefile1" $HOME/archive.tar /tmp "gpg --decrypt" &
782 # appendFileTar /tmp/largefile2.gpg "largefile2" $HOME/archive.tar /tmp "gpg --decrypt" &
783 # appendFileTar /tmp/largefile3.gpg "largefile3" $HOME/archive.tar /tmp "gpg --decrypt" &
784 # Depends: bash 5
785
786 # Save function name
787 local FN="${FUNCNAME[0]}";
788 #yell "DEBUG:STATUS:$FN:Finished appendFileTar()."
789
790 # Set file name
791 if ! [ -z "$2" ]; then FILENAME="$2"; else yell "ERROR:$FN:Not enough arguments."; exit 1; fi
792 # Check tar path is a file
793 if [ -f "$3" ]; then TAR_PATH="$3"; else yell "ERROR:$FN:Tar archive arg not a file."; exit 1; fi
794 # Check temp dir arg
795 if ! [ -z "$4" ]; then TMP_DIR="$4"; else yell "ERROR:$FN:No temporary working dir set."; exit 1; fi
796 # Set command strings
797 if ! [ -z "$5" ]; then CMD1="$5"; else CMD1="tee /dev/null "; fi # command string 1
798 if ! [ -z "$6" ]; then CMD2="$6"; else CMD2="tee /dev/null "; fi # command string 2
799 if ! [ -z "$7" ]; then CMD3="$7"; else CMD3="tee /dev/null "; fi # command string 3
800 if ! [ -z "$8" ]; then CMD4="$8"; else CMD4="tee /dev/null "; fi # command string 4
f665ce95
SBS
801
802 # Input command string
803 CMD0="cat \"\$1\""
804
e47e8048 805 # # Debug
f665ce95 806 # yell "DEBUG:STATUS:$FN:CMD0:$CMD0"
e47e8048
SBS
807 # yell "DEBUG:STATUS:$FN:CMD1:$CMD1"
808 # yell "DEBUG:STATUS:$FN:CMD2:$CMD2"
809 # yell "DEBUG:STATUS:$FN:CMD3:$CMD3"
810 # yell "DEBUG:STATUS:$FN:CMD4:$CMD4"
811 # yell "DEBUG:STATUS:$FN:FILENAME:$FILENAME"
812 # yell "DEBUG:STATUS:$FN:TAR_PATH:$TAR_PATH"
813 # yell "DEBUG:STATUS:$FN:TMP_DIR:$TMP_DIR"
814
815 # Write to temporary working dir
f665ce95 816 eval "$CMD0 | $CMD1 | $CMD2 | $CMD3 | $CMD4" > "$TMP_DIR"/"$FILENAME";
e47e8048
SBS
817
818 # Append to tar
819 try tar --append --directory="$TMP_DIR" --file="$TAR_PATH" "$FILENAME";
820 #yell "DEBUG:STATUS:$FN:Finished appendFileTar()."
821} # Append file to Tar archive
d6ba4173
SBS
822validateInput() {
823 # Desc: Validates Input
824 # Usage: validateInput [str input] [str input type]
825 # Version: 0.2.1
826 # Input: arg1: string to validate
827 # arg2: string specifying input type (ex:"ssh_pubkey")
828 # Output: return code 0: if input string matched specified string type
829 # Depends: bash 5, yell
830
831 # Save function name
832 local FN="${FUNCNAME[0]}";
833
834 # Process arguments
835 argInput="$1";
836 argType="$2";
837 if [[ $# -gt 2 ]]; then yell "ERROR:$0:$FN:Too many arguments."; exit 1; fi;
838
839 # Check for blank
840 if [[ -z "$argInput" ]]; then return 1; fi
841
842 # Define input types
843 ## ssh_pubkey
844 ### Check for alnum/dash base64 (ex: "ssh-rsa AAAAB3NzaC1yc2EAAA")
845 if [[ "$argType" = "ssh_pubkey" ]]; then
846 if [[ "$argInput" =~ ^[[:alnum:]-]*[\ ]*[[:alnum:]+/=]*$ ]]; then
847 return 0; fi; fi;
848
849 ## age_pubkey
850 ### Check for age1[:bech32:]
851 if [[ "$argType" = "age_pubkey" ]]; then
852 if [[ "$argInput" =~ ^age1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]*$ ]]; then
853 return 0; fi; fi
854
855 # Return error if no condition matched.
856 return 1;
857} # Validates strings
3395ae22
SBS
858magicWriteVersion() {
859 # Desc: Appends time-stamped VERSION to PATHOUT_TAR
860 # Usage: magicWriteVersion
ff22a93f 861 # Version: 0.1.0
3395ae22 862 # Input: CONTENT_VERSION, FILEOUT_VERSION, PATHOUT_TAR, DIR_TMP
ff22a93f
SBS
863 # Input: SCRIPT_VERSION, SCRIPT_URL, AGE_VERSION, AGE_URL, SCRIPT_HOSTNAME
864 # Output: appends tar PATHOUT_TAR
3395ae22 865 # Depends: dateTimeShort, appendArgTar
ff22a93f 866 local CONTENT_VERSION pubKeyIndex
3395ae22 867
ff22a93f 868 # Set VERSION file name
3395ae22 869 FILEOUT_VERSION="$(dateTimeShort)..VERSION";
ff22a93f
SBS
870
871 # Gather VERSION data in CONTENT_VERSION
872 CONTENT_VERSION="SCRIPT_VERSION=$SCRIPT_VERSION";
aa2d7921
SBS
873 #CONTENT_VERSION="$CONTENT_VERSION""\\n";
874 CONTENT_VERSION="$CONTENT_VERSION""\\n""SCRIPT_NAME=$SCRIPT_NAME";
875 CONTENT_VERSION="$CONTENT_VERSION""\\n""SCRIPT_URL=$SCRIPT_URL";
876 CONTENT_VERSION="$CONTENT_VERSION""\\n""AGE_VERSION=$AGE_VERSION";
877 CONTENT_VERSION="$CONTENT_VERSION""\\n""AGE_URL=$AGE_URL";
878 CONTENT_VERSION="$CONTENT_VERSION""\\n""DATE=$(date --iso-8601=seconds)";
879 CONTENT_VERSION="$CONTENT_VERSION""\\n""HOSTNAME=$SCRIPT_HOSTNAME";
ff22a93f
SBS
880 ## Add list of recipient pubkeys
881 for pubkey in "${recPubKeysValid[@]}"; do
882 ((pubKeyIndex++))
aa2d7921 883 CONTENT_VERSION="$CONTENT_VERSION""\\n""PUBKEY_$pubKeyIndex=$pubkey";
ff22a93f
SBS
884 done
885 ## Process newline escapes
4c0c5850
SBS
886 CONTENT_VERSION="$(echo -e "$CONTENT_VERSION")"
887
ff22a93f 888 # Write CONTENT_VERSION as file FILEOUT_VERSION and write-append to PATHOUT_TAR
3395ae22 889 appendArgTar "$CONTENT_VERSION" "$FILEOUT_VERSION" "$PATHOUT_TAR" "$DIR_TMP";
ff22a93f 890
3395ae22 891} # bkgpslog: write version data to PATHOUT_TAR via appendArgTar()
811f50f2 892magicGatherWriteBuffer() {
66af6225 893 # Desc: bkgpslog-specific meta function for writing data to DIR_TMP then appending each file to PATHOUT_TAR
e47e8048
SBS
894 # Inputs: PATHOUT_TAR FILEOUT_{NMEA,GPX,KML} CMD_CONV_{NMEA,GPX,KML} CMD_{COMPRESS,ENCRYPT} DIR_TMP,
895 # Inputs: BUFFER_TTL bufferTTL_STR SCRIPT_HOSTNAME CMD_COMPRESS_SUFFIX CMD_ENCRYPT_SUFFIX
f6fb18bd 896 # Depends: yell, try, vbm, appendArgTar, tar
1b0e6227 897 local FN="${FUNCNAME[0]}";
872c737e 898 wait; # Wait to avoid collision with older magicWriteBuffer() instances (see https://www.tldp.org/LDP/abs/html/x9644.html )
811f50f2
SBS
899 # Create buffer file with unique name
900 PATHOUT_BUFFER="$DIR_TMP/buffer$SECONDS";
901 # Fill buffer
902 timeout "$BUFFER_TTL"s gpspipe -r -o "$PATHOUT_BUFFER" ;
11f61f1a 903 timeBufferStart="$(dateTimeShort "$(date --date="$BUFFER_TTL seconds ago")")"; # Note start time
e47e8048
SBS
904 vbm "DEBUG:STATUS:$FN:Started magicWriteBuffer().";
905 # Determine file paths (time is start of buffer period)
906 FILEOUT_BASENAME="$timeBufferStart""--""$bufferTTL_STR""..""$SCRIPT_HOSTNAME""_location" && vbm "STATUS:Set FILEOUT_BASENAME to:$FILEOUT_BASENAME";
907 ## Files saved to DIR_TMP
908 FILEOUT_NMEA="$FILEOUT_BASENAME".nmea"$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX" && vbm "STATUS:Set FILEOUT_NMEA to:$FILEOUT_NMEA";
909 FILEOUT_GPX="$FILEOUT_BASENAME".gpx"$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX" && vbm "STATUS:Set FILEOUT_GPX to:$FILEOUT_GPX";
910 FILEOUT_KML="$FILEOUT_BASENAME".kml"$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX" && vbm "STATUS:Set FILEOUT_KML to:$FILEOUT_KML";
911 PATHOUT_NMEA="$DIR_TMP"/"$FILEOUT_NMEA" && vbm "STATUS:Set PATHOUT_NMEA to:$PATHOUT_NMEA";
912 PATHOUT_GPX="$DIR_TMP"/"$FILEOUT_GPX" && vbm "STATUS:Set PATHOUT_GPX to:$PATHOUT_GPX";
913 PATHOUT_KML="$DIR_TMP"/"$FILEOUT_KML" && vbm "STATUS:Set PATHOUT_KML to:$PATHOUT_KML";
914 ## Files saved to disk (DIR_OUT)
915 ### one file per day (Ex: "20200731..hostname_location.[.gpx.gz].tar")
916 PATHOUT_TAR="$DIR_OUT"/"$(dateShort "$(date --date="$BUFFER_TTL seconds ago")")".."$SCRIPT_HOSTNAME""_location""$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX".tar && \
917 vbm "STATUS:Set PATHOUT_TAR to:$PATHOUT_TAR";
918 # DEBUG: check vars
919 vbm "STATUS:DIR_TMP :$DIR_TMP";
920 vbm "STATUS:PATHOUT_TAR :$PATHOUT_TAR";
921 vbm "STATUS:PATHOUT_NMEA:$PATHOUT_NMEA";
922 vbm "STATUS:PATHOUT_GPX:$PATHOUT_GPX";
923 vbm "STATUS:PATHOUT_KML:$PATHOUT_KML";
924
925
3395ae22
SBS
926 # Validate PATHOUT_TAR as tar.
927 checkMakeTar "$PATHOUT_TAR";
928 ## Add VERSION file if checkMakeTar had to create a tar (exited 1) or replace one (exited 2)
929 if [[ $? -eq 1 ]] || [[ $? -eq 2 ]]; then magicWriteVersion; fi
f6fb18bd
SBS
930
931 # Write bufferBash to PATHOUT_TAR
e47e8048
SBS
932 appendFileTar "$PATHOUT_BUFFER" "$FILEOUT_NMEA" "$PATHOUT_TAR" "$DIR_TMP" "$CMD_CONV_NMEA" "$CMD_COMPRESS" "$CMD_ENCRYPT"; # Write NMEA data
933 appendFileTar "$PATHOUT_BUFFER" "$FILEOUT_GPX" "$PATHOUT_TAR" "$DIR_TMP" "$CMD_CONV_GPX" "$CMD_COMPRESS" "$CMD_ENCRYPT"; # Write GPX file
934 appendFileTar "$PATHOUT_BUFFER" "$FILEOUT_KML" "$PATHOUT_TAR" "$DIR_TMP" "$CMD_CONV_KML" "$CMD_COMPRESS" "$CMD_ENCRYPT"; # Write KML file
935
e0452100 936 # Remove secured chunks from DIR_TMP
e47e8048
SBS
937 rm "$PATHOUT_BUFFER" "$PATHOUT_NMEA" "$PATHOUT_GPX" "$PATHOUT_KML";
938 vbm "DEBUG:STATUS:$FN:Finished magicWriteBuffer().";
939} # write buffer to disk
66af6225 940
032f4b05 941main() {
0b3dde05 942 processArguments "$@" # Process arguments.
cfc25c90 943
aa2a49f1 944 # Determine working directory
cfc25c90
SBS
945 ## Set DIR_TMP_PARENT to user-specified value if specified
946 if [[ "$OPTION_TMPDIR" = "true" ]]; then
947 if [[ -d "$TMP_DIR_PRIORITY" ]]; then
948 DIR_TMP_PARENT="$OPTION_TMPDIR";
949 else
66af6225 950 yell "WARNING:Specified temporary working directory not valid:$OPTION_TMPDIR";
cfc25c90
SBS
951 exit 1;
952 fi
953 fi
954
955 ## Set DIR_TMP_PARENT to default or fallback otherwise
aa2a49f1 956 if [[ -d "$DIR_TMP_DEFAULT" ]]; then
cfc25c90
SBS
957 DIR_TMP_PARENT="$DIR_TMP_DEFAULT";
958 elif [[ -d /tmp ]]; then
959 yell "WARNING:/dev/shm not available. Falling back to /tmp .";
960 DIR_TMP_PARENT="/tmp";
aa2a49f1
SBS
961 else
962 yell "ERROR:No valid working directory available. Exiting.";
963 exit 1;
964 fi
cfc25c90
SBS
965
966 ## Set DIR_TMP using DIR_TMP_PARENT and nonce (SCRIPT_TIME_START)
0f4d2d90 967 DIR_TMP="$DIR_TMP_PARENT"/"$SCRIPT_TIME_START""..bkgpslog" && vbm "DEBUG:Set DIR_TMP to:$DIR_TMP"; # Note: removed at end of main().
aa2a49f1 968
6c30388f 969 # Set output encryption and compression option strings
17d49005
SBS
970 if [[ "$OPTION_ENCRYPT" = "true" ]]; then # Check if encryption option active.
971 if checkapp age; then # Check that age is available.
972 for pubkey in "${recPubKeys[@]}"; do # Validate recipient pubkey strings by forming test message
238775e6 973 vbm "DEBUG:Testing pubkey string:$pubkey";
d6ba4173
SBS
974 if echo "butts" | age -a -r "$pubkey" 1>/dev/null &&
975 ( validateInput "$pubkey" "ssh_pubkey" || validateInput "$pubkey" "age_pubkey"); then
ff22a93f 976 #### Form age recipient string
be9ef23e 977 recipients="$recipients""-r '$pubkey' ";
405ce7df 978 vbm "STATUS:Added pubkey for forming age recipient string:""$pubkey";
77361307 979 vbm "DEBUG:recipients:""$recipients";
ff22a93f
SBS
980 #### Add validated pubkey to recPubKeysValid array
981 recPubKeysValid+=("$pubkey") && vbm "DEBUG:recPubkeysValid:pubkey added:$pubkey";
408a342b
SBS
982 else
983 yell "ERROR:Exit code ""$?"". Invalid recipient pubkey string. Exiting."; exit 1;
77361307 984 fi
17d49005 985 done
77361307 986 vbm "DEBUG:Finished processing recPubKeys array";
ff22a93f
SBS
987
988 ## Form age command string
be9ef23e
SBS
989 CMD_ENCRYPT="age ""$recipients " && vbm "CMD_ENCRYPT:$CMD_ENCRYPT";
990 CMD_ENCRYPT_SUFFIX=".age" && vbm "CMD_ENCRYPT_SUFFIX:$CMD_ENCRYPT_SUFFIX";
17d49005
SBS
991 else
992 yell "ERROR:Encryption enabled but \"age\" not found. Exiting."; exit 1;
993 fi
408a342b 994 else
be9ef23e
SBS
995 CMD_ENCRYPT="tee /dev/null " && vbm "CMD_ENCRYPT:$CMD_ENCRYPT";
996 CMD_ENCRYPT_SUFFIX="" && vbm "CMD_ENCRYPT_SUFFIX:$CMD_ENCRYPT_SUFFIX";
408a342b 997 vbm "DEBUG:Encryption not enabled."
17d49005 998 fi
408a342b
SBS
999 if [[ "$OPTION_COMPRESS" = "true" ]]; then # Check if compression option active
1000 if checkapp gzip; then # Check if gzip available
be9ef23e
SBS
1001 CMD_COMPRESS="gzip " && vbm "CMD_COMPRESS:$CMD_COMPRESS";
1002 CMD_COMPRESS_SUFFIX=".gz" && vbm "CMD_COMPRESS_SUFFIX:$CMD_COMPRESS_SUFFIX";
408a342b
SBS
1003 else
1004 yell "ERROR:Compression enabled but \"gzip\" not found. Exiting."; exit 1;
286d9825 1005 fi
408a342b 1006 else
be9ef23e
SBS
1007 CMD_COMPRESS="tee /dev/null " && vbm "CMD_COMPRESS:$CMD_COMPRESS";
1008 CMD_COMPRESS_SUFFIX="" && vbm "CMD_COMPRESS_SUFFIX:$CMD_COMPRESS_SUFFIX";
1b0e6227 1009 vbm "DEBUG:Compression not enabled.";
408a342b 1010 fi
032f4b05 1011
6c30388f
SBS
1012 # Check that critical apps and dirs are available, displag missing ones.
1013 if ! checkapp gpspipe tar && ! checkdir "$DIR_OUT" "/dev/shm"; then
1014 yell "ERROR:Critical components missing.";
1015 displayMissing; yell "Exiting."; exit 1; fi
1016
1017 # Set script lifespan
3395ae22 1018 setScriptTTL "$SCRIPT_TTL"; # seconds until next new SCRIPT_TTL (ex: "day" or "hour")
6c30388f
SBS
1019
1020 # File name substring: encoded bufferTTL
1021 bufferTTL_STR="$(timeDuration $BUFFER_TTL)";
1022
1023 # Init temp working dir
3a7b92f8 1024 try mkdir "$DIR_TMP" && vbm "DEBUG:Working dir creatd at:$DIR_TMP";
6c30388f
SBS
1025
1026 # Initialize 'tar' archive
1027 ## Define output tar path (note: each day gets *one* tar file (Ex: "20200731..hostname_location.[.gpx.gz].tar"))
9efeccb5
SBS
1028 PATHOUT_TAR="$DIR_OUT"/"$(dateShort)".."$SCRIPT_HOSTNAME""_location""$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX".tar && \
1029 vbm "STATUS:Set PATHOUT_TAR to:$PATHOUT_TAR";
f6fb18bd
SBS
1030 ## Check that PATHOUT_TAR is a tar. Rename old and create empty one otherwise.
1031 checkMakeTar "$PATHOUT_TAR" && vbm "DEBUG:Confirmed or Created to be a tar:$PATHOUT_TAR";
6c30388f 1032 ## Append VERSION file to PATHOUT_TAR
3395ae22 1033 magicWriteVersion;
e47e8048
SBS
1034
1035 # Define GPS conversion commands
1036 CMD_CONV_NMEA="tee /dev/null " && vbm "STATUS:Set CMD_CONV_NMEA to:$CMD_CONV_NMEA"; # tee as passthrough
1037 CMD_CONV_GPX="gpsbabel -i nmea -f - -o gpx -F - " && vbm "STATUS:Set CMD_CONV_GPX to:$CMD_CONV_GPX"; # convert NMEA to GPX
1038 CMD_CONV_KML="gpsbabel -i nmea -f - -o kml -F - " && vbm "STATUS:Set CMD_CONV_KML to:$CMD_CONV_KML"; # convert NMEA to KML
811f50f2 1039
e47e8048 1040 # MAIN LOOP:Record gps data until script lifespan ends
6c30388f 1041 while [[ "$SECONDS" -lt "$scriptTTL" ]]; do
811f50f2 1042 magicGatherWriteBuffer &
238775e6 1043 sleep "$BUFFER_TTL";
811f50f2 1044 done
cfc25c90 1045
e47e8048
SBS
1046 # Cleanup
1047 ## Remove DIR_TMP
cfc25c90 1048 try rm -r "$DIR_TMP";
0aabe6a3 1049
1b0e6227 1050 vbm "STATUS:Main function finished.";
8fbca23d
SBS
1051} # Main function.
1052#===END Declare local script functions===
1053#==END Define script parameters==
032f4b05
SBS
1054
1055
8fbca23d
SBS
1056#==BEGIN Perform work and exit==
1057main "$@" # Run main function.
1058exit 0;
1059#==END Perform work and exit==