题目:编写监控/home/itcast/目录下文件创建与更改的守护进程,日志文件放在/home/itcast/filechangelog
思路:用链表存储文件列表,到下一个周期在用另一个链表存储新的文件列表,然后两个链表对比,找出那些没变,那些是增加的,那些已经删除了,然后根据这些信息把重新把第一个链表修改好,并且把这些信息写到log中去
本程序主要分为5部分,main代码文件,链表函数文件,function函数文件,头文件,Makefile。
main代码文件
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "defend.h"
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#define MAX_PATH 1024
struct list *tmp;
int status = 0; //这个是状态位,主要是来验证链表中的文件元素是不是已经被删除
void daemonize(void)
{
struct list *first; //正常维护的链表
first = creat_list();
struct list *second; //用来比对文件是否增加或删除的链表
second = creat_list();
pid_t pid;
if ((pid = fork()) < 0) //创建进程
sys_err("fork");
else if(pid != 0) //父进程挂掉
exit(0);
setsid(); //修改自身的会话id
if(chdir("/") < 0) //修改运行目录
sys_err("fork");
umask(0); //修改权限掩码
close(0); //0,1,2三个文件描述符重定向到NULL
open("/dev/null", O_RDWR);
dup2(0, 1);
dup2(0, 2);
tmp = first; //把第一次first的地址给tmp,然后通过load_list函数来加载目录
load_list("/home/itcast"); //第一次加载目录
while(1) {
sleep(600); //运行周期10分钟
status++; //更改存在状态位
tmp = second; //加载第二遍目录列表,用来和first链表比对
load_list("/home/itcast"); //加载第二遍
contrast(first, second); //对比两个链表
check_del(first); //把已经删除的文件所对应的first中的链表元素删除
free_list(second);//释放second的内存,方便下次使用
}
}
int main(void)
{
daemonize();
return 0;
}
链表函数文件
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include "defend.h"
struct list *creat_list() //创建链表空间
{
return calloc(sizeof(struct list), 1);
}
void add_list(struct list *ls, char *name, struct stat *st) //添加链表元素
{
struct list *p = ls;
while(p->next) {
p = p->next;
}
struct list *tmp = creat_list();
tmp->next = p->next;
p->next = tmp;
strcpy(tmp->name, name);
memcpy(&tmp->st, st, sizeof(struct stat));
tmp->status = status%2;
}
void show_list(struct list *ls) //遍历打印链表元素 调试的时候使用
{
struct list *p = ls;
while(p) {
p = p->next;
}
}
void del_list(struct list *ls, char *name, struct stat *st) //删除链表中特定的元素
{
struct list *p = ls;
while(p->next) {
if((strcmp(p->next->name, name) == 0) && (p->next->st.st_ino == st->st_ino))
break;
p = p->next;
}
struct list *tmp = p->next;
if(p->next->next == NULL)
p->next = NULL;
else
p->next = p->next->next;
free(tmp);
}
void free_list(struct list *ls) //释放链表
{
struct list *p = ls->next;
while(p) {
struct list *tmp = p->next;
free(p);
p = tmp;
}
ls->next = NULL;
}
void list_sort(struct list *ls) //链表排序,用过文件的inode号排序,本打算使用别的查找方法,但最终没有实现,暂且放着
{
struct list *i = ls->next;
struct list *j = ls->next;
struct list *tmp = creat_list();
while(i->next) {
while(j->next) {
if(j->st.st_ino > j->next->st.st_ino) {
strcpy(tmp->name, j->name);
strcpy(j->name, j->next->name);
strcpy(j->next->name, tmp->name);
memcpy(&tmp->st, &j->st, sizeof(struct stat));
memcpy(&j->st, &j->next->st, sizeof(struct stat));
memcpy(&j->next->st, &tmp->st, sizeof(struct stat));
tmp->status = j->status;
j->status = j->next->status;
j->next->status = tmp->status;
}
j = j->next;
}
j = ls->next;
i = i->next;
}
free(tmp);
}
function函数文件
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include "defend.h"
#define MAX_PATH 1024
extern struct list *tmp; //引用外部变量,用于加载链表
extern int status; //引用外部变量,用于修改文件存在状态
void sys_err(const char *str)
{
perror(str);
exit(0);
}
void load_list(char *dir) //把文件信息加载到链表中去
{
struct stat st;
if(stat(dir,&st) < 0)
sys_err("stat");
if((st.st_mode & S_IFMT) == S_IFDIR)
read_file(dir);
add_list(tmp, dir, &st); //加载
}
void read_file(char *file) //遍历目录中的文件
{
char name[MAX_PATH];
struct dirent *read;
DIR *dir;
if((dir = opendir(file)) < 0)
sys_err("opendir");
while((read = readdir(dir)) != NULL) {
if(strcmp(read->d_name,".") == 0 || strcmp(read->d_name, "..") == 0)
continue;
if(strlen(file) + strlen(read->d_name) + 2 > sizeof(name))
continue;
else {
sprintf(name, "%s/%s", file, read->d_name);
load_list(name);
closedir(dir);
}
void contrast(struct list *ls1, struct list *ls2) //对比两个链表元素,如果第二个链表中有,但第一个链表没有的,就增加到第一个链表,并写log
{
struct list *first = ls1->next;
struct list *second = ls2->next;
while (second) {
if(binary(first, second) != 0) {
add_list(first, second->name, &second->st);
write_log(second, "create");
}
second = second->next;
}
}
int binary(struct list *ls1, const struct list *ls2) //查找链表中有没有这个元素,有就返回0,并更改第一个链表中的status位,没有就返回-1
{
struct list *first = ls1;
while(first) {
if(ls2->st.st_ino == first->st.st_ino) {
first->status = status%2;
return 0;
}
}
first = first->next;
}
return -1;
}
void check_del(struct list *ls) //检查第一个链表中的status这个字段,来判断文件是否已删除
{
struct list *p = ls->next;
while(p->next) {
if(p->status != status%2) {
printf("inode = %d, status = %d, name = %s, size = %d\n", (int)p->st.st_ino, p->status, p->name, (int)p->st.st_size);
write_log(p, "delete");
del_list(ls, p->name, &p->st);
}
p = p->next;
}
}
void write_log(struct list *ls, char *buff) //写日志
{
int fd;
time_t t;
char str[1024] = {0};
fd = open("/home/itcast/filechangelog", O_CREAT|O_RDWR|O_APPEND, 0664);
time(&t);
sprintf(str, "%s\t%s\t%s", buff, ls->name, ctime(&t));
write(fd, str, strlen(str));
close(fd);
}
头文件
#define __DEFEND__
struct list {
char name[256]; //文件名
int status; //删除状态位
struct stat st; //文件信息
struct list *next;
};
struct list *creat_list(); //创建
void add_list(struct list *, char *, struct stat *); //添加
void show_list(struct list *); //遍历打印
void del_list(struct list *, char *, struct stat *); //删除元素
void free_list(struct list *); //释放链表
void list_sort(struct list *); //链表排序
void sys_err(const char *);
void load_list(char *); //加载目录
void read_file(char *); //遍历目录
void contrast(struct list *, struct list *); //对比两个链表
int binary(struct list *, const struct list *); //查找链表中时候存在某个元素
void check_del(struct list *); //删除文件不存在的元素
void write_log(struct list *ls, char *buff); //写日志
#endif
问题:
链表中第一个元素为空,只能判断增加或者删除,顺序查找法,效率低下,