Add GETINFO --data.
[pwmd.git] / src / misc.c
blobc536576455a539c03be34448cf9a402e3be2cf10
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <glib.h>
33 #include <glib/gprintf.h>
34 #include <string.h>
35 #include <ctype.h>
37 #include "pwmd-error.h"
38 #include <gcrypt.h>
40 #include "misc.h"
41 #include "mutex.h"
42 #include "cache.h"
44 extern void log_write(const gchar *fmt, ...);
46 gboolean strv_printf(gchar ***array, const gchar *fmt, ...)
48 gchar **a;
49 va_list ap;
50 gchar *buf;
51 gint len = *array ? g_strv_length(*array) : 0;
52 gint ret;
54 if (!fmt)
55 return FALSE;
57 if ((a = g_realloc(*array, (len + 2) * sizeof(gchar *))) == NULL) {
58 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
59 return FALSE;
62 va_start(ap, fmt);
63 ret = g_vasprintf(&buf, fmt, ap);
64 va_end(ap);
66 if (ret == -1) {
67 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
68 return FALSE;
71 a[len++] = buf;
72 a[len] = NULL;
73 *array = a;
74 return TRUE;
77 gchar **strvcatv(gchar **dst, gchar **src)
79 gchar **p;
80 gint i;
81 gchar **d;
83 if (!src)
84 return NULL;
86 d = g_strdupv(dst);
88 if (!d)
89 return NULL;
91 i = g_strv_length(d);
93 for (p = src; *p; p++) {
94 gchar **pa;
96 pa = g_realloc(d, (i + 2) * sizeof(gchar *));
98 if (!pa) {
99 g_strfreev(d);
100 return NULL;
103 d = pa;
104 d[i] = g_strdup(*p);
106 if (!d[i]) {
107 g_strfreev(d);
108 return NULL;
111 d[++i] = NULL;
114 return d;
117 gboolean valid_filename(const gchar *filename)
119 const gchar *p;
121 if (!filename || !*filename)
122 return FALSE;
124 if (!g_strcmp0(filename, "-"))
125 return FALSE;
127 for (p = filename; *p; p++) {
128 if (*p == '/' || isspace(*p))
129 return FALSE;
132 return TRUE;
135 gchar *print_fmt(gchar *buf, gsize len, const char *fmt, ...)
137 va_list ap;
139 va_start(ap, fmt);
140 g_vsnprintf(buf, len, fmt, ap);
141 va_end(ap);
142 return buf;
145 gchar *expand_homedir(gchar *str)
147 gchar *p = str;
149 if (*p++ == '~')
150 return g_strdup_printf("%s%s", g_get_home_dir(), p);
152 return g_strdup(str);
155 gchar **split_input_line(gchar *str, gchar *delim, gint n)
157 if (!str || !*str)
158 return NULL;
160 return g_strsplit(str, delim, n);
163 gpg_error_t parse_options(gchar **line, struct argv_s *args[], gpointer data)
165 gchar *p = *line;
166 gpg_error_t rc = 0;
168 for (; p && *p; p++) {
169 while (g_ascii_isspace(*p))
170 p++;
172 if (!*p)
173 break;
175 if (*p == '-' && *(p+1) == '-') {
176 p += 2;
177 gchar opt[255] = {0}, value[255] = {0};
178 gchar *tp;
179 guint len;
181 if (!*p || *p == ' ') {
182 if (*p)
183 p++;
185 break;
188 for (tp = opt, len = 0; *p; p++, len++) {
189 if (len+1 == 255)
190 return GPG_ERR_LINE_TOO_LONG;
192 if (*p == ' ' || *p == '=') {
193 gboolean inquote = FALSE;
195 *tp = 0;
197 if (*p == '=') {
198 p++;
200 for (tp = value, len = 0; *p; p++, len++) {
201 if (len+1 == 255)
202 return GPG_ERR_LINE_TOO_LONG;
204 if (*p == '\"') {
205 inquote = !inquote;
206 continue;
208 else if (*p == ' ' && !inquote)
209 break;
211 *tp++ = *p;
214 *tp = 0;
217 break;
220 *tp++ = *p;
223 *tp = 0;
224 gboolean match = FALSE;
226 for (int i = 0; args[i]; i++) {
227 if (!g_strcmp0(args[i]->opt, opt)) {
228 log_write1("param: name='%s' value='%s'", opt, value);
229 if (args[i]->type == OPTION_TYPE_NOARG && *value)
230 return GPG_ERR_SYNTAX;
231 else if (args[i]->type == OPTION_TYPE_ARG && !*value)
232 return GPG_ERR_SYNTAX;
234 rc = args[i]->func(data, value);
236 if (rc)
237 return rc;
239 match = TRUE;
240 break;
244 if (!match)
245 return GPG_ERR_UNKNOWN_OPTION;
247 if (!*p)
248 break;
250 continue;
253 break;
256 *line = p;
257 return rc;
260 gchar *bin2hex(const guchar *data, gsize len)
262 gsize size = len*2+1;
263 gchar buf[size];
264 gsize n;
266 buf[0] = 0;
268 for (n = 0; n < len; n++) {
269 gchar c[3];
271 g_sprintf(c, "%02X", data[n]);
272 g_strlcat(buf, c, size);
275 return g_strdup(buf);
278 gchar *plus_escape(const gchar *fmt, ...)
280 va_list ap;
281 gchar *str;
283 va_start(ap, fmt);
284 if (g_vasprintf(&str, fmt, ap) > 0) {
285 gchar *p;
287 for (p = str; *p; p++) {
288 if (*p == ' ')
289 *p = '+';
292 va_end(ap);
293 return str;
295 va_end(ap);
297 return NULL;
300 static gchar *strip_texi(const gchar *str)
302 const gchar *p;
303 gchar *s = g_strdup(str);
304 gsize len = strlen(s);
305 gint c = 0;
307 if (!s)
308 return NULL;
310 for (p = str; *p; p++) {
311 if (*p == '@' && *(p+1) != '@') {
312 if (!g_ascii_strncasecmp(p+1, "table", 5)
313 || !g_ascii_strncasecmp(p+1, "end ", 4)) {
314 while (*p++ != '\n');
315 p--;
316 continue;
318 else if (!g_ascii_strncasecmp(p+1, "example", 7)
319 || !g_ascii_strncasecmp(p+1, "end ", 4)) {
320 while (*p++ != '\n');
321 p--;
322 continue;
324 else if (!g_ascii_strncasecmp(p+1, "sp ", 3)) {
325 p += 3;
327 while (*p && isdigit(*p++))
328 p++;
329 continue;
331 else if (!g_ascii_strncasecmp(p+1, "item", 4)) {
332 p += 5;
333 while (*p && *p != '\n')
334 s[c++] = *p++;
336 continue;
338 else if (!g_ascii_strncasecmp(p+1, "pxref", 5)) {
339 p += 6;
340 c = g_strlcat(s, "see ", len);
341 goto close;
343 else if (!g_ascii_strncasecmp(p+1, "xref", 4)) {
344 p += 5;
345 c = g_strlcat(s, "See ", len);
346 goto close;
349 while (*p && *p != '{') {
350 if (*++p == '*') {
351 p++;
352 goto append;
356 close:
357 if (*p) {
358 p++;
359 s[c++] = '`';
360 while (*p && *p != '}')
361 s[c++] = *p++;
363 if (*p)
364 p++;
366 s[c++] = '\'';
369 else if (*p == '@' && *(p+1) == '@')
370 p++;
372 append:
373 if (*p)
374 s[c++] = *p;
376 s[c] = 0;
379 s[c] = 0;
380 return s;
384 gchar *strip_texi_and_wrap(const gchar *str)
386 gchar *tmp = strip_texi(str);
387 gchar *help = g_malloc(strlen(tmp+1)*2);
388 gchar *p, *ph;
389 gint i;
391 for (p = tmp, ph = help, i = 0; *p; p++, i++) {
392 if (i == 79 || *p == '\n') {
393 if (!g_ascii_isspace(*p)) {
394 gchar *t = ph;
395 gint n = 0;
397 while (!g_ascii_isspace(*--t))
398 n++;
400 *t++ = '\n';
401 i = -1;
402 p -= n;
403 while (n--) {
404 *t++ = *p++;
405 i++;
408 else {
409 *ph++ = '\n';
410 i = -1;
411 while (*p != '\n' && g_ascii_isspace(*p))
412 p++;
416 *ph++ = *p;
419 *ph = 0;
420 g_free(tmp);
421 return help;
424 void free_key(void *data)
426 g_free(data);
429 gpg_error_t create_thread(void *(*cb)(void *), void *data,
430 pthread_t *tid, gboolean detached)
432 pthread_attr_t attr;
433 gint n;
435 pthread_attr_init(&attr);
437 if (detached)
438 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
440 n = pthread_create(tid, &attr, cb, data);
441 pthread_attr_destroy(&attr);
442 return gpg_error_from_errno(n);
445 void cleanup_mutex_cb(void *arg)
447 pthread_mutex_t *m = (pthread_mutex_t *)arg;
449 MUTEX_UNLOCK(m);
452 void cleanup_fd_cb(void *arg)
454 gint fd = *(gint *)arg;
456 if (fd != -1)
457 close(fd);
460 void cleanup_unlink_cb(void *arg)
462 gchar *file = arg;
464 if (file && *file)
465 unlink(file);
468 void cleanup_cache_mutex(void *arg)
470 cache_unlock();
473 gboolean valid_keygrip(const guchar *data, gsize len)
475 for (gsize i = 0; i < len; i++) {
476 if (data[i])
477 return TRUE;
480 return FALSE;
483 gpg_error_t get_checksum(const gchar *filename, guchar **r_crc, gsize *r_crclen)
485 gint fd;
486 guchar *buf;
487 gpg_error_t rc = 0;
488 gsize len;
489 struct stat st;
491 if (stat(filename, &st) == -1)
492 return gpg_error_from_syserror();
494 fd = open(filename, O_RDONLY);
495 if (fd == -1)
496 return gpg_error_from_syserror();
498 pthread_cleanup_push(cleanup_fd_cb, &fd);
499 buf = g_malloc(st.st_size);
500 if (buf) {
501 pthread_cleanup_push(g_free, buf);
503 len = read(fd, buf, st.st_size);
504 if (len == st.st_size) {
505 if (buf) {
506 guchar *crc;
508 len = gcry_md_get_algo_dlen(GCRY_MD_CRC32);
509 crc = g_malloc(len);
510 if (crc) {
511 pthread_cleanup_push(g_free, crc);
512 gcry_md_hash_buffer(GCRY_MD_CRC32, crc, buf, st.st_size);
513 *r_crc = crc;
514 *r_crclen = len;
515 pthread_cleanup_pop(0);
517 else
518 rc = GPG_ERR_ENOMEM;
521 else
522 rc = GPG_ERR_TOO_SHORT;
524 pthread_cleanup_pop(1);
526 else
527 rc = GPG_ERR_ENOMEM;
529 pthread_cleanup_pop(1);
530 return rc;