Управление сервисами биллинговой системы в ОС Solaris 10

Все права защищены (c) 2001-2011 NetUP (www.netup.ru)
Перепечатка материалов разрешается только с предварительного разрешения
компании NetUP (info@netup.ru)

Обращаем ваше внимание на то, что информация в данной статье может быть не актуальной.

В ОС Solaris 10 появилась новая подсистема управления сервисами - SystemManagementFacility (SMF) [1], позволяющая лучше контролировать запуск и остановку сервисов биллинговой системы. Преимуществами данной подсистемы является:

  • Отсутствует необходимость запускать дополнительный контролирующий процесс (watchdog). В случае если все процессы сервиса по каким-то причинам завершают работу, его перезапуск выполняется автоматически и немедленно.
  • Также отпадает необходимость контролировать порядок запуска сервисов и перезапуска зависимых сервисов – достаточно описать зависимости сервисов, и какие действия выполнять в случае останова «главного» сервиса. Система все будет делать автоматически.
  • Если при запуске сервиса обнаружится ошибка, из-за которой не происходит нормальный запуск, то он переводится в состояние, предотвращающее дальнейшие бесполезные попытки его запуска.

Так как все сервисы, описываемые тут, идентичны с точки зрения SMF, то в этом документе рассмотрен пример реализации управления запуском одного сервиса на примере сервера MySQL и описан минимум команд для управления сервисом.

Также приведены листинги необходимых файлов для запуска остальных сервисов биллинговой системы с помощью SMF. В дополнение приведен листинг функции notify_admin, которая определена в файле /netup/utm5/smf/mail.sh. Данная функция предназначена для отправки сообщений по электронной почте администратору. Эта функция используется для информирования администратора об остановах сервисов биллинговой системы, при этом дополнительно в электронном письме можно высылать определенное администратором количество последних строк из журнальных файлов сервиса на момент останова. Таким образом, администратор получит важную информацию по работе сервиса и своевременно сможет принять меры для устранения неполадок.

База данных MySQL

Предварительно необходимо произвести установку сервера базы данных MySQL, произвести инициализацию базы, запустить сервер и проверить работоспособность. Далее будет рассмотрен процесс интегрирования MySQLв подсистему управления процессами ОС Solaris 10.

Описания и параметры запуска всех сервисов, запуском которых занимается SMF, хранятся в репозитарии и могут быть просмотрены и отредактированы с помощью программы svccfg(1M).

Чтобы добавить сервис в репозитарий SMF необходимо создать его «манифест» (manifest) – файл в формате XML, описывающий параметры запуска сервиса, и «метод» (method) – это может быть любая команда. В данном примере метод представляет собой скрипт на языке Bourne Shell.

Создадим манифест для сервера MySQL как указано в листинге 1.1. Манифесты хранятся в каталоге /var/svc/manifest и разделены по категориям (подкаталогам). Эти категории созданы только для удобства администратора. Подходящей категорией для сервера баз данных является application, а для сервисов UTM5 создадим отдельную категорию, например utm.

Листинг 1.1 – файл /var/svc/manifest/application/mysql.xml
<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type='manifest' name='mysql:mysql'>
<!-- Имя сервиса -->
<service
name='application/mysql'
type='service'
version='1'>
<create_default_instance enabled='false' />
<single_instance />
<!-- Зависимости.
Если сервисы обозначеные как зависимости не работают – сервис не должен запускатся.-->
<dependency name='fs'
grouping='require_all'
restart_on='none'
type='service'>
<service_fmri value='svc:/system/filesystem/local' />
</dependency>
<dependency name='net'
grouping='require_all'
restart_on='none'
type='service'>
<service_fmri value='svc:/network/loopback' />
</dependency>
<!-- Команды для запуска.
Обратите внимание, что здесь же задается имя пользователя от которого команда будет выполнена. -->
<exec_method
type='method'
name='start'
exec='/lib/svc/method/svc-mysql start'
timeout_seconds='-1'>
<method_context>
<method_credential user='mysql' group='mysql' />
</method_context>
</exec_method>
<exec_method
type='method'
name='stop'
exec=':kill'
timeout_seconds='-1'>
</exec_method>
</service>
</service_bundle>

