Глупый вопрос здесь. Я вижу это /sbin/reboot
кажется, ссылка на /bin/systemctl
. Однако это не ведет себя как "простая" ссылка потому что вызов /bin/systemctl
не то же как /sbin/reboot
.
Кроме того, хотя /bin/systemctl
действительно имеет a reboot
опция, /sbin/reboot
кажется, не простой псевдоним к /bin/systemctl reboot
, потому что, например, reboot --help
печатает определенную справку, которая не может быть достигнута с /bin/systemctl reboot --help
(или /bin/systemctl --help reboot
).
Таким образом, какова эта ссылка и как посмотреть на ее определение?
Деликатный вопрос, я нашел ответ, предоставленный @slm ♦, на Unix & Linux Q&A:
Много программ используют эту технику, где существует единственный исполняемый файл, который изменяет его поведение на основе того, как это выполнялось.
Обычно существует структура в программе, названной случаем/оператором переключения, который определяет имя, которым с исполняемым файлом назвали и затем назовет соответствующую функциональность для того исполняемого имени. То имя обычно является первым аргументом, который получает программа.
В то время как в исходном ответе предоставлены два примера с C и Perl, вот пример с Bash. В Bash позиционный параметр $0
содержит название сценария, который выполняется. Поэтому давайте создадим простой сценарий, названный program.sh
и сделайте это исполняемым файлом:
cat << EOF > program.sh && chmod +x program.sh
#!/bin/bash
echo "I was called as \"\${0##*/}\""
EOF
\$
выйдет из особого значения $
в cat
во время создания сценария.
${0##*/}
произведет только название исполняемого файла без пути во время выполнения сценария.
Затем давайте создадим три символьных ссылки на тот сценарий:
for link in call-{1..3}; do ln -s program.sh $link; done
Теперь, в зависимости от того, как мы звоним program.sh
- непосредственно или любой из символьных ссылок, которые мы создали - вывод будет отличаться:
$ ./program.sh
I was called as "program.sh"
$ ./call-1
I was called as "call-1"
$ ./call-2
I was called as "call-2"
$ ./call-3
I was called as "call-3"
Как pa4080 говорит, это - просто нормальная символьная ссылка, и systemctl
самостоятельно то, что проверяет то, что называет его, был выполнен как, для решения что действие работать. Этот вид вещи может быть достигнут с любым механизмом, который заставляет тот же исполняемый файл быть выполненным под несколькими именами; на практике это достигается с помощью символьных ссылок или жестких ссылок. В системах GNU/Linux, как Ubuntu, наиболее распространено использовать символьные ссылки с этой целью.
В выпусках Ubuntu с systemd (который в настоящее время включает все поддерживаемые версии кроме 14.04 LTS, который использует Выскочку), не просто reboot
команда, но также и halt
, poweroff
, runlevel
, shutdown
, и telinit
команды являются всеми символьными ссылками на /bin/systemctl
:
$ file /sbin/{halt,poweroff,reboot,runlevel,shutdown,telinit}
/sbin/halt: symbolic link to /bin/systemctl
/sbin/poweroff: symbolic link to /bin/systemctl
/sbin/reboot: symbolic link to /bin/systemctl
/sbin/runlevel: symbolic link to /bin/systemctl
/sbin/shutdown: symbolic link to /bin/systemctl
/sbin/telinit: symbolic link to /bin/systemctl
Точные действия systemctl
предпринимает на основе имени, которое Вы используете для выполнения его, а также другие способы, которыми можно указать те действия, объяснены подробно в этом превосходном ответе JdeBP к тому, Каково различие между этими командами для перевода в нерабочее состояние сервера Linux? на Unix. SE. Как это объясняет, эти команды (кроме runlevel
) действуйте в качестве сокращения от systemctl isolate ...
команды с ...
замененный различными целями.
В случае, если Вам интересно, код C, который рассматривает то, что называет Вас, раньше вызывал systemctl
в решении, что действие работать расположен в parse_argv
функция, определяемая в systemctl.c
, который в настоящее время запускает на строке 6972 из того файла. Для нахождения его, можно искать:
static int parse_argv(int argc, char *argv[]) {
Соответствующие части охватывают большую часть той функции, но все это примерно напоминает этот фрагмент его, продолжаясь так же, но с другим кодом для каждой строки, и с некоторыми другими проверками и переходящей логикой:
if (strstr(program_invocation_short_name, "halt")) {
arg_action = ACTION_HALT;
return halt_parse_argv(argc, argv);
} else if (strstr(program_invocation_short_name, "poweroff")) {
arg_action = ACTION_POWEROFF;
return halt_parse_argv(argc, argv);
} else if (strstr(program_invocation_short_name, "reboot")) {
Другие примеры команд, которые исследуют, как они были вызваны, чтобы (иногда) действовать по-другому, включают vim
, который ведет себя по-другому, когда выполнено как vim
, ex
, view
, gvim
, gview
, и несколько других; ip
, посмотрите этот вопрос; gksu
, посмотрите тот вопрос; less
, который изменяет его появление, если названо more
(но все еще позволяет Вам прокрутить двунаправлено, в отличие от Ubuntu more
); busybox
; и большинство оболочек стиля Границы, такой как bash
и zsh
, которые автоматически ведут себя более совместимо с требованиями POSIX для sh
если выполнено как sh
.