Iniciando um Script como Outro Usuário

12

Eu criei um script no /etc/init.d/ que deve executar vários outros scripts de outros usuários (com privilégios não root) de seus diretórios pessoais, como se eles os tivessem iniciado.

Eu inicio esses scripts com: sudo -b -u <username> <script_of_a_particular_user>

E isso funciona. Mas, para todo script de usuário que continua em execução (por exemplo, algum cão de guarda), vejo um processo sudo pai correspondente, ainda ativo e executando como root. Isso cria uma bagunça na lista de processos ativos.

Portanto, minha pergunta é: como iniciar (bifurcar) outro script a partir do script bash existente como outro usuário e deixá-lo como um processo órfão (independente)?

Explicação mais detalhada:
estou basicamente tentando fornecer a outros usuários na máquina um meio de executar coisas após o início ou o desligamento do sistema, executando arquivos executáveis ​​encontrados nos respectivos subdiretórios encontrados no diretório inicial, denominados .startUp e .shutDown. Como não encontrei outro meio de fazer isso, escrevi meu script bash que faz exatamente isso e o configurei como um script de serviço (seguindo o exemplo do esqueleto) em /etc/init.d/, portanto, quando é executado com o argumento start, lança tudo dos diretórios .startUp e quando é executado com o argumento stop, lança tudo dos diretórios .shutDown de todos os usuários como eles.

Como alternativa, também estou interessado se eu poderia ter usado alguma solução existente para resolver esse problema.

ATUALIZAÇÃO
Eu olhei um pouco e encontrei esta pergunta: /unix/22478/detach-a-daemon-using-sudo

Resposta aceita lá, para usar:, sudo -u user sh -c "daemon & disown %1"funciona para mim. Mas também tentei sem renegar% 1 e é o mesmo. Então é isso que funciona para mim como eu esperava:

sudo -u <username> bash -c "<script_of_a_particular_user> &"

Minha pergunta adicional agora é: por que está funcionando sem renúncia? ainda devo deixar a chamada rejeitada , independentemente de algum possível caso especial?

ATUALIZAÇÃO 2

Aparentemente, isso também funciona:

su <username> -c "<script_of_a_particular_user> &"

Existe alguma diferença entre esta chamada e a chamada sudo? Eu sei que isso é potencialmente uma questão totalmente diferente. Mas como eu mesmo estou encontrando as respostas aqui, talvez por causa deste tópico alguém possa esclarecer isso aqui.

ATUALIZAÇÃO 3
Ambos os métodos com su ou sudo agora produzem um novo processo startpar (processo único que é executado como root) após a inicialização da máquina. Visível na lista de processos como:

startpar -f -- <name_of_my_init.d_script>

Por que esse processo ocorreu? Obviamente, estou fazendo algo errado, pois nenhum outro script init.d tem esse processo em execução.

ATUALIZAÇÃO 4
O problema com o startpar foi resolvido. Comecei outra pergunta para isso:
processo startpar deixado pendente ao iniciar processos a partir do rc.local ou init.d

E outra questão para discutir ainda mais os mecanismos de inicialização para usuários não privilegiados:
Fornecer aos usuários normais (não raiz) recursos de inicialização e desligamento automático

Ivan Kovacevic
fonte

Respostas:

18

A resposta correta para isso foi que, para "daemonização" adequada, entrada padrão, saída padrão e erro padrão precisam ser redirecionados para / dev / null (ou algum arquivo real):

su someuser -c "nohup some_script.sh >/dev/null 2>&1 &"

su - substitui a identidade do usuário por algum argumento
-c - su para executar o comando especificado
nohup - Executa um comando imune ao hangups. Para evitar casos em que o processo pai encerrará o processo filho. Adicionado aqui apenas por precaução. Mas, na verdade, não tem efeito no meu caso particular. Se necessário, depende do ambiente (verifique o shopt )
> / dev / null - Redireciona a saída padrão para nada, basicamente desativando-a.
2> & 1 - Redireciona a saída de erro padrão (2) para a saída padrão (1), que é redirecionada para null
& - desanexa para segundo plano, isso também redireciona a entrada padrão para / dev / null.

