?? log.c
字號:
/* * @(#) log.c RCS: $Revision: 1.6 $ $Date: 95/03/08 15:54:50 $ * * Logging facility * * #define _USE_SYSLOG if you want to use logging via a socket to syslogd * instead of logging to a file. I don't trust syslog's socket to be secure, * so I don't use syslog; Your needs may be different. Also, syslog does * a fork(), making life even more complex. */#define _POSIX_SOURCE#include <unistd.h> /* close write _exit */#include <stdlib.h> /* atexit */#include <stdio.h>#include <sys/types.h>#include <sys/stat.h> /* S_IRUSR S_IWUSR */#include <fcntl.h> /* O_RDWR */#include <string.h> /* strerror strlen for braindamaged vsprintf */#include <errno.h> /* errno */#include <time.h> /* time() localtime() strftime() struct tms */#include <sys/utsname.h> /* uname() struct utsname */#if defined(_USE_SYSLOG)#include <syslog.h>#endif#include "log.h"#if (defined(sparc) || defined(sun3)) && !defined(__SOLARIS__)#define atexit on_exit#endif#define SYSLOG_FD 32767 /* run-time value to enable syslog */#define LOGBUFSIZ BUFSIZ /* POSIX2 may have a better value */static int logFd = 2; /* stderr */static char logBuf[LOGBUFSIZ];static int logOpen = 0; /* non-zero if openLog has ever been successful */static char *syslogId = ""; /* long-lived storage */extern char *progName;/* * Close the log file if it's open. Don't do anything if openLog has * never been called. Shut down syslog if it was a syslog connection. */void closeLog() { if (logOpen) { /* only close a log if it is open */ if (logFd == SYSLOG_FD) {#if defined(_USE_SYSLOG) /* to allow machines w/o syslog */ closelog();#endif logFd = -1; } if (logFd >= 0) { close(logFd); } logFd = -1; logOpen = 0; }}/* * Open the specified log file. If the open fails, the existing logfile * remains unchanged; if called multiple times on same log, works correctly. * the log() function acts like fprintf(stderr,...) until the first successful * call to openLog(), after which it formats like syslog(). */int openLog(fname) char *fname;{ register int newlog = SYSLOG_FD; /* default is success */#if defined(_USE_SYSLOG) if (logFd != SYSLOG_FD) { /* I don't trust syslog to reopen OK */#if !defined(__bsdi__) && !defined(linux) /* * Return value is not documented in BSD brick. * * BSD is braindamaged: How do you detect failure? it can definitely fail * (It often forks and opens a TCP socket to a remote machine.) * God only knows what BSD does if you call openlog twice; do you? * If so, please send mail to the author, so I can fix this code properly. * If your host is one of the ones that does't return a result, add * "|| !defined(__mymachine) above and add a -D__mymachine to CFLAGS. * * The following machines do have a return value for syslog: * HP-UX * DEC Alpha OSF1 * * I've been told that BSDI's BSD/386 doesn't. */ newlog = #endif openlog(syslogId, LOG_NDELAY|LOG_NOWAIT, LOG_AUTH); /* * We must open the log connection immediately (NDELAY) so that we don't * use file descriptors 0,1, or 2 for the log connection fd. */ if (newlog >= 0) { newlog = SYSLOG_FD; /* a value to signal syslog is being used */ } }#else newlog = open(fname, O_CREAT|O_APPEND|O_WRONLY|O_NOCTTY, S_IRUSR|S_IWUSR);#endif if (newlog < 0) { return -1; } if (logFd != SYSLOG_FD) { closeLog(); } logFd = newlog; logOpen = 1; newlog = atexit(closeLog); /* close log file upon exit */ return 0;}/* * Get the local host name (not the domain name!) * * A bombproof version of BSD's gethostname, which always succeeds and * has a sensible return value. * * returns in the array hostName the '\0' terminated name of the local host. * The size argument specifies space (in bytes) available. * Returns the number of characters stored not including the '\0'. * If the host cannot be determined, 0 is returned. * The array returned is always '\0'-terminated except if size is 0. * Only the characters before the first dot '.' character are returned. * * Returns: the number of characters stored (not including the final '\0'); */static size_t getHostName(hostName, size) register char *hostName; register size_t size;{ struct utsname hstats; register char *chp; int res; register size_t i = 0; res = uname(&hstats); if ((res >= 0) && size) { chp = hstats.nodename; --size; if (size) do { if ((*chp == '.') || (*chp == '\0')) { break; } *hostName++ = *chp++; i++; } while (--size); *hostName = '\0'; } return i;}#if !defined(__STDC__) /* { */#include <varargs.h>void log(va_alist) va_dcl#else /* } { */#include <stdarg.h>#if defined(__STDC__) || defined(__cplusplus) /* { */void log(char *fmt, ...) #else /* } { */void log(fmt) char *fmt;#endif /* } */#endif /* } */{ size_t count = 0; int ok = 1; char *chp = logBuf; time_t now = time((time_t *)0); va_list args;#if !defined(__STDC__) /* { */ char *fmt; va_start(args); fmt = va_arg(args, char *);#else /* } { */ va_start(args , fmt);#endif /* } */ if (logFd != -1) { /* do nothing if log fd not valid */ if (logOpen && (logFd != SYSLOG_FD)) { /* * Prepend the date time, and hostname like syslog does. */ /* strftime is in <time.h> for ANSI C */ count = strftime(chp, 64, "%b %d %H:%M:%S ", localtime(&now)); chp += count; count = getHostName(chp, 64); chp += count; if (count != 0) { *chp++ = ' '; *chp = '\0'; } if (chp != logBuf) { *chp++ = ':'; *chp++ = ' '; *chp = '\0'; } } count = vsprintf(chp, fmt, args); /* * If you get a compiler warning on the vsprintf line stating * pointer to int conversion, you're in big trouble. This * attempts to "fix" the braindamage. * * ANSI C states vsprintf returns the character count. * Some BSD machines (even when compiled with ANSI compilers!) * return a pointer to the first argument instead. */ if (((char *) count) == chp) { while (*chp != '\0') { chp++; } } else { chp += count; } count = chp - &logBuf[0]; if (count > 0) { /* if log message not empty */ /* * This is a kludge for now. Posix 2 has a constant LINE_MAX which * may solve this problem. Unfortunately, I don't have a copy of * the posix 2 standard. */ if (count > LOGBUFSIZ) { count = 37; /* length of message below + 1 for the '\0' */ memcpy(logBuf, "PANIC! log.c:log() buffer overflow!\n", count); ok = 0; } if (logFd == SYSLOG_FD) {#if defined(_USE_SYSLOG) syslog(LOG_INFO, "%-.*s", count, logBuf);#endif } else { /* Use write here instead of stdio to make atomic updates */ write(logFd, logBuf, count); } if (!ok) { closeLog(); _exit(1); } } } va_end(args);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -