Recently, while testing a configuration of Linux on a Lenovo laptop, I messed up. I had rebooted the laptop and there were some leftovers around from an attempted installation of the proprietary Nvidia driver. The system booted fine and was functional, but those leftovers where enough to make the screen go blank. The fix is easy, if you can enter the system in some other way: log in and remove anything related to the Nvidia driver. But unfortunately the only way to log in was from the console, so I was “de facto” locked out.
The first attempt to get out of the mud was to force a reboot of the system and in rescue mode. The system booted well, but after I typed the root password the boot process went a bit too far, loaded the infamous leftovers of the driver and here we go again, with a blank screen.
The way out: runlevels
Luckily, in UNIX systems there is the concept of runlevels. Roughly, a runlevel associates a number (what we humans call “the runlevel”) to the services that should be activated and deactivated when the system enters that state. Runlevels are then different states of a UNIX system, and only one is active at any given time. Runlevels 0, 1 and 6 are pretty standard: the system enters runlevel 0 when it’s being halted, 6 when it’s rebooted, and 1 when it goes into single-user mode (known also as “rescue mode” in Debian). Runlevels 2 to 5 are available for different modes of operations that are usually defined by those who designed the system. As you can imagine, not only they are used differently across different flavours of UNIX: they are used differently even across different distributions of Linux! But at least in the Linux case there is a standard: the Linux Standard Base defines the following specification for runlevels:
- 2: Multi-user mode
- 3: Multi-user mode with networking
- 4: Not used/user-definable
- 5: Start the system normally with appropriate display manager (with GUI)
Note: there is also a runlevel “S”, but we don’t talk about that here. Read the wikipedia article linked above if you want to know more.
Now, what are the runlevels for Debian? Good question: runlevels are a System V concept, while Debian has switched from System V to systemd years ago. Systemd uses the concept of targets instead of runlevels. They are similar and different at the same time: a target associates a name to a set of services (that is: systemd units) that should be activated/deactivated when that target is selected. For example: whereas System V has the runlevel 0, systemd defines the poweroff target.
The good news is, Debian has kept a compatibility interface between runlevels and systemd targets: you can still run the telinit
command to switch to, say, runlevel 1 and Debian will translate your command to a systemd activation request for the rescue target, so you can use the two concepts interchangeably.
Runlevel 3 to the rescue
Now, back to my problem. The system by default boots in runlevel 5 / graphical target, which of course exercises the advanced video drivers, so it’s not a good choice. runlevel 1 / rescue target seems also to get too far and exercise advanced video drivers, thus not a good choice either. The next attempt would be to run one of the intermediate targets, e.g. runlevel 3, which would then activate the multi-user target, hopefully in console (text-only) mode. Since neither the default runlevel nor the single-user mode work, I needed to boot the system directly in runlevel 3. How? It’s simple, once you know: you must change one of the command lines that grub, the boot manager, executes when it boots the system. To access the grub commands from the grub interface (the text-based interface from which you select which kernel to boot), select the boot option that you want to modify (in this case: the default boot option) and press “e
” in the grub interface: a list of commands will appear. From here, you have two options:
Method 1: set the runlevel: find a line prefixed by the word linux
, similar to this one:
linux /vmlinuz-5.4.0-0.bpo.3-amd64 root=/dev/mapper/example--vg-root ro quiet
add ” 3″ at the end of the line:
linux /vmlinuz-5.4.0-0.bpo.3-amd64 root=/dev/mapper/example--vg-root ro quiet 3
That will make the system boot in the runlevel 3. You can also remove the word “quiet” if you want the boot process to be more verbose — which can be useful when you are trying to debug a boot problem.
Method 2: same as above, but add “systemd.unit=multi-user.target” instead of “3”:
linux /vmlinuz-5.4.0-0.bpo.3-amd64 root=/dev/mapper/example--vg-root ro quiet systemd.unit=multi-user.target
Then, to boot with the modified commands, press F10.
And that worked: the multi-user target didn’t try to load the Nvidia driver, exactly as I hoped, and I was able to clean up the mess and successfully reboot the system.
That’s it! Until next time, enjoy!