Detect init system using the shell

I've stepped into this problem myself and decided to do some tests. I fully agree with the answer that one should package for each distro separately, but sometimes there are practical issues that prevent that (not least manpower).

So for those that want to "auto-detect" here's what I've found out on a limited set of distros (more below):

  • You can tell upstart from:

    [[ `/sbin/init --version` =~ upstart ]] && echo yes || echo no
    
  • You can tell systemd from:

    [[ `systemctl` =~ -\.mount ]] && echo yes || echo no
    
  • You can tell sys-v init from:

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

Here are my experiments with the following command line:

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

on ec2 instances (I'm including the us-east AMI id):

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

Just to be clear: I am not claiming that this is foolproof!, it almost certainly isn't. Also note that for convenience I use bash regexp matches, which are not available everywhere. The above is good enough for me right now. However, if you find a distro where it fails, please let me know and I'll try to fix it if there's an EC2 AMI that reproduces the problem...


For the second question, the answer is no and you should have a look at Resources for portable shell programming.

As for the first part - first of all, you certainly have to be careful. I'd say perform several tests to make sure - because the fact that someone does have systemd (for ex.) installed, does not mean it is actually used as the default init. Also, looking at /proc/1/comm can be misleading, because some installations of various init programs can automatically make /sbin/init a symlink hardlink or even a renamed version of their main program.

Maybe the most useful thing could be to look at the init scripts type - because those are what you'll actually be creating, no matter what runs them.

As a side note, you might also have a look at OpenRC which aims to provide a structure of init scripts that is compatible with both Linux and BSD systems.


Using processes

Looking at the output from a couple of ps commands that can detect the various versions of systemd & upstart, which could be crafted like so:

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

Paying attention to the name of the process that's PID #1 can also potentially shed light on which init system is being used. On Fedora 19 (which uses systemd, for example:

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

Notice it isn't init. On Ubuntu with Upstart it's still /sbin/init.

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

NOTE: But use this with a bit of caution. There isn't anything set in stone that says a particular init system being used on a given distro has to have systemd as the PID #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

Look at processes with ppid 1 (children of the init process). (Some of the) child process names might point to the init system in use.

The filesystem

If you interrogate the init executable, you can get some info from it as well. Simply parsing the --version output. For example:

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

NOTE: The fact that init is not in its standard location is a bit of a hint/tell. It's always located in /sbin/init on sysvinit systems.

sysvinit

$ type init
init is /sbin/init

Also this:

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

Conclusions

So there doesn't appear to be any one way to do it, but you could formulate a suite of checks that would pinpoint which init system you're using with a fairly high degree of confidence.