サービスの設定を簡単にする setconfig コマンド
Linuxでサービスの設定や解除を行う場合、GNOME等の"サービスの設定"ツールとかを使うのが一般的だが、遠隔からコマンドラインで設定したり、シェルスクリプトから設定する場合は結構手間がかかる。Redhat系の場合は、"chkconfig"というコマンドを使って一つ一つのサービスに対して設定を繰り返す必要がある。作業数も多くなり設定ミスの原因ともなりかねない。また、ランレベル毎の設定をきめ細かく行う場合はさらに手間がかかる。
そこで、(全てのRun Levelに対して)各サービスをまとめて設定するコマンドを作ってみた。
まず、サービスの設定を定義するデータファイルを作成する。(次の例では "servicelist" というファイルにサービスの設定が記述してある。)
[root@fedora-8 ~]# cat servicelist avahi-daemon 0:off 1:off 2:off 3:on 4:on 5:on 6:off bluetooth 0:off 1:off 2:on 3:on 4:on 5:on 6:off irda 0:off 1:off 2:off 3:off 4:off 5:off 6:off isdn 0:off 1:off 2:on 3:on 4:on 5:on 6:off lm_sensors 0:off 1:off 2:off 3:off 4:off 5:off 6:off sendmail 0:off 1:off 2:on 3:on 4:on 5:on 6:off sshd 0:off 1:off 2:on 3:on 4:on 5:on 6:off [root@fedora-8 ~]#
このデータファイルを引数として次のように実行するだけ。
[root@fedora-8 ~]# setconfig servicelist
これでリストに定義しているサービスのそれぞれのランレベルに関しての設定を全て行う。リストのフォーマットはご覧の通り "chkconfig --list" の出力形式と同じなので、ひな形リストは chkconfig を使って生成すればいい。
[root@fedora-8 ~]# chkconfig --list > servicelist [root@fedora-8 ~]# vi servicelist : : [root@fedora-8 ~]# setconfig servicelist
コマンドの引数は以下の通り。
Usage: setconfig [-qv] [--help] [config_list]
"-q"はメッセージを一切出さない。"-v"は逆に色々とメッセージを出すようにする。"config_list"がデータとなるリストで、ファイルの指定がなければ標準入力から読み込む。従って、次のような利用も可能。(この例では bluetooth と isdn のサービスを全てのランレベルでoffにして設定している。)
[root@fedora-8 ~]# chkconfig --list | grep -e bluetooth -e isdn | sed -e 's/on/off/g' | setconfig -v
■ サービス設定リストのフォーマット
setconfigに与えるサービス設定リストのフォーマットについては次のようの設定した。
- 基本的には "chkconfig --list" の形式。空白もしくはタブで区切られている。(従って、空白やタブで区切られていれば整列する必要はない。)
- 行頭に "#" がある行は無視する。コメント行として扱う。
- xinetd起動のサービスについては対象範囲外とする。
- ランレベルは0〜6まで全て定義しなくて良い。設定が必要なランレベルのだけ記述れば良い。記述されていないランレベルに関しては変化しない。(以前の設定のまま残る。)例えば、次のようなリストでOK。
avahi-daemon 2:off 3:off 4:off 5:on # bluetooth is off at run-level 3 bluetooth 3:off irda 2:off 3:off 4:off 5:off isdn 2:on 4:on 5:off
あとは余り説明の必要もないだろう。
■ インストールについて
setconfig はシェルスクリプトとして記述されたプログラムであり、「Source list of "setconfig"」にプログラムを載せているので、利用する場合はコピー&ペーストでシェルスクリプトファイルとして保存するだけ。例えば、次の要領でファイルに保存し、実行権を与えるだけ。
[root@fedora-8 ~]# cat > /usr/local/bin/setconfig 【ブログからコピーしたプログラムをペーストする。最後に Ctrl-D を入力して終了。】 [root@fedora-8 ~]# chmod +x /usr/local/bin/setconfig
なお、setconfigの引数の処理に "shargs" という別のプログラムを利用している。setconfigを利用する場合にはshargsも必要になる。ただ、shargsも同様にシェルスクリプトとして書かれているので、上記と同じ要領で簡単にインストールできる。(shargsについては「シェルスクリプトの引数を処理するためのシェルスクリプト」を参照。プログラムは「program list of "shargs" without line-number」からコピーしてくる。)shargsは /usr/local/bin に置いてあるという前提で setconfigは作っているので、もし異なる場所に設置しているのであれば setconfigの中の ". /usr/local/bin/shargs"の部分を適宜変える。
■ プログラムについて
プログラムにつては特段説明も必要ないと思う。1つだけ言い訳をしておくと、プログラムの中でreadコマンドを使って設定リストを1行1行読み込み、各フィールドをシェル変数に代入している。今回はあえて「配列変数」は使わなかった。配列変数を使えばもう少し(ちょっとだけだが)プログラムの記述が簡略化できるが、元々、Bourne Shellには配列シェル変数はなかったので、どうも配列を使うのをためらってしまう。(個人的な趣味の問題だが。)
あと、setconfigが出力するメッセージに関していくつかのレベルに分けている。
レベル | 意味 |
---|---|
II | 単なる情報。余り意味はない。 |
オペレータからの入力を必要とするメッセージ。今回は使っていない。 | |
WW | 警告メッセージ。プログラムの実行には差し支えない。 |
EE | エラーメッセージ。プログラムの実行に影響する。(通常はexitする。) |
-- | その他。 |
XX | メッセージの定義が不明の場合に出力。 |
Xウィンドウのログ、/var/log/Xorg.0.logを見ていて、ログがレベル分けしてあるので問題ヵ所を見つけやすいと思っていた。そこで、それに似たログの出力にしてみた。
Source list of "setconfig"
#! /bin/bash # setconfig Ver. 0.001 (2008/07/20) # Copyright (C) 2008 Adsaria # This program is free software; you can redistribute it and/or modify it. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY. ### Argument handling ########################################################## ARGS_DEF_opt_char_flg="qv" ARGS_DEF_opt_word_flg="help" ARGS_DEF_arg_namelist="config_list" ARGS_DEF_arg_num_must=0 . /usr/local/bin/shargs if [ "${ARGS_error}" == "Y" ]; then echo "${ARGS_usage}" 1>&2 ; exit 1; fi if [ "${ARGS_opt_help}" == "Y" ]; then echo "${ARGS_usage}" 1>&2 ; exit 1; fi if [ "${ARGS_opt_q}" == "Y" ]; then QUIET="yes"; else QUIET="" ; fi if [ "${ARGS_opt_v}" == "Y" ]; then CHATTY="yes"; else CHATTY="" ; fi if [ "${QUIET}" == "yes" ]; then CHATTY=""; fi ### Define shell vars ########################################################## CMD_NAME=`basename ${ARGS_0}` ### Define local functions ##################################################### function msg () { # Return Code 0: massage out, 1: message hold, 2: error ECHO_FLAG= if [ "${1}" == "-n" ]; then ECHO_FLAG="${ECHO_FLAG} -n"; shift; fi if [ -z "${1}" -o -z "${2}" ]; then return 2; fi MSG_CATEGORY="${1}" MSG_BODY="${2}" DO_ECHO="yes" case "${MSG_CATEGORY}" in II|I|ii|i) MSG_CATEGORY="II" if [ "${CHATTY}" != "yes" ]; then DO_ECHO="no"; fi ;; --|-) MSG_CATEGORY="--" if [ "${CHATTY}" != "yes" ]; then DO_ECHO="no"; fi ;; QQ|Q|qq|q) MSG_CATEGORY="QQ" ;; WW|W|ww|w) MSG_CATEGORY="WW" if [ "${QUIET}" == "yes" ]; then DO_ECHO="no"; fi ;; EE|E|ee|e) MSG_CATEGORY="EE" if [ "${QUIET}" == "yes" ]; then DO_ECHO="no"; fi ;; *) MSG_CATEGORY="XX" ;; esac if [ "${DO_ECHO}" == "yes" ]; then echo $ECHO_FLAG "(${MSG_CATEGORY}) $MSG_BODY" 1>&2 fi } ### Check arguments ############################################################ CONFIG_LIST_FILE= if [ -n "${ARGS__config_list}" ]; then if [ "${ARGS__config_list}" != "-" ]; then if [ -f ${ARGS__config_list} ]; then CONFIG_LIST_FILE=${ARGS__config_list} exec < ${CONFIG_LIST_FILE} else msg e "\"${ARGS__config_list}\" does not exist or is not a file." exit 1 fi fi fi ################################################################################ while read SERVICE LEVEL0 LEVEL1 LEVEL2 LEVEL3 LEVEL4 LEVEL5 LEVEL6 ; do if [ -z "${SERVICE}" ]; then continue; fi if [ "${SERVICE::1}" == "#" ]; then continue; fi if [ "${SERVICE}" == "xinetd" ]; then msg i "ignoring \"xinetd\" services." break fi msg i "${SERVICE} ${LEVEL0} ${LEVEL1} ${LEVEL2} ${LEVEL3} ${LEVEL4} ${LEVEL5} ${LEVEL6}" if [ -x "/etc/init.d/${SERVICE}" ]; then for (( count = 0 ; count <= 6 ; count++ )); do eval "CURRENT=\$LEVEL${count}" if [ -z "${CURRENT}" ]; then continue; fi LEVEL=${CURRENT::1} ONOFF=${CURRENT:2} if [ ${LEVEL} -ge 0 -a ${LEVEL} -le 6 ]; then if [ ${ONOFF} == "on" -o ${ONOFF} == "off" ]; then chkconfig --level ${LEVEL} ${SERVICE} ${ONOFF} else msg w "switch must be \"on\" or \"off\"" fi else msg w "level must be in 0..6" fi done else msg w "service \"${SERVICE}\" does not installed." fi done