109

This may have more to do with detecting operating systems, but I specifically need the init system currently in use on the system.

Fedora 15 and Ubuntu now use systemd, Ubuntu used to use Upstart (long time default until 15.04), while others use variations of System V.

I have an application that I am writing to be a cross-platform daemon. The init scripts are being dynamically generated based on parameters that can be passed in on configure.

What I'd like to do is only generate the script for the particular init system that they are using. This way the install script can be run reasonably without parameters as root and the daemon can be "installed" automagically.

This is what I've come up with:

  • Search for systemd, upstart, etc in /bin
  • Compare /proc/1/comm to the systemd, upstart, etc
  • Ask the user

What would be the best cross/platform way of doing this?

Kind of related, Can I depend on bash to be on the majority of *nix or is it distribution/OS dependent?

Target platforms:

  • Mac OS
  • Linux (all distributions)
  • BSD (all versions)
  • Solaris, Minix, and other *nix
phk
  • 5,953
  • 7
  • 42
  • 71
beatgammit
  • 7,583
  • 1
    Just to add my two cents, bash isn't installed by default on FreeBSD. – Chinmay Kanchi Aug 07 '11 at 03:27
  • @tjameson, did you find a more direct way? I'm looking for the same thing but the answers here are just directions, not direct answers. In particular 1) script locations to search and 2) detecting the init system in effect, in case there are multiple ones installed (bash was answered directly). – n611x007 Nov 24 '13 at 11:13
  • 3
    @naxa - Short answer, no. Long answer, you can get pretty far with ps -p 1 -o command (prints the path to the current init). On Arch Linux and Fedora (IIRC), it's a symlink to the systemd binary (probably same on all systemd systems). On upstart, init --help will print usage information, and on my box, upstart is mentioned where it says who to email. On FreeBSD (sysV), this will return an error. There may be similar clues on other systems, but since asking this question, I've decided to just create them for all platforms and make separate packages for each one. – beatgammit Nov 24 '13 at 19:48
  • thanks great info! Hopping from that I've learned that sudo lsof -a -p 1 -d txt may give even more exact results. ps may print an arbitrary name, whereas with lsof you will get the real executable path. (See my question http://unix.stackexchange.com/questions/102453/what-does-init-2-mean-in-the-command-column-of-ps ) – n611x007 Nov 24 '13 at 22:25
  • My question is not about detecting the init system from bash in order to write a cross-init-system daemon, and the answers do not provide a clear way to determine it because they are targeting specifically a programmatic solution. – Uyghur Lives Matter Feb 10 '14 at 20:15
  • Try and rephrase some more to distance yourself from that other Q. I'm reading them both and don't see how this isn't a dup. I'd hurry since you've already got 1 close, likely to get 4 more quickly. – slm Feb 10 '14 at 20:18
  • 1
    None of the answers or comments in the linked question are bash related. The solutions should be applicable to your case as well. – Marco Feb 10 '14 at 20:20
  • Wouldn't a ps -eaf|grep systemd, ps -eaf | upstart`...accomplish what you're asking? It reads like you're asking how you'd do this from visual inspection. Am I missing it still? – slm Feb 10 '14 at 20:20
  • @slm why did you not talk on https://unix.stackexchange.com/questions/114613 instead? leave other people's questions be next time. – n611x007 Jul 22 '15 at 12:45
  • 1
    related https://github.com/ansible/ansible-modules-core/blob/09aa79c58f93029a87ed3f4c42c8f04631472575/system/service.py#L383 – n611x007 Jul 22 '15 at 12:52
  • @naxa - I don't understand what you're talking about. When I left that comment that Q didn't even exist. Look at the dates! – slm Jul 22 '15 at 12:57
  • @slm question: 2014-02-10 20:08:49Z. your comment: 2014-02-10 20:18:59Z. I think somehow cpburnz ended up talking on this -ie. someone else's- question her/his own question's duplicate flag. it seems like unfortunate to me. – n611x007 Jul 22 '15 at 14:18
  • @naxa - I replied to his comments here, since they were here. That's just how the commenting works. His Q was eventually marked as a dup later on, in March. – slm Jul 22 '15 at 15:18
  • on rpm distros, rpm --quiet --query systemd. this avoids the hanky panky involved in looking for a process or pid or symlink. – Trevor Boyd Smith Jan 09 '18 at 19:12

22 Answers22

