使用 shell 检测 init 系统

使用 shell 检测 init 系统

这可能与检测操作系统有更多关系,但我特别需要系统上当前使用的 init 系统。

Fedora 15 和 Ubuntu 现在使用 systemd,Ubuntu 过去使用 Upstart(一直默认到 15.04),而其他版本则使用 System V 的变体。

我正在编写一个应用程序作为跨平台守护程序。初始化脚本是根据配置时传入的参数动态生成的。

我想做的只是为他们正在使用的特定初始化系统生成脚本。这样,安装脚本可以在没有参数的情况下以 root 身份合理运行,并且可以自动“安装”守护进程。

这就是我想出的:

  • 在 /bin 中搜索 systemd、upstart 等
  • 将 /proc/1/comm 与 systemd、upstart 等进行比较
  • 询问用户

执行此操作的最佳跨/平台方式是什么?

有点相关,我可以依赖 bash 来支持大多数 *nix 还是依赖于发行版/操作系统?

目标平台:

  • 苹果系统
  • Linux(所有发行版)
  • BSD(所有版本)
  • Solaris、Minix 和其他 *nix

答案1

我自己也遇到了这个问题,并决定做一些测试。我完全同意应该为每个发行版单独打包的答案,但有时存在实际问题(尤其是人力)。

因此,对于那些想要“自动检测”的人,这就是我发现的在一组有限的发行版上(更多内容见下文):

  • 你可以从以下方面辨别暴发户:

    [[ `/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 容器虚拟机:使用 sysv-init
  • RHEL 6.5 ami-8d756fe4:使用新贵
  • 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:使用新贵
  • Fedora 19 ami-f525389c:使用 systemd
  • Fedora 20 ami-21362b48:使用 systemd

需要明确的是:我并不是说这是万无一失的!,几乎可以肯定不是。另请注意,为了方便起见,我使用 bash 正则表达式匹配,但并非所有地方都可用。以上对我现在来说已经足够了。但是,如果您发现某个发行版出现故障,请告诉我,如果有 EC2 AMI 重现该问题,我将尝试修复它...

答案2

对于第二个问题,答案是你应该看看可移植 shell 编程的资源

至于第一部分——首先,你一定要小心。我会说进行多项测试以确保- 因为事实上有人确实有systemd(例如)已安装,并不意味着它实际上被用作默认值init。此外,查看/proc/1/comm可能会产生误导,因为各种 init 程序的某些安装可以自动创建/sbin/init符号链接硬链接,甚至是其主程序的重命名版本。

也许最有用的事情可能是查看 init 脚本类型 - 因为这些是您实际要创建的内容,无论运行它们的是什么。

顺便提一下,你也可以看看开放式RC其目的是提供一种兼容 Linux 和 BSD 系统的 init 脚本结构。

答案3

使用流程

查看几个ps可以检测systemd&的各种版本的命令的输出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

系统

$ 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。在带有 Upstart 的 Ubuntu 上它仍然是/sbin/init.

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

笔记:但使用它时要小心一点。没有任何一成不变的东西表明特定的 init 系统正在给定的发行版上使用作为systemdPID #1。

通用的

$ (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输出。例如:

暴发户

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

系统

$ type init
init is /usr/sbin/init

笔记:事实上,它init不在标准位置,这有点暗示/说明。它始终位于/sbin/initsysvinit 系统中。

系统维尼特

$ type init
init is /sbin/init

还有这个:

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

结论

因此,似乎没有任何一种方法可以做到这一点,但您可以制定一套检查,以相当高的置信度查明您正在使用哪个初始化系统。

答案4

有时它就像使用一样简单ls :

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

我想如果/sbin/init不是符号链接,您将不得不进一步检查其他答案中的以下建议。

相关内容