从文件管理器到安全工具,文件系统监控对于的许多程序来说都是必不可少的。从 Linux 2.6.13 内核开始,Linux 就推出了 inotify,允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件,例如打开、关闭、移动/重命名、删除、创建或者改变属性。在后期的内核中有了很多增强,因此在依赖这些特性之前,请先检查您的内核版本。
linux的2.6.11内核之后有了inotify,这个特性确实很不错,使得很多用户策略得以实现,但是这个特性的代码实现却不是那么好,说实话很乱,很难扩展,很多链表,抽象出的dev结构也不是那么符合逻辑,只不过是为了将各种杂乱的数据结合在一起的勉强罢了。近期由于换工作一直没有关注kernel方面的更新,今天在新工作敲定以后终于有时间看看kernel最新的进展了,发现2.6.31版本的内核中对notify进行了一番大的改动,将原来的inotify和dnotify这两个不想关的特性进行了抽象,将它们的共同的点抽象成了一个基础设施,这个基础设施就是fsnotify.
1, 前端部分:
【模板标签】
模板标签用”qqqq”和”qqqq”括起来
【注释】
qqqq/* a comment /qqqq
使用“qqqq/”和“*/qqqq”来包含注释内容
【变量】
qqqq.qqqq
此标签输出当前对象的值
qqqq.Admpubqqqq
表示输出Struct对象中字段或方法名称为“Admpub”的值。
当“Admpub”是匿名字段时,可以访问其内部字段或方法,比如“Com”:qqqq.Admpub.Comqqqq ,
如果“Com”是一个方法并返回一个Struct对象,同样也可以访问其字段或方法:qqqq.Admpub.Com.Field1qqqq
qqqq.Method1 “参数值1” “参数值2”qqqq
调用方法“Method1”,将后面的参数值依次传递给此方法,并输出其返回值。
qqqq$admpubqqqq
此标签用于输出在模板中定义的名称为“admpub”的变量。当$admpub本身是一个Struct对象时,可访问其字段:qqqq$admpub.Field1qqqq
在模板中定义变量:变量名称用字母和数字组成,并带上“$”前缀,采用符号“:=”进行赋值。
比如:qqqq$x := “OK”qqqq 或 qqqq$x := pipelineqqqq
【管道函数】
用法1:
qqqqFuncName1qqqq
此标签将调用名称为“FuncName1”的模板函数(等同于执行“FuncName1()”,不传递任何参数)并输出其返回值。
用法2:
qqqqFuncName1 “参数值1” “参数值2”qqqq
此标签将调用“FuncName1(“参数值1”, “参数值2”)”,并输出其返回值
用法3:
qqqq.Admpub|FuncName1qqqq
此标签将调用名称为“FuncName1”的模板函数(等同于执行“FuncName1(this.Admpub)”,将竖线“|”左边的“.Admpub”变量值作为函数参数传送)并输出其返回值。
【条件判断】
用法1:
qqqqif pipelineqqqq T1 qqqqendqqqq
标签结构:qqqqif …qqqq … qqqqendqqqq
用法2:
qqqqif pipelineqqqq T1 qqqqelseqqqq T0 qqqqendqqqq
标签结构:qqqqif …qqqq … qqqqelseqqqq … qqqqendqqqq
用法3:
qqqqif pipelineqqqq T1 qqqqelse if pipelineqqqq T0 qqqqendqqqq
标签结构:qqqqif …qqqq … qqqqelse if …qqqq … qqqqendqqqq
其中if后面可以是一个条件表达式(包括管道函数表达式。pipeline即管道),也可以是一个字符窜变量或布尔值变量。当为字符窜变量时,如为空字符串则判断为false,否则判断为true。
【遍历】
用法1:
qqqqrange $k, $v := .Varqqqq qqqq$kqqqq => qqqq$vqqqq qqqqend}}
range…end结构内部如要使用外部的变量,比如.Var2,需要这样写:$.Var2
(即:在外部变量名称前加符号“$”即可,单独的“$”意义等同于global)
用法2:
qqqqrange .Varqqqq qqqq.qqqq qqqqendqqqq
用法3:
qqqqrange pipelineqqqq T1 qqqqelseqqqq T0 qqqqendqqqq
当没有可遍历的值时,将执行else部分。
【嵌入子模板】
用法1:
qqqqtemplate “name”qqqq
嵌入名称为“name”的子模板。使用前,请确保已经用“qqqqdefine “name”qqqq子模板内容qqqqendqqqq”定义好了子模板内容。
用法2:
qqqqtemplate “name” pipelineqqqq
将管道的值赋给子模板中的“.”(即“qqqq.qqqq”)
【子模板嵌套】
qqqqdefine “T1”qqqqONEqqqqendqqqq
qqqqdefine “T2”qqqqTWOqqqqendqqqq
qqqqdefine “T3”qqqqqqqqtemplate “T1”qqqq qqqqtemplate “T2”qqqqqqqqend}}
qqqqtemplate “T3”qqqq
输出:
ONE TWO
【定义局部变量】
用法1:
qqqqwith pipelineqqqq T1 qqqqendqqqq
管道的值将赋给该标签内部的“.”。(注:这里的“内部”一词是指被qqqqwith pipelineqqqq…qqqqendqqqq包围起来的部分,即T1所在位置)
用法2:
qqqqwith pipelineqqqq T1 qqqqelseqqqq T0 qqqqendqqqq
如果管道的值为空,“.”不受影响并且执行T0,否则,将管道的值赋给“.”并且执行T1。
说明:qqqqendqqqq标签是if、with、range的结束标签。
【例子:输出字符窜】
qqqq”"output"“qqqq
输出一个字符窜常量。
qqqq"output"
qqqq
输出一个原始字符串常量
qqqqprintf “%q” “output”qqqq
函数调用.(等同于:printf(“%q”, “output”)。)
qqqq”output” | printf “%q”qqqq
竖线“|”左边的结果作为函数最后一个参数。(等同于:printf(“%q”, “output”)。)
qqqqprintf “%q” (print “out” “put”)qqqq
圆括号中表达式的整体结果作为printf函数的参数。(等同于:printf(“%q”, print(“out”, “put”))。)
qqqq”put” | printf “%s%s” “out” | printf “%q”qqqq
一个更复杂的调用。(等同于:printf(“%q”, printf(“%s%s”, “out”, “put”))。)
qqqq”output” | printf “%s” | printf “%q”qqqq
等同于:printf(“%q”, printf(“%s”, “output”))。
qqqqwith “output”qqqqqqqqprintf “%q” .qqqqqqqqendqqqq
一个使用点号“.”的with操作。(等同于:printf(“%q”, “output”)。)
qqqqwith $x := “output” | printf “%q”qqqqqqqq$xqqqqqqqqendqqqq
with结构,定义变量,值为执行管道函数之后的结果(等同于:$x := printf(“%q”, “output”)。)
qqqqwith $x := “output”qqqqqqqqprintf “%q” $xqqqqqqqqendqqqq
with结构中,在其它动作中使用定义的变量
qqqqwith $x := “output”qqqqqqqq$x | printf “%q”qqqqqqqqendqqqq
同上,但使用了管道。(等同于:printf(“%q”, “output”)。)
===============【预定义的模板全局函数】================
【and】
qqqqand x yqqqq
表示:if x then y else x
如果x为真,返回y,否则返回x。等同于Golang中的:x && y
【call】
qqqqcall .X.Y 1 2qqqq
表示:dot.X.Y(1, 2)
call后面的第一个参数的结果必须是一个函数(即这是一个函数类型的值),其余参数作为该函数的参数。
该函数必须返回一个或两个结果值,其中第二个结果值是error类型。
如果传递的参数与函数定义的不匹配或返回的error值不为nil,则停止执行。
【html】
转义文本中的html标签,如将“<”转义为“<”,“>”转义为“>”等
【index】
qqqqindex x 1 2 3qqqq
返回index后面的第一个参数的某个索引对应的元素值,其余的参数为索引值
表示:x[1][2][3]
x必须是一个map、slice或数组
【js】
返回用JavaScript的escape处理后的文本
【len】
返回参数的长度值(int类型)
【not】
返回单一参数的布尔否定值。
【or】
qqqqor x yqqqq
表示:if x then x else y。等同于Golang中的:x || y
如果x为真返回x,否则返回y。
【print】
fmt.Sprint的别名
【printf】
fmt.Sprintf的别名
【println】
fmt.Sprintln的别名
【urlquery】
返回适合在URL查询中嵌入到形参中的文本转义值。(类似于PHP的urlencode)
=================【布尔函数】===============
布尔函数对于任何零值返回false,非零值返回true。
这里定义了一组二进制比较操作符函数:
【eq】
返回表达式“arg1 == arg2”的布尔值
【ne】
返回表达式“arg1 != arg2”的布尔值
【lt】
返回表达式“arg1 < arg2”的布尔值
【le】
返回表达式“arg1 <= arg2”的布尔值
【gt】
返回表达式“arg1 > arg2”的布尔值
【ge】
返回表达式“arg1 >= arg2”的布尔值
对于简单的多路相等测试,eq只接受两个参数进行比较,后面其它的参数将分别依次与第一个参数进行比较,
qqqqeq arg1 arg2 arg3 arg4qqqq
即只能作如下比较:
arg1==arg2 || arg1==arg3 || arg1==arg4 …