После этого необходимо создать «метод», который будет использоваться для запуска сервера базы данных как указано в листинге 1.2.
Методы обычно расположены в каталоге /lib/svc/method.

Листинг 1.2 – файл /lib/svc/method/svc-mysql
#!/sbin/sh
# mysql
#
# Пути к файлам необходимо заменить соответственно конфигурации
#

. /lib/svc/share/smf_include.sh

DB_DIR=/var/mysql
PID_FILE=${DB_DIR}/`/usr/bin/uname -n`.pid

case "$1" in
start)
/usr/local/mysql/bin/mysqld_safe --user=mysql --datadir=${DB_DIR} \
--pid-file=${PID_FILE} > /dev/null &
;;

stop)
if [ -f ${PID_FILE} ]; then
/usr/bin/pkill mysqld_safe > /dev/null 2>&1
/usr/bin/kill `cat ${PID_FILE}` > /dev/null 2>&1 && echo -n mysql
fi
;;

'restart')
stop
while pgrep mysqld > /dev/null
do
sleep 1
done
start
;;
*)
echo "Usage: `basename $0` {start | stop | restart}"
exit 64
;;
esac

После этого необходимо установить корректные права доступа командами:

chown root:sys /var/svc/manifest/application/mysql.xml
chmod 444 /var/svc/manifest/application/mysql.xml
chown root:bin /lib/svc/method/svc-mysql
chmod 555 /lib/svc/method/svc-mysql

Проверить корректность настроек можно командой:

svccfg validate /var/svc/manifest/application/mysql.xml && echo OK

OK

Далее необходимо произвести импорт данных из XML файла в репозитарий командой:

svccfg import /var/svc/manifest/application/mysql.xml

Запуск сервиса можно произвести командой:

svcadmvenablemysql

при этом вывод должен содержать строку:

svc:/application/mysql:default enabled.

Проверить запустился ли сервис можно командой:

svcs -a | grepmysql

При успешном запуске вывод должен содержать строку:

online 12:29:59 svc:/application/mysql:default

Для просмотра детальной информации о сервисе следует воспользоваться следующей командой:

svcs -xmysql

вывод этой команды:


svc:/application/mysql:default (?)
State: online since Tue Dec 27 12:18:40 2005
See: /var/svc/log/application-mysql:default.log
Impact: None.

Чтобы увидеть список процессов запущенных сервисом, воспользуйтесь следующей командой:

svcs -pmysql

Вывод содержит следующую информацию:


STATE STIME FMRI

online Dec_27 svc:/application/mysql:default

Dec_27 212 mysqld_safe

Dec_27 291 mysqld

В случае необходимости становить сервис можно командой:

svcadmvdisablemysql

Если во время запуска произошла ошибка и сервис не смог запуститься, например из-за ошибки в конфигурации, подсистема SMF переводит его в состояние maintenance и после этого сервис не запустится командой svcadmenable. Для того чтобы запустить сервис после устранения ошибки, необходимо сначала «сбросить» его состояние командой:

svcadmclearmysql

Для каждого сервиса ведется свой журнал событий. Журналы располагаются в каталоге /var/svc/log.

Рекомендуется, также, изучить страницы справочного руководства man к приведенным командам. На этом интеграция сервера базы данных MySQL в подсистему SMFзавершена.

База данных PostgreSQL

База данных PostgreSQLинтегрируется аналогично базе данных MySQL. Ниже приведены листинги соответствующих файлов.

Листинг 2.1 – файл /var/svc/manifest/application/pgsql.xm

<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type='manifest' name='postgresql:postgresql'>
<service
name='application/pgsql'
type='service'
version='1'>
<create_default_instance enabled='false' />
<single_instance />
<dependency name='fs'
grouping='require_all'
restart_on='none'
type='service'>
<service_fmri value='svc:/system/filesystem/local' />
</dependency>
<dependency name='net'
grouping='require_all'
restart_on='none'
type='service'>
<service_fmri value='svc:/network/loopback' />
</dependency>
<!-- Обратите внимание на имя пользователя. Замените соответственно вашей конфигурации. -->
<exec_method
type='method'
name='start'
exec='/lib/svc/method/svc-pgsql start'
timeout_seconds='-1'>
<method_context>
<method_credential user='postgres' group='postgres' />
</method_context>
</exec_method>
<exec_method
type='method'
name='stop'
exec='/lib/svc/method/svc-pgsql stop'
timeout_seconds='-1'>
<method_context>
<method_credential user='postgres' group='postgres' />
</method_context>
</exec_method>
</service>
</service_bundle>
Листинг 2.2 – файл /lib/svc/method/svc-pgsq

