198 lines
4.4 KiB
C
198 lines
4.4 KiB
C
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
#include <time.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <errno.h>
|
||
|
|
|
||
|
|
#define INTERVAL_SEC 10
|
||
|
|
#define LOG_FILE "log"
|
||
|
|
|
||
|
|
static unsigned int compute_hash(const char *data, size_t len)
|
||
|
|
{
|
||
|
|
unsigned int hash =0;
|
||
|
|
const unsigned char *p = (const unsigned char *)data;
|
||
|
|
size_t i,n = len /4;
|
||
|
|
|
||
|
|
for ( i = 0; i < n; i++)
|
||
|
|
{
|
||
|
|
unsigned int val = (unsigned int)p[i * 4] | ((unsigned int)p[i * 4 + 1] << 8)
|
||
|
|
| ((unsigned int)p[i * 4 + 2] << 16) | ((unsigned int)p[i * 4 + 3] << 24);
|
||
|
|
hash += val;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t rem = len % 4,base = n*4;
|
||
|
|
for ( i = 0; i < rem; i++)
|
||
|
|
{
|
||
|
|
hash += (unsigned int)p[base + i];
|
||
|
|
}
|
||
|
|
return hash;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static char *read_file(const char *path,size_t *out_len)
|
||
|
|
{
|
||
|
|
int fd = open(path,O_RDONLY);
|
||
|
|
if (fd < 0)
|
||
|
|
{
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
off_t size = lseek(fd,0,SEEK_END);
|
||
|
|
if (size < 0)
|
||
|
|
{
|
||
|
|
close(fd);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
lseek(fd,0,SEEK_SET);
|
||
|
|
|
||
|
|
char *buf = malloc((size_t)size + 1);
|
||
|
|
if (!buf)
|
||
|
|
{
|
||
|
|
close(fd);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
ssize_t n = read(fd,buf,(size_t)size);
|
||
|
|
if (n < 0)
|
||
|
|
{
|
||
|
|
free(buf);
|
||
|
|
close(fd);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
buf[n] = '\0';
|
||
|
|
*out_len = (size_t)n;
|
||
|
|
close(fd);
|
||
|
|
return buf;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void write_log(unsigned int hash)
|
||
|
|
{
|
||
|
|
FILE *fp = fopen(LOG_FILE,"a");
|
||
|
|
if (!fp)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
time_t now = time(NULL);
|
||
|
|
struct tm *tm_info = localtime(&now);
|
||
|
|
char time_str[20];
|
||
|
|
strftime(time_str,sizeof(time_str),"%Y-%m-%d %H:%M:%S",tm_info);
|
||
|
|
|
||
|
|
fprintf(fp,"%s hash=%u\n",time_str,hash);
|
||
|
|
fclose(fp);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void daemonize(void)
|
||
|
|
{
|
||
|
|
pid_t pid = fork();
|
||
|
|
if (pid < 0)
|
||
|
|
{
|
||
|
|
exit(1);
|
||
|
|
}
|
||
|
|
if (pid > 0)
|
||
|
|
{
|
||
|
|
exit(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
setsid();
|
||
|
|
umask(0);
|
||
|
|
|
||
|
|
close(STDIN_FILENO);
|
||
|
|
close(STDOUT_FILENO);
|
||
|
|
close(STDERR_FILENO);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int main(int argc,char *argv[])
|
||
|
|
{
|
||
|
|
//自检模式
|
||
|
|
if (argc > 1 && strcmp(argv[1],"test") == 0)
|
||
|
|
{
|
||
|
|
/* 测试1: 不同内容应产生不同hash值 */
|
||
|
|
printf("自检模式\n");
|
||
|
|
|
||
|
|
const char *test_str = "Hello, World!";
|
||
|
|
unsigned int h1 = compute_hash(test_str,strlen(test_str));
|
||
|
|
|
||
|
|
const char *test_str2 = "Hello, world!"; // 注意 'W' 和 'w'
|
||
|
|
unsigned int h2 = compute_hash(test_str2,strlen(test_str2));
|
||
|
|
|
||
|
|
printf("测试1: hash1=%u, hash2=%u\n",h1,h2);
|
||
|
|
if (h1 != h2)
|
||
|
|
printf("通过: 不同内容 -> 不同hash值\n");
|
||
|
|
else
|
||
|
|
printf("失败: 不同内容应产生不同的hash值\n");
|
||
|
|
|
||
|
|
|
||
|
|
/* 测试2: 相同内容应产生相同hash值 */
|
||
|
|
unsigned int h3 = compute_hash(test_str,strlen(test_str));
|
||
|
|
printf("测试2: hash3=%u\n",h3);
|
||
|
|
if (h1 == h3)
|
||
|
|
printf("通过: 相同内容 -> 相同hash值\n");
|
||
|
|
else
|
||
|
|
printf("失败: 相同内容应产生相同的hash值\n");
|
||
|
|
|
||
|
|
/* 测试3: 读取自身并计算hash */
|
||
|
|
size_t len;
|
||
|
|
char *self = read_file("task53.c",&len);
|
||
|
|
if (self)
|
||
|
|
{
|
||
|
|
unsigned int hself = compute_hash(self,len);
|
||
|
|
printf("测试3: 自身hash=%u, 文件大小=%zu字节\n",hself,len);
|
||
|
|
free(self);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* 守护进程模式
|
||
|
|
* -f 表示前台运行(不调用daemonize), 便于测试
|
||
|
|
* 第二个参数可指定检查间隔秒数
|
||
|
|
*/
|
||
|
|
int foreground = (argc > 1 && strcmp(argv[1],"-f") == 0);
|
||
|
|
int interval = INTERVAL_SEC;
|
||
|
|
if (argc > 2) interval = atoi(argv[2]);
|
||
|
|
if (interval <= 0) interval = INTERVAL_SEC;
|
||
|
|
|
||
|
|
if (!foreground)
|
||
|
|
{
|
||
|
|
daemonize();
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t len;
|
||
|
|
char *prev_data = read_file("test.log",&len);
|
||
|
|
if (!prev_data) return 1;
|
||
|
|
unsigned int prev_hash = compute_hash(prev_data,len);
|
||
|
|
|
||
|
|
while (1)
|
||
|
|
{
|
||
|
|
sleep(interval);
|
||
|
|
|
||
|
|
size_t cur_len;
|
||
|
|
char *cur_data = read_file("test.log",&cur_len);
|
||
|
|
if (!cur_data)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
unsigned int cur_hash = compute_hash(cur_data,cur_len);
|
||
|
|
if (cur_hash != prev_hash)
|
||
|
|
{
|
||
|
|
write_log(cur_hash);
|
||
|
|
free(prev_data);
|
||
|
|
prev_data = cur_data;
|
||
|
|
prev_hash = cur_hash;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
free(cur_data);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
free(prev_data);
|
||
|
|
return 0;
|
||
|
|
}
|