Bump version to 0.3.5next
[archipelago] / xseg / sys / user / xseg_user.c
1 /*
2  * Copyright 2012 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *   2. Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials
14  *      provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and
30  * documentation are those of the authors and should not be
31  * interpreted as representing official policies, either expressed
32  * or implied, of GRNET S.A.
33  */
34
35 #define _GNU_SOURCE
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <time.h>
39 #include <string.h>
40 #include <dlfcn.h>
41 #include <unistd.h>
42 #include <stdint.h>
43 #include <sys/syscall.h>
44 #include <errno.h>
45 #include <sys/util.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #include <sys/time.h>
50 #include <execinfo.h>
51 #include <sys/domain.h>
52 #include <xtypes/domain.h>
53 #include <xseg/domain.h>
54
55 #include <xtypes/xlock.h>
56
57 int (*xseg_snprintf)(char *str, size_t size, const char *format, ...) = snprintf;
58
59 char __xseg_errbuf[4096];
60
61 static struct xlock __lock = { .owner = Noone};
62
63 void __lock_domain(void)
64 {
65         (void)xlock_acquire(&__lock, 1);
66 }
67
68 void __unlock_domain(void)
69 {
70         xlock_release(&__lock);
71 }
72
73 void __load_plugin(const char *name)
74 {
75         void *dl;
76         void (*init)(void);
77         char _name[128];
78         unsigned int namelen = strlen(name);
79
80         strncpy(_name, "xseg_", 5);
81         strncpy(_name + 5, name, 80);
82         strncpy(_name + 5 + namelen, ".so", 3);
83         _name[5 + namelen + 3 ] = 0;
84         dl = dlopen(_name, RTLD_NOW);
85         if (!dl) {
86                 XSEGLOG("Cannot load plugin '%s': %s\n", _name, dlerror());
87                 return;
88         }
89
90         strncpy(_name + 5 + namelen, "_init", 5);
91         _name[127] = 0;
92         init = (void (*)(void))(long)dlsym(dl, _name);
93         if (!init) {
94                 XSEGLOG("Init function '%s' not found!\n", _name);
95                 return;
96         }
97
98         init();
99         //XSEGLOG("Plugin '%s' loaded.\n", name);
100 }
101
102 uint64_t __get_id(void)
103 {
104         return (uint64_t)syscall(SYS_gettid);
105 }
106
107 void __xseg_log(const char *msg)
108 {
109         (void)puts(msg);
110         fflush(stdout);
111 }
112
113 void *xtypes_malloc(unsigned long size)
114 {
115         return malloc(size);
116 }
117
118 void xtypes_free(void *ptr)
119 {
120         free(ptr);
121 }
122
123 void __get_current_time(struct timeval *tv) {
124         gettimeofday(tv, NULL);
125 }
126
127 int __renew_logctx(struct log_ctx *lc, char *peer_name,
128                 enum log_level log_level, char *logfile, uint32_t flags)
129 {
130         int fd, tmp_fd;
131
132         if (peer_name){
133                 strncpy(lc->peer_name, peer_name, MAX_PEER_NAME);
134                 lc->peer_name[MAX_PEER_NAME -1] = 0;
135         }
136
137         lc->log_level = log_level;
138         if (logfile && logfile[0]) {
139                 strncpy(lc->filename, logfile, MAX_LOGFILE_LEN);
140                 lc->filename[MAX_LOGFILE_LEN - 1] = 0;
141         }
142         else if (!(flags & REOPEN_FILE) || lc->logfile == STDERR_FILENO)
143                 return 0;
144
145         fd = open(lc->filename, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
146         if (fd < 1){
147                 return -1;
148         }
149
150         tmp_fd = lc->logfile;
151         lc->logfile = fd;
152         close(tmp_fd);
153
154         flags &= ~REOPEN_FILE;
155         if ((flags|lc->flags) & REDIRECT_STDOUT){
156                 fd = dup2(lc->logfile, STDOUT_FILENO);
157                 if (fd < 0)
158                         return -1;
159         }
160         if ((flags|lc->flags) & REDIRECT_STDERR){
161                 fd = dup2(lc->logfile, STDERR_FILENO);
162                 if (fd < 0)
163                         return -1;
164         }
165         lc->flags |= flags;
166
167         return 0;
168 }
169 int (*renew_logctx)(struct log_ctx *lc, char *peer_name,
170         enum log_level log_level, char *logfile, uint32_t flags) = __renew_logctx;
171
172 int __init_logctx(struct log_ctx *lc, char *peer_name,
173                 enum log_level log_level, char *logfile, uint32_t flags)
174 {
175         int fd;
176
177         if (peer_name){
178                 strncpy(lc->peer_name, peer_name, MAX_PEER_NAME);
179                 lc->peer_name[MAX_PEER_NAME -1] = 0;
180         }
181         else {
182                 return -1;
183         }
184
185         /* set logfile to stderr by default */
186         lc->logfile = STDERR_FILENO;
187 #if 0
188         /* duplicate stdout, stderr */
189         fd = dup(STDOUT_FILENO);
190         if (fd < 0){
191                 return -1;
192         }
193         lc->stdout_orig = fd;
194
195         fd = dup(STDERR_FILENO);
196         if (fd < 0){
197                 return -1;
198         }
199         lc->stderr_orig = fd;
200 #endif
201         lc->log_level = log_level;
202         if (!logfile || !logfile[0]) {
203 //              lc->logfile = lc->stderr_orig;
204                 return 0;
205         }
206
207         strncpy(lc->filename, logfile, MAX_LOGFILE_LEN);
208         lc->filename[MAX_LOGFILE_LEN - 1] = 0;
209         fd = open(lc->filename, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
210         if (fd < 1){
211 //              lc->logfile = lc->stderr_orig;
212                 return -1;
213         }
214         lc->logfile = fd;
215
216         if (flags & REDIRECT_STDOUT){
217                 fd = dup2(lc->logfile, STDOUT_FILENO);
218                 if (fd < 0)
219                         return -1;
220         }
221         if (flags & REDIRECT_STDERR){
222                 fd = dup2(lc->logfile, STDERR_FILENO);
223                 if (fd < 0)
224                         return -1;
225         }
226         lc->flags = flags;
227
228         return 0;
229 }
230 int (*init_logctx)(struct log_ctx *lc, char *peer_name,
231         enum log_level log_level, char *logfile, uint32_t flags) = __init_logctx;
232
233 void __xseg_log2(struct log_ctx *lc, enum log_level level, char *fmt, ...)
234 {
235         va_list ap;
236         time_t timeval; 
237         char timebuf[1024], buffer[4096];
238         char *buf = buffer;
239         char *t = NULL, *pn = NULL;
240         ssize_t r, sum;
241         size_t count;
242         int fd;
243
244         va_start(ap, fmt);
245         switch (level) {
246                 case E: t = "XSEG[EE]"; break;
247                 case W: t = "XSEG[WW]"; break;
248                 case I: t = "XSEG[II]"; break;
249                 case D: t = "XSEG[DD]"; break;
250                 default: t = "XSEG[UNKNONW]"; break;
251         }
252         pn = lc->peer_name;
253         if (!pn)
254                 pn = "Invalid peer name";
255
256         time(&timeval);
257         ctime_r(&timeval, timebuf);
258         *strchr(timebuf, '\n') = '\0';
259
260         buf += sprintf(buf, "%s: ", t);
261         buf += snprintf(buf, MAX_PEER_NAME + 2, "%s: ", lc->peer_name);
262         buf += sprintf(buf, "%s (%ld):\n\t", timebuf, timeval);
263         unsigned long rem = sizeof(buffer) - (buf - buffer);
264         buf += vsnprintf(buf, rem, fmt, ap);
265         if (buf >= buffer + sizeof(buffer))
266                 buf = buffer + sizeof(buffer) - 2;/* enough to hold \n and \0 */
267         buf += sprintf(buf, "\n");
268
269         count = buf-buffer;
270         sum = 0;
271         r = 0;
272         fd = *(volatile int *)&lc->logfile;
273         do {
274                 r = write(fd, buffer + sum, count - sum);
275                 if (r < 0){
276                         if (errno == EBADF)
277                                 fd = *(volatile int *)&lc->logfile;
278                         else {
279                                 //XSEGLOG("Error while writing log");
280                                 break;
281                         }
282                 } else {
283                         sum += r;
284                 }
285         } while (sum < count);
286         /* No need to check for error */
287         //fsync(fd);
288         va_end(ap);
289
290         return;
291 }
292
293 /* FIXME: This is not async safe */
294 void xseg_printtrace(void)
295 {
296         void *array[20];
297         size_t size;
298
299         XSEGLOG("Backtrace:");
300         size = backtrace(array, 20);
301         /* stderr should be open since we don't close it */
302         backtrace_symbols_fd(array, size, 2);
303 }