#!/sbin/sh
#
# PostgreSQL Method
#

. /lib/svc/share/smf_include.sh

PGPREFIX=/usr/local/pgsql
PGHOME=/var/pgsql
PGDATADIR=$PGHOME/data
PGLOG=$PGHOME/pgsql.log

case "$1" in
‘start’)
[ -x $PGPREFIX/bin/pg_ctl ] && $PGPREFIX/bin/pg_ctl -D $PGDATADIR –l $PGLOG start
sleep 3
pgrep -x postgres && exit $SMF_EXIT_OK
exit $SMF_EXIT_ERR_FATAL
;;
‘stop’)
$PGPREFIX/bin/pg_ctl stop -D "$PGDATADIR" -s -m fast
[ $? -eq 0 ] && exit $SMF_EXIT_OK
exit $SMF_EXIT_ERR_OTHER
;;
*)
echo "sfm."
;;
esac

Ядро биллинговой системы utm5_core

Интеграция сервисов биллинговой системы производится аналогично серверу базы данных. Ниже приводятся листинги соответствующих файлов.

Листинг 3.1 – файл /var/svc/manifest/utm/utm5_core.xm

<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type='manifest' name='UTM5:utm5_core'>
<service
name='utm/utm5_core'
type='service'
version='1'>
<create_default_instance enabled='false' />
<single_instance />
<!-- Cannot work without application -->
<dependency
name='mysql'
grouping='require_all'
restart_on='restart'
type='service'>
<service_fmri value='svc:/application/mysql' />
</dependency>
<exec_method
type='method'
name='start'
exec='/lib/svc/method/svc-utm5_core start'
timeout_seconds='120'>
<method_context>
<method_credential user='root' group='root' />
</method_context>
</exec_method>
<exec_method
type='method'
name='stop'
exec='/lib/svc/method/svc-utm5_core stop %{restarter/contract}'
timeout_seconds='120'>
<method_context>
<method_credential user='root' group='root' />
</method_context>
</exec_method>
<template>
<common_name>
<loctext xml:lang='C'>
NetUP UTM5 core
</loctext>
</common_name>
<description>
<loctext xml:lang='C'>
The Core of UTM5 System
</loctext>
</description>
<documentation>
<doc_link name='netup.ru'
uri='http://www.netup.ru' />
</documentation>
</template>
</service>
</service_bundle>
Листинг 3.2 – файл /lib/svc/method/svc-utm5_coe

#!/sbin/sh
#
# NetUP UTM 5 Core Method
#

. /lib/svc/share/smf_include.sh
. /netup/utm5/smf/mail.sh

CFGFILE=/netup/utm5/utm5.cfg
[ ! -f $CFGFILE ] && exit $SMF_EXIT_ERR_CONFIG
. $CFGFILE

BINDIR=/netup/utm5/bin
EXEC=utm5_core

[ ! -x $BINDIR/$EXEC ] && exit $SMF_EXIT_ERR_CONFIG

PIDFILE=${core_pid_file:-/var/run/utm5_core.pid}
MAINLOG=${log_file_main:-/netup/utm5/log/main.log}
SVCLOG="/var/svc/log/utm-utm5_core:default.log"

check_and_kill ()
{
PID=`head -1 $1`
kill -0 $PID > /dev/null 2>&1
[ $? -eq 0 ] && kill -USR1 $PID
}

case "$1" in
'start')
[ -x $BINDIR/$EXEC ] && $BINDIR/$EXEC &
sleep 5

if kill -0 $! > /dev/null 2>&1 ; then
echo "Success."
exit $SMF_EXIT_OK
else
echo "Error."
exit $SMF_EXIT_ERR_FATAL
fi
;;

'stop')

# Kill process
[ -f $PIDFILE ] && check_and_kill $PIDFILE
sleep 10
[ -f $PIDFILE ] && rm -f $PIDFILE

