changer l'environnement d'un processus en cours


18

Comment pourrait-il être possible de modifier une variable dans envun processus déjà en cours, par exemple via /proc/PID/environ?Ce "fichier" read-only.

Vous devez modifier ou annuler la variable DISPLAY d'un travail par lots de longue durée sans la tuer.


3
Il est trop tard maintenant, mais pour référence future, cela xprapourrait être intéressant.
sr_

xprasemble utile. Normalement, je redirige vers des affichages non-utilisateurs hébergés par Xvfbou Xephyr, mais aujourd'hui, j'ai oublié et exécuté depuis cli plutôt que cron / at pour dépanner la sortie, donc cela m'a ennuyé à:0
Marcos

Réponses:


19

Vous ne pouvez pas faire cela sans un méchant piratage - il n'y a pas d'API pour cela, aucun moyen d'aviser le processus que son environnement a changé (car ce n'est pas vraiment possible de toute façon).
Même si vous parvenez à le faire, il n'y a aucun moyen d'être sûr que cela aura un effet - le processus pourrait très bien avoir mis en cache la variable d'environnement que vous essayez de piquer (car rien n'est censé pouvoir le changer ).

Si vous voulez vraiment le faire et êtes prêt à ramasser les morceaux si les choses tournent mal, vous pouvez utiliser un débogueur. Voir par exemple cette question Stack Overflow:
existe-t-il un moyen de modifier les variables d'environnement d'un autre processus?

Essentiellement:

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

Les autres fonctions possibles que vous pourriez essayer d'appeler sont setenvou unsetenv.

Veuillez garder à l'esprit que cela peut ne pas fonctionner ou avoir des conséquences désastreuses si le processus que vous ciblez fait des choses "intéressantes" avec son bloc d'environnement. Testez-le d'abord sur des processus non critiques, mais assurez-vous que ces processus de test reflètent aussi étroitement que possible celui que vous essayez de pousser.


3
Oui, je me rends compte que c'est un peu un hack, risqué et non garanti pour les raisons que vous avez mentionnées. (Une partie de la raison pour laquelle je visite ce groupe est pour de tels besoins non conventionnels que je n'arrive pas à trouver normalement.) Dans ce cas, régler DISPLAY sur junk ou vide résout simplement une gêne et un retard (captures d'écran fréquentes inutiles sur le réseau, très bien si ils échouent). Étant donné que l'enfant copie le parent, je n'ai besoin que de modifier le parent env. De nombreux nouveaux processus enfants et sous-enfants commencent à apparaître et se terminent rapidement dans mon travail par lots; ces questions. J'ai pensé qu'un débogueur pourrait faire cela, merci - je pourrais envelopper cela dans une fonction shell.
Marcos

0

Il n'est pas nécessaire de le faire si un travail par lots peut lire à partir d'un système de fichiers pour récupérer une modification. Exécutez simplement un travail avec le chemin vers un répertoire unique temporaire et passez le même chemin au script shell enfant. Le script verrouille un fichier dans ce répertoire et écrit un fichier avec de nouvelles valeurs près du fichier de verrouillage. Un script de travail verrouille de temps en temps le même fichier, analyse et lit les modifications du fichier de valeurs. Pour savoir comment verrouiller le shell Unix, il suffit de rechercher unix shell lock fileou bash lock file, il existe déjà de nombreuses solutions pour cela.

Bénéfices de cette solution:

  • portable entre presque n'importe quel OS comme Windows ou Unix
  • pas besoin d'écrire et de dupliquer des analyseurs complexes pour chaque interprète (unix / windows / etc) pour relire les valeurs du fichier tant que le fichier de valeurs reste simple

Problèmes de mise en œuvre ci-dessous:

  • L'implémentation repose sur un verrouillage de fichier dans une phase de redirection de shell ( flocksous Linux pour obtenir un effet d'exclusion, sous Windows a une exclusion intégrée)
  • Chaque valeur pour une variable est une valeur de ligne unique (pas une multiligne)

L'implémentation est stockée ici: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools

La bashmise en œuvre:

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"

La même chose sous Windows (comme exemple de portabilité):

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

Pour écrire les fichiers, verrouillez de la même manière votre code.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.