Como fazer um gerenciador de pacotes esperar se outra instância do APT estiver rodando?

47

Eu tenho visto muitos softwares como o Update Manager e o Synaptic Package Manager, eles esperam se algum outro programa estiver usando o /var/lib/dpkg/lock e estiver bloqueado. Como podemos fazer isso através do Terminal? Eu vi o manual de apt-get mas não encontrei nada útil.

    
por Piyush 05.05.2012 / 15:09

8 respostas

34

Você pode usar o comando aptdcon para enfileirar tarefas do gerenciador de pacotes comunicando-se com o aptdaemon em vez de usar o apt-get diretamente.

Então, basicamente, você pode fazer sudo aptdcon --install chromium-browser ou qualquer outra coisa e enquanto esse comando estiver rodando você pode rodar novamente mas instalar pacotes diferentes e o apt-daemon irá apenas colocá-los em fila em vez de errar.

Isso é especialmente útil se você estiver fazendo uma atualização longa ou algo assim e quiser continuar instalando pacotes ou se estiver criando scripts juntos e quiser garantir que a instalação das coisas seja mais confiável.

    
por Jorge Castro 22.12.2012 / 21:55
43

Você pode fazer apt-get aprender a esperar se outro gerenciador de software estiver em execução. Algo parecido com o comportamento da próxima tela:

Comoeufizisso?

Eucrieiumnovoscriptchamadoapt-get(wrapperparaapt-get)nodiretório/usr/local/sbincomoseguintecódigobash:

#!/bin/bash i=0 tput sc while fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do case $(($i % 4)) in 0 ) j="-" ;; 1 ) j="\" ;; 2 ) j="|" ;; 3 ) j="/" ;; esac tput rc echo -en "\r[$j] Waiting for other software managers to finish..." sleep 0.5 ((i=i+1)) done /usr/bin/apt-get "$@"

Não se esqueça de torná-lo executável:

sudo chmod +x /usr/local/sbin/apt-get

Antes de testar, verifique se está tudo ok. A saída do comando which apt-get deve ser agora /usr/local/sbin/apt-get . O motivo é: por padrão, o diretório /usr/local/sbin é colocado antes do diretório /usr/bin no usuário ou raiz PATH .

    
por Radu Rădeanu 10.11.2013 / 17:27
20

Além do óbvio && , você pode estar procurando por aptdcon . Esta ferramenta é capaz de detectar outras instâncias do apt e esperar que elas terminem:

sudo aptdcon --safe-upgrade
[/]  11% Waiting for other software managers to quit Waiting for aptitude

(estou executando o aptitude em outro lugar)

A vantagem dessa ferramenta é que você pode estocar várias ações consecutivamente sem se preocupar com o que fará em seguida. aptdcon é ideal para scripts autônomos e instalação de GUI, já que você pode permitir que a ferramenta seja executada em segundo plano para não bloquear seu frontend.

As operações suportadas por aptdcon são:

  • --refresh , -c : é o equivalente a apt-get update . Atualiza sua lista de pacotes.
  • --install , --remove , --upgrade , --purge , --downgrade . Cada um deles faz como seus nomes dizem. O nome do pacote (s) é obrigatório. -i , -r , -u , -p : estas são as opções curtas para todos, exceto para o downgrade, que não tem uma.
  • --safe-upgrade , --full-upgrade são as contrapartidas para apt-get upgrade / dist-upgrade e aptitude safe-upgrade / full-upgrade . Estes não precisam de parâmetros.
  • Existem várias outras operações, que podem ser encontradas no manual. Mas esses são os mais usados pelos usuários interessados em aptd . Existem opções que se sobrepõem a qual apt-key , apt-cache , dpkg do.

apt-get em si não suporta tais métodos (para esperar por outras instâncias do apt), então aptdcon é a solução preferida para os gerenciadores de pacotes da GUI: USC usa aptd como backend, igual ao Synaptic. Outra solução é packagekit , mas não suporta a função que você está procurando (ainda).

    
por Braiam 09.11.2013 / 13:19
18

Uma abordagem muito simples seria um script que esperasse que o bloqueio não estivesse aberto. Vamos chamá-lo de waitforapt e colocar em /usr/local/bin :

#!/bin/sh

while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do
   sleep 1
done

Em seguida, basta executar sudo waitforapt && sudo apt-get install whatever . Você pode adicionar exceções ao sudoers para permitir que você o execute sem precisar de uma senha (você precisará dele para o apt-get , por isso não é um grande ganho).

Infelizmente isso não enfileira as coisas. Dado que algumas das operações do apt são interativas ("Você tem certeza que quer remover todos esses pacotes ?!"), eu não consigo ver uma boa maneira de contornar isso ...

    
por Oli 09.11.2013 / 13:50
3

Você pode usar uma técnica de pesquisa:

$ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \
  apt-get -y install some-other-package
    
por malthe 09.12.2013 / 23:29
3

Eu fiz um script que faz isso:

#!/bin/bash

# File path to watch
LOCK_FILE='/var/lib/dpkg/lock'

# tput escape codes
cr="$(tput cr)"
clr_end="$(tput el)"
up_line="$(tput cuu 1)"

CLEAN(){
    # Cleans the last two lines of terminal output,
    # returns the cursor to the start of the first line
    # and exits with the specified value if not False

    echo -n "$cr$clr_end"
    echo
    echo -n "$cr$clr_end$up_line"
    if [[ ! "$1" == "False" ]]; then
        exit $1
    fi
}

_get_cmdline(){
    # Takes the LOCKED variable, expected to be output from 'lsof',
    # then gets the PID and command line from '/proc/$pid/cmdline'.
    #
    # It sets '$open_program' to a user friendly string of the above.

    pid="${LOCKED#p}"
    pid='echo $pid | sed 's/[\n\r ].*//''
    cmdline=()
    while IFS= read -d '' -r arg; do
        cmdline+=("$arg")
    done < "/proc/${pid}/cmdline"
    open_program="$pid : ${cmdline[@]}"
}

# Default starting value
i=0

# Checks if the file is locked, writing output to $FUSER
while LOCKED="$(lsof -F p "$LOCK_FILE" 2>/dev/null)" ; do
    # This will be true if it isn't the first run
    if [[ "$i" != 0 ]]; then
        case $(($i % 4)) in
            0 ) s='-'
                i=4
                _get_cmdline # Re-checks the command line each 4th iteration
            ;;
            1 ) s=\ ;;
            2 ) s='|' ;;
            3 ) s='/' ;;
        esac
    else
        # Traps to clean up the printed text and cursor position
        trap "CLEAN False; trap - SIGINT ; kill -SIGINT $$" SIGINT
        trap 'CLEAN $((128+15))' SIGTERM
        trap 'CLEAN $((128+1))' SIGHUP
        trap 'CLEAN $((128+3))' SIGQUIT

        # Default starting character
        s='-'

        _get_cmdline
        echo -n "$save_cur"
    fi
    # Prints the 2nd line first so the cursor is at the end of the 1st line (looks nicer)
    echo
    echo -n "$cr$clr_end$open_program"
    echo -n "$up_line$res_cur$cr$clr_end[$s] Waiting for other package managers to finish..."
    #echo -en "$cr$clr_end[$s] Waiting for other package managers to finish..."
    #echo -en "\n$cr$clr_end$open_program$cr$up_line"
    ((i++))
    sleep 0.025
done

CLEAN False

# This allows saving the script under a different name (e.g. 'apt-wait')
# and running it. It only imitates 'apt-get' if it was launched as such
if [[ "${0##*/}" == 'apt-get' ]]; then
    exec /usr/bin/apt-get "$@"
    exit $?
fi

Salve as opções acima em /usr/local/sbin/apt-get . apt-get esperará se outra instância já estiver em execução.

Como alternativa, salve-o como /usr/local/sbin/apt-wait , exemplo de uso:

apt-wait && aptitude

que executará aptitude depois que o processo atual mantendo o bloqueio encerrado.

Example run:

  1. First, an apt-get command is run, for example:

    $ sudo apt-get remove some_package
    
  2. Then, in another terminal, another command is run:

    $ sudo apt-get install some_other_package
    

    It will wait for the first command to finish then run. Output while waiting:

    [/] Waiting for other package managers to finish...
          28223 : /usr/bin/apt-get remove some_package
    
    
por kiri 19.01.2014 / 05:32
2

Infelizmente, o fusor não faz muito por você quando você está executando em diferentes contêineres de namespace não privilegiados, como o lxc.

Além disso, o aptdcon não é instalado por padrão (pelo menos no 18.04) e coloca sua tarefa em segundo plano em uma fila, para que você perca a serialização. Isso não é insuperável, mas significa que sua automação precisa ter alguma maneira de evitar erros de flock no apt ao instalar o aptdcon, e você precisará ter algum tipo de loop de espera para qualquer coisa que precisar serializar após instalar os pacotes via aptdcon a menos que haja algum tipo de sinalizador para isso já.

O que funciona é o bando. Isso também deve funcionar sobre o NFS, etc., já que ele usa o bloqueio do sistema de arquivos da mesma forma que o apt, apenas com o parâmetro -w seconds que irá aguardar no seu bloqueio em vez de lançar um erro.

Seguindo o modelo do wrapper, adicione-o como apt-get em / usr / local / bin / e compartilhe.

Isso também tem o benefício de limitar o IO ao não permitir o paralelismo no apt, para que você possa permitir que o cron acione atualizações à meia-noite em qualquer lugar, sem precisar bater o disco.

#!/bin/bash
exec /usr/bin/flock -w 900 -F --verbose /var/cache/apt/archives/lock /usr/bin/apt-get $@  

Uma requisição de recurso muito agradável e simples para o apt-get seria um sinalizador -w para alternar para um bloqueio de bloqueio / espera.

    
por 07.09.2018 / 20:02
1

One-liner baseado na resposta de Oli :

while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do sleep 1; done
    
por Menasheh 27.02.2018 / 07:55