# Notify admins about service stop
notify_admin E "UTM5 Core exited!" "${SVCLOG}.40" "${MAINLOG}.30"
smf_kill_contract $2 KILL 1
;;

*)
echo "Usage: `basename $0` {start | stop}"
;;
esac

RADIUS-серверutm5_radius

Листинг 4.1 – файл /var/svc/manifest/utm/utm5_radius.xm

<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type='manifest' name='netup:utm5_radius'>
<service
name='utm/utm5_radius'
type='service'
version='1'>
<create_default_instance enabled='false' />
<single_instance />

<!-- Cannot work without utm5_core -->

<dependency
name='utm5_core'
grouping='require_all'
restart_on='restart'
type='service'>
<service_fmri value='svc:/utm/utm5_core' />
</dependency>

<!-- Execution methods -->
<exec_method
type='method'
name='start'
exec='/lib/svc/method/svc-utm5_radius start'
timeout_seconds='120'>
<method_context>
<method_credential user='root' group='root' />
</method_context>
</exec_method>
<exec_method
type='method'
name='stop'
exec='/lib/svc/method/svc-utm5_radius stop %{restarter/contract}'
timeout_seconds='120'>
</exec_method>
<template>
<common_name>
<loctext xml:lang='C'>
NetUP UTM5 radius
</loctext>
</common_name>
<documentation>
<doc_link name='netup.ru'
uri='http://www.netup.ru' />
</documentation>
</template>
</service>
</service_bundle>
Листинг 4.2 – файл /lib/svc/method/svc-utm5_radiu


#!/sbin/sh
#
# Radius method
#

. /lib/svc/share/smf_include.sh
. /netup/utm5/smf/mail.sh

CFGFILE=/netup/utm5/radius5.cfg

[ ! -f $CFGFILE ] && exit $SMF_EXIT_ERR_CONFIG

. $CFGFILE

MAINLOG=${log_file_main:-/netup/utm5/log/radius_main.log}
BINDIR=/netup/utm5/bin
EXEC=utm5_radius
PIDFILE=/var/run/utm5_radius.pid
SVCLOG="/var/svc/log/utm-utm5_radius:default.log"
PING=core_ping

case "$1" in
'start')
[ -x $BINDIR/$PING -a -x $BINDIR/$EXEC ] && PING_ARGS="-h ${core_host:-127.0.0.1} \
-P ${core_port:-11758} -l ${radius_login:-radius} -p ${radius_password:-radius} -i 2 -c 1"
if [ -n "$PING_ARGS" ]; then
$BINDIR/$PING $PING_ARGS && $BINDIR/$EXEC &
sleep 3
kill -0 $! || exit $SMF_EXIT_ERR_FATAL
exit $SMF_EXIT_OK
else
exit $SMF_EXIT_ERR_CONFIG
fi
;;
'stop')
notify_admin W "Radius exited!" "${SVCLOG}.40" "${MAINLOG}.30"
smf_kill_contract $2 KILL 1 && rm -f $PIDFILE && exit $SMF_EXIT_OK
;;
*)
echo "Usage: `basename $0` {stop|start}"
;;
esac

Сервис utm5_rfw

Листинг 5.1 – файл /var/svc/manifest/utm/utm5_rfw.xm

<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type='manifest' name='netup:utm5_rfw'>
<service
name='utm/utm5_rfw'
type='service'
version='1'>

<create_default_instance enabled='false' />
<single_instance />

<!-- Cannot work without utm5_core -->

<dependency
name='utm5_core'
grouping='require_all'
restart_on='restart'
type='service'>
<service_fmri value='svc:/utm/utm5_core' />
</dependency>

<!-- Execution methods -->

<exec_method
type='method'
name='start'
exec='/lib/svc/method/svc-utm5_rfw start'
timeout_seconds='120'>
<method_context>
<method_credential user='root' group='root' />
</method_context>
</exec_method>

<exec_method
type='method'
name='stop'
exec='/lib/svc/method/svc-utm5_rfw stop %{restarter/contract}'
timeout_seconds='120'>
</exec_method>

<template>
<common_name>
<loctext xml:lang='C'>
NetUP UTM5 rfw
</loctext>
</common_name>
<documentation>
<doc_link name='netup.ru'
uri='http://www.netup.ru' />
</documentation>
</template>
</service>
</service_bundle>
Листинг 5.2 – файл /lib/svc/method/svc-utm5_rf

