Added startup stack size check
[elliptics.git] / example / common.c
blob487c9f847cfb6c1f67d3920c17112ec7fadfc404
1 /*
2 * 2008+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/socket.h>
19 #include <sys/time.h>
20 #include <sys/syscall.h>
22 #include <ctype.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <pthread.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <syslog.h>
30 #include <time.h>
31 #include <unistd.h>
33 #include <netinet/in.h>
35 #include <elliptics/packet.h>
36 #include <elliptics/interface.h>
38 #include "common.h"
40 #define DNET_CONF_COMMENT '#'
41 #define DNET_CONF_DELIM '='
42 #define DNET_CONF_TIME_DELIM '.'
44 int dnet_parse_groups(char *value, int **groupsp)
46 int len = strlen(value), i, num = 0, start = 0, pos = 0;
47 char *ptr = value;
48 int *groups;
50 if (sscanf(value, "auto%d", &num) == 1) {
51 *groupsp = NULL;
52 return num;
55 for (i=0; i<len; ++i) {
56 if (value[i] == DNET_CONF_ADDR_DELIM)
57 start = 0;
58 else if (!start) {
59 start = 1;
60 num++;
64 if (!num) {
65 fprintf(stderr, "no groups found\n");
66 return -ENOENT;
69 groups = malloc(sizeof(int) * num);
70 if (!groups)
71 return -ENOMEM;
73 memset(groups, 0, num * sizeof(int));
75 start = 0;
76 for (i=0; i<len; ++i) {
77 if (value[i] == DNET_CONF_ADDR_DELIM) {
78 value[i] = '\0';
79 if (start) {
80 groups[pos] = atoi(ptr);
81 pos++;
82 start = 0;
84 } else if (!start) {
85 ptr = &value[i];
86 start = 1;
90 if (start) {
91 groups[pos] = atoi(ptr);
92 pos++;
95 *groupsp = groups;
96 return pos;
99 int dnet_parse_numeric_id(char *value, unsigned char *id)
101 unsigned char ch[5];
102 unsigned int i, len = strlen(value);
104 memset(id, 0, DNET_ID_SIZE);
106 if (len/2 > DNET_ID_SIZE)
107 len = DNET_ID_SIZE * 2;
109 ch[0] = '0';
110 ch[1] = 'x';
111 ch[4] = '\0';
112 for (i=0; i<len / 2; i++) {
113 ch[2] = value[2*i + 0];
114 ch[3] = value[2*i + 1];
116 id[i] = (unsigned char)strtol((const char *)ch, NULL, 16);
119 if (len & 1) {
120 ch[2] = value[2*i + 0];
121 ch[3] = '0';
123 id[i] = (unsigned char)strtol((const char *)ch, NULL, 16);
126 return 0;
129 void dnet_common_log(void *priv, int level, const char *msg)
131 char str[64];
132 struct tm tm;
133 struct timeval tv;
134 FILE *stream = priv;
136 if (!stream)
137 stream = stdout;
139 gettimeofday(&tv, NULL);
140 localtime_r((time_t *)&tv.tv_sec, &tm);
141 strftime(str, sizeof(str), "%F %R:%S", &tm);
143 fprintf(stream, "%s.%06lu %ld/%4d %1d: %s", str, tv.tv_usec, dnet_get_id(), getpid(), level, msg);
144 fflush(stream);
147 void dnet_syslog(void *priv __attribute__ ((unused)), int level, const char *msg)
149 int prio = LOG_DEBUG;
150 char str[64];
151 struct tm tm;
152 struct timeval tv;
154 if (level == DNET_LOG_ERROR)
155 prio = LOG_ERR;
156 if (level == DNET_LOG_INFO)
157 prio = LOG_INFO;
159 gettimeofday(&tv, NULL);
160 localtime_r((time_t *)&tv.tv_sec, &tm);
161 strftime(str, sizeof(str), "%F %R:%S", &tm);
163 syslog(prio, "%s.%06lu %ld/%4d %1x: %s", str, tv.tv_usec, dnet_get_id(), getpid(), level, msg);
166 int dnet_common_add_remote_addr(struct dnet_node *n, struct dnet_config *main_cfg, char *orig_addr)
168 char *a;
169 char *addr, *p;
170 int added = 0, err;
171 struct dnet_config cfg;
173 if (!orig_addr)
174 return 0;
176 a = strdup(orig_addr);
177 if (!a) {
178 err = -ENOMEM;
179 goto err_out_exit;
182 addr = a;
184 while (addr) {
185 p = strchr(addr, ' ');
186 if (p)
187 *p++ = '\0';
189 memcpy(&cfg, main_cfg, sizeof(struct dnet_config));
191 err = dnet_parse_addr(addr, &cfg);
192 if (err) {
193 dnet_log_raw(n, DNET_LOG_ERROR, "Failed to parse addr '%s': %d.\n", addr, err);
194 goto next;
197 err = dnet_add_state(n, &cfg);
198 if (err)
199 goto next;
201 added++;
203 if (!p)
204 break;
206 next:
207 addr = p;
209 while (addr && *addr && isspace(*addr))
210 addr++;
213 free(a);
215 if (!added) {
216 err = 0;
217 dnet_log_raw(n, DNET_LOG_ERROR, "No remote addresses added. Continue to work though.\n");
218 goto err_out_exit;
221 return 0;
223 err_out_exit:
224 return err;
227 int dnet_common_prepend_data(struct timespec *ts, uint64_t size, void *buf, int *bufsize)
229 void *orig = buf;
230 struct dnet_common_embed *e = buf;
231 uint64_t *edata = (uint64_t *)e->data;
233 if (*bufsize < (int)(sizeof(struct dnet_common_embed) + sizeof(uint64_t)) * 2)
234 return -ENOBUFS;
236 e->size = sizeof(uint64_t) * 2;
237 e->type = DNET_FCGI_EMBED_TIMESTAMP;
238 e->flags = 0;
239 dnet_common_convert_embedded(e);
241 edata[0] = dnet_bswap64(ts->tv_sec);
242 edata[1] = dnet_bswap64(ts->tv_nsec);
244 buf += sizeof(struct dnet_common_embed) + sizeof(uint64_t) * 2;
246 e = buf;
247 e->size = size;
248 e->type = DNET_FCGI_EMBED_DATA;
249 e->flags = 0;
250 dnet_common_convert_embedded(e);
252 buf += sizeof(struct dnet_common_embed);
254 *bufsize = buf - orig;
255 return 0;
258 #define dnet_map_log(n, level, fmt, a...) do { if ((n)) dnet_log_raw((n), level, fmt, ##a); else fprintf(stderr, fmt, ##a); } while (0)
260 int dnet_map_history(struct dnet_node *n, char *file, struct dnet_history_map *map)
262 int err;
263 struct stat st;
265 map->fd = open(file, O_RDWR | O_CLOEXEC);
266 if (map->fd < 0) {
267 err = -errno;
268 dnet_map_log(n, DNET_LOG_ERROR, "Failed to open history file '%s': %s [%d].\n",
269 file, strerror(errno), errno);
270 goto err_out_exit;
273 err = fstat(map->fd, &st);
274 if (err) {
275 err = -errno;
276 dnet_map_log(n, DNET_LOG_ERROR, "Failed to stat history file '%s': %s [%d].\n",
277 file, strerror(errno), errno);
278 goto err_out_close;
281 if (st.st_size % (int)sizeof(struct dnet_history_entry)) {
282 dnet_map_log(n, DNET_LOG_ERROR, "Corrupted history file '%s', "
283 "its size %llu must be multiple of %zu.\n",
284 file, (unsigned long long)st.st_size,
285 sizeof(struct dnet_history_entry));
286 err = -EINVAL;
287 goto err_out_close;
289 map->size = st.st_size;
291 map->ent = mmap(NULL, map->size, PROT_READ | PROT_WRITE, MAP_SHARED, map->fd, 0);
292 if (map->ent == MAP_FAILED) {
293 err = -errno;
294 dnet_map_log(n, DNET_LOG_ERROR, "Failed to mmap history file '%s': %s [%d].\n",
295 file, strerror(errno), errno);
296 goto err_out_close;
299 map->num = map->size / sizeof(struct dnet_history_entry);
301 dnet_map_log(n, DNET_LOG_NOTICE, "Mapped %ld entries in '%s'.\n", map->num, file);
303 return 0;
305 err_out_close:
306 close(map->fd);
307 err_out_exit:
308 return err;
311 void dnet_unmap_history(struct dnet_node *n __attribute((unused)), struct dnet_history_map *map)
313 munmap(map->ent, map->size);
314 close(map->fd);
317 struct dnet_meta * dnet_meta_search_cust(struct dnet_meta_container *mc, uint32_t type)
319 void *data = mc->data;
320 uint32_t size = mc->size;
321 struct dnet_meta m, *found = NULL;
323 while (size) {
324 if (size < sizeof(struct dnet_meta)) {
325 fprintf(stderr, "Metadata size %u is too small, min %zu, searching for 0x%x.\n",
326 size, sizeof(struct dnet_meta), type);
327 break;
330 m = *(struct dnet_meta *)data;
331 dnet_convert_meta(&m);
333 if (m.size + sizeof(struct dnet_meta) > size) {
334 fprintf(stderr, "Metadata entry broken: entry size %u, type: 0x%x, struct size: %zu, "
335 "total size left: %u, searching for 0x%x.\n",
336 m.size, m.type, sizeof(struct dnet_meta), size, type);
337 break;
340 if (m.type == type) {
341 found = data;
342 break;
345 data += m.size + sizeof(struct dnet_meta);
346 size -= m.size + sizeof(struct dnet_meta);
349 return found;
352 int dnet_background(void)
354 pid_t pid;
355 int fd;
357 pid = fork();
358 if (pid == -1) {
359 fprintf(stderr, "Failed to fork to background: %s.\n", strerror(errno));
360 return -1;
363 if (pid != 0) {
364 printf("Daemon pid: %d.\n", pid);
365 exit(0);
368 setsid();
370 close(0);
371 close(1);
372 close(2);
374 fd = open("/dev/null", O_RDWR);
375 if (fd < 0) {
376 fd = -errno;
377 fprintf(stderr, "Can not open /dev/null: %d\n", fd);
378 exit(fd);
381 dup2(fd, 0);
382 dup2(fd, 1);
383 dup2(fd, 2);
385 return 0;