67

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

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
TvE
  • 778
  • 8
    According to the systemd documentation (sd_booted(3)), the correct way to check for systemd is to check if the directory /run/systemd/system exists. – Robie Basak Dec 13 '17 at 15:23
  • 1
    I'll add to this detecting launchd, the init system on macOS: [[ $(ps 1) =~ 'launchd' ]] && echo yes || echo no tested on a MacBookPro, macOS Sierra Version 10.12 – Tony Aug 08 '18 at 14:15
  • I'd also add busybox: if [ -h /sbin/init -a $(readlink /sbin/init | grep busybox | wc -l) -gt 0 ]; then echo yes; else echo no; fi – Astrinus Sep 25 '19 at 07:04
  • Currently on my debian box, /sbin/init --version complais tyhat there is no --version option. –  Oct 07 '20 at 13:01
34

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.

  • 2
    What do you mean by "look at the init scripts type"? Often different init systems put their scripts/files somewhere besides /etc/init, like systemd puts them in /etc/systemd. If I was to have my script grok these, it could take a little while. Oh, and thanks for the link BTW for portable shell programming. – beatgammit Aug 07 '11 at 00:23
  • 1
    I meant to say that some init implementations can be adjusted to make use of different init scripts' types and locations (like /etc/rc.d/ or /etc/init.d/). And you should properly adjust your program at installation time to utilize the structure that is used on the given system. – rozcietrzewiacz Aug 07 '11 at 01:08
  • 2
    So, are you saying that there is no reliable way to detect the init system programmatically? Having the user pass in parameters is certainly safer, but if the user does not pass anything in, what would be the best way to guess? – beatgammit Aug 07 '11 at 01:27
  • I've no idea what will be the best way for your program - it all depends on what systems will the program end up running. I haven't used too many distributions, but I was trying to share my observations to help you. It is a tough piece of scripting you are about to try and I tried to give you some view on the field - you must come to the final answer yourself or wait for more hints. – rozcietrzewiacz Aug 07 '11 at 01:40
  • Cool, thanks for all your help. You definitely have pointed me in the right direction. – beatgammit Aug 07 '11 at 01:47
22

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.

slm
  • 369,824
  • How about: pgrep systemd >/dev/null && echo init system: systemd – Marco Feb 10 '14 at 20:27
  • Thank you, this is exactly what I was looking for: some steps to take to try to determine the init system. – Uyghur Lives Matter Feb 10 '14 at 20:30
  • 2
    The PID #1 doesn't necessarily be /usr/lib/systemd/systemd if systemd is used, it's a false assumption. On my system, for instance, PID #1 is /sbin/init (I use systemd). It is distribution dependent. – Marco Feb 10 '14 at 20:32
  • On my kubuntu 15.04 installation I appear to both have systemd and sysvinit. Don't know why or what that means, just saying.. pgrep systemd >/dev/null && echo init system: systemd -> init system: systemd and type init -> init is /sbin/init – dotnetCarpenter Sep 03 '15 at 11:39
  • 1
    Linux Mint 17, has both systemd and upstart running, so exit status of pgrep alone isn't enough. – ychaouche Nov 19 '19 at 19:06
17

Not that efficient but I it seems to work.

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

It will print more lines if more than one strings match, which could be translated to "Can't guess". Strings used in grep could be slightly modified but when tested in the following os I always got one line.

  • RHEL 6.4 [UPSTART]
  • RHEL ES 4 (Nahant Update 7) [SYSVINIT]
  • Ubuntu 16.04.1 LTS [SYSTEMD]
  • Ubuntu 14.04.2 LTS [UPSTART]
  • Fedora release 23 (online shell) [SYSTEMD]
  • Debian GNU/Linux 7 (online shell) [SYSTEMD]
  • Centos 7.6 (VM) [SYSTEMD]

A more simplistic approach of the same solution (but it stops at first match)

strings /sbin/init |
  awk 'match($0, /(upstart|systemd|sysvinit)/) { print toupper(substr($0, RSTART, RLENGTH));exit; }'

Update:

As KCGD points out many systems don't come with strings installed. So a more portable alternative could be:

