1 /*
2 * Copyright (c) 2009 NLNet Labs. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27 /**
28 * Threading and locking.
29 *
30 */
31
32 #include "config.h"
33 #include "locks.h"
34 #include "log.h"
35
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <limits.h>
39 #include <syslog.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <signal.h> /* sigfillset(), sigprocmask() */
43 #include <string.h> /* strerror() */
44 #include <time.h> /* gettimeofday() */
45
46 static const char* lock_str = "lock";
47
48 int
ods_thread_wait(pthread_cond_t * cond,pthread_mutex_t * lock,time_t wait)49 ods_thread_wait(pthread_cond_t* cond, pthread_mutex_t* lock, time_t wait)
50 {
51 struct timespec ts;
52
53 if (wait <= 0)
54 return pthread_cond_wait(cond, lock);
55
56 if (clock_gettime(CLOCK_REALTIME, &ts) < 0) {
57 ods_log_error("[%s] clock_gettime() error: %s", lock_str,
58 strerror(errno));
59 return 1;
60 }
61
62 ts.tv_sec += wait;
63 return pthread_cond_timedwait(cond, lock, &ts);
64 }
65
66 janitor_threadclass_t detachedthreadclass;
67 janitor_threadclass_t workerthreadclass;
68 janitor_threadclass_t handlerthreadclass;
69 janitor_threadclass_t cmdhandlerthreadclass;
70
71 struct alertbuffer_struct {
72 char buffer[1024];
73 int index;
74 };
75 static void alert(struct alertbuffer_struct* buffer, const char *format, ...)
76 #ifdef HAVE___ATTRIBUTE__
77 __attribute__ ((format (printf, 2, 3)))
78 #endif
79 ;
80 static void alertsyslog(const char* format, ...)
81 #ifdef HAVE___ATTRIBUTE__
82 __attribute__ ((format (printf, 1, 2)))
83 #endif
84 ;
85
86 inline static int
alertoutput(struct alertbuffer_struct * buffer,int ch)87 alertoutput(struct alertbuffer_struct* buffer, int ch)
88 {
89 if (buffer->index < sizeof(buffer->buffer)) {
90 buffer->buffer[buffer->index++] = ch;
91 return 0;
92 } else
93 return -1;
94 }
95
96 static void
alertinteger(struct alertbuffer_struct * buffer,unsigned long value,int base)97 alertinteger(struct alertbuffer_struct* buffer, unsigned long value, int base)
98 {
99 char ch;
100 if (value > base - 1)
101 alertinteger(buffer, value / base, base);
102 ch = "0123456789abcdef"[value % base];
103 alertoutput(buffer, ch);
104 }
105
106 static void
valert(struct alertbuffer_struct * buffer,const char * format,va_list args)107 valert(struct alertbuffer_struct* buffer, const char* format, va_list args)
108 {
109 int idx, len;
110 const char* stringarg;
111 void* pointerarg;
112 int integerarg;
113 long longarg;
114 idx = 0;
115 while (format[idx]) {
116 if (format[idx] == '%') {
117 switch (format[idx + 1]) {
118 case '%':
119 alertoutput(buffer, '%');
120 idx += 2;
121 break;
122 case 's':
123 stringarg = va_arg(args, char*);
124 if (stringarg == NULL)
125 stringarg = "(null)";
126 while(*stringarg)
127 if(alertoutput(buffer, *(stringarg++)))
128 break;
129 idx += 2;
130 break;
131 case 'p':
132 pointerarg = va_arg(args, void*);
133 if (pointerarg == NULL) {
134 stringarg = "(null)";
135 while(stringarg)
136 alertoutput(buffer, *(stringarg++));
137 } else {
138 alertoutput(buffer, '0');
139 alertoutput(buffer, 'x');
140 alertinteger(buffer, (unsigned long) pointerarg, 16);
141 }
142 idx += 2;
143 break;
144 case 'l':
145 switch (format[idx + 2]) {
146 case 'd':
147 longarg = va_arg(args, long);
148 if (longarg < 0) {
149 alertoutput(buffer, '-');
150 alertinteger(buffer, 1UL + ~((unsigned long) longarg), 10);
151 } else
152 alertinteger(buffer, longarg, 10);
153 idx += 3;
154 break;
155 case '\0':
156 alertoutput(buffer, format[idx++]);
157 break;
158 default:
159 alertoutput(buffer, format[idx++]);
160 alertoutput(buffer, format[idx++]);
161 alertoutput(buffer, format[idx++]);
162 }
163 break;
164 case 'd':
165 integerarg = va_arg(args, int);
166 alertinteger(buffer, (long) integerarg, 10);
167 idx += 2;
168 break;
169 case '\0':
170 alertoutput(buffer, '%');
171 idx += 1;
172 break;
173 default:
174 alertoutput(buffer, format[idx++]);
175 alertoutput(buffer, format[idx++]);
176 }
177 } else {
178 alertoutput(buffer, format[idx++]);
179 }
180 }
181 }
182
183 static void
alertsyslog(const char * format,...)184 alertsyslog(const char* format, ...)
185 {
186 va_list args;
187 struct alertbuffer_struct buffer;
188 va_start(args, format);
189 buffer.index = 0;
190 valert(&buffer, format, args);
191 va_end(args);
192 if (buffer.index < sizeof(buffer.buffer)) {
193 buffer.buffer[buffer.index] = '\0';
194 } else {
195 strcpy(&buffer.buffer[buffer.index - strlen("...\n") -1], "...\n");
196 }
197 (void)write(2, buffer.buffer, strlen(buffer.buffer));
198 syslog(LOG_CRIT, "%s", buffer.buffer);
199 }
200
201 void
ods_janitor_initialize(char * argv0)202 ods_janitor_initialize(char*argv0)
203 {
204 janitor_initialize(alertsyslog, ods_log_error);
205
206 janitor_threadclass_create(&detachedthreadclass, "daemonthreads");
207 janitor_threadclass_setautorun(detachedthreadclass);
208 janitor_threadclass_setblockedsignals(detachedthreadclass);
209 janitor_threadclass_setdetached(detachedthreadclass);
210 janitor_threadclass_setminstacksize(detachedthreadclass, ODS_MINIMUM_STACKSIZE);
211
212 janitor_threadclass_create(&workerthreadclass, "workerthreads");
213 janitor_threadclass_setautorun(workerthreadclass);
214 janitor_threadclass_setblockedsignals(workerthreadclass);
215 janitor_threadclass_setminstacksize(workerthreadclass, ODS_MINIMUM_STACKSIZE);
216
217 janitor_threadclass_create(&handlerthreadclass, "handlerthreads");
218 janitor_threadclass_setautorun(handlerthreadclass);
219 janitor_threadclass_setminstacksize(handlerthreadclass, ODS_MINIMUM_STACKSIZE);
220
221 janitor_threadclass_create(&cmdhandlerthreadclass, "cmdhandlerthreads");
222 janitor_threadclass_setautorun(cmdhandlerthreadclass);
223 janitor_threadclass_setminstacksize(cmdhandlerthreadclass, ODS_MINIMUM_STACKSIZE);
224
225 janitor_trapsignals(argv0);
226 }
227