#!/sbin/sh
#
# UTM5 rfw method
#

. /lib/svc/share/smf_include.sh
. /netup/utm5/smf/mail.sh

CFGFILE=/netup/utm5/rfw5.cfg
[ ! -f $CFGFILE ] && exit $SMF_EXIT_ERR_CONFIG
. $CFGFILE

MAINLOG=${log_file_main:-/netup/utm5/log/rfw_main.log}
BINDIR=/netup/utm5/bin
EXEC=utm5_rfw
EXEC_FLAGS="-f"
PIDFILE=/var/run/utm5_rfw.pid
SVCLOG="/var/svc/log/utm-utm5_rfw:default.log"

case "$1" in
'start')
[ -x $BINDIR/$EXEC ] && $BINDIR/$EXEC $EXEC_FLAGS &
sleep 3
kill -0 $! || exit $SMF_EXIT_ERR_FATAL
exit $SMF_EXIT_OK
;;
'stop')
notify_admin W "UTM5 RFW exited!" "${SVCLOG}.40" "${MAINLOG}.30"
smf_kill_contract $2 KILL 1 && rm -f $PIDFILE && exit $SMF_EXIT_OK
;;
*)
echo "Usage: `basename $0` {stop|start}"
;;
esac

Сервис utm5_rapida_check

Листинг 6.1 – файл /var/svc/manifest/utm/utm5_rapida_check.xml

<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type='manifest' name='netup:utm5_rapida_check'>
<service
name='utm/utm5_rapida_check'
type='service'
version='1'>
<create_default_instance enabled='false' />
<single_instance />

<!-- Cannot work without utm5_core -->

<dependency
name='utm5_core'
grouping='require_all'
restart_on='restart'
type='service'>
<service_fmri value='svc:/utm/utm5_core' />
</dependency>

<!-- Execution methods -->
<exec_method
type='method'
name='start'
exec='/lib/svc/method/svc-utm5_rapida_check start'
timeout_seconds='120'>
<method_context>
<method_credential user='root' group='root' />
</method_context>
</exec_method>
<exec_method
type='method'
name='stop'
exec='/lib/svc/method/svc-utm5_rapida_check stop %{restarter/contract}'
timeout_seconds='120'>
</exec_method>
<template>
<common_name>
<loctext xml:lang='C'>
NetUP UTM5 Rapida Check
</loctext>
</common_name>
<documentation>
<doc_link name='netup.ru'
uri='http://www.netup.ru' />
</documentation>
</template>
</service>
</service_bundle>
Листинг 6.2 – файл /lib/svc/method/svc-utm5_rapida_check

#!/sbin/sh
#
# Rapida Check method
#

. /lib/svc/share/smf_include.sh
. /netup/utm5/smf/mail.sh

CFGFILE=/netup/utm5/rapida5.cfg
[ ! -f $CFGFILE ] && exit $SMF_EXIT_ERR_CONFIG

BINDIR=/netup/utm5/bin
EXEC=utm5_rapida_check
SVCLOG="/var/svc/log/utm-utm5_rapida_check:default.log"

case "$1" in
'start')
[ -x $BINDIR/$EXEC ] && $BINDIR/$EXEC $CFGFILE &
sleep 3
kill -0 $! || exit $SMF_EXIT_ERR_FATAL
exit $SMF_EXIT_OK
;;
'stop')
notify_admin W "UTM5 Rapida Check exited!" "${SVCLOG}.40"
smf_kill_contract $2 KILL 1 && exit $SMF_EXIT_OK
;;
*)
echo "Usage `basename $0` {stop|start}"
;;
esac

Функция notify_admin

Листинг 7.1 – файл /netup/utm5/smf/mail.sh

#!/sbin/sh
# Copyright (c) 2001-2005 NetUP Inc. <info@netup.ru>. All rights reserved.
#
# Common variables
# ----------------
#
notify_admin_ARGS=$@
# Укажите адреса электронной почты администратора.
# По этим адресам будут приходить уведомления.
MAIL_ADMIN_MAIL=any@email.address
MAIL_COPY_TO=another@email.address

