static char sccsid
[] = "@(#)syslogd.c 4.12 (Berkeley) %G%";
* syslogd -- log system messages
* This program implements a system log. It takes a series of lines.
* Each line may have a priority, signified as "<n>" as
* the first characters of the line. If this is
* not present, a default priority is used.
* To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
* cause it to reread its configuration file.
* MAXLINE -- the maximimum line length that can be handled.
* NLOGS -- the maximum number of simultaneous log files.
* NUSERS -- the maximum number of people that can
* be designated as "superusers" on your system.
* DEFUPRI -- the default priority for user messages
* DEFSPRI -- the default priority for kernel messages
* extensive changes by Ralph Campbell
#define NLOGS 10 /* max number of log files */
#define NSUSERS 10 /* max number of special users */
#define MAXLINE 1024 /* maximum line length */
#define DEFUPRI LOG_NOTICE
char logname
[] = "/dev/log";
char defconf
[] = "/etc/syslog.conf";
char defpid
[] = "/etc/syslog.pid";
char ctty
[] = "/dev/console";
#define dprintf if (Debug) printf
#define UNAMESZ 8 /* length of a login name */
#define mask(x) (1 << (x))
* This structure represents the files that will have log
int f_file
; /* file descriptor */
u_int f_pmask
; /* priority mask */
u_int f_flags
; /* see #defines below */
struct sockaddr_in f_addr
; /* forwarding address */
char f_name
[248]; /* filename */
#define F_TTY 001 /* file is a tty */
#define F_MARK 002 /* write to the file periodically */
#define F_FORW 004 /* forward message to another host */
#define F_CONS 010 /* file is the console */
struct filed Files
[NLOGS
];
u_int s_pmask
; /* priority mask */
struct susers Susers
[NSUSERS
];
int Debug
; /* debug flag */
int LogFile
; /* log file descriptor */
u_int Sumask
; /* priorities written to super-users */
int MarkIntvl
= 15; /* mark interval in minutes */
char *ConfFile
= defconf
; /* configuration file */
char host
[32]; /* our hostname */
char rhost
[32]; /* hostname of sender (forwarded messages) */
int inet
= 0; /* non-zero if INET sockets are being used */
int port
; /* port number for INET connections */
u_int Copymask
= 0xffffffff; /* priorities to supress multiple copies */
char prevline
[MAXLINE
+ 1]; /* copy of last line to supress repeats */
char *prevdate
; /* pointer to the date in prevline */
char prevhost
[32]; /* previous host */
int count
= 0; /* number of times seen */
extern int errno
, sys_nerr
;
extern char *sys_errlist
[];
extern char *ctime(), *index();
int funix
, finet
, inetm
, fklog
, klogm
, len
;
struct sockaddr_un sun
, fromunix
;
struct sockaddr_in sin
, frominet
;
char line
[MSG_BSIZE
+ 1];
extern int die(), domark(), reapchild();
sun
.sun_family
= AF_UNIX
;
strncpy(sun
.sun_path
, logname
, sizeof sun
.sun_path
);
gethostname(host
, sizeof host
);
case 'm': /* set mark interval */
case 'f': /* configuration file */
strncpy(sun
.sun_path
, &p
[2],
signal(SIGCHLD
, reapchild
);
funix
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
if (funix
< 0 || bind(funix
, &sun
,
sizeof(sun
.sun_family
)+strlen(sun
.sun_path
)) < 0 ||
chmod(sun
.sun_path
, 0666) < 0) {
fprintf(fp
, "\r\nsyslogd: cannot create %s (%d)\r\n", logname
, errno
);
dprintf("cannot create %s (%d)\n", logname
, errno
);
finet
= socket(AF_INET
, SOCK_DGRAM
, 0);
sp
= getservbyname("syslog", "udp");
logerror("syslog/udp: unknown service");
sin
.sin_family
= AF_INET
;
sin
.sin_port
= port
= sp
->s_port
;
if (bind(finet
, &sin
, sizeof(sin
), 0) < 0) {
if ((fklog
= open("/dev/klog", O_RDONLY
)) >= 0)
dprintf("can't open /dev/klog (%d)\n", errno
);
/* tuck my process id away */
fprintf(fp
, "%d\n", getpid());
dprintf("off & running....\n");
for (i
= 0; i
< NLOGS
; i
++)
int nfds
, readfds
= mask(funix
) | inetm
| klogm
;
dprintf("readfds = %#x\n", readfds
, funix
, finet
, fklog
);
nfds
= select(20, &readfds
, 0, 0, 0);
dprintf("got a message (%d, %#x)\n", nfds
, readfds
);
i
= read(fklog
, line
, sizeof(line
) - 1);
} else if (i
< 0 && errno
!= EINTR
) {
if (readfds
& mask(funix
)) {
i
= recvfrom(funix
, line
, MAXLINE
, 0, &fromunix
, &len
);
} else if (i
< 0 && errno
!= EINTR
)
i
= recvfrom(finet
, line
, MAXLINE
, 0, &frominet
, &len
);
if (i
> 0 && chkhost(&frominet
)) {
} else if (i
< 0 && errno
!= EINTR
)
fprintf(stderr
, "usage: syslogd [-m#] [-d] [-ppath] [-fconffile]\n");
i
= open("/dev/tty", O_RDWR
);
ioctl(i
, TIOCNOTTY
, (char *)0);
* Take a raw input line, decode the message, and print the message
* on the appropriate log files.
/* test for special codes */
pri
= 10 * pri
+ (*p
- '0');
if (pri
<= 0 || pri
>= 32)
while ((c
= *p
++ & 0177) != '\0' && c
!= '\n' &&
q
< &line
[sizeof(line
) - 1]) {
logmsg(pri
, line
, local
? host
: rhost
, 0);
* Take a raw input line from /dev/klog, split and format similar to syslog().
sprintf(line
, "vmunix: %.15s-- ", ctime(&now
) + 4);
lp
= line
+ strlen(line
);
for (p
= msg
; *p
!= '\0'; ) {
flags
= SYNC_FILE
; /* fsync file after write */
pri
= 10 * pri
+ (*p
- '0');
if (pri
<= 0 || pri
>= 32)
/* kernel printf's come out on console */
while (*p
!= '\0' && (c
= *p
++) != '\n' &&
logmsg(pri
, line
, host
, flags
);
* Log a message to the appropriate log files, users, etc. based on
logmsg(pri
, msg
, from
, flags
)
register struct filed
*f
;
register struct iovec
*v
= iov
;
omask
= sigblock(sigmask(SIGALRM
)|sigmask(SIGHUP
));
if ((flags
& NOCOPY
) == 0) {
* Check to see if copies should be supressed or
* msg looks non-standard (e.g., 'prog: Feb 16 13:23:56-- ').
if ((Copymask
& mask(pri
)) == 0 ||
(cp
= index(msg
, ':')) == NULL
|| strlen(cp
) < 20 ||
cp
[5] != ' ' || cp
[8] != ' ' || cp
[11] != ':' ||
cp
[14] != ':' || cp
[17] != '-' || cp
[18] != '-' ||
else if (!strncmp(msg
, prevline
, cp
-msg
) &&
!strcmp(cp
+20, prevdate
+18)) {
/* we found a match, update the time */
strncpy(prevdate
, cp
+2, 15);
(void) sigsetmask(omask
);
prevdate
= prevline
+ (cp
- msg
) + 2;
v
->iov_len
= strlen(v
->iov_base
);
v
->iov_len
= strlen(v
->iov_base
);
/* log the message to the particular outputs */
for (f
= Files
; f
< &Files
[NLOGS
]; f
++) {
if (flags
& ISMARK
) { /* mark message */
if (!(f
->f_flags
& F_MARK
))
if (!(f
->f_flags
& F_CONS
)) {
if (fstat(f
->f_file
, &stb
) < 0)
if (stb
.st_mtime
> now
- MarkIntvl
* 60)
} else if ((f
->f_pmask
& mask(pri
)) == 0 ||
(flags
& IGN_CONS
) && (f
->f_flags
& F_CONS
))
if (f
->f_flags
& F_FORW
) {
sprintf(line
, "<%d>%s", pri
, msg
);
if (sendto(f
->f_file
, line
, l
, 0,
&f
->f_addr
, sizeof f
->f_addr
) != l
) {
if (f
->f_flags
& F_TTY
) {
if (writev(f
->f_file
, iov
, 4) < 0) {
* Check for EBADF on the console due to vhangup() XXX
if (e
== EBADF
&& (f
->f_flags
& F_TTY
)) {
f
->f_file
= open(f
->f_name
, O_WRONLY
|O_APPEND
);
} else if (flags
& SYNC_FILE
)
* Output high priority messages to terminals.
if (!(flags
& ISMARK
) && (mask(pri
) & Sumask
))
(void) sigsetmask(omask
);
* INIT -- Initialize syslogd from configuration table
* The configuration table consists of a series of lines broken
* into two sections by a blank line. The first section gives a
* list of files to log on. Each line begins with a
* comma-separated list of digits or ranges of digits (pairs of
* digits separated by a dash); if the priority of a message falls
* in the set of digits defined by this list, then the message is
* logged in the file corresponding to this line. If the
* following character is an asterisk, then syslogd arranges for
* something to be printed every fifteen minutes (even if only a
* null line), so that crashes and other events can be localized.
* The rest of the line is the pathname of the log file. The
* second section is a list of user names; these people are all
* notified when subalert messages occur (if they are logged on).
* These lines may also have associated priority lists.
* The configuration table will be reread by this routine if a
* SIGHUP signal occurs; for that reason, it is tricky about not
* re-opening files and closing files it will not be using.
register struct filed
*f
;
/* flush any pending output */
* Close all open log files.
for (f
= Files
; f
< &Files
[NLOGS
]; f
++) {
/* open the configuration file */
if ((cf
= fopen(ConfFile
, "r")) == NULL
) {
dprintf("cannot open %s\n", ConfFile
);
if ((f
->f_file
= open(ctty
, O_WRONLY
)) >= 0) {
strncpy(f
->f_name
, ctty
, sizeof(f
->f_name
)-1);
f
->f_pmask
= mask(LOG_CRIT
);
f
->f_flags
= F_TTY
|F_MARK
|F_CONS
;
* Foreach line in the conf table, open that file.
while (fgets(cline
, sizeof cline
, cf
) != NULL
) {
/* check for end-of-section */
/* strip off newline character */
dprintf("F: got line '%s'\n", cline
);
/* extract priority mask and mark flag */
/* mark entry as used and update flags */
sprintf(buf
, "unknown host %s", p
);
bzero(&f
->f_addr
, sizeof f
->f_addr
);
f
->f_addr
.sin_family
= AF_INET
;
f
->f_addr
.sin_port
= port
;
bcopy(hp
->h_addr
, (char *) &f
->f_addr
.sin_addr
, hp
->h_length
);
f
->f_file
= socket(AF_INET
, SOCK_DGRAM
, 0);
dprintf("Host %s pmask %#x flags %#x\n", p
, pmask
, flags
);
strncpy(f
->f_name
, p
, sizeof(f
->f_name
)-1);
if ((f
->f_file
= open(p
, O_WRONLY
|O_APPEND
)) < 0) {
if (strcmp(p
, ctty
) == 0)
dprintf("File %s pmask %#x flags %#x\n", p
, pmask
, flags
);
* Read the list of users.
* Anyone in this list is informed directly if s/he
* is logged in when a high priority message comes through.
Sumask
= mask(KERN_EMERG
)|mask(LOG_EMERG
);
for (i
= 0; i
< NSUSERS
&& fgets(cline
, sizeof cline
, cf
) != NULL
; i
++) {
dprintf("U: got line '%s'\n", cline
);
pmask
= mask(LOG_SALERT
);
Susers
[i
].s_pmask
= pmask
;
strncpy(Susers
[i
].s_name
, p
, UNAMESZ
);
dprintf("Suser %s pmask %#x\n", p
, pmask
);
/* zero the rest of the old superusers */
Susers
[i
++].s_name
[0] = '\0';
/* close the configuration file */
dprintf("syslogd: restarted\n");
* WALLMSG -- Write a message to the world at large
* Write the specified message to either the entire
* world, or a list of approved users.
char line
[MAXLINE
+ 100];
/* open the user login file */
if ((uf
= fopen("/etc/utmp", "r")) == NULL
) {
"\r\n\7Message from syslogd@%s at %.24s ...\r\n%s\r\n",
/* scan the user login file */
while (fread(&ut
, sizeof ut
, 1, uf
) == 1) {
if (ut
.ut_name
[0] == '\0')
/* should we send the message to this user? */
for (i
= 0; i
< NSUSERS
; i
++) {
if ((mask(pri
) & Susers
[i
].s_pmask
) == 0)
if (strncmp(Susers
[i
].s_name
, ut
.ut_name
,
/* compute the device name */
strcpyn(&p
[5], ut
.ut_line
, UNAMESZ
);
* Might as well fork instead of using nonblocking I/O
signal(SIGALRM
, SIG_DFL
);
(void) write(f
, line
, len
);
/* close the user login file */
while (wait3(&status
, WNOHANG
, 0) > 0)
* Make sure every marked file gets written to periodically.
* Reset the alarm clock to call itself after MarkIntvl minutes.
sprintf(buf
, "syslogd: %.24s-- MARK", ctime(&now
));
logmsg(0, buf
, host
, NOCOPY
|ISMARK
);
* Check to see if we should log this message.
extern char *inet_ntoa();
if (f
->sin_family
!= AF_INET
) {
dprintf("Malformed from address\n");
hp
= gethostbyaddr(&f
->sin_addr
, sizeof(struct in_addr
), f
->sin_family
);
dprintf("Host name for your address (%s) unknown\n",
strncpy(rhost
, hp
->h_name
, sizeof rhost
);
sprintf(prevdate
+18, "last message repeated %d times", count
);
logmsg(prevpri
, prevline
, prevhost
, prevflags
|NOCOPY
);
* Print syslogd errors some place.
sprintf(buf
, "syslogd: %.24s-- %s", ctime(&now
), type
);
else if ((unsigned) errno
> sys_nerr
)
sprintf(buf
, "syslogd: %.24s-- %s: error %d",
ctime(&now
), type
, errno
);
sprintf(buf
, "syslogd: %.24s-- %s: %s",
ctime(&now
), type
, sys_errlist
[errno
]);
logmsg(LOG_ERR
, buf
, host
, 0);
dprintf("syslogd: going down\n");
* getpmask() parses a string cp looking for a set of numbers like
* '1-5,8,16' and returns in *ppmask the set of bits represented by
* these numbers. A notation '1-5' is interpreted to mean 'turn on
* bits 1 through 5 inclusive'. getpmask() returns the address of
* first byte after the number set.
count1
= 10 * count1
+ (*cp
++ - '0');
count2
= 10 * count2
+ (*cp
- '0');
for (i
= count1
; i
<= count2
; ++i
)