#!/bin/bash #============================================================================== # Copyright and license info is available in the LICENSE file included with # the Server Deployment Package (SDP), and also available online: # https://swarm.workshop.perforce.com/projects/perforce-software-sdp/view/main/LICENSE #------------------------------------------------------------------------------ #============================================================================== # Declarations and Environment export P4U_HOME=${P4U_HOME:-/p4/common/bin} export P4U_LIB=${P4U_LIB:-/p4/common/lib} export P4U_ENV=$P4U_LIB/p4u_env.sh export P4U_LOG=Unset export VERBOSITY=${VERBOSITY:-3} # Environment isolation. For stability and security reasons, prepend # PATH to include dirs where known-good scripts exist. # known/tested PATH and, by implication, executables on the PATH. export PATH=$P4U_HOME:$PATH:~/bin:. [[ -r "$P4U_ENV" ]] || { echo -e "\nError: Cannot load environment from: $P4U_ENV\n\n" exit 1 } declare BASH_LIBS=$P4U_ENV BASH_LIBS+=" $P4U_LIB/libcore.sh" BASH_LIBS+=" $P4U_LIB/libp4u.sh" for bash_lib in $BASH_LIBS; do source $bash_lib ||\ { echo -e "\nFATAL: Failed to load bash lib [$bash_lib]. Aborting.\n"; exit 1; } done declare Version=1.0.4 declare -i SilentMode=0 export VERBOSITY=3 #============================================================================== # Local Functions # Function: find_evil_twins function find_evil_twins () { declare p1=${1:-Unset} declare p2=${2:-Unset} declare s2= declare -i count [[ $p1 == Unset || $p2 == Unset ]] && bail "find_evil_twins(): BAD USAGE." s2=${p2%/...} vmsg "Switching workspace to stream $s2" p4 client -f -s -S "$s2" msg "Searching for evil twins between [$p1] and [$p2]:" vmsg "Executing: p4 integ -Ro -n $p1 $p2" p4 -s integ -Ro -n "$p1" "$p2" | grep "without -i flag" > $TmpFile 2>&1 || return 1 count=0 if [[ -s "$TmpFile" ]]; then count=$(wc -l $TmpFile | cut -d ' ' -f 1) msg "Found $count evil twins here:" cat $TmpFile EvilTwinCount=$((EvilTwinCount+count)) fi return 0 } #------------------------------------------------------------------------------ # Function: terminate function terminate { # Disable signal trapping. trap - EXIT SIGINT SIGTERM # Don't litter. cleanTrash vvmsg "$THISSCRIPT: EXITCODE: $OverallReturnStatus" # Stop logging. [[ "${P4U_LOG}" == off ]] || stoplog # With the trap removed, exit. exit $OverallReturnStatus } #------------------------------------------------------------------------------ # Function: usage (required function) # # Input: # $1 - style, either -h (for short form) or -man (for man-page like format). #------------------------------------------------------------------------------ function usage { declare style=${1:--h} echo "USAGE for $THISSCRIPT v$Version: $THISSCRIPT -d <stream_depot> [-s //source/stream] [-t //target/stream] [-i <instance>] [-L <log>] [-si] [-v<n>] [-n] [-D] or $THISSCRIPT [-h|-man|-V] " if [[ $style == -man ]]; then echo -e " DESCRIPTION: Detect \"evil twins\" in a given stream depot. OPTIONS: -d <stream_sdepot> Specify a stream depot to process, e.g. -d fgs to process the //fgs stream depot. This argument is required. -s //source/stream Specify a particular source stream to search. By default, all non-virtual streams are checked. Be aware that if neither -s nor -t are given, a very large numbers of streams may be checked, as all possible combinations of source and target stream are checked. -t //target/stream Specify a particular target stream to search. By default, all non-virtual streams are checked. Be aware that if neither -s nor -t are given, a very large numbers of streams may be checked, as all possible combinations of source and target stream are checked. -i <instance> Specify the SDP instance name. This is required unless the SDP environment has previously been loaded in the current shell, i.e. by sourcing the SDP p4_vars file and specifying the instance. -v<n> Set verbosity 1-5 (-v1 = quiet, -v5 = highest). -L <log> Specify the path to a log file, or the special value 'off' to disable logging. All output (stdout and stderr) are captured in the log. NOTE: This script is self-logging. That is, output displayed on the screen is simultaneously captured in the log file. Do not run this script with redirection operators like '> log' or '2>&1', and do not use 'tee.' -si Operate silently. All output (stdout and stderr) is redirected to the log only; no output appears on the terminal. This cannot be used with '-L off'. -n No-Op. Prints commands instead of running them. -D Set extreme debugging verbosity. HELP OPTIONS: -h Display short help message -man Display man-style help message -V Dispay version info for this script and its libraries. EXAMPLES: Search for evil twins between streams //fgs/DevA and //fgs/DevB. $THISSCRIPT -s //fgs/DevA -t //fgs/DevB Search for all possible evil twins in the //fgs stream depot: $THISSCRIPT -d fgs " fi exit 1 } #============================================================================== # Command Line Processing declare StreamListFile=/tmp/tmp.StreamList.$$.$RANDOM declare SearchedPathsFile=/tmp/tmp.SearchedPaths.$$.$RANDOM declare TmpFile=/tmp/tmp.EvilTwins.$$.$RANDOM declare StreamDepot=Unset declare SourceStream=Unset declare SourcePath= declare TargetStream=Unset declare TargetPath= declare DepotTypeCheck=Unset declare -i PathwayCount=0 declare -i EvilTwinCount=0 GARBAGE+=" $StreamListFile $SearchedPathsFile $TmpFile" declare -i shiftArgs=0 set +u while [[ $# -gt 0 ]]; do case $1 in (-s) SourceStream=$2; shiftArgs=1;; (-t) TargetStream=$2; shiftArgs=1;; (-d) StreamDepot=$2; shiftArgs=1;; (-h) usage -h;; (-man) usage -man;; (-V) show_versions; exit 1;; (-v1) export VERBOSITY=1;; (-v2) export VERBOSITY=2;; (-v3) export VERBOSITY=3;; (-v4) export VERBOSITY=4;; (-v5) export VERBOSITY=5;; (-i) export SDP_INSTANCE=$2; shiftArgs=1;; (-L) export P4U_LOG=$2; shiftArgs=1;; (-si) SilentMode=1;; (-n) export NO_OP=1;; (-D) set -x;; # Debug; use 'set -x' mode. (*) usageError "Unknown arg ($1).";; esac # Shift (modify $#) the appropriate number of times. shift; while [[ $shiftArgs -gt 0 ]]; do [[ $# -eq 0 ]] && usageError "Bad usage." shiftArgs=$shiftArgs-1 shift done done set -u #============================================================================== # Command Line Verification [[ $SilentMode -eq 1 && $P4U_LOG == off ]] && \ usageError "Cannot use '-si' with '-L off'." if [[ "$SourceStream" != Unset ]]; then [[ "$SourceStream" != "//"* ]] && \ usageError "The source stream specified with '-s' must be of the form //depot/stream." # Determine stream depot from source stream if it wasn't provided with '-d'. if [[ $StreamDepot == Unset ]]; then StreamDepot=${SourceStream#//} StreamDepot=${StreamDepot%%/*} fi fi if [[ "$TargetStream" != Unset ]]; then [[ "$TargetStream" != "//"* ]] && \ usageError "The target stream specified with '-t' must be of the form //depot/stream." # Determine stream depot from target stream if it wasn't provided with '-d'. if [[ $StreamDepot == Unset ]]; then StreamDepot=${TargetStream#//} StreamDepot=${StreamDepot%%/*} fi fi [[ $StreamDepot == Unset ]] && \ usageError "The '-d <stream_depot>' paramter is required." export SDP_INSTANCE=${SDP_INSTANCE:-Unset} [[ $SDP_INSTANCE == Unset ]] && \ usageError "The SDP environment must be loaded, or the '-i <instance>' parameter provided." # Load and then tweak SDP environment. source p4_vars "$SDP_INSTANCE" export P4ENVIRO=/dev/null/.p4enviro unset P4CONFIG [[ $P4U_LOG == Unset ]] && \ export P4U_LOG="${LOGS}/${THISSCRIPT%.sh}.$(date +'%Y%m%d-%H%M').log" #============================================================================== # Main Program trap terminate EXIT SIGINT SIGTERM declare -i OverallReturnStatus=0 if [[ "${P4U_LOG}" != off ]]; then touch ${P4U_LOG} || bail "Couldn't touch log file [${P4U_LOG}]." # Redirect stdout and stderr to a log file. if [[ $SilentMode -eq 0 ]]; then exec > >(tee ${P4U_LOG}) exec 2>&1 else exec >${P4U_LOG} exec 2>&1 fi initlog fi msg "$THISSCRIPT v$Version started at $(date)." # If depot was specified as '//x', normalize to 'x'. [[ "$StreamDepot" == "//"* ]] && StreamDepot=${StreamDepot#//} DepotTypeCheck=$(p4 -ztag -F %Type% depot -o $StreamDepot 2>/dev/null) if [[ -n "$DepotTypeCheck" ]]; then [[ "$DepotTypeCheck" != "stream" ]] && \ bail "The depot specified by '-d' must be of type 'stream', not $DepotTypeCheck." else bail "Could not determine depot type for depot $StreamDepot. Aborting." fi msg "Getting list of streams in //$StreamDepot." p4 -ztag -F "%Type%:%Stream%" streams "//$StreamDepot/*" > $StreamListFile export P4CLIENT=tmp.auto.$P4USER.${THISSCRIPT%.sh} echo -e "Client: $P4CLIENT\n\nOwner: $P4USER\n\nDescription:\n\tUsed by $THISSCRIPT\n\nRoot: $P4TMP/${THISSCRIPT%.sh}\n\nView:\n\t//spec/... //$P4CLIENT/spec/..." > $TmpFile msg "Using generated temporary workspace $P4CLIENT." p4 -s client -i < $TmpFile || bail "Failed to create temp client using this spec:\n$(cat $TmpFile)\n" if [[ $SourceStream == Unset && $TargetStream == Unset ]]; then touch $SearchedPathsFile || bail "Could not touch temp file $SearchedPathsFile." while read SourceStream; do [[ $SourceStream == "virtual:"* ]] && continue SourceStream=${SourceStream##*:} SourcePath="$SourceStream/..." while read TargetStream; do [[ "$TargetStream" == "virtual:"* ]] && continue TargetStream=${TargetStream##*:} [[ "$SourceStream" == "$TargetStream" ]] && continue TargetPath="$TargetStream/..." # Direction doesn't matter for evil twin detection, so we only need to search # in a single direction. Avoid redundant checking by checknig the # "searched paths" temp file, which contains a list of already searched paths. grep "${SourceStream#//}:${TargetStream#//}\$" $SearchedPathsFile > /dev/null 2>&1 [[ $? -eq 0 ]] && continue grep "${TargetStream#//}:${SourceStream#//}\$" $SearchedPathsFile > /dev/null 2>&1 [[ $? -eq 0 ]] && continue find_evil_twins "$SourcePath" "$TargetPath" ||\ OverallReturnStatus=1 PathwayCount=$((PathwayCount+1)) echo "${SourceStream#//}:${TargetStream#//}" >> $SearchedPathsFile done < $StreamListFile done < $StreamListFile elif [[ $SourceStream != Unset && $TargetStream != Unset ]]; then SourcePath="$SourceStream/..." TargetPath="$TargetStream/..." find_evil_twins "$SourcePath" "$TargetPath" ||\ OverallReturnStatus=1 PathwayCount=1 else bail "Specify only '-s' or '-t', but not both, is not (yet?) supported." fi if [[ $OverallReturnStatus -eq 0 ]]; then msg "${H}\nAll processing completed successfully.\n" else msg "${H}\nProcessing completed, but with errors. Scan above output carefully.\n" fi # Illustrate using $SECONDS to display runtime of a script. msg "Found $EvilTwinCount evil twins searching $PathwayCount pathway(s) in $(($SECONDS/3600)) hours $(($SECONDS%3600/60)) minutes $(($SECONDS%60)) seconds.\n" # See the terminate() function, which is really where this script exits. exit $OverallReturnStatus
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#4 | 26652 | Robert Cowham |
This is Tom's change: Introduced new 'Unsupported' directory to clarify that some files in the SDP are not officially supported. These files are samples for illustration, to provide examples, or are deprecated but not yet ready for removal from the package. The Maintenance and many SDP triggers have been moved under here, along with other SDP scripts and triggers. Added comments to p4_vars indicating that it should not be edited directly. Added reference to an optional site_global_vars file that, if it exists, will be sourced to provide global user settings without needing to edit p4_vars. As an exception to the refactoring, the totalusers.py Maintenance script will be moved to indicate that it is supported. Removed settings to support long-sunset P4Web from supported structure. Structure under new .../Unsupported folder is: Samples/bin Sample scripts. Samples/triggers Sample trigger scripts. Samples/triggers/tests Sample trigger script tests. Samples/broker Sample broker filter scripts. Deprecated/triggers Deprecated triggers. To Do in a subsequent change: Make corresponding doc changes. |
||
#3 | 25193 | C. Thomas Tyler |
EvilTwinDetector.sh v2.1.3: * Narrowed focus to stream depots only, as only in stream depots is there sufficient metadata detect evil twins. * Updated evil twin detection logic. * Updated docs and command line usage. * Better reporting. * Added capability to fix evil twins with baseless integrations. |
||
#2 | 24781 | C. Thomas Tyler |
EvilTwinDetector.sh v1.1.0: * Implemented trigger mode to prevent evil triggers. * Refined output. * Enhanced docs. * Fixed typos/grammatical errors in a few error messages. Bypassing code review for now as this change is about to be merged with and succeeded by a different, bigger change made elsewhere. |
||
#1 | 20062 | C. Thomas Tyler | Added Evil Twin Detector maintenance script. |