How to let the system start not into the desktop system, but to run their own procedures

How to let the system start not into the desktop system, but to run their own procedures

Not a direct answer, but it sounds like knowing how the system decides what to run (and when) might be helpful…

If you just want to see basics skip to “About the Actual Rc.Local:” (lots of people ask about this so I’m providing a more in-depth answer others might use as well).

The very first process the system runs becomes process ID 1. This in turn is what launches everything. That process is named “init”. init has used different means of picking things to launch over the years, so mechanics have changed, but some of the terminology remains.

init has (through other software) what are basically “bookmarks” of things to launch and call a “runlevel”. Describing runlevel depends on which Linux distribution, and even the release within this. Typically “runlevel 3” is “multi-user with networking”. Typically “runlevel 5” is having the GUI available in addition to everything in 3. Other runlevels might be named for reboot, shutdown, a debug mode for single user, so on.

The normal install with GUI will boot to runlevel 5, a.k.a., “graphical.target”. I say “graphical.target” because the software which init uses is actually “systemd”. Think of systemd as a kind of library catalog of services and conditions the system might run. If you are set up for boot to “multi-user.target”, then you are set to run purely in text mode, but otherwise normal operation. If you are set to boot to “graphical.target”, then you are able to do everything in “multi-user.target” plus the GUI. Neither of these matter for your question because neither requires you to log in…you can leave this as is and simply ignore login.

However, your application might have requirements. If this is a CUDA application (and you need to provide many more details about what your application requires, e.g., CUDA), then this likely (but not always) dictates that it must run in an X GUI environment. This doesn’t mean you have to log in personally, but if this is the case, then you at least need a virtual X server running which can automatically log in.

It used to be that file “/etc/rc.local” was always present and always used for any custom application start which would always run after reaching the final run stage of either mutli-user.target or graphical.target, but would not care about individuals logging in. This is still sort of true, but it is a side-effect of the systemd target “rc-local.service”. Thus, “rc-local.service”, if running (and it is a bookmark within both multi-user.target and graphical.target), implies you can start custom apps in file “/etc/rc.local” (in some cases you might have to create the file, but in many cases a blank template is already there). This file is just a bash script.

You can see if this is running in Ubuntu via:
systemctl status rc-local.service

If not already enabled:

sudo systemctl enable rc-local.service
sudo systemctl start rc-local.service

About the Actual Rc.Local:

This always starts with “#!/bin/sh -e”, which specifies it is a more secure (less functional) version of bash. Two or more lines later actual user customization takes place. If the file is not present, then you can use this Ubuntu 18.04 template to create “/etc/rc.local”:

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Add your customizations here.

exit 0

Application commands in that file will run as user root. If you wanted the command “date” to be redirected to file “/tmp/testing.txt”, then you could add this line:
/bin/date >/tmp/testing.txt

That resulting file would be owned by root, and the date would be executed by root.

If you need the command to be run as a different user, then keep in mind that you can use “sudo” in this script because user root has no need to enter any password to use sudo. The "sudo -u ubuntu something would execute the command “something” as user “ubuntu” without bothering for user “ubuntu”'s password. If you were to start a virtual X server without sudo, then it would run as user root, but this may not be what you want. If you were to start a virtual X server with “sudo -u ubuntu”, then the virtual server would run as user “ubuntu”. You need to specify a lot more detail on the nature of the application you are starting since there won’t be a terminal or GUI service running.

Note that the “polished and professional” way to do this same thing in the modern era of “systemd” is to create a service instead of using rc.local (I say that a bit “tongue in cheek” because systemd isn’t really any better at this, but it would allow creating a repeatable “package install” of your feature and not just something randomly typed in to a file…it could then be maintained by means of packages). One would then add the custom service as a requirement when reaching the appropriate runlevel…either “multi-user.target” or “graphical.target”, and if this starts a custom virtual X server, then it could run even in multi-user.target (graphical.target is for normal users to log in via GUI and does not mean multi-user.target can’t have a custom X server).

In the long run I’d always start by testing in rc.local. If I didn’t have an “official” system to ship, and it was just for me, I’d simply leave it in rc.local. If I need something other users and multiple systems could use, then I’d use a systemd service, and probably create a dpkg/apt package to install this.