From 70eb080fb13b8ca5261014880963f028c0876b3f Mon Sep 17 00:00:00 2001 From: kwindrem <58538395+kwindrem@users.noreply.github.com> Date: Thu, 18 Apr 2024 11:29:01 -0700 Subject: [PATCH] switched to using patch for some files --- .../{relaystate.py.edited => relaystate.py} | 0 ...elaystate.py.source => relaystate.py.orig} | 0 FileSets/PatchSource/relaystate.py.patch | 4 +- FileSets/gpio_list | 2 +- HelperResources/CommonResources | 806 ++++++++++++------ HelperResources/EssentialResources | 1 + HelperResources/ServiceResources | 15 +- HelperResources/version | 2 +- ReadMe | 28 +- changes | 4 + version | 2 +- 11 files changed, 571 insertions(+), 293 deletions(-) rename FileSets/PatchSource/{relaystate.py.edited => relaystate.py} (100%) rename FileSets/PatchSource/{relaystate.py.source => relaystate.py.orig} (100%) diff --git a/FileSets/PatchSource/relaystate.py.edited b/FileSets/PatchSource/relaystate.py similarity index 100% rename from FileSets/PatchSource/relaystate.py.edited rename to FileSets/PatchSource/relaystate.py diff --git a/FileSets/PatchSource/relaystate.py.source b/FileSets/PatchSource/relaystate.py.orig similarity index 100% rename from FileSets/PatchSource/relaystate.py.source rename to FileSets/PatchSource/relaystate.py.orig diff --git a/FileSets/PatchSource/relaystate.py.patch b/FileSets/PatchSource/relaystate.py.patch index be7deba..555f1b7 100644 --- a/FileSets/PatchSource/relaystate.py.patch +++ b/FileSets/PatchSource/relaystate.py.patch @@ -1,5 +1,5 @@ ---- /Users/Kevin/GitHub/RpiGpioSetup/FileSets/PatchSource/relaystate.py.source 2024-02-23 09:55:27 -+++ /Users/Kevin/GitHub/RpiGpioSetup/FileSets/PatchSource/relaystate.py.edited 2024-02-23 22:32:14 +--- /Users/Kevin/GitHub/RpiGpioSetup.copy/FileSets/PatchSource/relaystate.py-1.orig 2024-02-23 09:55:27 ++++ /Users/Kevin/GitHub/RpiGpioSetup.copy/FileSets/PatchSource/relaystate.py-1 2024-02-23 22:32:14 @@ -21,10 +21,16 @@ ('com.victronenergy.settings', [ '/Settings/Relay/Function'])] # Managed by the gui diff --git a/FileSets/gpio_list b/FileSets/gpio_list index 8ddf27d..c73b428 100644 --- a/FileSets/gpio_list +++ b/FileSets/gpio_list @@ -31,7 +31,7 @@ # these have pull UPs # Digital input 1 GPIO 5 / header pin 29 5 in digital_input_1 -# Digital input 2 PIO 6 / header pin 31 +# Digital input 2 GPIO 6 / header pin 31 6 in digital_input_2 # in stock code these have pull DOWNs diff --git a/HelperResources/CommonResources b/HelperResources/CommonResources index f448b30..02bc575 100755 --- a/HelperResources/CommonResources +++ b/HelperResources/CommonResources @@ -12,6 +12,9 @@ # (decommissioned) PROMPT - prompt user for additional installation options # UNINSTALL - remove package components # EXIT - exit script without taking any action +# CHECK - runs file set checks only +# this will attempt to create a missing file set so PackageManager +# won't report it missing # CommonResources may set the the action if initial checks # indicate a clear direction # otherwise, the action will be set based on user input (in the script) @@ -23,8 +26,6 @@ # checkFileSets EXITS locally scriptAction='NONE' -installFailed=false -installExitReason=$EXIT_SUCCESS # flags to control setup script behavior (in endScript) rebootNeeded=false @@ -46,6 +47,93 @@ fileListAll=() ######## skip to bottom of file for remainder of code executed when script is sourced +installFailed=false +installExitReason=$EXIT_ERROR +installFailMessage="" +installPreChecks=true +installFailCount=0 +uninstallFailed=false + +# cleanup on any exit +exitCleanup () +{ + # remove temp directory + rm -rf "$tempFileDir" +} + +trap exitCleanup EXIT + + +# setInstallFailed sets flags to prevent further install steps +# and insure the package is uninstalled completely +# +# $1 indicates the reason for the failure and will evenutally be uused +# report the failure reason when exiting the script +# +# any remaining paremeters are passed to logMessage +# and also saved in installFailMessage for others to use +# the message is also sent to stderr if not running from the command line +# this allows PackageManager to report the full reason for failure +# +# a setup script can be run from the console, or from another script or program (unattended) +# when running from the console +# setInstallFailed will report errors and return to the caller +# +# if running unattended and if the script action is INSTALL +# during the precheck period (before any system modification) +# setInstallFailed WILL EXIT WITHOUT RETURNING TO THE CALLER !!!!! +# after the precheck period, system modifications may have been made so +# the scriptAction is changed to UNINSTALL so the modifictions can be reversed +# otherwise, setInstallFailed just logs the error +# +# note that PackageManager makes most of the pre-check tests +# before calling the setup script +# the only exception is file set checks made in checkFileSets +# +# installFailed is set here so that additional install operations will not be performed + + +setInstallFailed () +{ + (( installFailCount += 1 )) + if [ ! -z "$1" ]; then + installExitReason=$1 + # no reson specified - use the generaic error exit code + else + installExitReason=EXIT_ERROR + fi + message="${@:2}" + if [ ! -z "$message" ]; then + installFailMessage="$message" + logMessage "ERROR: $message" + # if not running from console, output error to stderr + if ! $logToConsole ; then + echo "$message" >&2 + fi + else + installFailMessage="" + fi + + if [ $scriptAction == 'UNINSTALL' ]; then + uninstallFailed=true + else + installFailed=true + fi + if ! $userInteraction && [ $scriptAction == 'INSTALL' ]; then + # during "pre-checks" failures occur before any system mofifications + # EXIT NOW - DO NOT RETURN TO THE CALLER !!!!! + if $installPreChecks ; then + exit $installExitReason + # after "pre-checks" system mofifications may already have occured + # so an uninstall needs to follow the install + else + scriptAction='UNINSTALL' + fi + fi +} + + + # checkPackageDependencies checks the packageDependencies file in the package directory # # all unmet dependencies are reported to the command line/log @@ -59,9 +147,9 @@ function checkPackageDependencies () #no dependencies specified for this package if ! [ -f "$dependencyFile" ]; then return; fi - errors=false - + errors="" while IFS= read -r line; do + error="" read package requirement <<< "$line" if [ -f "$installedVersionPrefix"$package ]; then packageInstalled=true @@ -71,20 +159,26 @@ function checkPackageDependencies () case $requirement in installed) if ! $packageInstalled ; then - setInstallFailed $EXIT_PACKAGE_CONFLICT "$package must be installed first" - error=true + error="$package must be installed" fi ;; uninstalled) if $packageInstalled ; then - setInstallFailed $EXIT_PACKAGE_CONFLICT "$package must be uninstalled first" - error=true + error="$package must be uninstalled" fi ;; esac + if ! [ -z "$error" ]; then + if ! [ -z "$errors" ]; then + errors+=", " + fi + errors+="$error" + fi - if $errors; then endScript; fi done < "$dependencyFile" + if ! [ -z "$errors" ]; then + setInstallFailed $EXIT_PACKAGE_CONFLICT "$errors" + fi } # getFileLists reads the file list from files in the FileSets directory @@ -208,7 +302,6 @@ yesNoPrompt () # if this parameter does not exist, installation WILL change scriptAction to INSTALL # this provides backaward compatibility with scripts written prior to the reinstall logic # - standardActionPrompt () { if [ $# -gt 0 ] && [ $1 == 'MORE_PROMPTS' ]; then @@ -222,6 +315,8 @@ standardActionPrompt () # don't allow install choice if incompatibilities have already been detected if ! $installFailed ; then echo " Install and activate (i)" + else + echo " can't install - errors reported above" fi if $optionsSet ; then echo " Reinstall (r) based on options provided at last install" @@ -229,7 +324,7 @@ standardActionPrompt () echo " Uninstall (u) and restores all files to stock" echo " Quit (q) without further action" echo " Display setup log (s) outputs the last 100 lines of the log" - if [ ! -z $packageLogFile ]; then + if [ ! -z "$packageLogFile" ]; then echo " Display Log (l) outputs the last 100 lines of the log" fi echo @@ -271,37 +366,6 @@ standardActionPrompt () } -# setInstallFailed sets flags to prevent further install steps -# and insure the package is uninstalled completely -# -# $1 indicates the reason for the failure and will evenutally be uused -# report the failure reason when exiting the script -# -# any remaining paremeters are passed to logMessage -# -# the UNINSTALL scriptAction is used so that older package setup scripts -# will restore everything it has modified (not using updateActiveFile, etc) -# -# also test $installFailed to see if this was an install failure -# or an actuall uninstall - -setInstallFailed () -{ - installFailed=true - scriptAction='UNINSTALL' - if [ ! -z "$1" ]; then - installExitReason=$1 - fi - message="${@:2}" - if [ ! -z "$message" ]; then - logMessage "ERROR: $message" - # if not running from console, output error to stderr - if ! $logToConsole ; then - echo "$message" >&2 - fi - fi -} - # forcePackageUninstall insures a conflicting package is uninstalled before # this package is installed # the setup script must call this script BEFORE it begins installing anything @@ -447,7 +511,8 @@ updateActiveFile () # separate source and replacement files specified local sourceFile="" local activeFile="" - local prevousPackage="" + local previousPackage="" + local doPatch=false if [ $# == 2 ]; then if [ -f "$1" ]; then sourceFile="$1" @@ -462,16 +527,21 @@ updateActiveFile () fi local baseName=$(basename "$activeFile") - + local packageList="$activeFile.package" # replacement files are not needed for some versions # if so marked, leave original untouched if [ -f "$fileSet/$baseName.USE_ORIGINAL" ]; then return 1 + # source file not specified separately - look for it in expected places elif [ -z "$sourceFile" ]; then - # first in patched files - if [ -f "$patchedFiles/$baseName" ]; then - sourceFile="$patchedFiles/$baseName" + # first in temp files - patched file + if [ -f "$tempFileDir/$baseName.patchedForInstall" ]; then + sourceFile="$tempFileDir/$baseName.patchedForInstall" + doPatch=true + # then in temp files - replacement + elif [ -f "$tempFileDir/$baseName" ]; then + sourceFile="$tempFileDir/$baseName" # then in version-specific FileSet elif [ -f "$fileSet/$baseName" ]; then sourceFile="$fileSet/$baseName" @@ -504,24 +574,19 @@ updateActiveFile () fi # check for package conflicts - if [ -f "$activeFile.package" ]; then - prevousPackage=$( cat "$activeFile.package" ) - if [ $packageName != $prevousPackage ]; then - setInstallFailed $EXIT_PACKAGE_CONFLICT "$(basename $activeFile) was already modfied by $prevousPackage" - return 1 - fi - fi - # already updated - nothing to do - if [ -f "$activeFile" ]; then - if cmp -s "$sourceFile" "$activeFile" > /dev/null ; then - return 1 - fi - fi - - # backup missing (this should not ever happen) - if ! backupActiveFile "$activeFile" ; then - setInstallFailed $EXIT_FILE_SET_ERROR "no backup for $baseName" - return 1 + # loop through all names in .package file + # conflict if package names do not match and this is a replacement (not a patch) + matchFound=false + if [ -e "$packageList" ]; then + previousPackages=$( cat "$packageList" ) + for previousPackage in ${previousPackages[@]}; do + if [ $packageName == $previousPackage ]; then + matchFound=true + elif ! $doPatch ; then + setInstallFailed $EXIT_PACKAGE_CONFLICT "$(basename $activeFile) was already modfied by $previousPackage" + return 1 + fi + done fi # add file to installed files list (used for uninstallAll) @@ -530,15 +595,41 @@ updateActiveFile () echo "$activeFile" >> "$installedFilesList" # update package flag to prevent overwrites by other packages - echo $packageName > "$activeFile.package" + # if replacement, replace the .package file + if ! $doPatch ; then + echo $packageName > "$packageList" + # if patch and this package not in list, add add it + elif ! $matchFound ; then + echo $packageName >> "$packageList" + fi + # already updated - don't need to do any more + if [ -f "$activeFile" ]; then + if cmp -s "$sourceFile" "$activeFile" > /dev/null ; then + return 1 + fi + fi + + backupActiveFile "$activeFile" # update the active file + # patched files have already incorporated current active file content + # so nothing diffrerent here cp "$sourceFile" "$activeFile" + # save the current patch file for use during an uninstall + currentPatchFile="$tempFileDir/$baseName.currentPatch" + previousPatchFile="$previousPatchesDir/$baseName.patch" + if [ -e "$currentPatchFile" ]; then + cp "$currentPatchFile" "$previousPatchFile" + # no patch file used for this update + # make sure restoreActiveFile doesn't try to reverse patch for uninstall + else + rm -f "$previousPatchFile" + fi updateRestartFlags "$activeFile" thisFileUpdated=true return 0 -} +} # end updateActiveFile () # restoreActiveFile moves the backup copy to the active location @@ -552,37 +643,90 @@ updateActiveFile () # restore only if the package that updated this file is the current package # failure is indicated in the return code but does not trigger as faliure + restoreActiveFile () { thisFileUpdated=false - - if [ -f "$1.package" ]; then - prevousPackage=$( cat "$1.package" ) - if [ $packageName != $prevousPackage ]; then - return 1 - fi + local activeFile="$1" + local baseName=$( basename "$activeFile" ) + local packageList="$activeFile.package" + # look for this package's name in .package list + # and remove it if found + matchFound=false + remainingPackages="" + if [ -f "$packageList" ]; then + previousPackages=$( cat "$packageList" ) + for previousPackage in ${previousPackages[@]}; do + if [ $packageName == $previousPackage ]; then + matchFound=true + else + remainingPackages+="$previousPackage " + fi + done + # no .package file - so OK to install + else + matchFound=true + fi + + # if not found - nothing to uninstall + if ! $matchFound ; then + return 1 fi - if [ -e "$1.orig" ]; then - mv -f "$1.orig" "$1" - thisFileUpdated=true - elif [ -f "$1.NO_ORIG" ]; then - rm -f "$1" - thisFileUpdated=true + restoreOriginal=true + unpatchError=false + # no other packages in .package so remove it + # and restore the original + if [ -z "$remainingPackages" ] ; then + rm -f "$packageList" + else + # eliminate this package from .package list if there are others + grep -v "$packageName" "$packageList" | tee "$packageList" > /dev/null + + # attempt to reverse patch the active file + # if success, don't restore original + previousPatchFile="$previousPatchesDir/$baseName.patch" + if [ -e "$previousPatchFile" ] && + yes 'no' | patch -R "$activeFile" "$previousPatchFile" > /dev/null ; then + restoreOriginal=false + # no previous patch file or reverse patch failed + # original will be restored + else + unpatchError=true + fi + fi + # restore original if no other packages have modified this active file + # or if reverse patch failed + if $restoreOriginal ; then + if [ -e "$activeFile.orig" ]; then + mv -f "$activeFile.orig" "$activeFile" + thisFileUpdated=true + elif [ -f "$activeFile.NO_ORIG" ]; then + rm -f "$activeFile" + thisFileUpdated=true + fi fi - if $thisFileUpdated ; then - rm -f "$1.NO_ORIG" - rm -f "$1.package" - # remove file from installed file list - if [ -f "$installedFilesList" ]; then - grep -v "$1" "$installedFilesList" | tee "$installedFilesList" > /dev/null - fi - updateRestartFlags "$1" - return 0 - else - return 1 + if $unpatchError ; then + #### TODO: DRASTIC but can't think of a way around this + message="CRITICAL: $package $baseName could not be uninstalled" + logMessage "message" + echo "message" >> "$scriptDir/patchErrors" + message=" moodificataions by $remainingPackages were lost and must be reinstalled" + logMessage "message" + echo "message" >> "$scriptDir/patchErrors" + + setInstallFailed $EXIT_PATCH_ERROR "patch error details were saved in $packageName/patchErrors" fi -} + + rm -f "$previousPatchFile" + + # remove file from installed file list + if [ -f "$installedFilesList" ]; then + grep -v "$activeFile" "$installedFilesList" | tee "$installedFilesList" > /dev/null + fi + updateRestartFlags "$activeFile" + return 0 +} # end restoreActiveFile () # checkFileSets validates the file sets used to install package modifications @@ -602,15 +746,7 @@ restoreActiveFile () # Replacement files that have no original specify an "alternate original" that is used # for version comparisons that locate an appropriate replacement -# dummy routine for backward compatibility -# the actual work is now done in-line when CommonResources is sourced - checkFileSets () -{ - return -} - -_checkFileSets () { # no file sets - nothing to check if ! [ -e "$pkgFileSets" ]; then return; fi @@ -634,15 +770,17 @@ _checkFileSets () local versionList=( $(echo ${tempList[@]} | tr ' ' '\n' | sort -t ':' -r -n -k 2 | uniq ) ) # versioned file sets exist but empty file list - if [ ! -z $versionList ] && [ -z $fileList ]; then - setInstallFailed $EXIT_FILE_SET_ERROR "versions exist, but empty file list" + if [ ! -z "$versionList" ] && [ -z "$fileList" ]; then + setInstallFailed $EXIT_FILE_SET_ERROR "empty file list" + touch "$fileSet/INCOMPLETE" + rm -f "$fileSet/COMPLETE" return # no versioned file sets - nothing to validate - allow install - elif [ -z $versionList ]; then return; fi - + elif [ -z "$versionList" ]; then return; fi + # attempt to create a new file set or validate an existing one not marked as COMPLETE - rm -f "$fileSet/INCOMPLETE" + rm -f "$fileSet/INCOMPLETE" # attempt to create file set if it doesn't exist if [ ! -d "$fileSet" ]; then @@ -820,13 +958,14 @@ buildUninstallListsfromSetupScript () installAllFiles () { if [ -z "$fileListAll" ]; then - getFileLists + getFileLists "$pkgFileSets" fi - if [ ! -z $fileListAll ]; then + if [ ! -z "$fileListAll" ]; then logMessage "installing files" local file for file in ${fileListAll[@]}; do + if $installFailed ; then break; fi updateActiveFile "$file" done fi @@ -857,7 +996,7 @@ uninstallAllFiles () fi # uninstall the files - if [ ! -z $restoreFilesList ]; then + if [ ! -z "$restoreFilesList" ]; then logMessage "uninstalling files" local file for file in ${restoreFilesList[@]}; do @@ -874,9 +1013,10 @@ installAllServices () # get list of services in the package's service directory if [ -d "$servicesDir" ]; then servicesList=$( cd "$servicesDir"; ls -d * 2> /dev/null ) - if [ ! -z $servicesList ]; then + if [ ! -z "$servicesList" ]; then logMessage "installing services" for service in $servicesList ; do + if $installFailed; then break; fi installService $service done fi @@ -906,7 +1046,7 @@ uninstallAllServices () fi # uninstall services - if [ ! -z $servicesList ]; then + if [ ! -z "$servicesList" ]; then logMessage "uninstalling services" for service in $servicesList ; do if [ -z "$service" ]; then @@ -977,7 +1117,7 @@ restartGuiV2Service () endScript () { - if [ $scriptAction == 'INSTALL' ] ; then + if [ $scriptAction == 'INSTALL' ] && ! $installFailed ; then # do installs as indicated from caller while (( $# > 0 )); do case "$1" in @@ -994,25 +1134,25 @@ endScript () shift done - # assume that if we get this far, any command line opitons have already been set + # assume that if we get this far, any command line opitons have already been set touch "$setupOptionsDir/optionsSet" # clear flag preventing auto installs in PackageManager rm -f "$setupOptionsDir/DO_NOT_AUTO_INSTALL" - # if script needs to run again, installedVersionFile flag file is removed - # script should run again at boot time via reinstallMods - if $runAgain ; then - logMessage "script will run again at startup" - rm -f "$installedVersionFile" - # otherwise, installation is complete - update installedVersion - else - cp "$scriptDir/version" "$installedVersionFile" + # if script needs to run again, installedVersionFile flag file is removed + # script should run again at boot time via reinstallMods + if $runAgain ; then + logMessage "script will run again at startup" + rm -f "$installedVersionFile" + # otherwise, installation is complete - update installedVersion + else + cp "$scriptDir/version" "$installedVersionFile" fi # update rc.local to include call to reinstallMods # do only for SetupHelper since other packages are now installed by PackageManager - if ! $installFailed && [ "$packageName" == "SetupHelper" ]; then + if [ "$packageName" == "SetupHelper" ]; then if [ ! -f "$rcLocal" ]; then logMessage "creating $rcLocal" cp "$scriptDir/rcS.local" "$rcLocal" @@ -1031,9 +1171,10 @@ endScript () if [ $scriptAction == 'UNINSTALL' ] ; then - + if $installFailed ; then + logMessage "INSTALL failed - attempting UNINSTALL in endScript" # package was actually uninstalled (not an install failure) - set flag preventing auto installs - if ! $installFailed ; then + else touch "$setupOptionsDir/DO_NOT_AUTO_INSTALL" fi @@ -1055,27 +1196,20 @@ endScript () done # remove lines from rcS.local sed -i -e "/# SetupHelper reinstall/,/fi/d" "$rcLocal" - fi fi # setup script signals nothing to do - exit without further action without errors - if [ $scriptAction == 'EXIT' ]; then - exit $EXIT_SUCCESS - elif ! [ $scriptAction == 'INSTALL' ] && ! [ $scriptAction == 'UNINSTALL' ]; then - logMessage "unexpected script action $scriptAction - did not install or uninstall" - exit $EXIT_SUCCESS + if ! $installFailed && ! $uninstallFailed; then + if [ $scriptAction == 'EXIT' ]; then + exit $EXIT_SUCCESS + elif ! [ $scriptAction == 'INSTALL' ] && ! [ $scriptAction == 'UNINSTALL' ]; then + setInstallFailed $EXIT_ERROR "unexpected script action $scriptAction - did not install or uninstall" + fi fi - # remove temp directory used in installs of files requiring modificaion before installing - rm -rf "$patchedFiles" - - # if installation was attempted but failed, exit without checking anything else - # or signaling GUI restart or reboot - if $installFailed ; then - logMessage "installation failed - package has been uninstalled - exiting" - exit $installExitReason - elif $rebootNeeded ; then + # check for reboot or restarts + if $rebootNeeded ; then if $userInteraction ; then if yesNoPrompt "Reboot system now (y) or do it manually later (n): " ; then logMessage "rebooting ..." @@ -1107,9 +1241,13 @@ endScript () if yesNoPrompt "Restart the GUI now (y) or issue a do it manually later (n): " ; then logMessage "completed - restarting GUI" restartGuiV1Service - exit $EXIT_SUCCESS + if $installFailed || $uninstallFailed ; then + exit $installExitReason + else + exit $EXIT_SUCCESS + fi else - echo "GUI must be restarted to activate components" + echo "GUI must be restarted to activate changes" exit $EXIT_RESTART_GUI fi else @@ -1120,13 +1258,31 @@ endScript () else logMessage "completed - restarting GUI" restartGuiV1Service - exit $EXIT_SUCCESS + if $installFailed || $uninstallFailed ; then + exit $installExitReason + else + exit $EXIT_SUCCESS + fi fi fi fi - logMessage "completed" - exit $EXIT_SUCCESS -} + + # if installation was attempted but failed, exit without checking anything else + if $installFailed ; then + if [ $scriptAction == 'UNINSTALL' ]; then + logMessage "complete - package has been uninstalled" + else + logMessage "complete - no changes were made" + fi + exit $installExitReason + # install/uninstall succeeded + elif $uninstallFailed ; then + logMessage "complete - uninstall failed !!" + else + logMessage "complete - no errors" + exit $EXIT_SUCCESS + fi +} # endScript () ######## this code is executed in-line when CommonResources is sourced @@ -1155,18 +1311,6 @@ endScript () # It is set to false here the 'auto' parameter is passed on the command line # which indicates this script is NOT being run from the command line -# move old installedFlag ("...inInstalled...") -# to its new name ...installedVersionFile... -if [ ! -f "$installedVersionFile" ] && [ -f "$installedFlag" ]; then - installedVersion=$(cat "$installedFlag") - if [ -z $installedVersion ]; then - installedVersion="" - else - echo $installedVersion > "$installedVersionFile" - fi -fi -rm -f "$installedFlag" - # cleanup from previous versions - reinstallScriptsList no loner used rm -f "/data/reinstallScriptsList" @@ -1205,6 +1349,7 @@ force=false deferReboot=false deferGuiRestart=false userInteraction=true +runFromPm=false while [ $# -gt 0 ]; do case $1 in "reinstall") @@ -1229,56 +1374,27 @@ while [ $# -gt 0 ]; do logToConsole=false userInteraction=false ;; + "runFromPm") + runFromPm=true + logToConsole=false + userInteraction=false + deferReboot=true + deferGuiRestart=true + ;; + "check") + # if no other actions were set, set it here + # but allow other actions to override this one + if [ $scriptAction == 'NONE' ]; then + scriptAction='CHECK' + fi + ;; *) esac shift done # do after logToConsole is enabled/disabled abvove -logMessage "--- starting setup script $packageVersion" - -# make sure rootfs is mounted R/W & and resized to allow space for replacement files -# arbitrary minimum size of 3 MB -rootMinimumSize=3 -availableSpace=$(df -m / | tail -1 | awk '{print $4}') - -# remount read-write -if (( $(mount | grep ' / ' | grep -c 'rw') == 0 )); then - # only remount read-write for CCGX - if [ "$machine" == "ccgx" ]; then - if [ -f /opt/victronenergy/swupdate-scripts/remount-rw.sh ]; then - logMessage "remounting root read-write" - /opt/victronenergy/swupdate-scripts/remount-rw.sh - fi - # remount and resize for other platforms - elif [ -f /opt/victronenergy/swupdate-scripts/resize2fs.sh ]; then - /opt/victronenergy/swupdate-scripts/resize2fs.sh - availableSpace=$(df -m / | tail -1 | awk '{print $4}') - logMessage "remounting read-write root and resizing - $availableSpace MB now available" - fi - # check to see if remount was successful - if (( $(mount | grep ' / ' | grep -c 'rw') == 0 )); then - logMessage "ERROR: unable to remount root read-write - can't continue" - exit $EXIT_ROOT_FULL - fi -# root already read-write, attempt to resize if space is limited (CCGX can't resize) -elif (( $availableSpace < $rootMinimumSize )); then - if [ "$machine" == "ccgx" ]; then - logMessage "can't resize root on CCGX" - else - if [ -f /opt/victronenergy/swupdate-scripts/resize2fs.sh ]; then - /opt/victronenergy/swupdate-scripts/resize2fs.sh - availableSpace=$(df -m / | tail -1 | awk '{print $4}') - logMessage "resized root - $availableSpace MB now available" - fi - fi -fi -# make sure the root partition has space for the package -if (( $availableSpace < $rootMinimumSize )); then - logMessage "no room for modified files on root ($availableSpace MB remaining) - can't continue" - exit $EXIT_ROOT_FULL -fi - +logMessage "--- starting setup script $packageVersion action $scriptAction" # packages that require options to proceed unattended # must include the optionsRequried flag file in their package directory @@ -1313,7 +1429,6 @@ else optionsSet=true fi - # called from reinstallMods at boot time if $reinstall ; then runningAtBoot=true @@ -1338,49 +1453,63 @@ else pruneSetupLogFile fi +if [ ! -d "$setupOptionsDir" ]; then + logMessage "creating package options directory $setupOptionsDir" + mkdir -p $setupOptionsDir +fi + # initialze integer version number for venus version -# used below and in _checkFileSets +# used below and in checkFileSets versionStringToNumber $venusVersion venusVersionNumber=$versionNumber -# prevent installing Raspberry Pi packages on other platforms -if [ -f "$scriptDir/raspberryPiOnly" ]; then - if [[ $machine != *"raspberrypi"* ]]; then - setInstallFailed $EXIT_INCOMPATIBLE_PLATFORM "$packageName not compatible with $machine" - fi -fi +# flag the version that is performing these checks +# this is used by PackageManager to know when to run checks +echo "$venusVersion" > "$scriptDir/packageCheckVersion" -# check to see if package is compatible with this Venus version -if [ -f "$scriptDir/firstCompatibleVersion" ]; then - firstCompatibleVersion=$(cat "$scriptDir/firstCompatibleVersion") -# no first compatible version specified - use the default -else - firstCompatibleVersion='v2.71' -fi +getFileLists "$pkgFileSets" -versionStringToNumber $firstCompatibleVersion -firstCompatibleVersionNumber=$versionNumber -if (( $venusVersionNumber < $firstCompatibleVersionNumber )); then - setInstallFailed $EXIT_INCOMPATIBLE_VERSION "$venusVersion before first compatible $firstCompatibleVersion" -elif [ -f "$scriptDir/obsoleteVersion" ]; then - obsoleteVersion=$(cat "$scriptDir/obsoleteVersion") - versionStringToNumber $obsoleteVersion - obsoleteVersionNumber=$versionNumber - if (( $venusVersionNumber >= $obsoleteVersionNumber )); then - setInstallFailed $EXIT_INCOMPATIBLE_VERSION "$venusVersion after last compatible $obsoleteVersion" - fi -fi -if ! $installFailed ; then - if [ ! -d "$setupOptionsDir" ]; then - logMessage "creating package options directory $setupOptionsDir" - mkdir -p $setupOptionsDir - fi +# create temporary directory for temporary install/uninstall files (unique temp directory in volatile storage) +# updateActiveFile always checks this location first for a replacement before checking file sets +# tempFileDir is removed in the exit trap above but it is in volatile storage so will be removed on boot anyway +tempFileDir=$( mktemp -d ) + +# patch files previously used to patch a file are stored in setupOptions +# so they survive a firmware update or package update +previousPatchesDir="$setupOptionsDir/previousPatches" +if ! [ -e "$previousPatchesDir" ]; then + mkdir -p "$previousPatchesDir" fi -# if checks above passed and uninstall was not specified on command line, -# do final checks before permitting install +# do install pre-checks - skip if uninstalling if [ $scriptAction != 'UNINSTALL' ]; then + # prevent installing Raspberry Pi packages on other platforms + if [ -f "$scriptDir/raspberryPiOnly" ]; then + if [[ $machine != *"raspberrypi"* ]]; then + setInstallFailed $EXIT_INCOMPATIBLE_PLATFORM "$packageName not compatible with $machine" + fi + fi + # check to see if package is compatible with this Venus version + if [ -f "$scriptDir/firstCompatibleVersion" ]; then + firstCompatibleVersion=$(cat "$scriptDir/firstCompatibleVersion") + # no first compatible version specified - use the default + else + firstCompatibleVersion='v2.71' + fi + versionStringToNumber $firstCompatibleVersion + firstCompatibleVersionNumber=$versionNumber + if (( $venusVersionNumber < $firstCompatibleVersionNumber )); then + setInstallFailed $EXIT_INCOMPATIBLE_VERSION "$venusVersion before first compatible $firstCompatibleVersion" + elif [ -f "$scriptDir/obsoleteVersion" ]; then + obsoleteVersion=$(cat "$scriptDir/obsoleteVersion") + versionStringToNumber $obsoleteVersion + obsoleteVersionNumber=$versionNumber + if (( $venusVersionNumber >= $obsoleteVersionNumber )); then + setInstallFailed $EXIT_INCOMPATIBLE_VERSION "$venusVersion after last compatible $obsoleteVersion" + fi + fi + # determine if GUI v1 is installed # Note, it may NOT be running or selected to run!!!! if [ ! -d "/opt/victronenergy/gui" ]; then @@ -1388,7 +1517,6 @@ if [ $scriptAction != 'UNINSTALL' ]; then else guiV1present=true fi - # block installs if any GUI files would be modified and GUI v1 is not present # packages can bypass GUI v1 checks and allow installs even if package contains them if [ -f "$scriptDir/GUI_V1_NOT_REQUIRED" ]; then @@ -1402,34 +1530,29 @@ if [ $scriptAction != 'UNINSTALL' ]; then else guiV1required=false fi - if ! $guiV1present && $guiV1required ; then setInstallFailed $EXIT_NO_GUI_V1 "$packageName requires GUI v1" fi # attempting an install without the comand line prompting # and needed options have not been set yet - can't continue - if [ $scriptAction == 'INSTALL' ]; then + if ! $installFailed && [ $scriptAction == 'INSTALL' ]; then if ! $optionsSet ; then setInstallFailed $EXIT_OPTIONS_NOT_SET "required options have not been set" - endScript fi fi - checkPackageDependencies - - getFileLists "$pkgFileSets" + checkFileSets - _checkFileSets - - - # create installed files (and services) directory - if [ ! -d "$installedFilesDir" ]; then - mkdir "$installedFilesDir" + # checkFileSets created a missing file set and set the INCOMPLETE flag if needed + # that is all CHECK needed to do so EXIT HERE !!!! + if [ $scriptAction == 'CHECK' ]; then + if [ -f "$fileSet/INCOMPLETE" ]; then + exit $EXIT_FILE_SET_ERROR + fi fi - # location of patch output - used as the replacement file (unique temp directory in volatile storage) - patchedFiles=$( mktemp -d ) + checkPackageDependencies # create patched files for files with VisibleItemModel for older Venus OS versions versionStringToNumber "v3.00~14" @@ -1441,41 +1564,179 @@ if [ $scriptAction != 'UNINSTALL' ]; then sourceFile="$versionIndependentFileSet/$baseName" if ! [ -f "$sourceFile" ]; then continue; fi if (( $(grep -c "VisibleItemModel" "$sourceFile") == 0 )); then continue; fi - sed -e 's/VisibleItemModel/VisualItemModel/' "$sourceFile" > "$patchedFiles/$baseName" + sed -e 's/VisibleItemModel/VisualItemModel/' "$sourceFile" > "$tempFileDir/$baseName" done fi +fi # if [ $scriptAction != 'UNINSTALL' ] + +# create the forward and reverse patched files +# used during the actual install and to test if the patch/reverse patch will succeed +# done here so PackageManager knows if this will be possible before starting the opeartion! +# +# BusyBox patch doesn't support the -o option +# so copy orignals to the patched file locaiton first then patch the copy - # create patched files in fileListPatched +if ! [ -z "$fileListPatched" ];then + patchErrors=() for file in ${fileListPatched[@]}; do baseName=$( basename $file ) - patchFile="$patchSourceDir/$baseName.patch" - if ! [ -f "$file" ]; then - setInstallFailed $EXIT_FILE_SET_ERROR "original file missing for $baseName" - endScript - fi - if ! [ -f "$patchFile" ]; then - setInstallFailed $EXIT_FILE_SET_ERROR "patch file missing for $baseName" - endScript + tempActiveFile="$tempFileDir/$baseName" + if [ -e "$file" ] ; then + previousPatchFile="$previousPatchesDir/$baseName.patch" + cp "$file" "$tempActiveFile" + + # remove a previous patch for this package + # if this succeeds proceed with forward patch on temp file + useTempActiveFile=false + if [ -e "$previousPatchFile" ] && [ -e "$file.package" ] \ + && (( $( grep -c $packageName "$file.package" ) > 0 )); then + if yes 'no' | patch -R "$tempActiveFile" "$previousPatchFile" &> /dev/null ; then + useTempActiveFile=false + else + rm "$previousPatchFile" + fi + fi + + # attempt to patch the active file with any file ending in .patch + # the first one that successfully creates a forward AND reverse patch is used + forwardPatched="$tempFileDir/$baseName".patchedForInstall + + patchOk=false + reversePatchTest="$tempFileDir/$baseName.reversePatchTest" + + patchFiles=( $( ls "$patchSourceDir/$baseName"*.patch ) ) + for patchFile in ${patchFiles[@]};do + # if this package is still installed and it's modificaitons + # could be removed from the active file, then patch that + if $useTempActiveFile ; then + cp "$tempActiveFile" "$forwardPatched" + # otherwise start with the active file itself + else + cp "$file" "$forwardPatched" + fi + if yes 'no' | patch -N "$forwardPatched" "$patchFile" > /dev/null ; then + # forward patch succeeded - test reverse patch (both must succeed) + cp "$forwardPatched" "$reversePatchTest" + if yes 'no' | patch -R "$reversePatchTest" "$patchFile" > /dev/null ; then + patchOk=true + fi + fi + done + currentPatchFile="$tempFileDir/$baseName.currentPatch" + if $patchOk ; then + # save this so patch file used for install can be saved for evenutal uninstall + # or to reverse patch prior to reinstall + cp "$patchFile" "$currentPatchFile" + else + patchErrors+=( "patch unsuccesful for $baseName" ) + rm -r "$forwardPatched" + rm -f "$currentPatchFile" + fi + rm -f "$reversePatched" "$reversePatchTest" + else + patchErrors+=( "no original for $baseName patch" ) + continue fi - # BusyBox patch doesn't support the -o option so copy source to output first - # then patch the output - # if package already installed, patch .orig - if [ -e "$file.orig" ]; then - cp "$file.orig" "$patchedFiles/$baseName" - # if package probably not installed, patch the active file - elif [ -e "$file" ] ; then - cp "$file" "$patchedFiles/$baseName" + done # for file + + # save errors in patchErrors file + if ! [ -z "$patchErrors" ] ; then + rm -f "$scriptDir/patchErrors" + for patchError in "${patchErrors[@]}"; do + logMessage "$patchError" + echo "$patchError" >> "$scriptDir/patchErrors" + done + # script will exit since we are still in pre-checks !! + setInstallFailed $EXIT_PATCH_ERROR "patch error details were saved in $packageName/patchErrors" + if [ $scriptAction == 'CHECK' ]; then + exit $EXIT_PATCH_ERROR else - setInstallFailed $EXIT_FILE_SET_ERROR "no source for $baseName patch" endScript fi - if ! patch "$patchedFiles/$baseName" "$patchFile" &> /dev/null ; then - setInstallFailed $EXIT_FILE_SET_ERROR "could not patch $baseName" - endScript + # no errors - remove the error history + else + rm -f "$scriptDir/patchErrors" + fi +fi # if fileListPatched + +# go no further if just checking +if [ $scriptAction == 'CHECK' ]; then + exit $EXIT_SUCCESS +fi + +# make sure rootfs is mounted R/W & and resized to allow space for replacement files +# arbitrary minimum size of 3 MB +if ! $installFailed; then + rootMinimumSize=3 + availableSpace=$(df -m / | tail -1 | awk '{print $4}') + + # remount read-write + if (( $(mount | grep ' / ' | grep -c 'rw') == 0 )); then + # only remount read-write for CCGX + if [ "$machine" == "ccgx" ]; then + if [ -f /opt/victronenergy/swupdate-scripts/remount-rw.sh ]; then + logMessage "remounting root read-write" + /opt/victronenergy/swupdate-scripts/remount-rw.sh + fi + # remount and resize for other platforms + elif [ -f /opt/victronenergy/swupdate-scripts/resize2fs.sh ]; then + /opt/victronenergy/swupdate-scripts/resize2fs.sh + availableSpace=$(df -m / | tail -1 | awk '{print $4}') + logMessage "remounting read-write root and resizing - $availableSpace MB now available" fi - done + # check to see if remount was successful + if (( $(mount | grep ' / ' | grep -c 'rw') == 0 )); then + setInstallFailed $EXIT_ROOT_FULL "ERROR: unable to remount root read-write - can't continue" + fi + # root already read-write, attempt to resize if space is limited (CCGX can't resize) + elif (( $availableSpace < $rootMinimumSize )); then + if [ "$machine" == "ccgx" ]; then + logMessage "can't resize root on CCGX" + else + if [ -f /opt/victronenergy/swupdate-scripts/resize2fs.sh ]; then + /opt/victronenergy/swupdate-scripts/resize2fs.sh + availableSpace=$(df -m / | tail -1 | awk '{print $4}') + logMessage "resized root - $availableSpace MB now available" + fi + fi + fi +fi +if ! $installFailed; then + # make sure the root partition has space for the package + if (( $availableSpace < $rootMinimumSize )); then + setInstallFailed $EXIT_ROOT_FULL "no room for modified files on root ($availableSpace MB remaining) - can't continue" + fi +fi + + +# done with pre checks +# prior to this no system mofications have been made +# after this system modifications may occur + +if $installFailed ; then + if ! $userInteraction ; then + logMessage "ERROR: errors occured during pre-checks - can't continue" + # EXIT HERE if errors occured during pre-checks while running unattended !!!! + # the LAST install failure reported to setInstallFailed is used as the exit code + exit $installExitReason # EXIT HERE !!!! + # command line install request failed - reset scriptAction to NONE + # so prompts will be shown - eg + # to show the log or + # to trigger a manual uninstall + elif [ $scriptAction == 'INSTALL' ]; then + logMessage "ERROR: install failed during pre-checks - select another action" + scriptAction='NONE' + fi +fi + +# create installed files (and services) directory +if [ ! -d "$installedFilesDir" ]; then + mkdir "$installedFilesDir" fi +installPreChecks=false + + #### do standard prompting, automatic install/uninstall then exit if [ "$standardPromptAndActions" == 'yes' ]; then # prompt only if action hasn't been set yet (from command line) @@ -1488,6 +1749,3 @@ fi # otherwise continue with the setup script #### continue executing the setup script which sourced this file - - - diff --git a/HelperResources/EssentialResources b/HelperResources/EssentialResources index aadb94c..585790a 100755 --- a/HelperResources/EssentialResources +++ b/HelperResources/EssentialResources @@ -63,6 +63,7 @@ EXIT_ROOT_FULL=249 EXIT_DATA_FULL=248 EXIT_NO_GUI_V1=247 EXIT_PACKAGE_CONFLICT=246 +EXIT_PATCH_ERROR=245 # old variables - keep for compatibility diff --git a/HelperResources/ServiceResources b/HelperResources/ServiceResources index 1512bcf..9891297 100755 --- a/HelperResources/ServiceResources +++ b/HelperResources/ServiceResources @@ -112,7 +112,7 @@ removeService () svc -d "/service/$1/log" fi - # supervise processes hang around after removing the service so save info and kill them after removal + # supervise processes may hang around after removing the service so save info and kill them after removal pids="" while read -u 9 line; do read s uid pid ppid vsz rss tty stime time cmd blah <<< "$line" @@ -135,7 +135,9 @@ removeService () fi # now kill the supervise processes - kill $pids + if ! [ -z $pids ]; then + kill $pids + fi fi # remove service from installed services list @@ -264,8 +266,13 @@ installService () fi fi if serviceIsUp $serviceName ; then - logMessage "restarting $serviceName service" - svc -t "/service/$serviceName" + if $runFromPm && [ $serviceName == 'PackageManager' ]; then + logMessage "$serviceName restart deferred until GUI restart" + restartGui=true + else + logMessage "restarting $serviceName service" + svc -t "/service/$serviceName" + fi fi fi # log needs to be handled separtely including a restart diff --git a/HelperResources/version b/HelperResources/version index 7408476..f2302e4 100644 --- a/HelperResources/version +++ b/HelperResources/version @@ -1 +1 @@ -v6.12 +v8.0~2 diff --git a/ReadMe b/ReadMe index e10a664..d50d7fa 100644 --- a/ReadMe +++ b/ReadMe @@ -17,7 +17,7 @@ and the remaining have pull DOWNs. This makes some digital input pins behave dif This script installs a DT overlay that switches to pull UPs for all digital input pins -Only the relay 1 can be assigned to a function: alarm, genertor start/stop or pump. +Only the relay 1 can be assigned to a function: alarm, generator start/stop or pump. In addition, relay 2 can be assigned to temperature alarm The remaining 4 relays are only provided manual on/off control from the menu. @@ -35,22 +35,30 @@ You must provide isolation for the digital inputs to avoid damage to the CPU chi Venus OS does not provide native support for i2c relay boards and this package does not add any. -This script should be run manually initally. -It will then called from reinstallMods to reinstall functionality after a Venus update +This script will accept default options when run from PackagManager. + + +This script will select default options when run from PackageManager. +This may not be appropirate. See section below on GPIO conflicts: +The script MUST be run from the command line to set options. +After that, those options will be used when installing via PackageManager, +including automatic reinstall following a firmware update. GPIO conflicts: GPIO assignments for relays 5 and 6 may cause conflicts with hat board interrupts. -This conflict may cause the system to not boot properly or be extremely sluggish. +This conflict may cause the system to not boot or be extremely sluggish. This script allows for two assignments for relays 5 and 6. gpio_list is the legacy one: GPIO 23 and 24, respectively -gpio_listForCanHats provides compatibility with at least the two Waveshare CANbus dual channel hats - GPIOs 12 and 20 are used for relays 5 and 6, respectively - -An option to select the legady or compatible set is offered during manual setup. -However, this optoin is considered optional and installation with the legacy set -is allowed even if the setup script is not run manually first. +gpio_listForCanHats provides compatibility with + Waveshare CANbus dual channel hats (and possibly others) + GPIOs 2, 12 and 4 are used for relays 1. 5 and 6, respectively + GPIO 3 is used for digital input 4 + However, i2c is disabled since it uses GPIO 2 and 3 ! + +An option to select the legacy or compatible set is offered +when running setup from the command line. Custom GPIO list: diff --git a/changes b/changes index a174982..fba0459 100644 --- a/changes +++ b/changes @@ -1,3 +1,7 @@ +v4.8: + switched to using patch for some files + fixed typo in ReadMe + v4.7: removed spi1-1cs.dtbo - unused, and confilcts with VeCanSetup diff --git a/version b/version index d0c01d6..1d73516 100644 --- a/version +++ b/version @@ -1 +1 @@ -v4.7 +v4.8