Обнаружение системы init с использованием оболочки

Это может иметь больше общего с обнаружением операционных систем, но мне особенно нужна система init, которая в настоящее время используется в системе.

Fedora 15 и Ubuntu теперь используют systemd, Ubuntu используется для использования Upstart (долгое время по умолчанию до 15.04), в то время как другие используют вариации System V.

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

То, что я хотел бы сделать, это генерировать скрипт для конкретной системы init, которую они используют. Таким образом, скрипт установки может быть запущен без параметров с правами root, и демон может быть «установлен» автоматически.

Это то, что я придумал:

  • Поиск systemd, upstart и т. Д. В / bin
  • Сравните / proc / 1 / comm с systemd, выскочкой и т. Д.
  • Спросите пользователя

Какой был бы лучший кросс / платформенный способ сделать это?

Вид связанного, Могу ли я зависеть от bash быть на большинстве * nix или зависит от дистрибутива / ОС?

Целевые платформы:

  • Mac OS
  • Linux (все дистрибутивы)
  • BSD (все версии)
  • Solaris, Minix и другие * nix

16 Solutions collect form web for “Обнаружение системы init с использованием оболочки”

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

Что касается первой части – в первую очередь, вы, безусловно, должны быть осторожны. Я бы сказал, чтобы выполнить несколько тестов, чтобы убедиться – потому что тот факт, что у кого-то установлен systemd (например,), не означает, что он фактически используется как init по умолчанию. Кроме того, просмотр /proc/1/comm может вводить в заблуждение, поскольку некоторые установки различных программ init могут автоматически создавать /sbin/init жесткую ссылку symlink или даже переименованную версию их основной программы.

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

В качестве дополнительной заметки вы также можете взглянуть на OpenRC, целью которой является создание структуры сценариев init, совместимых как с системами Linux, так и с BSD.

Я сам вступил в эту проблему и решил сделать несколько тестов. Я полностью согласен с ответом на то, что каждый отдельный дистрибутив следует упаковывать отдельно, но иногда есть практические проблемы, которые мешают этому (не в последнюю очередь).

Итак, для тех, кто хочет «автоматически обнаружить», вот что я обнаружил на ограниченном наборе дистрибутивов (более подробно):

  • Вы можете сказать, выскочка из:

     [[ `/sbin/init --version` =~ upstart ]] && echo yes || echo no 
  • Вы можете сказать systemd:

     [[ `systemctl` =~ -\.mount ]] && echo yes || echo no 
  • Вы можете сказать sys-v init:

     [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]] && echo yes 

Вот мои эксперименты со следующей командной строкой:

 if [[ `/sbin/init --version` =~ upstart ]]; then echo using upstart; elif [[ `systemctl` =~ -\.mount ]]; then echo using systemd; elif [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]]; then echo using sysv-init; else echo cannot tell; fi 

на экземплярах ec2 (я включаю идентификатор AMI us-east):

  • ArchLinux: использование systemd (с 2012.10.06 )
  • CentOS6.4 ami-52009e3b: использование выскочки
  • CentOS7 ami-96a818fe: использование systemd
  • Debian 6 ami-80e915e9: использование sysv-init
  • Debian 7.5 ami-2c886c44: использование sysv-init
  • Debian 7.6 GCE container-vm: использование sysv-init
  • RHEL 6.5 ami-8d756fe4: использование выскочки
  • SLES 11 ami-e8084981: использование sysv-init
  • Ubuntu 10.04 ami-6b350a02: использование выскочки
  • Ubuntu 12.04 ami-b08b6cd8: использование выскочки
  • Ubuntu 14.04 ami-a427efcc: использование выскочки
  • Ubuntu 14.10 и младше: использование systemd
  • AWS linux 2014.3.2 ami-7c807d14: использование выскочки
  • Fedora 19 ami-f525389c: using systemd
  • Fedora 20 ami-21362b48: использование systemd

Уф. Просто чтобы быть ясным: я не утверждаю, что это безупречно! , это почти наверняка нет. Также обратите внимание, что для удобства я использую спички bash regexp, которые недоступны повсюду. Вышеприведенное достаточно для меня прямо сейчас :-), и я надеюсь, что это поможет другим. Однако, если вы найдете дистрибутив, где он не работает, сообщите мне, и я попытаюсь исправить это, если есть AMI AMI, который воспроизводит проблему …

Использование процессов

Рассматривая вывод из нескольких команд ps которые могут обнаруживать различные версии systemd & upstart , которые можно создать так:

