3 # Desc: Records gps data until midnight
4 # Author: Steven Baltakatei Sandoval; License: GPLv3+
5 # Usage: bkgpslog -o [output dir]
7 #==BEGIN Define script parameters==
8 ## Logging Behavior parameters
9 BUFFER_TTL
="300"; # time between file writes
10 SCRIPT_TTL
="day"; # (day|hour)
11 #### TZ="UTC"; export TZ; # Default time zone; overridden by '--time-zone=[str]' option
12 DIR_TMP_DEFAULT
="/dev/shm"; # Default parent of working directory
14 SCRIPT_TIME_START
=$
(date +%Y
%m
%dT
%H
%M
%S.
%N
);
15 PATH
="$HOME/.local/bin:$PATH"; # Add "$(systemd-path user-binaries)" path in case apps saved there
16 SCRIPT_HOSTNAME
=$
(hostname
); # Save hostname of system running this script.
17 SCRIPT_VERSION
="0.3.8"; # Define version of script.
18 SCRIPT_NAME
="bkgpslog"; # Define basename of script file.
19 SCRIPT_URL
="https://gitlab.com/baltakatei/ninfacyzga-01"; # Define wesite hosting this script.
20 AGE_VERSION
="1.0.0-beta2"; # Define version of age (encryption program)
21 AGE_URL
="https://github.com/FiloSottile/age/releases/tag/v1.0.0-beta2"; # Define website hosting age.
23 declare -Ag appRollCall
# Associative array for storing app status
24 declare -Ag fileRollCall
# Associative array for storing file status
25 declare -Ag dirRollCall
# Associative array for storing dir status
26 declare -a recPubKeys
# for processArguments function
27 declare recipients
# for main function
29 ## Initialize variables
30 OPTION_VERBOSE
=""; OPTION_ENCRYPT
=""; OPTION_COMPRESS
=""; OPTION_TMPDIR
="";
32 #===BEGIN Declare local script functions===
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'
39 #echo "DEBUG:$(date +%S.%N)..Starting checkapp function."
40 #echo "DEBUG:args: $@"
41 #echo "DEBUG:returnState:$returnState"
45 #echo "DEBUG:processing arg:$arg"
46 if command -v "$arg" 1>/dev
/null
2>&1; then # Check if arg is a valid command
47 appRollCall
[$arg]="true";
48 #echo "DEBUG:appRollCall[$arg]:"${appRollCall[$arg]}
49 if ! [ "$returnState" = "false" ]; then returnState
="true"; fi
51 appRollCall
[$arg]="false"; returnState
="false";
55 #for key in "${!appRollCall[@]}"; do echo "DEBUG:$key => ${appRollCall[$key]}"; done
56 #echo "DEBUG:evaluating returnstate. returnState:"$returnState
58 #===Determine function return code===
59 if [ "$returnState" = "true" ]; then
60 #echo "DEBUG:checkapp returns true for $arg";
63 #echo "DEBUG:checkapp returns false for $arg";
66 } # Check that app exists
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
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
83 fileRollCall
["$arg"]="false"; returnState
="false";
87 #for key in "${!fileRollCall[@]}"; do echo "DEBUG:fileRollCall key [$key] is:${fileRollCall[$key]}"; done
88 #echo "DEBUG:evaluating returnstate. returnState:"$returnState
90 #===Determine function return code===
91 if [ "$returnState" = "true" ]; then
92 #echo "DEBUG:checkapp returns true for $arg";
95 #echo "DEBUG:checkapp returns false for $arg";
98 } # Check that file exists
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
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
114 elif [ "$arg" = "" ]; then
115 dirRollCall
["$arg"]="false"; returnState
="false";
121 #for key in "${!dirRollCall[@]}"; do echo "DEBUG:dirRollCall key [$key] is:${dirRollCall[$key]}"; done
122 #echo "DEBUG:evaluating returnstate. returnState:"$returnState
124 #===Determine function return code===
125 if [ "$returnState" = "true" ]; then
126 #echo "DEBUG:checkapp returns true for $arg";
129 #echo "DEBUG:checkapp returns false for $arg";
132 } # Check that dir exists
134 # Yell, Die, Try Three-Fingered Claw technique
135 # Ref/Attrib: https://stackoverflow.com/a/25515370
136 yell
() { echo "$0: $*" >&2; }
137 die
() { yell
"$*"; exit 111; }
138 try
() { "$@" || die
"cannot $*"; }
141 echo "$@" 1>&2; # Define stderr echo function.
142 } # Define stderr message function.
145 echoerr
" bkgpslog [ options ]"
148 echoerr
" -h, --help"
149 echoerr
" Display help information."
152 echoerr
" Display script version."
154 echoerr
" -v, --verbose"
155 echoerr
" Display debugging info."
157 echoerr
" -e, --encrypt"
158 echoerr
" Encrypt output."
160 echoerr
" -r, --recipient [ pubkey string ]"
161 echoerr
" Specify recipient. May be age or ssh pubkey."
162 echoerr
" See https://github.com/FiloSottile/age"
164 echoerr
" -o, --output [ directory ]"
165 echoerr
" Specify output directory to save logs."
167 echoerr
" -c, --compress"
168 echoerr
" Compress output with gzip (before encryption if enabled)."
170 echoerr
" -z, --time-zone"
171 echoerr
" Specify time zone. (ex: \"America/New_York\")"
173 echoerr
" -t, --temp-dir"
174 echoerr
" Specify parent directory for temporary working directory."
175 echoerr
" Default: \"/dev/shm\""
177 echoerr
"EXAMPLE: (bash script lines)"
178 echoerr
"/bin/bash bkgpslog -e -c \\"
179 echoerr
"-r age1mrmfnwhtlprn4jquex0ukmwcm7y2nxlphuzgsgv8ew2k9mewy3rs8u7su5 \\"
180 echoerr
"-r age1ala848kqrvxc88rzaauc6vc5v0fqrvef9dxyk79m0vjea3hagclswu0lgq \\"
181 echoerr
"-o ~/Sync/Location"
182 } # Display information on how to use this script.
184 echoerr
"$SCRIPT_VERSION"
185 } # Display script version.
187 # Usage: vbm "DEBUG:verbose message here"
188 # Description: Prints verbose message ("vbm") to stderr if OPTION_VERBOSE is set to "true".
190 # - OPTION_VERBOSE variable set by processArguments function. (ex: "true", "false")
191 # - "$@" positional arguments fed to this function.
193 # Script function dependencies: echoerr
194 # External function dependencies: echo
195 # Last modified: 2020-04-11T23:57Z
196 # Last modified by: Steven Baltakatei Sandoval
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.
206 return 0; # Function finished.
207 } # Verbose message display function.
209 while [ ! $# -eq 0 ]; do # While number of arguments ($#) is not (!) equal to (-eq) zero (0).
210 #echoerr "DEBUG:Starting processArguments while loop."
211 #echoerr "DEBUG:Provided arguments are:""$*"
213 -h |
--help) showUsage
; exit 1;; # Display usage.
214 --version) showVersion
; exit 1;; # Show version
215 -v |
--verbose) OPTION_VERBOSE
="true"; vbm
"DEBUG:Verbose mode enabled.";; # Enable verbose mode.
216 -o |
--output) if [ -d "$2" ]; then DIR_OUT
="$2"; vbm
"DEBUG:DIR_OUT:$DIR_OUT"; shift; fi ;; # Define output directory.
217 -e |
--encrypt) OPTION_ENCRYPT
="true"; vbm
"DEBUG:Encrypted output mode enabled.";;
218 -r |
--recipient) # Add 'age' recipient via public key string
219 recPubKeys
+=("$2"); vbm
"STATUS:pubkey added:""$2"; shift;;
220 -c |
--compress) OPTION_COMPRESS
="true"; vbm
"DEBUG:Compressed output mode enabled.";;
221 -z |
--time-zone) try setTimeZoneEV
"$2"; shift;;
222 -t |
--temp-dir) OPTION_TMPDIR
="true" && TMP_DIR_PRIORITY
="$2"; shift;;
223 *) echoerr
"ERROR: Unrecognized argument: $1"; echoerr
"STATUS:All arguments:$*"; exit 1;; # Handle unrecognized options.
227 } # Argument Processing
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")
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
240 local tzDir returnState
241 if ! [[ $# -eq 1 ]]; then
242 yell
"ERROR:Invalid argument count.";
246 # Read TZDIR env var if available
247 if printenv TZDIR
1>/dev
/null
2>&1; then
248 tzDir
="$(printenv TZDIR)";
250 tzDir
="/usr/share/zoneinfo";
254 if ! [[ -f "$tzDir"/"$ARG1" ]]; then
255 yell
"ERROR:Invalid time zone argument.";
258 # Export ARG1 as TZ environment variable
259 TZ
="$ARG1" && export TZ
&& returnState
="true";
262 # Determine function return code
263 if [ "$returnState" = "true" ]; then
266 } # Exports TZ environment variable
268 # Desc: Report seconds until next day.
270 # Output: stdout: integer seconds until next day
271 # Output: exit code 0 if stdout > 0; 1 if stdout = 0; 2 if stdout < 0
272 # Usage: timeUntilNextDay
273 # Usage: if ! myTTL="$(timeUntilNextDay)"; then yell "ERROR in if statement"; exit 1; fi
274 # Depends: date 8, echo 8, yell, try
276 local returnState TIME_CURRENT TIME_NEXT_DAY SECONDS_UNTIL_NEXT_DAY
278 TIME_CURRENT
="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
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
283 elif [[ "$SECONDS_UNTIL_NEXT_DAY" -eq 0 ]]; then
284 returnState
="warning_zero";
285 yell
"WARNING:Reported time until next day exactly zero.";
286 elif [[ "$SECONDS_UNTIL_NEXT_DAY" -lt 0 ]]; then
287 returnState
="warning_negative";
288 yell
"WARNING:Reported time until next day is negative.";
291 try
echo "$SECONDS_UNTIL_NEXT_DAY"; # Report
293 # Determine function return code
294 if [[ "$returnState" = "true" ]]; then
296 elif [[ "$returnState" = "warning_zero" ]]; then
298 elif [[ "$returnState" = "warning_negative" ]]; then
301 } # Report seconds until next day
303 # Desc: Report seconds until next hour
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
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
316 elif [[ "$SECONDS_UNTIL_NEXT_HOUR" -eq 0 ]]; then
317 returnState
="warning_zero";
318 yell
"WARNING:Reported time until next hour exactly zero.";
319 elif [[ "$SECONDS_UNTIL_NEXT_HOUR" -lt 0 ]]; then
320 returnState
="warning_negative";
321 yell
"WARNING:Reported time until next hour is negative.";
324 try
echo "$SECONDS_UNTIL_NEXT_HOUR"; # Report
326 # Determine function return code
327 if [[ "$returnState" = "true" ]]; then
329 elif [[ "$returnState" = "warning_zero" ]]; then
331 elif [[ "$returnState" = "warning_negative" ]]; then
334 } # Report seconds until next hour
336 # Desc: Timestamp without separators (YYYYmmddTHHMMSS+zzzz)
337 # Usage: dateTimeShort ([str date])
339 # Input: arg1: 'date'-parsable timestamp string (optional)
340 # Output: stdout: timestamp (ISO-8601, no separators)
342 local TIME_CURRENT TIME_CURRENT_SHORT
346 TIME_CURRENT
="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
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";
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";
358 ### F: Time argument not valid; exit
359 yell
"ERROR:Invalid time argument supplied. Exiting."; exit 1;
362 # Construct and deliver separator-les date string
363 TIME_CURRENT_SHORT
="$(date -d "$TIME_INPUT" +%Y%m%dT%H%M%S%z)";
364 echo "$TIME_CURRENT_SHORT";
365 } # Get YYYYmmddTHHMMSS±zzzz
367 # Desc: Date without separators (YYYYmmdd)
368 # Usage: dateShort ([str date])
370 # Input: arg1: 'date'-parsable timestamp string (optional)
371 # Output: stdout: date (ISO-8601, no separators)
373 local TIME_CURRENT DATE_CURRENT_SHORT
377 TIME_CURRENT
="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
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";
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";
389 ### F: Time argument not valid; exit
390 yell
"ERROR:Invalid time argument supplied. Exiting."; exit 1;
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.
395 echo "$DATE_CURRENT_SHORT";
398 # Desc: Given seconds, output ISO-8601 duration string
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)
401 # Usage: timeDuration [1:seconds] ([2:precision])
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")
406 # exit code 0: success
407 # exit code 1: error_input
408 # exit code 2: error_unknown
409 # Example: 'timeDuration 111111 3' yields 'P1DT6H51M'
410 # Depends: date 8 (gnucoreutils), yell,
411 local returnState argSeconds argPrecision remainder precision witherPrecision
412 local fullYears fullMonths fullDays fullHours fullMinutes fullSeconds
413 local displayYears displayMonths displayDays displayHours displayMinutes displaySeconds
414 local hasYears hasMonths hasDays hasHours hasMinutes hasSeconds
416 argSeconds
="$1"; # read arg1 (seconds)
417 argPrecision
="$2"; # read arg2 (precision)
418 precision
=2; # set default precision
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.";
423 returnState
="error_input"; fi
425 # Check that argSeconds provided
426 if [[ $# -ge 1 ]]; then
427 ## Check that argSeconds is a positive integer
428 if [[ "$argSeconds" =~ ^
[[:digit
:]]+$
]]; then
431 yell
"ERROR:argSeconds not a digit.";
432 returnState
="error_input";
435 yell
"ERROR:No argument provided. Exiting.";
439 # Consider whether argPrecision was provided
440 if [[ $# -eq 2 ]]; then
441 # Check that argPrecision is a positive integer
442 if [[ "$argPrecision" =~ ^
[[:digit
:]]+$
]] && [[ "$argPrecision" -gt 0 ]]; then
443 precision
="$argPrecision";
445 yell
"ERROR:argPrecision not a positive integer. (is $argPrecision ). Leaving early.";
446 returnState
="error_input";
452 remainder
="$argSeconds" ; # seconds
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
479 ## Determine which fields to display (see ISO-8601:2004 §4.4.3.2)
480 witherPrecision
="false"
483 if $hasYears && [[ $precision -gt 0 ]]; then
485 witherPrecision
="true";
487 displayYears
="false";
489 if $witherPrecision; then ((precision--
)); fi;
492 if $hasMonths && [[ $precision -gt 0 ]]; then
493 displayMonths
="true";
494 witherPrecision
="true";
496 displayMonths
="false";
498 if $witherPrecision && [[ $precision -gt 0 ]]; then
499 displayMonths
="true";
501 if $witherPrecision; then ((precision--
)); fi;
504 if $hasDays && [[ $precision -gt 0 ]]; then
506 witherPrecision
="true";
510 if $witherPrecision && [[ $precision -gt 0 ]]; then
513 if $witherPrecision; then ((precision--
)); fi;
516 if $hasHours && [[ $precision -gt 0 ]]; then
518 witherPrecision
="true";
520 displayHours
="false";
522 if $witherPrecision && [[ $precision -gt 0 ]]; then
525 if $witherPrecision; then ((precision--
)); fi;
528 if $hasMinutes && [[ $precision -gt 0 ]]; then
529 displayMinutes
="true";
530 witherPrecision
="true";
532 displayMinutes
="false";
534 if $witherPrecision && [[ $precision -gt 0 ]]; then
535 displayMinutes
="true";
537 if $witherPrecision; then ((precision--
)); fi;
541 if $hasSeconds && [[ $precision -gt 0 ]]; then
542 displaySeconds
="true";
543 witherPrecision
="true";
545 displaySeconds
="false";
547 if $witherPrecision && [[ $precision -gt 0 ]]; then
548 displaySeconds
="true";
550 if $witherPrecision; then ((precision--
)); fi;
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
556 ## Construct duration output string
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
573 ## Output duration string to stdout
574 echo "$OUTPUT" && returnState
="true";
576 #===Determine function return code===
577 if [ "$returnState" = "true" ]; then
579 elif [ "$returnState" = "error_input" ]; then
583 yell
"ERROR:Unknown";
587 } # Get duration (ex: PT10M4S )
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 "
605 if [ "$appMissing" = "true" ]; then # Only indicate if an app is missing.
606 echo "$missingApps" 1>&2;
608 #===END Display Missing Apps===
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 "
621 if [ "$fileMissing" = "true" ]; then # Only indicate if an app is missing.
622 echo "$missingFiles" 1>&2;
624 #===END Display Missing Files===
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 "
637 if [ "$dirMissing" = "true" ]; then # Only indicate if an dir is missing.
638 echo "$missingDirs" 1>&2;
640 #===END Display Missing Directories===
642 #==END Display errors==
643 } # Display missing apps, files, dirs
645 #Desc: Sets script TTL
646 #Usage: setScriptTTL arg1
647 #Input: arg1: "day" or "hour"
649 #Depends: timeUntilNextHour or timeUntilNextDay
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.
658 yell
"ERROR: timeUntilNextDay exit code $?"; exit 1;
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.
667 yell
"ERROR: timeUntilNextHour exit code $?"; exit 1;
671 yell
"ERROR:Invalid argument for setScriptTTL function."; exit 1;
673 } # Seconds until next (day|hour).
675 # Desc: Checks that a valid tar archive exists, creates one otherwise
676 # Usage: checkMakeTar [ path ]
678 # Input: arg1: path of tar archive
679 # Output: exit code 0 : tar readable
680 # exit code 1 : tar missing; created
681 # exit code 2 : tar not readable; moved; replaced
682 # Depends: try, tar, date
683 local PATH_TAR returnFlag0 returnFlag1 returnFlag2
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
689 returnFlag0
="tar valid";
691 ## F1: Check if file exists
692 if [[ -f "$PATH_TAR" ]]; then
694 try
mv "$PATH_TAR" "$PATH_TAR""--broken--""$(date +%Y%m%dT%H%M%S)" && \
695 returnFlag1
="tar moved";
700 ## F2: Create tar archive, return 0
701 try
tar --create --file="$PATH_TAR" --files-from=/dev
/null
&& \
702 returnFlag2
="tar created";
705 # Determine function return code
706 if [[ "$returnFlag0" = "tar valid" ]]; then
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
713 } # checks if arg1 is tar; creates one otherwise
715 # Desc: Writes first argument to temporary file with arguments as options, then appends file to tar
716 # Usage: appendArgTar "$(echo "Data to be written.")" [name of file to be inserted] [tar path] [temp dir] ([cmd1] [cmd2] [cmd3] [cmd4]...)
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" &
729 # Ref/Attrib: Using 'eval' to construct command strings https://askubuntu.com/a/476533
732 local FN
="${FUNCNAME[0]}";
733 #yell "DEBUG:STATUS:$FN:Finished appendArgTar()."
736 if ! [ -z "$2" ]; then FILENAME
="$2"; else yell
"ERROR:$FN:Not enough arguments."; exit 1; fi
738 # Check tar path is a file
739 if [ -f "$3" ]; then TAR_PATH
="$3"; else yell
"ERROR:$FN:Tar archive arg not a file."; exit 1; fi
742 if ! [ -z "$4" ]; then TMP_DIR
="$4"; else yell
"ERROR:$FN:No temporary working dir set."; exit 1; fi
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
754 # yell "DEBUG:STATUS:$FN:CMD0:$CMD0"
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"
763 # Write to temporary working dir
764 eval "$CMD0"" | ""$CMD1"" | ""$CMD2"" | ""$CMD3"" | ""$CMD4" > "$TMP_DIR"/"$FILENAME";
767 try
tar --append --directory="$TMP_DIR" --file="$TAR_PATH" "$FILENAME";
768 #yell "DEBUG:STATUS:$FN:Finished appendArgTar()."
769 } # Append Bash var to file appended to Tar archive
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]...)
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" &
787 local FN
="${FUNCNAME[0]}";
788 #yell "DEBUG:STATUS:$FN:Finished appendFileTar()."
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
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
802 # Input command string
806 # yell "DEBUG:STATUS:$FN:CMD0:$CMD0"
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"
815 # Write to temporary working dir
816 eval "$CMD0 | $CMD1 | $CMD2 | $CMD3 | $CMD4" > "$TMP_DIR"/"$FILENAME";
819 try
tar --append --directory="$TMP_DIR" --file="$TAR_PATH" "$FILENAME";
820 #yell "DEBUG:STATUS:$FN:Finished appendFileTar()."
821 } # Append file to Tar archive
823 # Desc: Validates Input
824 # Usage: validateInput [str input] [str input type]
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
832 local FN
="${FUNCNAME[0]}";
837 if [[ $# -gt 2 ]]; then yell
"ERROR:$0:$FN:Too many arguments."; exit 1; fi;
840 if [[ -z "$argInput" ]]; then return 1; fi
844 ### Check for alnum/dash base64 (ex: "ssh-rsa AAAAB3NzaC1yc2EAAA")
845 if [[ "$argType" = "ssh_pubkey" ]]; then
846 if [[ "$argInput" =~ ^
[[:alnum
:]-]*[\
]*[[:alnum
:]+/=]*$
]]; then
850 ### Check for age1[:bech32:]
851 if [[ "$argType" = "age_pubkey" ]]; then
852 if [[ "$argInput" =~ ^age1
[qpzry9x8gf2tvdw0s3jn54khce6mua7l
]*$
]]; then
855 # Return error if no condition matched.
857 } # Validates strings
858 magicWriteVersion
() {
859 # Desc: Appends time-stamped VERSION to PATHOUT_TAR
860 # Usage: magicWriteVersion
862 # Input: CONTENT_VERSION, FILEOUT_VERSION, PATHOUT_TAR, DIR_TMP
863 # Input: SCRIPT_VERSION, SCRIPT_URL, AGE_VERSION, AGE_URL, SCRIPT_HOSTNAME
864 # Output: appends tar PATHOUT_TAR
865 # Depends: dateTimeShort, appendArgTar
866 local CONTENT_VERSION pubKeyIndex
868 # Set VERSION file name
869 FILEOUT_VERSION
="$(dateTimeShort)..VERSION";
871 # Gather VERSION data in CONTENT_VERSION
872 CONTENT_VERSION
="SCRIPT_VERSION=$SCRIPT_VERSION";
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";
880 ## Add list of recipient pubkeys
881 for pubkey
in "${recPubKeysValid[@]}"; do
883 CONTENT_VERSION
="$CONTENT_VERSION""\\n""PUBKEY_$pubKeyIndex=$pubkey";
885 ## Process newline escapes
886 CONTENT_VERSION
="$(echo -e "$CONTENT_VERSION")"
888 # Write CONTENT_VERSION as file FILEOUT_VERSION and write-append to PATHOUT_TAR
889 appendArgTar
"$CONTENT_VERSION" "$FILEOUT_VERSION" "$PATHOUT_TAR" "$DIR_TMP";
891 } # bkgpslog: write version data to PATHOUT_TAR via appendArgTar()
892 magicGatherWriteBuffer
() {
893 # Desc: bkgpslog-specific meta function for writing data to DIR_TMP then appending each file to PATHOUT_TAR
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
896 # Depends: yell, try, vbm, appendArgTar, tar
897 local FN
="${FUNCNAME[0]}";
898 wait; # Wait to avoid collision with older magicWriteBuffer() instances (see https://www.tldp.org/LDP/abs/html/x9644.html )
899 # Create buffer file with unique name
900 PATHOUT_BUFFER
="$DIR_TMP/buffer$SECONDS";
902 timeout
"$BUFFER_TTL"s gpspipe
-r -o "$PATHOUT_BUFFER" ;
903 timeBufferStart
="$(dateTimeShort "$
(date --date="$BUFFER_TTL seconds ago")")"; # Note start time
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";
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";
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
931 # Write bufferBash to PATHOUT_TAR
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
936 # Remove secured chunks from DIR_TMP
937 rm "$PATHOUT_BUFFER" "$PATHOUT_NMEA" "$PATHOUT_GPX" "$PATHOUT_KML";
938 vbm
"DEBUG:STATUS:$FN:Finished magicWriteBuffer().";
939 } # write buffer to disk
942 processArguments
"$@" # Process arguments.
944 # Determine working directory
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";
950 yell
"WARNING:Specified temporary working directory not valid:$OPTION_TMPDIR";
955 ## Set DIR_TMP_PARENT to default or fallback otherwise
956 if [[ -d "$DIR_TMP_DEFAULT" ]]; then
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";
962 yell
"ERROR:No valid working directory available. Exiting.";
966 ## Set DIR_TMP using DIR_TMP_PARENT and nonce (SCRIPT_TIME_START)
967 DIR_TMP
="$DIR_TMP_PARENT"/"$SCRIPT_TIME_START""..bkgpslog" && vbm
"DEBUG:Set DIR_TMP to:$DIR_TMP"; # Note: removed at end of main().
969 # Set output encryption and compression option strings
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
973 vbm
"DEBUG:Testing pubkey string:$pubkey";
974 if echo "butts" | age
-a -r "$pubkey" 1>/dev
/null
&&
975 ( validateInput
"$pubkey" "ssh_pubkey" || validateInput
"$pubkey" "age_pubkey"); then
976 #### Form age recipient string
977 recipients
="$recipients""-r '$pubkey' ";
978 vbm
"STATUS:Added pubkey for forming age recipient string:""$pubkey";
979 vbm
"DEBUG:recipients:""$recipients";
980 #### Add validated pubkey to recPubKeysValid array
981 recPubKeysValid
+=("$pubkey") && vbm
"DEBUG:recPubkeysValid:pubkey added:$pubkey";
983 yell
"ERROR:Exit code ""$?"". Invalid recipient pubkey string. Exiting."; exit 1;
986 vbm
"DEBUG:Finished processing recPubKeys array";
988 ## Form age command string
989 CMD_ENCRYPT
="age ""$recipients " && vbm
"CMD_ENCRYPT:$CMD_ENCRYPT";
990 CMD_ENCRYPT_SUFFIX
=".age" && vbm
"CMD_ENCRYPT_SUFFIX:$CMD_ENCRYPT_SUFFIX";
992 yell
"ERROR:Encryption enabled but \"age\" not found. Exiting."; exit 1;
995 CMD_ENCRYPT
="tee /dev/null " && vbm
"CMD_ENCRYPT:$CMD_ENCRYPT";
996 CMD_ENCRYPT_SUFFIX
="" && vbm
"CMD_ENCRYPT_SUFFIX:$CMD_ENCRYPT_SUFFIX";
997 vbm
"DEBUG:Encryption not enabled."
999 if [[ "$OPTION_COMPRESS" = "true" ]]; then # Check if compression option active
1000 if checkapp
gzip; then # Check if gzip available
1001 CMD_COMPRESS
="gzip " && vbm
"CMD_COMPRESS:$CMD_COMPRESS";
1002 CMD_COMPRESS_SUFFIX
=".gz" && vbm
"CMD_COMPRESS_SUFFIX:$CMD_COMPRESS_SUFFIX";
1004 yell
"ERROR:Compression enabled but \"gzip\" not found. Exiting."; exit 1;
1007 CMD_COMPRESS
="tee /dev/null " && vbm
"CMD_COMPRESS:$CMD_COMPRESS";
1008 CMD_COMPRESS_SUFFIX
="" && vbm
"CMD_COMPRESS_SUFFIX:$CMD_COMPRESS_SUFFIX";
1009 vbm
"DEBUG:Compression not enabled.";
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
1017 # Set script lifespan
1018 setScriptTTL
"$SCRIPT_TTL"; # seconds until next new SCRIPT_TTL (ex: "day" or "hour")
1020 # File name substring: encoded bufferTTL
1021 bufferTTL_STR
="$(timeDuration $BUFFER_TTL)";
1023 # Init temp working dir
1024 try mkdir
"$DIR_TMP" && vbm
"DEBUG:Working dir creatd at:$DIR_TMP";
1026 # Initialize 'tar' archive
1027 ## Define output tar path (note: each day gets *one* tar file (Ex: "20200731..hostname_location.[.gpx.gz].tar"))
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";
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";
1032 ## Append VERSION file to PATHOUT_TAR
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
1040 # MAIN LOOP:Record gps data until script lifespan ends
1041 while [[ "$SECONDS" -lt "$scriptTTL" ]]; do
1042 magicGatherWriteBuffer
&
1043 sleep "$BUFFER_TTL";
1048 try
rm -r "$DIR_TMP";
1050 vbm
"STATUS:Main function finished.";
1052 #===END Declare local script functions===
1053 #==END Define script parameters==
1056 #==BEGIN Perform work and exit==
1057 main
"$@" # Run main function.
1059 #==END Perform work and exit==