it-swarm.cn

使用shell检测init系统

这可能与检测操作系统有关,但是我特别需要系统上当前使用的初始化系统。

Fedora 15和Ubuntu现在使用systemd,Ubuntu以前使用Upstart(长期使用默认时间为15.04),而其他人则使用System V的变体。

我有一个要编写为跨平台守护程序的应用程序。初始化脚本是根据可在configure上传递的参数动态生成的。

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

这是我想出的:

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

这样做的最佳跨平台方式是什么?

相关种类我可以依赖bash来依赖大多数* nix还是依赖于发行版/ OS?

目标平台:

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

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

至于第一部分-首先,您一定要小心。我会说执行几次测试以确保-因为安装了某人确实有 systemd(例如,ex。),但这并不意味着它实际上被用作默认值init。另外,看着/proc/1/comm可能会产生误导,因为安装了各种初始化程序的某些程序会自动生成/sbin/init符号链接,甚至是其主程序的重命名版本。

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

附带说明一下,您可能还会看到 OpenRC ,它旨在提供一种与Linux和BSD系统兼容的初始化脚本结构。

30
rozcietrzewiacz

我本人已介入此问题,并决定进行一些测试。我完全同意一个答案,即应该为每个发行版分别打包,但是有时存在一些实际问题会阻止这种发行(尤其是人力)。

因此,对于那些想要“自动检测”的人,这是我发现的在有限的发行版中(更多信息请参见下文):

  • 您可以从以下位置告诉暴发户:

    [[ `/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:使用新贵
  • 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:使用新贵
  • Ubuntu 12.04 AMI-b08b6cd8:使用新贵
  • Ubuntu 14.04 AMI-a427efcc:使用新贵
  • Ubuntu 14.10及更低版本:使用systemd
  • AWS Linux 2014.3.2 AMI-7c807d14:使用新贵
  • Fedora 19 AMI-f525389c:使用systemd
  • Fedora 20 AMI-21362b48:使用systemd

只是要清楚一点:我并不是说这是万无一失的!几乎可以肯定不是。另请注意,为方便起见,我使用了bash regexp匹配项,但并非在所有地方都可用。以上对我来说已经足够了。但是,如果您发现发行版失败,请告诉我,如果有EC2 AMI重现该问题,我将尝试修复它。

61
TvE

使用流程

查看几个ps命令的输出,这些命令可以检测systemdupstart的各种版本,可以像这样制作:

新贵

$ 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的进程名称也可能会揭示正在使用哪个初始化系统。在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

注意:但请谨慎使用。没有什么可以改变的,它说在给定发行版上使用特定的初始化系统hassystemd作为PID#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

查看带有p​​pid 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

(NOTE:init不在其标准位置这一事实有点暗示/暗示。它总是位于/sbin/init在sysvinit系统上。

sysvinit

$ type init
init is /sbin/init

还有这个:

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

结论

因此,似乎没有任何一种方法可以执行此操作,但是您可以制定一套检查方法,以相当高的信心确定使用的初始化系统。

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中使用的字符串可以稍作修改,但是在以下操作系统中进行测试时,我总是得到一行。

  • RHEL 6.4 [UPSTART]
  • RHEL ES 4(Nahant更新7)[SYSVINIT]
  • Ubuntu 16.04.1 LTS [SYSTEMD]
  • Ubuntu 14.04.2 LTS [UPSTART]
  • Fedora版本23(在线Shell)[SYSTEMD]
  • Debian GNU/Linux 7(在线Shell)[SYSTEMD]
  • Centos 7.6(VM)[系统]

相同解决方案的更简单方法(但在第一次比赛时停止)

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不是符号链接,您必须进一步检查其他答案中的以下建议。

10
Skippy le Grand Gourou

我也遇到了同样的问题,并在某些RedHat/CentOS/Debian/Ubuntu/Mint机器上进行了很多测试。这就是我最终得到的结果。

  1. 查找具有PID 1的可执行文件的名称:

    ps -p 1
    

    如果是systemd或Upstart,问题就解决了。如果是“ init”,则可能是符号链接或其他名称。前进。

  2. 查找可执行文件的真实路径(仅以root身份工作):

    ls -l `which init`
    

    如果init是Upstart或systemd的符号链接,则问题已解决。否则,几乎确定您具有SysV初始化。但是它可能是一个错误命名的可执行文件。前进。

  3. 查找提供可执行文件的软件包。不幸的是,这是依赖发行版的:

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

然后,如果要编写脚本(最有趣的部分,恕我直言),这些是我的一线书(以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. 这就是特定于发行版的软件包的用途。正确安装软件不只是检测启动系统而已。许多发行版都使用SysVinit,但并非所有人都以相同的方式编写其初始化脚本。解决此问题的正确方法是包括所有不同的变体,然后使用带有rpm发行版特定发行版的依赖项名称的spec文件,适用于apt的系统的deb文件等将其捆绑在一起。几乎所有发行版都有某种软件包规范可以编写包括依赖项,脚本,初始化脚本等在内的内容。不要在这里重新发明轮子。

  2. 否。这使我们回到1。如果您需要bash,则它应该是一个依赖项。您可以在配置脚本中指定此检查,但也应在软件包描述中。

编辑:在配置脚本上使用标志,例如--with upstart 要么 --without sysvinit。选择一个合理的默认值,然后为其他发行版打包软件的脚本可以选择使用其他选项来运行它。

3
Caleb

检查文件描述符也可以提供帮助。它来自实际运行的init(Debian Stretch目前允许安装更多的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
Cyrille Pontvieux

然后不了解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,则初始化系统为OpenRC。如果是systemd,则初始化系统为systemd

您可以使用[ -f /etc/gentoo-release ]检测Gentoo。

Gentoo的另一种方法是使用profile-config show,它将显示正在使用的默认配置文件。除以/ systemd结尾的两个以外的所有配置文件均使用OpenRC初始化。请记住,这些仅代表默认值,并且用户可能已采取措施覆盖该默认值,并且可能未指示实际使用的初始化管理器。

2
casey

对于某些初始化系统来说,这确实很容易。对于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脚本。它目前仅检查新贵和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