From: Andre Noll Date: Sat, 11 Aug 2012 18:32:19 +0000 (+0200) Subject: Rename source files which also exist as system headers. X-Git-Tag: v0.1.5~6^2 X-Git-Url: http://git.tuebingen.mpg.de/?p=dss.git;a=commitdiff_plain;h=46cbddf465bd66ba1d5c4bcc780ae0d65abd7f73 Rename source files which also exist as system headers. As pointed out by Daniel Richard G. some of the dss header files are named the same as system header files. This patch renames these headers as well as their corresponding .c files. Specifically, error.h, fd.h, signal.h, string.h and time.h become err.h, file.h, sig.h, str.h and tv.h. --- diff --git a/Makefile b/Makefile index 1eb37af..bbe616a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -dss_objects := cmdline.o dss.o string.o fd.o exec.o signal.o daemon.o df.o time.o snap.o ipc.o +dss_objects := cmdline.o dss.o str.o file.o exec.o sig.o daemon.o df.o tv.o snap.o ipc.o all: dss man: dss.1 diff --git a/daemon.c b/daemon.c index d48e30c..2ea64ec 100644 --- a/daemon.c +++ b/daemon.c @@ -19,9 +19,9 @@ #include #include "gcc-compat.h" -#include "error.h" +#include "err.h" #include "log.h" -#include "string.h" +#include "str.h" /** * Do the usual stuff to become a daemon. diff --git a/df.c b/df.c index 513bd19..1356db2 100644 --- a/df.c +++ b/df.c @@ -12,8 +12,8 @@ #include "gcc-compat.h" #include "log.h" -#include "error.h" -#include "string.h" +#include "err.h" +#include "str.h" #include "df.h" int get_disk_space(const char *path, struct disk_space *result) diff --git a/dss.c b/dss.c index 745729f..d1a11e2 100644 --- a/dss.c +++ b/dss.c @@ -24,14 +24,14 @@ #include "gcc-compat.h" #include "cmdline.h" #include "log.h" -#include "string.h" -#include "error.h" -#include "fd.h" +#include "str.h" +#include "err.h" +#include "file.h" #include "exec.h" #include "daemon.h" -#include "signal.h" +#include "sig.h" #include "df.h" -#include "time.h" +#include "tv.h" #include "snap.h" #include "ipc.h" diff --git a/err.h b/err.h new file mode 100644 index 0000000..14cc032 --- /dev/null +++ b/err.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2006-2010 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ +extern char *dss_errlist[]; +extern char *dss_error_txt; + +__printf_2_3 void dss_log(int ll, const char* fmt,...); + +/** + * This bit indicates whether a number is considered a system error number + * If yes, the system errno is just the result of clearing this bit from + * the given number. + */ +#define SYSTEM_ERROR_BIT 30 + +/** Check whether the system error bit is set. */ +#define IS_SYSTEM_ERROR(num) (!!((num) & (1 << SYSTEM_ERROR_BIT))) + +/** Set the system error bit for the given number. */ +#define ERRNO_TO_DSS_ERROR(num) ((num) | (1 << SYSTEM_ERROR_BIT)) + +/** + * dss' version of strerror(3). + * + * \param num The error number. + * + * \return The error text of \a num. + */ +static inline char *dss_strerror(int num) +{ + assert(num > 0); + if (IS_SYSTEM_ERROR(num)) + return strerror((num) & ((1 << SYSTEM_ERROR_BIT) - 1)); + else + return dss_errlist[num]; +} + +#define DSS_ERRORS \ + DSS_ERROR(SUCCESS, "success"), \ + DSS_ERROR(SYNTAX, "syntax error"), \ + DSS_ERROR(ATOI_OVERFLOW, "value too large"), \ + DSS_ERROR(STRTOLL, "unknown strtoll error"), \ + DSS_ERROR(ATOI_NO_DIGITS, "no digits found in string"), \ + DSS_ERROR(ATOI_JUNK_AT_END, "further characters after number"), \ + DSS_ERROR(INVALID_NUMBER, "invalid number"), \ + DSS_ERROR(STRFTIME, "strftime() failed"), \ + DSS_ERROR(LOCALTIME, "localtime() failed"), \ + DSS_ERROR(NULL_OPEN, "can not open /dev/null"), \ + DSS_ERROR(DUP_PIPE, "exec error: can not create pipe"), \ + DSS_ERROR(INVOLUNTARY_EXIT, "unexpected termination cause"), \ + DSS_ERROR(BAD_EXIT_CODE, "unexpected exit code"), \ + DSS_ERROR(SIGNAL_SIG_ERR, "signal() returned SIG_ERR"), \ + DSS_ERROR(SIGNAL, "caught terminating signal"), \ + DSS_ERROR(BUG, "values of beta might cause dom!"), \ + DSS_ERROR(NOT_RUNNING, "dss not running") + +/** + * This is temporarily defined to expand to its first argument (prefixed by + * 'E_') and gets later redefined to expand to the error text only + */ +#define DSS_ERROR(err, msg) E_ ## err + +enum dss_error_codes { + DSS_ERRORS +}; +#undef DSS_ERROR +#define DSS_ERROR(err, msg) msg +#define DEFINE_DSS_ERRLIST char *dss_errlist[] = {DSS_ERRORS} diff --git a/error.h b/error.h deleted file mode 100644 index 14cc032..0000000 --- a/error.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2006-2010 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ -extern char *dss_errlist[]; -extern char *dss_error_txt; - -__printf_2_3 void dss_log(int ll, const char* fmt,...); - -/** - * This bit indicates whether a number is considered a system error number - * If yes, the system errno is just the result of clearing this bit from - * the given number. - */ -#define SYSTEM_ERROR_BIT 30 - -/** Check whether the system error bit is set. */ -#define IS_SYSTEM_ERROR(num) (!!((num) & (1 << SYSTEM_ERROR_BIT))) - -/** Set the system error bit for the given number. */ -#define ERRNO_TO_DSS_ERROR(num) ((num) | (1 << SYSTEM_ERROR_BIT)) - -/** - * dss' version of strerror(3). - * - * \param num The error number. - * - * \return The error text of \a num. - */ -static inline char *dss_strerror(int num) -{ - assert(num > 0); - if (IS_SYSTEM_ERROR(num)) - return strerror((num) & ((1 << SYSTEM_ERROR_BIT) - 1)); - else - return dss_errlist[num]; -} - -#define DSS_ERRORS \ - DSS_ERROR(SUCCESS, "success"), \ - DSS_ERROR(SYNTAX, "syntax error"), \ - DSS_ERROR(ATOI_OVERFLOW, "value too large"), \ - DSS_ERROR(STRTOLL, "unknown strtoll error"), \ - DSS_ERROR(ATOI_NO_DIGITS, "no digits found in string"), \ - DSS_ERROR(ATOI_JUNK_AT_END, "further characters after number"), \ - DSS_ERROR(INVALID_NUMBER, "invalid number"), \ - DSS_ERROR(STRFTIME, "strftime() failed"), \ - DSS_ERROR(LOCALTIME, "localtime() failed"), \ - DSS_ERROR(NULL_OPEN, "can not open /dev/null"), \ - DSS_ERROR(DUP_PIPE, "exec error: can not create pipe"), \ - DSS_ERROR(INVOLUNTARY_EXIT, "unexpected termination cause"), \ - DSS_ERROR(BAD_EXIT_CODE, "unexpected exit code"), \ - DSS_ERROR(SIGNAL_SIG_ERR, "signal() returned SIG_ERR"), \ - DSS_ERROR(SIGNAL, "caught terminating signal"), \ - DSS_ERROR(BUG, "values of beta might cause dom!"), \ - DSS_ERROR(NOT_RUNNING, "dss not running") - -/** - * This is temporarily defined to expand to its first argument (prefixed by - * 'E_') and gets later redefined to expand to the error text only - */ -#define DSS_ERROR(err, msg) E_ ## err - -enum dss_error_codes { - DSS_ERRORS -}; -#undef DSS_ERROR -#define DSS_ERROR(err, msg) msg -#define DEFINE_DSS_ERRLIST char *dss_errlist[] = {DSS_ERRORS} diff --git a/exec.c b/exec.c index adfd24d..36602df 100644 --- a/exec.c +++ b/exec.c @@ -15,8 +15,8 @@ #include "gcc-compat.h" #include "log.h" -#include "error.h" -#include "string.h" +#include "err.h" +#include "str.h" /** * Spawn a new process using execvp(). diff --git a/fd.c b/fd.c deleted file mode 100644 index 2b002c7..0000000 --- a/fd.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2006-2010 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "gcc-compat.h" -#include "error.h" -#include "string.h" - -/** - * Call a function for each subdirectory of the current working directory. - * - * \param dirname The directory to traverse. - * \param func The function to call for each subdirecrtory. - * \param private_data Pointer to an arbitrary data structure. - * - * For each top-level directory under \a dirname, the supplied function \a func is - * called. The full path of the subdirectory and the \a private_data pointer - * are passed to \a func. - * - * \return This function returns immediately if \a func returned a negative - * value. In this case \a func must set error_txt and this negative value is - * returned to the caller. Otherwise the function returns when all - * subdirectories have been passed to \a func. - */ - -int for_each_subdir(int (*func)(const char *, void *), void *private_data) -{ - struct dirent *entry; - int ret; - DIR *dir = opendir("."); - - if (!dir) - return -ERRNO_TO_DSS_ERROR(errno); - while ((entry = readdir(dir))) { - mode_t m; - struct stat s; - - if (!strcmp(entry->d_name, ".")) - continue; - if (!strcmp(entry->d_name, "..")) - continue; - ret = lstat(entry->d_name, &s) == -1; - if (ret == -1) { - ret = -ERRNO_TO_DSS_ERROR(errno); - goto out; - } - m = s.st_mode; - if (!S_ISDIR(m)) - continue; - ret = func(entry->d_name, private_data); - if (ret < 0) - goto out; - } - ret = 1; -out: - closedir(dir); - return ret; -} -/** - * Wrapper for chdir(2). - * - * \param path The specified directory. - * - * \return Standard. - */ -int dss_chdir(const char *path) -{ - if (chdir(path) >= 0) - return 1; - return -ERRNO_TO_DSS_ERROR(errno); -} - -/** - * Set a file descriptor to non-blocking mode. - * - * \param fd The file descriptor. - * - * \return Standard. - */ -__must_check int mark_fd_nonblocking(int fd) -{ - int flags = fcntl(fd, F_GETFL); - if (flags < 0) - return -ERRNO_TO_DSS_ERROR(errno); - flags = fcntl(fd, F_SETFL, ((long)flags) | O_NONBLOCK); - if (flags < 0) - return -ERRNO_TO_DSS_ERROR(errno); - return 1; -} - -/** - * dss' wrapper for select(2). - * - * It calls select(2) (with no exceptfds) and starts over if select() was - * interrupted by a signal. - * - * \param n The highest-numbered descriptor in any of the two sets, plus 1. - * \param readfds fds that should be checked for readability. - * \param writefds fds that should be checked for writablility. - * \param timeout_tv upper bound on the amount of time elapsed before select() - * returns. - * - * \return The return value of the underlying select() call on success, the - * negative system error code on errors. - * - * All arguments are passed verbatim to select(2). - * \sa select(2) select_tut(2). - */ -int dss_select(int n, fd_set *readfds, fd_set *writefds, - struct timeval *timeout_tv) -{ - int ret, err; - do { - ret = select(n, readfds, writefds, NULL, timeout_tv); - err = errno; - } while (ret < 0 && err == EINTR); - if (ret < 0) - return -ERRNO_TO_DSS_ERROR(errno); - return ret; -} diff --git a/fd.h b/fd.h deleted file mode 100644 index 991afd4..0000000 --- a/fd.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2006-2010 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ -int dss_chdir(const char *path); -int for_each_subdir(int (*func)(const char *, void *), void *private_data); -__must_check int mark_fd_nonblocking(int fd); -/** - * A wrapper for rename(2). - * - * \param old_path The source path. - * \param new_path The destination path. - * - * \return Standard. - * - * \sa rename(2). - */ -_static_inline_ int dss_rename(const char *old_path, const char *new_path) -{ - if (rename(old_path, new_path) >= 0) - return 1; - return -ERRNO_TO_DSS_ERROR(errno); -} - -int dss_select(int n, fd_set *readfds, fd_set *writefds, - struct timeval *timeout_tv); diff --git a/file.c b/file.c new file mode 100644 index 0000000..ea671b1 --- /dev/null +++ b/file.c @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2006-2010 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "gcc-compat.h" +#include "err.h" +#include "str.h" + +/** + * Call a function for each subdirectory of the current working directory. + * + * \param dirname The directory to traverse. + * \param func The function to call for each subdirecrtory. + * \param private_data Pointer to an arbitrary data structure. + * + * For each top-level directory under \a dirname, the supplied function \a func is + * called. The full path of the subdirectory and the \a private_data pointer + * are passed to \a func. + * + * \return This function returns immediately if \a func returned a negative + * value. In this case \a func must set error_txt and this negative value is + * returned to the caller. Otherwise the function returns when all + * subdirectories have been passed to \a func. + */ + +int for_each_subdir(int (*func)(const char *, void *), void *private_data) +{ + struct dirent *entry; + int ret; + DIR *dir = opendir("."); + + if (!dir) + return -ERRNO_TO_DSS_ERROR(errno); + while ((entry = readdir(dir))) { + mode_t m; + struct stat s; + + if (!strcmp(entry->d_name, ".")) + continue; + if (!strcmp(entry->d_name, "..")) + continue; + ret = lstat(entry->d_name, &s) == -1; + if (ret == -1) { + ret = -ERRNO_TO_DSS_ERROR(errno); + goto out; + } + m = s.st_mode; + if (!S_ISDIR(m)) + continue; + ret = func(entry->d_name, private_data); + if (ret < 0) + goto out; + } + ret = 1; +out: + closedir(dir); + return ret; +} +/** + * Wrapper for chdir(2). + * + * \param path The specified directory. + * + * \return Standard. + */ +int dss_chdir(const char *path) +{ + if (chdir(path) >= 0) + return 1; + return -ERRNO_TO_DSS_ERROR(errno); +} + +/** + * Set a file descriptor to non-blocking mode. + * + * \param fd The file descriptor. + * + * \return Standard. + */ +__must_check int mark_fd_nonblocking(int fd) +{ + int flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -ERRNO_TO_DSS_ERROR(errno); + flags = fcntl(fd, F_SETFL, ((long)flags) | O_NONBLOCK); + if (flags < 0) + return -ERRNO_TO_DSS_ERROR(errno); + return 1; +} + +/** + * dss' wrapper for select(2). + * + * It calls select(2) (with no exceptfds) and starts over if select() was + * interrupted by a signal. + * + * \param n The highest-numbered descriptor in any of the two sets, plus 1. + * \param readfds fds that should be checked for readability. + * \param writefds fds that should be checked for writablility. + * \param timeout_tv upper bound on the amount of time elapsed before select() + * returns. + * + * \return The return value of the underlying select() call on success, the + * negative system error code on errors. + * + * All arguments are passed verbatim to select(2). + * \sa select(2) select_tut(2). + */ +int dss_select(int n, fd_set *readfds, fd_set *writefds, + struct timeval *timeout_tv) +{ + int ret, err; + do { + ret = select(n, readfds, writefds, NULL, timeout_tv); + err = errno; + } while (ret < 0 && err == EINTR); + if (ret < 0) + return -ERRNO_TO_DSS_ERROR(errno); + return ret; +} diff --git a/file.h b/file.h new file mode 100644 index 0000000..991afd4 --- /dev/null +++ b/file.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2006-2010 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ +int dss_chdir(const char *path); +int for_each_subdir(int (*func)(const char *, void *), void *private_data); +__must_check int mark_fd_nonblocking(int fd); +/** + * A wrapper for rename(2). + * + * \param old_path The source path. + * \param new_path The destination path. + * + * \return Standard. + * + * \sa rename(2). + */ +_static_inline_ int dss_rename(const char *old_path, const char *new_path) +{ + if (rename(old_path, new_path) >= 0) + return 1; + return -ERRNO_TO_DSS_ERROR(errno); +} + +int dss_select(int n, fd_set *readfds, fd_set *writefds, + struct timeval *timeout_tv); diff --git a/ipc.c b/ipc.c index c438939..9889674 100644 --- a/ipc.c +++ b/ipc.c @@ -15,10 +15,10 @@ #include #include "gcc-compat.h" -#include "string.h" +#include "str.h" #include "log.h" #include "gcc-compat.h" -#include "error.h" +#include "err.h" #if (defined(__GNUC__) && defined(__i386__)) #define get16bits(d) (*((const uint16_t *) (d))) diff --git a/sig.c b/sig.c new file mode 100644 index 0000000..9694684 --- /dev/null +++ b/sig.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2004-2010 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "gcc-compat.h" +#include "err.h" +#include "log.h" +#include "str.h" +#include "file.h" + +static int signal_pipe[2]; + +/** + * Initialize the signal subsystem. + * + * This function creates a pipe, the signal pipe, to deliver pending signals to + * the application (Bernstein's trick). It should be called during the + * application's startup part, followed by subsequent calls to + * install_sighandler() for each signal that should be caught. + * + * signal_init() installs a generic signal handler which is used for all + * signals simultaneously. When a signal arrives, this generic signal handler + * writes the corresponding signal number to the signal pipe so that the + * application can test for pending signals simply by checking the signal pipe + * for reading, e.g. by using the select(2) system call. + * + * \return This function either succeeds or calls exit(2) to terminate + * the current process. On success, the file descriptor of the signal pipe is + * returned. + */ +int signal_init(void) +{ + int ret; + if (pipe(signal_pipe) < 0) { + ret = -ERRNO_TO_DSS_ERROR(errno); + goto err_out; + } + ret = mark_fd_nonblocking(signal_pipe[0]); + if (ret < 0) + goto err_out; + ret = mark_fd_nonblocking(signal_pipe[1]); + if (ret < 0) + goto err_out; + return signal_pipe[0]; +err_out: + DSS_EMERG_LOG("%s\n", dss_strerror(-ret)); + exit(EXIT_FAILURE); +} + +/* + * just write one integer to signal pipe + */ +static void generic_signal_handler(int s) +{ + write(signal_pipe[1], &s, sizeof(int)); +} + +/** + * Reap one child. + * + * \param pid In case a child died, its pid is returned here. + * + * Call waitpid() and print a log message containing the pid and the cause of + * the child's death. + * + * \return A (negative) error code on errors, zero, if no child died, one + * otherwise. If and only if the function returns one, the content of \a pid is + * meaningful. + * + * \sa waitpid(2) + */ +int reap_child(pid_t *pid, int *status) +{ + *pid = waitpid(-1, status, WNOHANG); + + if (!*pid) + return 0; + if (*pid < 0) + return -ERRNO_TO_DSS_ERROR(errno); + if (WIFEXITED(*status)) + DSS_DEBUG_LOG("child %i exited. Exit status: %i\n", (int)*pid, + WEXITSTATUS(*status)); + else if (WIFSIGNALED(*status)) + DSS_DEBUG_LOG("child %i was killed by signal %i\n", (int)*pid, + WTERMSIG(*status)); + else + DSS_WARNING_LOG("child %i terminated abormally\n", (int)*pid); + return 1; +} + +/** + * Wrapper around signal(2) + * + * \param sig The number of the signal to catch. + * + * This installs the generic signal handler for the given signal. + * + * \return This function returns 1 on success and \p -E_SIGNAL_SIG_ERR on errors. + * \sa signal(2) + */ +int install_sighandler(int sig) +{ + DSS_DEBUG_LOG("catching signal %d\n", sig); + if (signal(sig, &generic_signal_handler) != SIG_ERR) + return 1; + return -E_SIGNAL_SIG_ERR; +} + +/** + * Return number of next pending signal. + * + * This should be called if the fd for the signal pipe is ready for reading. + * + * \return On success, the number of the received signal is returned. + * If the read was interrupted by another signal the function returns 0. + * Otherwise a negative error code is returned. + */ +int next_signal(void) +{ + int s, err; + ssize_t r; + + r = read(signal_pipe[0], &s, sizeof(s)); + if (r == sizeof(s)) { + DSS_DEBUG_LOG("next signal: %d\n", s); + return s; + } + err = errno; + assert(r < 0); + if (err == EAGAIN) + return 0; + DSS_ERROR_LOG("failed to read from signal pipe\n"); + return -ERRNO_TO_DSS_ERROR(err); +} + +/** + * Close the signal pipe. + */ +void signal_shutdown(void) +{ + close(signal_pipe[1]); +} diff --git a/sig.h b/sig.h new file mode 100644 index 0000000..dea7cde --- /dev/null +++ b/sig.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2007-2010 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +int signal_init(void); +int install_sighandler(int); +int next_signal(void); +void signal_shutdown(void); +int reap_child(pid_t *pid, int *status); diff --git a/signal.c b/signal.c deleted file mode 100644 index 8dc93a6..0000000 --- a/signal.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2004-2010 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ -/** \file signal.c Signal handling functions. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "gcc-compat.h" -#include "error.h" -#include "log.h" -#include "string.h" -#include "fd.h" - -static int signal_pipe[2]; - -/** - * Initialize the signal subsystem. - * - * This function creates a pipe, the signal pipe, to deliver pending signals to - * the application (Bernstein's trick). It should be called during the - * application's startup part, followed by subsequent calls to - * install_sighandler() for each signal that should be caught. - * - * signal_init() installs a generic signal handler which is used for all - * signals simultaneously. When a signal arrives, this generic signal handler - * writes the corresponding signal number to the signal pipe so that the - * application can test for pending signals simply by checking the signal pipe - * for reading, e.g. by using the select(2) system call. - * - * \return This function either succeeds or calls exit(2) to terminate - * the current process. On success, the file descriptor of the signal pipe is - * returned. - */ -int signal_init(void) -{ - int ret; - if (pipe(signal_pipe) < 0) { - ret = -ERRNO_TO_DSS_ERROR(errno); - goto err_out; - } - ret = mark_fd_nonblocking(signal_pipe[0]); - if (ret < 0) - goto err_out; - ret = mark_fd_nonblocking(signal_pipe[1]); - if (ret < 0) - goto err_out; - return signal_pipe[0]; -err_out: - DSS_EMERG_LOG("%s\n", dss_strerror(-ret)); - exit(EXIT_FAILURE); -} - -/* - * just write one integer to signal pipe - */ -static void generic_signal_handler(int s) -{ - write(signal_pipe[1], &s, sizeof(int)); -} - -/** - * Reap one child. - * - * \param pid In case a child died, its pid is returned here. - * - * Call waitpid() and print a log message containing the pid and the cause of - * the child's death. - * - * \return A (negative) error code on errors, zero, if no child died, one - * otherwise. If and only if the function returns one, the content of \a pid is - * meaningful. - * - * \sa waitpid(2) - */ -int reap_child(pid_t *pid, int *status) -{ - *pid = waitpid(-1, status, WNOHANG); - - if (!*pid) - return 0; - if (*pid < 0) - return -ERRNO_TO_DSS_ERROR(errno); - if (WIFEXITED(*status)) - DSS_DEBUG_LOG("child %i exited. Exit status: %i\n", (int)*pid, - WEXITSTATUS(*status)); - else if (WIFSIGNALED(*status)) - DSS_DEBUG_LOG("child %i was killed by signal %i\n", (int)*pid, - WTERMSIG(*status)); - else - DSS_WARNING_LOG("child %i terminated abormally\n", (int)*pid); - return 1; -} - -/** - * Wrapper around signal(2) - * - * \param sig The number of the signal to catch. - * - * This installs the generic signal handler for the given signal. - * - * \return This function returns 1 on success and \p -E_SIGNAL_SIG_ERR on errors. - * \sa signal(2) - */ -int install_sighandler(int sig) -{ - DSS_DEBUG_LOG("catching signal %d\n", sig); - if (signal(sig, &generic_signal_handler) != SIG_ERR) - return 1; - return -E_SIGNAL_SIG_ERR; -} - -/** - * Return number of next pending signal. - * - * This should be called if the fd for the signal pipe is ready for reading. - * - * \return On success, the number of the received signal is returned. - * If the read was interrupted by another signal the function returns 0. - * Otherwise a negative error code is returned. - */ -int next_signal(void) -{ - int s, err; - ssize_t r; - - r = read(signal_pipe[0], &s, sizeof(s)); - if (r == sizeof(s)) { - DSS_DEBUG_LOG("next signal: %d\n", s); - return s; - } - err = errno; - assert(r < 0); - if (err == EAGAIN) - return 0; - DSS_ERROR_LOG("failed to read from signal pipe\n"); - return -ERRNO_TO_DSS_ERROR(err); -} - -/** - * Close the signal pipe. - */ -void signal_shutdown(void) -{ - close(signal_pipe[1]); -} diff --git a/signal.h b/signal.h deleted file mode 100644 index 0c5b3d8..0000000 --- a/signal.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) 2007-2010 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ - -/** \file signal.h exported symbols from signal.c */ - -int signal_init(void); -int install_sighandler(int); -int next_signal(void); -void signal_shutdown(void); -int reap_child(pid_t *pid, int *status); diff --git a/snap.c b/snap.c index a9383c1..aef0c51 100644 --- a/snap.c +++ b/snap.c @@ -14,11 +14,11 @@ #include #include "gcc-compat.h" -#include "error.h" +#include "err.h" #include "snap.h" -#include "string.h" -#include "time.h" -#include "fd.h" +#include "str.h" +#include "tv.h" +#include "file.h" /** * Wrapper for isdigit. diff --git a/str.c b/str.c new file mode 100644 index 0000000..e2b7f30 --- /dev/null +++ b/str.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2004-2010 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "gcc-compat.h" +#include "log.h" +#include "err.h" +#include "str.h" + +/** + * Write a message to a dynamically allocated string. + * + * \param fmt Usual format string. + * \param p Result pointer. + * + * \sa printf(3). */ +#define VSPRINTF(fmt, p) \ +{ \ + int n; \ + size_t size = 100; \ + p = dss_malloc(size); \ + while (1) { \ + va_list ap; \ + /* Try to print in the allocated space. */ \ + va_start(ap, fmt); \ + n = vsnprintf(p, size, fmt, ap); \ + va_end(ap); \ + /* If that worked, return the string. */ \ + if (n > -1 && n < size) \ + break; \ + /* Else try again with more space. */ \ + if (n > -1) /* glibc 2.1 */ \ + size = n + 1; /* precisely what is needed */ \ + else /* glibc 2.0 */ \ + size *= 2; /* twice the old size */ \ + p = dss_realloc(p, size); \ + } \ +} + +/** + * dss' version of realloc(). + * + * \param p Pointer to the memory block, may be \p NULL. + * \param size The desired new size. + * + * A wrapper for realloc(3). It calls \p exit(\p EXIT_FAILURE) on errors, + * i.e. there is no need to check the return value in the caller. + * + * \return A pointer to the newly allocated memory, which is suitably aligned + * for any kind of variable and may be different from \a p. + * + * \sa realloc(3). + */ +__must_check __malloc void *dss_realloc(void *p, size_t size) +{ + /* + * No need to check for NULL pointers: If p is NULL, the call + * to realloc is equivalent to malloc(size) + */ + assert(size); + if (!(p = realloc(p, size))) { + DSS_EMERG_LOG("realloc failed (size = %zu), aborting\n", + size); + exit(EXIT_FAILURE); + } + return p; +} + +/** + * dss' version of malloc(). + * + * \param size The desired new size. + * + * A wrapper for malloc(3) which exits on errors. + * + * \return A pointer to the allocated memory, which is suitably aligned for any + * kind of variable. + * + * \sa malloc(3). + */ +__must_check __malloc void *dss_malloc(size_t size) +{ + void *p; + assert(size); + p = malloc(size); + + if (!p) { + DSS_EMERG_LOG("malloc failed (size = %zu), aborting\n", + size); + exit(EXIT_FAILURE); + } + return p; +} + +/** + * dss' version of calloc(). + * + * \param size The desired new size. + * + * A wrapper for calloc(3) which exits on errors. + * + * \return A pointer to the allocated and zeroed-out memory, which is suitably + * aligned for any kind of variable. + * + * \sa calloc(3) + */ +__must_check __malloc void *dss_calloc(size_t size) +{ + void *ret = dss_malloc(size); + + memset(ret, 0, size); + return ret; +} + +/** + * dss' version of strdup(). + * + * \param s The string to be duplicated. + * + * A wrapper for strdup(3). It calls \p exit(EXIT_FAILURE) on errors, i.e. + * there is no need to check the return value in the caller. + * + * \return A pointer to the duplicated string. If \p s was the NULL pointer, + * an pointer to an empty string is returned. + * + * \sa strdup(3) + */ + +__must_check __malloc char *dss_strdup(const char *s) +{ + char *ret; + + if ((ret = strdup(s? s: ""))) + return ret; + DSS_EMERG_LOG("strdup failed, aborting\n"); + exit(EXIT_FAILURE); +} + +/** + * Allocate a sufficiently large string and print into it. + * + * \param fmt A usual format string. + * + * Produce output according to \p fmt. No artificial bound on the length of the + * resulting string is imposed. + * + * \return This function either returns a pointer to a string that must be + * freed by the caller or aborts without returning. + * + * \sa printf(3). + */ +__must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...) +{ + char *msg; + + VSPRINTF(fmt, msg); + return msg; +} + +/** + * Get the home directory of the current user. + * + * \return A dynammically allocated string that must be freed by the caller. If + * the home directory could not be found, this function returns "/tmp". + */ +__must_check __malloc char *get_homedir(void) +{ + struct passwd *pw = getpwuid(getuid()); + return dss_strdup(pw? pw->pw_dir : "/tmp"); +} + +/** + * Convert a string to a 64-bit signed integer value. + * + * \param str The string to be converted. + * \param value Result pointer. + * + * \return Standard. + * + * \sa strtol(3), atoi(3). + */ +int dss_atoi64(const char *str, int64_t *value) +{ + char *endptr; + long long tmp; + + errno = 0; /* To distinguish success/failure after call */ + tmp = strtoll(str, &endptr, 10); + if (errno == ERANGE && (tmp == LLONG_MAX || tmp == LLONG_MIN)) + return -E_ATOI_OVERFLOW; + if (errno != 0 && tmp == 0) /* other error */ + return -E_STRTOLL; + if (endptr == str) + return -E_ATOI_NO_DIGITS; + if (*endptr != '\0') /* Further characters after number */ + return -E_ATOI_JUNK_AT_END; + *value = tmp; + return 1; +} + +/** + * Get the logname of the current user. + * + * \return A dynammically allocated string that must be freed by the caller. On + * errors, the string "unknown user" is returned, i.e. this function never + * returns \p NULL. + * + * \sa getpwuid(3). + */ +__must_check __malloc char *dss_logname(void) +{ + struct passwd *pw = getpwuid(getuid()); + return dss_strdup(pw? pw->pw_name : "unknown_user"); +} + +/** + * Split string and return pointers to its parts. + * + * \param args The string to be split. + * \param argv_ptr Pointer to the list of substrings. + * \param delim Delimiter. + * + * This function modifies \a args by replacing each occurance of \a delim by + * zero. A \p NULL-terminated array of pointers to char* is allocated dynamically + * and these pointers are initialized to point to the broken-up substrings + * within \a args. A pointer to this array is returned via \a argv_ptr. + * + * \return The number of substrings found in \a args. + */ +unsigned split_args(char *args, char *** const argv_ptr, const char *delim) +{ + char *p = args; + char **argv; + size_t n = 0, i, j; + + p = args + strspn(args, delim); + for (;;) { + i = strcspn(p, delim); + if (!i) + break; + p += i; + n++; + p += strspn(p, delim); + } + *argv_ptr = dss_malloc((n + 1) * sizeof(char *)); + argv = *argv_ptr; + i = 0; + p = args + strspn(args, delim); + while (p) { + argv[i] = p; + j = strcspn(p, delim); + if (!j) + break; + p += strcspn(p, delim); + if (*p) { + *p = '\0'; + p++; + p += strspn(p, delim); + } + i++; + } + argv[n] = NULL; + return n; +} diff --git a/str.h b/str.h new file mode 100644 index 0000000..0f158fe --- /dev/null +++ b/str.h @@ -0,0 +1,20 @@ +__must_check __malloc void *dss_realloc(void *p, size_t size); +__must_check __malloc void *dss_malloc(size_t size); +__must_check __malloc void *dss_calloc(size_t size); +__must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...); +__must_check __malloc char *dss_strdup(const char *s); +__must_check __malloc char *get_homedir(void); +int dss_atoi64(const char *str, int64_t *value); +__must_check __malloc char *dss_logname(void); +unsigned split_args(char *args, char *** const argv_ptr, const char *delim); + + +/** \cond LLONG_MAX and LLONG_LIN might not be defined. */ +#ifndef LLONG_MAX +#define LLONG_MAX (1 << (sizeof(long) - 1)) +#endif +#ifndef LLONG_MIN +#define LLONG_MIN (-LLONG_MAX - 1LL) +#endif +/** \endcond */ + diff --git a/string.c b/string.c deleted file mode 100644 index d340811..0000000 --- a/string.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2004-2010 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "gcc-compat.h" -#include "log.h" -#include "error.h" -#include "string.h" - -/** - * Write a message to a dynamically allocated string. - * - * \param fmt Usual format string. - * \param p Result pointer. - * - * \sa printf(3). */ -#define VSPRINTF(fmt, p) \ -{ \ - int n; \ - size_t size = 100; \ - p = dss_malloc(size); \ - while (1) { \ - va_list ap; \ - /* Try to print in the allocated space. */ \ - va_start(ap, fmt); \ - n = vsnprintf(p, size, fmt, ap); \ - va_end(ap); \ - /* If that worked, return the string. */ \ - if (n > -1 && n < size) \ - break; \ - /* Else try again with more space. */ \ - if (n > -1) /* glibc 2.1 */ \ - size = n + 1; /* precisely what is needed */ \ - else /* glibc 2.0 */ \ - size *= 2; /* twice the old size */ \ - p = dss_realloc(p, size); \ - } \ -} - -/** - * dss' version of realloc(). - * - * \param p Pointer to the memory block, may be \p NULL. - * \param size The desired new size. - * - * A wrapper for realloc(3). It calls \p exit(\p EXIT_FAILURE) on errors, - * i.e. there is no need to check the return value in the caller. - * - * \return A pointer to the newly allocated memory, which is suitably aligned - * for any kind of variable and may be different from \a p. - * - * \sa realloc(3). - */ -__must_check __malloc void *dss_realloc(void *p, size_t size) -{ - /* - * No need to check for NULL pointers: If p is NULL, the call - * to realloc is equivalent to malloc(size) - */ - assert(size); - if (!(p = realloc(p, size))) { - DSS_EMERG_LOG("realloc failed (size = %zu), aborting\n", - size); - exit(EXIT_FAILURE); - } - return p; -} - -/** - * dss' version of malloc(). - * - * \param size The desired new size. - * - * A wrapper for malloc(3) which exits on errors. - * - * \return A pointer to the allocated memory, which is suitably aligned for any - * kind of variable. - * - * \sa malloc(3). - */ -__must_check __malloc void *dss_malloc(size_t size) -{ - void *p; - assert(size); - p = malloc(size); - - if (!p) { - DSS_EMERG_LOG("malloc failed (size = %zu), aborting\n", - size); - exit(EXIT_FAILURE); - } - return p; -} - -/** - * dss' version of calloc(). - * - * \param size The desired new size. - * - * A wrapper for calloc(3) which exits on errors. - * - * \return A pointer to the allocated and zeroed-out memory, which is suitably - * aligned for any kind of variable. - * - * \sa calloc(3) - */ -__must_check __malloc void *dss_calloc(size_t size) -{ - void *ret = dss_malloc(size); - - memset(ret, 0, size); - return ret; -} - -/** - * dss' version of strdup(). - * - * \param s The string to be duplicated. - * - * A wrapper for strdup(3). It calls \p exit(EXIT_FAILURE) on errors, i.e. - * there is no need to check the return value in the caller. - * - * \return A pointer to the duplicated string. If \p s was the NULL pointer, - * an pointer to an empty string is returned. - * - * \sa strdup(3) - */ - -__must_check __malloc char *dss_strdup(const char *s) -{ - char *ret; - - if ((ret = strdup(s? s: ""))) - return ret; - DSS_EMERG_LOG("strdup failed, aborting\n"); - exit(EXIT_FAILURE); -} - -/** - * Allocate a sufficiently large string and print into it. - * - * \param fmt A usual format string. - * - * Produce output according to \p fmt. No artificial bound on the length of the - * resulting string is imposed. - * - * \return This function either returns a pointer to a string that must be - * freed by the caller or aborts without returning. - * - * \sa printf(3). - */ -__must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...) -{ - char *msg; - - VSPRINTF(fmt, msg); - return msg; -} - -/** - * Get the home directory of the current user. - * - * \return A dynammically allocated string that must be freed by the caller. If - * the home directory could not be found, this function returns "/tmp". - */ -__must_check __malloc char *get_homedir(void) -{ - struct passwd *pw = getpwuid(getuid()); - return dss_strdup(pw? pw->pw_dir : "/tmp"); -} - -/** - * Convert a string to a 64-bit signed integer value. - * - * \param str The string to be converted. - * \param value Result pointer. - * - * \return Standard. - * - * \sa strtol(3), atoi(3). - */ -int dss_atoi64(const char *str, int64_t *value) -{ - char *endptr; - long long tmp; - - errno = 0; /* To distinguish success/failure after call */ - tmp = strtoll(str, &endptr, 10); - if (errno == ERANGE && (tmp == LLONG_MAX || tmp == LLONG_MIN)) - return -E_ATOI_OVERFLOW; - if (errno != 0 && tmp == 0) /* other error */ - return -E_STRTOLL; - if (endptr == str) - return -E_ATOI_NO_DIGITS; - if (*endptr != '\0') /* Further characters after number */ - return -E_ATOI_JUNK_AT_END; - *value = tmp; - return 1; -} - -/** - * Get the logname of the current user. - * - * \return A dynammically allocated string that must be freed by the caller. On - * errors, the string "unknown user" is returned, i.e. this function never - * returns \p NULL. - * - * \sa getpwuid(3). - */ -__must_check __malloc char *dss_logname(void) -{ - struct passwd *pw = getpwuid(getuid()); - return dss_strdup(pw? pw->pw_name : "unknown_user"); -} - -/** - * Split string and return pointers to its parts. - * - * \param args The string to be split. - * \param argv_ptr Pointer to the list of substrings. - * \param delim Delimiter. - * - * This function modifies \a args by replacing each occurance of \a delim by - * zero. A \p NULL-terminated array of pointers to char* is allocated dynamically - * and these pointers are initialized to point to the broken-up substrings - * within \a args. A pointer to this array is returned via \a argv_ptr. - * - * \return The number of substrings found in \a args. - */ -unsigned split_args(char *args, char *** const argv_ptr, const char *delim) -{ - char *p = args; - char **argv; - size_t n = 0, i, j; - - p = args + strspn(args, delim); - for (;;) { - i = strcspn(p, delim); - if (!i) - break; - p += i; - n++; - p += strspn(p, delim); - } - *argv_ptr = dss_malloc((n + 1) * sizeof(char *)); - argv = *argv_ptr; - i = 0; - p = args + strspn(args, delim); - while (p) { - argv[i] = p; - j = strcspn(p, delim); - if (!j) - break; - p += strcspn(p, delim); - if (*p) { - *p = '\0'; - p++; - p += strspn(p, delim); - } - i++; - } - argv[n] = NULL; - return n; -} diff --git a/string.h b/string.h deleted file mode 100644 index 0f158fe..0000000 --- a/string.h +++ /dev/null @@ -1,20 +0,0 @@ -__must_check __malloc void *dss_realloc(void *p, size_t size); -__must_check __malloc void *dss_malloc(size_t size); -__must_check __malloc void *dss_calloc(size_t size); -__must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...); -__must_check __malloc char *dss_strdup(const char *s); -__must_check __malloc char *get_homedir(void); -int dss_atoi64(const char *str, int64_t *value); -__must_check __malloc char *dss_logname(void); -unsigned split_args(char *args, char *** const argv_ptr, const char *delim); - - -/** \cond LLONG_MAX and LLONG_LIN might not be defined. */ -#ifndef LLONG_MAX -#define LLONG_MAX (1 << (sizeof(long) - 1)) -#endif -#ifndef LLONG_MIN -#define LLONG_MIN (-LLONG_MAX - 1LL) -#endif -/** \endcond */ - diff --git a/time.c b/time.c deleted file mode 100644 index 3cc1ad6..0000000 --- a/time.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2005-2010 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ - -/** \file time.c Helper functions for dealing with time values. */ - -#include -#include -#include -#include -#include - -#include "gcc-compat.h" -#include "error.h" -#include "string.h" -#include "log.h" - -/** - * Convert struct timeval to milliseconds. - * - * \param tv The time value value to convert. - * - * \return The number off milliseconds in \a tv. - */ -long unsigned tv2ms(const struct timeval *tv) -{ - return tv->tv_sec * 1000 + (tv->tv_usec + 500)/ 1000; -} - -/** - * Convert milliseconds to a struct timeval. - * - * \param n The number of milliseconds. - * \param tv Result pointer. - */ -void ms2tv(long unsigned n, struct timeval *tv) -{ - tv->tv_sec = n / 1000; - tv->tv_usec = (n % 1000) * 1000; -} - -/** - * Convert a double to a struct timeval. - * - * \param x The value to convert. - * \param tv Result pointer. - */ -void d2tv(double x, struct timeval *tv) -{ - tv->tv_sec = x; - tv->tv_usec = (x - (double)tv->tv_sec) * 1000.0 * 1000.0 + 0.5; -} - -/** - * Compute the difference of two time values. - * - * \param b Minuend. - * \param a Subtrahend. - * \param diff Result pointer. - * - * If \a diff is not \p NULL, it contains the absolute value |\a b - \a a| on - * return. - * - * \return If \a b < \a a, this function returns -1, otherwise it returns 1. - */ -int tv_diff(const struct timeval *b, const struct timeval *a, struct timeval *diff) -{ - int ret = 1; - - if ((b->tv_sec < a->tv_sec) || - ((b->tv_sec == a->tv_sec) && (b->tv_usec < a->tv_usec))) { - const struct timeval *tmp = a; - a = b; - b = tmp; - ret = -1; - } - if (!diff) - return ret; - diff->tv_sec = b->tv_sec - a->tv_sec; - if (b->tv_usec < a->tv_usec) { - diff->tv_sec--; - diff->tv_usec = 1000 * 1000 - a->tv_usec + b->tv_usec; - } else - diff->tv_usec = b->tv_usec - a->tv_usec; - return ret; -} - -/** - * Add two time values. - * - * \param a First addend. - * \param b Second addend. - * \param sum Contains the sum \a + \a b on return. - */ -void tv_add(const struct timeval *a, const struct timeval *b, - struct timeval *sum) -{ - sum->tv_sec = a->tv_sec + b->tv_sec; - if (a->tv_usec + b->tv_usec >= 1000 * 1000) { - sum->tv_sec++; - sum->tv_usec = a->tv_usec + b->tv_usec - 1000 * 1000; - } else - sum->tv_usec = a->tv_usec + b->tv_usec; -} - -/** - * Compute integer multiple of given struct timeval. - * - * \param mult The integer value to multiply with. - * \param tv The timevalue to multiply. - * - * \param result Contains \a mult * \a tv on return. - */ -void tv_scale(const unsigned long mult, const struct timeval *tv, - struct timeval *result) -{ - result->tv_sec = mult * tv->tv_sec; - result->tv_sec += tv->tv_usec * mult / 1000 / 1000; - result->tv_usec = tv->tv_usec * mult % (1000 * 1000); -} - -/** - * Compute a fraction of given struct timeval. - * - * \param divisor The integer value to divide by. - * \param tv The timevalue to divide. - * \param result Contains (1 / mult) * tv on return. - */ -void tv_divide(const unsigned long divisor, const struct timeval *tv, - struct timeval *result) -{ - uint64_t x = ((uint64_t)tv->tv_sec * 1000 * 1000 + tv->tv_usec) / divisor; - - result->tv_sec = x / 1000 / 1000; - result->tv_usec = x % (1000 * 1000); -} - -int64_t get_current_time(void) -{ - time_t now; - time(&now); - DSS_DEBUG_LOG("now: %jd\n", (intmax_t)now); - return (int64_t)now; -} diff --git a/time.h b/time.h deleted file mode 100644 index f2021e0..0000000 --- a/time.h +++ /dev/null @@ -1,9 +0,0 @@ -int tv_diff(const struct timeval *b, const struct timeval *a, struct timeval *diff); -long unsigned tv2ms(const struct timeval*); -void d2tv(double, struct timeval*); -void tv_add(const struct timeval*, const struct timeval *, struct timeval *); -void tv_scale(const unsigned long, const struct timeval *, struct timeval *); -void tv_divide(const unsigned long divisor, const struct timeval *tv, - struct timeval *result); -void ms2tv(const long unsigned n, struct timeval *tv); -int64_t get_current_time(void); diff --git a/tv.c b/tv.c new file mode 100644 index 0000000..b0acc79 --- /dev/null +++ b/tv.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2005-2010 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +#include +#include +#include +#include +#include + +#include "gcc-compat.h" +#include "err.h" +#include "str.h" +#include "log.h" + +/** + * Convert struct timeval to milliseconds. + * + * \param tv The time value value to convert. + * + * \return The number off milliseconds in \a tv. + */ +long unsigned tv2ms(const struct timeval *tv) +{ + return tv->tv_sec * 1000 + (tv->tv_usec + 500)/ 1000; +} + +/** + * Convert milliseconds to a struct timeval. + * + * \param n The number of milliseconds. + * \param tv Result pointer. + */ +void ms2tv(long unsigned n, struct timeval *tv) +{ + tv->tv_sec = n / 1000; + tv->tv_usec = (n % 1000) * 1000; +} + +/** + * Convert a double to a struct timeval. + * + * \param x The value to convert. + * \param tv Result pointer. + */ +void d2tv(double x, struct timeval *tv) +{ + tv->tv_sec = x; + tv->tv_usec = (x - (double)tv->tv_sec) * 1000.0 * 1000.0 + 0.5; +} + +/** + * Compute the difference of two time values. + * + * \param b Minuend. + * \param a Subtrahend. + * \param diff Result pointer. + * + * If \a diff is not \p NULL, it contains the absolute value |\a b - \a a| on + * return. + * + * \return If \a b < \a a, this function returns -1, otherwise it returns 1. + */ +int tv_diff(const struct timeval *b, const struct timeval *a, struct timeval *diff) +{ + int ret = 1; + + if ((b->tv_sec < a->tv_sec) || + ((b->tv_sec == a->tv_sec) && (b->tv_usec < a->tv_usec))) { + const struct timeval *tmp = a; + a = b; + b = tmp; + ret = -1; + } + if (!diff) + return ret; + diff->tv_sec = b->tv_sec - a->tv_sec; + if (b->tv_usec < a->tv_usec) { + diff->tv_sec--; + diff->tv_usec = 1000 * 1000 - a->tv_usec + b->tv_usec; + } else + diff->tv_usec = b->tv_usec - a->tv_usec; + return ret; +} + +/** + * Add two time values. + * + * \param a First addend. + * \param b Second addend. + * \param sum Contains the sum \a + \a b on return. + */ +void tv_add(const struct timeval *a, const struct timeval *b, + struct timeval *sum) +{ + sum->tv_sec = a->tv_sec + b->tv_sec; + if (a->tv_usec + b->tv_usec >= 1000 * 1000) { + sum->tv_sec++; + sum->tv_usec = a->tv_usec + b->tv_usec - 1000 * 1000; + } else + sum->tv_usec = a->tv_usec + b->tv_usec; +} + +/** + * Compute integer multiple of given struct timeval. + * + * \param mult The integer value to multiply with. + * \param tv The timevalue to multiply. + * + * \param result Contains \a mult * \a tv on return. + */ +void tv_scale(const unsigned long mult, const struct timeval *tv, + struct timeval *result) +{ + result->tv_sec = mult * tv->tv_sec; + result->tv_sec += tv->tv_usec * mult / 1000 / 1000; + result->tv_usec = tv->tv_usec * mult % (1000 * 1000); +} + +/** + * Compute a fraction of given struct timeval. + * + * \param divisor The integer value to divide by. + * \param tv The timevalue to divide. + * \param result Contains (1 / mult) * tv on return. + */ +void tv_divide(const unsigned long divisor, const struct timeval *tv, + struct timeval *result) +{ + uint64_t x = ((uint64_t)tv->tv_sec * 1000 * 1000 + tv->tv_usec) / divisor; + + result->tv_sec = x / 1000 / 1000; + result->tv_usec = x % (1000 * 1000); +} + +int64_t get_current_time(void) +{ + time_t now; + time(&now); + DSS_DEBUG_LOG("now: %jd\n", (intmax_t)now); + return (int64_t)now; +} diff --git a/tv.h b/tv.h new file mode 100644 index 0000000..f2021e0 --- /dev/null +++ b/tv.h @@ -0,0 +1,9 @@ +int tv_diff(const struct timeval *b, const struct timeval *a, struct timeval *diff); +long unsigned tv2ms(const struct timeval*); +void d2tv(double, struct timeval*); +void tv_add(const struct timeval*, const struct timeval *, struct timeval *); +void tv_scale(const unsigned long, const struct timeval *, struct timeval *); +void tv_divide(const unsigned long divisor, const struct timeval *tv, + struct timeval *result); +void ms2tv(const long unsigned n, struct timeval *tv); +int64_t get_current_time(void);