it-swarm-eu.dev

Zjistit init systém pomocí shellu

To může mít více společného s detekcí operačních systémů, ale potřebuji konkrétně systém init, který se v systému právě používá.

Fedora 15 a Ubuntu nyní používají systemd, Ubuntu používal Upstart (dlouhodobě výchozí do 15.04), zatímco ostatní používají varianty systému V.

Mám aplikaci, kterou píšu, jako démona napříč platformami. Inicializační skripty jsou dynamicky generovány na základě parametrů, které lze předat při konfiguraci.

Chtěl bych pouze vygenerovat skript pro konkrétní systém init, který používají. Tímto způsobem lze instalační skript spouštět přiměřeně bez parametrů jako root a démona lze automaticky „nainstalovat“.

To je to, s čím jsem přišel:

  • Vyhledejte systemd, upstart atd. V/bin
  • Porovnejte/proc/1/comm s systemd, upstart atd
  • Zeptejte se uživatele

Jaký by byl nejlepší způsob napříč platformami?

Druh příbuzného, ​​Mohu se spoléhat na to, že bash bude na většině * nix nebo je to závislé na distribuci/OS?

Cílové platformy:

  • Operační Systém Mac
  • Linux (všechny distribuce)
  • BSD (všechny verze)
  • Solaris, Minix a další * nix
96
beatgammit

Pro druhou otázku je odpověď ne a měli byste se podívat na Zdroje pro přenosné programování Shell .

Pokud jde o první část - především musíte být opatrní. Řekl bych provést několik testů, abyste se ujistili - protože skutečnost, že někdo nemá systemd (např.) Nainstalován, neznamená, že je to ve skutečnosti používá se jako výchozí init. Při pohledu na /proc/1/comm může být zavádějící, protože některé instalace různých init programů mohou automaticky provést /sbin/init odkaz na symlink nebo dokonce přejmenovanou verzi jejich hlavního programu.

Možná by nejužitečnější bylo podívat se na typ init skriptů - protože to jsou to, co ve skutečnosti vytvoříte, bez ohledu na to, co je spouští.

Jako vedlejší poznámku se můžete také podívat na OpenRC , jehož cílem je poskytnout strukturu init skriptů, která je kompatibilní jak se systémy Linux, tak BSD.

30
rozcietrzewiacz

Sám jsem vstoupil do tohoto problému sám a rozhodl se udělat několik testů. Plně souhlasím s odpovědí, že jeden by měl balíček pro každou distro samostatně, ale někdy existují praktické problémy, které tomu brání (v neposlední řadě pracovní síla).

Takže pro ty, kteří chtějí "auto-detekovat" tady je to, co jsem zjistil na omezeném počtu distros (více níže):

  • Můžete říci upstart od:

    [[ `/sbin/init --version` =~ upstart ]] && echo yes || echo no
    
  • Systemd můžete říct z:

    [[ `systemctl` =~ -\.mount ]] && echo yes || echo no
    
  • Můžete sys-v init říct z:

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

Zde jsou mé experimenty s následující příkazovou řádkou:

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

v případech ec2 (zahrnuji ID AMI z východu USA):

  • ArchLinux: pomocí systemd (od 2012.10.06 )
  • CentOS6.4 AMI-52009e3b: použití upstart
  • CentOS7 AMI-96a818fe: using systemd
  • Debian 6 AMI-80e915e9: pomocí sysv-init
  • Debian 7.5 AMI-2c886c44: pomocí sysv-init
  • Debian 7.6 GCE container-vm: using sysv-init
  • RHEL 6,5 AMI-8d756fe4: použití upstartu
  • SLES 11 AMI-e8084981: pomocí sysv-init
  • Ubuntu 10.04 AMI-6b350a02: pomocí upstartu
  • Ubuntu 12.04 AMI-b08b6cd8: pomocí upstartu
  • Ubuntu 14.04 AMI-a427efcc: pomocí upstartu
  • Ubuntu 14.10 a mladší: using systemd
  • AWS linux 2014.3.2 AMI-7c807d14: použití upstartu
  • Fedora 19 AMI-f525389c: using systemd
  • Fedora 20 AMI-21362b48: pomocí systemd

