web-dev-qa-db-fra.com

Détecter le système d'initialisation à l'aide du shell

Cela peut avoir plus à voir avec la détection des systèmes d'exploitation, mais j'ai spécifiquement besoin du système init actuellement utilisé sur le système.

Fedora 15 et Ubuntu utilisent désormais systemd, Ubuntu utilisait Upstart (défaut de longue date jusqu'au 15.04), tandis que d'autres utilisent des variantes de System V.

J'ai une application que j'écris pour être un démon multiplateforme. Les scripts d'initialisation sont générés dynamiquement en fonction de paramètres pouvant être transmis lors de la configuration.

Ce que j'aimerais faire, c'est seulement générer le script pour le système d'initialisation particulier qu'ils utilisent. De cette façon, le script d'installation peut être exécuté raisonnablement sans paramètres en tant que root et le démon peut être "installé" de manière automatique.

Voici ce que j'ai trouvé:

  • Recherchez systemd, upstart, etc. dans/bin
  • Comparez/proc/1/comm à systemd, upstart, etc.
  • Demandez à l'utilisateur

Quelle serait la meilleure façon de faire cela sur plusieurs plates-formes?

Type de relation, Puis-je dépendre de bash pour être sur la majorité de * nix ou est-ce que cela dépend de la distribution/du système d'exploitation?

Plateformes cibles:

  • Mac OS
  • Linux (toutes les distributions)
  • BSD (toutes versions)
  • Solaris, Minix et autres * nix
96
beatgammit

Pour la deuxième question, la réponse est non et vous devriez jeter un oeil à Ressources pour la programmation Shell portable .

En ce qui concerne la première partie - tout d'abord, vous devez certainement être prudent. Je dirais effectuez plusieurs tests pour vous assurer - parce que le fait que quelqu'un ait systemd (par exemple) installé, ne signifie pas qu'il est en fait utilisé par défaut init. De plus, en regardant /proc/1/comm peut être trompeur, car certaines installations de divers programmes d'initialisation peuvent automatiquement rendre /sbin/init un lien symbolique ou même une version renommée de leur programme principal.

Peut-être que la chose la plus utile pourrait être de regarder le type de scripts d'initialisation - parce que c'est ce que vous allez réellement créer, peu importe ce qui les exécute.

En guise de remarque, vous pouvez également consulter OpenRC qui vise à fournir une structure de scripts d'initialisation compatible avec les systèmes Linux et BSD.

30
rozcietrzewiacz

Je suis moi-même entré dans ce problème et j'ai décidé de faire quelques tests. Je suis entièrement d'accord avec la réponse selon laquelle on devrait emballer séparément chaque distribution, mais parfois il y a des problèmes pratiques qui empêchent cela (notamment la main-d'œuvre).

Donc, pour ceux qui veulent "détecter automatiquement", voici ce que j'ai découvert sur un ensemble limité de distributions (plus ci-dessous):

  • Vous pouvez dire par le biais de:

    [[ `/sbin/init --version` =~ upstart ]] && echo yes || echo no
    
  • Vous pouvez indiquer à systemd:

    [[ `systemctl` =~ -\.mount ]] && echo yes || echo no
    
  • Vous pouvez indiquer à sys-v init:

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

Voici mes expériences avec la ligne de commande suivante:

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

sur les instances ec2 (j'inclus l'identifiant AMI us-east):

  • ArchLinux: utilisation de systemd (depuis 2012.10.06 )
  • CentOS6.4 AMI-52009e3b: utilisation par le haut
  • CentOS7 AMI-96a818fe: utilisation de systemd
  • Debian 6 AMI-80e915e9: utiliser sysv-init
  • Debian 7.5 AMI-2c886c44: utiliser sysv-init
  • Debian 7.6 GCE container-vm: utiliser sysv-init
  • RHEL 6.5 AMI-8d756fe4: utiliser un parvenu
  • SLES 11 AMI-e8084981: utilisation de sysv-init
  • Ubuntu 10.04 AMI-6b350a02: utiliser upstart
  • Ubuntu 12.04 AMI-b08b6cd8: utiliser upstart
  • Ubuntu 14.04 AMI-a427efcc: utiliser upstart
  • Ubuntu 14.10 et moins: utilisation de systemd
  • AWS linux 2014.3.2 AMI-7c807d14: à l'aide de upstart
  • Fedora 19 AMI-f525389c: utilisation de systemd
  • Fedora 20 AMI-21362b48: utilisation de systemd

Juste pour être clair: Je ne prétends pas que c'est infaillible! , ce n'est certainement pas le cas. Notez également que pour plus de commodité, j'utilise des correspondances d'expression régulière bash, qui ne sont pas disponibles partout. Ce qui précède est assez bon pour moi en ce moment. Cependant, si vous trouvez une distribution où elle échoue, faites-le moi savoir et je vais essayer de la corriger s'il y a une AMI EC2 qui reproduit le problème ...

61
TvE

Utilisation de processus

En regardant la sortie de quelques commandes ps qui peuvent détecter les différentes versions de systemd & upstart, qui pourraient être conçues comme ceci:

parvenu

$ 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

Prêter attention au nom du processus qui est PID # 1 peut également éclairer le système d'initialisation utilisé. Sur Fedora 19 (qui utilise systemd, par exemple:

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

Notez que ce n'est pas init. Sur Ubuntu avec Upstart c'est toujours /sbin/init.

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

REMARQUE: Mais utilisez ceci avec un peu de prudence. Il n'y a rien de figé qui dit qu'un système d'initialisation particulier utilisé sur une distribution donnée a pour avoir systemd comme PID #1.

générique

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

Regardez les processus avec ppid 1 (enfants du processus init). (Certains des) noms de processus enfant peuvent pointer vers le système init utilisé.

Le système de fichiers

Si vous interrogez l'exécutable init, vous pouvez également en obtenir des informations. Analyser simplement le --version production. Par exemple:

parvenu

$ 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

REMARQUE: Le fait que init ne se trouve pas à son emplacement standard est un peu un indice. Il est toujours situé dans /sbin/init sur les systèmes sysvinit.

sysvinit

$ type init
init is /sbin/init

Aussi ceci:

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

Conclusions

Il ne semble donc pas y avoir une seule façon de le faire, mais vous pouvez formuler une suite de vérifications qui identifierait le système d'initialisation que vous utilisez avec un degré de confiance assez élevé.

19
slm

Pas si efficace que ça mais ça semble marcher.

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

Il imprimera plus de lignes si plusieurs chaînes correspondent, ce qui pourrait être traduit par "Je ne peux pas deviner". Les chaînes utilisées dans grep peuvent être légèrement modifiées, mais lorsqu'elles sont testées dans le système d'exploitation suivant, j'ai toujours une ligne.

  • RHEL 6.4 [UPSTART]
  • RHEL ES 4 (Nahant Update 7) [SYSVINIT]
  • Ubuntu 16.04.1 LTS [SYSTEMD]
  • Ubuntu 14.04.2 LTS [UPSTART]
  • Fedora version 23 (shell en ligne) [SYSTEMD]
  • Debian GNU/Linux 7 (shell en ligne) [SYSTEMD]
  • Centos 7.6 (VM) [SYSTEMD]

Une approche plus simpliste de la même solution (mais elle s'arrête au premier match)

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

Parfois, c'est aussi simple que d'utiliser ls:

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

Je suppose que si /sbin/init n'est pas un lien symbolique, vous devrez vérifier les suggestions suivantes dans d'autres réponses.

10

J'ai également eu ce même problème et j'ai fait beaucoup de tests sur certaines machines RedHat/CentOS/Debian/Ubuntu/Mint. C'est ce que j'ai fini avec de bons résultats.

  1. Trouvez le nom de l'exécutable avec PID 1:

    ps -p 1
    

    Si c'est systemd ou Upstart, le problème est résolu. Si c'est "init", il peut s'agir d'un lien symbolique ou autre chose qu'un nom initial. Aller de l'avant.

  2. Trouvez le vrai chemin pour l'exécutable (ne fonctionne qu'en root):

    ls -l `which init`
    

    Si init est un lien symbolique vers Upstart ou systemd, problème résolu. Sinon, il est presque certain que vous avez SysV init. Mais il peut s'agir d'un exécutable mal nommé. Aller de l'avant.

  3. Trouvez le package qui fournit l'exécutable. Malheureusement, cela dépend de la distribution:

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

Ensuite, si vous voulez écrire cela (la partie la plus drôle, à mon humble avis), ce sont mes one-liners (exécutés en tant que 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. C'est à cela que servent les packages spécifiques à la distribution. Installer un logiciel correctement ne se résume pas à détecter le système init. De nombreuses distributions utilisent SysVinit mais elles n'écrivent pas toutes leurs scripts d'initialisation de la même manière. La bonne façon de résoudre ce problème est d'inclure toutes les différentes variantes, puis de les regrouper en utilisant des fichiers de spécifications avec des noms de dépendance spécifiques aux distributions pour les distributions rpm, les fichiers deb pour les systèmes basés sur apt, etc. Presque toutes les distributions ont une sorte de spécification de package que vous peut écrire qui inclut des dépendances, des scripts, des scripts d'initialisation, etc. Ne réinventez pas la roue ici.

  2. Non. Ce qui nous ramène à 1. Si vous avez besoin de bash, ce devrait être une dépendance. Vous pouvez spécifier cette vérification dans le cadre de vos scripts de configuration, mais elle devrait également figurer dans les descriptions des packages.

Edit: Utilisez des indicateurs sur votre script de configuration tels que --with upstart ou --without sysvinit. Choisissez une valeur par défaut saine, puis les scripts qui conditionnent votre logiciel pour d'autres distributions peuvent choisir de l'exécuter avec d'autres options.

3
Caleb

L'inspection des descripteurs de fichiers peut également aider. Et c'est en fait en train de lancer init (Debian stretch permet actuellement d'installer plus de systèmes init) :-)

$ 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

Un moyen probablement plus sûr de vérifier la présence d'une boîte occupée serait de check /proc/1/exe, comme busybox utilise généralement des liens symboliques:

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

La vérification pourrait donc être:

{ 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

Le simple fait de vous lancer dans le processus avec PID 1 vous dira:

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

Je ne connais pas d'autres systèmes que Debian (wheezy)/ou Ubuntu (14.10.) Mais je teste de tels problèmes avec la vieille commande file.

file /sbin/init

donne ça:

/sbin/init: symbolic link to 'upstart'

Les systèmes Debian avec systemd (par exemple sid) montrent ceci:

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

Sur debian/sbin/init est un lien symbolique vers votre init par défaut donc

ls -l /sbin/init

vous donnera les informations que vous recherchez.

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

Sur Gentoo, jetez un œil au 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]

Si c'est init, alors le système init est OpenRC. Si c'est systemd, alors le système init est systemd.

Vous pouvez détecter Gentoo avec [ -f /etc/gentoo-release ].

Une autre méthode sur Gentoo consiste à utiliser profile-config show, qui montrera quel profil par défaut est utilisé. Tous les profils, à l'exception des deux se terminant par/systemd, utilisent l'init OpenRC. Gardez à l'esprit que ceux-ci ne sont représentatifs que d'une valeur par défaut et il est possible que l'utilisateur ait pris des mesures pour remplacer cette valeur par défaut et peut ne pas indiquer le gestionnaire d'initialisation réellement utilisé.

2
casey

C'est vraiment facile pour certains systèmes d'initialisation. Pour systemd:

test -d /run/systemd/system

parvenu:

initctl --version | grep -q upstart

pour tout le reste, vous pouvez simplement supposer basé sur la distribution (launchd sur OS X, sysvinit sur Debian, OpenRC sur Gentoo).

1
CameronNemo

Pour systemd:

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

Ma solution: vérifiez la commande exécutée en tant que processus avec l'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

Pour le moment, je n'ai accès qu'aux machines Init et SystemD, donc je ne peux pas dire comment Upstart ou macOS (OS X) seront détectés, mais je continuerai à chercher.

1
t0r0X

Voici un script bash pour effectuer la détection. Il ne vérifie pour le moment que upstart et systemd, mais devrait être facile à étendre. J'ai pris cela à partir du code que j'ai contribué au script d'installation du pilote 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

Il existe de nombreux pièges de compatibilité lors du test de systemd vs initd. Cela fonctionne réellement sur OpenSuSE 42.1: ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init'

1
David Lakatos

How'bout celui-ci:

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

Testé uniquement sur les systèmes que j'ai: Ubuntu et 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