web-dev-qa-db-fra.com

Démarrage d'un script en tant qu'autre utilisateur

J'ai créé un script dans /etc/init.d/ qui doit exécuter plusieurs autres scripts d'autres utilisateurs (privilégiés non root) à partir de leurs répertoires personnels, comme s'ils les avaient démarrés.

Je lance ces scripts avec: Sudo -b -u <username> <script_of_a_particular_user>

Et il fonctionne. Mais pour chaque script utilisateur qui continue de fonctionner (par exemple, un chien de garde), je vois un processus Sudo parent correspondant, toujours vivant et fonctionnant en tant que root. Cela crée un gâchis dans la liste des processus actifs.

Donc ma question est: Comment puis-je lancer (fork) un autre script à partir d'un script bash existant en tant qu'un autre utilisateur et le laisser comme un processus orphelin (autonome)?

Explication plus détaillée:
J'essaie essentiellement de fournir aux autres utilisateurs de la machine un moyen d'exécuter des tâches au démarrage ou à l'arrêt du système en exécutant des fichiers exécutables trouvés dans les sous-répertoires respectifs trouvés dans leur répertoire personnel, nommés .startUp et .shutDown. Comme je n'ai trouvé aucun autre moyen de le faire, j'ai écrit mon script bash qui fait exactement cela et je l'ai configuré en tant que script de service (en suivant l'exemple squelette) dans /etc/init.d/ donc quand il est exécuté avec l'argument de démarrage, il lance tout à partir des répertoires .startUp et lorsqu'il est exécuté avec l'argument d'arrêt, il lance tout à partir des répertoires .shutDown de tous les utilisateurs comme eux.

Sinon, je suis également intéressé si j'aurais pu utiliser une solution existante pour résoudre ce problème.

[~ # ~] mise à jour [~ # ~]
J'ai regardé un peu et j'ai trouvé cette question: https://unix.stackexchange.com/questions/22478/detach-a-daemon-using-Sudo

Réponse acceptée là-bas, à utiliser: Sudo -u user sh -c "daemon & disown %1", fonctionne pour moi. Mais j'ai aussi essayé sans désavouer% 1 et c'est la même chose. Voilà donc ce qui fonctionne pour moi comme je m'y attendais:

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

Ma question supplémentaire est maintenant, pourquoi cela fonctionne-t-il sans renier? dois-je quand même laisser l'appel désavoué , quel que soit le cas, pour un cas particulier potentiel?

MISE À JOUR 2

Apparemment, cela fonctionne aussi:

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

Y a-t-il une différence entre cet appel et l'appel Sudo? Je sais que c'est potentiellement une toute autre question. Mais puisque je trouve moi-même les réponses ici, peut-être pour le bien de ce sujet, quelqu'un pourrait clarifier cela ici.

MISE À JOUR 3
Ces deux méthodes avec su ou Sudo produisent maintenant un nouveau processus startpar (processus unique qui s'exécute en tant que root) après avoir démarré le machine. Visible dans la liste des processus comme:

startpar -f -- <name_of_my_init.d_script>

Pourquoi ce processus est-il engendré? Évidemment, je fais quelque chose de mal car aucun autre script init.d n'a ce processus en cours d'exécution.

MISE À JOUR 4
Le problème avec startpar est résolu. J'ai commencé une autre question pour cela:
processus startpar laissé suspendu lors du démarrage des processus depuis rc.local ou init.d

Et une autre question pour discuter davantage du lancement de mécanismes pour les utilisateurs non privilégiés:
Fournir aux utilisateurs normaux (non root) des capacités d'initialisation et d'arrêt automatique

12
Ivan Kovacevic

La bonne réponse était que pour une "démonisation" appropriée, l'entrée standard, la sortie standard et l'erreur standard doivent être redirigées vers/dev/null (ou un fichier réel):

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

su - remplace l'identité de l'utilisateur par someuser
- c - argument su pour exécuter la commande spécifiée
Nohup - Exécutez une commande à l'abri des blocages. Pour éviter les cas où le processus parent mettra fin au processus enfant. Ajouté ici juste au cas où. Mais n'a en fait aucun effet dans mon cas particulier. Son utilisation dépend de l'environnement (vérifier shopt )
>/dev/null - Redirige la sortie standard vers rien, la désactivant essentiellement.
2> & 1 - Redirige la sortie d'erreur standard (2) vers la sortie standard (1), qui est redirigée vers null
& - détachez-vous en arrière-plan, cela redirigera également l'entrée standard vers/dev/null.

C'est essentiellement exactement ce que fait l'utilitaire start-stop-daemon de Debian dpkg. C'est pourquoi je préfère démarrer les scripts de cette manière plutôt que d'introduire un autre appel d'utilitaire externe dans mon code. start-stop-daemon est utile dans les cas où vous avez des programmes démon complets que vous devez démarrer et où vous avez ensuite besoin de fonctionnalités supplémentaires qui start-stop-daemon fournit (par exemple, vérifier si le processus spécifié est déjà en cours d'exécution afin qu'il ne le relance pas).

Il convient également de noter que vous pouvez également fermer les descripteurs de fichiers de votre processus au lieu de les rediriger vers /dev/null , par exemple:

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

0 <& - Fermer l'entrée standard (0)
1> & - Fermer la sortie standard (1)
2> & - Fermer la sortie d'erreur standard (2)

La direction des signes <> n'a pas d'importance car le numéro de descripteur de fichier long est spécifié. C'est donc tout aussi bon:

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

ou

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

Cependant, il existe un moyen un peu plus court d'écrire cela, sans chiffres pour stdin et stdout, où la direction importe:

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

Lorsque les descripteurs de fichiers sont fermés ou redirigés vers/dev/null ( start-stop-daemon effectue la redirection vers/dev/null) le processus est sûr de fonctionner en arrière-plan en tant que démon. C'est donc ce qui est nécessaire pour éviter les problèmes ( startpar ) avec le lancement de scripts pendant le démarrage.

J'ai implémenté toute la solution à partir de mon idée initiale et l'ai placée sur GitHub:
https://github.com/ivankovacevic/userspaceServices

18
Ivan Kovacevic

Vous pouvez utiliser le start-stop-daemon sur init.d avec le --user option.

3
dmourati

Je n'ai pas entièrement testé cela, mais je pense que quelque chose comme:

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

au démarrage puis

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

lors de l'arrêt.

La gestion du script .shutDown pourrait être effectuée par quelque chose comme le démarrage, mais vous ne pouvez pas être sûr que les scripts se terminent car l'arrêt devrait de toute façon se produire :-)

devrait faire l'affaire, vous devriez peut-être ajouter une redirection d'entrée, mais vous devrez alors vous soucier du remplissage des fichiers journaux.

2
Mr Shark

Avez-vous essayé d'utiliser su?

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

-c indique à su d'exécuter la commande, et le dernier paramètre est l'utilisateur pour l'exécuter en tant que.

1
Tero Kilkanen