[Netadm-devel] gwc/gwcklogd Makefile,NONE,1.1 gwcklogd.c,NONE,1.1 gwcklogd.h,NONE,1.1
Status: Beta
Brought to you by:
linuxpark
From: linuxpark <lin...@us...> - 2006-05-09 01:17:46
|
Update of /cvsroot/netadm/gwc/gwcklogd In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11615/gwcklogd Added Files: Makefile gwcklogd.c gwcklogd.h Log Message: Initial Check in gwcklogd : kernel log daemon just only for receiving kernel module logs and saving these log to /usr/local/gwc/log/~ --- NEW FILE: gwcklogd.c --- /* Title : gwcklogd.c Author : Jeho-Park <de...@sk...> Created date : 2006. 05. 06. (sat) 01:50:54 KST Description : user log daemon for gwc kernel logging This code is mainly based on klogd.c ~/.vimrc Local variables: c-indent-level: 8 c-basic-offset: 8 tab-width: 4 End: */ #ident "@(#) $Header: /cvsroot/netadm/gwc/gwcklogd/gwcklogd.c,v 1.1 2006/05/06 15:48:47 linuxpark Exp $" #include <stdio.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <sys/fcntl.h> #include <sys/stat.h> #include <sys/file.h> #include <linux/time.h> #include <stdarg.h> #include <paths.h> #include <stdlib.h> #include <syslog.h> #include <string.h> #include "global.h" #include "gwcklogd.h" #include "sysutil.h" #include "sysnio.h" #define LOG_BUFFER_SIZE 4096 #define LOG_LINE_LENGTH 1000 static char *PidFile = _PATH_VARRUN "gwcklogd.pid"; static int kmsg; static int change_state = 0; static int terminate = 0; static int caught_TSTP = 0; static int one_shot = 0; static int no_fork = 0; #ifdef RUNWITH_SYSLOGD /* i dont need to run with syslogd --LP (linuxpark, Jeho Park )*/ static char log_buffer[LOG_BUFFER_SIZE]; #endif static FILE *output_file = (FILE *) 0; static int debugging = 0; /* sig handler */ void restart(int sig); void stop_logging(int sig); void stop_daemon(int sig); static void closelogsrc(void); static void signaldaemon(int); static void changelog(void); static enum src get_klog_src(void); #ifdef RUNWITH_SYSLOGD static void logline(char *ptr, int len); #endif static void Syslog(int priority, char *fmt, ...); static enum src { none, proc, kernel } logsrc; enum parse_state_enum { PARSING_TEXT, PARSING_SYMSTART, /* at < */ PARSING_SYMBOL, PARSING_SYMEND /* at ] */ }; typedef int (*klog_cmdcb_t) (void *arg); typedef struct { int idx; int fd; int log_fd; char devname[MAXPATHLEN/4]; char log_file [MINBUF]; klog_cmdcb_t func; } gwc_klog_cmd_t; int gwcklog_pf (void *arg); int gwcklog_sys (void *arg); gwc_klog_cmd_t klogcmdtab [MAXSYSIDX] = { { GWC_PF_IDX, -1, -1, GWC_PF_DNAME, " ", gwcklog_pf }, { GWC_KSYS_IDX, -1, -1, GWC_SYS_DNAME, " ", gwcklog_sys }, }; int wlog (int idx, char *buf) { int ret; if (klogcmdtab[idx].log_fd < 0 ) { switch (idx) { case GWC_PF_IDX: sprintf (klogcmdtab[idx].log_file, "%s/log/%s", SZMAINPATH, GWC_PF_LOG); break; case GWC_KSYS_IDX: sprintf (klogcmdtab[idx].log_file, "%s/log/%s", SZMAINPATH, GWC_KSYS_LOG); break; default: return -1; break; } klogcmdtab[idx].log_fd = open (klogcmdtab[idx].log_file, O_CREAT | O_RDWR | O_APPEND | O_SYNC, 0600); if (klogcmdtab [idx].log_fd < 0 ) { out ("Failed to open %s: %s\n", klogcmdtab[idx].log_file, strerror(errno)); return -1; } if ( sys_blockingmode ( klogcmdtab[idx].log_fd, TRUE) < 0 ) { out ("Failed to make blocking idx [%d] devname[%s] error[%s]\n", idx, klogcmdtab[idx].devname, strerror(errno)); close ( klogcmdtab[idx].log_fd); klogcmdtab[idx].log_fd = -1; } } ret = write (klogcmdtab [idx].log_fd, buf, strlen (buf)); if (ret < 0 ) { out ("Failed to write to %s(%d): %s\n", klogcmdtab[idx].log_file, klogcmdtab[idx].log_fd, strerror(errno)); } return ret; } int rlog (int fd, char *buf, int bufsiz) { int ret; int i; char *p; if ((ret = read (fd, buf, bufsiz)) < 0 ) { for (i = 0; i < MAXSYSIDX; i++) if (klogcmdtab[i].fd == fd) break; out ("Failed to read from %s: %d \n", klogcmdtab[i].devname, ret); } /* TODO: "How about accumulated log lines" * * device accumulated about 1.6M log, when gwcklogd first start, he will read * accumulated log at one time * but i now eat accumulated log --LP */ if ( ret > MAXFNLEN ) { return -1; } p = strchr (buf, '\n'); if (!p) { out ("Get some agly log (no newline) from log device (nread:%d)\n", ret); return -1; } /* i don't have interest after newline */ *(p+1) = '\0'; #if 0 /* Check point : what i have gotten from log device --LP */ printf ("Log:%s\n", ret, buf); #endif return ret; } int gwcklog_pf (void *arg) { int ret; char buf[BUFLEN]; ret = rlog (klogcmdtab [GWC_PF_IDX].fd, buf, sizeof (buf)); if (ret > 0 ) { /* TODO: If you want to save love to Database, here is that point * but i just save this log to our gwc log files /usr/local/gwc/log/~ --LP */ ret = wlog (GWC_PF_IDX, buf); } else { return -1; } return ret; } int gwcklog_sys (void *arg) { int ret; char buf[BUFLEN]; ret = rlog (klogcmdtab [GWC_KSYS_IDX].fd, buf, sizeof (buf)); if (ret > 0) { /* TODO: If you want to save love to Database, here is that point * but i just save this log to our gwc log files /usr/local/gwc/log/~ --LP */ ret = wlog (GWC_KSYS_IDX, buf); } else { return -1; } return ret; } static int read_pid (char *pidfile) { FILE *f; int pid; if (!(f=fopen(pidfile,"r"))) return 0; fscanf(f,"%d", &pid); fclose(f); return pid; } static int check_pid (char *pidfile) { int pid = read_pid(pidfile); /* Amazing ! _I_ am already holding the pid file... */ if ((!pid) || (pid == getpid ())) return 0; if (kill(pid, 0) && errno == ESRCH) return 0; return pid; } static int write_pid (char *pidfile) { FILE *f; int fd; int pid; if ( ((fd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1) || ((f = fdopen(fd, "r+")) == NULL) ) { out ("Can't open or create %s. :%s \n", pidfile, strerror(errno)); return 0; } if (flock(fd, LOCK_EX|LOCK_NB) == -1) { fscanf(f, "%d", &pid); fclose(f); out ("Can't lock, lock is held by pid %d.\n", pid); return 0; } pid = getpid(); if (!fprintf(f, "%d\n", pid)) { out ("Can't write pid , %s.\n", strerror(errno)); close(fd); return 0; } fflush(f); if (flock(fd, LOCK_UN) == -1) { out ("Can't unlock pidfile %s, %s.\n", pidfile, strerror(errno)); close(fd); return 0; } close(fd); return pid; } static int remove_pid (char *pidfile) { return unlink (pidfile); } static void exitprog(void) { int i; closelogsrc(); Syslog(LOG_INFO, "Kernel log daemon terminating."); if ( output_file != (FILE *) 0 ) { fclose(output_file); } for (i = 0; i < MAXSYSIDX; i++) { close (klogcmdtab[i].fd); close (klogcmdtab[i].log_fd); } closelog(); (void) remove_pid(PidFile); exit(1); } static void closelogsrc(void) { switch ( logsrc ) { case kernel: Syslog(LOG_INFO, "Kernel logging (ksyslog) stopped."); break; case proc: close(kmsg); Syslog(LOG_INFO, "Kernel logging (proc) stopped."); break; case none: break; } if ( output_file != (FILE *) 0 ) fflush(output_file); return; } void restart(int sig) { signal(SIGCONT, restart); change_state = 1; caught_TSTP = 0; return; } void stop_logging(int sig) { signal(SIGTSTP, stop_logging); change_state = 1; caught_TSTP = 1; return; } void stop_daemon(int sig) { exitprog(); return; } static void signaldaemon(int sig) { int pid = check_pid(PidFile); kill(pid, sig); return; } static void changelog(void) { if (terminate) exitprog(); Syslog(LOG_INFO, "gwcklogd %s.%s, ---------- state change ----------\n", VERSION, PATCHLEVEL); if (caught_TSTP) { closelogsrc(); logsrc = none; change_state = 0; return; } if ( logsrc != none ) { Syslog(LOG_INFO, "Kernel logging re-started after SIGSTOP."); change_state = 0; return; } /* Restart logging. */ logsrc = get_klog_src(); change_state = 0; return; } static enum src get_klog_src(void) { int i; if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 ) { out ("klogd: Cannot open proc file system, %d - %s.\n", errno, strerror(errno)); for (i = 0; i < MAXSYSIDX; i++) { close (klogcmdtab[i].fd); close (klogcmdtab[i].log_fd); } exit(1); } Syslog(LOG_INFO, "klogd %s.%s, log source = %s started.", VERSION, PATCHLEVEL, _PATH_KLOG); return (proc); } static void Syslog(int priority, char *fmt, ...) { va_list ap; char *argl; /* Handle output to a file. */ if ( output_file != (FILE *) 0 ) { va_start(ap, fmt); vfprintf(output_file, fmt, ap); va_end(ap); fputc('\n', output_file); fflush(output_file); if (!one_shot) fsync(fileno(output_file)); return; } /* Output using syslog. */ if (!strcmp(fmt, "%s")) { va_start(ap, fmt); argl = va_arg(ap, char *); if (argl[0] == '<' && argl[1] && argl[2] == '>') { switch ( argl[1] ) { case '0': priority = LOG_EMERG; break; case '1': priority = LOG_ALERT; break; case '2': priority = LOG_CRIT; break; case '3': priority = LOG_ERR; break; case '4': priority = LOG_WARNING; break; case '5': priority = LOG_NOTICE; break; case '6': priority = LOG_INFO; break; case '7': default: priority = LOG_DEBUG; } argl += 3; } #ifdef RUNWITH_SYSLOGD /* If you want, send syslogd with uncommenting this line below. --LP */ syslog(priority, fmt, argl); /* org */ #endif /* fprintf (stdout, fmt, argl); my debug code --LP */ out (fmt, argl); va_end(ap); /* putchar ('\n'); org */ out ("\n"); /* mine --LP */ return; } va_start(ap, fmt); #ifdef RUNWITH_SYSLOGD vsyslog(priority, fmt, ap); #endif argl = va_arg(ap, char *); fprintf (stdout, fmt, argl); va_end(ap); return; } #ifdef RUNWITH_SYSLOGD static int copyin( char *line, int space, const char *ptr, int len, const char *delim ) { int i; int count; count = len < space ? len : space; for(i=0; i<count && !strchr(delim, *ptr); i++ ) { *line++ = *ptr++; } return i; } #endif #ifdef RUNWITH_SYSLOGD static void logline (char *ptr, int len) { static char line_buff[LOG_LINE_LENGTH]; static char *line = line_buff; static enum parse_state_enum parse_state = PARSING_TEXT; static int space = sizeof(line_buff)-1; int delta = 0; /* number of chars copied */ char *save_ptr = ptr; /* save start of input line */ int save_len = len; /* save length at start of input line */ while( len > 0 ) { if( space == 0 ) { /* line buffer is full */ /* ** Line too long. Start a new line. */ *line = 0; /* force null terminator */ if ( debugging ) { out ("Line buffer full:\n"); out ("\tLine: %s\n", line); } Syslog( LOG_INFO, "%s", line_buff ); line = line_buff; space = sizeof(line_buff)-1; parse_state = PARSING_TEXT; save_ptr = ptr; save_len = len; } switch( parse_state ) { case PARSING_TEXT: delta = copyin( line, space, ptr, len, "\n[%" ); line += delta; ptr += delta; space -= delta; len -= delta; if( !space || !len ) break; /* full line_buff or end of input buffer */ /* zero byte */ if( *ptr == '\0' ) { ptr++; /* skip zero byte */ space -= 1; len -= 1; break; } /* newline */ if( *ptr == '\n' ) { ptr++; /* skip newline */ space -= 1; len -= 1; *line = 0; /* force null terminator */ Syslog( LOG_INFO, "%s", line_buff ); line = line_buff; space = sizeof(line_buff)-1; break; } /* possible kernel symbol */ if( *ptr == '[' ) { *line++ = *ptr++; space -= 1; len -= 1; break; } /* dangerous printf marker */ if( *ptr == '%' ) { delta = 0; while (len && *ptr == '%') { *line++ = *ptr++; /* copy it in */ space -= 1; len -= 1; delta++; } /* odd amount of %'s */ if (delta % 2) { if (space) { *line++ = '%'; /* so simply add one */ space -= 1; } else { *line++ = '\0'; /* remove the last one / terminate the string */ } } } break; /* end of PARSING_TEXT */ case PARSING_SYMSTART: break; case PARSING_SYMBOL: break; case PARSING_SYMEND: break; default: /* Can't get here! */ parse_state = PARSING_TEXT; } } return; } #endif int main( int argc, char ** argv) { int ch; int use_output = 0; char *log_level = NULL; char *output = NULL; fd_set sock_set; struct timeval tv; struct timeval *ptv; int i; char path[MAXPATHLEN]; int ret; #ifdef USE_SYSLOG char *cp; char ident[MINBUF]; #endif chdir ("/"); /* Parse the command-line. */ while ((ch = getopt(argc, argv, "c:df:iIk:nopsvx")) != EOF) { switch((char)ch) { case 'c': /* Set console message level. */ log_level = optarg; break; case 'd': /* Activity debug mode. */ debugging = 1; break; case 'f': /* Define an output file. */ output = optarg; use_output++; break; case 'i': /* Reload module symbols. */ signaldaemon(SIGUSR1); return(0); case 'I': signaldaemon(SIGUSR2); return(0); case 'n': /* don't fork */ no_fork++; break; case 'o': /* One-shot mode. */ one_shot = 1; break; case 'v': printf("gwcklogd %s.%s\n", VERSION, PATCHLEVEL); exit (1); } } #ifdef USE_SYSLOG if ((cp = strrchr(argv[0], '/')) != NULL) cp++; else cp = argv[0]; sprintf(ident, "%s", cp); sysl_open(ident, SYSL_DAEMON); #endif /* * The following code allows klogd to auto-background itself. */ if ( (!one_shot) && (!no_fork) ) { if (!check_pid(PidFile)) { if ( fork() == 0 ) { int fl; int num_fds = getdtablesize(); /* This is the child closing its file descriptors. */ for (fl= 0; fl <= num_fds; ++fl) { if ( fileno(stdout) == fl && use_output ) if ( strcmp(output, "stdout") == 0 ) continue; close(fl); } setsid(); } else { /* bye son */ exit(0); } } else { out ("klogd: Already running.\n"); exit(1); } } /* tuck my process id away */ if (!check_pid(PidFile)) { if (!write_pid(PidFile)) exitprog(); } else { out ("klogd: Already running.\n"); exitprog(); } /* Signal setups. */ for (ch= 1; ch < NSIG; ++ch) { signal(ch, SIG_IGN); } signal(SIGINT, stop_daemon); signal(SIGKILL, stop_daemon); signal(SIGTERM, stop_daemon); signal(SIGHUP, stop_daemon); signal(SIGTSTP, stop_logging); signal(SIGCONT, restart); /* Open outputs. */ if ( strcmp(output, "-") == 0 ) { output_file = stdout; } else if ( (output_file = fopen(output, "w")) == (FILE *) 0 ) { out ("klogd: Cannot open output file %s - %s\n", output, strerror(errno)); return 1; } /* Determine where kernel logging information is to come from. */ for (i = 0; i < MAXSYSIDX; i++) { sprintf (path, "%s/%s", DEV_DIR, klogcmdtab[i].devname); klogcmdtab[i].fd = open (path, O_RDONLY); if (klogcmdtab[i].fd < 0 ) { out ("Failed to open fd[%d] {%s}: %s\n", i, klogcmdtab[i].devname, strerror(errno)); goto exit; } else { if ( sys_blockingmode ( klogcmdtab[i].fd, FALSE) < 0 ) { out ("Failed to make blocking fd[%d] {%s}: %s\n", i, klogcmdtab[i].devname, strerror(errno)); goto exit; } } } /* The main loop. */ while (1) { FD_ZERO(&sock_set); for (i = 0; i < MAXSYSIDX; i++) { FD_SET( klogcmdtab[i].fd, &sock_set); } if ( change_state ) changelog(); tv.tv_sec = GWC_KLOGD_TIMEOUT * 60L; tv.tv_usec = 0; ptv = &tv; ret = select(klogcmdtab [MAXSYSIDX].fd + 1, &sock_set, NULL, NULL, ptv); if ((ret < 0 ) && (errno != EAGAIN)) { out ("select failed: %s\n", strerror(errno)); goto exit; } else if (!ret) { out ("Timeout: continue ...\n"); continue; } else { for (i = 0; i < MAXSYSIDX; i++) { if( FD_ISSET(klogcmdtab[i].fd, &sock_set) ) { ret = klogcmdtab[i].func (NULL); if (ret < 0 ) { out ("Failed to save log : idx:%d, devname:%d fd:%d file:%s\n", i, klogcmdtab[i].devname, klogcmdtab[i].fd, klogcmdtab[i].log_file ); } break; } } } } exit: /* TODO: close syslog */ #ifdef USE_SYSLOG sysl_close(); #endif for (i = 0; i < MAXSYSIDX; i++) { if (klogcmdtab[i].fd > 0 ) { close (klogcmdtab[i].fd); } close (klogcmdtab[i].log_fd); } exit(0); } --- NEW FILE: gwcklogd.h --- /* Title : gwcklogd.h Author : Jeho-Park <de...@sk...> Created date : 2006. 05. 06. (sat) 00:58:44 KST Description : */ #ident "@(#) $Header: /cvsroot/netadm/gwc/gwcklogd/gwcklogd.h,v 1.1 2006/05/06 15:48:47 linuxpark Exp $" #ifndef __SYS_GWCKLOGD_H #define __SYS_GWCKLOGD_H #define VERSION "0.0.1" #define PATCHLEVEL "0" #undef _PATH_KLOG #define _PATH_KLOG "/proc/gwc/syskmsg" #endif /* __SYS_GWCKLOGD_H */ --- NEW FILE: Makefile --- # # Title : Makefile # Author : Jeho-Park <de...@sk...> # Created date : 2006. 05. 05. (Fri) 20:20:20 KST # Description : Makefile for gwcklogd # #ident "@(#) $Header: /cvsroot/netadm/gwc/gwcklogd/Makefile,v 1.1 2006/05/06 15:48:46 linuxpark Exp $" include ../Makefile.tmpl TARGET = gwcklogd OBJECTS = gwcklogd.o all: $(TARGET) $(TARGET): $(OBJECTS) $(CC) -o $@ $(OBJECTS) $(LIBSYS) .c.o: $(CC) $(CFLAGS) $(INCLUDE) -c $< tags: ctags *.c *.h clean: rm -f ${TARGET} *.o depend: $(MAKEDEPEND) -- $(CFLAGS) -- *.c rm -f Makefile.bak # DO NOT DELETE THIS LINE -- make depend depends on it. |