]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/libstrongswan/utils/utils.c
pki: Switch to binary mode on Windows when reading/writing DER to FDs
[people/ms/strongswan.git] / src / libstrongswan / utils / utils.c
CommitLineData
552cc11b 1/*
766141bc 2 * Copyright (C) 2008-2014 Tobias Brunner
552cc11b
MW
3 * Copyright (C) 2005-2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
552cc11b
MW
15 */
16
766141bc 17#define _GNU_SOURCE /* for memrchr */
4de7401a
MW
18#ifdef WIN32
19/* for GetTickCount64, Windows 7 */
20# define _WIN32_WINNT 0x0601
21#endif
22
23#include "utils.h"
24
6c20579a 25#include <sys/stat.h>
552cc11b 26#include <string.h>
552cc11b 27#include <stdio.h>
6c20579a 28#include <unistd.h>
876961cf 29#include <inttypes.h>
74b14b40 30#include <stdint.h>
d24a74c5 31#include <limits.h>
6c20579a 32#include <dirent.h>
f464d750 33#include <time.h>
552cc11b 34
f1c9653e
MW
35#include <library.h>
36#include <utils/debug.h>
37#include <utils/chunk.h>
38#include <collections/enumerator.h>
39#include <threading/spinlock.h>
552cc11b 40
a8809bb0 41ENUM(status_names, SUCCESS, NEED_MORE,
552cc11b
MW
42 "SUCCESS",
43 "FAILED",
44 "OUT_OF_RES",
45 "ALREADY_DONE",
46 "NOT_SUPPORTED",
47 "INVALID_ARG",
48 "NOT_FOUND",
49 "PARSE_ERROR",
50 "VERIFY_ERROR",
51 "INVALID_STATE",
52 "DESTROY_ME",
53 "NEED_MORE",
54);
55
552cc11b
MW
56/**
57 * Described in header.
58 */
01e43e31 59void memxor(u_int8_t dst[], u_int8_t src[], size_t n)
552cc11b 60{
01e43e31 61 int m, i;
7daf5226 62
01e43e31 63 /* byte wise XOR until dst aligned */
09846603 64 for (i = 0; (uintptr_t)&dst[i] % sizeof(long) && i < n; i++)
4fd233a7 65 {
01e43e31 66 dst[i] ^= src[i];
4fd233a7 67 }
01e43e31 68 /* try to use words if src shares an aligment with dst */
74b14b40 69 switch (((uintptr_t)&src[i] % sizeof(long)))
552cc11b 70 {
01e43e31
MW
71 case 0:
72 for (m = n - sizeof(long); i <= m; i += sizeof(long))
73 {
74 *(long*)&dst[i] ^= *(long*)&src[i];
75 }
76 break;
77 case sizeof(int):
78 for (m = n - sizeof(int); i <= m; i += sizeof(int))
79 {
80 *(int*)&dst[i] ^= *(int*)&src[i];
81 }
82 break;
83 case sizeof(short):
84 for (m = n - sizeof(short); i <= m; i += sizeof(short))
85 {
86 *(short*)&dst[i] ^= *(short*)&src[i];
87 }
88 break;
89 default:
90 break;
91 }
92 /* byte wise XOR of the rest */
93 for (; i < n; i++)
94 {
95 dst[i] ^= src[i];
552cc11b
MW
96 }
97}
98
ed678b52
MW
99/**
100 * Described in header.
101 */
102void memwipe_noinline(void *ptr, size_t n)
103{
104 memwipe_inline(ptr, n);
105}
106
81736d7d
TB
107/**
108 * Described in header.
109 */
110void *memstr(const void *haystack, const char *needle, size_t n)
111{
2ed241ae 112 const u_char *pos = haystack;
7b91011d
TB
113 size_t l;
114
115 if (!haystack || !needle || (l = strlen(needle)) == 0)
116 {
117 return NULL;
118 }
81736d7d
TB
119 for (; n >= l; ++pos, --n)
120 {
121 if (memeq(pos, needle, l))
122 {
123 return (void*)pos;
124 }
125 }
126 return NULL;
127}
128
2ed241ae
TB
129/**
130 * Described in header.
131 */
132void *utils_memrchr(const void *s, int c, size_t n)
133{
134 const u_char *pos;
135
136 if (!s || !n)
137 {
138 return NULL;
139 }
140
141 for (pos = s + n - 1; pos >= (u_char*)s; pos--)
142 {
143 if (*pos == (u_char)c)
144 {
145 return (void*)pos;
146 }
147 }
148 return NULL;
149}
150
d543d9ca
TB
151/**
152 * Described in header.
153 */
154char* translate(char *str, const char *from, const char *to)
155{
156 char *pos = str;
157 if (strlen(from) != strlen(to))
158 {
159 return str;
160 }
161 while (pos && *pos)
162 {
163 char *match;
164 if ((match = strchr(from, *pos)) != NULL)
165 {
166 *pos = to[match - from];
167 }
168 pos++;
169 }
170 return str;
ccb6758e
TB
171}
172
173/**
174 * Described in header.
175 */
176char* strreplace(const char *str, const char *search, const char *replace)
177{
178 size_t len, slen, rlen, count = 0;
179 char *res, *pos, *found, *dst;
180
181 if (!str || !*str || !search || !*search || !replace)
182 {
183 return (char*)str;
184 }
185 slen = strlen(search);
186 rlen = strlen(replace);
187 if (slen != rlen)
188 {
189 for (pos = (char*)str; (pos = strstr(pos, search)); pos += slen)
190 {
191 found = pos;
192 count++;
193 }
194 if (!count)
195 {
196 return (char*)str;
197 }
198 len = (found - str) + strlen(found) + count * (rlen - slen);
199 }
200 else
201 {
202 len = strlen(str);
203 }
204 found = strstr(str, search);
205 if (!found)
206 {
207 return (char*)str;
208 }
209 dst = res = malloc(len + 1);
210 pos = (char*)str;
211 do
212 {
213 len = found - pos;
214 memcpy(dst, pos, len);
215 dst += len;
216 memcpy(dst, replace, rlen);
217 dst += rlen;
218 pos = found + slen;
219 }
220 while ((found = strstr(pos, search)));
221 strcpy(dst, pos);
222 return res;
d543d9ca
TB
223}
224
766141bc
TB
225/**
226 * Described in header.
227 */
228char* path_dirname(const char *path)
229{
230 char *pos;
231
8182631b 232 pos = path ? strrchr(path, DIRECTORY_SEPARATOR[0]) : NULL;
766141bc
TB
233
234 if (pos && !pos[1])
235 { /* if path ends with slashes we have to look beyond them */
8182631b 236 while (pos > path && *pos == DIRECTORY_SEPARATOR[0])
766141bc
TB
237 { /* skip trailing slashes */
238 pos--;
239 }
8182631b 240 pos = memrchr(path, DIRECTORY_SEPARATOR[0], pos - path + 1);
766141bc
TB
241 }
242 if (!pos)
243 {
2496eaff
MW
244#ifdef WIN32
245 if (path && strlen(path))
246 {
247 if ((isalpha(path[0]) && path[1] == ':'))
248 { /* if just a drive letter given, return that as dirname */
249 return chunk_clone(chunk_from_chars(path[0], ':', 0)).ptr;
250 }
251 }
252#endif
766141bc
TB
253 return strdup(".");
254 }
8182631b 255 while (pos > path && *pos == DIRECTORY_SEPARATOR[0])
766141bc
TB
256 { /* skip superfluous slashes */
257 pos--;
258 }
259 return strndup(path, pos - path + 1);
260}
261
262/**
263 * Described in header.
264 */
265char* path_basename(const char *path)
266{
267 char *pos, *trail = NULL;
268
269 if (!path || !*path)
270 {
271 return strdup(".");
272 }
8182631b 273 pos = strrchr(path, DIRECTORY_SEPARATOR[0]);
766141bc
TB
274 if (pos && !pos[1])
275 { /* if path ends with slashes we have to look beyond them */
8182631b 276 while (pos > path && *pos == DIRECTORY_SEPARATOR[0])
766141bc
TB
277 { /* skip trailing slashes */
278 pos--;
279 }
8182631b 280 if (pos == path && *pos == DIRECTORY_SEPARATOR[0])
766141bc 281 { /* contains only slashes */
8182631b 282 return strdup(DIRECTORY_SEPARATOR);
766141bc
TB
283 }
284 trail = pos + 1;
8182631b 285 pos = memrchr(path, DIRECTORY_SEPARATOR[0], trail - path);
766141bc
TB
286 }
287 pos = pos ? pos + 1 : (char*)path;
288 return trail ? strndup(pos, trail - pos) : strdup(pos);
289}
290
67b3bcd1
MW
291/**
292 * Described in header.
293 */
294bool path_absolute(const char *path)
295{
296 if (!path)
297 {
298 return FALSE;
299 }
300#ifdef WIN32
301 if (strpfx(path, "\\\\"))
302 { /* UNC */
303 return TRUE;
304 }
305 if (strlen(path) && isalpha(path[0]) && path[1] == ':')
306 { /* drive letter */
307 return TRUE;
308 }
309#else /* !WIN32 */
310 if (path[0] == DIRECTORY_SEPARATOR[0])
311 {
312 return TRUE;
313 }
314#endif
315 return FALSE;
316}
317
6c20579a
TB
318/**
319 * Described in header.
320 */
321bool mkdir_p(const char *path, mode_t mode)
322{
fc1afcc8 323 int len;
6c20579a
TB
324 char *pos, full[PATH_MAX];
325 pos = full;
326 if (!path || *path == '\0')
327 {
328 return TRUE;
329 }
330 len = snprintf(full, sizeof(full)-1, "%s", path);
331 if (len < 0 || len >= sizeof(full)-1)
332 {
8b0e0910 333 DBG1(DBG_LIB, "path string %s too long", path);
6c20579a
TB
334 return FALSE;
335 }
336 /* ensure that the path ends with a '/' */
337 if (full[len-1] != '/')
338 {
339 full[len++] = '/';
340 full[len] = '\0';
341 }
342 /* skip '/' at the beginning */
343 while (*pos == '/')
344 {
345 pos++;
346 }
347 while ((pos = strchr(pos, '/')))
348 {
349 *pos = '\0';
350 if (access(full, F_OK) < 0)
351 {
a3f7dfc1
MW
352#ifdef WIN32
353 if (_mkdir(full) < 0)
354#else
6c20579a 355 if (mkdir(full, mode) < 0)
a3f7dfc1 356#endif
6c20579a 357 {
8b0e0910 358 DBG1(DBG_LIB, "failed to create directory %s", full);
6c20579a
TB
359 return FALSE;
360 }
361 }
362 *pos = '/';
363 pos++;
364 }
365 return TRUE;
366}
367
4d174272
MW
368ENUM(tty_color_names, TTY_RESET, TTY_BG_DEF,
369 "\e[0m",
370 "\e[1m",
371 "\e[4m",
372 "\e[5m",
373 "\e[30m",
374 "\e[31m",
375 "\e[32m",
376 "\e[33m",
377 "\e[34m",
378 "\e[35m",
379 "\e[36m",
380 "\e[37m",
381 "\e[39m",
382 "\e[40m",
383 "\e[41m",
384 "\e[42m",
385 "\e[43m",
386 "\e[44m",
387 "\e[45m",
388 "\e[46m",
389 "\e[47m",
390 "\e[49m",
391);
392
393/**
394 * Get the escape string for a given TTY color, empty string on non-tty FILE
395 */
396char* tty_escape_get(int fd, tty_escape_t escape)
397{
398 if (!isatty(fd))
399 {
400 return "";
401 }
402 switch (escape)
403 {
404 case TTY_RESET:
405 case TTY_BOLD:
406 case TTY_UNDERLINE:
407 case TTY_BLINKING:
1f2b8c8c
MW
408#ifdef WIN32
409 return "";
410#endif
4d174272
MW
411 case TTY_FG_BLACK:
412 case TTY_FG_RED:
413 case TTY_FG_GREEN:
414 case TTY_FG_YELLOW:
415 case TTY_FG_BLUE:
416 case TTY_FG_MAGENTA:
417 case TTY_FG_CYAN:
418 case TTY_FG_WHITE:
419 case TTY_FG_DEF:
420 case TTY_BG_BLACK:
421 case TTY_BG_RED:
422 case TTY_BG_GREEN:
423 case TTY_BG_YELLOW:
424 case TTY_BG_BLUE:
425 case TTY_BG_MAGENTA:
426 case TTY_BG_CYAN:
427 case TTY_BG_WHITE:
428 case TTY_BG_DEF:
429 return enum_to_name(tty_color_names, escape);
1f2b8c8c 430 /* warn if a escape code is missing */
4d174272
MW
431 }
432 return "";
433}
2a595276 434
9a8fdc15
TB
435#ifndef HAVE_CLOSEFROM
436/**
437 * Described in header.
438 */
439void closefrom(int lowfd)
440{
5051bd23
TB
441 char fd_dir[PATH_MAX];
442 int maxfd, fd, len;
443
444 /* try to close only open file descriptors on Linux... */
445 len = snprintf(fd_dir, sizeof(fd_dir), "/proc/%u/fd", getpid());
4a4cf41b 446 if (len > 0 && len < sizeof(fd_dir) && access(fd_dir, F_OK) == 0)
5051bd23
TB
447 {
448 enumerator_t *enumerator = enumerator_create_directory(fd_dir);
449 if (enumerator)
450 {
68fcf917 451 char *rel;
5051bd23
TB
452 while (enumerator->enumerate(enumerator, &rel, NULL, NULL))
453 {
454 fd = atoi(rel);
455 if (fd >= lowfd)
456 {
457 close(fd);
458 }
459 }
460 enumerator->destroy(enumerator);
461 return;
462 }
463 }
464
465 /* ...fall back to closing all fds otherwise */
d3c30b35
MW
466#ifdef WIN32
467 maxfd = _getmaxstdio();
468#else
9a8fdc15 469 maxfd = (int)sysconf(_SC_OPEN_MAX);
d3c30b35 470#endif
9a8fdc15
TB
471 if (maxfd < 0)
472 {
473 maxfd = 256;
474 }
475 for (fd = lowfd; fd < maxfd; fd++)
476 {
477 close(fd);
478 }
479}
480#endif /* HAVE_CLOSEFROM */
481
3f310c0d
MW
482/**
483 * Return monotonic time
484 */
485time_t time_monotonic(timeval_t *tv)
486{
4de7401a
MW
487#ifdef WIN32
488 ULONGLONG ms;
489 time_t s;
490
491 ms = GetTickCount64();
492 s = ms / 1000;
493 if (tv)
494 {
495 tv->tv_sec = s;
496 tv->tv_usec = (ms - (s * 1000)) * 1000;
497 }
498 return s;
499#else /* !WIN32 */
b2944d71
TB
500#if defined(HAVE_CLOCK_GETTIME) && \
501 (defined(HAVE_CONDATTR_CLOCK_MONOTONIC) || \
502 defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
3d5818ec
MW
503 /* as we use time_monotonic() for condvar operations, we use the
504 * monotonic time source only if it is also supported by pthread. */
3f310c0d 505 timespec_t ts;
7daf5226 506
3f310c0d
MW
507 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
508 {
509 if (tv)
510 {
511 tv->tv_sec = ts.tv_sec;
512 tv->tv_usec = ts.tv_nsec / 1000;
513 }
514 return ts.tv_sec;
515 }
b2944d71 516#endif /* HAVE_CLOCK_GETTIME && (...) */
3f310c0d
MW
517 /* Fallback to non-monotonic timestamps:
518 * On MAC OS X, creating monotonic timestamps is rather difficult. We
519 * could use mach_absolute_time() and catch sleep/wakeup notifications.
3d5818ec
MW
520 * We stick to the simpler (non-monotonic) gettimeofday() for now.
521 * But keep in mind: we need the same time source here as in condvar! */
3f310c0d
MW
522 if (!tv)
523 {
524 return time(NULL);
525 }
526 if (gettimeofday(tv, NULL) != 0)
527 { /* should actually never fail if passed pointers are valid */
528 return -1;
529 }
530 return tv->tv_sec;
4de7401a 531#endif /* !WIN32 */
3f310c0d
MW
532}
533
081ae2eb
MW
534/**
535 * return null
536 */
537void *return_null()
538{
539 return NULL;
540}
541
da17b016
MW
542/**
543 * returns TRUE
544 */
545bool return_true()
546{
547 return TRUE;
548}
549
550/**
551 * returns FALSE
552 */
553bool return_false()
554{
555 return FALSE;
556}
557
502edf42
MW
558/**
559 * returns FAILED
560 */
561status_t return_failed()
562{
563 return FAILED;
564}
565
4755ab50
MW
566/**
567 * returns SUCCESS
568 */
569status_t return_success()
570{
571 return SUCCESS;
572}
573
233b853d
MW
574/**
575 * nop operation
576 */
577void nop()
578{
579}
580
0f603d42 581#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
efd0fe21 582
552cc11b 583/**
f1c9653e 584 * Spinlock for ref_get/put
552cc11b 585 */
f1c9653e 586static spinlock_t *ref_lock;
552cc11b
MW
587
588/**
efd0fe21 589 * Increase refcount
552cc11b 590 */
3160b92a 591refcount_t ref_get(refcount_t *ref)
552cc11b 592{
3160b92a
MW
593 refcount_t current;
594
f1c9653e 595 ref_lock->lock(ref_lock);
3160b92a 596 current = ++(*ref);
f1c9653e
MW
597 ref_lock->unlock(ref_lock);
598
3160b92a 599 return current;
552cc11b
MW
600}
601
602/**
efd0fe21 603 * Decrease refcount
552cc11b
MW
604 */
605bool ref_put(refcount_t *ref)
606{
607 bool more_refs;
7daf5226 608
f1c9653e 609 ref_lock->lock(ref_lock);
21f411b8 610 more_refs = --(*ref) > 0;
f1c9653e 611 ref_lock->unlock(ref_lock);
552cc11b
MW
612 return !more_refs;
613}
5317dd68 614
efedd0d2
TB
615/**
616 * Current refcount
617 */
618refcount_t ref_cur(refcount_t *ref)
619{
620 refcount_t current;
621
f1c9653e 622 ref_lock->lock(ref_lock);
efedd0d2 623 current = *ref;
f1c9653e
MW
624 ref_lock->unlock(ref_lock);
625
efedd0d2
TB
626 return current;
627}
628
5317dd68 629/**
f1c9653e 630 * Spinlock for all compare and swap operations.
5317dd68 631 */
f1c9653e 632static spinlock_t *cas_lock;
5317dd68
TB
633
634/**
635 * Compare and swap if equal to old value
636 */
637#define _cas_impl(name, type) \
638bool cas_##name(type *ptr, type oldval, type newval) \
639{ \
640 bool swapped; \
f1c9653e 641 cas_lock->lock(cas_lock); \
5317dd68 642 if ((swapped = (*ptr == oldval))) { *ptr = newval; } \
f1c9653e 643 cas_lock->unlock(cas_lock); \
5317dd68
TB
644 return swapped; \
645}
646
647_cas_impl(bool, bool)
648_cas_impl(ptr, void*)
649
0f603d42 650#endif /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
552cc11b 651
2077d996 652
9df621d2 653#ifdef HAVE_FMEMOPEN_FALLBACK
2077d996
MW
654
655static int fmemread(chunk_t *cookie, char *buf, int size)
656{
657 int len;
658
659 len = min(size, cookie->len);
660 memcpy(buf, cookie->ptr, len);
661 *cookie = chunk_skip(*cookie, len);
662
663 return len;
664}
665
666static int fmemwrite(chunk_t *cookie, const char *buf, int size)
667{
668 int len;
669
670 len = min(size, cookie->len);
671 memcpy(cookie->ptr, buf, len);
672 *cookie = chunk_skip(*cookie, len);
673
674 return len;
675}
676
677static int fmemclose(void *cookie)
678{
679 free(cookie);
680 return 0;
681}
682
683FILE *fmemopen(void *buf, size_t size, const char *mode)
684{
685 chunk_t *cookie;
686
687 INIT(cookie,
688 .ptr = buf,
689 .len = size,
690 );
691
692 return funopen(cookie, (void*)fmemread, (void*)fmemwrite, NULL, fmemclose);
693}
694
695#endif /* FMEMOPEN fallback*/
696
f1c9653e
MW
697/**
698 * See header
699 */
700void utils_init()
701{
702#ifdef WIN32
703 windows_init();
704#endif
705
706#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
707 ref_lock = spinlock_create();
708 cas_lock = spinlock_create();
709#endif
710
711 strerror_init();
712}
713
714/**
715 * See header
716 */
717void utils_deinit()
718{
719#ifdef WIN32
720 windows_deinit();
721#endif
722
723#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
724 ref_lock->destroy(ref_lock);
725 cas_lock->destroy(cas_lock);
726#endif
727
728 strerror_deinit();
729}
730
552cc11b 731/**
d25ce370 732 * Described in header.
552cc11b 733 */
1b40b74d 734int time_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
d25ce370 735 const void *const *args)
552cc11b
MW
736{
737 static const char* months[] = {
738 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
739 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
740 };
741 time_t *time = *((time_t**)(args[0]));
13f2d3a2 742 bool utc = *((int*)(args[1]));
8f129319 743 struct tm t, *ret = NULL;
7daf5226 744
8f129319 745 if (*time != UNDEFINED_TIME)
552cc11b 746 {
8f129319
MW
747 if (utc)
748 {
749 ret = gmtime_r(time, &t);
750 }
751 else
752 {
753 ret = localtime_r(time, &t);
754 }
552cc11b 755 }
8f129319 756 if (ret == NULL)
552cc11b 757 {
8f129319
MW
758 return print_in_hook(data, "--- -- --:--:--%s----",
759 utc ? " UTC " : " ");
552cc11b 760 }
1b40b74d 761 return print_in_hook(data, "%s %02d %02d:%02d:%02d%s%04d",
d25ce370
TB
762 months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min,
763 t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900);
552cc11b
MW
764}
765
766/**
d25ce370 767 * Described in header.
552cc11b 768 */
1b40b74d 769int time_delta_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
d25ce370 770 const void *const *args)
552cc11b
MW
771{
772 char* unit = "second";
d25ce370
TB
773 time_t *arg1 = *((time_t**)(args[0]));
774 time_t *arg2 = *((time_t**)(args[1]));
876961cf 775 u_int64_t delta = llabs(*arg1 - *arg2);
7daf5226 776
552cc11b
MW
777 if (delta > 2 * 60 * 60 * 24)
778 {
779 delta /= 60 * 60 * 24;
780 unit = "day";
781 }
782 else if (delta > 2 * 60 * 60)
783 {
784 delta /= 60 * 60;
785 unit = "hour";
786 }
787 else if (delta > 2 * 60)
788 {
789 delta /= 60;
790 unit = "minute";
791 }
1b40b74d 792 return print_in_hook(data, "%" PRIu64 " %s%s", delta, unit,
876961cf 793 (delta == 1) ? "" : "s");
552cc11b
MW
794}
795
796/**
797 * Number of bytes per line to dump raw data
798 */
799#define BYTES_PER_LINE 16
800
801static char hexdig_upper[] = "0123456789ABCDEF";
802
803/**
d25ce370 804 * Described in header.
552cc11b 805 */
1b40b74d 806int mem_printf_hook(printf_hook_data_t *data,
d25ce370 807 printf_hook_spec_t *spec, const void *const *args)
552cc11b
MW
808{
809 char *bytes = *((void**)(args[0]));
817ab8a8 810 u_int len = *((int*)(args[1]));
7daf5226 811
552cc11b
MW
812 char buffer[BYTES_PER_LINE * 3];
813 char ascii_buffer[BYTES_PER_LINE + 1];
814 char *buffer_pos = buffer;
815 char *bytes_pos = bytes;
816 char *bytes_roof = bytes + len;
817 int line_start = 0;
818 int i = 0;
819 int written = 0;
7daf5226 820
1b40b74d 821 written += print_in_hook(data, "=> %u bytes @ %p", len, bytes);
7daf5226 822
552cc11b
MW
823 while (bytes_pos < bytes_roof)
824 {
825 *buffer_pos++ = hexdig_upper[(*bytes_pos >> 4) & 0xF];
826 *buffer_pos++ = hexdig_upper[ *bytes_pos & 0xF];
827
828 ascii_buffer[i++] =
829 (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.';
830
7daf5226 831 if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE)
552cc11b
MW
832 {
833 int padding = 3 * (BYTES_PER_LINE - i);
7daf5226 834
552cc11b
MW
835 while (padding--)
836 {
837 *buffer_pos++ = ' ';
838 }
839 *buffer_pos++ = '\0';
840 ascii_buffer[i] = '\0';
7daf5226 841
1b40b74d 842 written += print_in_hook(data, "\n%4d: %s %s",
323f9f99 843 line_start, buffer, ascii_buffer);
7daf5226 844
552cc11b
MW
845 buffer_pos = buffer;
846 line_start += BYTES_PER_LINE;
847 i = 0;
848 }
849 else
850 {
851 *buffer_pos++ = ' ';
852 }
853 }
854 return written;
855}