Iniciar un script como otro usuario

12

Creé un script en /etc/init.d/ que tiene que ejecutar varios otros scripts de otros usuarios (sin privilegios de root) desde sus directorios de inicio, como si los hubieran iniciado.

Lanzo estos scripts con: sudo -b -u <username> <script_of_a_particular_user>

Y funciona. Pero por cada script de usuario que continúa ejecutándose (por ejemplo, algún perro guardián) veo un proceso de sudo padre correspondiente, aún vivo y ejecutándose como root. Esto crea un desastre en la lista de procesos activos.

Entonces mi pregunta es: ¿cómo puedo iniciar (bifurcar) otro script desde el script bash existente como otro usuario y dejarlo como un proceso huérfano (independiente)?

Explicación más detallada:
Básicamente estoy tratando de proporcionar a otros usuarios en la máquina un medio para ejecutar cosas al iniciar o apagar el sistema ejecutando archivos ejecutables que se encuentran en los respectivos subdirectorios que se encuentran en su directorio de inicio, llamados .startUp y .shutDown. Como no encontré ningún otro medio para hacerlo, escribí mi script bash que hace exactamente eso y lo configuré como un script de servicio (siguiendo el ejemplo de esqueleto) en /etc/init.d/, así que cuando se ejecuta con el argumento de inicio, inicia todo desde los directorios .startUp y cuando se ejecuta con el argumento de detención, inicia todo desde los directorios .shutDown de todos los usuarios como ellos.

Alternativamente, también estoy interesado si podría haber utilizado alguna solución existente para resolver este problema.

ACTUALIZACIÓN
He buscado un poco y encontré esta pregunta: /unix/22478/detach-a-daemon-using-sudo

Respuesta aceptada allí, para usar:, sudo -u user sh -c "daemon & disown %1"funciona para mí. Pero también lo intenté sin disown% 1 y es lo mismo. Entonces esto es lo que funciona para mí como esperaba:

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

Mi pregunta adicional ahora es, ¿por qué funciona sin rechazo? ¿Debería dejar la llamada desconocida , independientemente de algún posible caso especial?

ACTUALIZACIÓN 2

Aparentemente esto también funciona:

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

¿Hay alguna diferencia entre esta llamada y la llamada sudo? Sé que esta es potencialmente una pregunta completamente diferente. Pero dado que estoy encontrando las respuestas aquí, tal vez por el tema, alguien podría aclarar esto aquí.

ACTUALIZACIÓN 3
Ambos métodos con su o sudo ahora producen un nuevo proceso startpar (proceso único que se ejecuta como raíz) después de iniciar la máquina. Visible en la lista de procesos como:

startpar -f -- <name_of_my_init.d_script>

¿Por qué se genera este proceso? Obviamente estoy haciendo algo mal ya que ningún otro script init.d tiene este proceso ejecutándose.

ACTUALIZACIÓN 4
El problema con startpar está resuelto. He comenzado otra pregunta para eso: el
proceso startpar se quedó colgado al iniciar procesos desde rc.local o init.d

Y otra pregunta para analizar más a fondo los mecanismos de lanzamiento para usuarios no privilegiados:
proporcionar a los usuarios normales (no root) capacidades de ejecución automática de inicialización y apagado

Ivan Kovacevic
fuente

Respuestas:

18

La respuesta correcta para esto fue que para una "demonización" adecuada, la entrada estándar, la salida estándar y el error estándar deben ser redirigidos a / dev / null (o algún archivo real):

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

su - sustituye la identidad del usuario a someuser
-c - argumento su para ejecutar el comando especificado
nohup - Ejecuta un comando inmune a los bloqueos. Para evitar casos en los que el proceso principal finalizará el proceso secundario. Añadido aquí por si acaso. Pero en realidad no tiene ningún efecto en mi caso particular. Si es necesario depende del entorno (consulte shopt )
> / dev / null : redirija la salida estándar a nada, básicamente deshabilitándola.
2> & 1 - Redirige la salida del error estándar (2) a la salida estándar (1), que se redirige a nulo
y - se desconecta al fondo, esto redirigirá la entrada estándar también a / dev / null.

