37c7cd7199107864c39e35f761bd6673f5a68179
[multipath-tools/.git] / libmultipath / log.c
1 /*
2  * Copyright (c) 2005 Christophe Varoqui
3  * Copyright (c) 2005 Benjamin Marzinski, Redhat
4  * Copyright (c) 2005 Jun'ichi Nomura, NEC
5  */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include <syslog.h>
11
12 #include "memory.h"
13 #include "log.h"
14
15 #define ALIGN(len, s) (((len)+(s)-1)/(s)*(s))
16
17 #if LOGDBG
18 static void dump_logarea (void)
19 {
20         struct logmsg * msg;
21
22         logdbg(stderr, "\n==== area: start addr = %p, end addr = %p ====\n",
23                 la->start, la->end);
24         logdbg(stderr, "|addr     |next     |prio|msg\n");
25
26         for (msg = (struct logmsg *)la->head; (void *)msg != la->tail;
27              msg = msg->next)
28                 logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
29                                 msg->prio, (char *)&msg->str);
30
31         logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
32                         msg->prio, (char *)&msg->str);
33
34         logdbg(stderr, "\n\n");
35 }
36 #endif
37
38 static int logarea_init (int size)
39 {
40         logdbg(stderr,"enter logarea_init\n");
41         la = (struct logarea *)MALLOC(sizeof(struct logarea));
42
43         if (!la)
44                 return 1;
45
46         if (size < MAX_MSG_SIZE)
47                 size = DEFAULT_AREA_SIZE;
48
49         la->start = MALLOC(size);
50         if (!la->start) {
51                 FREE(la);
52                 return 1;
53         }
54         memset(la->start, 0, size);
55
56         la->empty = 1;
57         la->end = la->start + size;
58         la->head = la->start;
59         la->tail = la->start;
60
61         la->buff = MALLOC(MAX_MSG_SIZE + sizeof(struct logmsg));
62
63         if (!la->buff) {
64                 FREE(la->start);
65                 FREE(la);
66                 return 1;
67         }
68         return 0;
69
70 }
71
72 int log_init(char *program_name, int size)
73 {
74         logdbg(stderr,"enter log_init\n");
75         openlog(program_name, 0, LOG_DAEMON);
76
77         if (logarea_init(size))
78                 return 1;
79
80         return 0;
81 }
82
83 void free_logarea (void)
84 {
85         FREE(la->start);
86         FREE(la->buff);
87         FREE(la);
88         return;
89 }
90
91 void log_close (void)
92 {
93         free_logarea();
94         closelog();
95
96         return;
97 }
98
99 void log_reset (char *program_name)
100 {
101         closelog();
102         openlog(program_name, 0, LOG_DAEMON);
103 }
104
105 int log_enqueue (int prio, const char * fmt, va_list ap)
106 {
107         int len, fwd;
108         char buff[MAX_MSG_SIZE];
109         struct logmsg * msg;
110         struct logmsg * lastmsg;
111
112         lastmsg = (struct logmsg *)la->tail;
113
114         if (!la->empty) {
115                 fwd = sizeof(struct logmsg) +
116                       strlen((char *)&lastmsg->str) * sizeof(char) + 1;
117                 la->tail += ALIGN(fwd, sizeof(void *));
118         }
119         vsnprintf(buff, MAX_MSG_SIZE, fmt, ap);
120         len = ALIGN(sizeof(struct logmsg) + strlen(buff) * sizeof(char) + 1,
121                     sizeof(void *));
122
123         /* not enough space on tail : rewind */
124         if (la->head <= la->tail && len > (la->end - la->tail)) {
125                 logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail);
126                 if (la->head == la->start ) {
127                         logdbg(stderr, "enqueue: can not rewind tail, drop msg\n");
128                         la->tail = lastmsg;
129                         return 1;  /* can't reuse */
130                 }
131                 la->tail = la->start;
132
133                 if (la->empty)
134                         la->head = la->start;
135         }
136
137         /* not enough space on head : drop msg */
138         if (la->head > la->tail && len >= (la->head - la->tail)) {
139                 logdbg(stderr, "enqueue: log area overrun, drop msg\n");
140
141                 if (!la->empty)
142                         la->tail = lastmsg;
143
144                 return 1;
145         }
146
147         /* ok, we can stage the msg in the area */
148         la->empty = 0;
149         msg = (struct logmsg *)la->tail;
150         msg->prio = prio;
151         memcpy((void *)&msg->str, buff, strlen(buff) + 1);
152         lastmsg->next = la->tail;
153         msg->next = la->head;
154
155         logdbg(stderr, "enqueue: %p, %p, %i, %s\n", (void *)msg, msg->next,
156                 msg->prio, (char *)&msg->str);
157
158 #if LOGDBG
159         dump_logarea();
160 #endif
161         return 0;
162 }
163
164 int log_dequeue (void * buff)
165 {
166         struct logmsg * src = (struct logmsg *)la->head;
167         struct logmsg * dst = (struct logmsg *)buff;
168         struct logmsg * lst = (struct logmsg *)la->tail;
169
170         if (la->empty)
171                 return 1;
172
173         int len = strlen((char *)&src->str) * sizeof(char) +
174                   sizeof(struct logmsg) + 1;
175
176         dst->prio = src->prio;
177         memcpy(dst, src,  len);
178
179         if (la->tail == la->head)
180                 la->empty = 1; /* we purge the last logmsg */
181         else {
182                 la->head = src->next;
183                 lst->next = la->head;
184         }
185         logdbg(stderr, "dequeue: %p, %p, %i, %s\n",
186                 (void *)src, src->next, src->prio, (char *)&src->str);
187
188         memset((void *)src, 0,  len);
189
190         return 0;
191 }
192
193 /*
194  * this one can block under memory pressure
195  */
196 void log_syslog (void * buff)
197 {
198         struct logmsg * msg = (struct logmsg *)buff;
199
200         syslog(msg->prio, "%s", (char *)&msg->str);
201 }