Запуск скрипта от имени другого пользователя

12

Я создал сценарий в /etc/init.d/, который должен запускать несколько других сценариев от других (без привилегий root) пользователей из их домашних каталогов, как будто они их запустили.

Я запускаю эти скрипты с: sudo -b -u <username> <script_of_a_particular_user>

И это работает. Но для каждого пользовательского скрипта, который продолжает работать (например, для некоторого сторожевого таймера), я вижу соответствующий родительский процесс sudo, все еще работающий и работающий от имени пользователя root. Это создает беспорядок в списке активных процессов.

Поэтому мой вопрос: как я могу запустить (разветвлять) другой скрипт из существующего скрипта bash от имени другого пользователя и оставить его как потерянный (автономный) процесс?

Более подробное объяснение:
я в основном пытаюсь предоставить другим пользователям на машине средство запуска чего-либо при запуске системы или выключении системы путем запуска исполняемых файлов, находящихся в соответствующих подкаталогах в их домашнем каталоге с именами .startUp и .shutDown. Поскольку я не нашел другого способа сделать это, я написал свой bash-скрипт, который делает именно это, и я настроил его как служебный скрипт (следуя примеру скелета) в /etc/init.d/, поэтому, когда он запускается с аргументом start он запускает все из каталогов .startUp, а когда он запускается с аргументом stop, он запускает все из каталогов .shutDown всех пользователей как они.

В качестве альтернативы мне также интересно, если бы я мог использовать какое-то существующее решение для решения этой проблемы.

ОБНОВЛЕНИЕ
Я немного осмотрелся и нашел этот вопрос: /unix/22478/detach-a-daemon-using-sudo

Принимается ответ там, для использования: sudo -u user sh -c "daemon & disown %1"у меня работает. Но я тоже пробовал без дизауна% 1 и тоже самое. Так вот что работает для меня, как я ожидал:

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

Мой дополнительный вопрос: почему он работает без отрешенности? я должен все еще оставить вызов disown , независимо от некоторого потенциального особого случая?

ОБНОВЛЕНИЕ 2

Видимо это тоже работает:

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

Есть ли разница между этим вызовом и вызовом sudo? Я знаю, что это потенциально совершенно другой вопрос. Но так как я сам здесь нахожу ответы, может быть, ради этой темы кто-то мог бы прояснить это здесь.

ОБНОВЛЕНИЕ 3
Оба этих метода с su или sudo теперь производят новый процесс startpar (один процесс, который запускается от имени root) после загрузки машины. Отображается в списке процессов как:

startpar -f -- <name_of_my_init.d_script>

Почему этот процесс порожден? Очевидно, что я делаю что-то не так, поскольку ни один другой скрипт init.d не запускает этот процесс.

ОБНОВЛЕНИЕ 4
Проблема с startpar решена. Я начал другой вопрос для этого:
процесс startpar оставался зависшим при запуске процессов из rc.local или init.d

И еще один вопрос для дальнейшего обсуждения механизмов запуска для непривилегированных пользователей: предоставление обычным пользователям ( без полномочий
root) возможностей инициализации и автоматического запуска

Иван Ковачевич
источник

Ответы:

18

Правильный ответ на это заключался в том, что для правильной «демонизации» стандартный ввод, стандартный вывод и стандартная ошибка должны быть перенаправлены в / dev / null (или в какой-то реальный файл):

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

su - подставить идентификатор пользователя в аргумент someuser
-c - su для запуска указанной команды
nohup - запустить команду, защищенную от зависаний. Для предотвращения случаев, когда родительский процесс завершит дочерний процесс. Добавлено здесь на всякий случай. Но на самом деле не имеет никакого эффекта в моем конкретном случае. Требуется ли это, зависит от среды (проверьте shopt )
> / dev / null - Перенаправить стандартный вывод в ничто, в основном отключив его.
2> & 1 - Перенаправить стандартный вывод ошибки (2) на стандартный вывод (1), который перенаправлен на нуль
и - отсоединиться от фона, это перенаправит стандартный ввод также на / dev / null.

