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