it-swarm-ru.tech

Определить систему инициализации с помощью оболочки

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

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

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

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

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

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

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

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

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

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

Для второго вопроса ответ нет , и вы должны взглянуть на Ресурсы для переносимого программирования на Shell .

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

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

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

30
rozcietrzewiacz

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

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

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

    [[ `/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 с восточной стороны США):

  • ArchLinux: использование systemd (начиная с 2012.10.06 )
  • CentOS6.4 AMI-52009e3b: использование upstart
  • 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: использование upstart
  • SLES 11 AMI-e8084981: использование sysv-init
  • Ubuntu 10.04 AMI-6b350a02: использование upstart
  • Ubuntu 12.04 AMI-b08b6cd8: использование upstart
  • Ubuntu 14.04 AMI-a427efcc: использование upstart
  • Ubuntu 14.10 и младше: использование systemd
  • AWS linux 2014.3.2 AMI-7c807d14: использование upstart
  • Fedora 19 AMI-f525389c: использование systemd
  • Fedora 20 AMI-21362b48: использование systemd

Просто чтобы прояснить: Я не утверждаю, что это надежно! , почти наверняка это не так. Также обратите внимание, что для удобства я использую совпадения регулярных выражений bash, которые не везде доступны. Выше это достаточно хорошо для меня прямо сейчас. Однако, если вы обнаружите дистрибутив, где он не работает, пожалуйста, дайте мне знать, и я постараюсь это исправить, если есть EC2 AMI, который воспроизводит проблему ...

61
TvE

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

Рассмотрим выходные данные нескольких команд 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, также может пролить свет на то, какая система инициализации используется. На 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, вы также сможете получить от него некоторую информацию. Просто разбирая --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

Выводы

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

19
slm

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

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, могут быть немного изменены, но при тестировании в следующей ОС я всегда получал одну строку.

  • 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]
  • Centos 7,6 (VM) [SYSTEMD]

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

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

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

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

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

10
Skippy le Grand Gourou

У меня тоже была такая же проблема, и я провел много тестов на некоторых машинах 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  
    

Затем, если вы хотите написать это (самая забавная часть, ИМХО), это мои однострочники (запускаются с правами 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  
5
Emerson Prado
  1. Для этого предназначены специальные дистрибутивные пакеты. Правильная установка программного обеспечения - это гораздо больше, чем просто обнаружение системы инициализации. Многие дистрибутивы используют SysVinit, но не все пишут свои сценарии инициализации одинаково. Правильный способ решить эту проблему - включить все различные варианты, а затем объединить их, используя файлы спецификаций с именами зависимых от дистрибутивов зависимостей для дистрибутивов rpm, файлы deb для систем на основе apt и т.д. Почти во всех дистрибутивах есть какая-то спецификация пакета, которую вы Можно написать, что включает в себя зависимости, сценарии, сценарии инициализации и т. д. Не изобретайте колесо здесь.

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

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

3
Caleb

Также может помочь проверка файловых дескрипторов. И это из фактического запуска 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

Возможно, более безопасный способ проверить занятость - это 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"
3
pevik

Простой переход к процессу с PID 1 скажет вам:

strings /proc/1/exe |grep -q sysvinit
strings /proc/1/exe |grep -q systemd
2
Cyrille Pontvieux

Не знаю о других системах, кроме 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
2
zzeroo

На 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
2
rmorelli74

В 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, то система инициализации OpenRC. Если это systemd, то система инициализации systemd.

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

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

2
casey

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

test -d /run/systemd/system

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

initctl --version | grep -q upstart

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

1
CameronNemo

Для systemd:

if [[ `systemctl is-system-running` =~ running ]]; then echo using systemd; fi
1
guilhermebr

Мое решение: проверьте команду, запущенную как процесс, с ID 1.

case `cat /proc/1/comm` in
    init)    echo Init ;;
    systemd) echo SystemD ;;
    # add here other patterns
    *)       echo "unknown: '`cat /proc/1/comm`'" ;;
esac

На данный момент у меня есть доступ только к компьютерам Init и SystemD, поэтому я не могу сказать, как будет обнаружен Upstart или macOS (OS X), но я продолжу поиск.

1
t0r0X

Вот скрипт bash для обнаружения. На данный момент он проверяет только upstart и 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
}
1
Ben McCann

При тестировании systemd vs initd существует множество ошибок совместимости. На самом деле это работает на OpenSuSE 42.1: ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init'

1
David Lakatos

Как насчет этого:

strings $(\ps -p 1 o cmd= | cut -d" " -f1) | egrep -o "upstart|sysvinit|systemd" | head -1

Проверено только на тех системах, которые у меня есть: Ubuntu и SailfishOS.

0
SebMa
check(){
    if hash systemctl 2>/dev/null;
    then
        echo "there is systemd"
    fi

    if hash initctl 2>/dev/null;
    then
        echo "there is upStart"
    fi

    if [ -f "/etc/inittab"];
    then
        echo "there is systemV"
    fi
}
0
hxysayhi