blob: cd16279dc5aae27b1c8c84f8dca9ca54eb19735b [file] [log] [blame]
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001/* dnsmasq is Copyright (c) 2000-2024 Simon Kelley
Simon Kelleyf2621c72007-04-29 19:47:21 +01002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelleyf2621c72007-04-29 19:47:21 +01008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelleyf2621c72007-04-29 19:47:21 +010015*/
16
17#include "dnsmasq.h"
18
Simon Kelley572b41e2011-02-18 18:11:18 +000019#ifdef __ANDROID__
20# include <android/log.h>
21#endif
22
Simon Kelleyf2621c72007-04-29 19:47:21 +010023/* Implement logging to /dev/log asynchronously. If syslogd is
24 making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
25 syslogd, then the two daemons can deadlock. We get around this
26 by not blocking when talking to syslog, instead we queue up to
27 MAX_LOGS messages. If more are queued, they will be dropped,
28 and the drop event itself logged. */
29
30/* The "wire" protocol for logging is defined in RFC 3164 */
31
32/* From RFC 3164 */
33#define MAX_MESSAGE 1024
34
35/* defaults in case we die() before we log_start() */
36static int log_fac = LOG_DAEMON;
Simon Kelley8ef5ada2010-06-03 19:42:45 +010037static int log_stderr = 0;
38static int echo_stderr = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +010039static int log_fd = -1;
40static int log_to_file = 0;
41static int entries_alloced = 0;
42static int entries_lost = 0;
43static int connection_good = 1;
44static int max_logs = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +010045static int connection_type = SOCK_DGRAM;
Simon Kelleyf2621c72007-04-29 19:47:21 +010046
47struct log_entry {
48 int offset, length;
Simon Kelley5aabfc72007-08-29 11:24:47 +010049 pid_t pid; /* to avoid duplicates over a fork */
Simon Kelleyf2621c72007-04-29 19:47:21 +010050 struct log_entry *next;
51 char payload[MAX_MESSAGE];
52};
53
54static struct log_entry *entries = NULL;
55static struct log_entry *free_entries = NULL;
56
57
Simon Kelley1a6bca82008-07-11 11:11:42 +010058int log_start(struct passwd *ent_pw, int errfd)
Simon Kelleyf2621c72007-04-29 19:47:21 +010059{
Simon Kelley1a6bca82008-07-11 11:11:42 +010060 int ret = 0;
61
Simon Kelley28866e92011-02-14 20:19:14 +000062 echo_stderr = option_bool(OPT_DEBUG);
Simon Kelleyf2621c72007-04-29 19:47:21 +010063
64 if (daemon->log_fac != -1)
65 log_fac = daemon->log_fac;
66#ifdef LOG_LOCAL0
Simon Kelley28866e92011-02-14 20:19:14 +000067 else if (option_bool(OPT_DEBUG))
Simon Kelleyf2621c72007-04-29 19:47:21 +010068 log_fac = LOG_LOCAL0;
69#endif
70
71 if (daemon->log_file)
Simon Kelley5aabfc72007-08-29 11:24:47 +010072 {
Simon Kelleyf2621c72007-04-29 19:47:21 +010073 log_to_file = 1;
74 daemon->max_logs = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +010075 if (strcmp(daemon->log_file, "-") == 0)
76 {
77 log_stderr = 1;
78 echo_stderr = 0;
79 log_fd = dup(STDERR_FILENO);
80 }
Simon Kelleyf2621c72007-04-29 19:47:21 +010081 }
Simon Kelleyf2621c72007-04-29 19:47:21 +010082
Simon Kelley5aabfc72007-08-29 11:24:47 +010083 max_logs = daemon->max_logs;
84
85 if (!log_reopen(daemon->log_file))
Simon Kelley1a6bca82008-07-11 11:11:42 +010086 {
Simon Kelleyc72daea2012-01-05 21:33:27 +000087 send_event(errfd, EVENT_LOG_ERR, errno, daemon->log_file ? daemon->log_file : "");
Simon Kelley1a6bca82008-07-11 11:11:42 +010088 _exit(0);
89 }
90
Simon Kelleyf2621c72007-04-29 19:47:21 +010091 /* if queuing is inhibited, make sure we allocate
92 the one required buffer now. */
Simon Kelley5aabfc72007-08-29 11:24:47 +010093 if (max_logs == 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +010094 {
95 free_entries = safe_malloc(sizeof(struct log_entry));
96 free_entries->next = NULL;
97 entries_alloced = 1;
98 }
Simon Kelley824af852008-02-12 20:43:05 +000099
100 /* If we're running as root and going to change uid later,
101 change the ownership here so that the file is always owned by
102 the dnsmasq user. Then logrotate can just copy the owner.
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700103 Failure of the chown call is OK, (for instance when started as non-root).
104
105 If we've created a file with group-id root, we also make
106 the file group-writable. This gives processes in the root group
107 write access to the file and avoids the problem that on some systems,
108 once the file is owned by the dnsmasq user, it can't be written
109 whilst dnsmasq is running as root during startup.
110 */
111 if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0)
112 {
113 struct stat ls;
114 if (getgid() == 0 && fstat(log_fd, &ls) == 0 && ls.st_gid == 0 &&
115 (ls.st_mode & S_IWGRP) == 0)
116 (void)fchmod(log_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
117 if (fchown(log_fd, ent_pw->pw_uid, -1) != 0)
118 ret = errno;
119 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100120
121 return ret;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100122}
Simon Kelleyf2621c72007-04-29 19:47:21 +0100123
Simon Kelley5aabfc72007-08-29 11:24:47 +0100124int log_reopen(char *log_file)
125{
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100126 if (!log_stderr)
127 {
128 if (log_fd != -1)
129 close(log_fd);
130
131 /* NOTE: umask is set to 022 by the time this gets called */
132
133 if (log_file)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700134 log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100135 else
136 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000137#if defined(HAVE_SOLARIS_NETWORK) || defined(__ANDROID__)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100138 /* Solaris logging is "different", /dev/log is not unix-domain socket.
139 Just leave log_fd == -1 and use the vsyslog call for everything.... */
Simon Kelley824af852008-02-12 20:43:05 +0000140# define _PATH_LOG "" /* dummy */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100141 return 1;
Simon Kelley824af852008-02-12 20:43:05 +0000142#else
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100143 int flags;
144 log_fd = socket(AF_UNIX, connection_type, 0);
145
146 /* if max_logs is zero, leave the socket blocking */
147 if (log_fd != -1 && max_logs != 0 && (flags = fcntl(log_fd, F_GETFL)) != -1)
148 fcntl(log_fd, F_SETFL, flags | O_NONBLOCK);
Simon Kelley824af852008-02-12 20:43:05 +0000149#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100150 }
151 }
152
153 return log_fd != -1;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100154}
Simon Kelley5aabfc72007-08-29 11:24:47 +0100155
156static void free_entry(void)
157{
158 struct log_entry *tmp = entries;
159 entries = tmp->next;
160 tmp->next = free_entries;
161 free_entries = tmp;
162}
163
Simon Kelleyf2621c72007-04-29 19:47:21 +0100164static void log_write(void)
165{
166 ssize_t rc;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100167
Simon Kelleyf2621c72007-04-29 19:47:21 +0100168 while (entries)
169 {
Josh Soref730c6742017-02-06 16:14:04 +0000170 /* The data in the payload is written with a terminating zero character
Simon Kelley7de060b2011-08-26 17:24:52 +0100171 and the length reflects this. For a stream connection we need to
172 send the zero as a record terminator, but this isn't done for a
173 datagram connection, so treat the length as one less than reality
174 to elide the zero. If we're logging to a file, turn the zero into
175 a newline, and leave the length alone. */
176 int len_adjust = 0;
177
178 if (log_to_file)
179 entries->payload[entries->offset + entries->length - 1] = '\n';
180 else if (connection_type == SOCK_DGRAM)
181 len_adjust = 1;
182
Simon Kelley5aabfc72007-08-29 11:24:47 +0100183 /* Avoid duplicates over a fork() */
184 if (entries->pid != getpid())
185 {
186 free_entry();
187 continue;
188 }
189
Simon Kelleyf2621c72007-04-29 19:47:21 +0100190 connection_good = 1;
191
Simon Kelley7de060b2011-08-26 17:24:52 +0100192 if ((rc = write(log_fd, entries->payload + entries->offset, entries->length - len_adjust)) != -1)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100193 {
194 entries->length -= rc;
195 entries->offset += rc;
Simon Kelley7de060b2011-08-26 17:24:52 +0100196 if (entries->length == len_adjust)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100197 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100198 free_entry();
Simon Kelleyf2621c72007-04-29 19:47:21 +0100199 if (entries_lost != 0)
200 {
201 int e = entries_lost;
202 entries_lost = 0; /* avoid wild recursion */
203 my_syslog(LOG_WARNING, _("overflow: %d log entries lost"), e);
204 }
205 }
206 continue;
207 }
208
209 if (errno == EINTR)
210 continue;
211
Simon Kelleyc72daea2012-01-05 21:33:27 +0000212 if (errno == EAGAIN || errno == EWOULDBLOCK)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100213 return; /* syslogd busy, go again when select() or poll() says so */
214
215 if (errno == ENOBUFS)
216 {
217 connection_good = 0;
218 return;
219 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100220
221 /* errors handling after this assumes sockets */
222 if (!log_to_file)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100223 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100224 /* Once a stream socket hits EPIPE, we have to close and re-open
225 (we ignore SIGPIPE) */
226 if (errno == EPIPE)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100227 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100228 if (log_reopen(NULL))
229 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100230 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100231 else if (errno == ECONNREFUSED ||
232 errno == ENOTCONN ||
233 errno == EDESTADDRREQ ||
234 errno == ECONNRESET)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100235 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100236 /* socket went (syslogd down?), try and reconnect. If we fail,
237 stop trying until the next call to my_syslog()
238 ECONNREFUSED -> connection went down
239 ENOTCONN -> nobody listening
240 (ECONNRESET, EDESTADDRREQ are *BSD equivalents) */
241
242 struct sockaddr_un logaddr;
243
244#ifdef HAVE_SOCKADDR_SA_LEN
245 logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1;
246#endif
Simon Kelley824af852008-02-12 20:43:05 +0000247 logaddr.sun_family = AF_UNIX;
Petr Menšík47b45b22018-08-15 18:17:00 +0200248 safe_strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100249
250 /* Got connection back? try again. */
251 if (connect(log_fd, (struct sockaddr *)&logaddr, sizeof(logaddr)) != -1)
252 continue;
253
254 /* errors from connect which mean we should keep trying */
255 if (errno == ENOENT ||
256 errno == EALREADY ||
257 errno == ECONNREFUSED ||
258 errno == EISCONN ||
259 errno == EINTR ||
Simon Kelleyc72daea2012-01-05 21:33:27 +0000260 errno == EAGAIN ||
261 errno == EWOULDBLOCK)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100262 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100263 /* try again on next syslog() call */
264 connection_good = 0;
265 return;
266 }
267
268 /* try the other sort of socket... */
269 if (errno == EPROTOTYPE)
270 {
271 connection_type = connection_type == SOCK_DGRAM ? SOCK_STREAM : SOCK_DGRAM;
272 if (log_reopen(NULL))
273 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100274 }
275 }
276 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100277
Simon Kelleyf2621c72007-04-29 19:47:21 +0100278 /* give up - fall back to syslog() - this handles out-of-space
279 when logging to a file, for instance. */
280 log_fd = -1;
281 my_syslog(LOG_CRIT, _("log failed: %s"), strerror(errno));
282 return;
283 }
284}
285
Simon Kelley7622fc02009-06-04 20:32:05 +0100286/* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
287 OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
288 DNS, DHCP and TFTP services.
Simon Kelleyb260d222021-03-12 21:57:57 +0000289 If OR'd with MS_DEBUG, the messages are suppressed unless --log-debug is set. */
Simon Kelleyf2621c72007-04-29 19:47:21 +0100290void my_syslog(int priority, const char *format, ...)
291{
292 va_list ap;
293 struct log_entry *entry;
294 time_t time_now;
295 char *p;
296 size_t len;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100297 pid_t pid = getpid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100298 char *func = "";
Simon Kelley5aabfc72007-08-29 11:24:47 +0100299
Simon Kelley7622fc02009-06-04 20:32:05 +0100300 if ((LOG_FACMASK & priority) == MS_TFTP)
301 func = "-tftp";
302 else if ((LOG_FACMASK & priority) == MS_DHCP)
303 func = "-dhcp";
Petr Menšíkc77fb9d2017-04-16 20:20:08 +0100304 else if ((LOG_FACMASK & priority) == MS_SCRIPT)
305 func = "-script";
Simon Kelleyb260d222021-03-12 21:57:57 +0000306 else if ((LOG_FACMASK & priority) == MS_DEBUG)
307 {
308 if (!option_bool(OPT_LOG_DEBUG))
309 return;
310 func = "-debug";
311 }
312
Simon Kelley316e2732010-01-22 20:16:09 +0000313#ifdef LOG_PRI
Simon Kelley7622fc02009-06-04 20:32:05 +0100314 priority = LOG_PRI(priority);
Simon Kelley316e2732010-01-22 20:16:09 +0000315#else
316 /* Solaris doesn't have LOG_PRI */
317 priority &= LOG_PRIMASK;
318#endif
319
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100320 if (echo_stderr)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100321 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100322 fprintf(stderr, "dnsmasq%s: ", func);
Simon Kelley824af852008-02-12 20:43:05 +0000323 va_start(ap, format);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100324 vfprintf(stderr, format, ap);
Simon Kelley824af852008-02-12 20:43:05 +0000325 va_end(ap);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100326 fputc('\n', stderr);
327 }
Simon Kelley824af852008-02-12 20:43:05 +0000328
Simon Kelleyf2621c72007-04-29 19:47:21 +0100329 if (log_fd == -1)
330 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000331#ifdef __ANDROID__
332 /* do android-specific logging.
333 log_fd is always -1 on Android except when logging to a file. */
334 int alog_lvl;
335
336 if (priority <= LOG_ERR)
337 alog_lvl = ANDROID_LOG_ERROR;
338 else if (priority == LOG_WARNING)
339 alog_lvl = ANDROID_LOG_WARN;
340 else if (priority <= LOG_INFO)
341 alog_lvl = ANDROID_LOG_INFO;
342 else
343 alog_lvl = ANDROID_LOG_DEBUG;
344
345 va_start(ap, format);
346 __android_log_vprint(alog_lvl, "dnsmasq", format, ap);
347 va_end(ap);
348#else
349 /* fall-back to syslog if we die during startup or
350 fail during running (always on Solaris). */
Simon Kelleyf2621c72007-04-29 19:47:21 +0100351 static int isopen = 0;
Simon Kelley572b41e2011-02-18 18:11:18 +0000352
Simon Kelleyf2621c72007-04-29 19:47:21 +0100353 if (!isopen)
354 {
355 openlog("dnsmasq", LOG_PID, log_fac);
356 isopen = 1;
357 }
Simon Kelley824af852008-02-12 20:43:05 +0000358 va_start(ap, format);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100359 vsyslog(priority, format, ap);
360 va_end(ap);
Simon Kelley572b41e2011-02-18 18:11:18 +0000361#endif
362
Simon Kelleyf2621c72007-04-29 19:47:21 +0100363 return;
364 }
365
366 if ((entry = free_entries))
367 free_entries = entry->next;
368 else if (entries_alloced < max_logs && (entry = malloc(sizeof(struct log_entry))))
369 entries_alloced++;
370
371 if (!entry)
372 entries_lost++;
373 else
374 {
375 /* add to end of list, consumed from the start */
376 entry->next = NULL;
377 if (!entries)
378 entries = entry;
379 else
380 {
381 struct log_entry *tmp;
382 for (tmp = entries; tmp->next; tmp = tmp->next);
383 tmp->next = entry;
384 }
385
386 time(&time_now);
387 p = entry->payload;
388 if (!log_to_file)
389 p += sprintf(p, "<%d>", priority | log_fac);
Simon Kelley7622fc02009-06-04 20:32:05 +0100390
Simon Kelley28866e92011-02-14 20:19:14 +0000391 /* Omit timestamp for default daemontools situation */
392 if (!log_stderr || !option_bool(OPT_NO_FORK))
393 p += sprintf(p, "%.15s ", ctime(&time_now) + 4);
394
395 p += sprintf(p, "dnsmasq%s[%d]: ", func, (int)pid);
Simon Kelley7622fc02009-06-04 20:32:05 +0100396
Simon Kelleyf2621c72007-04-29 19:47:21 +0100397 len = p - entry->payload;
Simon Kelley824af852008-02-12 20:43:05 +0000398 va_start(ap, format);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100399 len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */
Simon Kelley824af852008-02-12 20:43:05 +0000400 va_end(ap);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100401 entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
402 entry->offset = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100403 entry->pid = pid;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100404 }
405
406 /* almost always, logging won't block, so try and write this now,
407 to save collecting too many log messages during a select loop. */
408 log_write();
409
410 /* Since we're doing things asynchronously, a cache-dump, for instance,
411 can now generate log lines very fast. With a small buffer (desirable),
412 that means it can overflow the log-buffer very quickly,
413 so that the cache dump becomes mainly a count of how many lines
414 overflowed. To avoid this, we delay here, the delay is controlled
415 by queue-occupancy, and grows exponentially. The delay is limited to (2^8)ms.
416 The scaling stuff ensures that when the queue is bigger than 8, the delay
417 only occurs for the last 8 entries. Once the queue is full, we stop delaying
418 to preserve performance.
419 */
420
421 if (entries && max_logs != 0)
422 {
423 int d;
424
425 for (d = 0,entry = entries; entry; entry = entry->next, d++);
426
427 if (d == max_logs)
428 d = 0;
429 else if (max_logs > 8)
430 d -= max_logs - 8;
431
432 if (d > 0)
433 {
434 struct timespec waiter;
435 waiter.tv_sec = 0;
436 waiter.tv_nsec = 1000000 << (d - 1); /* 1 ms */
437 nanosleep(&waiter, NULL);
438
439 /* Have another go now */
440 log_write();
441 }
442 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100443}
444
Simon Kelleyb842bc92015-07-12 21:09:11 +0100445void set_log_writer(void)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100446{
447 if (entries && log_fd != -1 && connection_good)
Simon Kelleyb842bc92015-07-12 21:09:11 +0100448 poll_listen(log_fd, POLLOUT);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100449}
450
Simon Kelleyb842bc92015-07-12 21:09:11 +0100451void check_log_writer(int force)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100452{
Simon Kelleyb842bc92015-07-12 21:09:11 +0100453 if (log_fd != -1 && (force || poll_check(log_fd, POLLOUT)))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100454 log_write();
455}
456
Simon Kelley5aabfc72007-08-29 11:24:47 +0100457void flush_log(void)
458{
Simon Kelley28866e92011-02-14 20:19:14 +0000459 /* write until queue empty, but don't loop forever if there's
Josh Soref730c6742017-02-06 16:14:04 +0000460 no connection to the syslog in existence */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100461 while (log_fd != -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100462 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100463 struct timespec waiter;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100464 log_write();
Simon Kelley28866e92011-02-14 20:19:14 +0000465 if (!entries || !connection_good)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100466 {
467 close(log_fd);
468 break;
469 }
470 waiter.tv_sec = 0;
471 waiter.tv_nsec = 1000000; /* 1 ms */
472 nanosleep(&waiter, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100473 }
474}
475
476void die(char *message, char *arg1, int exit_code)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100477{
478 char *errmess = strerror(errno);
479
480 if (!arg1)
481 arg1 = errmess;
482
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100483 if (!log_stderr)
484 {
485 echo_stderr = 1; /* print as well as log when we die.... */
486 fputc('\n', stderr); /* prettyfy startup-script message */
487 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100488 my_syslog(LOG_CRIT, message, arg1, errmess);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100489 echo_stderr = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100490 my_syslog(LOG_CRIT, _("FAILED to start up"));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100491 flush_log();
Simon Kelleyf2621c72007-04-29 19:47:21 +0100492
Simon Kelley5aabfc72007-08-29 11:24:47 +0100493 exit(exit_code);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100494}