feat(bkgpslog):Enable custom TTL for buffer and script
authorSteven Baltakatei Sandoval <baltakatei@gmail.com>
Mon, 6 Jul 2020 18:42:14 +0000 (18:42 +0000)
committerSteven Baltakatei Sandoval <baltakatei@gmail.com>
Mon, 6 Jul 2020 18:42:14 +0000 (18:42 +0000)
New options: '-b' (buffer), '-B' (script).

Updated showUsage().

exec/bkgpslog

index 3a7bae87fb20af28d0f223bc50952332326728b0..6739f0123f4e376eeb8144ffde41118a140acb1d 100755 (executable)
@@ -7,14 +7,14 @@
 #==BEGIN Define script parameters==
 ## Logging Behavior parameters
 BUFFER_TTL="300"; # time between file writes
-SCRIPT_TTL="day"; # (day|hour)
+SCRIPT_TTL_TE="day"; # (day|hour)
 #### TZ="UTC"; export TZ; # Default time zone; overridden by '--time-zone=[str]' option
 DIR_TMP_DEFAULT="/dev/shm"; # Default parent of working directory
 
 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="0.3.9";          # Define version of script.
+SCRIPT_VERSION="0.3.10";          # Define version of script.
 SCRIPT_NAME="bkgpslog";          # Define basename of script file.
 SCRIPT_URL="https://gitlab.com/baltakatei/ninfacyzga-01"; # Define wesite hosting this script.
 AGE_VERSION="1.0.0-beta2";       # Define version of age (encryption program)
@@ -152,21 +152,26 @@ showUsage() {
     echoerr "            Display debugging info."
     echoerr "    -e, --encrypt"
     echoerr "            Encrypt output."
-    echoerr "    -r, --recipient [ pubkey string ]"
+    echoerr "    -r, --recipient [ string pubkey ]"
     echoerr "            Specify recipient. May be age or ssh pubkey."
+    echoerr "            May be specified multiple times for multiple pubkeys."
     echoerr "            See https://github.com/FiloSottile/age"
-    echoerr "    -o, --output [ directory ]"
+    echoerr "    -o, --output [ path dir ]"
     echoerr "            Specify output directory to save logs."
     echoerr "    -c, --compress"
     echoerr "            Compress output with gzip (before encryption if enabled)."
     echoerr "    -z, --time-zone"
     echoerr "            Specify time zone. (ex: \"America/New_York\")"
-    echoerr "    -t, --temp-dir"
+    echoerr "    -t, --temp-dir [path dir]"
     echoerr "            Specify parent directory for temporary working directory."
     echoerr "            Default: \"/dev/shm\""
-    echoerr "    -R, --recipient-dir"
+    echoerr "    -R, --recipient-dir [path dir]"
     echoerr "            Specify directory containing files whose first lines are"
-    echoerr "            to be interpreted as pubkey strings (see \'-r\' option)."
+    echoerr "            to be interpreted as pubkey strings (see \\'-r\\' option)."
+    echoerr "    -b, --buffer-ttl [integer]"
+    echoerr "            Specify custom buffer period in seconds (default: 300 seconds)"
+    echoerr "    -B, --script-ttl [integer]"
+    echoerr "            Specify custom script time-to-live in seconds (default: \"day\")"
     echoerr
     echoerr "EXAMPLE: (bash script lines)"
     echoerr "/bin/bash bkgpslog -v -e -c \\"
@@ -215,6 +220,8 @@ processArguments() {
            -z | --time-zone) try setTimeZoneEV "$2"; shift;; # Set timestamp timezone
            -t | --temp-dir) OPTION_TMPDIR="true" && argTempDirPriority="$2"; shift;; # Set time zone
            -R | --recipient-dir) OPTION_RECIPIENTS="true"; OPTION_RECDIR="true" && argRecDir="$2"; shift;; # Add recipient watch dir
+           -b | --buffer-ttl) OPTION_CUSTOM_BUFFERTTL="true" && argCustomBufferTTL="$2"; shift;; # Set custom buffer period (default: 300 seconds)
+           -B | --script-ttl) OPTION_CUSTOM_SCRIPTTTL_TE="true" && argCustomScriptTTL="$2"; shift;; # Set custom script TTL (default: "day")
            *) echoerr "ERROR: Unrecognized argument: $1"; echoerr "STATUS:All arguments:$*"; exit 1;; # Handle unrecognized options.
        esac
        shift
