cambia l'ambiente di un processo in esecuzione


18

Come potrebbe essere possibile modificare alcune variabili envdi un processo già in esecuzione, ad esempio tramite /proc/PID/environ?Quel "file" è read-only.

È necessario modificare o annullare l'impostazione della variabile DISPLAY di un processo batch di lunga durata senza interromperlo.


3
Adesso è troppo tardi, ma per riferimento futuro, xprapotrebbe essere interessante.
sr_

xprasembra utile. Normalmente reindirizzo ai display non utente ospitati da Xvfbo Xephyr, ma oggi ho dimenticato ed eseguito da cli piuttosto che cron / at per risolvere l'output, quindi mi ha infastidito a:0
Marcos

Risposte:


19

Non puoi farlo senza un brutto trucco - non c'è API per questo, non c'è modo di notificare al processo che il suo ambiente è cambiato (dal momento che non è davvero possibile comunque).
Anche se riesci a farlo, non c'è modo di essere sicuro che avrà alcun effetto: il processo potrebbe benissimo aver memorizzato nella cache la variabile d'ambiente che stai cercando di colpire (dal momento che nulla dovrebbe essere in grado di cambiarlo ).

Se vuoi davvero farlo e sei pronto a raccogliere i pezzi se le cose vanno male, puoi usare un debugger. Vedi ad esempio questa domanda di overflow dello stack:
esiste un modo per modificare le variabili di ambiente di un altro processo?

Essenzialmente:

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

Altre possibili funzioni che potresti provare a chiamare sono setenvo unsetenv.

Ti preghiamo di tenere presente che questo potrebbe non funzionare o avere conseguenze disastrose se il processo che scegli come target fa cose "interessanti" con il suo blocco ambientale. Provalo prima su processi non critici, ma assicurati che questi processi di test rispecchino il più vicino possibile a quello che stai cercando di colpire.


3
Sì, mi rendo conto che è un po 'un hack, rischioso e non garantito per i motivi che hai citato. (Parte del motivo per cui visito questo gruppo è per esigenze non convenzionali che non riesco a trovare normalmente.) In questo caso, impostare DISPLAY su junk o vuoto risolve semplicemente un fastidio e un ritardo (schermate frequenti non necessarie sulla rete, bene se falliscono). Dato che il bambino copia il genitore, ho solo bisogno di modificare il gen env. Molti nuovi processi secondari e secondari vengono generati e terminano rapidamente nel mio lavoro batch; quelli contano. Ho pensato che un debugger potesse farlo, grazie - avrei potuto inserirlo in una funzione shell.
Marcos,

0

Non è necessario farlo se un processo batch può leggere da un file system per recuperare una modifica. Basta eseguire un lavoro con il percorso in una directory univoca temporanea e passare lo stesso percorso allo script della shell figlio. Lo script bloccherà un file in quella directory e scriverà un file con nuovi valori vicino al file di blocco. Uno script di lavoro di volta in volta bloccherà lo stesso file, analizzerà e rileggerà le modifiche dal file dei valori. Per scoprire come creare un blocco nella shell unix basta cercare unix shell lock fileo bash lock file, esistono già molte soluzioni per questo.

Vantaggi di questa soluzione:

  • portatile tra quasi tutti i sistemi operativi come Windows o Unix
  • non è necessario scrivere e duplicare parser complessi per ciascun interprete (unix / windows / ecc.) per rileggere i valori dal file purché il file dei valori rimanga semplice

Problemi di attuazione di seguito:

  • L'implementazione si basa su un blocco di file in una fase di reindirizzamento della shell ( flockin Linux per ottenere l'effetto di esclusione, in Windows ha un'esclusione integrata)
  • Ogni valore per una variabile è un valore a riga singola (non una multilinea)

L'implementazione è memorizzata qui: https://sourceforge.net/p/contools/contools/HEAD/tree/trunk/Scripts/Tools

L' bashimplementazione:

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"

Lo stesso su Windows (come esempio di 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

Per scrivere i file basta bloccare allo stesso modo il codice.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.