8 Создание более гибких rc.d скриптов

Во время запуска и остановки системы rc.d скрипт предположительно оперирует над той или иной подсистемой целиком. К примеру, скрипт /etc/rc.d/netif должен запускать и останавливать все сетевые интерфейсы, описанные в rc.conf(5). Так же каждая задача должна быть целиком описана одной командой - start или stop. Но между запуском системы и ее остановкой rc.d должны помогать системному администратору управлять запущенными процессами, и зачастую для этого необходимо больше гибкости. Например, администратор может сконфигурировать новый интерфейс в rc.conf(5) и ему понадобиться запустить только этот интерфейс, не затрагивая все остальные. В следующий раз, администратору может понадобиться остановить этот единственный интерфейс. Для этого можно передавать дополнительные опции для скрипта, такие как название интерфейса, в виде дополнительных аргументов командной строки.

К счастью, rc.subr(8) позволяет передать скрипту любое количество аргументов (в пределах системных ограничений). Поэтому, можно обойтись минимальными изменениями скрипта.

Как rc.subr(8) может получить доступ к аргументам командной строки? Передать их непосредственно внутри скрипта функции run_rc_command невозможно, так как функции sh(1) не имеют доступа к позиционным параметрам вызывающего их объекта. Кроме того, в rc.d скриптах считается хорошим тоном, когда скрипт сам определяет какие аргументы должны быть переданы его методам.

В rc.subr(8) используется следующее решение: функции run_rc_command передаются все аргументы командной строки, при этом подразумевается, что первым из этих аргументов является имя запускаемого метода - start, stop и т.д. Эти аргументы сдвигаются внутри функции run_rc_command c помощью оператора sh(1) shift. Таким образом, переменная $2 в изначальной командной строке передается методу как $1, и так далее.

So the approach adopted by rc.subr(8) is as follows:

Хорошо проиллюстрировать это нам поможет следующий пример. Давайте изменим наш первый простейший скрипт так, чтобы его сообщения зависели от дополнительных аргументов. Итак:

#!/bin/sh

. /etc/rc.subr

name="dummy"
start_cmd="${name}_start"
stop_cmd=":"
kiss_cmd="${name}_kiss"
extra_commands="kiss"

dummy_start()
{
        if [ $# -gt 0 ]; then(1)
                echo "Greeting message: $*"
        else
                echo "Nothing started."
        fi
}

dummy_kiss()
{
        echo -n "A ghost gives you a kiss"
        if [ $# -gt 0 ]; then(2)
                echo -n " and whispers: $*"
        fi
        case "$*" in
        *[.!?])
                echo
                ;;
        *)
                echo .
                ;;
        esac
}

load_rc_config $name
run_rc_command "$@"(3)

Какие значимые изменения были сделаны в этом файле?

(1)
Все аргументы, переданные скрипту после аргумента start будут переданы как аргументы соответствующему методу. Мы можем использовать их любым способом в соответствии с поставленной задачей и в меру наших навыков и фантазии. В настоящем примере мы просто передаем их все команде echo(1) как одну строку в переменной $* внутри двойных кавычек. Вот пример как может быть вызван такой скрипт:
# /etc/rc.d/dummy start
Nothing started.
# /etc/rc.d/dummy start Hello world!
Greeting message: Hello world!
(2)
Такой же трюк можно проделать с любыми методом нашего скрипта, а не только со стандартными. Добавим нестандартный метод kiss, и он будет иметь те же возможности, что и метод start:
# /etc/rc.d/dummy kiss
A ghost gives you a kiss.
# /etc/rc.d/dummy kiss Once I was Etaoin Shrdlu...
A ghost gives you a kiss and whispers: Once I was Etaoin Shrdlu...
(3)
Если мы хотим просто передать все дополнительные аргументы любому методу, мы можем просто заменить "$1" на "$@" в последней строке нашего скрипта, в которой мы вызываем run_rc_command.

Important: Программисты на языке sh(1) обязаны понимать тонкую разницу между специальными переменными $* и $@ и тем, как они передают позиционные параметры. Для более тщательного изучения этого вопроса ознакомьтесь с очень подробной страница справочника sh(1). Не используйте эти переменные, если вы не понимаете их действие, поскольку их неправильное использование может сделать ваш скрипт неправильно работающим и небезопасным.

Note: В настоящее время функция run_rc_command имеет ошибку, которая может привести терять к потере разделителей между аргументами. Поэтому, аргументы, в которых присутствует пробел могут обрабатываться некорректно. Появление этой ошибки может быть спровоцировано неправильным использованием переменной $*.

Этот, и другие документы, могут быть скачаны с ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

По вопросам, связанным с FreeBSD, прочитайте документацию прежде чем писать в <questions@FreeBSD.org>.
По вопросам, связанным с этой документацией, пишите <doc@FreeBSD.org>.
По вопросам, связанным с русским переводом документации, пишите в рассылку <frdp@FreeBSD.org.ua>.
Информация по подписке на эту рассылку находится на сайте проекта перевода.