выскочка

 $ ps -eaf|grep '[u]pstart' root 492 1 0 Jan02 ? 00:00:00 upstart-udev-bridge --daemon root 1027 1 0 Jan02 ? 00:00:00 upstart-socket-bridge --daemon 

Systemd

 $ ps -eaf|grep '[s]ystemd' root 1 0 0 07:27 ? 00:00:03 /usr/lib/systemd/systemd --switched-root --system --deserialize 20 root 343 1 0 07:28 ? 00:00:03 /usr/lib/systemd/systemd-journald root 367 1 0 07:28 ? 00:00:00 /usr/lib/systemd/systemd-udevd root 607 1 0 07:28 ? 00:00:00 /usr/lib/systemd/systemd-logind dbus 615 1 0 07:28 ? 00:00:13 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation 

Обращая внимание на имя процесса, который является PID # 1, также может потенциально пролить свет, на котором используется система init. В Fedora 19 (который использует systemd , например:

 UID PID PPID C STIME TTY TIME CMD root 1 0 0 07:27 ? 00:00:03 /usr/lib/systemd/systemd --switched-root --system --deserialize 20 

Обратите внимание, что это не init . На Ubuntu с Upstart все равно /sbin/init .

 $ ps -efa|grep init root 1 0 0 Jan02 ? 00:00:03 /sbin/init 

ПРИМЕЧАНИЕ. Но используйте это с некоторой осторожностью. В камне нет ничего, что говорит о том, что конкретная система инициализации, используемая для данного дистрибутива , должна иметь systemd как PID # 1.

общий

 $ (ps -eo "ppid,args" 2>/dev/null || echo "ps call error") \ | awk 'NR==1 || $1==1' | less PPID COMMAND 1 /lib/systemd/systemd-journald 1 /lib/systemd/systemd-udevd 1 /lib/systemd/systemd-timesyncd 

Посмотрите на процессы с ppid 1 (дети процесса init). (Некоторые из) имен дочерних процессов могут указывать на используемую систему init.

Файловая система

Если вы допросите исполняемый файл init , вы также можете получить информацию от него. Просто анализируется вывод --version . Например:

выскочка

 $ sudo /sbin/init --version init (upstart 1.5) Copyright (C) 2012 Scott James Remnant, Canonical Ltd. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

Systemd

 $ type init init is /usr/sbin/init 

ПРИМЕЧАНИЕ. Тот факт, что init не находится в стандартном расположении, – это немного подсказка / подсказка. Он всегда находится в /sbin/init в системах sysvinit.

Sysvinit

 $ type init init is /sbin/init 

Также это:

 $ sudo init --version init: invalid option -- - Usage: init 0123456SsQqAaBbCcUu 

Выводы

Таким образом, похоже, нет какого-либо способа сделать это, но вы можете сформулировать набор проверок, которые бы точно определили, какую систему инициализации вы используете с довольно высокой степенью уверенности.

Не так эффективно, но я, похоже, работает.

 strings /sbin/init | grep -q "/lib/systemd" && echo SYSTEMD strings /sbin/init | grep -q "sysvinit" && echo SYSVINIT strings /sbin/init | grep -q "upstart" && echo UPSTART 

Он будет печатать больше строк, если более чем одно совпадение строк, которое можно перевести на «Невозможно догадаться». Строки, используемые в grep, могут быть слегка изменены, но при тестировании в следующих os я всегда получал одну строку.

  • RHEL 6.4 [UPSTART]
  • RHEL ES 4 (Обновление Nahant 7) [SYSVINIT]
  • Ubuntu 16.04.1 LTS [SYSTEMD]
  • Ubuntu 14.04.2 LTS [UPSTART]
  • Релиз Fedora 23 (онлайн-оболочка) [SYSTEMD]
  • Debian GNU / Linux 7 (онлайн-оболочка) [SYSTEMD]

Более упрощенный подход одного и того же решения (но он останавливается при первом совпадении)

 strings /sbin/init | awk 'match($0, /(upstart|systemd|sysvinit)/) { print toupper(substr($0, RSTART, RLENGTH));exit; }' 

Иногда это так же просто, как использование ls :

 $ ls -l /sbin/init lrwxrwxrwx 1 root root 20 juin 25 12:04 /sbin/init -> /lib/systemd/systemd 

