2
which shutdown

returns

/usr/bin/shutdown

I also tried sudo which shutdown just in case...but got the same result.

I can see that

lrwxrwxrwx 1 root root 9 Dec 13 03:38 /usr/bin/shutdown -> systemctl

I can also do something like (shutdown the machine in 2 hours)

sudo shutdown -h +120

But if I try something goofy like this:

 sudo systemctl -h +120

I get an error...

When I issue shutdown am I actually invoking the /usr/bin/shutdown? If so how does the link from shutdown to systemctl actually work then?

hba
  • 259

1 Answers1

2

Short answer

A program can know the name it was invoked as; it learns its own name by examining argv[0]. This allows identical executables to behave differently under different names (example) or a single executable to behave differently when called via differently named symlinks (example).

In your case the actual systemctl executable knows if it's being invoked as systemctl or shutdown or whatever. It adjusts its behavior accordingly.


Additional details

The array of arguments is set by the parent process. It's a convention (not a strict requirement) that argv[0] is the name. The parent may or may not follow the convention. When you run systemctl or shutdown from a shell, the shell is the parent and it follows the convention; in general shells follow the convention.

An example where the convention is not followed is the behavior of login (and tools that try to mimic it): login uses a leading dash in the zeroth argument to inform a child shell it is supposed to be a login shell. Let's assume the login shell is Bash. In the shell echo "$0" will show you -bash, despite the fact the executable is named bash. This leading dash is another convention.

You can run systemctl with an arbitrary name. Some names are special, they change the behavior of systemctl, this is deliberately to support symlinks like the one you observed. In my Debian 12 these are (among others) shutdown and runlevel. You don't need to create a symlink or a copy to pass an arbitrary argv[0] to systemctl, you can use exec -a of Bash.


Examples of using arbitrary argv[0]

(The examples assume systemctl can be reached via $PATH. Supply the full pathname if needed.)

bash -c 'exec -a foo      systemctl'        # should behave like plain systemctl because foo is not a name that would change the behavior
bash -c 'exec -a shutdown systemctl --help' # should behave like shutdown --help
bash -c 'exec -a runlevel systemctl'        # should behave like runlevel

In fact you can use a symlink to systemctl (like your shutdown) and still pass an arbitrary argv[0]. Example:

bash -c 'exec -a runlevel shutdown'         # should behave like runlevel

Fixing your "goofy command"

Your "goofy command"

sudo systemctl -h +120

can be fixed like this:

sudo bash -c 'exec -a shutdown systemctl -h +120'

Here the symlink named shutdown is not used at all (it might not exist), the executable systemctl is invoked directly; still it behaves like shutdown because we pass the right name (shutdown) as argv[0].