cat /sbin/init | 
  awk 'match($0, /(upstart|systemd|sysvinit)/) { print toupper(substr($0, RSTART, RLENGTH));exit; }' 2> /dev/null
  • nice first answer. welcome to unix.se! – Olivier Dulac Nov 24 '16 at 18:23
  • 1
    I just tried this on a Gentoo default docker image with OpenRC installed, and it returned SYSVINIT. According to https://wiki.gentoo.org/wiki/Comparison_of_init_systems the default for Gentoo is OpenRC, but it appears that OpenRC uses sysvinit. When I then attempt OpenRC commands I get "You are attempting to run an OpenRC service on a system which openrc did not boot." Is there a way to distinguish between sysvinit proper and OpenRC using sysvinit? – tudor -Reinstate Monica- Jan 04 '17 at 02:10
  • +1. That awk command can be simplified to strings -n7 /sbin/init | awk '/upstart|systemd|sysvinit/ {print;exit}'. Or better, on GNU: grep -aEiom1 'upstart|systemd|sysvinit' – Amit Naidu Oct 07 '20 at 02:07
  • 1
    That script works well, but many minimalist systems dont come with strings installed by default. This command should work with only cat and awk, which are both present by default: cat /sbin/init | awk 'match($0, /(upstart|systemd|sysvinit)/) { print toupper(substr($0, RSTART, RLENGTH));exit; }' 2> /dev/null – KCGD Nov 29 '22 at 00:59
  • @KCGD Correct. Updated my answer accordingly. – Marinos An Nov 29 '22 at 08:50
12

Sometimes it's as easy as using ls :

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

I guess if /sbin/init is not a symbolic link, you'll have to check further following suggestions in other answers.

5

I also had this same problem, and did a lot of tests in some RedHat/CentOS/Debian/Ubuntu/Mint machines. This is what I ended up with, with good results.

  1. Find the name of the executable with PID 1:

    ps -p 1
    

    If it's systemd or Upstart, problem solved. If it's "init", it may be a symlink or something other than an upfront name. Go ahead.

  2. Find the real path for the executable (only work as root):

    ls -l `which init`
    

    If init is a symlink to Upstart or systemd, problem solved. Otherwise, it's almost certain that you have SysV init. But it can be a misnamed executable. Go ahead.

  3. Find the package which provides the executable. Unfortunately, this is distro-dependent:

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

Then, if you want to script that (the funniest part, IMHO), these are my one-liners (run as 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  
4

Also inspecting file descriptors can help. And it's from actually running init (Debian stretch currently allow to have more init systems installed) :-)

$ 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

Probably safer way to check for busybox would be to check /proc/1/exe, as busybox usually uses symlinks:

$ ls -l /proc/1/exe 
lrwxrwxrwx    1 root     root          0 Jan  1 00:00 /proc/1/exe -> /bin/busybox

So check could be:

{ 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"
pevik
  • 1,463
  • 17
  • 28
3

On Gentoo, take a look at 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]

If it is init, then the init system is OpenRC. If it is systemd, then the init system is systemd.

You can detect Gentoo with [ -f /etc/gentoo-release ].

Another method on Gentoo is to use profile-config show, which will show what default profile is in use. All of the profiles except the two ending in /systemd use the OpenRC init. Keep in mind, these are only representative of a default and it is possible that the user has taken steps to override that default and may not be indicative of the init manger actually in use.

casey
  • 14,754
3
  1. This is what distro-specific packages are for. There is much more to installing software properly than just detecting the init system. Many distros use SysVinit but not all of them write their init scripts the same way. The proper way to solve this is to include all the different variants and then bundle it up using spec files with distro-specific dependency names for rpm distros, deb files for apt based systems, etc. Almost all distros have some sort of package specification you can write that includes dependencies, scripts, init scripts, etc. Don't re-invent the wheel here.

  2. No. Which brings us back to 1. If you need bash it should be a dependency. You can specify this check as part of your configure scripts, but it should also be in the package descriptions.

Edit: Use flags on your configure script such as --with upstart or --without sysvinit. Pick a sane default, then the scripts that package your software for other distros can choose to run this with other options.

Caleb
  • 70,105
  • Hmph, so it's looking like I can't have a 'one script to rule them all' solution. I've seen a lot of programs that use autoconf or similar to handle cross-platform stuff, but it doesn't seem like it's the right tool for my application. Is maintaining versions for each platform really the only reliable solution? – beatgammit Aug 07 '11 at 07:27
  • One installation script to rule them all is a BadIdea. It ends up failing more places than it works. Autoconf is good as far as it goes. Work hard on keeping your end of the software as generic as possible and include alternate init scripts in your package. Setup package specifications for several major distros. If your software is good you can get other people to help you out with getting it packaged for other systems. – Caleb Aug 07 '11 at 07:34
  • @tjameson: I just realized I forgot the most important bit. This sort of thing is usually done with switches passed to the configure script. Each distro's build/package routines can call different switches, and your configure/make only has to know what switch it was passed, not detect all the possible software configurations. – Caleb Aug 07 '11 at 07:38
  • @Caleb- Yeah, I already have that logic in there, but good catch. I was hoping for a way to sniff the init system to use an intelligent guess than a sane default. – beatgammit Aug 07 '11 at 07:40
3

For systemd:

if [[ `systemctl is-system-running` =~ running ]]; then echo using systemd; fi
Chris Davies
  • 116,213
  • 16
  • 160
  • 287
  • downvoting because this answer doesn't provide any new or different information compared to the numerous existing answers. – jayhendren Nov 26 '16 at 19:27
  • @jayhendren I don't see this snippet elsewhere. It's not complete in itself, and would probably better stand as a comment against the answer http://unix.stackexchange.com/a/164092/100397 by TvE – Chris Davies Nov 26 '16 at 22:42
  • Oh you're right @roaima. It's not exactly the same as the others. I searched the page for a not-too-specific string :) – jayhendren Nov 26 '16 at 22:46
  • 2
    This seems to be by far the most correct answer :) – Jack O'Connor Oct 30 '17 at 20:57
