web-dev-qa-db-ja.com

シェルを使用してinitシステムを検出する

これはオペレーティングシステムの検出に関係している可能性がありますが、システムで現在使用されているinitシステムが特に必要です。

Fedora 15とUbuntuはsystemdを使用し、UbuntuはUpstart(15.04までの長いデフォルト)を使用していましたが、他はSystem Vのバリエーションを使用しています。

クロスプラットフォームデーモンになるように作成しているアプリケーションがあります。 initスクリプトは、configureで渡すことができるパラメーターに基づいて動的に生成されます。

私がやりたいのは、彼らが使用している特定のinitシステム用のスクリプトを生成することだけです。このようにして、インストールスクリプトをrootとしてパラメータなしで合理的に実行でき、デーモンを自動的に「インストール」できます。

これは私が思いついたものです:

  • / binでsystemd、upstartなどを検索します
  • / proc/1/commをsystemd、upstartなどと比較します
  • ユーザーに尋ねる

これを行うための最良のクロス/プラットフォームの方法は何ですか?

関連する種類* nixの大部分をbashに依存することはできますか、それともディストリビューション/ OS依存ですか?

対象プラットフォーム:

  • マックOS
  • Linux(すべてのディストリビューション)
  • BSD(すべてのバージョン)
  • Solaris、Minix、およびその他の* nix
96
beatgammit

2番目の質問の答えはnoであり、 ポータブルシェルプログラミングのリソース を確認する必要があります。

最初の部分については-まず第一に、あなたは確かに注意する必要があります。私は確認するためにいくつかのテストを実行します-誰かがsystemd(例えば)をインストールしているという事実のため、実際にデフォルトとして使用されるという意味ではありませんinit。また、/proc/1/commは誤解を招く可能性があります。これは、さまざまなinitプログラムのインストールによっては、自動的に/sbin/init symlinkハードリンク、またはメインプログラムの名前が変更されたバージョン。

おそらく、最も役立つのは、initスクリプトのタイプを確認することでしょう。これらは、何を実行しても、実際に作成するものだからです。

補足として、LinuxとBSDの両方のシステムと互換性のあるinitスクリプトの構造を提供することを目的とする OpenRC もご覧ください。

30
rozcietrzewiacz

私はこの問題に自分で踏み込み、いくつかのテストを行うことにしました。ディストリビューションごとに個別にパッケージ化する必要があるという答えには完全に同意しますが、それを妨げる実際的な問題がある場合もあります(特に人的資源)。

したがって、「自動検出」したい人のために、ここに私が見つけたものがあります限られたディストリビューションのセット(以下でさらに詳しく):

  • Upstartは次の場所からわかります。

    [[ `/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インスタンス上(私はus-east AMI IDを含めています):

  • 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

プロセスの使用

pssystemdのさまざまなバージョンを検出できるいくつかのupstartコマンドの出力を確認します。次のように作成できます。

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

注:ただし、これは少し注意して使用してください。特定のディストリビューションで使用されている特定のinitシステムがPIDとしてsystemdを持っていると言っているような具体的な設定はありません#1。

generic

$ (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の出力を解析するだけです。例えば:

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

注:initが標準の場所にないという事実は、ちょっとしたヒントです。 sysvinitシステムでは常に/sbin/initにあります。

sysvinit

$ type init
init is /sbin/init

これも:

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

結論

したがって、それを行うための1つの方法はないように見えますが、かなり高い信頼度で使用している初期化システムを特定する一連のチェックを作成できます。

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で使用される文字列はわずかに変更できますが、次のOSでテストすると、常に1行表示されます。

  • RHEL 6.4 [アップスタート]
  • RHEL ES 4(Nahant Update 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はシンボリックリンクではありません。他の回答で以下の提案をさらに確認する必要があります。

私も同じ問題を抱えており、一部の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)、これらは私の1行(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. これがディストリビューション固有のパッケージの目的です。ソフトウェアを適切にインストールすることには、単にinitシステムを検出するだけではありません。多くのディストリビューションはSysVinitを使用していますが、すべてが同じ方法でinitスクリプトを作成しているわけではありません。これを解決する適切な方法は、さまざまなバリアントをすべて含めてから、rpmディストリビューションのディストリビューション固有の依存関係名を持つスペックファイル、aptベースのシステムのdebファイルなどを使用してバンドルすることです。ほとんどすべてのディストリビューションには、ある種のパッケージ仕様があります。依存関係、スクリプト、initスクリプトなどを含む書き込みが可能です。ここでホイールを再発明しないでください。

  2. いいえ。これで1に戻ります。bashが必要な場合は、依存関係である必要があります。このチェックは設定スクリプトの一部として指定できますが、パッケージの説明にも含める必要があります。

編集:--with upstart--without sysvinitなどの構成スクリプトでフラグを使用します。適切なデフォルトを選択すると、他のディストリビューション向けにソフトウェアをパッケージ化するスクリプトが、これを他のオプションで実行することを選択できます。

3
Caleb

また、ファイル記述子の検査も役立ちます。そして、それは実際にinitを実行することによるものです(Debianストレッチは現在、より多くの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

おそらく、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"
3
pevik

PID 1を使用してプロセスに取り組むだけで、次のことがわかります。

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

Debian(wheezy)/ Ubuntu(14.10。)以外の他のシステムについては知りませんが、私はそのような問題を単純な古いfileコマンドでテストします。

file /sbin/init

これを与える:

/sbin/init: symbolic link to 'upstart'

systemd(例:sid)を備えたDebianシステムはこれを示します:

# 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の場合、initシステムはOpenRCです。 systemdの場合、initシステムはsystemdです。

Gentooは[ -f /etc/gentoo-release ]で検出できます。

Gentooのもう1つの方法は、profile-config showを使用することです。これにより、使用されているデフォルトのプロファイルが表示されます。/systemdで終わる2つを除くすべてのプロファイルは、OpenRC initを使用します。これらはデフォルトを表すだけであり、ユーザーがそのデフォルトをオーバーライドする手順を実行した可能性があり、実際に使用されているinitマネージャーを示していない可能性があることに注意してください。

2
casey

これは、いくつかのinitシステムでは本当に簡単です。 systemdの場合:

test -d /run/systemd/system

新興企業向け:

initctl --version | grep -q upstart

それ以外の場合は、ディストリビューションに基づいて想定できます(OS Xで起動、Debianでsysvinit、GentooでOpenRC)。

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と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