Imported Upstream version 0.8.7
[platform/upstream/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 #include <time.h>
12 #include <pthread.h>
13
14 #include "memory.h"
15 #include "log.h"
16 #include "util.h"
17
18 #define ALIGN(len, s) (((len)+(s)-1)/(s)*(s))
19
20 struct logarea* la;
21 static pthread_mutex_t logq_lock = PTHREAD_MUTEX_INITIALIZER;
22
23 #if LOGDBG
24 static void dump_logarea (void)
25 {
26         struct logmsg * msg;
27
28         logdbg(stderr, "\n==== area: start addr = %p, end addr = %p ====\n",
29                 la->start, la->end);
30         logdbg(stderr, "|addr     |next     |prio|msg\n");
31
32         for (msg = (struct logmsg *)la->head; (void *)msg != la->tail;
33              msg = msg->next)
34                 logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
35                                 msg->prio, (char *)&msg->str);
36
37         logdbg(stderr, "|%p |%p |%i   |%s\n", (void *)msg, msg->next,
38                         msg->prio, (char *)&msg->str);
39
40         logdbg(stderr, "\n\n");
41 }
42 #endif
43
44 static int logarea_init (int size)
45 {
46         logdbg(stderr,"enter logarea_init\n");
47         la = (struct logarea *)MALLOC(sizeof(struct logarea));
48
49         if (!la)
50                 return 1;
51
52         if (size < MAX_MSG_SIZE)
53                 size = DEFAULT_AREA_SIZE;
54
55         la->start = MALLOC(size);
56         if (!la->start) {
57                 FREE(la);
58                 return 1;
59         }
60         memset(la->start, 0, size);
61
62         la->empty = 1;
63         la->end = la->start + size;
64         la->head = la->start;
65         la->tail = la->start;
66
67         la->buff = MALLOC(MAX_MSG_SIZE + sizeof(struct logmsg));
68
69         if (!la->buff) {
70                 FREE(la->start);
71                 FREE(la);
72                 return 1;
73         }
74         return 0;
75
76 }
77
78 int log_init(char *program_name, int size)
79 {
80         int ret = 1;
81
82         logdbg(stderr,"enter log_init\n");
83
84         pthread_mutex_lock(&logq_lock);
85         pthread_cleanup_push(cleanup_mutex, &logq_lock);
86
87         openlog(program_name, 0, LOG_DAEMON);
88         if (!la)
89                 ret = logarea_init(size);
90
91         pthread_cleanup_pop(1);
92
93         return ret;
94 }
95
96 static void free_logarea (void)
97 {
98         FREE(la->start);
99         FREE(la->buff);
100         FREE(la);
101         return;
102 }
103
104 void log_close (void)
105 {
106         pthread_mutex_lock(&logq_lock);
107         pthread_cleanup_push(cleanup_mutex, &logq_lock);
108
109         if (la)
110                 free_logarea();
111         closelog();
112
113         pthread_cleanup_pop(1);
114         return;
115 }
116
117 void log_reset (char *program_name)
118 {
119         pthread_mutex_lock(&logq_lock);
120         pthread_cleanup_push(cleanup_mutex, &logq_lock);
121
122         closelog();
123         openlog(program_name, 0, LOG_DAEMON);
124
125         pthread_cleanup_pop(1);
126 }
127
128 __attribute__((format(printf, 2, 0)))
129 static int _log_enqueue(int prio, const char * fmt, va_list ap)
130 {
131         int len, fwd;
132         char buff[MAX_MSG_SIZE];
133         struct logmsg * msg;
134         struct logmsg * lastmsg;
135
136         lastmsg = (struct logmsg *)la->tail;
137
138         if (!la->empty) {
139                 fwd = sizeof(struct logmsg) +
140                       strlen((char *)&lastmsg->str) * sizeof(char) + 1;
141                 la->tail += ALIGN(fwd, sizeof(void *));
142         }
143         vsnprintf(buff, MAX_MSG_SIZE, fmt, ap);
144         len = ALIGN(sizeof(struct logmsg) + strlen(buff) * sizeof(char) + 1,
145                     sizeof(void *));
146
147         /* not enough space on tail : rewind */
148         if (la->head <= la->tail && len > (la->end - la->tail)) {
149                 logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail);
150                 if (la->head == la->start ) {
151                         logdbg(stderr, "enqueue: can not rewind tail, drop msg\n");
152                         la->tail = lastmsg;
153                         return 1;  /* can't reuse */
154                 }
155                 la->tail = la->start;
156
157                 if (la->empty)
158                         la->head = la->start;
159         }
160
161         /* not enough space on head : drop msg */
162         if (la->head > la->tail && len >= (la->head - la->tail)) {
163                 logdbg(stderr, "enqueue: log area overrun, drop msg\n");
164
165                 if (!la->empty)
166                         la->tail = lastmsg;
167
168                 return 1;
169         }
170
171         /* ok, we can stage the msg in the area */
172         la->empty = 0;
173         msg = (struct logmsg *)la->tail;
174         msg->prio = prio;
175         memcpy((void *)&msg->str, buff, strlen(buff) + 1);
176         lastmsg->next = la->tail;
177         msg->next = la->head;
178
179         logdbg(stderr, "enqueue: %p, %p, %i, %s\n", (void *)msg, msg->next,
180                 msg->prio, (char *)&msg->str);
181
182 #if LOGDBG
183         dump_logarea();
184 #endif
185         return 0;
186 }
187
188 int log_enqueue(int prio, const char *fmt, va_list ap)
189 {
190         int ret = 1;
191
192         pthread_mutex_lock(&logq_lock);
193         pthread_cleanup_push(cleanup_mutex, &logq_lock);
194         if (la)
195                 ret = _log_enqueue(prio, fmt, ap);
196         pthread_cleanup_pop(1);
197         return ret;
198 }
199
200 static int _log_dequeue(void *buff)
201 {
202         struct logmsg * src = (struct logmsg *)la->head;
203         struct logmsg * dst = (struct logmsg *)buff;
204         struct logmsg * lst = (struct logmsg *)la->tail;
205
206         if (la->empty)
207                 return 1;
208
209         int len = strlen((char *)&src->str) * sizeof(char) +
210                   sizeof(struct logmsg) + 1;
211
212         dst->prio = src->prio;
213         memcpy(dst, src,  len);
214
215         if (la->tail == la->head)
216                 la->empty = 1; /* we purge the last logmsg */
217         else {
218                 la->head = src->next;
219                 lst->next = la->head;
220         }
221         logdbg(stderr, "dequeue: %p, %p, %i, %s\n",
222                 (void *)src, src->next, src->prio, (char *)&src->str);
223
224         memset((void *)src, 0,  len);
225
226         return 0;
227 }
228
229 int log_dequeue(void *buff)
230 {
231         int ret = 1;
232
233         pthread_mutex_lock(&logq_lock);
234         pthread_cleanup_push(cleanup_mutex, &logq_lock);
235         if (la)
236                 ret = _log_dequeue(buff);
237         pthread_cleanup_pop(1);
238         return ret;
239 }
240
241 /*
242  * this one can block under memory pressure
243  */
244 void log_syslog (void * buff)
245 {
246         struct logmsg * msg = (struct logmsg *)buff;
247
248         syslog(msg->prio, "%s", (char *)&msg->str);
249 }