Jednoduše řečeno: Netvrdím, že je to spolehlivé! , téměř určitě to tak není. Také si všimněte, že pro větší pohodlí používám bash regexp zápasy, které nejsou dostupné všude. Výše uvedené je pro mě právě teď dost dobré. Pokud však najdete distro, kde selže, dejte mi prosím vědět a pokusím se to opravit, pokud existuje ECI AMI, který problém reprodukuje ...

61
TvE

Použití procesů

Při pohledu na výstup z několika příkazů ps, které mohou detekovat různé verze systemd & upstart, které by mohly být vytvořeny takto:

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

Věnovat pozornost názvu procesu, který je PID # 1, může také potenciálně vrhnout světlo na to, který systém init se používá. Na Fedoře 19 (která používá systemd, například:

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

Všimněte si, že to není init. Na Ubuntu s aktualizací je to stále /sbin/init.

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

POZNÁMKA: Ale používejte to s trochou opatrnosti. Není nic nastaveného v kameni, které říká, že konkrétní iniciační systém používaný na daném distro musí mít jako PID systemd # 1.

obecný

$ (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

Podívejte se na procesy s ppid 1 (děti iniciačního procesu). (Některá z) podřízených názvů procesů mohou ukazovat na použitý systém init.

Souborový systém

Pokud vyslýcháte spustitelný soubor init, můžete z něj získat také nějaké informace. Jednoduše analyzujte --version výstup. Například:

upstart

$ 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

POZNÁMKA: Skutečnost, že init není ve svém standardním umístění, je trochu nápověda/vyprávění. Vždy se nachází v /sbin/init na sysvinitových systémech.

sysvinit

$ type init
init is /sbin/init

Také toto:

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

Závěry

Zdá se, že neexistuje žádný způsob, jak to udělat, ale mohli byste formulovat sadu kontrol, které by určily, který systém iniciátoru používáte s poměrně vysokou mírou důvěry.

19
slm

Ne tak efektivní, ale zdá se, že to funguje.

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

Pokud se bude shodovat více řetězců, vytiskne více řádků, které by mohly být přeloženy do „Nelze hádat“. Řetězce použité v grepu se daly mírně modifikovat, ale při testování v následujících os jsem vždy dostal jednu řádku.

  • RHEL 6.4 [UPSTART]
  • RHEL ES 4 (Nahant Update 7) [SYSVINIT]
  • Ubuntu 16.04.1 LTS [SYSTEMD]
  • Ubuntu 14.04.2 LTS [UPSTART]
  • Vydání Fedory 23 (online prostředí) [SYSTEMD]
  • Debian GNU/Linux 7 (online prostředí) [SYSTEMD]
  • Centos 7.6 (VM) [SYSTEMD]

Zjednodušený přístup stejného řešení (ale zastaví se při prvním zápase)

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

Někdy je to stejně snadné jako použití ls:

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

Myslím, že pokud /sbin/init není symbolický odkaz, budete muset zkontrolovat další následující návrhy v jiných odpovědích.

Také jsem měl stejný problém a udělal jsem spoustu testů na některých strojích RedHat/CentOS/Debian/Ubuntu/Mint. To jsem skončil s dobrými výsledky.

  1. Najděte název spustitelného souboru pomocí PID 1:

    ps -p 1
    

    Pokud je to systemd nebo Upstart, problém vyřešen. Pokud se jedná o „init“, může to být symbolický odkaz nebo něco jiného než jméno předem. Pokračuj.

  2. Najděte skutečnou cestu ke spustitelnému souboru (funguje pouze jako root):

    ls -l `which init`
    

    Pokud init je symbolický odkaz na Upstart nebo systemd, problém vyřešen. V opačném případě je téměř jisté, že máte SysV init. Ale může to být špatně pojmenovaný spustitelný soubor. Pokračuj.

  3. Najděte balíček, který poskytuje spustitelný soubor. Bohužel je to závislé na distro:

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

Pokud tedy chcete skriptovat (nejzábavnější část, IMHO), jedná se o moje jednorázové vložky (spouštěné jako 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. To je to, co distro-specifické balíčky jsou pro. Správná instalace softwaru je mnohem více, než jen zjištění systému init. Mnoho distros používá SysVinit, ale ne všichni z nich píšou své iniciační skripty stejným způsobem. Správný způsob, jak to vyřešit, je zahrnout všechny různé varianty a poté je spojit pomocí souborů spec se jmény distro-specific závislostí pro rpm distros, deb soubory pro apt systémy atd. Téměř všechna distros mají nějakou specifikaci balíčku můžete psát, který zahrnuje závislosti, skripty, inicializační skripty atd. Zde znovu nevynalézejte kolo.

  2. Ne. Což nás přivádí zpět k 1. Pokud potřebujete bash, měla by to být závislost. Tuto kontrolu můžete zadat jako součást vašich konfiguračních skriptů, ale měla by být také v popisech balíčků.

pravit: Použijte příznaky ve vašem konfiguračním skriptu, například --with upstart nebo --without sysvinit. Vyberte rozumný výchozí stav, a pak si skripty, které dodávají váš software pro další distribuce, mohou zvolit spuštění s dalšími možnostmi.

3
Caleb

Pomůže také kontrola deskriptorů souborů. A je to z aktuálně spuštěného init (Debian stretch aktuálně umožňuje mít nainstalovaných více init systémů) :-)

$ 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

Pravděpodobně bezpečnějším způsobem kontroly busyboxu by bylo check /proc/1/exe, protože busybox obvykle používá symbolické odkazy:

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

Kontrola by tedy mohla být:

{ 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

Jednoduše se zapojíte do procesu s PID 1 vám řekne:

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

Nevím o jiných systémech než Debian (wheezy)/nebo Ubuntu (14.10.), Ale takové problémy testuji pomocí prostého starého příkazu file.

file /sbin/init

dát toto:

/sbin/init: symbolic link to 'upstart'

Debianové systémy s systemd (např. Sid) ukazují toto:

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

Na debian/sbin/init je symbolický odkaz na váš výchozí init

ls -l /sbin/init

vám poskytne informace, které hledáte.

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

Na Gentoo se podívejte na 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]

Pokud je to init, pak je iniciačním systémem OpenRC. Pokud je to systemd, pak je iniciačním systémem systemd.

Gentoo můžete detekovat pomocí [ -f /etc/gentoo-release ].

Další metodou na Gentoo je použití profile-config show, která ukáže, jaký výchozí profil se používá. Všechny profily kromě dvou konců v/systemd používají initRR. Mějte na paměti, že jsou pouze reprezentativní pro výchozí nastavení a je možné, že uživatel podnikl kroky k přepsání tohoto výchozího nastavení a nemusí naznačovat, že se spouštěcí program skutečně používá.

2
casey

Pro některé init systémy je to opravdu snadné. Pro systemd:

test -d /run/systemd/system

pro začátek:

initctl --version | grep -q upstart

pro cokoli jiného, ​​stačí předpokládat na základě distro (spuštění v OS X, sysvinit na Debianu, OpenRC na Gentoo).

1
CameronNemo

Pro systemd:

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

Moje řešení: zkontrolujte příkaz spuštěný jako proces s 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

V tuto chvíli mám přístup pouze k počítačům Init a SystemD, takže nemohu říct, jak bude detekován Upstart nebo macOS (OS X), ale budu pokračovat ve vyhledávání.

1
t0r0X

Zde je bash skript pro detekci. Momentálně kontroluje pouze upstart a systemd, ale mělo by být snadno rozšířitelné. Vzal jsem si to z kódu, který jsem přispěl do instalačního skriptu ovladače 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

Při testování systemd vs initd existuje mnoho nástrah kompatibility. Ve skutečnosti to funguje na OpenSuSE 42.1: ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init'

1
David Lakatos

Jak na to:

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

Testováno pouze na systémech, které mám: Ubuntu a 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