Umgebung eines laufenden Prozesses ändern

18

Wie könnte es möglich sein, eine Variable in enveinem bereits laufenden Prozess zu ändern , zum Beispiel über /proc/PID/environ?Diese "Datei" read-only.

Sie müssen die DISPLAY-Variable eines Batch-Jobs mit langer Laufzeit ändern oder deaktivieren, ohne ihn zu beenden.

Marcos
quelle
3
Es ist jetzt zu spät, aber für eine spätere Bezugnahme xprakönnte es interessant sein.
Sr_
xpraklingt nützlich. Normalerweise ich umleiten zu nicht-User - Displays gehostet von Xvfboder Xephyr, aber heute habe ich vergessen und lief von cli statt cron / at zu beheben Ausgang, so ist es bei mir lästig gewesen:0
Marcos

Antworten:

19

Sie können dies nicht ohne böse Hacks tun - es gibt keine API dafür, keine Möglichkeit, den Prozess zu benachrichtigen, dass sich seine Umgebung geändert hat (da dies sowieso nicht wirklich möglich ist).
Selbst wenn Sie dies schaffen, können Sie nicht sicher sein, ob dies Auswirkungen hat - der Prozess hätte die Umgebungsvariable, die Sie anstoßen möchten, sehr gut zwischengespeichert (da nichts sie ändern kann) ).

Wenn Sie dies wirklich tun möchten und bereit sind, die Teile abzuholen, wenn etwas schief geht, können Sie einen Debugger verwenden. Siehe zum Beispiel diese Stapelüberlauf-Frage:
Gibt es eine Möglichkeit, die Umgebungsvariablen eines anderen Prozesses zu ändern?

Im Wesentlichen:

(gdb) attach process_id
(gdb) call putenv ("DISPLAY=your.new:value")
(gdb) detach

Andere mögliche Funktionen, die Sie aufrufen möchten, sind setenvoder unsetenv.

Bitte denken Sie wirklich daran, dass dies möglicherweise nicht funktioniert oder schwerwiegende Konsequenzen hat, wenn der Prozess, den Sie anvisieren, "interessante" Dinge mit seinem Umgebungsblock tut. Testen Sie es zunächst an unkritischen Prozessen, aber stellen Sie sicher, dass diese Testprozesse dem entsprechen, den Sie anstreben.

Matte
quelle
3
Ja, mir ist klar, dass es ein bisschen hacken, riskant und aus den von Ihnen genannten Gründen nicht garantiert ist. (Ein Teil des Grundes, warum ich diese Gruppe besuche, ist für solche nicht konventionellen Bedürfnisse, die ich normalerweise nicht zu finden scheine.) In diesem Fall behebt die Einstellung von DISPLAY auf Junk oder Empty lediglich einen Ärger und eine Verzögerung (unnötig häufige Screenshots über das Netzwerk, in Ordnung, wenn Sie versagen). Da Kind Eltern kopiert, muss ich nur die Elternumgebung modifizieren. Viele neue Child & Subchild-Prozesse entstehen und werden in meinem Batch-Job schnell beendet. diese Angelegenheit. Ich dachte, ein Debugger könnte das tun, danke - ich könnte das in eine Shell-Funktion umschließen.
Marcos
0

Dies ist nicht erforderlich, wenn ein Stapeljob aus einem Dateisystem lesen kann, um eine Änderung abzurufen. Führen Sie einfach einen Job mit einem Pfad zu einem temporären eindeutigen Verzeichnis aus und übergeben Sie den gleichen Pfad an das untergeordnete Shell-Skript. Das Skript sperrt eine Datei in diesem Verzeichnis und schreibt eine Datei mit neuen Werten in die Nähe der Sperrdatei. Von Zeit zu Zeit sperrt ein Jobskript dieselbe Datei, analysiert und liest Änderungen aus der Wertedatei zurück. Um herauszufinden, wie Sie eine Sperre in der Unix-Shell erstellen können, suchen Sie einfach nach unix shell lock fileoder bash lock file, dafür gibt es bereits zahlreiche Lösungen.

Vorteile dieser Lösung:

  • portabel zwischen fast jedem Betriebssystem wie Windows oder Unix
  • Es ist nicht erforderlich, komplexe Parser für jeden Interpreter (Unix / Windows / usw.) zu schreiben und zu duplizieren, um Werte aus der Datei zurückzulesen, solange die Wertedatei einfach bleibt

Probleme bei der Implementierung unten:

  • Die Implementierung basiert auf einer Dateisperre in einer Shell-Umleitungsphase ( flockunter Linux wird ein Ausschlusseffekt erzielt, unter Windows ist ein Ausschluss integriert).
  • Jeder Wert für eine Variable ist ein einzeiliger Wert (kein mehrzeiliger Wert).

Die Implementierung wird hier gespeichert: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools

Die bashUmsetzung:

set_vars_from_locked_file_pair.sh

#!/bin/bash

# Another variant of a configuration file variables read and set script.
# The script must stay as simple as possible, so for this task it uses these parameters:
# 1. path where to lock a lock file
# 2. path where to read a file with variable names (each per line)
# 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