Isto é essencialmente exatamente o que o utilitário start-stop-daemon do Debian dpkg faz em seu núcleo. É por isso que prefiro iniciar scripts dessa maneira em vez de introduzir outra chamada de utilitário externo no meu código. O start-stop-daemon é útil nos casos em que você tem programas completos de daemon que precisa iniciar e em que precisa de funcionalidades adicionais fornecidas pelo start-stop-daemon (por exemplo, verificando se o processo especificado já está em execução para que não ocorra). inicie novamente).

Também é importante notar que você também pode fechar os descritores de arquivo do seu processo em vez de redirecioná-los para / dev / null , por exemplo:

su someuser -c "some_script.sh 0<&- 1>&- 2>&- &"

0 <& - Fechar entrada padrão (0)
1> & - Fechar saída padrão (1)
2> & - Fechar erro padrão (2) saída

A direção dos sinais <> não importa, desde que o número do descritor de arquivo seja especificado. Então, isso é igualmente bom:

su someuser -c "some_script.sh 0>&- 1>&- 2>&- &"

ou

su someuser -c "some_script.sh 0<&- 1<&- 2<&- &"

No entanto, existe uma maneira um pouco mais curta de escrever isso, sem números para stdin e stdout, onde a direção importa:

su someuser -c "some_script.sh <&- >&- 2>&- &" 

Quando os descritores de arquivo são fechados ou redirecionados para / dev / null ( start-stop-daemon está redirecionando para / dev / null), é seguro executar o processo em segundo plano como um daemon. É isso que é necessário para evitar problemas ( startpar ) com o lançamento de scripts durante o tempo de inicialização.

Implementei toda a solução a partir da minha ideia inicial e a coloquei no GitHub:
https://github.com/ivankovacevic/userspaceServices

Ivan Kovacevic
fonte
Ivan, é melhor usar su ou su -login? Eu li o homem de su, mas não consigo entender para este caso específico.
Massimo
1
@ Massimo, desculpe pelo atraso na minha resposta! Confira esta pergunta: unix.stackexchange.com/questions/318572/… existe uma página de manual melhor lá explicando. Basicamente, a diferença está na configuração do diretório de trabalho e das variáveis ​​de ambiente. Eu diria para casos de uso como este (fazendo algo como outro usuário) pode ser uma opção preferível para realmente usar -login
Ivan Kovacevic
3

Você pode usar o start-stop-daemon fora do init.d com a --useropção

dmourati
fonte
Eu comentei sobre o start-stop-daemon na resposta do Sr. Tubarão e eu também fez uma atualização para a minha resposta ea minha pergunta (atualização 4)
Ivan Kovacevic
2

Não testei completamente isso, mas acho que algo como:

/sbin/start-stop-daemon --background --start --exec /home/USER/.startUp --user USER --pidfile=/home/USER/.startUp.pid --make-pidfile

na inicialização e depois

/sbin/start-stop-daemon --stop --user USER --pidfile=/home/USER/.startUp.pid

ao desligar.

A manipulação do script .shutDown pode ser feita por algo como a inicialização, mas você não pode ter certeza de que os scripts terminam porque o desligamento deve acontecer de qualquer maneira :-)

deve fazer o truque, talvez você deva lançar algum redirecionamento de entrada, mas precisará se preocupar com o preenchimento dos arquivos de log.

Mr Shark
fonte
2
Essencialmente, isso funcionaria! O start-stop-daemon pode iniciar processos com êxito na inicialização ou não. Eu testei. E também elimina esse problema com a suspensão do processo startpar. No entanto, você também está perdendo um USUÁRIO --chuid na sua chamada inicial. Sem ele, o processo seria iniciado como raiz. O arquivo pid provavelmente também deve ser gravado em / var / run /, pois, caso contrário, ele gera um arquivo de propriedade raiz no diretório inicial do usuário. Mas, na minha opinião, para o lançamento genérico de scripts start-stop-daemon parece ser um exagero. Verifique minha resposta onde tentei explicar o porquê.
Ivan Kovacevic
1

Você já tentou usar su?

su -c /home/user/.startUp/executable - user

-c diz ao su para executar o comando e o último parâmetro é o usuário para executá-lo como.

Tero Kilkanen
fonte
sim, isso funciona, mas com alguma citação e adição de e comercial. E acho mais limpo escrevê-lo assim: su <username> -c "/some/path/script.sh &" Basicamente, usei o sudo, pois parecia mais limpo, mas agora parece melhor do que usar: sudo - u <nome do usuário> bash -c "/some/path/script.sh &". Mas não sei se existem diferenças entre os dois
Ivan Kovacevic 31/03