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

12

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.

Ma question est donc la suivante: comment lancer (bifurquer) un autre script à partir d'un script bash existant en tant qu'autre utilisateur et le laisser en tant que 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 choses 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: /unix/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 renier% 1 et c'est pareil. Voici 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 ça marche sans renier? dois-je quand même quitter 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é la 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 à partir de rc.local ou init.d

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

Ivan Kovacevic
la source

Réponses:

18

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 vrai fichier):

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écute 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. La nécessité dépend de l'environnement (vérifiez shopt )
> / dev / null - Redirige la sortie standard vers rien, la désactivant essentiellement.
2> & 1 - Redirige la sortie de l'erreur standard (2) vers la sortie standard (1), qui est redirigée vers null
& - se détache 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 de démon complets que vous devez démarrer et où vous avez ensuite besoin de fonctionnalités supplémentaires fournies par start-stop-daemon (par exemple, vérifier si le processus spécifié est déjà en cours d'exécution afin qu'il ne fonctionne pas) pas le relancer).

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 l'erreur standard (2) la sortie

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 peut être exécuté 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

Ivan Kovacevic
la source
Ivan, vaut-il mieux utiliser su ou su -login? J'ai lu l'homme de su mais je ne peux pas comprendre pour ce cas spécifique.
Massimo
1
@Massimo, désolé pour le retard dans ma réponse! Consultez cette question: unix.stackexchange.com/questions/318572/… il y a une meilleure page de manuel qui l'explique. Fondamentalement, la différence réside dans la définition du répertoire de travail et des variables d'environnement. Je dirais que pour des cas d'utilisation comme celui-ci (faire quelque chose en tant qu'autre utilisateur), il pourrait être préférable d'utiliser réellement -login
Ivan Kovacevic
3

Vous pouvez utiliser le démon start-stop- out de init.d avec l' --useroption.

dmourati
la source
J'ai commenté le start-stop-daemon sur la réponse de M. Shark et j'ai également mis à jour ma réponse et ma question (mise à jour 4)
Ivan Kovacevic
2

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.

Mr Shark
la source
2
Essentiellement, cela fonctionnerait! start-stop-daemon peut lancer des processus avec succès au démarrage ou autrement. Je l'ai testé. Et il se débarrasse également de ce problème avec la suspension du processus startpar. Cependant, il vous manque également un --chuid USER dans votre appel de démarrage. Sans cela, il lancerait le processus en tant que root. Le fichier pid devrait aussi probablement être écrit dans / var / run / car sinon il génère un fichier appartenant à la racine dans le répertoire personnel des utilisateurs. Mais, dans mon esprit, le lancement d'un script générique start-stop-daemon semble être un peu exagéré. Vérifiez ma réponse où j'ai essayé d'expliquer pourquoi.
Ivan Kovacevic
1

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.

Tero Kilkanen
la source
oui, cela fonctionne mais avec une citation et une esperluette ajoutée. Et je trouve plus propre de l'écrire comme ceci: su <username> -c "/some/path/script.sh &" En gros, j'ai utilisé sudo car il semblait être plus propre mais maintenant cela semble mieux que d'utiliser: sudo - u <nom d'utilisateur> bash -c "/some/path/script.sh &". Je ne sais pas s'il y a des différences entre ces deux-là
Ivan Kovacevic