Portability fixes. Mostly for Android.
[pwmd.git] / src / util-misc.c
blob2e2115a5951b3315e949c51621a3b29b59a2eaa7
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <pwd.h>
35 #include "pwmd-error.h"
36 #include <gcrypt.h>
37 #include "util-misc.h"
38 #include "util-string.h"
39 #include "mutex.h"
40 #include "cache.h"
41 #include "mem.h"
43 extern void log_write(const char *fmt, ...);
45 int valid_filename(const char *filename)
47 const char *p;
49 if (!filename || !*filename)
50 return 0;
52 if (!strcmp(filename, "-"))
53 return 0;
55 for (p = filename; *p; p++) {
56 if (*p == '/' || isspace(*p))
57 return 0;
60 return 1;
63 char *get_username()
65 struct passwd *pw = getpwuid(getuid());
67 return pw ? pw->pw_name : NULL;
70 char *get_home_dir()
72 #ifdef HAVE_GETPWNAM_R
73 struct passwd pw, *result;
74 size_t len;
75 char *buf;
77 if (home_directory)
78 return home_directory;
80 len = sysconf(_SC_GETPW_R_SIZE_MAX);
81 if (len == -1)
82 len = 16384;
84 buf = xmalloc(len);
85 if (!buf)
86 return NULL;
88 if (!getpwuid_r(getuid(), &pw, buf, len, &result))
89 home_directory = str_dup(result->pw_dir);
91 xfree(buf);
92 #else
93 struct passwd *result = getpwuid(getuid());
95 if (result)
96 home_directory = str_dup(result->pw_dir);
97 #endif
99 return home_directory;
102 char *expand_homedir(char *str)
104 char *p = str;
106 if (*p++ == '~')
107 return str_asprintf("%s%s", get_home_dir(), p);
109 return str_dup(str);
112 gpg_error_t parse_options(char **line, struct argv_s *args[], void * data)
114 char *p = *line;
115 gpg_error_t rc = 0;
117 for (; p && *p; p++) {
118 while (*p == ' ')
119 p++;
121 if (!*p)
122 break;
124 if (*p == '-' && *(p+1) == '-') {
125 p += 2;
126 char opt[255] = {0}, value[255] = {0};
127 char *tp;
128 unsigned len;
130 if (!*p || *p == ' ') {
131 if (*p)
132 p++;
134 break;
137 for (tp = opt, len = 0; *p; p++, len++) {
138 if (len+1 == 255)
139 return GPG_ERR_LINE_TOO_LONG;
141 if (*p == ' ' || *p == '=') {
142 int inquote = 0;
144 *tp = 0;
146 if (*p == '=') {
147 p++;
149 for (tp = value, len = 0; *p; p++, len++) {
150 if (len+1 == 255)
151 return GPG_ERR_LINE_TOO_LONG;
153 if (*p == '\"') {
154 inquote = !inquote;
155 continue;
157 else if (*p == ' ' && !inquote)
158 break;
160 *tp++ = *p;
163 *tp = 0;
166 break;
169 *tp++ = *p;
172 *tp = 0;
173 int match = 0;
175 for (int i = 0; args[i]; i++) {
176 if (!strcmp(args[i]->opt, opt)) {
177 log_write1("param: name='%s' value='%s'", opt, value);
178 if (args[i]->type == OPTION_TYPE_NOARG && *value)
179 return GPG_ERR_SYNTAX;
180 else if (args[i]->type == OPTION_TYPE_ARG && !*value)
181 return GPG_ERR_SYNTAX;
183 rc = args[i]->func(data, value);
185 if (rc)
186 return rc;
188 match = 1;
189 break;
193 if (!match)
194 return GPG_ERR_UNKNOWN_OPTION;
196 if (!*p)
197 break;
199 continue;
202 break;
205 *line = p;
206 return rc;
209 char *bin2hex(const unsigned char *data, size_t len)
211 size_t size = len*2+1;
212 char buf[size];
213 size_t n;
215 buf[0] = 0;
217 for (n = 0; n < len; n++) {
218 char c[3];
220 sprintf(c, "%02X", data[n]);
221 strcat(buf, c);
224 return str_dup(buf);
227 char *plus_escape(const char *fmt, ...)
229 va_list ap;
230 char *str;
232 va_start(ap, fmt);
234 if (str_vasprintf(&str, fmt, ap) > 0) {
235 char *p;
237 for (p = str; *p; p++) {
238 if (*p == ' ')
239 *p = '+';
242 va_end(ap);
243 return str;
246 va_end(ap);
247 return NULL;
250 static char *strip_texi(const char *str)
252 const char *p;
253 char *s = str_dup(str);
254 int c = 0;
256 if (!s)
257 return NULL;
259 for (p = str; *p; p++) {
260 if (*p == '@' && *(p+1) != '@') {
261 if (!strncasecmp(p+1, "table", 5)
262 || !strncasecmp(p+1, "end ", 4)) {
263 while (*p++ != '\n');
264 p--;
265 continue;
267 else if (!strncasecmp(p+1, "example", 7)
268 || !strncasecmp(p+1, "end ", 4)) {
269 while (*p++ != '\n');
270 p--;
271 continue;
273 else if (!strncasecmp(p+1, "sp ", 3)) {
274 p += 3;
276 while (*p && isdigit(*p++))
277 p++;
278 continue;
280 else if (!strncasecmp(p+1, "item", 4)) {
281 p += 5;
282 while (*p && *p != '\n')
283 s[c++] = *p++;
285 continue;
287 else if (!strncasecmp(p+1, "pxref", 5)) {
288 p += 6;
289 strcat(s, "see ");
290 c = strlen(s);
291 goto close;
293 else if (!strncasecmp(p+1, "xref", 4)) {
294 p += 5;
295 strcat(s, "See ");
296 c = strlen(s);
297 goto close;
300 while (*p && *p != '{') {
301 if (*++p == '*') {
302 p++;
303 goto append;
307 close:
308 if (*p) {
309 p++;
310 s[c++] = '`';
311 while (*p && *p != '}')
312 s[c++] = *p++;
314 if (*p)
315 p++;
317 s[c++] = '\'';
320 else if (*p == '@' && *(p+1) == '@')
321 p++;
323 append:
324 if (*p)
325 s[c++] = *p;
327 s[c] = 0;
330 s[c] = 0;
331 return s;
335 char *strip_texi_and_wrap(const char *str)
337 char *tmp = strip_texi(str);
338 char *help = xmalloc(strlen(tmp+1)*2);
339 char *p, *ph;
340 int i;
342 for (p = tmp, ph = help, i = 0; *p; p++, i++) {
343 if (i == 78 || *p == '\n') {
344 if (!isspace(*p)) {
345 char *t = ph;
346 int n = 0;
348 while (!(*--t == ' '))
349 n++;
351 *t++ = '\n';
352 i = -1;
353 p -= n;
354 while (n--) {
355 *t++ = *p++;
356 i++;
359 else {
360 *ph++ = '\n';
361 i = -1;
362 while (*p != '\n' && *p == ' ')
363 p++;
367 *ph++ = *p;
370 *ph = 0;
371 xfree(tmp);
372 return help;
375 void free_key(void *data)
377 xfree(data);
380 gpg_error_t create_thread(void *(*cb)(void *), void *data,
381 pthread_t *tid, int detached)
383 pthread_attr_t attr;
384 int n;
386 pthread_attr_init(&attr);
388 if (detached)
389 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
391 n = pthread_create(tid, &attr, cb, data);
392 pthread_attr_destroy(&attr);
393 return gpg_error_from_errno(n);
396 void cleanup_mutex_cb(void *arg)
398 pthread_mutex_t *m = (pthread_mutex_t *)arg;
400 MUTEX_UNLOCK(m);
403 void cleanup_fd_cb(void *arg)
405 int fd = *(int *)arg;
407 if (fd != -1)
408 close(fd);
411 void cleanup_unlink_cb(void *arg)
413 char *file = arg;
415 if (file && *file)
416 unlink(file);
419 void cleanup_cache_mutex(void *arg)
421 cache_unlock();
424 int valid_keygrip(const unsigned char *data, size_t len)
426 for (size_t i = 0; i < len; i++) {
427 if (data[i])
428 return 1;
431 return 0;
434 gpg_error_t get_checksum(const char *filename, unsigned char **r_crc, size_t *r_crclen)
436 int fd;
437 unsigned char *buf;
438 gpg_error_t rc = 0;
439 size_t len;
440 struct stat st;
442 if (stat(filename, &st) == -1)
443 return gpg_error_from_syserror();
445 fd = open(filename, O_RDONLY);
446 if (fd == -1)
447 return gpg_error_from_syserror();
449 pthread_cleanup_push(cleanup_fd_cb, &fd);
450 buf = xmalloc(st.st_size);
451 if (buf) {
452 pthread_cleanup_push(xfree, buf);
454 len = read(fd, buf, st.st_size);
455 if (len == st.st_size) {
456 if (buf) {
457 unsigned char *crc;
459 len = gcry_md_get_algo_dlen(GCRY_MD_CRC32);
460 crc = xmalloc(len);
461 if (crc) {
462 pthread_cleanup_push(xfree, crc);
463 gcry_md_hash_buffer(GCRY_MD_CRC32, crc, buf, st.st_size);
464 *r_crc = crc;
465 *r_crclen = len;
466 pthread_cleanup_pop(0);
468 else
469 rc = GPG_ERR_ENOMEM;
472 else
473 rc = GPG_ERR_TOO_SHORT;
475 pthread_cleanup_pop(1);
477 else
478 rc = GPG_ERR_ENOMEM;
480 pthread_cleanup_pop(1);
481 return rc;