По сути, это именно то, что делает утилита start-stop-daemon из Debian dpkg в своей основе. Вот почему я предпочитаю запускать сценарии таким образом, а не вводить другой вызов внешней утилиты в моем коде. start-stop-daemon полезен в тех случаях, когда у вас есть полнофункциональные программы-демоны, которые нужно запустить, и где вам затем необходимы дополнительные функции, которые предоставляет start-stop-daemon (например, проверка, запущен ли уже указанный процесс, чтобы он не не запускаю его снова).

Также стоит отметить, что вы можете также закрыть файловые дескрипторы вашего процесса вместо перенаправления их в / dev / null , например:

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

0 <& - Закрыть стандартный вход (0)
1> & - Закрыть стандартный выход (1)
2> & - Закрыть стандартный вывод ошибки (2)

Направление знаков <> не имеет значения, так как указан длинный номер дескриптора файла. Так что это одинаково хорошо:

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

или

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

Однако есть немного более короткий способ написать это без чисел для stdin и stdout, где направление имеет значение:

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

Когда файловые дескрипторы либо закрыты, либо перенаправлены в / dev / null ( start-stop-daemon выполняет перенаправление в / dev / null), процесс можно безопасно запускать в фоновом режиме в качестве демона. Это то, что нужно, чтобы избежать проблем ( startpar ) с запуском скриптов во время загрузки.

Я реализовал все решение из своей первоначальной идеи и разместил его на GitHub:
https://github.com/ivankovacevic/userspaceServices

Иван Ковачевич
источник
Иван, лучше использовать su или su -login? Я прочитал человека Су, но я не могу понять для этого конкретного случая.
Массимо
1
@Massimo, извините за задержку в моем ответе! Проверьте этот вопрос: unix.stackexchange.com/questions/318572/… там есть лучшая страница руководства, объясняющая это. В основном разница заключается в настройке рабочего каталога и переменных среды. Я бы сказал, что для таких случаев использования (как что-то от имени другого пользователя) может быть предпочтительнее использовать -login
Ivan Kovacevic
3

Вы можете использовать start-stop-daemon из init.d с --userопцией.

dmourati
источник
Я прокомментировал start-stop-daemon ответ г-на Акулы, а также обновил свой ответ и мой вопрос (обновление 4)
Иван Ковачевич,
2

Я не полностью проверил это, но я думаю, что-то вроде:

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

при запуске, а затем

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

при выключении

Обработка скрипта .shutDown может быть сделана чем-то вроде запуска, но вы не можете быть уверены, что скрипты будут работать до конца, так как в любом случае должно произойти завершение работы :-)

следует сделать свое дело, возможно, вы должны добавить некоторое перенаправление ввода, но тогда вам придется беспокоиться о заполнении файлов журнала.

Мистер акула
источник
2
По сути, это будет работать! start-stop-daemon может успешно запускать процессы при загрузке или другим способом. Я проверял это. И это также избавляет от этой проблемы с зависанием процесса startpar. Однако в стартовом вызове вам также не хватает пользователя --chuid. Без этого он запустил бы процесс как root. Файл pid также, вероятно, должен быть записан в / var / run /, так как в противном случае он создает корневой файл в домашнем каталоге пользователя. Но, на мой взгляд, запуск общего скрипта start-stop-daemon кажется излишним. Проверьте мой ответ, где я пытался объяснить, почему.
Иван Ковачевич
1

Вы пробовали использовать su?

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

-c говорит su выполнить команду, а последний параметр - это пользователь, который ее выполняет.

Теро Килканен
источник
да, это работает, но с некоторой цитатой и добавил амперсанд. И я считаю более понятным написать это так: su <username> -c "/some/path/script.sh &" В основном я использовал sudo, поскольку он казался более чистым, но теперь это кажется лучше, чем с помощью: sudo - u <имя пользователя> bash -c "/some/path/script.sh &". Не знаю, есть ли различия в этих двух, хотя
Иван Ковачевич