Я думаю, если /sbin/init не является символической ссылкой, вам нужно будет проверить дальнейшие предложения в других ответах.

  1. Для этого нужны дистрибутивные пакеты. Существует гораздо больше возможностей для установки программного обеспечения, чем просто определение системы init. Многие дистрибутивы используют SysVinit, но не все из них записывают свои сценарии инициализации одинаково. Правильный способ решения этого вопроса состоит в том, чтобы включить все различные варианты, а затем объединить его с помощью файлов спецификаций с именами зависимостей для дистрибутива для rpm-дистрибутивов, deb-файлов для основанных на apt систем и т. Д. Почти у всех дистрибутивов есть какая-то спецификация пакета, которую вы может писать, что включает зависимости, скрипты, скрипты инициализации и т. д. Не изобретайте колесо здесь.

  2. Нет. Что возвращает нас к 1. Если вам нужен bash, это должно быть зависимость. Вы можете указать эту проверку как часть ваших скриптов configure, но она также должна быть в описаниях пакетов.

Изменить: использовать флаги в вашем скрипте configure, например, – с --with upstart или – --without sysvinit . Выберите стандартную настройку по умолчанию, затем скрипты, которые упаковывают ваше программное обеспечение для других дистрибутивов, могут выбрать запуск с другими параметрами.

В Gentoo взгляните на pid 1:

 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 4216 340 ? Ss 2013 0:57 init [3] 

Если это init , то система init – это OpenRC . Если это systemd , то система init – systemd .

Вы можете обнаружить Gentoo с [ -f /etc/gentoo-release ] .

Другой метод Gentoo – использовать profile-config show , который покажет, какой профиль по умолчанию используется. Все профили, кроме двух, заканчивающихся в / systemd, используют init Open init. Имейте в виду, что они представлены только по умолчанию, и, возможно, пользователь предпринял шаги для переопределения этого значения по умолчанию и может не указывать на фактическое использование ящика инициализации.

В debian / sbin / init символическая ссылка на ваш init по умолчанию, поэтому

 ls -l /sbin/init 

предоставит вам информацию, которую вы ищете.

 $ ls -l /sbin/init lrwxrwxrwx 1 root root 20 nov 18 13:15 /sbin/init -> /lib/systemd/systemd 

Просто сглаживание процесса с помощью PID 1 скажет вам:

 strings /proc/1/exe |grep -q sysvinit strings /proc/1/exe |grep -q systemd 

Также может помочь проверка файловых дескрипторов. И это от фактического запуска init (Debian stretch в настоящее время позволяет устанавливать больше систем инициализации) 🙂

 $ ls -l /proc/1/fd |grep systemd lrwx------ 1 root root 64 srp 14 13:56 25 -> /run/systemd/initctl/fifo lr-x------ 1 root root 64 srp 14 13:56 6 -> /sys/fs/cgroup/systemd $ ls -l /proc/1/fd |grep /run/initctl # sysvinit lrwx------ 1 root root 64 srp 14 14:04 10 -> /run/initctl $ ls -l /proc/1/fd |grep upstart l-wx------ 1 root root 64 srp 13 16:09 13 -> /var/log/upstart/mysql.log.1 (delete l-wx------ 1 root root 64 srp 13 16:09 9 -> /var/log/upstart/dbus.log.1 (deleted) $ ls -l /proc/1/fd # busybox total 0 lrwx------ 1 root root 64 Jan 1 00:00 0 -> /dev/console lrwx------ 1 root root 64 Jan 1 00:00 1 -> /dev/console lrwx------ 1 root root 64 Jan 1 00:00 2 -> /dev/console 

Вероятно, более безопасный способ проверить busybox – check /proc/1/exe , поскольку busybox обычно использует символические ссылки:

 $ ls -l /proc/1/exe lrwxrwxrwx 1 root root 0 Jan 1 00:00 /proc/1/exe -> /bin/busybox 

Таким образом, проверка может быть:

 { ls -l /proc/1/fd |grep -q systemd && echo "init: systemd"; } || \ { ls -l /proc/1/fd |grep -q /run/initctl && echo "init: sysvinit"; } || \ { ls -l /proc/1/fd |grep -q upstart && echo "init: upstart"; } || \ { ls -l /proc/1/exe |grep -q busybox && echo "init: busybox"; } || \ echo "unknown init" 

Не знаю о других системах, тогда Debian (wheezy) / или Ubuntu (14.10.), Но я тестирую такие проблемы с помощью простой старой команды file .

 file /sbin/init 

дайте это:

 /sbin/init: symbolic link to 'upstart' 

