multilog.c
来自「daemontools-0.76.tar.gz是在linux环境下自动监控进程的」· C语言 代码 · 共 618 行
C
618 行
#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include "direntry.h"#include "alloc.h"#include "buffer.h"#include "strerr.h"#include "error.h"#include "open.h"#include "lock.h"#include "scan.h"#include "str.h"#include "byte.h"#include "seek.h"#include "timestamp.h"#include "wait.h"#include "coe.h"#include "env.h"#include "fd.h"#include "sig.h"#include "match.h"#include "deepsleep.h"#define FATAL "multilog: fatal: "#define WARNING "multilog: warning: "void pause3(const char *s1,const char *s2,const char *s3){ strerr_warn4(WARNING,s1,s2,s3,&strerr_sys); deepsleep(5);}void pause5(const char *s1,const char *s2,const char *s3,const char *s4,const char *s5){ strerr_warn6(WARNING,s1,s2,s3,s4,s5,&strerr_sys); deepsleep(5);}int fdstartdir;int *f;void f_init(char **script){ int i; int fd; for (i = 0;script[i];++i) ; f = (int *) alloc(i * sizeof(*f)); if (!f) strerr_die2x(111,FATAL,"out of memory"); for (i = 0;script[i];++i) { fd = -1; if (script[i][0] == '=') { if (fchdir(fdstartdir) == -1) strerr_die2sys(111,FATAL,"unable to switch to starting directory: "); fd = open_append(script[i] + 1); if (fd == -1) strerr_die4sys(111,FATAL,"unable to create ",script[i] + 1,": "); close(fd); fd = open_write(script[i] + 1); if (fd == -1) strerr_die4sys(111,FATAL,"unable to write ",script[i] + 1,": "); coe(fd); } f[i] = fd; }}struct cyclog { char buf[512]; buffer ss; int fdcurrent; unsigned long bytes; unsigned long num; unsigned long size; char *processor; char *dir; int fddir; int fdlock; int flagselected;} *c;int cnum;char fn[40];int filesfit(struct cyclog *d){ DIR *dir; direntry *x; int count; int i; dir = opendir("."); if (!dir) return -1; fn[0] = '@'; fn[1] = 'z'; fn[2] = 0; count = 0; for (;;) { errno = 0; x = readdir(dir); if (!x) break; if (x->d_name[0] == '@') if (str_len(x->d_name) >= 25) { ++count; if (str_diff(x->d_name,fn) < 0) { for (i = 0;i < 25;++i) fn[i] = x->d_name[i]; fn[25] = 0; } } } if (errno) { closedir(dir); return -1; } closedir(dir); if (count < d->num) return 1; dir = opendir("."); if (!dir) return -1; for (;;) { errno = 0; x = readdir(dir); if (!x) break; if (x->d_name[0] == '@') if (str_len(x->d_name) >= 25) if (str_start(x->d_name,fn)) { unlink(x->d_name); break; } } if (errno) { closedir(dir); return -1; } closedir(dir); return 0;}void finish(struct cyclog *d,const char *file,const char *code){ struct stat st; for (;;) { if (stat(file,&st) == 0) break; if (errno == error_noent) return; pause5("unable to stat ",d->dir,"/",file,", pausing: "); } if (st.st_nlink == 1) for (;;) { timestamp(fn); fn[25] = '.'; fn[26] = code[0]; fn[27] = 0; if (link(file,fn) == 0) break; pause5("unable to link to ",d->dir,"/",fn,", pausing: "); } while (unlink(file) == -1) pause5("unable to remove ",d->dir,"/",file,", pausing: "); for (;;) switch(filesfit(d)) { case 1: return; case -1: pause3("unable to read ",d->dir,", pausing: "); }}void startprocessor(struct cyclog *d){ const char *args[4]; int fd; sig_uncatch(sig_term); sig_uncatch(sig_alarm); sig_unblock(sig_term); sig_unblock(sig_alarm); fd = open_read("previous"); if (fd == -1) return; if (fd_move(0,fd) == -1) return; fd = open_trunc("processed"); if (fd == -1) return; if (fd_move(1,fd) == -1) return; fd = open_read("state"); if (fd == -1) return; if (fd_move(4,fd) == -1) return; fd = open_trunc("newstate"); if (fd == -1) return; if (fd_move(5,fd) == -1) return; args[0] = "sh"; args[1] = "-c"; args[2] = d->processor; args[3] = 0; execve("/bin/sh",args,environ);}void fullcurrent(struct cyclog *d){ int fd; int pid; int wstat; while (fchdir(d->fddir) == -1) pause3("unable to switch to ",d->dir,", pausing: "); while (fsync(d->fdcurrent) == -1) pause3("unable to write ",d->dir,"/current to disk, pausing: "); close(d->fdcurrent); while (rename("current","previous") == -1) pause3("unable to rename current to previous in directory ",d->dir,", pausing: "); while ((d->fdcurrent = open_append("current")) == -1) pause3("unable to create ",d->dir,"/current, pausing: "); coe(d->fdcurrent); d->bytes = 0; while (fchmod(d->fdcurrent,0644) == -1) pause3("unable to set mode of ",d->dir,"/current, pausing: "); while (chmod("previous",0744) == -1) pause3("unable to set mode of ",d->dir,"/previous, pausing: "); if (!d->processor) finish(d,"previous","s"); else { for (;;) { while ((pid = fork()) == -1) pause3("unable to fork for processor in ",d->dir,", pausing: "); if (!pid) { startprocessor(d); strerr_die4sys(111,FATAL,"unable to run ",d->processor,": "); } if (wait_pid(&wstat,pid) == -1) pause3("wait failed for processor in ",d->dir,", pausing: "); else if (wait_crashed(wstat)) pause3("processor crashed in ",d->dir,", pausing: "); else if (!wait_exitcode(wstat)) break; strerr_warn4(WARNING,"processor failed in ",d->dir,", pausing",0); deepsleep(5); } while ((fd = open_append("processed")) == -1) pause3("unable to create ",d->dir,"/processed, pausing: "); while (fsync(fd) == -1) pause3("unable to write ",d->dir,"/processed to disk, pausing: "); while (fchmod(fd,0744) == -1) pause3("unable to set mode of ",d->dir,"/processed, pausing: "); close(fd); while ((fd = open_append("newstate")) == -1) pause3("unable to create ",d->dir,"/newstate, pausing: "); while (fsync(fd) == -1) pause3("unable to write ",d->dir,"/newstate to disk, pausing: "); close(fd); while (unlink("previous") == -1) pause3("unable to remove ",d->dir,"/previous, pausing: "); while (rename("newstate","state") == -1) pause3("unable to rename newstate to state in directory ",d->dir,", pausing: "); finish(d,"processed","s"); }}int c_write(int pos,char *buf,int len){ struct cyclog *d; int w; d = c + pos; if (d->bytes >= d->size) fullcurrent(d); if (len >= d->size - d->bytes) len = d->size - d->bytes; if (d->bytes + len >= d->size - 2000) { w = byte_rchr(buf,len,'\n'); if (w < len) len = w + 1; } for (;;) { w = write(d->fdcurrent,buf,len); if (w > 0) break; pause3("unable to write to ",d->dir,"/current, pausing: "); } d->bytes += w; if (d->bytes >= d->size - 2000) if (buf[w - 1] == '\n') fullcurrent(d); return w;}void restart(struct cyclog *d){ struct stat st; int fd; int flagprocessed; if (fchdir(fdstartdir) == -1) strerr_die2sys(111,FATAL,"unable to switch to starting directory: "); mkdir(d->dir,0700); d->fddir = open_read(d->dir); if ((d->fddir == -1) || (fchdir(d->fddir) == -1)) strerr_die4sys(111,FATAL,"unable to open directory ",d->dir,": "); coe(d->fddir); d->fdlock = open_append("lock"); if ((d->fdlock == -1) || (lock_exnb(d->fdlock) == -1)) strerr_die4sys(111,FATAL,"unable to lock directory ",d->dir,": "); coe(d->fdlock); if (stat("current",&st) == -1) { if (errno != error_noent) strerr_die4sys(111,FATAL,"unable to stat ",d->dir,"/current: "); } else if (st.st_mode & 0100) { fd = open_append("current"); if (fd == -1) strerr_die4sys(111,FATAL,"unable to append to ",d->dir,"/current: "); if (fchmod(fd,0644) == -1) strerr_die4sys(111,FATAL,"unable to set mode of ",d->dir,"/current: "); coe(fd); d->fdcurrent = fd; d->bytes = st.st_size; return; } unlink("state"); unlink("newstate"); flagprocessed = 0; if (stat("processed",&st) == -1) { if (errno != error_noent) strerr_die4sys(111,FATAL,"unable to stat ",d->dir,"/processed: "); } else if (st.st_mode & 0100) flagprocessed = 1; if (flagprocessed) { unlink("previous"); finish(d,"processed","s"); } else { unlink("processed"); finish(d,"previous","u"); } finish(d,"current","u"); fd = open_trunc("state"); if (fd == -1) strerr_die4sys(111,FATAL,"unable to write to ",d->dir,"/state: "); close(fd); fd = open_append("current"); if (fd == -1) strerr_die4sys(111,FATAL,"unable to write to ",d->dir,"/current: "); if (fchmod(fd,0644) == -1) strerr_die4sys(111,FATAL,"unable to set mode of ",d->dir,"/current: "); coe(fd); d->fdcurrent = fd; d->bytes = 0;}void c_init(char **script){ int i; struct cyclog *d; char *processor; unsigned long num; unsigned long size; cnum = 0; for (i = 0;script[i];++i) if ((script[i][0] == '.') || (script[i][0] == '/')) ++cnum; c = (struct cyclog *) alloc(cnum * sizeof(*c)); if (!c) strerr_die2x(111,FATAL,"out of memory"); d = c; processor = 0; num = 10; size = 99999; for (i = 0;script[i];++i) if (script[i][0] == 's') { scan_ulong(script[i] + 1,&size); if (size < 4096) size = 4096; if (size > 16777215) size = 16777215; } else if (script[i][0] == 'n') { scan_ulong(script[i] + 1,&num); if (num < 2) num = 2; } else if (script[i][0] == '!') { processor = script[i] + 1; } else if ((script[i][0] == '.') || (script[i][0] == '/')) { d->num = num; d->size = size; d->processor = processor; d->dir = script[i]; buffer_init(&d->ss,c_write,d - c,d->buf,sizeof d->buf); restart(d); ++d; }}void c_quit(void){ int j; for (j = 0;j < cnum;++j) { buffer_flush(&c[j].ss); while (fsync(c[j].fdcurrent) == -1) pause3("unable to write ",c[j].dir,"/current to disk, pausing: "); while (fchmod(c[j].fdcurrent,0744) == -1) pause3("unable to set mode of ",c[j].dir,"/current, pausing: "); }}int flagexitasap = 0;int flagforcerotate = 0;int flagnewline = 1;void exitasap(void){ flagexitasap = 1;}void forcerotate(void){ flagforcerotate = 1;}int flushread(int fd,char *buf,int len){ int j; for (j = 0;j < cnum;++j) buffer_flush(&c[j].ss); if (flagforcerotate) { for (j = 0;j < cnum;++j) if (c[j].bytes > 0) fullcurrent(&c[j]); flagforcerotate = 0; } if (!len) return 0; if (flagexitasap) { if (flagnewline) return 0; len = 1; } sig_unblock(sig_term); sig_unblock(sig_alarm); len = read(fd,buf,len); sig_block(sig_term); sig_block(sig_alarm); if (len <= 0) return len; flagnewline = (buf[len - 1] == '\n'); return len;}char inbuf[1024];buffer ssin = BUFFER_INIT(flushread,0,inbuf,sizeof inbuf);char line[1001];int linelen; /* 0 <= linelen <= 1000 */void doit(char **script){ int flageof; char ch; int j; int i; char *action; int flagselected; int flagtimestamp; flagtimestamp = 0; if (script[0]) if (script[0][0] == 't') flagtimestamp = 1; for (i = 0;i <= 1000;++i) line[i] = '\n'; linelen = 0; flageof = 0; for (;;) { for (i = 0;i < linelen;++i) line[i] = '\n'; linelen = 0; while (linelen < 1000) { if (buffer_GETC(&ssin,&ch) <= 0) { if (!linelen) return; flageof = 1; break; } if (!linelen) if (flagtimestamp) { timestamp(line); line[25] = ' '; linelen = 26; } if (ch == '\n') break; line[linelen++] = ch; } flagselected = 1; j = 0; for (i = 0;action = script[i];++i) switch(*action) { case '+': if (!flagselected) if (match(action + 1,line,linelen)) flagselected = 1; break; case '-': if (flagselected) if (match(action + 1,line,linelen)) flagselected = 0; break; case 'e': if (flagselected) { if (linelen > 200) { buffer_put(buffer_2,line,200); buffer_puts(buffer_2,"...\n"); } else { buffer_put(buffer_2,line,linelen); buffer_puts(buffer_2,"\n"); } buffer_flush(buffer_2); } break; case '=': if (flagselected) for (;;) { while (seek_begin(f[i]) == -1) pause3("unable to move to beginning of ",action + 1,", pausing: "); if (write(f[i],line,1001) == 1001) break; pause3("unable to write ",action + 1,", pausing: "); } break; case '.': case '/': c[j].flagselected = flagselected; ++j; break; } for (j = 0;j < cnum;++j) if (c[j].flagselected) buffer_put(&c[j].ss,line,linelen); if (linelen == 1000) for (;;) { if (buffer_GETC(&ssin,&ch) <= 0) { flageof = 1; break; } if (ch == '\n') break; for (j = 0;j < cnum;++j) if (c[j].flagselected) buffer_PUTC(&c[j].ss,ch); } for (j = 0;j < cnum;++j) if (c[j].flagselected) { ch = '\n'; buffer_PUTC(&c[j].ss,ch); } if (flageof) return; }}int main(int argc,char **argv){ umask(022); fdstartdir = open_read("."); if (fdstartdir == -1) strerr_die2sys(111,FATAL,"unable to switch to current directory: "); coe(fdstartdir); sig_block(sig_term); sig_block(sig_alarm); sig_catch(sig_term,exitasap); sig_catch(sig_alarm,forcerotate); ++argv; f_init(argv); c_init(argv); doit(argv); c_quit(); _exit(0);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?