📄 syslogd.c
字号:
#include <arpa/inet.h>#include <resolv.h>#ifndef TESTING#include "pidfile.h"#endif#include "version.h"#if defined(__linux__)#include <paths.h>#endif#ifndef UTMP_FILE#ifdef UTMP_FILENAME#define UTMP_FILE UTMP_FILENAME#else#ifdef _PATH_UTMP#define UTMP_FILE _PATH_UTMP#else#define UTMP_FILE "/etc/utmp"#endif#endif#endif#ifndef _PATH_LOGCONF #define _PATH_LOGCONF "/etc/syslog.conf"#endif#if defined(SYSLOGD_PIDNAME)#undef _PATH_LOGPID#if defined(FSSTND)#define _PATH_LOGPID _PATH_VARRUN SYSLOGD_PIDNAME#else#define _PATH_LOGPID "/etc/" SYSLOGD_PIDNAME#endif#else#ifndef _PATH_LOGPID#if defined(FSSTND)#define _PATH_LOGPID _PATH_VARRUN "syslogd.pid"#else#define _PATH_LOGPID "/etc/syslogd.pid"#endif#endif#endif#ifndef _PATH_DEV#define _PATH_DEV "/dev/"#endif#ifndef _PATH_CONSOLE#define _PATH_CONSOLE "/dev/console"#endif#ifndef _PATH_TTY#define _PATH_TTY "/dev/tty"#endif#ifndef _PATH_LOG#define _PATH_LOG "/dev/log"#endifchar *ConfFile = _PATH_LOGCONF;char *PidFile = _PATH_LOGPID;char ctty[] = _PATH_CONSOLE;char **parts;int inetm = 0;static int debugging_on = 0;static int nlogs = -1;static int restart = 0;#define MAXFUNIX 20int nfunix = 1;char *funixn[MAXFUNIX] = { _PATH_LOG };int funix[MAXFUNIX] = { -1, };#ifdef UT_NAMESIZE# define UNAMESZ UT_NAMESIZE /* length of a login name */#else# define UNAMESZ 8 /* length of a login name */#endif#define MAXUNAMES 20 /* maximum number of user names */#define MAXFNAME 200 /* max file pathname length */#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */#define TABLE_NOPRI 0 /* Value to indicate no priority in f_pmask */#define TABLE_ALLPRI 0xFF /* Value to indicate all priorities in f_pmask */#define LOG_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" *//* * Flags to logmsg(). */#define IGN_CONS 0x001 /* don't print on console */#define SYNC_FILE 0x002 /* do fsync on file after printing */#define ADDDATE 0x004 /* add a date to the message */#define MARK 0x008 /* this message is a mark *//* * This table contains plain text for h_errno errors used by the * net subsystem. */const char *sys_h_errlist[] = { "No problem", /* NETDB_SUCCESS */ "Authoritative answer: host not found", /* HOST_NOT_FOUND */ "Non-authoritative answer: host not found, or serverfail", /* TRY_AGAIN */ "Non recoverable errors", /* NO_RECOVERY */ "Valid name, no data record of requested type", /* NO_DATA */ "no address, look for MX record" /* NO_ADDRESS */ };/* * This structure represents the files that will have log * copies printed. */struct filed {#ifndef SYSV struct filed *f_next; /* next in linked list */#endif short f_type; /* entry type, see below */ short f_file; /* file descriptor */ time_t f_time; /* time this was last written */ u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ union { char f_uname[MAXUNAMES][UNAMESZ+1]; struct { char f_hname[MAXHOSTNAMELEN+1]; struct sockaddr_in f_addr; } f_forw; /* forwarding address */ char f_fname[MAXFNAME]; } f_un; char f_prevline[MAXSVLINE]; /* last message logged */ char f_lasttime[16]; /* time of last occurrence */ char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ int f_prevpri; /* pri of f_prevline */ int f_prevlen; /* length of f_prevline */ int f_prevcount; /* repetition cnt of prevline */ int f_repeatcount; /* number of "repeated" msgs */ int f_flags; /* store some additional flags */};/* * Intervals at which we flush out "message repeated" messages, * in seconds after previous message is logged. After each flush, * we move to the next interval until we reach the largest. */int repeatinterval[] = { 30, 60 }; /* # of secs before flush */#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount])#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ (f)->f_repeatcount = MAXREPEAT; \ }#ifdef SYSLOG_INET#define INET_SUSPEND_TIME 180 /* equal to 3 minutes */#define INET_RETRY_MAX 10 /* maximum of retries for gethostbyname() */#endif#define LIST_DELIMITER ':' /* delimiter between two hosts *//* values for f_type */#define F_UNUSED 0 /* unused entry */#define F_FILE 1 /* regular file */#define F_TTY 2 /* terminal */#define F_CONSOLE 3 /* console terminal */#define F_FORW 4 /* remote machine */#define F_USERS 5 /* list of users */#define F_WALL 6 /* everyone logged on */#define F_FORW_SUSP 7 /* suspended host forwarding */#define F_FORW_UNKN 8 /* unknown host forwarding */#define F_PIPE 9 /* named pipe */char *TypeNames[] = { "UNUSED", "FILE", "TTY", "CONSOLE", "FORW", "USERS", "WALL", "FORW(SUSPENDED)", "FORW(UNKNOWN)", "PIPE"};struct filed *Files = (struct filed *) 0;struct filed consfile;struct code { char *c_name; int c_val;};struct code PriNames[] = { {"alert", LOG_ALERT}, {"crit", LOG_CRIT}, {"debug", LOG_DEBUG}, {"emerg", LOG_EMERG}, {"err", LOG_ERR}, {"error", LOG_ERR}, /* DEPRECATED */ {"info", LOG_INFO}, {"none", INTERNAL_NOPRI}, /* INTERNAL */ {"notice", LOG_NOTICE}, {"panic", LOG_EMERG}, /* DEPRECATED */ {"warn", LOG_WARNING}, /* DEPRECATED */ {"warning", LOG_WARNING}, {"*", TABLE_ALLPRI}, {NULL, -1}};struct code FacNames[] = { {"auth", LOG_AUTH}, {"authpriv", LOG_AUTHPRIV}, {"cron", LOG_CRON}, {"daemon", LOG_DAEMON}, {"kern", LOG_KERN}, {"lpr", LOG_LPR}, {"mail", LOG_MAIL}, {"mark", LOG_MARK}, /* INTERNAL */ {"news", LOG_NEWS}, {"security", LOG_AUTH}, /* DEPRECATED */ {"syslog", LOG_SYSLOG}, {"user", LOG_USER}, {"uucp", LOG_UUCP},#if defined(LOG_FTP) {"ftp", LOG_FTP},#endif {"local0", LOG_LOCAL0}, {"local1", LOG_LOCAL1}, {"local2", LOG_LOCAL2}, {"local3", LOG_LOCAL3}, {"local4", LOG_LOCAL4}, {"local5", LOG_LOCAL5}, {"local6", LOG_LOCAL6}, {"local7", LOG_LOCAL7}, {NULL, -1},};int Debug; /* debug flag */char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */char *LocalDomain; /* our local domain name */int InetInuse = 0; /* non-zero if INET sockets are being used */int finet = -1; /* Internet datagram socket */int LogPort; /* port number for INET connections */int Initialized = 0; /* set when we have initialized ourselves */int MarkInterval = 20 * 60; /* interval between marks in seconds */int MarkSeq = 0; /* mark sequence number */int NoFork = 0; /* don't fork - don't run in daemon mode */int AcceptRemote = 0; /* receive messages that come via UDP */char **StripDomains = NULL; /* these domains may be stripped before writing logs */char **LocalHosts = NULL; /* these hosts are logged with their hostname */int NoHops = 1; /* Can we bounce syslog messages through an intermediate host. */extern int errno;/* Function prototypes. */int main(int argc, char **argv);char **crunch_list(char *list);int usage(void);void untty(void);void printchopped(const char *hname, char *msg, int len, int fd);void printline(const char *hname, char *msg);void printsys(char *msg);void logmsg(int pri, char *msg, const char *from, int flags);void fprintlog(register struct filed *f, char *from, int flags, char *msg);void endtty();void wallmsg(register struct filed *f, struct iovec *iov);void reapchild();const char *cvthname(struct sockaddr_in *f);void domark();void debug_switch();void logerror(char *type);void die(int sig);#ifndef TESTINGvoid doexit(int sig);#endifvoid init();void cfline(char *line, register struct filed *f);int decode(char *name, struct code *codetab);#if defined(__GLIBC__)#define dprintf mydprintf#endif /* __GLIBC__ */static void dprintf(char *, ...);static void allocate_log(void);void sighup_handler();#ifdef SYSLOG_UNIXAFstatic int create_unix_socket(const char *path);#endif#ifdef SYSLOG_INETstatic int create_inet_socket();#endifint main(argc, argv) int argc; char **argv;{ register int i; register char *p;#if !defined(__GLIBC__) int len, num_fds;#else /* __GLIBC__ */#ifndef TESTING size_t len;#endif int num_fds;#endif /* __GLIBC__ */ /* * It took me quite some time to figure out how this is * supposed to work so I guess I should better write it down. * unixm is a list of file descriptors from which one can * read(). This is in contrary to readfds which is a list of * file descriptors where activity is monitored by select() * and from which one cannot read(). -Joey * * Changed: unixm is gone, since we now use datagram unix sockets. * Hence we recv() from unix sockets directly (rather than * first accept()ing connections on them), so there's no need * for separate book-keeping. --okir */ fd_set readfds;#ifndef TESTING int fd;#ifdef SYSLOG_INET struct sockaddr_in frominet; char *from;#endif pid_t ppid = getpid();#endif int ch; struct hostent *hent; char line[MAXLINE +1]; extern int optind; extern char *optarg; int maxfds;#ifndef TESTING chdir ("/");#endif for (i = 1; i < MAXFUNIX; i++) { funixn[i] = ""; funix[i] = -1; } while ((ch = getopt(argc, argv, "a:dhf:l:m:np:rs:v")) != EOF) switch((char)ch) { case 'a': if (nfunix < MAXFUNIX) funixn[nfunix++] = optarg; else fprintf(stderr, "Out of descriptors, ignoring %s\n", optarg); break; case 'd': /* debug */ Debug = 1; break; case 'f': /* configuration file */ ConfFile = optarg; break; case 'h': NoHops = 0; break; case 'l': if (LocalHosts) { fprintf (stderr, "Only one -l argument allowed," \ "the first one is taken.\n"); break; } LocalHosts = crunch_list(optarg); break; case 'm': /* mark interval */ MarkInterval = atoi(optarg) * 60; break; case 'n': /* don't fork */ NoFork = 1; break; case 'p': /* path to regular log socket */ funixn[0] = optarg; break; case 'r': /* accept remote messages */ AcceptRemote = 1; break; case 's': if (StripDomains) { fprintf (stderr, "Only one -s argument allowed," \ "the first one is taken.\n"); break; } StripDomains = crunch_list(optarg); break; case 'v': printf("syslogd %s.%s\n", VERSION, PATCHLEVEL); exit (0); case '?': default: usage(); } if ((argc -= optind)) usage();#ifndef TESTING if ( !(Debug || NoFork) ) { dprintf("Checking pidfile.\n"); if (!check_pid(PidFile)) { if (fork()) { /* * Parent process */ signal (SIGTERM, doexit); sleep(300); /* * Not reached unless something major went wrong. 5 * minutes should be a fair amount of time to wait. * Please note that this procedure is important since * the father must not exit before syslogd isn't * initialized or the klogd won't be able to flush its * logs. -Joey */ exit(1); } num_fds = getdtablesize(); for (i= 0; i < num_fds; i++) (void) close(i); untty(); } else { fputs("syslogd: Already running.\n", stderr); exit(1); } } else#endif debugging_on = 1;#ifndef SYSV else setlinebuf(stdout);#endif#ifndef TESTING /* tuck my process id away */ if ( !Debug ) { dprintf("Writing pidfile.\n"); if (!check_pid(PidFile)) { if (!write_pid(PidFile)) { dprintf("Can't write pid.\n"); exit(1); } } else { dprintf("Pidfile (and pid) already exist.\n"); exit(1); } } /* if ( !Debug ) */#endif consfile.f_type = F_CONSOLE; (void) strcpy(consfile.f_un.f_fname, ctty); (void) gethostname(LocalHostName, sizeof(LocalHostName)); if ( (p = strchr(LocalHostName, '.')) ) { *p++ = '\0'; LocalDomain = p; } else { LocalDomain = ""; /* * It's not clearly defined whether gethostname() * should return the simple hostname or the fqdn. A * good piece of software should be aware of both and * we want to distribute good software. Joey * * Good software also always checks its return values... * If syslogd starts up before DNS is up & /etc/hosts * doesn't have LocalHostName listed, gethostbyname will * return NULL. */ hent = gethostbyname(LocalHostName); if ( hent ) snprintf(LocalHostName, sizeof(LocalHostName), "%s", hent->h_name); if ( (p = strchr(LocalHostName, '.')) ) { *p++ = '\0'; LocalDomain = p; } } /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -