Detectar o sistema init usando o shell

79

Isso pode ter mais a ver com a detecção de sistemas operacionais, mas eu especificamente preciso do sistema init atualmente em uso no sistema.

O Fedora 15 e o Ubuntu agora usam o systemd, o Ubuntu costumava usar o Upstart (padrão longo de tempo até 15.04), enquanto outros usam variações do System V.

Eu tenho um aplicativo que estou escrevendo para ser um daemon de plataforma cruzada. Os scripts de init estão sendo gerados dinamicamente com base em parâmetros que podem ser passados no configure.

O que eu gostaria de fazer é gerar apenas o script para o sistema init específico que eles estão usando. Desta forma, o script de instalação pode ser executado razoavelmente sem parâmetros como root e o daemon pode ser "instalado" automaticamente.

Isso é o que eu criei:

  • Procure por systemd, upstart, etc em / bin
  • Comparar / proc / 1 / comm ao systemd, upstart, etc
  • Pergunte ao usuário

Qual seria a melhor maneira de fazer isso?

Tipo de relacionado, Posso depender do bash para estar na maioria de * nix ou ele é dependente de distribuição / SO?

Plataformas de destino:

  • Mac OS
  • Linux (todas as distribuições)
  • BSD (todas as versões)
  • Solaris, Minix e outros * nix
por beatgammit 07.08.2011 / 01:29

17 respostas

28

Para a segunda pergunta, a resposta é no e você deve dar uma olhada em Recursos para programação de shell portátil .

Quanto à primeira parte - antes de tudo, você certamente tem que ter cuidado. Eu diria executar vários testes para ter certeza - porque o fato de que alguém tem systemd (por ex.) Instalado, não significa que ele seja realmente usado como padrão %código%. Além disso, olhar para init pode ser enganador, porque algumas instalações de vários programas init podem fazer automaticamente /proc/1/comm um link simbólico ou mesmo uma versão renomeada de seu programa principal.

Talvez a coisa mais útil seja olhar o tipo de scripts de inicialização - porque eles são o que você realmente estará criando, não importa o que os execute.

Como uma nota lateral, você também pode dar uma olhada em OpenRC que visa fornecer uma estrutura de scripts de inicialização que é compatível com os sistemas Linux e BSD.

    
por 07.08.2011 / 02:03
48

Eu mesmo entrei nesse problema e decidi fazer alguns testes. Eu concordo plenamente com a resposta que se deve empacotar para cada distro separadamente, mas às vezes há questões práticas que impedem isso (não menos mão de obra).

Então, para aqueles que querem "detectar automaticamente" aqui está o que eu descobri em um conjunto limitado de distros (mais abaixo):

  • Você pode dizer ao upstart de:

    [[ '/sbin/init --version' =~ upstart ]] && echo yes || echo no
    
  • Você pode dizer ao systemd a partir de:

    [[ 'systemctl' =~ -\.mount ]] && echo yes || echo no
    
  • Você pode dizer ao init do sys-v a partir de:

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

Aqui estão minhas experiências com a seguinte linha de comando:

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

em instâncias ec2 (estou incluindo o id da AMI do oriente):

  • ArchLinux: usando o systemd (desde 2012.10.06 )
  • CentOS6.4 ami-52009e3b: usando upstart
  • CentOS7 ami-96a818fe: usando o systemd
  • Debian 6 ami-80e915e9: usando sysv-init
  • Debian 7.5 ami-2c886c44: usando o sysv-init
  • Debian 7.6 GCE container-vm: usando sysv-init
  • RHEL 6.5 ami-8d756fe4: usando upstart
  • SLES 11 ami-e8084981: usando o sysv-init
  • Ubuntu 10.04 ami-6b350a02: usando upstart
  • Ubuntu 12.04 ami-b08b6cd8: usando upstart
  • Ubuntu 14.04 ami-a427efcc: usando upstart
  • Ubuntu 14.10 e mais novo: usando o systemd
  • AWS linux 2014.3.2 ami-7c807d14: usando upstart
  • Fedora 19 ami-f525389c: usando systemd
  • Fedora 20 ami-21362b48: usando o systemd

Ufa. Só para ficar claro: Eu não estou afirmando que isso é infalível! , quase certamente não é. Observe também que, por conveniência, uso combinações regulares de expressões regulares, que não estão disponíveis em todos os lugares. O acima é bom o suficiente para mim agora :-) e espero que ajude os outros. No entanto, se você encontrar uma distro onde ela falhar, avise-me e tentarei corrigi-la se houver um AMI do EC2 que reproduza o problema ...

    
por 25.10.2014 / 00:23
17

Usando processos

Analisando a saída de alguns comandos ps que podem detectar as várias versões de systemd & upstart , que pode ser criado da seguinte forma:

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

Prestar atenção ao nome do processo que é o PID # 1 também pode esclarecer qual sistema init está sendo usado. No Fedora 19 (que usa systemd , por exemplo:

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

Observe que não é init . No Ubuntu com Upstart ainda é /sbin/init .

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

NOTA: Mas use isso com um pouco de cautela. Não há nada definido na pedra que diga que um determinado sistema de inicialização sendo usado em uma determinada distribuição tenha para ter systemd como o PID # 1.

genérico

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

Veja os processos com o ppid 1 (filhos do processo init). (Alguns dos) nomes de processos filhos podem apontar para o sistema init em uso.

O sistema de arquivos

Se você interrogar o executável init , poderá obter algumas informações dele também. Simplesmente analisando a saída --version . Por exemplo:

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

NOTA: O fato de init não estar em sua localização padrão é um pouco de hint / tell. Está sempre localizado em /sbin/init nos sistemas sysvinit.

sysvinit

$ type init
init is /sbin/init

Também isso:

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

Conclusões

Portanto, não parece haver uma maneira de fazê-lo, mas você poderia formular um conjunto de verificações que identificaria qual sistema de init você está usando com um alto grau de confiança.

    
por 10.02.2014 / 21:24
9

Não tão eficiente, mas parece que funciona.

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

Ele imprimirá mais linhas se mais de uma string corresponder, o que pode ser traduzido como "Não é possível adivinhar". As strings usadas no grep poderiam ser levemente modificadas, mas quando testadas nos seguintes sistemas operacionais, sempre obtive uma linha.

  • RHEL 6.4 [UPSTART]
  • RHEL ES 4 (Nahant Update 7) [SYSVINIT]
  • Ubuntu 16.04.1 LTS [SYSTEMD]
  • Ubuntu 14.04.2 LTS [UPSTART]
  • Fedora release 23 (shell online) [SYSTEMD]
  • Debian GNU / Linux 7 (shell online) [SYSTEMD]

Uma abordagem mais simplista da mesma solução (mas para na primeira partida)

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

Às vezes, é tão fácil quanto usar ls :

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

Eu suponho que se /sbin/init não for um link simbólico, você terá que verificar mais seguindo sugestões em outras respostas.

    
por 05.09.2014 / 11:08
3
  1. É para isso que servem os pacotes específicos de distribuição. Há muito mais para instalar o software corretamente do que apenas detectar o sistema init. Muitas distros usam o SysVinit, mas nem todas escrevem seus scripts de inicialização da mesma maneira. A maneira correta de resolver isso é incluir todas as variantes diferentes e agrupá-las usando arquivos de especificação com nomes de dependência específicos de distro para distribuições de rpm, arquivos deb para sistemas baseados em apt, etc. Quase todas as distribuições têm algum tipo de especificação de pacote pode escrever que inclui dependências, scripts, scripts de inicialização, etc. Não reinvente a roda aqui.

  2. Não. O que nos traz de volta para 1. Se você precisa de bash, deve ser uma dependência. Você pode especificar essa verificação como parte de seus scripts de configuração, mas também deve estar nas descrições de pacotes.

Editar: use sinalizadores em seu script de configuração, como --with upstart ou --without sysvinit . Escolha um padrão são, então os scripts que empacotam seu software para outras distros podem optar por executar isso com outras opções.

    
por 07.08.2011 / 09:21
2