# Script can be ONLY included by "source" command.
if [[ -n "$BASH" && (-z "$BASH_LINENO" || ${BASH_LINENO[0]} -gt 0) ]]; then 

function set_vars_from_locked_file_pair()
{
  # the lock file directory must already exist
  if [[ ! -d "${1%[/\\]*}" ]]; then
    echo "$0: error: lock file directory does not exist: \`${1%[/\\]*}\`" >&2
    return 1
  fi

  if [[ ! -f "${2//\\//}" ]]; then
    echo "$0: error: variable names file does not exist: \`$2\`" >&2
    return 2
  fi

  if [[ ! -f "${3//\\//}" ]]; then
    echo "$0: error: variable values file does not exist: \`$3\`" >&2
    return 3
  fi

  function LocalMain()
  {
    # open file for direct reading by the `read` in the same shell process
    exec 7< "$2"
    exec 8< "$3"

    # cleanup on return
    trap "rm -f \"$1\" 2> /dev/null; exec 8>&-; exec 7>&-; trap - RETURN" RETURN

    local __VarName
    local __VarValue

    # shared acquire of the lock file
    while :; do
      # lock via redirection to file
      {
        flock -s 9

        # simultaneous iteration over 2 lists in the same time
        while read -r -u 7 __VarName; do
          read -r -u 8 __VarValue
          # drop line returns
          __VarName="${__VarName//[$'\r\n']}"
          __VarValue="${__VarValue//[$'\r\n']}"
          # instead of `declare -gx` because `-g` is introduced only in `bash-4.2-alpha`
          export $__VarName="$__VarValue"
          (( ${4:-0} )) && echo "$__VarName=\`$__VarValue\`"
        done

        break

        # return with previous code
      } 9> "$1" 2> /dev/null # has exclusive lock been acquired?

      # busy wait
      sleep 0.02
    done
  }

  LocalMain "${1//\\//}" "${2//\\//}" "${3//\\//}" "${4:-0}"
}

fi

testlock.sh

#!/bin/bash

{
  flock -x 9 2> /dev/null
  read -n1 -r -p "Press any key to continue..."
  echo >&2
} 9> "lock"

Dasselbe unter Windows (als Beispiel für Portabilität):

set_vars_from_locked_file_pair.bat

@echo off

rem Another variant of a configuration file variables read and set script.
rem The script must stay as simple as possible, so for this task it uses these parameters:
rem 1. path where to lock a lock file
rem 2. path where to read a file with variable names (each per line)
rem 3. path where to read a file with variable values (each per line, must be the same quantity of lines with the variable names file)

rem disable alternative variables expansion to avoid `!` character consumption
setlocal DISABLEDELAYEDEXPANSION

set "FILE_LOCK_PATH=%~1"
set "FILE_VAR_NAMES_PATH=%~2"
set "FILE_VAR_VALUES_PATH=%~3"
set "PRINT_VARS_SET=%~4"

set "FILE_LOCK_DIR=%~d1"

rem the lock file directory must already exist
if not exist "%FILE_LOCK_DIR%" (
  echo.%~nx0: error: FILE_LOCK_DIR does not exist: "%FILE_LOCK_DIR%"
  exit /b 1
) >&2

if not exist "%FILE_VAR_NAMES_PATH%" (
  echo.%~nx0: error: FILE_VAR_NAMES_PATH does not exist: "%FILE_VAR_NAMES_PATH%"
  exit /b 2
) >&2

if not exist "%FILE_VAR_VALUES_PATH%" (
  echo.%~nx0: error: FILE_VAR_VALUES_PATH does not exist: "%FILE_VAR_VALUES_PATH%"
  exit /b 3
) >&2

rem The endlocal works only in the same call context
endlocal

rem exclusive acquire of the lock file
:REPEAT_LOCK_LOOP

(
  (
    rem if lock is acquired, then we are in...
    call :MAIN "%%~2" "%%~3" "%%~4"
    call set "LASTERROR=%%ERRORLEVEL%%"

    rem exit with return code from the MAIN
  ) 9> "%~1" && (del /F /Q /A:-D "%~1" & goto EXIT)
) 2>nul

rem Busy wait: with external call significantly reduces CPU consumption while in a waiting state
pathping localhost -n -q 1 -p 20 >nul 2>&1
goto REPEAT_LOCK_LOOP

:EXIT
exit /b %LASTERROR%

:MAIN
rem drop last error
type nul>nul

if %~30 NEQ 0 goto SET_WITH_PRINT

rem trick with simultaneous iteration over 2 lists in the same time
(
  for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
    set /p "%%i="
  )
) < "%~2"

exit /b 0

:SET_WITH_PRINT
rem trick with simultaneous iteration over 2 lists in the same time
(
  for /f "usebackq eol=# tokens=* delims=" %%i in ("%~1") do (
    set /p "%%i="
    rem to filter out wrong matches of a variable from the `set "%%i"`
    for /f "usebackq eol=# tokens=1,* delims==" %%j in (`set "%%i"`) do if /i "%%j" == "%%i" echo.%%i=%%k
  )
) < "%~2"

exit /b 0

testlock.bat

@echo off

(
  pause
) 9> ./lock

Um die Dateien zu schreiben, sperren Sie auf die gleiche Weise Ihren Code.

Andry
quelle