Esto es esencialmente exactamente lo que hace la utilidad start-stop-daemon de Debian dpkg en su núcleo. Es por eso que prefiero iniciar scripts de esta manera en lugar de introducir otra llamada de utilidad externa en mi código. start-stop-daemon es útil en casos en los que tiene programas de daemon completos que necesita iniciar y donde luego necesita una funcionalidad adicional que start-stop-daemon proporciona (por ejemplo, verificar si el proceso especificado ya se está ejecutando para que no No lo lance de nuevo).

También vale la pena señalar que también puede cerrar los descriptores de archivo de su proceso en lugar de redirigirlos a / dev / null , por ejemplo:

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

0 <& - Cerrar entrada estándar (0)
1> & - Cerrar salida estándar (1)
2> & - Cerrar salida de error estándar (2)

La dirección de los signos <> no importa, ya que se especifica un número de descriptor de archivo largo. Entonces esto es igualmente bueno:

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

o

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

Sin embargo, hay una forma un poco más corta de escribir eso, sin números para stdin y stdout, donde la dirección sí importa:

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

Cuando los descriptores de archivo se cierran o se redirigen a / dev / null ( start-stop-daemon está haciendo la redirección a / dev / null), el proceso es seguro para ejecutarse en segundo plano como un demonio. Eso es lo que se necesita para evitar problemas ( startpar ) con el lanzamiento de scripts durante el tiempo de arranque.

Implementé toda la solución desde mi idea inicial y la puse en GitHub:
https://github.com/ivankovacevic/userspaceServices

Ivan Kovacevic
fuente
Ivan, ¿es mejor usar su o su -login? Leí al hombre de su pero no puedo entender para este caso específico.
Massimo
1
@ Massimo, perdón por el retraso en mi respuesta! Echa un vistazo a esta pregunta: unix.stackexchange.com/questions/318572/… hay una página de manual mejor que lo explica. Básicamente, la diferencia está en establecer el directorio de trabajo y las variables de entorno. Yo diría que para casos de uso como este (hacer algo como otro usuario) podría ser una opción preferible usar realmente -login
Ivan Kovacevic
3

Puede usar start-stop-daemon fuera de init.d con la --useropción.

dmourati
fuente
He comentado sobre start-stop-daemon en la respuesta del Sr. Shark y también actualicé mi respuesta y mi pregunta (actualización 4)
Ivan Kovacevic
2

No he probado completamente esto, pero creo que algo así como:

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

al inicio y luego

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

cuando se apaga.

El manejo de la secuencia de comandos .shutDown podría hacerse mediante algo parecido al inicio, pero no puede estar seguro de que las secuencias de comandos se ejecuten para finalizar ya que el apagado debería ocurrir de todos modos :-)

deberías hacer el truco, tal vez deberías incluir alguna redirección de entrada, pero luego deberías preocuparte de que se llenen los archivos de registro.

Señor tiburón
fuente
2
¡Esencialmente, esto funcionaría! start-stop-daemon puede iniciar procesos con éxito en el arranque o de otra manera. Lo he probado Y también elimina ese problema con el proceso de inicio pendiente. Sin embargo, también falta un USUARIO --chuid en su llamada de inicio. Sin él, lanzaría el proceso como root. El archivo pid probablemente también debería escribirse en / var / run / ya que de lo contrario genera un archivo propiedad raíz en el directorio de inicio de los usuarios. Pero, en mi opinión, el lanzamiento de script genérico start-stop-daemon parece ser un poco exagerado. Comprueba mi respuesta donde intenté explicar por qué.
Ivan Kovacevic
1

¿Has intentado usar su?

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

-c le dice a su que ejecute el comando, y el último parámetro es que el usuario lo ejecute como.

Tero Kilkanen
fuente
sí, eso funciona pero con alguna cita y ampersand agregado. Y me parece más limpio escribirlo así: su <nombre de usuario> -c "/some/path/script.sh &" Básicamente he usado sudo ya que parecía estar más limpio, pero ahora parece mejor que usar: sudo - u <nombre de usuario> bash -c "/some/path/script.sh &". Sin embargo, no sé si hay alguna diferencia en esos dos
Ivan Kovacevic,