vyatta 的exit safe mode命令是如何实现的?

保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
单击提交则表示您同意developerWorks
的条款和条件。 .
所有提交的信息确保安全。
developerWorks 社区:
我的概要信息
选择语言:
本文主要讲述 cp、mkdir、rm、tac、df 五个命令主要功能的模拟实现代码。让读者学会使用 strace 来跟踪系统调用的使用情况。加深读者对操作系统的认识与理解,引导读者学习 Linux 系统编程。
, 系统工程师, 新浪网技术(中国)有限公司
张冬,新浪网研发部,从事系统工程师工作,工作的主要内容是维护 Linux 服务器和其上运行的各种服务。由于经常使用各种 Linux 命令,对命令的具体工作原理非常感兴趣,因此工作之余花时间研究了一下命令的实现。
本文章中的示例代码是在 CentOS 5.4 64 位环境下运行通过的,在其它 unix 系统上没有测试过。Linux 操作系统中的命令实际上是编译好的可执行程序,比如说 ls 这个命令,这个文件位于 /bin 目录下面,当我们用 file /bin/ls 命令查看的时候会有以下输出: [root@localhost ~]# file /bin/ls
/bin/ls: ELF 64-bit LSB executable,
AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9,
dynamically linked (uses shared libs), for GNU/Linux 2.6.9, stripped这个命令通过调用 stat 系统调用和 /usr/share/file/magic.mgc 文件来决定文件的类型。如上的 /bin/ls 是一个 ELF 格式的动态链接的 64 位的可执行文件。系统调用是用户程序和操作系统内核之间的接口,我们可以使用操作系统提供的系统调用来请求分配资源和服务。我们可以通过 man 2 章节来查找 Linux 提供的系统调用的具体使用方法。有关文件操作的常见系统调用命令有:open、creat、close、read、write、lseek、opendir、readdir、mkdir、stat 等等。cp 命令的实现cp 命令的模拟实现大家也都知道 cp 这个命令主要的作用就是把一个文件从一个位置复制到另一个位置。比如现在 /root 目录下有一个 test.txt 文件,如果我们用 cp test.txt test2.txt 命令的话,在同一个目录下面就会生成一个同样内容的 test2.txt 文件了。那么 cp 命令是怎么实现的呢,我们看如下代码:清单 1. cp 命令实现代码 #include
&unistd.h&
&stdlib.h&
#define BUFFERSIZE
#define COPYMODE
void oops(char *, char *);
main(int argc, char * argv[])
in_fd, out_fd, n_
buf[BUFFERSIZE];
if ( argc != 3 ){
fprintf( stderr, "usage: %s source destination\n", *argv);
if ( (in_fd=open(argv[1], O_RDONLY)) == -1 ){
oops("Cannot open ", argv[1]);
if ( (out_fd=creat( argv[2], COPYMODE)) == -1 ){
oops( "Cannot creat", argv[2]);
while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) & 0 ){
if ( write( out_fd, buf, n_chars ) != n_chars ){
oops("Write error to ", argv[2]);
if ( n_chars == -1 ){
oops("Read error from ", argv[1]);
if ( close(in_fd) == -1 || close(out_fd) == -1 )
oops("Error closing files","");
void oops(char *s1, char *s2)
fprintf(stderr,"Error: %s ", s1);
perror(s2);
}该程序的主要实现思想是:打开一个输入文件,创建一个输出文件,建立一个 BUFFERSIZE 大小的缓冲区;然后在判断输入文件未完的循环中,每次读入多少就向输出文件中写入多少,直到输入文件结束。cp 命令实现的说明让我来详细的讲述一下这个程序:
开头四行包含了 4 个头文件,&stdio.h& 文件包含了 fprintf、perror 的函数原型定义;&unistd.h& 文件包含了 read、write 的函数原型定义;&fcntl.h& 文件包含了 open、creat 的函数原型定义、&stdlib.h& 文件包含了 exit 的函数原型定义。这些函数原型有些是系统调用、有些是库函数,通常都可以在 /usr/include 目录中找到这些头文件。
接下来的 2 行以宏定义的方式定义了 2 个常量。BUFFERSIZE 用来表示缓冲区的大小、COPYMODE 用来定义创建文件的权限。
接下来的一行定义了一个函数原型 oops,该函数的具体定义在最后出现,用来输出出错信息到 stderr,也就是标准错误输出的文件流。
接下来主程序开始。首先定义了 2 个文件描述符、一个存放读出字节数的变量 n_chars、和一个 BUFFERSIZE 大小的字符数组用来作为拷贝文件的缓冲区。
接下来判断输入参数的个数是否为 3,也就是程序名 argv[0]、拷贝源文件 argv[1]、目标文件 argv[2]。不为 3 的话就输出错误信息到 stderr,然后退出程序。
接下来的 2 行,用 open 系统调用以 O_RDONLY 只读模式打开拷贝源文件,如果打开失败就输出错误信息并退出。如果想了解文件打开模式的详细内容请使用命令 man 2 open,来查看帮助文档。
接下来的 2 行,用 creat 系统调用以 COPYMODE 的权限建立一个文件,如果建立失败函数的返回值为 -1 的话,就输出错误信息并退出。
接下来的循环是拷贝的主要过程。它从输入文件描述符 in_fd 中,读入 BUFFERSIZE 字节的数据,存放到 buf 字符数组中。在正常读入的情况下,read 函数返回实际读入的字节数,也就是说只要没有异常情况和文件没有读到结尾,那么 n_chars 中存放的就是实际读出的字节的数字。然后 write 函数将从 buf 缓冲区中,读出 n_chars 个字符,写入 in_out 输出文件描述符。由于 write 系统调用返回的是实际写入成功的字节数。所以当读出 N 个字符,又成功写入 N 个字符到输出文件描述符中去的时候,就表示写成功了,否则就报告写入错误。
最后就是用 close 系统调用关闭打开的输入和输出文件描述符。rm 命令的实现rm 命令的模拟实现rm 命令主要是用来删除一个文件。该命令的实现代码如下:清单 2. rm 命令代码 #include &unistd.h&
#include &stdio.h&
#include &stdlib.h&
int main(int argc , char * argv[]) {
if(argc != 2){
if((rt = unlink(argv[1])) !=
fprintf(stderr,"error.");
}其中程序的关键是 unlink 系统调用,unlink 函数原型包含在 &unistd.h& 头文件里面。用 strace 来跟踪命令我们从这个程序的创建过程来分析这个程序。这个命令的模拟程序是怎么写出来的呢?首先,我们可以在机器上 touch test 建立一个 test 文件,然后调用 strace rm test 命令来查看 rm 命令具体使用了那些系统调用。通过查看,我们看到主要使用的系统调用如下: [root@localhost aa]# strace rm test
execve("/bin/rm", ["rm", "test"], [/* 24 vars */]) = 0
= 0xcc66000
mmap(NULL, 4096, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2aff83ffb000
uname({sys="Linux", node="localhost.localdomain", ...}) = 0
lstat("test", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
stat("test", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
access("test", W_OK)
unlink("test")
exit_group(0)
= ?我们可以看到起主要作用的就是 unlink(“test”) 这个系统调用。让我们来分析一下这些输出的含义:
首先第一行 execve 系统调用。该系统调用执行参数“/bin/rm”中的程序(以 #! 开头的可执行脚本也可以),后面第一个方括号中表示执行的参数,第二个方括号中表示执行的环境变量。
接下来的 brk 和 mmap 命令,主要是用来给可执行命令分配内存空间。
后面的 lstat 系统调用用来确定文件的 mode 信息,包括文件的类型和权限,文件大小等等。
然后 access 系统调用检查当前用户进程对于 test 文件的写入访问权限。这里返回值为 0 也就是说进程对于 test 文件有写入的权限。
最后调用 unlink 系统调用删除文件。这里如果我们建立一个目录 test1,然后用 rm test1 去删除这个目录会有什么结果呢?我们看到有如下输出: rm: cannot remove `test1': Is a directory这时我们用 strace 命令来追踪一下,发现输出主要是如下不同。 unlink("test")
= -1 EISDIR (Is a directory)这里说明了删除不掉的原因是 unlink 系统调用报错,unlink 它认为 test 是一个目录,不予处理。那么怎么删除一个目录呢?应该是用 rmdir 系统调用,这样就不会出现上述的问题了。mkdir 命令的实现mkdir 命令的模拟实现再让我们来看看 mkdir 的实现。完整的代码如下:清单 3. mkdir 实现代码 #include &sys/stat.h&
#include &sys/types.h&
#include &stdio.h&
int main(int argc, char *argv[]){
if( (rt = mkdir (argv[1],10705)) == -1 ){
fprintf(stderr,"cannot mkdir");
}这段代码也比较简单,我这里就不逐行解释了,主要说以下几点:首先 mkdir 函数是定义于 &sys/stat.h& 和 &sys/types.h& 头文件之中的。而 fprintf 函数是位于 &stdio.h& 文件之中的。mkdir 的函数原型如下: int mkdir(const char *pathname, mode_t mode);mode 声明为 mode_t 类型。那么 mode_t 数据类型是什么数据类型,应该从哪个文件去查看它的定义呢?mode_t 数据类型究竟是什么类型让我们逐步查找一下。首先从文件 /usr/include/sys/stat.h 中找到 mode_t 类型/usr/include/sys/stat.h
mode_t;说明 mode_t 只是对 __mode_t 的一种定义。然后从 /usr/include/bits/types.h 中找到 __mode_t 类型/usr/include/bits/types.h
__STD_TYPE
__MODE_T_TYPE
__mode_t;说明 __mode_t 也只是对 __MODE_T_TYPE 的一种定义。/usr/include/bits/typesizes.h
__MODE_T_TYPE
__U32_TYPE说明 __MODE_T_TYPE 是对 __U32_TYPE 的一种定义。/usr/include/bits/types.h
__U32_TYPE
unsigned int最后 __U32_TYPE 是一种无符号的整数的定义。从上述推导可以看出,mode_t 实际上也就是一种无符号整数。另外如下结构 struct stat 定义中的 st_mode 成员变量也是使用的 mode_t 类型的变量。从 man 2 stat 中可以找到结构 struct stat 的定义,如下:
struct stat {
/* ID of device containing file */
/* inode number */
/* protection */
/* number of hard links */
/* user ID of owner */
/* group ID of owner */
/* device ID (if special file) */
/* total size, in bytes */
blksize_t st_ /* blocksize for filesystem I/O */
/* number of blocks allocated */
/* time of last access */
/* time of last modification */
/* time of last status change */
};该结构也是我们在后面的 tac 命令实现中需要用到的结构体。我们需要用到结构体中的 st_size 成员,该成员反映了被读取的文件描述符对应的文件的大小。tac 命令的实现tac 命令的模拟实现tac 命令主要用来以倒序的方式显示一个文本文件的内容,也就是先显示最后一行的内容,最后显示第一行的内容。代码如下:清单 4. tac 命令实现代码 #include &stdio.h&
#include &sys/types.h&
#include &sys/stat.h&
#include &fcntl.h&
#include &string.h&
#include &unistd.h&
#include &stdlib.h&
#include &errno.h&
#define SIZE
#define NLINE '\n'
int main(int argc , char *argv[]){
char buf[SIZE];
char *p1,*p2,*p3,*p4;
struct stat
fp=(struct stat *)malloc(sizeof(struct stat));
if(argc != 2){
fprintf(stderr,"input error %s \n");
if( (fd=open(argv[1],O_RDONLY)) == -1 ){
fprintf(stderr,"open error %s \n",strerror(errno));
if(fstat(fd,fp)== -1){
fprintf(stderr,"fstat error %s \n",strerror(errno));
if(fp-&st_size & (SIZE-1)){
fprintf(stderr,"buffer size is not big enough \n");
if(read(fd,buf,fp-&st_size) == -1){
fprintf(stderr,"read error.\n");
p1=strchr(buf,NLINE);
p2=strrchr(buf,NLINE);
p2=strrchr(buf,NLINE);
p3=p2+sizeof(char);
printf("%s\n",p3);
}while(p2 != p1);
if(p2 == p1){
*p2 = '\0';
printf("%s\n",buf);
}让我们来运行一下该程序:程序的运行情况如下,假设编译后的可执行文件名为 emulatetac,有一个文本文件 test.txt。 # gcc emulatetac.c
emulatetac
# cat test.txt
# ./emulatetac test.txt
1可以看出文件内容以倒序方式显示输出了。tac 命令实现的说明下面逐行讲解:
#include 的头文件,都应该通过 man 2 系统调用命令来查找,这里就不多说了。
下面定义了一个宏常量 SIZE,该常量主要用来表示能够读入最大多少个字节的文件,当文件过大的时候程序就不执行,直接退出。然后定义了宏常量 NLINE 表示换行符'\n'。
接下来主程序体开始了:首先定义一个字符数组 buf,用来把读入文件的每个字节都存在该数组里面。
然后定义了 4 个字符串指针,一个指向结构体 struct stat 的指针 fp,一个文件描述符。
然后为指向结构体的指针 fp 分配存储空间。
接下来判断输入参数是否为 2 个,也就是命令本身和文件名。不是 2 个就直接退出。
然后以只读方式打开输入文件名的文件,也就是 test.txt。打开成功的话,把打开的文件赋值到文件描述符 fd 中,错误的话退出。
然后用 fstat 系统调用把文件描述符 fd 中对应文件的元信息,存放到结构体指针 fp 指向的结构中。
下面判断当文件的大小超过缓冲区数组 buf 的大小 SIZE-1 时,就退出。
下面将把文件 test.txt 中的每个字符存放到数组 buf 中。
下面是程序的核心部分:首先我们找到字符串 buf 中的第一个换行字符存放到 p1 指针里面,然后把最后一个换行字符置为字符串结束符。
接下来我们从后往前查找字符串 buf 中的换行符,直到遇到第一个换行符 p1。同时打印每个找到的换行符'\n'中的下一个字符开始的字符串,也就刚好是一行文本。
最后当从后向前找到第一个换行字符时,打印第一行,程序结束。df 命令的实现df 命令的模拟实现通过 strace 命令查看 df 主要使用了如下的系统调用:open、fstat、read、statfs我这里实际上是模拟实现的 df
--block-size=4096 这个命令,也就是说以 4096 字节为块大小来显示磁盘使用情况。这里最为关键的是 statfs 这个结构体,该结构体的某些字段被用作 df 命令的输出字段:
struct statfs {
/* type of filesystem (see below) */
/* optimal transfer block size */
/* total data blocks in file system */
/* free blocks in fs */
/* free blocks avail to non-superuser */
/* total file nodes in file system */
/* free file nodes in fs */
/* file system id */
/* maximum length of filenames */
};比如:df
--block-size=4096 的输出如下(纵向列出): Filesystem
5077005    f_blocks 字段
145105    f_blocks 字段 -f_bfree 字段
4669841    f_bavail 字段
4%   (f_blocks-f_bfree)/ f_blocks*100% 来计算磁盘使用率。
Mounted on
/模拟实现的代码如下:清单 5. 模拟实现代码 #include &stdio.h&
#include &errno.h&
#include &stdlib.h&
#include &string.h&
#include &sys/vfs.h&
#include &math.h&
#define SIZE1 100
#define FN "/etc/mtab"
#define SPACE ' '
int displayapartition(char * pt,char * pt1);
int main(void){
char tmpline[SIZE1];
char * pt1;
char * pt2;
char * pt3;
if( (fp = fopen(FN,"r")) == NULL ){
fprintf(stderr,"%s \n",strerror(errno));
while( fgets(tmpline, SIZE1, fp) != NULL ){
pt1=strchr(tmpline, SPACE);
pt2=pt1+sizeof(char);
*pt1='\0';
pt3=strchr(pt2,SPACE);
*pt3='\0';
if(strstr(tmpline,"/dev") != NULL ){
displayapartition(tmpline,pt2);
int displayapartition(char * pt,char * pt1){
statfs(pt1,&buf);
usage=ceil((buf.f_blocks-buf.f_bfree)*100/buf.f_blocks);
printf("%s ",pt);
printf("%ld ",buf.f_blocks);
printf("%ld ",buf.f_blocks-buf.f_bfree);
printf("%ld ",buf.f_bavail);
printf("%d%% ",usage);
printf("%s ",pt1);
printf("\n");
}df 命令实现的说明下面解释一下这个程序:
首先,该程序定义了一个函数 displayapartition, 这里先定义它的函数原型。
然后我们从主程序说起:首先定义了一个 char tmpline[SIZE1] 数组,该数组用来存放从宏定义常量 FN 代表的文件中,打开后存入文件的每行记录。
接着定义了一个文件流指针和 3 个字符串指针。
接下来打开文件 FN 并把结果赋值给文件流变量 fp, 如果打开失败就退出。
下面从打开的文件流中读出 SIZE1 个字符到临时数组 tmpline。比如读出一行数据为:/dev/sda1 / ext3 rw 0 0  将把 /dev/sda1 放入数组 tmpline,把加载点 / 放入指针 pt2,同时判断字符串 tmpline 是否包含 /dev 字符串,这样来判断是否是一个磁盘文件,如果是的话就调用子函数 displayapartition,不是则返回。
子函数 displayapartition 是做什么的呢?该函数接受 2 个参数,一个是行 /dev/sda1 / ext3 rw 0 0 中的第一列比如:/dev/sda1 也就是实际磁盘作为 pt 指针,一个是行中的第二列比如:/ 也就是挂载点作为 pt1 指针。然后子函数通过 pt1 指针,读取挂载上的文件系统信息到 buf 数据结构里面。
根据开头介绍过的 statfs 结构体,buf.f_blocks 表示打开的文件系统的总数据块,buf.f_blocks-buf.f_bfree 表示已经使用的数据块,buf.f_bavail 表示非超级用户可用的剩余数据块,磁盘使用率就是前面列出过的计算表达式:(f_blocks- f_bfree)/ f_blocks*100%。通过子函数就可以打印出 df 需要显示的所有信息到标准输出了。小结本文依次讲述了 cp、rm、mkdir、tac、df 命令的主要功能实现代码,当然每个命令还有很多参数,我这个模拟实现代码甚至连主要功能的很多细节都没有实现,比如 df 命令的输出头我没有打印出来,这牵涉到打印头和输出格式化等很多细节。所以,从这里我们就可以推断出,真实的源代码肯定是考虑得非常全面、严谨和健壮的。我这里只是抛砖引玉,希望能给爱好 Linux 的朋友们提供一种理解 Linux 系统的思路。
下载描述名字大小样例代码3KB
参考资料 参考:《 Linux 操作系统下 c 语言编程入门》。
参考 developerWorks 文章:。参考 developerWorks 文章:。参考 developerWorks 文章:。 在
寻找为 Linux 开发人员(包括 )准备的更多参考资料,查阅我们 。 在 developerWorks 上查阅所有
和 。 随时关注 developerWorks 和。 欢迎加入 。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
IBM PureSystems(TM) 系列解决方案是一个专家集成系统
通过学习路线图系统掌握软件开发技能
软件下载、试用版及云计算
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=LinuxArticleID=630370ArticleTitle=Linux 下几个文件操作命令的代码实现publish-date=您所在的位置: &
如何扩展Nagios,以实现自定义监控?
如何扩展Nagios,以实现自定义监控?
布加迪编译
Nagios是一款开源的免费网络监视工具,能有效监控Windows、Linux和Unix的主机状态,功能强大的Nagios网络监控平台让你可以为其功能增添一系列可用插件。本文就介绍了如何自行编写插件,扩展Nagios,以实现自定义监控。
【51CTO精选译文】功能强大的网络监控平台让你可以为其功能增添一系列可用插件。
如果你找不到可以满足自身要求的一款插件,也很容易自行编写,本文就介绍了如何自行编写插件。
Nagios插件可以用任何一门编程语言来编写,只要该编程语言在运行Nagios的平台上得到支持。Bash是用来编写的一门流行语言,因为它功能强大、使用简单。
借助插件进行的每一次有效的Nagios检查(Nagios check)都会生成一个数字表示的退出状态。可能的状态有:
0--各方面都正常,检查成功完成。
1--资源处于警告状态。某个地方不太妙。
2--资源处于临界状态。原因可能是主机宕机或服务未运行。
3--未知状态,这未必表明就有问题,而是表明检查没有给出一个清楚明确的状态。
插件还能输出文本消息。默认情况下,该消息显示在Nagios web界面和Nagios邮件警报信息中。尽管消息并不是硬性要求,你通常还是可以在可用插件中找到它们,因为消息告诉用户出了什么岔子,而不会迫使用户查阅说明文档。
用Bash编写的一个简单的Nagios插件类似这样。这个示例插件检查一个指定的文件:
#!/bin/bash
#将第一个实参($1)指定为文件名
filename=$1
#先检查该文件是否存在。这是你应该开始的第一个检查,也是最基本的检查。
if [ ! -e $filename ]; thenecho &CRITICAL status - file $filename doesn't exist&
exit 2 #返回临界状态,那是由于你的最糟糕情况是该文件根本就不存在。
#如果前一个条件通过(文件存在),那么接下来检查该文件是否可读:
elif [ ! -r $filename ]; thenecho &WARNING status - file $filename is not readable.&
exit 1 #返回警告状态,那是由于该状态胜于根本不存在文件;
#如果前一个条件通过,检查它是不是一个普通文件,而不是目录或设备文件。
elif [ ! -f $filename ]; thenecho &UNKNOWN status - file $filename is not a file.&
exit 3 #返回未知状态;
#如果所有上述检查均通过,那么表明它正常:
elseecho &OK status - file is OK&exit 0 #Return OK statusfi
注释(Bash中以#开始)解释了代码;如果你需要更清晰的解释,或者想进一步了解的文件测试操作符,请查阅说明文档(http://tldp.org/LDP/abs/html/fto.html)。
尽管这个实例很简单,但它清楚地表明了如何实现Nagios插件逻辑。始终首先要寻找最糟糕的情况。只有当所有检查均通过,脚本退出时才会显示状态正常。确保在退出之前指定明确消息。
默认情况下,所有的Nagios插件均存放在用$USER1宏命令定义的目录中,具体在文件/etc/nagios/private/resource.cfg中定义。在来自EPEL存储库(http://fedoraproject.org/wiki/EPEL)的典型Nagios安装环境下,$USER1被定义为/usr/lib/nagios/plugins。你对插件应该做的头一件事就是,把它拷贝到用$USER1宏命令定义的目录中。插件通常归root所有,其权限设置为755。Nagios在属于nagios群组的用户nagios下工作,所以脚本需要读取和执行其他群组的权限。
一旦你把脚本放在/usr/lib/nagios/plugins目录中,就要在文件/etc/nagios/objects/commands.cfg里面把它定义成Nagios命令。假设你将脚本命名为check_file.sh,添加下列命令定义:
#我们的自定义文件检查命令:
define command{command_name&&& check_filecommand_line&&& $USER1$/check_file.sh $ARG1$}
这应当相当清楚。变量$ARG1$代表传递给Nagios命令的第一个实参;在本例中,这第一个实参应该是文件名称。如果你想传递更多的实参,可以将$ARG2$用作第二个实参,将$ARG3$用作第三个实参,以此类推。
想开始使用你的插件,应在你的nagios配置文件(比如service.cfg)中将其定义成一项服务:
define service{use&&&&&&&&&&&&&&&&&&&&&&&&&&&& local-servicehost_name&&&&&&&&&&&&&&&&&&&&&& localhostservice_description&&&&&&&&&&&& Check the file /etc/passwdcheck_command&&&&&&&&&&&&&&&&&& check_file!/etc/passwd}
上述服务是为本地主机(host_name localhost)定义的,为本地服务使用模板(使用local-service),详见文明文档的对象继承部分(http://nagios.sourceforge.net/docs/3_0/objectinheritance.html),即可了解模板及模板的工作原理。最重要的部分是check_command指令。它指定了命令check_file,然后是作为分隔符的感叹号,后面是作为实参的文件名称。如果你的插件有不止一个实参,可以用另外的感叹号来分隔。
远程运行Nagios插件
示例check_file plugin存在的一个明显缺点是它本地运行,这意味着无法检查远程服务器上的文件。你有许多办法可以解决这个问题。
第一个办法就是使用ssh命令,远程执行代码。这需要你把脚本拷贝到远程服务器上,并利用可以运行远程命令的功能。这还需要你为Nagios服务器及其nagios用户配置无密码密钥登录。如果这方面你不太确信如何操作,可以参阅本文/blog/opensource/remotely-monitor-servers-with-the-nagios-checkbyssh-plugin/321,了解所有的相关细节。
这第一个办法的优点是,你拥有了针对被监控的服务器,本地运行命令所具有的功能和灵活性。缺点就是,Nagios服务器必须能够借助密钥,无密码登录到远程服务器。这是个安全问题,不推荐敏感环境使用。
第二个比较安全的办法是,使用扩展功能。这要求你已在远程服务器上安装和配置好了net-snmp程序包(面向CentOS)。
想使用SNMP扩展命令,先将check_file.sh脚本拷贝到远程服务器上。比如说,你可以把该脚本放在目录/usr/bin/中。
接下来,将配置指令extend check_passwd_file /usr/bin/check_file.sh /etc/passwd添加到远程服务器上的文件/etc/snmp/snmpd.conf。语法是extend some_alias command argument。下面是这种方法存在的主要不便之处:你得为每一次独立的检查定义一个别名,在本例中这意味着为我们想要测试的每一个独立文件定义一个别名,因为无法通过SNMP来传送实参。
文件/etc/snmp/snmpd.conf只要出现变化,都需要你用service snmpd reload命令(面向CentOS),重新装入snmpd服务。之后,你可以用snmpget命令来测试新的检查,就跟在snmpget -v2c -c public -OvQ 10.0.0.2 NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\&check_passwd_file\&中一样。这个示例snmpget命令通过SNMP版本2c,以&public&共用字符串查询服务器10.0.0.2。自定义SNMP扩展命令的对象标识符(OID)是NET-SNMP-EXTEND-MIB::nsExtendOutputFull.\&some_alias\&。
遗憾的是,上面这个命令无法直接用Nagios来实现。如果snmpget正常工作,可以连接至远程主机,它总是会返回状态0,这表明每方面都正常,因为程序snmpget本身退出时没有错误。因而,即使某个文件不存在,检查脚本也会返回状态0,不过它会输出文件不存在的正确消息。
你可以解决这个问题,只要充分利用针对Nagios的名为check_snmp_extend.sh的特殊插件。这个插件取得状态消息的第一个单词后,根据该单词来设定状态。由于预计使用这个插件,我们在示例脚本check_file.sh中设定了消息,以便从OK(正常)、CRITICAL(临界)、WARNING(警告)和UNKNOWN(未知)开始。
想开始使用check_snmp_extend.sh插件,先下载该插件(http://www.logix.cz/michal/devel/nagios/check_snmp_extend.sh),然后把它放到Nagios服务器上的目录/usr/lib/nagios/plugins($USER1宏命令)。在CentOS上,你得编辑脚本check_snmp_extend.sh,并把/usr/local/nagios/libexec/utils.sh换成/usr/lib/nagios/plugins/utils.sh,这是utils.sh脚本的正确路径。
之后,你就可以像使用其他任何插件那样使用check_snmp_extend.sh。首先,把它定义为一个命令:
define command{command_name&check_snmp_extendcommand_line&$USER1$/check_snmp_extend.sh $HOSTADDRESS$ $ARG1$}
之后,定义一项服务:
define service{use&&&&&&&&&&&&&&&& generic-servicehost_name&&&&&&&& somehost.example.orgservice_description&Check For /etc/passwdcheck_command&&check_snmp_extend!check_passwd_file}
使用SNMP的扩展选项就跟你的SNMP配置一样安全。这个办法只需要在远程主机上进行极少的改动,又确保了标准的设置环境符合安全方面的最佳实践。你可以找到用于类似用途的其他Nagios插件,比如nrpe,但是它们要求远程安装额外服务,从安全和兼容性的角度来看这并非总是一个好主意。
如你所见,很容易用自行编写的插件来扩展Nagios。Nagios允许这种扩展,这一点正是许多管理员青睐它、而不是青睐其他监控解决方案的原因之一。
原文链接:
【编辑推荐】
【责任编辑: TEL:(010)】
关于&&的更多文章
Nagios是一个流行的电脑系统和网络监控程序,能监视所指定的本地
本期重点推荐:转角遇到Zabbix:企业级分布式系统监控部署
霾欲静而风不止,又是雾霾黄色预警时,北京最近的天气
经过八个月的开发,openSUSE 13.1在其官网正式发布。o
开源软件、闭源软件之争多年来从未停歇。开源有开源的
随着互联网的迅速发展,几乎所有工具软件和程序语言都支持的正则表达式也变得越来越强大和易于使用。本书是讲解正则表达式的经典
51CTO旗下网站}

我要回帖

更多关于 system.exit 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信