add improved argument parsing. also add helper messages
[archipelago] / xseg / sys / user / xseg_user.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include <time.h>
5 #include <string.h>
6 #include <dlfcn.h>
7 #include <unistd.h>
8 #include <stdint.h>
9 #include <sys/syscall.h>
10 #include <errno.h>
11 #include <sys/util.h>
12 #include <sys/time.h>
13
14 #include <sys/domain.h>
15 #include <xtypes/domain.h>
16 #include <xseg/domain.h>
17
18 #include <xtypes/xlock.h>
19
20 int (*xseg_snprintf)(char *str, size_t size, const char *format, ...) = snprintf;
21
22 char __xseg_errbuf[4096];
23
24 static struct xlock __lock = { .owner = Noone};
25
26 void __lock_domain(void)
27 {
28         (void)xlock_acquire(&__lock, 1);
29 }
30
31 void __unlock_domain(void)
32 {
33         xlock_release(&__lock);
34 }
35
36 void __load_plugin(const char *name)
37 {
38         void *dl;
39         void (*init)(void);
40         char _name[128];
41         unsigned int namelen = strlen(name);
42
43         strncpy(_name, "xseg_", 5);
44         strncpy(_name + 5, name, 80);
45         strncpy(_name + 5 + namelen, ".so", 3);
46         _name[5 + namelen + 3 ] = 0;
47         dl = dlopen(_name, RTLD_NOW);
48         if (!dl) {
49                 XSEGLOG("Cannot load plugin '%s': %s\n", _name, dlerror());
50                 return;
51         }
52
53         strncpy(_name + 5 + namelen, "_init", 5);
54         _name[127] = 0;
55         init = (void (*)(void))(long)dlsym(dl, _name);
56         if (!init) {
57                 XSEGLOG("Init function '%s' not found!\n", _name);
58                 return;
59         }
60
61         init();
62         //XSEGLOG("Plugin '%s' loaded.\n", name);
63 }
64
65 uint64_t __get_id(void)
66 {
67         return (uint64_t)syscall(SYS_gettid);
68 }
69
70 void __xseg_log(const char *msg)
71 {
72         (void)puts(msg);
73         fflush(stdout);
74 }
75
76 void *xtypes_malloc(unsigned long size)
77 {
78         return malloc(size);
79 }
80
81 void xtypes_free(void *ptr)
82 {
83         free(ptr);
84 }
85
86 void __get_current_time(struct timeval *tv) {
87         gettimeofday(tv, NULL);
88 }
89
90 int __renew_logctx(struct log_ctx *lc, char *peer_name,
91                 enum log_level log_level, char *logfile, uint32_t flags)
92 {
93         FILE *file;
94
95         if (peer_name){
96                 strncpy(lc->peer_name, peer_name, MAX_PEER_NAME);
97                 lc->peer_name[MAX_PEER_NAME -1] = 0;
98         }
99
100         lc->log_level = log_level;
101         if (logfile && logfile[0]) {
102                 strncpy(lc->filename, logfile, MAX_LOGFILE_LEN);
103                 lc->filename[MAX_LOGFILE_LEN - 1] = 0;
104         }
105         else if (!(flags & REOPEN_FILE) || lc->logfile == stderr)
106                 return 0;
107
108         if (lc->logfile == stderr)
109                 file = fopen(lc->filename, "a");
110         else
111                 file = freopen(lc->filename, "a", lc->logfile);
112         if (!file) {
113                 return -1;
114         }
115
116         flags &= ~REOPEN_FILE;
117         if ((flags|lc->flags) & REDIRECT_STDOUT)
118                 if (!freopen(lc->filename, "a", stdout))
119                         return -1;
120         if ((flags|lc->flags) & REDIRECT_STDERR)
121                 if (!freopen(lc->filename, "a", stderr))
122                         return -1;
123         lc->flags |= flags;
124
125         return 0;
126 }
127 int (*renew_logctx)(struct log_ctx *lc, char *peer_name,
128         enum log_level log_level, char *logfile, uint32_t flags) = __renew_logctx;
129
130 int __init_logctx(struct log_ctx *lc, char *peer_name,
131                 enum log_level log_level, char *logfile, uint32_t flags)
132 {
133         FILE *file;
134
135         if (peer_name){
136                 strncpy(lc->peer_name, peer_name, MAX_PEER_NAME);
137                 lc->peer_name[MAX_PEER_NAME -1] = 0;
138         }
139         else {
140                 return -1;
141         }
142
143         lc->log_level = log_level;
144         if (!logfile || !logfile[0]) {
145                 lc->logfile = stderr;
146                 return 0;
147         }
148
149         strncpy(lc->filename, logfile, MAX_LOGFILE_LEN);
150         lc->filename[MAX_LOGFILE_LEN - 1] = 0;
151         file = fopen(lc->filename, "a");
152         if (!file) {
153                 lc->logfile = stderr;
154                 return -1;
155         }
156         lc->logfile = file;
157
158         if (flags & REDIRECT_STDOUT)
159                 if (!freopen(lc->filename, "a", stdout))
160                         return -1;
161         if (flags & REDIRECT_STDERR)
162                 if (!freopen(lc->filename, "a", stderr))
163                         return -1;
164         lc->flags = flags;
165
166         return 0;
167 }
168 int (*init_logctx)(struct log_ctx *lc, char *peer_name,
169         enum log_level log_level, char *logfile, uint32_t flags) = __init_logctx;
170
171 void __xseg_log2(struct log_ctx *lc, enum log_level level, char *fmt, ...)
172 {
173         va_list ap;
174         time_t timeval; 
175         char timebuf[1024], buffer[4096];
176         char *buf = buffer;
177         char *t = NULL, *pn = NULL;
178
179         va_start(ap, fmt);
180         switch (level) {
181                 case E: t = "XSEG[EE]"; break;
182                 case W: t = "XSEG[WW]"; break;
183                 case I: t = "XSEG[II]"; break;
184                 case D: t = "XSEG[DD]"; break;
185                 default: t = "XSEG[UNKNONW]"; break;
186         }
187         pn = lc->peer_name;
188         if (!pn)
189                 pn = "Invalid peer name";
190
191         time(&timeval);
192         ctime_r(&timeval, timebuf);
193         *strchr(timebuf, '\n') = '\0';
194
195         buf += sprintf(buf, "%s: ", t);
196         buf += snprintf(buf, MAX_PEER_NAME + 2, "%s: ", lc->peer_name);
197         buf += sprintf(buf, "%s (%ld):\n\t", timebuf, timeval);
198         unsigned long rem = sizeof(buffer) - (buf - buffer);
199         buf += vsnprintf(buf, rem, fmt, ap);
200         if (buf >= buffer + sizeof(buffer))
201                 buf = buffer + sizeof(buffer) - 2;/* enough to hold \n and \0 */
202         buf += sprintf(buf, "\n");
203
204         fprintf(lc->logfile, "%s", buffer);
205         fflush(lc->logfile);
206         va_end(ap);
207
208         return;
209 }
210
211 void xseg_printtrace(void)
212 {
213         void *array[10];
214         size_t size;
215         char **strings;
216         int i;
217
218         size = backtrace (array, 10);
219         strings = backtrace_symbols (array, size);
220
221         XSEGLOG("Obtained %zd stack frames.\n", size);
222
223         for (i = 0; i < size; i++)
224                 XSEGLOG ("%s\n", strings[i]);
225
226         free (strings);
227 }