2

Don't know about other systems then Debian (wheezy) /or Ubuntu (14.10.) but I test such issues with the plain old file command.

file /sbin/init

give this:

/sbin/init: symbolic link to 'upstart'

Debian systems with systemd (e.g. sid) show this:

# file /sbin/init 
/sbin/init: symbolic link to /lib/systemd/systemd
zzeroo
  • 556
  • What system did you test it on? There's no such thing as Debian/Ubuntu and this does not work on Debian. Did you try it on Ubuntu? – terdon Oct 07 '14 at 12:53
  • Sorry for this confusion, I mean Debian (wheezy) /or Ubuntu (14.10.).

    Output on debian: file /sbin/init /sbin/init: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, BuildID[sha1]=0x8c68a736c6a4e6fadf22d5ac9debf11e79c6bdcd, stripped means we use SYSV here. Output for ubuntu is shown in my answer.

    – zzeroo Oct 08 '14 at 14:14
  • Exactly, so your solution seems to only work if one happens to be using upstart and Ubuntu. – terdon Oct 08 '14 at 14:17
  • @terdon: On systems (RHEL, Fedora) running systemd, it returns "symbolic link to...systemd"; on systems (Ubuntu) running upstart it returns "symbolic link to upstart"; on systems (RHEL, Ubuntu, Debian) running SysV init it returns "executable". While that's hardly a comprehensive survey, and this method is clearly not 100% foolproof, it's clearly much closer to "works for at least the major distros" rather than "only upstart and Ubuntu"! – psmears Oct 20 '14 at 21:46
  • 1
    @psmears if it also works for some systemd systems, that is indeed better (but not mentioned in this answer). I just tested on a Debian running sysvinit, and three Ubuntus (10.04,12.04 and 14.04, all running upstart) and file /sbin/init returned "executable" on all systems. It also returns the same on a CentOS 5.8, a SLES 10, an Ubuntu 8.04, basically every single system I can get my hands on. So, as far as I can tell it doesn't even work for upstart and Ubuntu. – terdon Oct 21 '14 at 00:06
2

On debian /sbin/init is a symlink to your default init so

ls -l /sbin/init

will give you the info you're looking for.

$ ls -l /sbin/init 
lrwxrwxrwx 1 root root 20 nov 18 13:15 /sbin/init -> /lib/systemd/systemd
2

Simply greping into the process with PID 1 will tell you:

strings /proc/1/exe |grep -q sysvinit
strings /proc/1/exe |grep -q systemd
1

This is really easy for some init systems. For systemd:

test -d /run/systemd/system

for upstart:

initctl --version | grep -q upstart

for anything else, you can just assume based on the distro (launchd on OS X, sysvinit on Debian, OpenRC on Gentoo).

CameronNemo
  • 1,131
1

