SysV-init has been a staple of Linux for years and years. In recent versions of Fedora (current version is 18) this has changed to using systemd. I’m no stranger to alternative means for running startup commands (I did, after all, have Annvix using Annvix:User_Guide/Services runit to handle boot with a custom script called srv to handle all the service management stuff (similar to service and chkconfig).
Now I need to learn a new system which is quite a bit different from both and reminds me a lot of launchd on OS X.
Command Comparison
Out of the box, we’re used to commands like “service foo restart” or “chkconfig —add foo” and so forth. In Fedora 17, you could still use these commands and they would transparently go to the equivalent systemctl command. But some stuff doesn’t work (like “chkconfig —list” doesn’t really list the systemd service units), and it’s just plain old better to learn the real commands for the day when these wrappers are deprecated.
SysV-init | systemd | What it does |
---|---|---|
chkconfig —list | systemctl list-units -t service —all | List available services; the systemctl command however does not list targets, so unlike chkconfig we do not know what runlevel (or boot target) a specific service will start in |
chkconfig X on | systemctl enable X.service | Enables service X so that it will start at boot; this does not start X now |
chkconfig X off | systemctl disable X.service | Disables service X so that it will not start at boot; this does not stop X now |
service X start | systemctl start X.service | Starts service X immediately; service provides feedback on success, but systemctl does not (although it will tell you if it fails) |
service X stop | systemctl stop X.service | Stops service X immediately |
service X restart | systemctl restart X.service | Restarts service X immediately |
service X status | systemctl status X.service or systemctl is-active X.service |
Displays the status of service X; the first command displays the path to the loaded service unit file, the process, PID, etc. The second command will simply display whether or not the service is active (good for shell scripts, etc.) |
chkconfig —list | grep ‘3:on’ | systemctl -p show “Wants” multi-user.target | cat | Lists all services enabled for runlevel 3 (or multi-user/network/text);see #Systemctl_Show below. |
telinit 3 | systemctl isolate multi-user.target | Switch to runlevel 3 (or multi-user.target). See #Runlevels for more details. |
chkconfig —list | systemctl -t service | Show all loaded services (running, failed, active, inactive, etc.). Can use target, etc. as well; no arguments shows everything loaded |
n/a | systemctl -t service | grep running | Show all currently running services |
Boot Commands
With systemd, if you want to boot into the non-default runlevel (or target) you need to edit the GRUB boot command for the linux kernel and options to specify the target to boot into. The default is typically graphical.target. You can do this by appending to the boot command:
linux /vmlinuz-3.7.2-204.fc18.i686.PAE root= [...] quiet systemd.unit=multi-user.target
Other valid targets include “rescue.target” (like runlevel 1), “emergency.target” (like using init=/bin/sh). Further details can be found via man systemd.special.
Runlevels
SysV-init had the concept of runlevels, defined in /etc/inittab, for example:
# Default runlevel. The runlevels used are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id:3:initdefault:
The above will boot into runlevel 3 by default. Systemd does not have the same concept of runlevels, it uses targets instead. You can get the output of available targets using:
% systemctl list-units -t target --all UNIT LOAD ACTIVE SUB JOB DESCRIPTION emergency.target loaded inactive dead Emergency Mode graphical.target loaded active active Graphical Interface multi-user.target loaded active active Multi-User rescue.target loaded inactive dead Rescue Mode shutdown.target loaded inactive dead Shutdown
I’ve snipped out the targets that are not really relevant as “runlevels” (for instance the “unmount.target” isn’t really a runlevel you would boot into, so I didn’t include it in the above output). Again, if you want to see what any of these load, use systemctl show -p “Wants” rescue.target, which will show ou what services and/or targets this target (or runlevel) wants.
Also note that there is some correspondance with the initial runlevel; for instance multi-user.target can also be called as runlevel3.target. You can look at /lib/systemd/system/runlevel* to see which runlevel target corresponds to the systemctl target, for instance:
ls /lib/systemd/system/runlevel3.target -al lrwxrwxrwx. 1 root root 17 Jan 8 21:19 /lib/systemd/system/runlevel3.target -> multi-user.target
Changing the Default Runlevel
Changing the default runlevel is done by changing the symlink of the /etc/systemd/system/default.target:
% ls -al /etc/systemd/system/default.target lrwxrwxrwx. 1 root root 36 May 28 2012 /etc/systemd/system/default.target -> /lib/systemd/system/runlevel5.target
So if you wanted to boot into runlevel3 (multi-user.target) by default, you would:
# cd /etc/systemd/system # rm default.target # ln -s /lib/systemd/system/multi-user.target default.target
Systemctl Commands In Depth
Here we’ll look at a few commands in depth to try to make sense of them.
Systemctl Show
One of the more annoying things about systemctl is the show command. This is probably because it behaves quite differently from what I would expect from chkconfig and it’s worth discussing in a little more depth.
The primary issue is that when you run systemctl show -p “Wants” multi-user.target it pipes it to less, so you don’t really get to see all of the commands at once. Not sure why it does this, but it’s annoying. Piping that output to cat instead gives us the whole thing together:
% systemctl show -p "Wants" multi-user.target | cat Wants=systemd-update-utmp-runlevel.service sm-client.service abrt-vmcore.service remote-fs.target abrt-xorg.service apcupsd.service sssd.service mcelog.service nfs-idmap.service nfs-lock.service auditd.service crond.service sendmail.service sshd.service rsyslog.service acpid.service avahi-daemon.service netatalk.service ntpd.service rpcbind.service NetworkManager.service chronyd.service httpd.service arp-ethers.service atd.service irqbalance.service abrt-oops.service certmonger.service mysqld.service abrt-ccpp.service cups.path abrtd.service mdmonitor.service plymouth-quit-wait.service systemd-logind.service dbus.service getty.target systemd-ask-password-wall.path plymouth-quit.service systemd-user-sessions.service rc-local.service nrpe.service tcsd.service
This shows all the services and targets that the multi-user.target wants, which is our non-GUI runlevel (essentially runlevel 3). So if we want to see what starts with our graphical target:
% systemctl show -p "Wants" graphical.target | cat Wants=systemd-readahead-collect.service systemd-readahead-replay.service systemd-update-utmp-runlevel.service system-setup-keyboard.service prefdm.service nrpe.service tcsd.service atieventsd.service
Based on the above, it doesn’t look like the graphical target wants a whole heck of a lot. This is quite different from the chkconfig output where you see all the services and whether or not they are enabled in a particular runlevel. Here, at a quick glance, we would be thinking that things like dbus, getty, sshd, etc. aren’t being started. But we need to look at the dependencies between targets to know for sure what is going on. To that end:
% systemctl show -p "RequiredBy" multi-user.target| cat RequiredBy=graphical.target
and:
% systemctl show -p "Requires" graphical.target | cat Requires=multi-user.target
So now we see that multi-user.target is required by graphical.target (and likewise that graphical.target requires multi-user.target). This means that the multi-user.target must be loaded before graphical.target can be loaded. In other words, for the graphical.target we can add the “Wants” of multi-user.target to its “Wants” list. Confused yet? It’s not bad, but just annoying. With systemctl you need to to run two commands (“Wants” on both targets) versus a simple chkconfig command (chkconfig —list | grep ‘5:on’).
References
Here are links to other systemd documentation and articles worth reading: