1
2 /* libdax_msgs
3 Message handling facility of libdax.
4 Copyright (C) 2006 - 2016 Thomas Schmitt <scdbackup@gmx.net>,
5 provided under GPL version 2 or later.
6 */
7
8 #ifdef HAVE_CONFIG_H
9 #include "../config.h"
10 #endif
11
12 #include <stdio.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <errno.h>
18 #include <sys/time.h>
19 #include <pthread.h>
20
21 /* Only this single source module is entitled to do this */
22 #define LIBDAX_MSGS_H_INTERNAL 1
23
24 /* All participants in the messaging system must do this */
25 #include "libdax_msgs.h"
26
27
28 /* ----------------------------- libdax_msgs_item ------------------------- */
29
30
libdax_msgs_item_new(struct libdax_msgs_item ** item,struct libdax_msgs_item * link,int flag)31 static int libdax_msgs_item_new(struct libdax_msgs_item **item,
32 struct libdax_msgs_item *link, int flag)
33 {
34 int ret;
35 struct libdax_msgs_item *o;
36 struct timeval tv;
37
38 (*item)= o=
39 (struct libdax_msgs_item *) calloc(1, sizeof(struct libdax_msgs_item));
40 if(o==NULL)
41 return(-1);
42 o->timestamp= 0.0;
43 ret= gettimeofday(&tv, NULL);
44 if(ret==0)
45 o->timestamp= tv.tv_sec+0.000001*tv.tv_usec;
46 o->process_id= getpid();
47 o->origin= -1;
48 o->severity= LIBDAX_MSGS_SEV_ALL;
49 o->priority= LIBDAX_MSGS_PRIO_ZERO;
50 o->error_code= 0;
51 o->msg_text= NULL;
52 o->os_errno= 0;
53 o->prev= link;
54 o->next= NULL;
55 if(link!=NULL) {
56 if(link->next!=NULL) {
57 link->next->prev= o;
58 o->next= link->next;
59 }
60 link->next= o;
61 }
62 return(1);
63 }
64
65
66 /** Detaches item from its queue and eventually readjusts start, end pointers
67 of the queue */
libdax_msgs_item_unlink(struct libdax_msgs_item * o,struct libdax_msgs_item ** chain_start,struct libdax_msgs_item ** chain_end,int flag)68 int libdax_msgs_item_unlink(struct libdax_msgs_item *o,
69 struct libdax_msgs_item **chain_start,
70 struct libdax_msgs_item **chain_end, int flag)
71 {
72 if(o->prev!=NULL)
73 o->prev->next= o->next;
74 if(o->next!=NULL)
75 o->next->prev= o->prev;
76 if(chain_start!=NULL)
77 if(*chain_start == o)
78 *chain_start= o->next;
79 if(chain_end!=NULL)
80 if(*chain_end == o)
81 *chain_end= o->prev;
82 o->next= o->prev= NULL;
83 return(1);
84 }
85
86
libdax_msgs_item_destroy(struct libdax_msgs_item ** item,int flag)87 int libdax_msgs_item_destroy(struct libdax_msgs_item **item,
88 int flag)
89 {
90 struct libdax_msgs_item *o;
91
92 o= *item;
93 if(o==NULL)
94 return(0);
95 libdax_msgs_item_unlink(o,NULL,NULL,0);
96 if(o->msg_text!=NULL)
97 free((char *) o->msg_text);
98 free((char *) o);
99 *item= NULL;
100 return(1);
101 }
102
103
libdax_msgs_item_get_msg(struct libdax_msgs_item * item,int * error_code,char ** msg_text,int * os_errno,int flag)104 int libdax_msgs_item_get_msg(struct libdax_msgs_item *item,
105 int *error_code, char **msg_text, int *os_errno,
106 int flag)
107 {
108 *error_code= item->error_code;
109 *msg_text= item->msg_text;
110 *os_errno= item->os_errno;
111 return(1);
112 }
113
114
libdax_msgs_item_get_origin(struct libdax_msgs_item * item,double * timestamp,pid_t * process_id,int * origin,int flag)115 int libdax_msgs_item_get_origin(struct libdax_msgs_item *item,
116 double *timestamp, pid_t *process_id, int *origin,
117 int flag)
118 {
119 *timestamp= item->timestamp;
120 *process_id= item->process_id;
121 *origin= item->origin;
122 return(1);
123 }
124
125
libdax_msgs_item_get_rank(struct libdax_msgs_item * item,int * severity,int * priority,int flag)126 int libdax_msgs_item_get_rank(struct libdax_msgs_item *item,
127 int *severity, int *priority, int flag)
128 {
129 *severity= item->severity;
130 *priority= item->priority;
131 return(1);
132 }
133
134
135 /* ------------------------------- libdax_msgs ---------------------------- */
136
137
libdax_msgs_new(struct libdax_msgs ** m,int flag)138 int libdax_msgs_new(struct libdax_msgs **m, int flag)
139 {
140 struct libdax_msgs *o;
141
142 (*m)= o= (struct libdax_msgs *) calloc(1, sizeof(struct libdax_msgs));
143 if(o==NULL)
144 return(-1);
145 o->refcount= 1;
146 o->oldest= NULL;
147 o->youngest= NULL;
148 o->count= 0;
149 o->queue_severity= LIBDAX_MSGS_SEV_ALL;
150 o->print_severity= LIBDAX_MSGS_SEV_NEVER;
151 strcpy(o->print_id,"libdax: ");
152
153 #ifndef LIBDAX_MSGS_SINGLE_THREADED
154 pthread_mutex_init(&(o->lock_mutex),NULL);
155 #endif
156
157 return(1);
158 }
159
160
libdax_msgs_lock(struct libdax_msgs * m,int flag)161 static int libdax_msgs_lock(struct libdax_msgs *m, int flag)
162 {
163
164 #ifndef LIBDAX_MSGS_SINGLE_THREADED
165 int ret;
166
167 ret= pthread_mutex_lock(&(m->lock_mutex));
168 if(ret!=0)
169 return(0);
170 #endif
171
172 return(1);
173 }
174
175
libdax_msgs_unlock(struct libdax_msgs * m,int flag)176 static int libdax_msgs_unlock(struct libdax_msgs *m, int flag)
177 {
178
179 #ifndef LIBDAX_MSGS_SINGLE_THREADED
180 int ret;
181
182 ret= pthread_mutex_unlock(&(m->lock_mutex));
183 if(ret!=0)
184 return(0);
185 #endif
186
187 return(1);
188 }
189
190
libdax_msgs_destroy(struct libdax_msgs ** m,int flag)191 int libdax_msgs_destroy(struct libdax_msgs **m, int flag)
192 {
193 struct libdax_msgs *o;
194 struct libdax_msgs_item *item, *next_item;
195
196 o= *m;
197 if(o==NULL)
198 return(0);
199 if(o->refcount > 1) {
200 if(libdax_msgs_lock(*m,0)<=0)
201 return(-1);
202 o->refcount--;
203 libdax_msgs_unlock(*m,0);
204 *m= NULL;
205 return(1);
206 }
207
208 #ifndef LIBDAX_MSGS_SINGLE_THREADED
209 if(pthread_mutex_destroy(&(o->lock_mutex))!=0) {
210 pthread_mutex_unlock(&(o->lock_mutex));
211 pthread_mutex_destroy(&(o->lock_mutex));
212 }
213 #endif
214
215 for(item= o->oldest; item!=NULL; item= next_item) {
216 next_item= item->next;
217 libdax_msgs_item_destroy(&item,0);
218 }
219 free((char *) o);
220 *m= NULL;
221 return(1);
222 }
223
224
libdax_msgs_refer(struct libdax_msgs ** pt,struct libdax_msgs * m,int flag)225 int libdax_msgs_refer(struct libdax_msgs **pt, struct libdax_msgs *m, int flag)
226 {
227 if(libdax_msgs_lock(m,0)<=0)
228 return(0);
229 m->refcount++;
230 *pt= m;
231 libdax_msgs_unlock(m,0);
232 return(1);
233 }
234
235
libdax_msgs_set_severities(struct libdax_msgs * m,int queue_severity,int print_severity,char * print_id,int flag)236 int libdax_msgs_set_severities(struct libdax_msgs *m, int queue_severity,
237 int print_severity, char *print_id, int flag)
238 {
239 if(libdax_msgs_lock(m,0)<=0)
240 return(0);
241 m->queue_severity= queue_severity;
242 m->print_severity= print_severity;
243 strncpy(m->print_id,print_id,80);
244 m->print_id[80]= 0;
245 libdax_msgs_unlock(m,0);
246 return(1);
247 }
248
249
libdax_msgs__text_to_sev(char * severity_name,int * severity,int flag)250 int libdax_msgs__text_to_sev(char *severity_name, int *severity,
251 int flag)
252 {
253 if(strncmp(severity_name,"NEVER",5)==0)
254 *severity= LIBDAX_MSGS_SEV_NEVER;
255 else if(strncmp(severity_name,"ABORT",5)==0)
256 *severity= LIBDAX_MSGS_SEV_ABORT;
257 else if(strncmp(severity_name,"FATAL",5)==0)
258 *severity= LIBDAX_MSGS_SEV_FATAL;
259 else if(strncmp(severity_name,"FAILURE",7)==0)
260 *severity= LIBDAX_MSGS_SEV_FAILURE;
261 else if(strncmp(severity_name,"MISHAP",6)==0)
262 *severity= LIBDAX_MSGS_SEV_MISHAP;
263 else if(strncmp(severity_name,"SORRY",5)==0)
264 *severity= LIBDAX_MSGS_SEV_SORRY;
265 else if(strncmp(severity_name,"WARNING",7)==0)
266 *severity= LIBDAX_MSGS_SEV_WARNING;
267 else if(strncmp(severity_name,"HINT",4)==0)
268 *severity= LIBDAX_MSGS_SEV_HINT;
269 else if(strncmp(severity_name,"NOTE",4)==0)
270 *severity= LIBDAX_MSGS_SEV_NOTE;
271 else if(strncmp(severity_name,"UPDATE",6)==0)
272 *severity= LIBDAX_MSGS_SEV_UPDATE;
273 else if(strncmp(severity_name,"DEBUG",5)==0)
274 *severity= LIBDAX_MSGS_SEV_DEBUG;
275 else if(strncmp(severity_name,"ERRFILE",7)==0)
276 *severity= LIBDAX_MSGS_SEV_ERRFILE;
277 else if(strncmp(severity_name,"ALL",3)==0)
278 *severity= LIBDAX_MSGS_SEV_ALL;
279 else {
280 *severity= LIBDAX_MSGS_SEV_ALL;
281 return(0);
282 }
283 return(1);
284 }
285
286
libdax_msgs__sev_to_text(int severity,char ** severity_name,int flag)287 int libdax_msgs__sev_to_text(int severity, char **severity_name,
288 int flag)
289 {
290 if(flag&1) {
291 *severity_name= "ALL ERRFILE DEBUG UPDATE NOTE HINT WARNING SORRY MISHAP FAILURE FATAL ABORT NEVER";
292 return(1);
293 }
294 *severity_name= "";
295 if(severity>=LIBDAX_MSGS_SEV_NEVER)
296 *severity_name= "NEVER";
297 else if(severity>=LIBDAX_MSGS_SEV_ABORT)
298 *severity_name= "ABORT";
299 else if(severity>=LIBDAX_MSGS_SEV_FATAL)
300 *severity_name= "FATAL";
301 else if(severity>=LIBDAX_MSGS_SEV_FAILURE)
302 *severity_name= "FAILURE";
303 else if(severity>=LIBDAX_MSGS_SEV_MISHAP)
304 *severity_name= "MISHAP";
305 else if(severity>=LIBDAX_MSGS_SEV_SORRY)
306 *severity_name= "SORRY";
307 else if(severity>=LIBDAX_MSGS_SEV_WARNING)
308 *severity_name= "WARNING";
309 else if(severity>=LIBDAX_MSGS_SEV_HINT)
310 *severity_name= "HINT";
311 else if(severity>=LIBDAX_MSGS_SEV_NOTE)
312 *severity_name= "NOTE";
313 else if(severity>=LIBDAX_MSGS_SEV_UPDATE)
314 *severity_name= "UPDATE";
315 else if(severity>=LIBDAX_MSGS_SEV_DEBUG)
316 *severity_name= "DEBUG";
317 else if(severity>=LIBDAX_MSGS_SEV_ERRFILE)
318 *severity_name= "ERRFILE";
319 else if(severity>=LIBDAX_MSGS_SEV_ALL)
320 *severity_name= "ALL";
321 else {
322 *severity_name= "";
323 return(0);
324 }
325 return(1);
326 }
327
328
329 /*
330 @param flag Bitfield for control purposes
331 bit0= If direct output to stderr:
332 CarriageReturn rather than LineFeed
333 */
libdax_msgs_submit(struct libdax_msgs * m,int origin,int error_code,int severity,int priority,char * msg_text,int os_errno,int flag)334 int libdax_msgs_submit(struct libdax_msgs *m, int origin, int error_code,
335 int severity, int priority, char *msg_text,
336 int os_errno, int flag)
337 {
338 int ret;
339 char *textpt,*sev_name,sev_text[81];
340 struct libdax_msgs_item *item= NULL;
341
342 if(severity >= m->print_severity) {
343 if(msg_text==NULL)
344 textpt= "";
345 else
346 textpt= msg_text;
347 sev_text[0]= 0;
348 ret= libdax_msgs__sev_to_text(severity,&sev_name,0);
349 if(ret>0)
350 sprintf(sev_text,"%s : ",sev_name);
351
352 fprintf(stderr, "%s%s%s%c", m->print_id, sev_text, textpt,
353 (flag & 1) ? '\r' : '\n');
354 if(os_errno!=0) {
355 ret= libdax_msgs_lock(m,0);
356 if(ret<=0)
357 return(-1);
358 fprintf(stderr,"%s( Most recent system error: %d '%s' )\n",
359 m->print_id,os_errno,strerror(os_errno));
360 libdax_msgs_unlock(m,0);
361 }
362
363 }
364 if(severity < m->queue_severity)
365 return(0);
366
367 ret= libdax_msgs_lock(m,0);
368 if(ret<=0)
369 return(-1);
370 ret= libdax_msgs_item_new(&item,m->youngest,0);
371 if(ret<=0)
372 goto failed;
373 item->origin= origin;
374 item->error_code= error_code;
375 item->severity= severity;
376 item->priority= priority;
377 if(msg_text!=NULL) {
378 item->msg_text= calloc(1, strlen(msg_text)+1);
379 if(item->msg_text==NULL)
380 goto failed;
381 strcpy(item->msg_text,msg_text);
382 }
383 item->os_errno= os_errno;
384 if(m->oldest==NULL)
385 m->oldest= item;
386 m->youngest= item;
387 m->count++;
388 libdax_msgs_unlock(m,0);
389
390 /*
391 fprintf(stderr,"libdax_experimental: message submitted to queue (now %d)\n",
392 m->count);
393 */
394
395 return(1);
396 failed:;
397 libdax_msgs_item_destroy(&item,0);
398 libdax_msgs_unlock(m,0);
399 return(-1);
400 }
401
402
libdax_msgs_obtain(struct libdax_msgs * m,struct libdax_msgs_item ** item,int severity,int priority,int flag)403 int libdax_msgs_obtain(struct libdax_msgs *m, struct libdax_msgs_item **item,
404 int severity, int priority, int flag)
405 {
406 int ret;
407 struct libdax_msgs_item *im, *next_im= NULL;
408
409 *item= NULL;
410 ret= libdax_msgs_lock(m,0);
411 if(ret<=0)
412 return(-1);
413 for(im= m->oldest; im!=NULL; im= next_im) {
414 for(; im!=NULL; im= next_im) {
415 next_im= im->next;
416 if(im->severity>=severity)
417 break;
418 libdax_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
419 libdax_msgs_item_destroy(&im,0); /* severity too low: delete */
420 }
421 if(im==NULL)
422 break;
423 if(im->priority>=priority)
424 break;
425 }
426 if(im==NULL)
427 {ret= 0; goto ex;}
428 libdax_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
429 *item= im;
430 ret= 1;
431 ex:;
432 libdax_msgs_unlock(m,0);
433 return(ret);
434 }
435
436
libdax_msgs_destroy_item(struct libdax_msgs * m,struct libdax_msgs_item ** item,int flag)437 int libdax_msgs_destroy_item(struct libdax_msgs *m,
438 struct libdax_msgs_item **item, int flag)
439 {
440 int ret;
441
442 ret= libdax_msgs_lock(m,0);
443 if(ret<=0)
444 return(-1);
445 ret= libdax_msgs_item_destroy(item,0);
446 libdax_msgs_unlock(m,0);
447 return(ret);
448 }
449
450