# Function
# ========
# Name: notify_admin ()
# Descr: Sends formatted email to admin
# Version: 0.2
# Usage: notify_admin [type] [subject] [message] [logfile.lines ...]
# [type] char {E|W|N} ERROR, WARNING, NOTICE respectively. Default "INFO".
# [subject] string Subject. If contains spaces MUST be "QUOTED".
# [message] string Message body. If contains spaces MUST be "QUOTED".
# [logfile.lines ...] string Last $lines to be included into message body of the $logfile
# (`tail -$lines $logfile' used)
# All parameters are optional.
#
notify_admin ()
{
#
# Initialize some variables
# -------------------------
notify_admin_ADMIN_MAIL=${MAIL_ADMIN_MAIL:-root}
notify_admin_COPY_TO=$MAIL_COPY_TO
notify_admin_STATUS="INFO"
notify_admin_SUBJECT=""
notify_admin_MESSAGE=""
notify_admin_MAILER_ARGS=""
#
# If command line contains status
# -------------------------------
case "$1" in
'E')
notify_admin_STATUS="ERROR"
shift
;;
'W')
notify_admin_STATUS="WARNING"
shift
;;
'N')
notify_admin_STATUS="NOTICE"
shift
;;
esac

#
# Set notify_admin_SUBJECT and notify_admin_MESSAGE variables
# -------------------------------------------
#
while echo "$1" | egrep -v '^[^ ]*\.[0-9]?+$' > /dev/null 2>&1
do
if [ -z "$notify_admin_SUBJECT" ]; then
notify_admin_SUBJECT="$1"
shift
continue
fi
if [ -z "$notify_admin_MESSAGE" ]; then
notify_admin_MESSAGE="${1}\n"
shift
continue
fi
break
done

#
# Check other arguments if any and prepare message
# ------------------------------------------------
if [ -n "$1" ]; then
for opt in "$@"
do
notify_admin_NUM_LINES=`echo "$opt" | grep -v ' ' | awk -F. '{ print $NF }' \
| egrep '^[0-9]?+$' 2>/dev/null`
if [ $? -ne 0 -o -z "$notify_admin_NUM_LINES" ]; then
continue
else
#
# work with the argument as it is a logfile.
# ------------------------------------------
notify_admin_LOG_FNAME=`echo "$opt" | sed "s/\.${notify_admin_NUM_LINES}$//;"`
[ -f "$notify_admin_LOG_FNAME" ] || { notify_admin_MESSAGE="${notify_admin_MESSAGE}\
\n---\n${notify_admin_LOG_FNAME} does not exist.\n\n"; continue; }
[ -r $notify_admin_LOG_FNAME ] || { notify_admin_MESSAGE="${notify_admin_MESSAGE}\
\n---\n${notify_admin_LOG_FNAME} is not readable.\n\n"; continue; }
[ -s $notify_admin_LOG_FNAME ] || { notify_admin_MESSAGE="${notify_admin_MESSAGE}\
\n---\n${notify_admin_LOG_FNAME} is empty.\n\n"; continue; }
notify_admin_MESSAGE="$notify_admin_MESSAGE\n---\n--- ${notify_admin_LOG_FNAME}\
:Last $notify_admin_NUM_LINES lines.\n---\n`eval tail -${notify_admin_NUM_LINES}
$notify_admin_LOG_FNAME`\n"
fi
done
fi

#
# Finally compose and send the message
# ------------------------------------
#

[ -n "$notify_admin_COPY_TO" ] && notify_admin_MAILER_ARGS="$notify_admin_MAILER_ARGS \
-c $notify_admin_COPY_TO"
{
echo "Date: `date`"
echo "Host: `hostname`"
echo "OS: `uname -sr`"
echo "Uptime: `uptime | sed 's/^[ ]*//;'`"
echo "Command: $0"
[ -n "$notify_admin_ARGS" ] && echo "Args: $notify_admin_ARGS"
echo "---"
echo "$notify_admin_SUBJECT"
echo ""
echo "$notify_admin_MESSAGE"
echo "*** End ***"
} | mailx -s "${notify_admin_STATUS}: $notify_admin_SUBJECT" \
$notify_admin_MAILER_ARGS $notify_admin_ADMIN_MAIL
}

[1] Страница в интернет с описанием подсистемы SMFhttp://www.sun.com/bigadmin/content/selfheal/sdev_intro.html