Eu também tive esse mesmo problema, e fiz muitos testes em algumas máquinas RedHat / CentOS / Debian / Ubuntu / Mint. Foi com isso que acabei, com bons resultados.

  1. Encontre o nome do executável com o PID 1:

    ps -p 1
    

    Se é systemd ou Upstart, problema resolvido. Se é "init", pode ser um symlink ou algo diferente de um nome inicial. Continue.

  2. Encontre o caminho real para o executável (só funciona como root):

    ls -l 'which init'
    

    Se init for um symlink para Upstart ou systemd, problema resolvido. Caso contrário, é quase certo que você tem o init do SysV. Mas pode ser um executável com nome errado. Continue.

  3. Encontre o pacote que fornece o executável. Infelizmente, isso depende da distribuição:

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

Então, se você quiser roteirizar isso (a parte mais engraçada, IMHO), estes são meus one-liners (executados como 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  
    
por 25.04.2016 / 18:30
2

No Gentoo, dê uma olhada no 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]

Se for init , o sistema init será OpenRC . Se for systemd , o sistema init será systemd .

Você pode detectar o Gentoo com [ -f /etc/gentoo-release ] .

Outro método no Gentoo é usar profile-config show , que mostrará qual perfil padrão está em uso. Todos os perfis, exceto os dois que terminam em / systemd, usam o init do OpenRC. Tenha em mente que estes são apenas representativos de um padrão e é possível que o usuário tenha tomado medidas para substituir esse padrão e pode não ser indicativo do gerenciador de init realmente em uso.

    
por 10.02.2014 / 21:37
2

No debian / sbin / init é um symlink para o seu init padrão, então

ls -l /sbin/init

fornecerá as informações que você está procurando.

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

Basta entrar no processo com o PID 1:

strings /proc/1/exe |grep -q sysvinit
strings /proc/1/exe |grep -q systemd
    
por 04.11.2015 / 10:13
2

Também inspecionar descritores de arquivos pode ajudar. E é de fato rodar o init (a extensão do Debian atualmente permite ter mais sistemas init instalados): -)

$ 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

Provavelmente, uma maneira mais segura de verificar o busybox seria check /proc/1/exe , pois o busybox geralmente usa links simbólicos:

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

Portanto, o cheque pode ser:

{ 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"
    
por 14.08.2015 / 14:04
2

Não sei sobre outros sistemas, em seguida, Debian (wheezy) / ou Ubuntu (14.10.), mas eu testo esses problemas com o antigo comando file .

file /sbin/init

dê isso:

/sbin/init: symbolic link to 'upstart'

Sistemas Debian com systemd (por exemplo, sid) mostram isso:

# file /sbin/init 
/sbin/init: symbolic link to /lib/systemd/systemd
    
por 07.10.2014 / 14:23
1

Isso é realmente fácil para alguns sistemas init. Para systemd:

test -d /run/systemd/system

para upstart:

initctl --version | grep -q upstart

para qualquer outra coisa, você pode simplesmente assumir baseado na distro (launchd no OS X, sysvinit no Debian, OpenRC no Gentoo).

    
por 03.06.2014 / 04:51
1

Aqui está um script bash para fazer a detecção. Ele verifica apenas o upstart e o systemd no momento, mas deve ser fácil de estender. Eu tomei este do código que eu contribuí para o script de instalação do driver 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
}
    
por 13.03.2016 / 05:43
1

Há muitas armadilhas de compatibilidade ao testar o systemd vs o initd. Isso realmente funciona no OpenSuSE 42.1: ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init'

    
por 15.04.2016 / 10:18
1

Para systemd :

if [[ 'systemctl is-system-running' =~ running ]]; then echo using systemd; fi
    
por 26.11.2016 / 17:58
0

Minha solução: verifique o comando executando como processo com o 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

No momento, tenho acesso somente a máquinas Init e SystemD, então não posso dizer como o Upstart ou o MacOS (OS X) serão detectados, mas continuarei pesquisando.

    
por 31.07.2018 / 16:24