@@ -636,34 +643,34 @@ displayMissing() {
 
     #==END Display errors==
 } # Display missing apps, files, dirs
-setScriptTTL() {
-    #Desc: Sets script TTL
-    #Usage: setScriptTTL arg1
-    #Input: arg1: "day" or "hour"
-    #Output: scriptTTL
-    #Depends: timeUntilNextHour or timeUntilNextDay
-    local ARG1
-    ARG1="$1"
-    if [[ "$ARG1" = "day" ]]; then
+magicSetScriptTTL() {
+    #Desc: Sets script_TTL seconds from provided time_element string argument
+    #Usage: magicSetScriptTTL [str time_element]
+    #Input: arg1: string (Ex: SCRIPT_TTL_TE; "day" or "hour")
+    #Output: var: SCRIPT_TTL (integer seconds)
+    #Depends: timeUntilNextHour, timeUntilNextDay
+    local argTimeElement
+    argTimeElement="$1"
+    if [[ "$argTimeElement" = "day" ]]; then
            # Set script lifespan to end at start of next day
-       if ! scriptTTL="$(timeUntilNextDay)"; then
-           if [[ "$scriptTTL" -eq 0 ]]; then
-           ((scriptTTL++)); # Add 1 because 0 would cause 'timeout' to never timeout.
+       if ! SCRIPT_TTL="$(timeUntilNextDay)"; then
+           if [[ "$SCRIPT_TTL" -eq 0 ]]; then
+           ((SCRIPT_TTL++)); # Add 1 because 0 would cause 'timeout' to never timeout.
            else
            yell "ERROR: timeUntilNextDay exit code $?"; exit 1;
            fi;
        fi;
-    elif [[ "$ARG1" = "hour" ]]; then
+    elif [[ "$argTimeElement" = "hour" ]]; then
        # Set script lifespan to end at start of next hour
-       if ! scriptTTL="$(timeUntilNextHour)"; then
-           if [[ "$scriptTTL" -eq 0 ]]; then
-               ((scriptTTL++)); # Add 1 because 0 would cause 'timeout' to never timeout.
+       if ! SCRIPT_TTL="$(timeUntilNextHour)"; then
+           if [[ "$SCRIPT_TTL" -eq 0 ]]; then
+               ((SCRIPT_TTL++)); # Add 1 because 0 would cause 'timeout' to never timeout.
            else
                yell "ERROR: timeUntilNextHour exit code $?"; exit 1;
            fi;
        fi;
     else
-       yell "ERROR:Invalid argument for setScriptTTL function."; exit 1;
+       yell "ERROR:Invalid argument for setScriptTTL function:$argTimeElement"; exit 1;
     fi
 } # Seconds until next (day|hour).
 checkMakeTar() {
@@ -835,7 +842,7 @@ checkAgePubkey() {
 validateInput() {
     # Desc: Validates Input
     # Usage: validateInput [str input] [str input type]
-    # Version: 0.2.1
+    # Version: 0.3.0
     # Input: arg1: string to validate
     #        arg2: string specifying input type (ex:"ssh_pubkey")
     # Output: return code 0: if input string matched specified string type
@@ -857,7 +864,7 @@ validateInput() {
     ### Check for alnum/dash base64 (ex: "ssh-rsa AAAAB3NzaC1yc2EAAA")
     if [[ "$argType" = "ssh_pubkey" ]]; then
        if [[ "$argInput" =~ ^[[:alnum:]-]*[\ ]*[[:alnum:]+/=]*$ ]]; then
-       return 0; fi; fi;
+           return 0; fi; fi;
 
     ## age_pubkey
     ### Check for age1[:bech32:]
@@ -865,6 +872,22 @@ validateInput() {
        if [[ "$argInput" =~ ^age1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]*$ ]]; then
            return 0; fi; fi
 
+    ## integer
+    if [[ "$argType" = "integer" ]]; then
+       if [[ "$argInput" =~ ^[[:digit:]]*$ ]]; then
+           return 0; fi; fi;
+
+    ## time element (year, month, week, day, hour, minute, second)
+    if [[ "$argType" = "time_element" ]]; then
+       if [[ "$argInput" = "year" ]] || \
+              [[ "$argInput" = "month" ]] || \
+              [[ "$argInput" = "week" ]] || \
+              [[ "$argInput" = "day" ]] || \
+              [[ "$argInput" = "hour" ]] || \
+              [[ "$argInput" = "minute" ]] || \
+              [[ "$argInput" = "second" ]]; then
+           return 0; fi; fi;
+    
     # Return error if no condition matched.
     return 1;
 } # Validates strings
@@ -967,11 +990,11 @@ magicParseRecipientDir() {
            #### Initialize variable indicating outcome of pubkey review
            unset updateRecipients
            #### Add existing recipients
-           candRecPubKeysValid=(${recPubKeysValid[@]});
+           candRecPubKeysValid=("${recPubKeysValid[@]}");
            #### Parse files in recipientDir
            for file in "$recipientDir"/*; do
                ##### Read first line of each file
-               recFileLine="$(cat "$file" | head -n1)";
+               recFileLine="$(head -n1 "$file")";
                ##### check if first line is a valid pubkey
                if checkAgePubkey "$recFileLine" && \
                        ( validateInput "$recFileLine" "ssh_pubkey" || validateInput "$recFileLine" "age_pubkey"); then
@@ -984,8 +1007,8 @@ magicParseRecipientDir() {
                fi;
            done
            #### Write updated recPubKeysValid array to recPubKeysValid if no failure detected
-           if ! updateRecipients="false"; then
-               recPubKeysValid=(${candRecPubKeysValid[@]});
+           if ! [[ "$updateRecipients" = "false" ]]; then
+               recPubKeysValid=("${candRecPubKeysValid[@]}");
            fi;
        else
            yell "ERROR:$0:Recipient directory $argRecDir does not exist. Exiting."; exit 1;
@@ -993,10 +1016,10 @@ magicParseRecipientDir() {
     fi;
     # Handle case if '-e' set but '-R' not set
     if [[ "$OPTION_ENCRYPTION" = "true" ]] && [[ ! "$OPTION_RECDIR" = "true" ]]; then
-       yell "ERROR: \'-e\' set but \'-R\' is not set."; fi;
+       yell "ERROR: \\'-e\\' set but \\'-R\\' is not set."; fi;
     # Handle case if '-R' set but '-e' not set
     if [[ ! "$OPTION_ENCRYPTION" = "true" ]] && [[ "$OPTION_RECDIR" = "true" ]]; then
-       yell "ERROR: \'-R\' is set but \'-e\' is not set."; fi;
+       yell "ERROR: \\'-R\\' is set but \\'-e\\' is not set."; fi;
 } # Update recPubKeysValid with argRecDir
 magicParseRecipientArgs() {
     # Desc: Parses recipient arguments specified by '-r' option
@@ -1039,10 +1062,10 @@ magicParseRecipientArgs() {
     fi;
     # Catch case if '-e' is set but '-r' or '-R' is not
     if [[ "$OPTION_ENCRYPT" = "true" ]] && [[ ! "$OPTION_RECIPIENTS" = "true" ]]; then
-       yell "ERROR:\'-e\' set but no \'-r\' or \'-R\' set."; exit 1; fi;
+       yell "ERROR:\\'-e\\' set but no \\'-r\\' or \\'-R\\' set."; exit 1; fi;
     # Catch case if '-r' or '-R' set but '-e' is not
     if [[ ! "$OPTION_ENCRYPT" = "true" ]] && [[ "$OPTION_RECIPIENTS" = "true" ]]; then
-       yell "ERROR:\'-r\' or \'-R\' set but \'-e\' is not set."; exit 1; fi; 
+       yell "ERROR:\\'-r\\' or \\'-R\\' set but \\'-e\\' is not set."; exit 1; fi; 
 } # Populate recPubKeysValid with argRecPubKeys; form encryption cmd string and filename suffix
 magicParseCompressionArg() {
     # Desc: Parses compression arguments specified by '-c' option
@@ -1095,6 +1118,41 @@ magicInitWorkingDir() {
     ## Set DIR_TMP using DIR_TMP_PARENT and nonce (SCRIPT_TIME_START)
     DIR_TMP="$DIR_TMP_PARENT"/"$SCRIPT_TIME_START""..bkgpslog" && vbm "DEBUG:Set DIR_TMP to:$DIR_TMP"; # Note: removed at end of main().    
 } # Sets working dir
+magicParseCustomTTL() {
+    # Desc: Set user-specified TTLs for buffer and script
+    # Input: vars: argCustomBufferTTL (integer), argCustomScriptTTL_TE (string)
+    # Input: vars: OPTION_CUSTOM_BUFFERTTL, OPTION_CUSTOM_SCRIPTTTL
+    # Input: vars: BUFFER_TTL (integer), SCRIPT_TTL_TE (string)
+    # Output: BUFFER_TTL (integer), SCRIPT_TTL_TE (string)
+    # Depends validateInput(), showUsage(), yell
+
+    # React to '-b, --buffer-ttl' option
+    if [[ "$OPTION_CUSTOM_BUFFERTTL" = "true" ]]; then
+       ## T: Check if argCustomBufferTTL is an integer
+       if validateInput "$argCustomBufferTTL" "integer"; then
+           ### T: argCustomBufferTTL is an integer
+           BUFFER_TTL="$argCustomBufferTTL";
+       else
+           ### F: argcustomBufferTTL is not an integer
+           yell "ERROR:Invalid integer argument for custom buffer time-to-live."; showUsage; exit 1;
+       fi;
+       ## F: do not change BUFFER_TTL
+    fi;
+    
+    # React to '-B, --script-ttl' option
+    if [[ "$OPTION_CUSTOM_SCRIPTTTL_TE" = "true" ]]; then
+       ## T: Check if argCustomScriptTTL is a time element (ex: "day", "hour")
+       if validateInput "$argCustomScriptTTL" "time_element"; then
+           ### T: argCustomScriptTTL is a time element
+           SCRIPT_TTL_TE="$argCustomScriptTTL";
+       else
+           ### F: argcustomScriptTTL is not a time element
+           yell "ERROR:Invalid time element argument for custom script time-to-live."; showUsage; exit 1;
+       fi;
+       ## F: do not change SCRIPT_TTL_TE
+    fi;    
+} # Sets custom script or buffer TTL if specified
+
 
 main() {
     # Process arguments
@@ -1109,17 +1167,20 @@ main() {
     magicParseCompressionArg; # Updates CMD_COMPRESS[_SUFFIX]
     #### React to "-R" ("recipient directory") option
     magicParseRecipientDir; # Updates recPubKeysValid
+    #### React to custom buffer and script TTL options ("-b", "-B")
+    magicParseCustomTTL; # Sets custom SCRIPT_TTL_TE and/or BUFFER_TTL if specified
 
     # Check that critical apps and dirs are available, display missing ones.
     if ! checkapp gpspipe tar && ! checkdir "$DIR_OUT" "DIR_TMP"; then
        yell "ERROR:Critical components missing.";
        displayMissing; yell "Exiting."; exit 1; fi
 
-    # Set script lifespan
-    setScriptTTL "$SCRIPT_TTL"; # seconds until next new SCRIPT_TTL (ex: "day" or "hour")
+    # Set script lifespan (SCRIPT_TTL from SCRIPT_TTL_TE)
+    magicSetScriptTTL "$SCRIPT_TTL_TE";
+    ## Note: SCRIPT_TTL_TE is time element string (ex: "day") while SCRIPT_TTL is integer seconds
 
-    # File name substring: encoded bufferTTL
-    bufferTTL_STR="$(timeDuration $BUFFER_TTL)";
+    # File name substring (ISO-8601 duration from BUFFER_TTL)
+    bufferTTL_STR="$(timeDuration "$BUFFER_TTL")";
 
     # Init temp working dir
     try mkdir "$DIR_TMP" && vbm "DEBUG:Working dir creatd at:$DIR_TMP";
@@ -1139,7 +1200,7 @@ main() {
     CMD_CONV_KML="gpsbabel -i nmea -f - -o kml -F - " && vbm "STATUS:Set CMD_CONV_KML to:$CMD_CONV_KML"; # convert NMEA to KML
 
     # MAIN LOOP:Record gps data until script lifespan ends
-    while [[ "$SECONDS" -lt "$scriptTTL" ]]; do
+    while [[ "$SECONDS" -lt "$SCRIPT_TTL" ]]; do
        magicGatherWriteBuffer &
        sleep "$BUFFER_TTL";
     done