diff --git a/src/conftest/conftest.c b/src/conftest/conftest.c index ac6d697a5..584a2698a 100644 --- a/src/conftest/conftest.c +++ b/src/conftest/conftest.c @@ -81,7 +81,7 @@ static bool load_configs(char *suite_file, char *test_file) } conftest->test = settings_create(suite_file); conftest->test->load_files(conftest->test, test_file, TRUE); - conftest->suite_dir = strdup(dirname(suite_file)); + conftest->suite_dir = path_dirname(suite_file); return TRUE; } diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c index ff93c94d0..f908219ed 100644 --- a/src/libcharon/plugins/stroke/stroke_cred.c +++ b/src/libcharon/plugins/stroke/stroke_cred.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -1158,8 +1157,7 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets, } else { /* use directory of current file if relative */ - dir = strdup(file); - dir = dirname(dir); + dir = path_dirname(file); if (line.len + 1 + strlen(dir) + 1 > sizeof(pattern)) { diff --git a/src/libpts/plugins/imv_attestation/attest.c b/src/libpts/plugins/imv_attestation/attest.c index 6e63c2653..b8a6854cb 100644 --- a/src/libpts/plugins/imv_attestation/attest.c +++ b/src/libpts/plugins/imv_attestation/attest.c @@ -266,19 +266,20 @@ static void do_args(int argc, char *argv[]) continue; case 'F': { - char *path = strdup(optarg); - char *dir = dirname(path); - char *file = basename(optarg); + char *dir = path_dirname(optarg); + char *file = path_basename(optarg); if (*dir != '.') { if (!attest->set_directory(attest, dir, op == OP_ADD)) { - free(path); + free(file); + free(dir); exit(EXIT_FAILURE); } } - free(path); + free(file); + free(dir); if (!attest->set_file(attest, file, op == OP_ADD)) { exit(EXIT_FAILURE); diff --git a/src/libpts/pts/pts.c b/src/libpts/pts/pts.c index f528d4520..8699282f0 100644 --- a/src/libpts/pts/pts.c +++ b/src/libpts/pts/pts.c @@ -627,7 +627,7 @@ METHOD(pts_t, get_metadata, pts_file_meta_t*, metadata->destroy(metadata); return NULL; } - entry->filename = strdup(basename(pathname)); + entry->filename = path_basename(pathname); metadata->add(metadata, entry); } diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c index 95b1114f6..07e8ae1da 100644 --- a/src/libpts/pts/pts_database.c +++ b/src/libpts/pts/pts_database.c @@ -249,7 +249,7 @@ METHOD(pts_database_t, check_file_measurement, status_t, enumerator_t *e; chunk_t hash; status_t status = NOT_FOUND; - char *path, *dir, *file; + char *dir, *file; if (strlen(filename) < 1) { @@ -257,9 +257,8 @@ METHOD(pts_database_t, check_file_measurement, status_t, } /* separate filename into directory and basename components */ - path = strdup(filename); - dir = dirname(path); - file = basename(filename); + dir = path_dirname(filename); + file = path_basename(filename); if (*dir == '.') { /* relative pathname */ @@ -281,7 +280,8 @@ METHOD(pts_database_t, check_file_measurement, status_t, DB_TEXT, dir, DB_INT); if (!e) { - free(path); + free(file); + free(dir); return FAILED; } dir_found = e->enumerate(e, &did); @@ -289,7 +289,8 @@ METHOD(pts_database_t, check_file_measurement, status_t, if (!dir_found) { - free(path); + free(file); + free(dir); return NOT_FOUND; } @@ -301,7 +302,8 @@ METHOD(pts_database_t, check_file_measurement, status_t, DB_TEXT, product, DB_INT, did, DB_TEXT, file, DB_INT, algo, DB_BLOB); } - free(path); + free(file); + free(dir); if (!e) { diff --git a/src/libpts/pts/pts_file_meas.c b/src/libpts/pts/pts_file_meas.c index f684087d7..77a0957bb 100644 --- a/src/libpts/pts/pts_file_meas.c +++ b/src/libpts/pts/pts_file_meas.c @@ -341,9 +341,10 @@ pts_file_meas_t *pts_file_meas_create_from_path(u_int16_t request_id, success = FALSE; goto end; } - filename = use_rel_name ? basename(pathname) : pathname; + filename = use_rel_name ? path_basename(pathname) : strdup(pathname); DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); add(this, filename, measurement); + free(filename); } end: diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index 492522ff5..440913071 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -36,7 +36,8 @@ selectors/traffic_selector.c threading/thread.c threading/thread_value.c \ threading/mutex.c threading/semaphore.c threading/rwlock.c threading/spinlock.c \ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \ utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \ -utils/printf_hook/printf_hook_builtin.c utils/settings.c utils/test.c +utils/printf_hook/printf_hook_builtin.c utils/settings.c utils/test.c \ +utils/utils/strerror.c # adding the plugin source files diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 28d78df31..b3a4eda99 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -34,7 +34,8 @@ selectors/traffic_selector.c threading/thread.c threading/thread_value.c \ threading/mutex.c threading/semaphore.c threading/rwlock.c threading/spinlock.c \ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \ utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \ -utils/settings.c utils/test.c +utils/settings.c utils/test.c \ +utils/utils/strerror.c if USE_DEV_HEADERS strongswan_includedir = ${dev_headers} @@ -82,7 +83,8 @@ utils/utils.h utils/chunk.h utils/debug.h utils/enum.h utils/identification.h \ utils/lexparser.h utils/optionsfrom.h utils/capabilities.h utils/backtrace.h \ utils/leak_detective.h utils/printf_hook/printf_hook.h \ utils/printf_hook/printf_hook_vstr.h utils/printf_hook/printf_hook_builtin.h \ -utils/settings.h utils/test.h utils/integrity_checker.h +utils/settings.h utils/test.h utils/integrity_checker.h \ +utils/utils/strerror.h endif library.lo : $(top_builddir)/config.status diff --git a/src/libstrongswan/tests/suites/test_utils.c b/src/libstrongswan/tests/suites/test_utils.c index 2d290f81e..92f65596a 100644 --- a/src/libstrongswan/tests/suites/test_utils.c +++ b/src/libstrongswan/tests/suites/test_utils.c @@ -467,6 +467,57 @@ START_TEST(test_strreplace) } END_TEST +/******************************************************************************* + * path_dirname/basename + */ + +static struct { + char *path; + char *dir; + char *base; +} path_data[] = { + {NULL, ".", "."}, + {"", ".", "."}, + {".", ".", "."}, + {"..", ".", ".."}, + {"/", "/", "/"}, + {"//", "/", "/"}, + {"foo", ".", "foo"}, + {"f/", ".", "f"}, + {"foo/", ".", "foo"}, + {"foo//", ".", "foo"}, + {"/f", "/", "f"}, + {"/f/", "/", "f"}, + {"/foo", "/", "foo"}, + {"/foo/", "/", "foo"}, + {"//foo/", "/", "foo"}, + {"foo/bar", "foo", "bar"}, + {"foo//bar", "foo", "bar"}, + {"/foo/bar", "/foo", "bar"}, + {"/foo/bar/", "/foo", "bar"}, + {"/foo/bar/baz", "/foo/bar", "baz"}, +}; + +START_TEST(test_path_dirname) +{ + char *dir; + + dir = path_dirname(path_data[_i].path); + ck_assert_str_eq(path_data[_i].dir, dir); + free(dir); +} +END_TEST + +START_TEST(test_path_basename) +{ + char *base; + + base = path_basename(path_data[_i].path); + ck_assert_str_eq(path_data[_i].base, base); + free(base); +} +END_TEST + /******************************************************************************* * time_printf_hook */ @@ -630,6 +681,11 @@ Suite *utils_suite_create() tcase_add_loop_test(tc, test_strreplace, 0, countof(strreplace_data)); suite_add_tcase(s, tc); + tc = tcase_create("path_dirname/basename"); + tcase_add_loop_test(tc, test_path_dirname, 0, countof(path_data)); + tcase_add_loop_test(tc, test_path_basename, 0, countof(path_data)); + suite_add_tcase(s, tc); + tc = tcase_create("printf_hooks"); tcase_add_loop_test(tc, test_time_printf_hook, 0, countof(time_data)); tcase_add_loop_test(tc, test_time_delta_printf_hook, 0, countof(time_delta_data)); diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 6f5a2c87a..82eadcb97 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -499,7 +499,7 @@ static bool register_hooks() char *whitelist[] = { /* backtraces, including own */ "backtrace_create", - "safe_strerror", + "strerror_safe", /* pthread stuff */ "pthread_create", "pthread_setspecific", diff --git a/src/libstrongswan/utils/settings.c b/src/libstrongswan/utils/settings.c index a2c892211..490490a1e 100644 --- a/src/libstrongswan/utils/settings.c +++ b/src/libstrongswan/utils/settings.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -1302,8 +1301,7 @@ static bool parse_files(linked_list_t *contents, char *file, int level, } else { /* base relative paths to the directory of the current file */ - char *dir = strdup(file); - dir = dirname(dir); + char *dir = path_dirname(file); if (snprintf(pat, sizeof(pat), "%s/%s", dir, pattern) >= sizeof(pat)) { DBG1(DBG_LIB, "include pattern too long, ignored"); diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c index 77d875445..406c5c811 100644 --- a/src/libstrongswan/utils/utils.c +++ b/src/libstrongswan/utils/utils.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 Tobias Brunner + * Copyright (C) 2008-2014 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -14,8 +14,7 @@ * for more details. */ -#include "utils.h" - +#define _GNU_SOURCE /* for memrchr */ #include #include #include @@ -27,6 +26,8 @@ #include #include +#include "utils.h" + #include "collections/enumerator.h" #include "utils/debug.h" #include "utils/chunk.h" @@ -193,6 +194,63 @@ char* strreplace(const char *str, const char *search, const char *replace) return res; } +/** + * Described in header. + */ +char* path_dirname(const char *path) +{ + char *pos; + + pos = path ? strrchr(path, '/') : NULL; + + if (pos && !pos[1]) + { /* if path ends with slashes we have to look beyond them */ + while (pos > path && *pos == '/') + { /* skip trailing slashes */ + pos--; + } + pos = memrchr(path, '/', pos - path + 1); + } + if (!pos) + { + return strdup("."); + } + while (pos > path && *pos == '/') + { /* skip superfluous slashes */ + pos--; + } + return strndup(path, pos - path + 1); +} + +/** + * Described in header. + */ +char* path_basename(const char *path) +{ + char *pos, *trail = NULL; + + if (!path || !*path) + { + return strdup("."); + } + pos = strrchr(path, '/'); + if (pos && !pos[1]) + { /* if path ends with slashes we have to look beyond them */ + while (pos > path && *pos == '/') + { /* skip trailing slashes */ + pos--; + } + if (pos == path && *pos == '/') + { /* contains only slashes */ + return strdup("/"); + } + trail = pos + 1; + pos = memrchr(path, '/', trail - path); + } + pos = pos ? pos + 1 : (char*)path; + return trail ? strndup(pos, trail - pos) : strdup(pos); +} + /** * Described in header. */ @@ -303,84 +361,6 @@ char* tty_escape_get(int fd, tty_escape_t escape) return ""; } -/** - * The size of the thread-specific error buffer - */ -#define STRERROR_BUF_LEN 256 - -/** - * Key to store thread-specific error buffer - */ -static pthread_key_t strerror_buf_key; - -/** - * Only initialize the key above once - */ -static pthread_once_t strerror_buf_key_once = PTHREAD_ONCE_INIT; - -/** - * Create the key used for the thread-specific error buffer - */ -static void create_strerror_buf_key() -{ - pthread_key_create(&strerror_buf_key, free); -} - -/** - * Retrieve the error buffer assigned to the current thread (or create it) - */ -static inline char *get_strerror_buf() -{ - char *buf; - - pthread_once(&strerror_buf_key_once, create_strerror_buf_key); - buf = pthread_getspecific(strerror_buf_key); - if (!buf) - { - buf = malloc(STRERROR_BUF_LEN); - pthread_setspecific(strerror_buf_key, buf); - } - return buf; -} - -#ifdef HAVE_STRERROR_R -/* - * Described in header. - */ -const char *safe_strerror(int errnum) -{ - char *buf = get_strerror_buf(), *msg; - -#ifdef STRERROR_R_CHAR_P - /* char* version which may or may not return the original buffer */ - msg = strerror_r(errnum, buf, STRERROR_BUF_LEN); -#else - /* int version returns 0 on success */ - msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf; -#endif - return msg; -} -#else /* HAVE_STRERROR_R */ -/* we actually wan't to call strerror(3) below */ -#undef strerror -/* - * Described in header. - */ -const char *safe_strerror(int errnum) -{ - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - char *buf = get_strerror_buf(); - - /* use a mutex to ensure calling strerror(3) is thread-safe */ - pthread_mutex_lock(&mutex); - strncpy(buf, strerror(errnum), STRERROR_BUF_LEN); - pthread_mutex_unlock(&mutex); - buf[STRERROR_BUF_LEN - 1] = '\0'; - return buf; -} -#endif /* HAVE_STRERROR_R */ - - #ifndef HAVE_CLOSEFROM /** * Described in header. diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h index 5cd0a34b1..4c113900e 100644 --- a/src/libstrongswan/utils/utils.h +++ b/src/libstrongswan/utils/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 Tobias Brunner + * Copyright (C) 2008-2014 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -30,6 +30,7 @@ #include #include "enum.h" +#include "utils/strerror.h" /** * strongSwan program return codes @@ -485,6 +486,32 @@ char *translate(char *str, const char *from, const char *to); */ char *strreplace(const char *str, const char *search, const char *replace); +/** + * Like dirname(3) returns the directory part of the given null-terminated + * pathname, up to but not including the final '/' (or '.' if no '/' is found). + * Trailing '/' are not counted as part of the pathname. + * + * The difference is that it does this in a thread-safe manner (i.e. it does not + * use static buffers) and does not modify the original path. + * + * @param path original pathname + * @return allocated directory component + */ +char *path_dirname(const char *path); + +/** + * Like basename(3) returns the filename part of the given null-terminated path, + * i.e. the part following the final '/' (or '.' if path is empty or NULL). + * Trailing '/' are not counted as part of the pathname. + * + * The difference is that it does this in a thread-safe manner (i.e. it does not + * use static buffers) and does not modify the original path. + * + * @param path original pathname + * @return allocated filename component + */ +char *path_basename(const char *path); + /** * Creates a directory and all required parent directories. * @@ -494,23 +521,6 @@ char *strreplace(const char *str, const char *search, const char *replace); */ bool mkdir_p(const char *path, mode_t mode); -/** - * Thread-safe wrapper around strerror and strerror_r. - * - * This is required because the first is not thread-safe (on some platforms) - * and the second uses two different signatures (POSIX/GNU) and is impractical - * to use anyway. - * - * @param errnum error code (i.e. errno) - * @return error message - */ -const char *safe_strerror(int errnum); - -/** - * Replace usages of strerror(3) with thread-safe variant. - */ -#define strerror(errnum) safe_strerror(errnum) - #ifndef HAVE_CLOSEFROM /** * Close open file descriptors greater than or equal to lowfd. diff --git a/src/libstrongswan/utils/utils/strerror.c b/src/libstrongswan/utils/utils/strerror.c new file mode 100644 index 000000000..95e463f5f --- /dev/null +++ b/src/libstrongswan/utils/utils/strerror.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012-2014 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include +#include + +#include "strerror.h" + +/** + * The size of the thread-specific error buffer + */ +#define STRERROR_BUF_LEN 256 + +/** + * Key to store thread-specific error buffer + */ +static pthread_key_t strerror_buf_key; + +/** + * Only initialize the key above once + */ +static pthread_once_t strerror_buf_key_once = PTHREAD_ONCE_INIT; + +/** + * Create the key used for the thread-specific error buffer + */ +static void create_strerror_buf_key() +{ + pthread_key_create(&strerror_buf_key, free); +} + +/** + * Retrieve the error buffer assigned to the current thread (or create it) + */ +static inline char *get_strerror_buf() +{ + char *buf; + + pthread_once(&strerror_buf_key_once, create_strerror_buf_key); + buf = pthread_getspecific(strerror_buf_key); + if (!buf) + { + buf = malloc(STRERROR_BUF_LEN); + pthread_setspecific(strerror_buf_key, buf); + } + return buf; +} + +#ifdef HAVE_STRERROR_R +/* + * Described in header. + */ +const char *strerror_safe(int errnum) +{ + char *buf = get_strerror_buf(), *msg; + +#ifdef STRERROR_R_CHAR_P + /* char* version which may or may not return the original buffer */ + msg = strerror_r(errnum, buf, STRERROR_BUF_LEN); +#else + /* int version returns 0 on success */ + msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf; +#endif + return msg; +} +#else /* HAVE_STRERROR_R */ +/* we actually wan't to call strerror(3) below */ +#undef strerror +/* + * Described in header. + */ +const char *strerror_safe(int errnum) +{ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + char *buf = get_strerror_buf(); + + /* use a mutex to ensure calling strerror(3) is thread-safe */ + pthread_mutex_lock(&mutex); + strncpy(buf, strerror(errnum), STRERROR_BUF_LEN); + pthread_mutex_unlock(&mutex); + buf[STRERROR_BUF_LEN - 1] = '\0'; + return buf; +} +#endif /* HAVE_STRERROR_R */ diff --git a/src/libstrongswan/utils/utils/strerror.h b/src/libstrongswan/utils/utils/strerror.h new file mode 100644 index 000000000..2cb76f12e --- /dev/null +++ b/src/libstrongswan/utils/utils/strerror.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012-2014 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @{ @ingroup utils + */ + +#ifndef STRERROR_H_ +#define STRERROR_H_ + +/** + * Thread-safe wrapper around strerror and strerror_r. + * + * This is required because the first is not thread-safe (on some platforms) + * and the second uses two different signatures (POSIX/GNU) and is impractical + * to use anyway. + * + * @param errnum error code (i.e. errno) + * @return error message + */ +const char *strerror_safe(int errnum); + +/** + * Replace usages of strerror(3) with thread-safe variant. + */ +#define strerror(errnum) strerror_safe(errnum) + +#endif /** STRERROR_H_ @}*/