2 * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "syslog_output.h"
16 #include <FindDirectory.h>
18 #include <driver_settings.h>
21 static const char *kFacilities
[] = {
22 "KERN", "USER", "MAIL", "DAEMON",
23 "AUTH", "SYSLOGD", "LPR", "NEWS",
24 "UUCP", "CRON", "AUTHPRIV", "FTP",
26 "LOCAL0", "LOCAL1", "LOCAL2", "LOCAL3",
27 "LOCAL4", "LOCAL5", "LOCAL6", "LOCAL7",
30 static const int32 kNumFacilities
= 24;
33 static char sLastMessage
[1024];
34 static thread_id sLastThread
;
35 static int32 sRepeatCount
;
36 static size_t sLogMaxSize
= 524288; // 512kB
37 static bool sLogTimeStamps
= false;
40 /*! Creates the log file if not yet existing, or renames the old
41 log file, if it's too big already.
47 bool tooLarge
= false;
52 if (fstat(sLog
, &stat
) == 0) {
53 if (stat
.st_size
< (off_t
)sLogMaxSize
)
61 // close old file; it'll be (re)moved soon
65 // get path (and create it if necessary)
67 find_directory(B_SYSTEM_LOG_DIRECTORY
, &base
, true);
70 syslog
.Append("syslog");
72 // move old file if it already exists
75 oldlog
.Append("syslog.old");
77 remove(oldlog
.Path());
78 rename(syslog
.Path(), oldlog
.Path());
80 // ToDo: just remove old file if space on device is tight?
83 bool haveSyslog
= sLog
>= 0;
86 sLog
= open(syslog
.Path(), O_APPEND
| O_CREAT
| O_WRONLY
, 0644);
87 if (!haveSyslog
&& sLog
>= 0) {
88 // first time open, check file size again
93 return sLog
>= 0 ? B_OK
: B_ERROR
;
98 write_to_log(const char *buffer
, int32 length
)
100 if (sRepeatCount
> 0) {
102 ssize_t size
= snprintf(repeat
, sizeof(repeat
),
103 "Last message repeated %" B_PRId32
" time%s\n", sRepeatCount
,
104 sRepeatCount
> 1 ? "s" : "");
106 if (write(sLog
, repeat
, strlen(repeat
)) < size
)
110 if (write(sLog
, buffer
, length
) < length
)
118 syslog_output(syslog_message
&message
)
124 if (sLogTimeStamps
) {
125 // parse & nicely print the time stamp from the message
127 localtime_r(&message
.when
, &when
);
128 pos
= strftime(header
, sizeof(header
), "%Y-%m-%d %H:%M:%S ", &when
);
132 int facility
= SYSLOG_FACILITY_INDEX(message
.priority
);
133 if (facility
>= kNumFacilities
)
134 facility
= SYSLOG_FACILITY_INDEX(LOG_USER
);
135 pos
+= snprintf(header
+ pos
, sizeof(header
) - pos
, "%s",
136 kFacilities
[facility
]);
138 // add ident/thread ID
139 if (message
.ident
[0] == '\0') {
140 // ToDo: find out team name?
142 pos
+= snprintf(header
+ pos
, sizeof(header
) - pos
, " '%s'",
146 if ((message
.options
& LOG_PID
) != 0) {
147 pos
+= snprintf(header
+ pos
, sizeof(header
) - pos
, "[%" B_PRId32
"]",
151 headerLength
= pos
+ strlcpy(header
+ pos
, ": ", sizeof(header
) - pos
);
152 if (headerLength
>= (int32
)sizeof(header
))
153 headerLength
= sizeof(header
) - 1;
155 // add header to every line of the message and write it to the syslog
157 char buffer
[SYSLOG_MESSAGE_BUFFER_SIZE
];
161 strcpy(buffer
, header
);
164 const char *newLine
= strchr(message
.message
+ pos
, '\n');
165 if (newLine
!= NULL
) {
166 length
= newLine
- message
.message
+ 1 - pos
;
167 strlcpy(buffer
+ headerLength
, message
.message
+ pos
, length
+ 1);
170 length
= strlcpy(buffer
+ headerLength
, message
.message
+ pos
,
171 sizeof(buffer
) - headerLength
);
176 length
+= headerLength
;
178 if (length
>= (int32
)sizeof(buffer
))
179 length
= sizeof(buffer
) - 1;
181 if (message
.from
== sLastThread
182 && !strncmp(buffer
+ headerLength
, sLastMessage
,
183 sizeof(sLastMessage
))) {
184 // we got this message already
189 if (prepare_output() < B_OK
190 || write_to_log(buffer
, length
) < B_OK
) {
191 // cannot write to syslog!
195 // save this message to suppress repeated messages
196 strlcpy(sLastMessage
, buffer
+ headerLength
, sizeof(sLastMessage
));
197 sLastThread
= message
.from
;
200 if (newLine
== NULL
|| !newLine
[1]) {
201 // wrote last line of output
209 init_syslog_output(SyslogDaemon
*daemon
)
213 // get kernel syslog settings
214 handle
= load_driver_settings("kernel");
215 if (handle
!= NULL
) {
216 sLogTimeStamps
= get_driver_boolean_parameter(handle
,
217 "syslog_time_stamps", false, false);
218 const char *param
= get_driver_parameter(handle
,
219 "syslog_max_size", "0", "0");
220 int maxSize
= strtol(param
, NULL
, 0);
221 if (strchr(param
, 'k') || strchr(param
, 'K'))
223 else if (strchr(param
, 'm') || strchr(param
, 'M'))
226 sLogMaxSize
= maxSize
;
228 unload_driver_settings(handle
);
231 daemon
->AddHandler(syslog_output
);