Como posso executar um comando local (para executar um script) em (logo antes) sair de uma sessão Unity?

4

Correndo o risco de postar uma pergunta duplicada:

Como posso executar um script local (como o usuário atual) quando eu sair?

Eu li (e tentei) entre outros:

  1. Este (versão de Marton), que não fez nada, usado em um script simples criando um arquivo, caminhos absolutos para o script (sendo executável) e o arquivo.
  2. Esse aqui , que deve estar desatualizado; isso me fez remover o arquivo da linha de comando para poder usar meu sistema novamente.
  3. Eu também procurei em este >, sem sucesso.

Eu acredito que devo estar fazendo algo errado aqui, mas não consigo descobrir qual é o meu ponto cego.

Contexto

Procurando por uma solução elegante (solução alternativa) para essa questão , presumivelmente o resultado de um bug, eu fiz um script que, dependendo do argumento, faz um instantâneo do arranjo atual do ícone da área de trabalho, ou organiza os ícones , de acordo com o último instantâneo. O script funciona bem, mas não é um candidato para ser executado como script de plano de fundo.

O script, portanto, deve ser executado no logout para obter o arranjo, obviamente executado pelo usuário atual.

    
por Jacob Vlijm 12.01.2016 / 22:53

1 resposta

3

Teoria básica

Como você pode ou não saber, muitas ações do Unity são implementadas usando o dbus . A grande conveniência do dbus é que você pode realizar muitas ações requeridas pela raiz, chamando os métodos apropriados na linha de comando, sem precisar de conta de administrador, por exemplo desligando o seu sistema .

Especificamente em nosso caso, estamos interessados em com.canonical.Unity service, /com/canonical/Unity/Session path. Você pode listar informações sobre ele com o comando qdbus . Particularmente, estamos interessados em sinais que possuem Requested neles.

$ qdbus com.canonical.Unity /com/canonical/Unity/Session | grep 'signal.*Requested.*'                             
signal void com.canonical.Unity.Session.LockRequested()
signal void com.canonical.Unity.Session.LogoutRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.RebootRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.ShutdownRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.UnlockRequested()

Esses sinais aparecem no barramento quando o usuário clica em qualquer um dos itens de desligamento, bloqueio, logout ou reinicialização no menu da sessão suspensa, no lado direito da barra superior do Unity. Então, o que precisamos fazer é isto:

  • monitore o barramento para esses sinais aparecerem.
  • depois de aparecerem, execute uma determinada ação.

É claro que o grande divulgador é que, se um usuário usar sudo shutdown -P now ou gnome-session-quit , isso não será informado para o dbus , portanto, qualquer ação desejada não será ser feito.

Monitorando o dbus

Convenientemente, há um comando para isso, dbus-monitor , e podemos filtrar sua saída usando um conjunto de opções e executar uma ação usando while read do … done structure

Abaixo está um exemplo de um script de monitoramento simples.

dbus-monitor --profile "interface='com.canonical.Unity.Session',type=signal" | \
while read -r line;
do
  echo "$line" 
  sleep 0.25
done

O que ele faz é meramente monitorar o barramento em busca de sinais, e fazer com que eles voltem ao stdout se eles aparecerem; Claro que o eco pode ser qualquer comando. Execute-o e tente clicar em cada item no menu da sessão que deve gerar sinais, e você verá algo como isto:

$ ./logout_monitor.sh                                                                                             
sig 1458319246  172587  2   /org/freedesktop/DBus   org.freedesktop.DBus    NameAcquired
sig 1458319251  213766  5496    /com/canonical/Unity/Session    com.canonical.Unity.Session RebootRequested
sig 1458319265  62555   5525    /com/canonical/Unity/Session    com.canonical.Unity.Session LogoutRequested
sig 1458319271  856770  5555    /com/canonical/Unity/Session    com.canonical.Unity.Session LockRequested
sig 1458319273  223940  5564    /com/canonical/Unity/Session    com.canonical.Unity.Session Locked
sig 1458319276  991413  5604    /com/canonical/Unity/Session    com.canonical.Unity.Session UnlockRequested
sig 1458319278  3443    5606    /com/canonical/Unity/Session    com.canonical.Unity.Session Unlocked

Portanto, agora temos uma função de monitoramento que pode executar uma ação quando ocorre uma interrupção. Agora, para resolver a questão específica que você estava tentando resolver, seu script está tirando instantâneos dos ícones na área de trabalho. Não há nenhum dano se fizermos um snapshot a cada vez que um sinal ocorrer - ele não precisa ser reinicializado ou desligado especificamente. Portanto, se monitorarmos essa interface Unity específica para sinais e tirarmos instantâneos após a chegada de cada sinal, poderemos simplificar o script.

Script orientado a interrupções

Abaixo, você pode ver um script baseado em interrupções que irá monitorar o barramento por sinais (ignorando o primeiro) e se tivermos um sinal entrando, então chame uma função de interrupção (que no seu caso será o script de instantâneo do ícone que você escreveu).

#!/bin/bash

main()
{
  ARG="cow"
  dbus-monitor --profile "interface='com.canonical.Unity.Session',type=signal" | 
  while read -r line;
  do
    grep -q '.*NameAcquired.*' <<< "$line"  && continue  #  Ignore that first line
    if [ -n "$line"  ];then
       interrupt $ARG # call your python snapshot script here
    fi
  done
}

interrupt()
{
  echo 'Old McDonald had a ' $ARG ' e-i-e-i-o '
}

main

OBSERVAÇÃO : O Dbus conta com uma sessão GUI, já que (até onde eu sei) começa com o login do Unity / Gnome. Ambientes mais antigos, como blackbox e openbox, assim como ambientes TTY não iniciam a sessão dbus, por isso o script vai vomitar se você tentar iniciá-lo em ~/.profile (eu tive um usuário que tentou fazer algo assim e ele entrou em apuros). Inicie o script usando o programa Unity ou Gnome's Startup Applications .

Indo além deste script

  • O Dbus tem muitas APIs, incluindo python
  • Eu prefiro usar qdbus porque é simples, mas sempre é possível usar dbus-send . Exemplos
  • A função de interrupção pode ser qualquer coisa, até mesmo outros métodos dbus . Há muito para se olhar.

Curiosidades : Eu usei esse mesmo método para prevenir o desligamento se o apt estiver em execução

    
por Sergiy Kolodyazhnyy 18.03.2016 / 18:12