SCRIPT_TIME_START=$(date +%Y%m%dT%H%M%S.%N);
PATH="$HOME/.local/bin:$PATH"; # Add "$(systemd-path user-binaries)" path in case apps saved there
SCRIPT_HOSTNAME=$(hostname); # Save hostname of system running this script.
-SCRIPT_VERSION="bkgpslog 0.1.0"; # Define version of script.
+SCRIPT_VERSION="bkgpslog 0.2.1"; # Define version of script.
+SCRIPT_NAME="$(basename "$0")"; # Define basename of script file.
declare -Ag appRollCall # Associative array for storing app status
declare -Ag fileRollCall # Associative array for storing file status
} # Exports TZ environment variable
timeUntilNextDay(){
# Desc: Report seconds until next day.
+ # Version: 1.0.0
# Output: stdout: integer seconds until next day
# Output: exit code 0 if stdout > 0; 1 if stdout = 0; 2 if stdout < 0
# Usage: timeUntilNextDay
# Usage: if ! myTTL="$(timeUntilNextDay)"; then yell "ERROR in if statement"; exit 1; fi
+ # Depends: date 8, echo 8, yell, try
+
local returnState TIME_CURRENT TIME_NEXT_DAY SECONDS_UNTIL_NEXT_DAY
+
TIME_CURRENT="$(date --iso-8601=seconds)" ; # Produce `date`-parsable current timestamp with resolution of 1 second.
TIME_NEXT_DAY="$(date -d "$TIME_CURRENT next day" --iso-8601=date)"; # Produce timestamp of beginning of tomorrow with resolution of 1 second.
SECONDS_UNTIL_NEXT_DAY="$(( $(date +%s -d "$TIME_NEXT_DAY") - $(date +%s -d "$TIME_CURRENT") ))" ; # Calculate seconds until closest future midnight (res. 1 second).
if [[ "$SECONDS_UNTIL_NEXT_DAY" -gt 0 ]]; then
returnState="true";
elif [[ "$SECONDS_UNTIL_NEXT_DAY" -eq 0 ]]; then
- returnState="WARNING_ZERO";
+ returnState="warning_zero";
yell "WARNING:Reported time until next day exactly zero.";
elif [[ "$SECONDS_UNTIL_NEXT_DAY" -lt 0 ]]; then
- returnState="WARNING_NEGATIVE";
+ returnState="warning_negative";
yell "WARNING:Reported time until next day is negative.";
fi
try echo "$SECONDS_UNTIL_NEXT_DAY"; # Report
- #===Determine function return code===
+ # Determine function return code
if [[ "$returnState" = "true" ]]; then
return 0;
- elif [[ "$returnState" = "WARNING_ZERO" ]]; then
+ elif [[ "$returnState" = "warning_zero" ]]; then
return 1;
- elif [[ "$returnState" = "WARNING_NEGATIVE" ]]; then
+ elif [[ "$returnState" = "warning_negative" ]]; then
return 2;
fi
} # Report seconds until next day
timeUntilNextHour(){
# Desc: Report seconds until next hour
+ # Version 1.0.0
# Output: stdout: integer seconds until next hour
# Output: exit code 0 if stdout > 0; 1 if stdout = 0; 2 if stdout < 0
# Usage: timeUntilNextHour
# Usage: if ! myTTL="$(timeUntilNextHour)"; then yell "ERROR in if statement"; exit 1; fi
+
local returnState TIME_CURRENT TIME_NEXT_HOUR SECONDS_UNTIL_NEXT_HOUR
TIME_CURRENT="$(date --iso-8601=seconds)"; # Produce `date`-parsable current timestamp with resolution of 1 second.
TIME_NEXT_HOUR="$(date -d "$TIME_CURRENT next hour" --iso-8601=hours)"; # Produce `date`-parsable current time stamp with resolution of 1 second.
if [[ "$SECONDS_UNTIL_NEXT_HOUR" -gt 0 ]]; then
returnState="true";
elif [[ "$SECONDS_UNTIL_NEXT_HOUR" -eq 0 ]]; then
- returnState="WARNING_ZERO";
+ returnState="warning_zero";
yell "WARNING:Reported time until next hour exactly zero.";
elif [[ "$SECONDS_UNTIL_NEXT_HOUR" -lt 0 ]]; then
- returnState="WARNING_NEGATIVE";
+ returnState="warning_negative";
yell "WARNING:Reported time until next hour is negative.";
fi
try echo "$SECONDS_UNTIL_NEXT_HOUR"; # Report
- #===Determine function return code===
+ # Determine function return code
if [[ "$returnState" = "true" ]]; then
return 0;
- elif [[ "$returnState" = "WARNING_ZERO" ]]; then
+ elif [[ "$returnState" = "warning_zero" ]]; then
return 1;
- elif [[ "$returnState" = "WARNING_NEGATIVE" ]]; then
+ elif [[ "$returnState" = "warning_negative" ]]; then
return 2;
fi
} # Report seconds until next hour
# Ref/Attrib: ISO-8601:2004(E), §4.4.4.2 Representations of time intervals by duration and context information
# Note: "1 month" ("P1M") is assumed to be "30 days" (see ISO-8601:2004(E), §2.2.1.2)
# Usage: timeDuration [arg1] ([arg2])
+ # Version: 1.0.1
# Input: arg1: seconds as base 10 integer >= 0 (ex: 3601)
# arg2: precision level (optional; default=2)
# Output: stdout: ISO-8601 duration string (ex: "P1H1S", "P2Y10M15DT10H30M20S")
# Example: 'timeDuration 111111 3' yields 'P1DT6H51M'
- # Depends: date 8 (gnucoreutils)
- local returnState fullHours fullMinutes fullSeconds;
+ # Depends: date 8 (gnucoreutils), yell,
+ local returnState ARG1 ARG2 remainder precision witherPrecision
+ local fullYears fullMonths fullDays fullHours fullMinutes fullSeconds
+ local displayYears displayMonths displayDays displayHours displayMinutes displaySeconds
+ local hasYears hasMonths hasDays hasHours hasMinutes hasSeconds
+
ARG1="$1";
ARG2="$2";
precision=2; # set default precision
# Check that arg1 provided
if [[ $# -ge 1 ]]; then
- # Check that arg1 is a positive integer
+ ## Check that arg1 is a positive integer
if [[ "$ARG1" =~ ^[[:digit:]]+$ ]]; then
- arg1Valid="true";
+ :
else
yell "ERROR:ARG1 not a digit.";
returnState="ERROR_INPUT";
- arg1Valid="false";
fi
else
yell "ERROR:No argument provided. Exiting.";
# Consider whether arg2 was provided
if [[ $# -eq 2 ]]; then
# Check that the second arg is a positive integer
- if [[ "$ARG2" =~ ^[[:digit:]]+$ ]] && [[ "ARG2" -gt 0 ]]; then
- arg2Valid="true";
+ if [[ "$ARG2" =~ ^[[:digit:]]+$ ]] && [[ "$ARG2" -gt 0 ]]; then
precision="$ARG2";
else
yell "ERROR:ARG2 not a positive integer. (is $ARG2 ). Leaving early.";
returnState="ERROR_INPUT";
- arg2Valid="false";
fi;
else
- arg2Valid="false";
+ :
fi;
remainder="$ARG1" ; # seconds
yell "ERROR:Invalid argument for setScriptTTL function."; exit 1;
fi
} # Seconds until next (day|hour).
+checkMakeTar() {
+ # Desc: Checks that a valid tar archive exists, creates one otherwise
+ # Usage: checkMakeTar [ path ]
+ # Version: 1.0.1
+ # Input: arg1: path of tar archive
+ # Output: exit code 0 : tar readable
+ # exit code 1 : tar missing; created
+ # exit code 2 : tar not readable; moved; replaced
+ # Depends: try, tar, date
+ local PATH_TAR returnFlag0 returnFlag1 returnFlag2
+ PATH_TAR="$1"
+
+ # Check if file is a valid tar archive
+ if tar --list --file="$PATH_TAR" 1>/dev/null 2>&1; then
+ ## T1: return success
+ returnFlag0="tar valid";
+ else
+ ## F1: Check if file exists
+ if [[ -f "$PATH_TAR" ]]; then
+ ### T: Rename file
+ try mv "$PATH_TAR" "$PATH_TAR""--broken--""$(date +%Y%m%dT%H%M%S)" && \
+ returnFlag1="tar moved";
+ else
+ ### F: -
+ :
+ fi
+ ## F2: Create tar archive, return 0
+ try tar --create --file="$PATH_TAR" --files-from=/dev/null && \
+ returnFlag2="tar created";
+ fi
+
+ # Determine function return code
+ if [[ "$returnFlag0" = "tar valid" ]]; then
+ return 0;
+ elif [[ "$returnFlag2" = "tar created" ]] && ! [[ "$returnFlag1" = "tar moved" ]]; then
+ return 1; # tar missing so created
+ elif [[ "$returnFlag2" = "tar created" ]] && [[ "$returnFlag1" = "tar moved" ]]; then
+ return 2; # tar not readable so moved; replaced
+ fi
+} # checks if arg1 is tar; creates one otherwise
appendArgTar(){
# Desc: Writes first argument to temporary file with arguments as options, then appends file to tar
# Usage: writeArg "$(echo "Data to be written.")" [name of file to be inserted] [tar path] [temp dir] ([cmd1] [cmd2] [cmd3] [cmd4]...)
try tar --append --directory="$TMP_DIR" --file="$TAR_PATH" "$FILENAME";
yell "DEBUG:STATUS:$FN:Finished appendArgTar()."
} # Append Bash var to file appended to Tar archive
+magicWriteVersion() {
+ # Desc: Appends time-stamped VERSION to PATHOUT_TAR
+ # Usage: magicWriteVersion
+ # Input: CONTENT_VERSION, FILEOUT_VERSION, PATHOUT_TAR, DIR_TMP
+ # Depends: dateTimeShort, appendArgTar
+ local CONTENT_VERSION
+
+ # Generate VERSION file in BashVar
+ FILEOUT_VERSION="$(dateTimeShort)..VERSION";
+ CONTENT_VERSION="VERSION=$SCRIPT_VERSION";
+ CONTENT_VERSION="$CONTENT_VERSION""\n""SCRIPT_NAME=SCRIPT_NAME";
+ CONTENT_VERSION="$CONTENT_VERSION""\n""DATE=$(date --iso-8601=seconds)";
+ CONTENT_VERSION="$CONTENT_VERSION""\n""HOSTNAME=$SCRIPT_HOSTNAME";
+ CONTENT_VERSION="$(echo -e "$CONTENT_VERSION")"
+
+ # Create BashVar as file FILEOUT_VERSION and write-append to PATHOUT_TAR
+ appendArgTar "$CONTENT_VERSION" "$FILEOUT_VERSION" "$PATHOUT_TAR" "$DIR_TMP";
+} # bkgpslog: write version data to PATHOUT_TAR via appendArgTar()
magicWriteBuffer() {
# Desc: bkgpslog-specific meta function for writing data to DIR_TMP then appending each file to PATHOUT_TAR
- local FN="${FUNCNAME[0]}"
- yell "DEBUG:STATUS:$FN:Started magicWriteBuffer()."
+ # Inputs: PATHOUT_TAR FILEOUT_{NMEA,GPX,KML} CMD_CONV_{NMEA,GPX,KML} CMD_{COMPRESS,ENCRYPT} DIR_TMP
+ # Depends: yell, try, vbm, appendArgTar, tar
+ local FN="${FUNCNAME[0]}";
+ wait; # Wait to avoid collision with older magicWriteBuffer() instances (see https://www.tldp.org/LDP/abs/html/x9644.html )
+ vbm "DEBUG:STATUS:$FN:Started magicWriteBuffer().";
+
+ # Validate PATHOUT_TAR as tar.
+ checkMakeTar "$PATHOUT_TAR";
+ ## Add VERSION file if checkMakeTar had to create a tar (exited 1) or replace one (exited 2)
+ if [[ $? -eq 1 ]] || [[ $? -eq 2 ]]; then magicWriteVersion; fi
+
+ # Write bufferBash to PATHOUT_TAR
appendArgTar "$bufferBash" "$FILEOUT_NMEA" "$PATHOUT_TAR" "$DIR_TMP" "$CMD_CONV_NMEA" "$CMD_COMPRESS" "$CMD_ENCRYPT"; # Write NMEA data
- appendArgTar "$bufferBash" "$FILEOUT_GPX" "$PATHOUT_TAR" "$DIR_TMP" "$CMD_CONV_NMEA" "$CMD_COMPRESS" "$CMD_ENCRYPT"; # Write GPX file
- appendArgTar "$bufferBash" "$FILEOUT_KML" "$PATHOUT_TAR" "$DIR_TMP" "$CMD_CONV_NMEA" "$CMD_COMPRESS" "$CMD_ENCRYPT"; # Write KML file
- yell "DEBUG:STATUS:$FN:Finished magicWriteBuffer()."
+ appendArgTar "$bufferBash" "$FILEOUT_GPX" "$PATHOUT_TAR" "$DIR_TMP" "$CMD_CONV_GPX" "$CMD_COMPRESS" "$CMD_ENCRYPT"; # Write GPX file
+ appendArgTar "$bufferBash" "$FILEOUT_KML" "$PATHOUT_TAR" "$DIR_TMP" "$CMD_CONV_KML" "$CMD_COMPRESS" "$CMD_ENCRYPT"; # Write KML file
+ # Remove secured chunks from DIR_TMP
+ try rm "$PATHOUT_NMEA" "$PATHOUT_GPX" "$PATHOUT_KML";
+ yell "DEBUG:STATUS:$FN:Finished magicWriteBuffer().";
} # bkgpslog write function
-
main() {
processArguments "$@" # Process arguments.
else
CMD_COMPRESS="tee /dev/null ";
CMD_COMPRESS_SUFFIX="";
- vbm "DEBUG:Compression not enabled."
+ vbm "DEBUG:Compression not enabled.";
fi
# Check that critical apps and dirs are available, displag missing ones.
displayMissing; yell "Exiting."; exit 1; fi
# Set script lifespan
- setScriptTTL "$SCRIPT_TTL";
+ setScriptTTL "$SCRIPT_TTL"; # seconds until next new SCRIPT_TTL (ex: "day" or "hour")
# File name substring: encoded bufferTTL
bufferTTL_STR="$(timeDuration $BUFFER_TTL)";
## Define output tar path (note: each day gets *one* tar file (Ex: "20200731..hostname_location.[.gpx.gz].tar"))
PATHOUT_TAR="$DIR_OUT"/"$(dateShort)".."$SCRIPT_HOSTNAME""_location""$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX".tar && \
vbm "STATUS:Set PATHOUT_TAR to:$PATHOUT_TAR";
- ## Write bkgpslog version to DIR_TMP/VERSION
- FILEOUT_VERSION="$(dateTimeShort)..VERSION";
- PATHOUT_VERSION="$DIR_TMP"/"$FILEOUT_VERSION";
- echo "$(dateTimeShort):$(basename "$0")"" Version:""$SCRIPT_VERSION" >> "$PATHOUT_VERSION" && vbm "DEBUG:VERSION created:$PATHOUT_VERSION";
- ## Check if PATHOUT_TAR already exists.
- if [[ -f "$PATHOUT_TAR" ]]; then
- vbm "STATUS:Output tar already exists:$PATHOUT_TAR";
- ### Check if preexisting tar is appendable.
- FILEOUT_APPENDTEST="$(dateTimeShort)..RESUMING_LOGGING_SESSION.txt";
- PATHOUT_APPENDTEST="$DIR_TMP"/"$FILEOUT_APPENDTEST" && \
- vbm "DEBUG:Set PATHOUT_APPENDTEST to:$PATHOUT_APPENDTEST";
- echo "$(dateTimeShort):""$(basename "$0")"" version $SCRIPT_VERSION resuming logging session." >> "$PATHOUT_APPENDTEST" && \
- vbm "DEBUG:""$PATHOUT_APPENDTEST"" created."
- if ! tar --append --directory="$DIR_TMP" --file="$PATHOUT_TAR" "$FILEOUT_APPENDTEST"; then
- ### If not appendable, label tar broken, move tar, proceed.
- mv "$PATHOUT_TAR" "${PATHOUT_TAR%.*}""-broken$(dateTimeShort)".tar && \
- vbm "DEBUG:tar not writable, moving out of the way $PATHOUT_TAR";
- fi
- else
- vbm "STATUS:Output tar does not already exist. Creating:$PATHOUT_TAR"
- ### If (no preexisting|appendable) tar found, create empty tar archive at PATHOUT_TAR
- try tar --create --directory="$DIR_TMP" --file="$PATHOUT_TAR" --files-from=/dev/null && \
- vbm "DEBUG:Empty tar created at:$PATHOUT_TAR";
- fi
+ ## Check that PATHOUT_TAR is a tar. Rename old and create empty one otherwise.
+ checkMakeTar "$PATHOUT_TAR" && vbm "DEBUG:Confirmed or Created to be a tar:$PATHOUT_TAR";
## Append VERSION file to PATHOUT_TAR
- try tar --append --directory="$DIR_TMP" --file="$PATHOUT_TAR" "$FILEOUT_VERSION" && \
- vbm "DEBUG:VERSION added to $PATHOUT_TAR";
+ magicWriteVersion;
# Record gps data until script lifespan ends
declare debugCounter; debugCounter="0"; # set debug counter
# Determine file paths (time is start of buffer period)
FILEOUT_BASENAME="$timeBufferStart""--""$bufferTTL_STR""..""$SCRIPT_HOSTNAME""_location" && vbm "STATUS:Set FILEOUT_BASENAME to:$FILEOUT_BASENAME";
## Files saved to DIR_TMP
- FILEOUT_NMEA="$FILEOUT_BASENAME".nmea"$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX" && vbm "STATUS:Set FILEOUT_NMEA to:$FILEOUT_NMEA"
- FILEOUT_GPX="$FILEOUT_BASENAME".gpx"$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX" && vbm "STATUS:Set FILEOUT_GPX to:$FILEOUT_GPX"
- FILEOUT_KML="$FILEOUT_BASENAME".kml"$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX" && vbm "STATUS:Set FILEOUT_KML to:$FILEOUT_KML"
+ FILEOUT_NMEA="$FILEOUT_BASENAME".nmea"$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX" && vbm "STATUS:Set FILEOUT_NMEA to:$FILEOUT_NMEA";
+ FILEOUT_GPX="$FILEOUT_BASENAME".gpx"$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX" && vbm "STATUS:Set FILEOUT_GPX to:$FILEOUT_GPX";
+ FILEOUT_KML="$FILEOUT_BASENAME".kml"$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX" && vbm "STATUS:Set FILEOUT_KML to:$FILEOUT_KML";
PATHOUT_NMEA="$DIR_TMP"/"$FILEOUT_NMEA" && vbm "STATUS:Set PATHOUT_NMEA to:$PATHOUT_NMEA";
PATHOUT_GPX="$DIR_TMP"/"$FILEOUT_GPX" && vbm "STATUS:Set PATHOUT_GPX to:$PATHOUT_GPX";
PATHOUT_KML="$DIR_TMP"/"$FILEOUT_KML" && vbm "STATUS:Set PATHOUT_KML to:$PATHOUT_KML";
## Files saved to disk (DIR_OUT)
### one file per day (Ex: "20200731..hostname_location.[.gpx.gz].tar")
PATHOUT_TAR="$DIR_OUT"/"$(dateShort)".."$SCRIPT_HOSTNAME""_location""$CMD_COMPRESS_SUFFIX""$CMD_ENCRYPT_SUFFIX".tar && \
- vbm "STATUS:Set PATHOUT_TAR to:$PATHOUT_TAR"
+ vbm "STATUS:Set PATHOUT_TAR to:$PATHOUT_TAR";
# Define GPS conversion commands
CMD_CONV_NMEA="tee /dev/null " && vbm "STATUS:Set CMD_CONV_NMEA to:$CMD_CONV_NMEA"; # tee as passthrough
CMD_CONV_GPX="gpsbabel -i nmea -f - -o gpx -F - " && vbm "STATUS:Set CMD_CONV_GPX to:$CMD_CONV_GPX"; # convert NMEA to GPX
# Process bufferBash, save secured chunk set to DIR_TMP
vbm "STATUS:Beginning to save data to $DIR_TMP";
magicWriteBuffer &
- #echo "$bufferBash" | $CMD_CONV_NMEA | $CMD_COMPRESS | $CMD_ENCRYPT > "$PATHOUT_NMEA" & # Create NMEA file (secured if requested)
- #echo "$bufferBash" | $CMD_CONV_GPX | $CMD_COMPRESS | $CMD_ENCRYPT > "$PATHOUT_GPX" & # Create GPX file (secured if requested)
- #echo "$bufferBash" | $CMD_CONV_KML | $CMD_COMPRESS | $CMD_ENCRYPT > "$PATHOUT_KML" & # Create KML file (secured if requested)
# Append each secured chunk in memory dir (DIR_TMP) to file on disk (PATHOUT_TAR in DIR_OUT)
vbm "STATUS:DIR_TMP :$DIR_TMP";
vbm "STATUS:PATHOUT_TAR :$PATHOUT_TAR";
vbm "STATUS:PATHOUT_NMEA:$PATHOUT_NMEA";
vbm "STATUS:PATHOUT_GPX:$PATHOUT_GPX";
vbm "STATUS:PATHOUT_KML:$PATHOUT_KML";
- try tar --append --directory="$DIR_TMP" --file="$PATHOUT_TAR" "$(basename "$PATHOUT_NMEA")" && \
- vbm "DEBUG:Appended NMEA location data $PATHOUT_NMEA to $PATHOUT_TAR";
- try tar --append --directory="$DIR_TMP" --file="$PATHOUT_TAR" "$(basename "$PATHOUT_GPX")" && \
- vbm "DEBUG:Appended GPX location data $PATHOUT_GPX to $PATHOUT_TAR";
- try tar --append --directory="$DIR_TMP" --file="$PATHOUT_TAR" "$(basename "$PATHOUT_KML")" && \
- vbm "DEBUG:Appended KML location $PATHOUT_KML to $PATHOUT_TAR";
- # Remove secured chunks from DIR_TMP
- try rm "$PATHOUT_NMEA" "$PATHOUT_GPX" "$PATHOUT_KML";
+
# Reset buffer and filenames
unset bufferBash FILEOUT_BASENAME PATHOUT_NMEA PATHOUT_GPX PATHOUT_KML PATHOUT_TAR timeBufferStart;
vbm "DEBUG:Completed buffer session $debugCounter ." 1>&2;
# Remove DIR_TMP
try rm -r "$DIR_TMP";
- vbm "STATUS:Main function finished."
+ vbm "STATUS:Main function finished.";
} # Main function.
#===END Declare local script functions===
#==END Define script parameters==