これはオペレーティングシステムの検出に関係している可能性がありますが、システムで現在使用されているinitシステムが特に必要です。
Fedora 15とUbuntuはsystemdを使用し、UbuntuはUpstart(15.04までの長いデフォルト)を使用していましたが、他はSystem Vのバリエーションを使用しています。
クロスプラットフォームデーモンになるように作成しているアプリケーションがあります。 initスクリプトは、configureで渡すことができるパラメーターに基づいて動的に生成されます。
私がやりたいのは、彼らが使用している特定のinitシステム用のスクリプトを生成することだけです。このようにして、インストールスクリプトをrootとしてパラメータなしで合理的に実行でき、デーモンを自動的に「インストール」できます。
これは私が思いついたものです:
これを行うための最良のクロス/プラットフォームの方法は何ですか?
関連する種類* nixの大部分をbashに依存することはできますか、それともディストリビューション/ OS依存ですか?
対象プラットフォーム:
2番目の質問の答えはnoであり、 ポータブルシェルプログラミングのリソース を確認する必要があります。
最初の部分については-まず第一に、あなたは確かに注意する必要があります。私は確認するためにいくつかのテストを実行します-誰かがsystemd(例えば)をインストールしているという事実のため、実際にデフォルトとして使用されるという意味ではありませんinit
。また、/proc/1/comm
は誤解を招く可能性があります。これは、さまざまなinitプログラムのインストールによっては、自動的に/sbin/init
symlinkハードリンク、またはメインプログラムの名前が変更されたバージョン。
おそらく、最も役立つのは、initスクリプトのタイプを確認することでしょう。これらは、何を実行しても、実際に作成するものだからです。
補足として、LinuxとBSDの両方のシステムと互換性のあるinitスクリプトの構造を提供することを目的とする OpenRC もご覧ください。
私はこの問題に自分で踏み込み、いくつかのテストを行うことにしました。ディストリビューションごとに個別にパッケージ化する必要があるという答えには完全に同意しますが、それを妨げる実際的な問題がある場合もあります(特に人的資源)。
したがって、「自動検出」したい人のために、ここに私が見つけたものがあります限られたディストリビューションのセット(以下でさらに詳しく):
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を含めています):
明確にするために:これが絶対確実であるとは主張していません!、それはほぼ間違いなくそうではありません。また、便宜上、どこでも利用できるわけではないbash正規表現一致を使用していることにも注意してください。上記は今のところ私には十分です。ただし、失敗したディストリビューションを見つけた場合はお知らせください。問題を再現するEC2 AMIがある場合は修正を試みます...
ps
&systemd
のさまざまなバージョンを検出できるいくつかの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つの方法はないように見えますが、かなり高い信頼度で使用している初期化システムを特定する一連のチェックを作成できます。
それほど効率的ではありませんが、私はそれがうまくいくようです。
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行表示されます。
同じソリューションのより単純なアプローチ(ただし、最初の一致で停止します)
strings /sbin/init |
awk 'match($0, /(upstart|systemd|sysvinit)/) { print toupper(substr($0, RSTART, RLENGTH));exit; }'
場合によっては、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マシンで多くのテストを行いました。これは私が最終的に得たものであり、良い結果が得られました。
PID 1の実行可能ファイルの名前を見つけます。
ps -p 1
SystemdまたはUpstartの場合、問題は解決しました。 「init」の場合、シンボリックリンクか、事前の名前以外の何かである可能性があります。どうぞ。
実行可能ファイルの実際のパスを見つけます(rootとしてのみ機能します)。
ls -l `which init`
init
がUpstartまたはsystemdへのシンボリックリンクである場合、問題は解決しました。それ以外の場合は、SysV initがあることはほぼです。しかし、それは誤った名前の実行可能ファイルである可能性があります。どうぞ。
実行可能ファイルを提供するパッケージを見つけます。残念ながら、これはディストリビューションに依存しています:
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
これがディストリビューション固有のパッケージの目的です。ソフトウェアを適切にインストールすることには、単にinitシステムを検出するだけではありません。多くのディストリビューションはSysVinitを使用していますが、すべてが同じ方法でinitスクリプトを作成しているわけではありません。これを解決する適切な方法は、さまざまなバリアントをすべて含めてから、rpmディストリビューションのディストリビューション固有の依存関係名を持つスペックファイル、aptベースのシステムのdebファイルなどを使用してバンドルすることです。ほとんどすべてのディストリビューションには、ある種のパッケージ仕様があります。依存関係、スクリプト、initスクリプトなどを含む書き込みが可能です。ここでホイールを再発明しないでください。
いいえ。これで1に戻ります。bashが必要な場合は、依存関係である必要があります。このチェックは設定スクリプトの一部として指定できますが、パッケージの説明にも含める必要があります。
編集:--with upstart
や--without sysvinit
などの構成スクリプトでフラグを使用します。適切なデフォルトを選択すると、他のディストリビューション向けにソフトウェアをパッケージ化するスクリプトが、これを他のオプションで実行することを選択できます。
また、ファイル記述子の検査も役立ちます。そして、それは実際に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"
PID 1を使用してプロセスに取り組むだけで、次のことがわかります。
strings /proc/1/exe |grep -q sysvinit
strings /proc/1/exe |grep -q systemd
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
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
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マネージャーを示していない可能性があることに注意してください。
これは、いくつかのinitシステムでは本当に簡単です。 systemdの場合:
test -d /run/systemd/system
新興企業向け:
initctl --version | grep -q upstart
それ以外の場合は、ディストリビューションに基づいて想定できます(OS Xで起動、Debianでsysvinit、GentooでOpenRC)。
systemd
の場合:
if [[ `systemctl is-system-running` =~ running ]]; then echo using systemd; fi
私の解決策: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)がどのように検出されるのかわかりませんが、引き続き検索します。
検出を行うための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
}
Systemdとinitdをテストする場合、互換性に関する多くの落とし穴があります。これは実際にはOpenSuSE 42.1で動作します:ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init'
これはどうですか?
strings $(\ps -p 1 o cmd= | cut -d" " -f1) | egrep -o "upstart|sysvinit|systemd" | head -1
私が持っているシステムでのみテストされています:UbuntuとSailfishOS。
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
}