34

In Arch Linux, if I do ls -l in /sbin, I can see that reboot, shutdown and poweroff are all symlinks to /usr/bin/systemctl. But issuing reboot, shutdown and systemctl commands obviously does not all have the same behaviour.

Is ls -l not showing me full information regarding symlinks? How can I, for example, know what the real symlink of reboot is?

Anthon
  • 79,293
Gradient
  • 3,659

1 Answers1

47

Many programs make use of this technique where there is a single executable that changes its behavior based on how it was executed.

There's typically a structure inside the program called a case/switch statement that determines the name the executable was called with and then will call the appropriate functionality for that executable name. That name is usually the first argument the program receives. For example, in C when you write:

int main(int argc, char** argv)

argv[0] contains the name of the called executable. At least, this is the standard behaviour for all shells, and all executables that use arguments should be aware of it.

Example in Perl

Here's a contrived example I put together in Perl which shows the technique as well.

Here's the actual script, call it mycmd.pl:

#!/usr/bin/perl

use feature ':5.10';

(my $arg = $0) =~ s#./##;

my $msg = "I was called as: ";

given ($arg) {
  $msg .= $arg  when 'ls';
  $msg .= $arg  when 'find';
  $msg .= $arg  when 'pwd';
  default { $msg = "Error: I don't know who I am 8-)"; }
}

say $msg;
exit 0;

Here's the file system setup:

$ ls -l
total 4
lrwxrwxrwx 1 saml saml   8 May 24 20:49 find -> mycmd.pl
lrwxrwxrwx 1 saml saml   8 May 24 20:34 ls -> mycmd.pl
-rwxrwxr-x 1 saml saml 275 May 24 20:49 mycmd.pl
lrwxrwxrwx 1 saml saml   8 May 24 20:49 pwd -> mycmd.pl

Now when I run my commands:

$ ./find 
I was called as: find

$ ./ls
I was called as: ls

$ ./pwd
I was called as: pwd

$ ./mycmd.pl 
Error: I don't know who I am 8-)
Netch
  • 2,529
slm
  • 369,824
  • See also: ssh-argv0 – jordanm May 25 '13 at 00:19
  • Thank you! This is a trick I didn't think about. – Gradient May 25 '13 at 01:46
  • 4
    This is actually how BusyBox works. It has a single binary that acts as most of the common GNU utilities. – Fake Name May 25 '13 at 03:28
  • 1
    The arguments to the main are reversed. argc comes before argv. – Bakuriu May 25 '13 at 08:02
  • 4
    in C, you can't make a switch statement with strings. – BatchyX May 25 '13 at 13:51
  • Thanks for the feedback. Someone else added that bit to my answer. This answer is just giving the OP the gist of how/why the links are present in his /sbin directory. There are ways to get the functionality via switch as described here in C/C++. The concept is what matters not the semantics. – slm May 25 '13 at 14:06
  • 4
    +1 for "I don't know who I am" :) – user May 25 '13 at 14:56
  • I've copy/paste part of this answer in AU where is provided also and Bash example: https://askubuntu.com/a/1023946/566421 – pa4080 Apr 11 '18 at 09:27
  • 1
    I just wondered why this isn't considered bad programming style: By making systemctl doing the switch on the various names of callers ('shutdown', 'reboot', etc.) effectively additional dependencies are created. Wouldn't it be better to let 'shutdown' just be a simple command calling 'systemctl poweroff' (and let systemctl as-is)? – Grimm Apr 01 '21 at 18:31
  • Actual implementation in systemd

    https://github.com/systemd/systemd/blob/main/src/systemctl/systemctl.c#L1090

    – xitong Feb 03 '24 at 20:25