シェルのメッセージを一元的に出力する自作のツールです。
職場で使われているロギングツールがシンプルで使いやすいので、同じようなものを自作したものです。
ツールはgithubで公開しています。
- uploggerのページ → Uplogger by Noppy
- githubソース → Noppy/uplogger · GitHub
シェルのメッセージを一元的に出力する自作のツールです。
職場で使われているロギングツールがシンプルで使いやすいので、同じようなものを自作したものです。
ツールはgithubで公開しています。
オープンソースでよくある、configure → make → make installというセットアップの流れ。これはGNUのautotoolsというツール&フレームワーク群により実現されている。
本記事ではそのautotoolsによりconfigureを作成する手順を説明する。
ユーザが編集するファイルは、configure.acとMakefile.am。これらファイルを修正した時は、aclocalコマンド以降を都度実行してファイルを再生性する。なので、aclocalコマンド以降をシェル化して一気に実行するようにしておくと便利である。
automakeコマンド実行時に求められるファイルを作成する。とりあえずファイルがあればよいので、空ファイルを作成する。(内容は必要に応じ別途修正する)
$ touch INSTALL NEWS README LICENSE AUTHORS ChangeLog
次のautoscanコマンドで、AC_CONFIG_FILESを自動生成するため、とりあえずMakefile.amを作成する。とりあえずこの段階では空ファイルでもかまわない。(automake実行時に中身があればOK)
-> Makefile.amのつくり方(別途作成予定)
configure.scanを作成し、それをRenameしてconfigure.acを作成する。
$ autoscan $ mv configure.scan configure.ac
configure.acを修正する。詳細は別途作成
# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. sAC_PREREQ([2.63]) AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) <== パッケージ&バージョン&連絡先を記入 AC_CONFIG_SRCDIR([src/uplog_util.c]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. AC_CHECK_HEADERS([fcntl.h limits.h locale.h stdlib.h string.h sys/socket.h syslog.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_PID_T # Checks for library functions. AC_FUNC_FORK AC_FUNC_MALLOC AC_FUNC_STRNLEN AC_CHECK_FUNCS([dup2 getcwd gethostname gettimeofday memset realpath select setlocale socket strerror]) AC_CONFIG_FILES([Makefile conf/Makefile src/Makefile]) <==Makefile.amを増やしたらここに追加 AC_OUTPUT
以後はシェル化し、Makefile.amやconfigure.ac修正時に都度実行すると楽。
echo aclocal aclocal echo autoheader autoheader echo automake automake --add-missing --copy echo autoconf autoconf
本当はvSphere CLIをインストールして利用すればよいのだが、VMのPowerOnとハイパーバイザのシャットダウンだけで十分だったので、TeraTermのマクロで自動化。
ESXiは、SSH 鍵認証でログインできること。
SSH設定詳細はこちら→ESXi5 SSH 有効化&鍵認証(TeraTermの自動ログインマクロ付) - のぴぴのメモ
コマンド"vim-cmd hostsvc/standby_mode_enter'"で停止。
; ========================================================== ; Setting (IP, UserName, KEY file) HOSTADDR = 'xxx.xxx.xxx.xx' ;ESXiのIPアドレス USERNAME = 'root' KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵 CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル ; ========================================================== ;; Generate login command COMMAND = HOSTADDR strconcat COMMAND ':22 /ssh /2 /auth=publickey /user=' strconcat COMMAND USERNAME strconcat COMMAND ' /keyfile="' strconcat COMMAND KEY_FILE strconcat COMMAND '" /F="' strconcat COMMAND CNF_FILE strconcat COMMAND '"' ;; Login connect COMMAND wait '~ #' ;; shutdown hypervisor sendln 'vim-cmd hostsvc/standby_mode_enter' sendln 'exit' end
; ========================================================== ; Setting (IP, UserName, KEY file) HOSTADDR = 'xxx.xxx.xxx.xx' ;ESXiのIPアドレス USERNAME = 'root' KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵 CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル ; ========================================================== ;; Initialize NUM=256 strdim VM_NO NUM strdim VM_NAME NUM strdim VM_STAT NUM timeout=1 ;; Generate login command COMMAND = HOSTADDR strconcat COMMAND ':22 /ssh /2 /auth=publickey /user=' strconcat COMMAND USERNAME strconcat COMMAND ' /keyfile="' strconcat COMMAND KEY_FILE strconcat COMMAND '" /F="' strconcat COMMAND CNF_FILE strconcat COMMAND '"' ;; Login connect COMMAND wait '~ #' ;;PowerOn VM count = 0 result = 1 sendln 'vim-cmd vmsvc/getallvms' waitln 'Vmid' while result ; receive VM list recvln if result = 0 then goto getall_fail endif strmatch inputstr '~ #' if result <> 0 then goto getall_fail endif ; Split strreplace inputstr 1 '\s+' ' ' strsplit inputstr " " VM_NO[count] = groupmatchstr1 VM_NAME[count] = groupmatchstr2 count = count + 1 goto getall_end :getall_fail result = 0 :getall_end endwhile ; Get VM power status for i 0 count-1 ; get VM stat MSG = 'vim-cmd vmsvc/power.getstate ' strconcat MSG VM_NO[i] sendln MSG waitln 'Retrieved' recvln strsplit inputstr " " VM_STAT[i] = groupmatchstr2 next ;;Select VM MSG="Select VM Number\n-----------------------------\n" for i 0 count-1 int2str stri i strconcat MSG stri strconcat MSG '.\t' strconcat MSG VM_STAT[i] strconcat MSG '\t' strconcat MSG VM_NAME[i] strconcat MSG '\n' next strconcat MSG '\n\n-1\tCancel\n-----------------------------' :select_RETRY inputbox MSG 'select VM' 1 str2int vmnum inputstr if result = 0 then goto select_RETRY endif if vmnum < 0 then goto EXIT_MACRO endif ; PowerON VM COMMAND= 'vim-cmd vmsvc/power.on ' strconcat COMMAND VM_NO[vmnum] sendln COMMAND wait '~ #' ;;exit :EXIT_MACRO sendln 'exit' end
; ========================================================== ; Setting (IP, UserName, KEY file) HOSTADDR = 'xxx.xxx.xxx.xx' ;ESXiのIPアドレス USERNAME = 'root' KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵 CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル ; =========================================================== ;; Initialize NUM=256 strdim VM_NO NUM strdim VM_NAME NUM strdim VM_STAT NUM timeout=1 ;; Generate login command COMMAND = HOSTADDR strconcat COMMAND ':22 /ssh /2 /auth=publickey /user=' strconcat COMMAND USERNAME strconcat COMMAND ' /keyfile="' strconcat COMMAND KEY_FILE strconcat COMMAND '" /F="' strconcat COMMAND CNF_FILE strconcat COMMAND '"' ;; Login connect COMMAND wait '~ #' ;;PowerOn VM count = 0 result = 1 sendln 'vim-cmd vmsvc/getallvms' waitln 'Vmid' while result ; receive VM list recvln if result = 0 then goto getall_fail endif strmatch inputstr '~ #' if result <> 0 then goto getall_fail endif ; Split strreplace inputstr 1 '\s+' ' ' strsplit inputstr " " VM_NO[count] = groupmatchstr1 VM_NAME[count] = groupmatchstr2 count = count + 1 goto getall_end :getall_fail result = 0 :getall_end endwhile ; Get VM power status for i 0 count-1 ; get VM stat MSG = 'vim-cmd vmsvc/power.getstate ' strconcat MSG VM_NO[i] sendln MSG waitln 'Retrieved' recvln strsplit inputstr " " VM_STAT[i] = groupmatchstr2 next ;;Select VM MSG="Select VM Number\n-----------------------------\n" for i 0 count-1 int2str stri i strconcat MSG stri strconcat MSG '.\t' strconcat MSG VM_STAT[i] strconcat MSG '\t' strconcat MSG VM_NAME[i] strconcat MSG '\n' next strconcat MSG '\n\n-1\tCancel\n-----------------------------' :select_RETRY inputbox MSG 'select VM' 1 str2int vmnum inputstr if result = 0 then goto select_RETRY endif if vmnum < 0 then goto EXIT_MACRO endif ; PowerON VM COMMAND= 'vim-cmd vmsvc/power.off ' strconcat COMMAND VM_NO[vmnum] sendln COMMAND wait '~ #' ;;exit :EXIT_MACRO sendln 'exit' end
VMware ESXi5をSSHでリモートで操作したい場合の設定手順を記録する。
SSHのサービス有効化は、コンソール画面とvSphereClientの2通りのがあるらしい。
ここではコンソール画面からの変更を記載する。
これでSSHが有効化される。
ちなみにコンソール画面から直接操作するには、ひとつ上の項目"Enable ESXi shell"を有効化する。ついでに、コンソールシェル(ESXi shell)も有効化する。(必須ではない)
TeraTermからSSHのパスワード認証でログイン可能なことを確認する。ここで中が必要なのは、ESXi5では「チャレンジレスポンス認証」を利用しているらしく、TeraTermのSSH認証で「チャレンジレスポンス認証を使う(キーボードインタラクティブ)」を選択する必要があることである。(下図参照)
SSHでとりあえずログインできることを確認したら、ESXiにログインに利用する公開鍵を登録する。
~ # cd /etc/ssh/keys-root /etc/ssh/keys-root #
/etc/ssh/keys-root # cat > authorized_keys <<公開鍵のテキストカット&ペーストする>> "CTL+D"を押すと入力終了する /etc/ssh/keys-root #
参考までに、SSH鍵認証の場合の自動ログインマクロを公開。
; ========================================================== ; Setting (IP, UserName, KEY file) HOSTADDR = 'xxx.xxx.xxx.xx' ;ESXiのIPアドレス USERNAME = 'root' KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵 CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル ; ========================================================== ;; Generate login command COMMAND = HOSTADDR strconcat COMMAND ':22 /ssh /2 /auth=publickey /user=' strconcat COMMAND USERNAME strconcat COMMAND ' /keyfile="' strconcat COMMAND KEY_FILE strconcat COMMAND '" /F="' strconcat COMMAND CNF_FILE strconcat COMMAND '"' ;; Login connect COMMAND wait '~ #' end
ファイルシステム上のファイルにキャッシュを解さずread/writeするためには、DirectIOで操作する必要がある。DirectIOを操作するには、
サンプルコードは以下の通り。
#include <unistd.h> #include <fcntl.h> #define BLOCKSIZE 512 int main(void) { int fdi, fdo; int size = 100 * 1024 * 1024; /* 100MB */ char *buf; /* allocate buffer memory */ posix_memalign( (void **)&buf, BLOCKSIZE, size); /* open file */ fdi = open("file_in", O_RDONLY |O_DIRECT ); fdo = open("file_out",O_WRONLY|O_CREAT|O_TRUNC|O_DIRECT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP ); /* copy "fdi" file to "fdo" file. */ read(fdi, buf, size); write(fdo,buf, size); }
コンパイルコマンド
$ gcc -D_GNU_SOURCE -o directio directio.c
テスト
$ dd if=/dev/zero of=file_in bs=1024 count=102400 102400+0 records in 102400+0 records out 104857600 bytes (105 MB) copied, 1.31783 s, 79.6 MB/s $ ./directio
straceコマンドでシステムとレースしてみても
$ strace ./directio <中略> open("file_in", O_RDONLY|O_DIRECT) = 3 open("file_out", O_WRONLY|O_CREAT|O_TRUNC|O_DIRECT, 0660) = 4 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 104857600) = 104857600 write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 104857600) = 104857600 exit_group(104857600) = ? $
デーモンを起動する場合、2度forkするのが作法らしく、これは「セッションリーダにならないようにすることで端末の制御を誤ってしないように」ということらしい。
詳しくはこちらを参照
そうなのかぁと思いながら、見よう見まねでdaemonの関数を作ってみました。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> static pid_t do_daemon(int close_interface) { pid_t ret; int fd; /*create child process and terminate parent process*/ ret = fork(); if( ret < 0 ){ /* fork error */ perror("Cannot fork"); return(-1); }else if( ret != 0 ){ /* parent process */ return(ret); } /* child process */ /* change chiled process to session gruop reader */ ret = setsid(); if( ret < 0 ){ perror("Cannot create a session"); return(-1); } /* create 2nd child process and terminate parent process again * to never connect terminal */ ret = fork(); if( ret < 0 ){ /* fork error */ perror("Cannot fork"); return(-1); }else if( ret != 0 ){ /* parent process */ return(ret); } /* change the current directory to root directory */ (void) chdir("/"); /* close stdin/stdout/stderr */ fd = open("/dev/null", O_RDWR); if( fd < 0 ){ perror("Cannot open NULL device"); return(-1); } /* close the STDIN file descriptor */ if ((fd != STDIN_FILENO) && (dup2(fd, STDIN_FILENO) < 0)){ perror("Cannot close the STDIN"); (void)close(fd); return(-1); } /* close the STDOUT and STDERR file descriptor, if option is TRUE */ if( close_interface ){ /* close the STDOUT file descriptor */ if ((fd != STDOUT_FILENO) && (dup2(fd, STDOUT_FILENO) < 0)) { perror("Cannot close the STDOUT"); (void)close(fd); return(-1); } /* close the STDERR file descriptor */ if ((fd != STDERR_FILENO) && (dup2(fd, STDERR_FILENO) < 0)) { perror("Cannot close the STDERR"); (void)close(fd); return(-1); } } if( fd > STDERR_FILENO ){ (void)close(fd); } /* daemon complete */ return(0); }
でもudevとかsyslogdとかのソースを見ると、案外fork一度しかやってなかったりするんだけどね。
/etc/yum.repos.d/に、xxx.repoというファイルを作る。(xxxは任意)
/etc/yum.repos.d/mnt_rhel60.repo
[rhel60_dvd] ※1 name=RHEL6.0(x86_64) DVD ※2 baseurl=file:///mnt/Server/ enabled=1 ※3 gpgcheck=1 ※4 gpgkey=file:///mnt/RPM-GPG-KEY-redhat-release ※5
※1 : レポジトリ名(わかりやすい名前をつける)
※2 : ラベル名(わかりやすい名前をつける)
※3 : 常に参照する場合は1。0の場合、yumオプションで"--enablerepo="を指定する。
※4 : GPG認証チェックを有効化する
※5 : GPG-KEYのファイルパスを指定
必須ではないが、RHNの接続エラーが毎回出るので抑止する。(enabled=0とする)
/etc/yum/pluginconf.d/rhnplugin.conf [main] #enabled = 1 enabled = 0 gpgcheck = 1
yumコマンドで、DVDのパッケージが認識できるか確認。
# yum list Loaded plugins: refresh-packagekit Installed Packages <中略> cdparanoia.x86_64 10.2-5.1.el6 rhel60_dvd cdparanoia-libs.i686 10.2-5.1.el6 rhel60_dvd cdrdao.x86_64 1.2.3-4.el6 rhel60_dvd celt051.x86_64 0.5.1.3-0.el6 rhel60_dvd check.i686 0.9.8-1.1.el6 rhel60_dvd <中略>
※指定したレポジトリ名のパッケージが表示されることを確認。
ipv6の無効化方法について説明。
/etc/modprobe.d/にdisable_ipv6.confというファイル設定ファイルを作成する。
(ファイル名は任意の名前で可)
/etc/modprobe.d/disable_ipv6.conf
options ipv6 disable=1
# service ip6tables stop ip6tables: モジュールを取り外し中: [ OK ]
ネットワークを再起動する。
# service network restart
(面倒であればOSの再起動でもいいんでは)
dmesgに下記メッセージがあることを確認。
IPv6: Loaded, but administratively disabled, reboot required to enable
※(意訳)モジュールをロードしたけど、管理上機能が無効化されてるよ
一般的な方法として、modprobe.confに「alias net-pf-10 off」と設定する方法があちらこちらで紹介されている。しかいこの設定は、「off」という存在しないモジュールをロードさせようとすることで(当然失敗する)、結果としてipv6のモジュールをロードさせないようにしている。
おそらく、disableオプションが実装される前の苦肉の策の設定ではないだろうか。
シリアル接続した端末(PC)からコンソール操作が行えるように設定を行う。(PCからはTeraTermのコンソール接続を利用する。)
/boot/grub/grub.confに以下の設定を行う。
/boot/grub/grub.confの編集内容 ①GRUBをtext表示にするため、splashimageをコメントアウトする。 # splashimage=(hd0,0)/grub/splash.xpm.gz ②シリアルポートの通信設定を行う serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1 ③グラフィックとシリアルの両方が使用できるよう設定 terminal --timeout=3 serial console ※3秒以内にキー入力があった場合はserial接続、 無い場合は、グラフィック接続。 必ずserial接続にする場合は、"terminal serial"
カーネルのブートオプションにシリアルコンソールの設定を追加する。
設定は、/boot/grub/grub.confに設定を行う。
/boot/grub/grub.confの編集内容
カーネルオプションに、"console=tty0 console=ttyS0,115200n8r"を追加する。 kernel /vmlinuz-2.6.19-1.2288.2.1.fc5 ro root=LABEL=/ console=tty0 console=ttyS0,115200n8r
シリアルコンソールからログインが可能になるよう設定を行う。
inittabにシリアルコンソールの設定を追加する。
/etc/inittabに以下の設定を追加
co:2345:respawn:/sbin/agetty -h 115200 ttyS0 vt100
下記コマンドで設定を反映する。
# init q
デフォルトではrootユーザのログインは不許可であるため、/etc/securettyにttyS0(シリアルのデバイス)設定を追加する。
console vc/1 <中略> tty10 tty11 ttyS0 <- 追加
FedoraやRHEL,Suseなど多くのLinuxディストリビューションに標準実装されているデーモンで、マルチCPU環境において、IRQ割込み処理を複数のCPU間で負荷分散させることを目的としています。
Linux Kernelはデフォルトの状態では、CPU0のみでIRQ割込み(ハードウエアからの割込み要求)の処理を行います。しかしそれではIRQ割り込みが頻繁に発生する場合CPU0に負荷が偏りパフォーマンスが劣化する可能性があります。そこでマルチCPU環境でにおいてirqbalanceを導入することで、2nd CPU以降も割り込み処理を行えるようになります。
irqbalanceは、10秒毎に各CPUのIRQ割込み処理負荷状態状態に応じ、各CPUへのIRQ割込み処理の再配置をおこないます。CPUのIRQ割込み処理負荷状態は"/proc/interrupts"から算出しています。またIRQの再配置は、"/proc/irq/[IRQ番号]/smp_affinity"のCPUマスク設定を変更することで実現しています。
List.1 /proc/interruptsの例
# cat /proc/interrupts CPU0 CPU1 1: 76 0 Phys-irq-level i8042 6: 5 0 Phys-irq-level floppy 7: 0 0 Phys-irq-level parport0 8: 0 0 Phys-irq-level rtc 9: 0 0 Phys-irq-level acpi 12: 147 2867 Phys-irq-level i8042 14: 0 0 Phys-irq-level libata 15: 5427 6975 Phys-irq-level libata 17: 9064 1343 Phys-irq-level ioc0 18: 1525405 6344 Phys-irq-level peth0 256: 377093 0 Dynamic-irq-level timer0 257: 6835 0 Dynamic-irq-level resched0 258: 35 0 Dynamic-irq-level callfunc0 259: 0 6868 Dynamic-irq-level resched1 260: 0 89 Dynamic-irq-level callfunc1 261: 0 153764 Dynamic-irq-level timer1 262: 144 0 Dynamic-irq-level xenbus 263: 0 0 Dynamic-irq-level console NMI: 0 0 LOC: 0 0 ERR: 0
List.2 /proc/irq/[IRQ番号]/smp_affinityの例
# cat /proc/irq/17/smp_affinity 00000000,00000001
なおirqbalanceの実行周期はirqbalanceのソースコードにハードコーティングされており、設定で変更することはできません。
各CPUの割込み状態の確認は、/proc/interrupts にて確認することが可能です。
1CPU(1core)のみの環境の場合、irqbalanceを利用する必要はありません。(起動しようとしてもエラーとなります。)
irqbalanceに対するサービス可否の考え方を以下に示します。
・マルチCPU(マルチcore)環境の場合、irqbalanceを有効にする。
・1CPU(1core)環境の場合はirqbalanceを無効化する。
cloopは、Debian系の1CD Linuxとして有名なKNOPPIXのルートファイルシステムとして利用されていることで有名であるが、redhat系カーネルでの動作事例はインターネット上にあまりなく、あっても多くが古い情報である。
今回、FedoraCore5とRHEL4にcloopしたので、その導入手順を纏める。(手順はFedoraCore5ベースで記述するが、RHEL4でもほとんど手順は同じである。)
※cloopは、読み込み専用のファイルシステム。
cloopのREADMEには、KNOPPIXの公式サイトの記載があるが、最新のソースコードは見当たらない。探したところ、Debianのunstableパッケージから入手が可能である。
最新版は、"cloop-2.05~20060829"(2007.3.2現在)
・「Debian パッケージ」
・「不安定版 (unstable) ディストリビューションのパッケージを見る」
・「Miscellaneous」
・「cloop-src」パッケージを選択
任意の場所(手順では/tmp)にtarのデータを展開する。
$ cd /tmp $ tar -zxvf cloop_2.05~20060829-1.tar.gz $ cd cloop-2.05~20060829/
RHELの場合、そのままではコンパイルが通らないため一部のソースを修正する。
$ vi compressed_loop.c
29行目の"REDHAT_KERNEL"のdefineのコメントをはずす。
before: 29: /* #define REDHAT_KERNEL */ after: 29: #define REDHAT_KERNEL
必要に応じて、cloopデバイスの最大数を変更する。デフォルトは、8。
$ vi compressed_loop.c
26行目の"CLOOP_MAX"の値を必要に応じ変更する。
before: 26 #define CLOOP_MAX 8 after: 26 #define CLOOP_MAX 16
正常にcloopが組み込めるか確認する。
cloopのモジュール情報が出力されることを確認
# modinfo cloop filename: /lib/modules/2.6.19-1.2288.2.1.fc5/misc/cloop.ko description: Transparently decompressing loopback block device author: Klaus Knopper (Kernel 2.4 and up, Knoppix version), Paul Russel (initial version) <以下略>
create_compressed_fsとextract_compressed_fs(cloopソースコード内に梱包)をコピーする。
# install -m0755 create_compressed_fs /usr/local/bin/ # install -m0755 extract_compressed_fs /usr/local/bin/
下記コマンドで、cloopのファイルシステムにしたいデータがあるディレクトリをcloopのフォーマットに変換する。
# mkisofs -r datadir | \ create_compressed_fs - 65536 > datadir.iso.compressed ; datadir : 対象データのディレクトリ名 datadir.iso.compressed : cloopフォーマットのファイル名
下記コマンドで、生成したcloopファイルとcloopのデバイスをくくりつける。<例:cloop0デバイスに、iso.compressedファイルを括り付ける>
# losetup /dev/cloop0 /tmp/datadir.iso.compressed
ファイルシステムをマウントする。
# mount -o ro -t whatever /dev/cloop0 /mnt/compressed
※OS起動停止時のcloopファイルシステムの自動マウント・アンマウントシェル(rcシェル)はこちらを参照→ 【Fedora/RHEL】cloop自動マウント用rcスクリプト
OS起動停止時に、cloopモジュールロード・アンロードとcloopファイルシステムのマウント・アンマウントを行うrcシェルを作る。
cloopモジュールの実装は → こちらを参照
サンプルシェル(cloop)を以下に示す。
#!/bin/sh # script to start and stop cloop devices # and mount and umount cloop filesystems # # chkconfig: 35 60 20 # description: Starts, stops cloop modules # # set the maximum number of cloop device # refer to the MAX_CLOOP in compressed_loop.c MAX_CLOOP=8 CLOOP_DEV[0]=/dev/cloop0 CLOOP_FIL[0]=/tmp/a.cloop CLOOP_DIR[0]=/tmp/a #CLOOP_DEV[1]=/dev/cloop1 #CLOOP_FIL[1]=/dummy1 #CLOOP_DIR[1]=/dummy1 #CLOOP_DEV[2]=/dev/cloop2 #CLOOP_FIL[2]=/dummyr2 #CLOOP_DIR[2]=/dummy2 #CLOOP_DEV[3]=/dev/cloop3 #CLOOP_FIL[3]=/dummy3 #CLOOP_DIR[3]=/dummy3 # Source function library. . /etc/init.d/functions function abend(){ echo ERROR: $@ failure exit 1 } function load_cloop_module(){ lsmod |grep cloop > /dev/null [ $? -eq 0 ] && (echo "cloop has already been loaded.";return ) modprobe cloop [ $? -ne 0 ] && abend can not load the cloop module. i=0; FLAG=FALSE while [ $i -lt 10 ] do sleep 1 if [ -b "/dev/cloop`expr $MAX_CLOOP - 1`" ] then FLAG=TRUE; break fi i=`expr $i + 1` done [ "$FLAG" != TRUE ] && abend not found the maximum cloop device. } function bind_and_mount(){ # check a cloop device [ -b $1 ] || abend $1 is a invalid cloop device. # check a cloop file [ -f $2 ] || abend not found $2 file. head -3 $2 | grep cloop 2>&1 > /dev/null [ $? -eq 0 ] || abend $2 is a invalid cloop file. # check mount directory [ -d $3 ] || abend $3 is not directory. losetup $1 $2 || abend can not bind $2 file to $1 device. mount -r -t iso9660 $1 $3 || abend can not mount $1 on $3. } function start(){ load_cloop_module i=0 while [ -n "${CLOOP_DEV[$i]}" -a \ -n "${CLOOP_FIL[$i]}" -a \ -n "${CLOOP_DIR[$i]}" ] do bind_and_mount ${CLOOP_DEV[$i]} ${CLOOP_FIL[$i]} ${CLOOP_DIR[$i]} i=`expr $i + 1` done success touch /var/lock/subsys/cloop } function stop(){ i=0 while [ -n "${CLOOP_DEV[$i]}" -a \ -n "${CLOOP_FIL[$i]}" -a \ -n "${CLOOP_DIR[$i]}" ] do umount ${CLOOP_DIR[$i]} losetup -d ${CLOOP_DEV[$i]} i=`expr $i + 1` done modprobe -r cloop success rm -f /var/lock/subsys/cloop } # See how we were called. case "$1" in start) start ;; stop) stop ;; restart|reload) stop start ;; *) echo $"Usage: $0 {start|stop|restart}" exit 1 esac exit 0
環境に応じて、下記パラメータを設定する。
→cloopデバイスの最大数。compressed_loop.cの"#define CLOOP_MAX"の値を設定する。
# vi /etc/init.d/cloop # chown root:root /etc/init.d/cloop # chmod 755 /etc/init.d/cloop