Here's a bash script to do the detection. It only checks for upstart and systemd at the moment, but should be easy to extend. I've taken this from code I've contributed to the DisplayLink driver install script.

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
}
  • 3
    I think the use of /proc ties this down to Linux (if suitably configured) and one or two others - it's certainly far from universal. – Toby Speight Apr 25 '16 at 17:12
1

There is a lot of compatibility pitfalls when testing systemd vs initd. This actually works on OpenSuSE 42.1: ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init'

1

My solution: check the command running as process with 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

At the moment I have access only to Init and SystemD machines, so I can't Tell how Upstart or macOS (OS X) will be detected, but I'll keep searching.

t0r0X
  • 819
1

I would use pstree and simply find its root. On my Ubuntu, Arch and Fedora systems (unfortunately all use systemd for init), running pstree gives me the following output head:

systemd-+-GUIPool-+-calibre-paralle
        |         `-8*[{GUIPool}]
        |-MainThread-+-Privileged Cont---29*[{Privileged Cont}]
        |            |-Web Content---30*[{Web Content}]
        |            |-Web Content---32*[{Web Content}]
  1. So, as a simple solution using pstree, head and cut which are come preinstalled on most systems, I'd run pstree | head -n 1 | cut -d "-" -f 1,1 It threw the needed string "systemd" at me on all three OSs I tested it on.
  2. Alternately, you could run something like pstree | head -n 1 | ([[ $(grep systemd) ]] && echo systemd) || ([[ $(grep upstart) ]] && echo upstart) || ([[ $(grep sysvinit) ]] && echo sysvinit)
0
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
}
hxysayhi
  • 161
  • 1
  • 4
0

How'bout this one :

strings $(\ps -p 1 o cmd= | cut -d" " -f1) | egrep -o "upstart|sysvinit|systemd" | head -1

Only tested on the systems I have: Ubuntu and SailfishOS.

SebMa
  • 2,149
0

My ultimate solution.

As upstart seem dead and I don't them anywhere, I'm not able to test what's happen if I hit ps -C upstart on upstart based host.

Trying different ps 1 was definitively not efficient in all my tested hosts...

My purpose is finally:

if ps -C systemd | grep -q '^ *1 ' ;then
    echo This system run systemd
else
    echo This system run init
fi
0

Check to see if my system has systemd available

For anyone wondering if your system has systemd, not if it was booted by systemd, these are the easiest commands I could come up with. I'm using this to test if my custom embedded Linux board successfully got systemd onto it from Buildroot:

# best: check the systemd-run version
systemd-run --version

or: look for any "systemd" files or folders on your computer

find / | grep -i systemd | sort -V

or: look for "systemd" files in /usr/bin

find /usr/bin | grep -i systemd | sort -V

For my board, I get the following output:

1st command:

# systemd-run --version
systemd 244 (244)
-PAM -AUDIT -SELINUX -IMA -APPARMOR -SMACK +SYSVINIT +UTMP -LIBCRYPTSETUP -GCRYPT -GNUTLS -ACL -XZ -LZ4 -SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 -IDN -PCRE2 default-hierarchy=hybrid

My systemd.mk makefile in Buildroot shows SYSTEMD_VERSION = 244.3, so this makes sense.

2nd command:

It's too long for me to care to copy/paste it all, but it shows entries in /usr/lib/systemd, /usr/bin/systemd*, etc.

3rd command:

# find /usr/bin | grep -i systemd | sort -V
/usr/bin/systemd-analyze
/usr/bin/systemd-ask-password
/usr/bin/systemd-cat
/usr/bin/systemd-cgls
/usr/bin/systemd-cgtop
/usr/bin/systemd-delta
/usr/bin/systemd-detect-virt
/usr/bin/systemd-escape
/usr/bin/systemd-id128
/usr/bin/systemd-machine-id-setup
/usr/bin/systemd-mount
/usr/bin/systemd-notify
/usr/bin/systemd-nspawn
/usr/bin/systemd-path
/usr/bin/systemd-run
/usr/bin/systemd-socket-activate
/usr/bin/systemd-stdio-bridge
/usr/bin/systemd-tty-ask-password-agent
/usr/bin/systemd-umount

This is the list from which I found the systemd-run executable. I simply guessed that running systemd-run --version might work, and sure enough, it did!

See also

  1. Super User: How to know if I am using systemd on Linux?
  2. Convenient way to check if system is using systemd or sysvinit in BASH?