How to find out if a system uses SysV, Upstart or Systemd initsystem

The init process is always assigned PID 1. The /proc filesystem provides a way to obtain the path to an executable given a PID.

In other words:

nathan@nathan-desktop:~$ sudo stat /proc/1/exe
  File: '/proc/1/exe' -> '/sbin/upstart'

As you can see, the init process on my Ubuntu 14.10 box is Upstart. Ubuntu 15.04 uses systemd, so running that command instead yields:

nathan@nathan-gnome:~$ sudo stat /proc/1/exe
  File: '/proc/1/exe' -> '/lib/systemd/systemd'

If the system you're on gives /sbin/init as a result, then you'll want to try statting that file:

nathan@nathan-gnome:~$ sudo stat /proc/1/exe
  File: '/proc/1/exe' -> '/sbin/init'
nathan@nathan-gnome:~$ stat /sbin/init
  File: ‘/sbin/init’ -> ‘/lib/systemd/systemd’

You can also execute it to find out more:

[user@centos ~]$ /sbin/init --version
init (upstart 0.6.5)
Copyright (C) 2010 Canonical Ltd.

You can poke around the system to find indicators. One way is to check for the existence of three directories:

  • /usr/lib/systemd tells you you're on a systemd based system.

  • /usr/share/upstart is a pretty good indicator that you're on an Upstart-based system.

  • /etc/init.d tells you the box has SysV init in its history

The thing is, these are heuristics that must be considered together, possibly with other data, not certain indicators by themselves. The Ubuntu 14.10 box I'm looking at right now has all three directories. Why? Because Ubuntu just switched to systemd from Upstart in that version, but keeps Upstart and SysV init for backwards compatibility.

In the end, I think the best answer is "experience." You will see that you have logged into a CentOS 7 box and know that it's systemd. How do you learn this? Playing around, RTFMing, etc. The same way you gain all experience.

I realize this is not a very satisfactory answer, but that's what happens when there is fragmentation in the market, creating nonstandard designs. It's like asking how you know whether ls accepts -C, or --color, or doesn't do color output at all. Again, the answer is "experience."


This is actually quite a difficult problem. One of the major difficulties is that the places where one most often wants to do this are the places where it's quite likely that one will be in the middle of installing or changing stuff. Another is that there's a subtle but very important difference between the system management toolset that is installed, the system management toolset that is running right now, and the system management toolset that will run at next boot.

Determining what is installed one does with a package manager, of course. But this is complicated by the fact that several systems can be installed side by side.

On Debian Linux, for example, one can install the systemd package, but it is the installation of the separate systemd-sysv package that makes it the active system. The intention is that the systemd and sysvinit packages can be installed simultaneously. Indeed, the Debian Linux crowd has taken steps in Debian 8 to shift towards every program having a different name (/lib/sysvinit/init, /lib/systemd/systemd, /sbin/runit-init, /sbin/minit, /sbin/system-manager, and so forth) for this very reason, that the "non-activating" packages don't conflict on the name /sbin/init. /sbin/init is then a symbolic link to whichever was configured to run at next boot by an "activating package".

Determining what is running now and ready to run next one can only do with a series of toolset-specific tests, with varying degrees of risk from false positives, and with varying degrees of documentation. To check for what system manager is running right now, specifically, one really has to look at the process list or at the various APIs that system managers publish. But this isn't wholly without pitfalls.

General non-starters

Let's start with things that definitely will not work.

  • /proc/1/exe will point to the same /sbin/init when either upstart or System 5 init are running right now. And on some systems, it's also /sbin/init when systemd is running.

    The Debian Linux crowd wanted to shift towards every program having a different name, as mentioned earlier. But this is Debian-specific, far from universal, and doesn't really help when the program is invoked as /sbin/init (by the initramfs phase of the bootstrap) anyway. Only Felix von Leitner's minit is actually packaged by Debian 8 to be invoked with its own name.

  • The existence of the control API file /dev/initctl isn't specific to System 5 init. systemd has a (non process #1) systemd-initctl server that serves this. Joachim Nilsson's finit serves it too. (Just to make things extra fun, on Debian it's now located at /run/initctl. See https://superuser.com/a/888936/38062 for details.)
  • systemd, upstart, System 5 rc, and OpenRC all process /etc/init.d/, for backwards compatibility in the case of the former two. Its existence does not indicate the presence of any given system.

Detecting System 5 init

Ironically, as explained at https://unix.stackexchange.com/a/196197/5132 , one way on Debian Linux at least for detecting the absence of System 5 init is the absence of /etc/inittab. However:

  • This is an side-effect of Debian's way of packaging things like /etc/inittab.
  • One part of the overall problem is that /etc/inittab sticks around if System 5 init was used at any point in the past, because uninstalling the package does not delete its configuration file. (This has been a sizeable problem for Debian 8 work, since there are several packages in Debian 7 which install themselves by adding entries to /etc/inittab.)
  • It's an inverted test.

Detecting systemd

To check for systemd as the running system manager in the "official" manner, one checks for the existence of /run/systemd/system. This is a directory, in /run, that systemd itself creates at boot, and that other system managers are unlikely to create.

But that's merely unlikely. This check is already broken, because uselessd creates this directory too.

Other, unofficial, checks won't work:

  • systemd publishes a whole RPC API over D-Bus, which even contains a version name and number; but:
    • This is not covered by the infamous "Interface Stability Guarantee" and could change tomorrow or at whim.
    • So too does the lookalike D-Bus server in systemd-shim.
    • So too does uselessd.
  • The existence of /run/systemd/private is similarly not guaranteed and similarly duplicated by uselessd.

Detecting nosh

The system-manager in nosh creates a /run/system-manager directory. But this shares the weaknesses of the equivalent systemd check.

Further non-starters:

  • The nosh system-manager by design doesn't create pipes or sockets in the filesystem, and doesn't have an RPC API in the first place.
  • The nosh service-manager conventionally has an API socket at /run/service-manager/control, but one can run the nosh service manager under some other system manager; so this doesn't tell one what system manager is running as process #1. In any case, it doesn't set that name itself; whatever invoked it does.
  • The existence of a nosh version string, emitted by system-control version, systemctl version (if one has the systemd compatibility shims installed) and initctl version (if one has the upstart compatibility shims installed) only indicates the presence of the toolset, as these tools make no query of the running system.

Detecting upstart

Upstart's own initctl makes an API call over D-Bus, and the official check is to both check that one can run initctl and that its output contains the string "upstart" somewhere.

But, like the systemd API:

  • There's no guarantee that the API will be around tomorrow or not changed at whim.
  • There's no guarantee that some compatibility shim doesn't exist or won't exist in the future.

    Indeed, there already is one compatibility shim. nosh has an upstart compatibility package that provides shims for the upstart initctl, start, stop, and status commands. Luckily (although this was intentional), the initctl shim does not emit the word "upstart".

    root ~ #initctl version
    nosh version 1.14
    root ~ #