Системы Debian с systemd (например, sid) показывают это:

 # file /sbin/init /sbin/init: symbolic link to /lib/systemd/systemd 

У меня также была такая же проблема, и я провел много тестов на некоторых компьютерах RedHat / CentOS / Debian / Ubuntu / Mint. Это то, с чем я столкнулся, с хорошими результатами.

  1. Найдите имя исполняемого файла с помощью PID 1:

     ps -p 1 

    Если это systemd или Upstart, проблема решена. Если это «init», это может быть символическая ссылка или что-то другое, кроме имени вверх. Преуспевать.

  2. Найдите реальный путь для исполняемого файла (работайте только как root):

     ls -l `which init` 

    Если init является символической ссылкой на Upstart или systemd, проблема решена. В противном случае почти наверняка у вас есть SysV init. Но это может быть неназванный исполняемый файл. Преуспевать.

  3. Найдите пакет, который предоставляет исполняемый файл. К сожалению, это зависит от дистрибутива:

     dpkg-query -S (executable real path) # Debian rpm -qf (executable real path) # RedHat 

Затем, если вы хотите, чтобы сценарий (самая забавная часть, IMHO), это мои однострочные (запускать как root):

 ls -l $(which $(ps -p 1 o comm)) | awk '{ system("dpkg-query -S "$NF) }' # Debian ls -l $(which $(ps -p 1 o comm)) | awk '{ system("rpm -qf "$NF) }' # RedHat 

Это действительно легко для некоторых систем init. Для systemd:

 test -d /run/systemd/system 

для выскочки:

 initctl --version | grep -q upstart 

для чего угодно, вы можете просто предположить на основе дистрибутива (запуск на OS X, sysvinit на Debian, OpenRC на Gentoo).

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

 detect_distro() { # init process is pid 1 INIT=`ls -l /proc/1/exe` if [[ $INIT == *"upstart"* ]]; then SYSTEMINITDAEMON=upstart elif [[ $INIT == *"systemd"* ]]; then SYSTEMINITDAEMON=systemd elif [[ $INIT == *"/sbin/init"* ]]; then INIT=`/sbin/init --version` if [[ $INIT == *"upstart"* ]]; then SYSTEMINITDAEMON=upstart elif [[ $INIT == *"systemd"* ]]; then SYSTEMINITDAEMON=systemd fi fi if [ -z "$SYSTEMINITDAEMON" ]; then echo "WARNING: Unknown distribution, assuming defaults - this may fail." >&2 else echo "Init system discovered: $SYSTEMINITDAEMON" fi } 

При тестировании systemd vs initd существует много проблем с совместимостью. Это действительно работает на OpenSuSE 42.1: ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init' ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init'

Для systemd :

 if [[ `systemctl is-system-running` =~ running ]]; then echo using systemd; fi 
  • Задача, не выполняемая crontab
  • Напишите сценарий оболочки, который принимает переменную из терминала? (переменная ~ $ command)
  • Вставить текст в другое приложение из сценария через ярлык
  • Что вы используете, когда не можете использовать Bash?
  • Linux Mint Corners Музыкальная последовательность Ассоциативный массив
  • Определить файлы text / ascii в Linux / Solaris
  • Linux + заменить STRING / WORD в файле согласно правилу
  • переменная конкатенация не работает?
  • sed, как заменить, когда в строке есть «http: //»?
  • Выполнять команды по отключению tmux
  • Сохранять все даты в определенном диапазоне дат в переменной
  • Interesting Posts

    Как реплицировать установленный пакет из одного экземпляра Fedora в другой?

    сопоставление шаблонов без эха

    Почему мой процесс слишком долго умирает?

    Строки печати, если заданный столбец начинается с заглавной буквы

    распределенная файловая система, которая хорошо работает с несколькими небольшими файлами

    Список установленных программ без запуска программы в системе

    Найти файлы с точным именем файла с помощью mdfind

    Организация электронной почты по дате Использование procmail или maildrop

    Текущая дата в awk

    Команда резервного копирования LUKS (cryptsetup Command) или тома

    Печать в командной строке с использованием принтера Samba, требующего аутентификации

    Как заставить dnsmasq подчиняться порядку серверов в файле resolv.conf

    Использование инкрементирующей переменной в командной строке bash для цикла?

    ssh: Использовать случаи отпечатков пальцев и randomart

    Почему kernel ​​Linux поддерживает «umount /»?

    Linux и Unix - лучшая ОС в мире.