Many operating systems use the concept of runlevels. This is particularly the case for System V Unix based systems. As you might have read in our earlier post how Linux boots it uses runlevels to determine what to do. Let's study runlevels and rc scripts in detail.
Runlevels
Runlevels are the state to which a computer intends to go, or it intends to reach. There are total 7 runlevels.
Runlevel 0: Halt or Shutdown
Runlevel 1: Single-user mode
Runlevel 2: Basic Multi-user mode but without networking
Runlevel 3: Full text-based Multi-user mode (includes networking)
Runlevel 4: X11 with session managers (Generally not used by most of the operating systems and is customizable)
Runlevel 5: Full GUI based Multi-user mode
Runlevel 6: Reboot
These are the basic definitions what each runlevel is responsible for. For example, if an operating system is required to shut down, then it'd go to runlevel 0. You can even switch between these runlevels using the init command. Just type init \<runlevel> and it'd change the current runlevel to the one specified. For example:
init 0
will shut down the system.
Each system has a default runlevel to which it boots. Like Fedora has runlevel as default. To see which runlevel you are in type:
runlevel
To check the default runlevel of your system, type:
systemctl get-default
You can even change the default, keeping in mind what runlevel provided, like you want it to be multiuser or the graphical one. Using it you can set the default like:
systemctl set-default multi-user.target
rm '/etc/systemd/system/default.target # To remove current default
ln -s '/usr/lib/systemd/system/multi-user.target' '/etc/systemd/system/default.target'
Runlevel and target file have the following relation:
runlevel 0: poweroff.target
runlevel 1: rescue.target
runlevel 2: multi-user.target
runlevel 3: multi-user.target
runlevel 4: multi-user.target
runlevel 5: graphical.target
runlevel 6: reboot.target
You should never mess with the default runlevel unless you are absolutely sure with what you're doing. Like, if you manage to set runlevel 0 or 6 as default you will end up in a loop kind of condition. Your PC will shut down( or reboot depending on what runlevel you set) as soon as it has booted.
rc Scripts
When a computer has entered into a specific runlevel, it runs scripts according to the runlevel it's in. The rc here comes from use in the older computers which had rc files to contain commands that run at startup. These files were called runcom files. Where runcom files meant files used to RunCommand.
Your script must contain the line before any command executes:
. /etc/init.d/functions
This is because, your script might be executed at a time when nothing is loaded, not even file system( though it can be specified in boot facilities in Required-Start
in LSB styled stanzas discussed below) so we can not say that each command we write will already be present( Remeber that each command is executed from a script present in PATH variable of your system). Hence in order for those commands to work, we need the functions file to be loaded as the first step. This function file contains the functions that a shell script might use.
Fedora and most of the distros have folders that contain scripts that are to be run at a specific runlevel. They are located in the /etc
folder. The folders containing these scripts are:
/etc/init.d
/etc/rc.d/rc0.d
/etc/rc.d/rc1.d
/etc/rc.d/rc2.d
/etc/rc.d/rc3.d
/etc/rc.d/rc4.d
/etc/rc.d/rc5.d
/etc/rc.d/rc6.d
And, folders with the same name also exist in /etc
but they are actually symbolic links of there corresponding folders in /etc/rc.d
For example:
/etc/rc0.d (Symbolic link of /etc/rc.d/rc0.d)
Each of these folders contain symbolic links of scripts that are actually stored in init.d for the runlevel they have in their name. Like /etc/rc.d/rc0.d
contains a symbolic link for scripts in /etc/init.d
that are required to be run at shutdown.
Now if you open any of these folders you'd find out weird names with the structure like
S|K[01-99]filename
where filename is the name of the script in /etc/int.d
Like K50netconsole. Now let's see what these names mean.
Demystifying the symlink names
The terms have their meanings as follows:
S: start the service, if it's not already started.
K: Kill the service, if it's running.
01-99 is the priority for that start or kill task
filename is the exact same name of the file in /etc/init.d
folder.
(Remember that it's actually /etc/init.d
that actually houses those scripts. Rest of the folders just have symlinks to these.)
So, If a file named shutdown-script is to be run at shutdown all times with a priority of 90 then the file shutdown-script
should be present in init.d
folder. And a symlink to it must be created in /etc/rc.d/rc0.d
with the name S90shutdown-script, rest of the folders rc[1-6] can have K90shutdown-script. If 90 is the priority required to shut down.
Priority Of these scripts
Essentially, it can be better thought of as a position, and think of them being executed downwards from 01 to 99. For example, if you have a script that requires the network to be switched on then the network script should be at a higher position or priority than your script. Like the network, a script can have a priority of 01 and your script can have any number greater than it. So that it's executed after the network script.
The chkconfig
the chkconfig command here deserves the 'The' in the heading for how easy it makes to manage these scripts and runlevels! Yes, this command just needs your source script file and manages creation deletion, the setting of S or D and also the priority level!
chkconfig has an amazing man page and here are the basic commands that will get you going.
chkconfig --list
This prints the System V services, and that will do for us.
chkconfig --add
Is used to add your file for management by chkconfig. BUT wait. This command won't run unless you have some things set with your script.
First and foremost, your script should exist in the home of all scripts, and that is:
/etc/init.d
Paste your script here.
Secondly, your file must have certain comment lines so that it can be managed by chkconfig.
It must have these comment lines, though the description is not absolutely necessary and the script would work without it, it's recommended. So that anyone who intends to clean up the unnecessary services knows if this script is essential or not:
# chkconfig: 235 29 88
# description: The description of the script like what it does
The first line here has some numbers ahead chkconfig:
like 235, 29 and 88.
here the First number is the runlevels it's required to run on combined into a string. Like 235 here means it's supposed to run in runlevel 2,3 and 5.
The next two numbers are the priority for start and stop respectively. So in this example, start priority is 29 and stop priority is 88.
you can use backslash for a multiline comment though you still require a #
, in the beginning, to identify it as a comment.
This is how it creates the symlinks with required priorities.
Another way you can do this is enter LSB(Linux Standard Base) style init stanzas instead of these two comments. For it you can do it like:
### BEGIN INIT INFO
# Provides: scriptA
# Required-Start: scriptB
# Default-Start: 2 3 5
# Default-Stop: 0 1 6
# Description: Description of what the script does
### END INIT INFO
This one gives you more ease though it just looks a bit more complicated.
In this, Required-Start
is the script that is required to start this script. That is, it should be running before the current script gets up. Provides
: It tells about the boot facilities that this script provides so that those will be counted as already present when another script requires it. Hence priorities will be set accordingly to what is required to be already present and what it'll provide. Default-Start
or Stop
tells which runlevel should this start on and stopped(if running) respectively.
And don't forget a shebang at the beginning of the file.
Now we are all set to go with these things done. Let's execute this command to add it to the management of chkconfig:
chkconfig --add filename
like for a file named bootpref in init.d
it would be:
chkconfig --add bootpref
Now most probably your file will be visible with a status of on under the respective runlevels when you run
chkconfig --list
And if it's not or you want to change runlevels you can go like:
chkconfig bootpref --level 0 on
Will make it run on runlevel 0 that is at shutdown.
Similarly off argument will kill it if present in that level. If no level is specified then these act on level 2,3,4 and 5. You can also specify multiple levels like --level 26
for level 2 and 6.
chkconfig --del bootpref
will delete its symlinks from all rc folders but not from the init.d folder. That is required to be done manually. Ad chkconfig generally doesn't modify the content of init.d but rc folders.
Hope this will help you play with your scripts in a better and safe manner.
Thank you for reading!