summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makemodule.am8
-rw-r--r--lib/canonicalize.c99
-rw-r--r--lib/colors.c20
-rw-r--r--lib/cpuset.c32
-rw-r--r--lib/loopdev.c41
-rw-r--r--lib/monotonic.c6
-rw-r--r--lib/path.c54
-rw-r--r--lib/strutils.c15
-rw-r--r--lib/sysfs.c14
-rw-r--r--lib/timer.c40
-rw-r--r--lib/timeutils.c27
11 files changed, 276 insertions, 80 deletions
diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index 13b19f151..862a06c17 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -48,10 +48,12 @@ libcommon_la_SOURCES += lib/cpuset.c
endif
if HAVE_OPENAT
+if HAVE_DIRFD
libcommon_la_SOURCES += lib/path.c
libcommon_la_SOURCES += lib/procutils.c
libcommon_la_SOURCES += lib/sysfs.c
endif
+endif
noinst_LTLIBRARIES += libtcolors.la
libtcolors_la_CFLAGS = $(AM_CFLAGS)
@@ -96,9 +98,11 @@ check_PROGRAMS += \
endif
if HAVE_OPENAT
+if HAVE_DIRFD
check_PROGRAMS += test_procutils
check_PROGRAMS += test_path
endif
+endif
test_ttyutils_SOURCES = lib/ttyutils.c
test_ttyutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_TTYUTILS
@@ -126,11 +130,10 @@ test_randutils_SOURCES = lib/randutils.c
test_randutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_RANDUTILS
if HAVE_OPENAT
+if HAVE_DIRFD
test_procutils_SOURCES = lib/procutils.c
test_procutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_PROCUTILS
-endif
-if HAVE_OPENAT
test_path_SOURCES = lib/path.c lib/fileutils.c
if HAVE_CPU_SET_T
test_path_SOURCES += lib/cpuset.c
@@ -138,6 +141,7 @@ endif
test_path_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_PATH
test_path_LDADD = $(LDADD)
endif
+endif
if LINUX
test_cpuset_SOURCES = lib/cpuset.c
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index f3a2a3af2..fe104953d 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -14,9 +14,11 @@
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/wait.h>
#include "canonicalize.h"
#include "pathnames.h"
+#include "all-io.h"
/*
* Converts private "dm-N" names to "/dev/mapper/<name>"
@@ -140,39 +142,92 @@ char *canonicalize_path(const char *path)
char *canonicalize_path_restricted(const char *path)
{
- char *canonical, *dmname;
- int errsv;
- uid_t euid;
- gid_t egid;
+ char *canonical = NULL;
+ int errsv = 0;
+ int pipes[2];
+ ssize_t len;
+ pid_t pid;
if (!path || !*path)
return NULL;
- euid = geteuid();
- egid = getegid();
-
- /* drop permissions */
- if (setegid(getgid()) < 0 || seteuid(getuid()) < 0)
+ if (pipe(pipes) != 0)
return NULL;
- errsv = errno = 0;
-
- canonical = realpath(path, NULL);
- if (!canonical)
- errsv = errno;
- else if (is_dm_devname(canonical, &dmname)) {
- char *dm = canonicalize_dm_name(dmname);
- if (dm) {
- free(canonical);
- canonical = dm;
+ /*
+ * To accurately assume identity of getuid() we must use setuid()
+ * but if we do that, we lose ability to reassume euid of 0, so
+ * we fork to do the check to keep euid intact.
+ */
+ pid = fork();
+ switch (pid) {
+ case -1:
+ close(pipes[0]);
+ close(pipes[1]);
+ return NULL; /* fork error */
+ case 0:
+ close(pipes[0]); /* close unused end */
+ pipes[0] = -1;
+ errno = 0;
+
+ /* drop permissions */
+ if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
+ canonical = NULL; /* failed */
+ else {
+ char *dmname = NULL;
+
+ canonical = realpath(path, NULL);
+ if (canonical && is_dm_devname(canonical, &dmname)) {
+ char *dm = canonicalize_dm_name(dmname);
+ if (dm) {
+ free(canonical);
+ canonical = dm;
+ }
+ }
}
+
+ len = canonical ? strlen(canonical) : errno ? -errno : -EINVAL;
+
+ /* send length or errno */
+ write_all(pipes[1], (char *) &len, sizeof(len));
+ if (canonical)
+ write_all(pipes[1], canonical, len);
+ exit(0);
+ default:
+ break;
}
- /* restore */
- if (setegid(egid) < 0 || seteuid(euid) < 0) {
+ close(pipes[1]); /* close unused end */
+ pipes[1] = -1;
+
+ /* read size or -errno */
+ if (read_all(pipes[0], (char *) &len, sizeof(len)) != sizeof(len))
+ goto done;
+ if (len < 0) {
+ errsv = -len;
+ goto done;
+ }
+
+ canonical = malloc(len + 1);
+ if (!canonical) {
+ errsv = ENOMEM;
+ goto done;
+ }
+ /* read path */
+ if (read_all(pipes[0], canonical, len) != len) {
+ errsv = errno;
+ goto done;
+ }
+ canonical[len] = '\0';
+done:
+ if (errsv) {
free(canonical);
- return NULL;
+ canonical = NULL;
}
+ close(pipes[0]);
+
+ /* We make a best effort to reap child */
+ waitpid(pid, NULL, 0);
errno = errsv;
return canonical;
diff --git a/lib/colors.c b/lib/colors.c
index f636ecc4f..bea7bd1d7 100644
--- a/lib/colors.c
+++ b/lib/colors.c
@@ -653,9 +653,6 @@ static int colors_terminal_is_ready(void)
{
int ncolors = -1;
- if (isatty(STDOUT_FILENO) != 1)
- goto none;
-
#if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBNCURSESW)
{
int ret;
@@ -692,11 +689,16 @@ int colors_init(int mode, const char *name)
struct ul_color_ctl *cc = &ul_colors;
cc->utilname = name;
- cc->mode = mode;
termcolors_init_debug();
- if (mode == UL_COLORMODE_UNDEF && (ready = colors_terminal_is_ready())) {
+ if (mode != UL_COLORMODE_ALWAYS && !isatty(STDOUT_FILENO))
+ cc->mode = UL_COLORMODE_NEVER;
+ else
+ cc->mode = mode;
+
+ if (cc->mode == UL_COLORMODE_UNDEF
+ && (ready = colors_terminal_is_ready())) {
int rc = colors_read_configuration(cc);
if (rc)
cc->mode = UL_COLORMODE_DEFAULT;
@@ -755,6 +757,14 @@ int colors_wanted(void)
}
/*
+ * Returns mode
+ */
+int colors_mode(void)
+{
+ return ul_colors.mode;
+}
+
+/*
* Enable @seq color
*/
void color_fenable(const char *seq, FILE *f)
diff --git a/lib/cpuset.c b/lib/cpuset.c
index 011b6882b..2847db853 100644
--- a/lib/cpuset.c
+++ b/lib/cpuset.c
@@ -260,6 +260,19 @@ int cpumask_parse(const char *str, cpu_set_t *set, size_t setsize)
return 0;
}
+static int nextnumber(const char *str, char **end, unsigned int *result)
+{
+ errno = 0;
+ if (str == NULL || *str == '\0' || !isdigit(*str))
+ return -EINVAL;
+ *result = (unsigned int) strtoul(str, end, 10);
+ if (errno)
+ return -errno;
+ if (str == *end)
+ return -EINVAL;
+ return 0;
+}
+
/*
* Parses string with list of CPU ranges.
* Returns 0 on success.
@@ -272,7 +285,7 @@ int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail)
{
size_t max = cpuset_nbits(setsize);
const char *p, *q;
- int r = 0;
+ char *end = NULL;
q = str;
CPU_ZERO_S(setsize, set);
@@ -282,21 +295,24 @@ int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail)
unsigned int b; /* end of range */
unsigned int s; /* stride */
const char *c1, *c2;
- char c;
- if ((r = sscanf(p, "%u%c", &a, &c)) < 1)
+ if (nextnumber(p, &end, &a) != 0)
return 1;
b = a;
s = 1;
+ p = end;
c1 = nexttoken(p, '-');
c2 = nexttoken(p, ',');
+
if (c1 != NULL && (c2 == NULL || c1 < c2)) {
- if ((r = sscanf(c1, "%u%c", &b, &c)) < 1)
+ if (nextnumber(c1, &end, &b) != 0)
return 1;
- c1 = nexttoken(c1, ':');
+
+ c1 = end && *end ? nexttoken(end, ':') : NULL;
+
if (c1 != NULL && (c2 == NULL || c1 < c2)) {
- if ((r = sscanf(c1, "%u%c", &s, &c)) < 1)
+ if (nextnumber(c1, &end, &s) != 0)
return 1;
if (s == 0)
return 1;
@@ -313,7 +329,7 @@ int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail)
}
}
- if (r == 2)
+ if (end && *end)
return 1;
return 0;
}
@@ -390,7 +406,7 @@ int main(int argc, char *argv[])
usage_err:
fprintf(stderr,
- "usage: %s [--ncpus <num>] --mask <mask> | --range <list>",
+ "usage: %s [--ncpus <num>] --mask <mask> | --range <list>\n",
program_invocation_short_name);
exit(EXIT_FAILURE);
}
diff --git a/lib/loopdev.c b/lib/loopdev.c
index de0d50ba2..5d2e95b7e 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -96,6 +96,7 @@ int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
}
lc->fd = -1;
lc->mode = 0;
+ lc->blocksize = 0;
lc->has_info = 0;
lc->info_failed = 0;
*lc->device = '\0';
@@ -127,7 +128,7 @@ int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
return 0;
}
-int loopcxt_has_device(struct loopdev_cxt *lc)
+inline int loopcxt_has_device(struct loopdev_cxt *lc)
{
return lc && *lc->device;
}
@@ -362,7 +363,7 @@ int loopcxt_deinit_iterator(struct loopdev_cxt *lc)
/*
* Same as loopcxt_set_device, but also checks if the device is
- * associeted with any file.
+ * associated with any file.
*
* Returns: <0 on error, 0 on success, 1 device does not match with
* LOOPITER_FL_{USED,FREE} flags.
@@ -691,7 +692,7 @@ char *loopcxt_get_backing_file(struct loopdev_cxt *lc)
if (sysfs)
/*
- * This is always preffered, the loop_info64
+ * This is always preferred, the loop_info64
* has too small buffer for the filename.
*/
ul_path_read_string(sysfs, &res, "loop/backing_file");
@@ -1107,6 +1108,22 @@ int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit)
}
/*
+ * The blocksize will be used by loopcxt_set_device(). For already exiting
+ * devices use loopcxt_ioctl_blocksize().
+ *
+ * The setting is removed by loopcxt_set_device() loopcxt_next()!
+ */
+int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize)
+{
+ if (!lc)
+ return -EINVAL;
+ lc->blocksize = blocksize;
+
+ DBG(CXT, ul_debugobj(lc, "set blocksize=%jd", blocksize));
+ return 0;
+}
+
+/*
* @lc: context
* @flags: kernel LO_FLAGS_{READ_ONLY,USE_AOPS,AUTOCLEAR} flags
*
@@ -1216,7 +1233,7 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
"size mismatch (%ju/%ju)",
size, expected_size));
- if (loopcxt_set_capacity(lc)) {
+ if (loopcxt_ioctl_capacity(lc)) {
/* ioctl not available */
if (errno == ENOTTY || errno == EINVAL)
errno = ERANGE;
@@ -1331,6 +1348,12 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD: OK"));
+ if (lc->blocksize > 0
+ && (rc = loopcxt_ioctl_blocksize(lc, lc->blocksize)) < 0) {
+ errsv = -rc;
+ goto err;
+ }
+
if (ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info)) {
rc = -errno;
errsv = errno;
@@ -1374,7 +1397,7 @@ err:
*
* Returns: <0 on error, 0 on success.
*/
-int loopcxt_set_status(struct loopdev_cxt *lc)
+int loopcxt_ioctl_status(struct loopdev_cxt *lc)
{
int dev_fd, rc = -1;
@@ -1397,7 +1420,7 @@ int loopcxt_set_status(struct loopdev_cxt *lc)
return 0;
}
-int loopcxt_set_capacity(struct loopdev_cxt *lc)
+int loopcxt_ioctl_capacity(struct loopdev_cxt *lc)
{
int fd = loopcxt_get_fd(lc);
@@ -1415,7 +1438,7 @@ int loopcxt_set_capacity(struct loopdev_cxt *lc)
return 0;
}
-int loopcxt_set_dio(struct loopdev_cxt *lc, unsigned long use_dio)
+int loopcxt_ioctl_dio(struct loopdev_cxt *lc, unsigned long use_dio)
{
int fd = loopcxt_get_fd(lc);
@@ -1437,7 +1460,7 @@ int loopcxt_set_dio(struct loopdev_cxt *lc, unsigned long use_dio)
* Kernel uses "unsigned long" as ioctl arg, but we use u64 for all sizes to
* keep loopdev internal API simple.
*/
-int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize)
+int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize)
{
int fd = loopcxt_get_fd(lc);
@@ -1753,7 +1776,7 @@ char *loopdev_find_by_backing_file(const char *filename, uint64_t offset, uint64
/*
* Returns number of loop devices associated with @file, if only one loop
- * device is associeted with the given @filename and @loopdev is not NULL then
+ * device is associated with the given @filename and @loopdev is not NULL then
* @loopdev returns name of the device.
*/
int loopdev_count_by_backing_file(const char *filename, char **loopdev)
diff --git a/lib/monotonic.c b/lib/monotonic.c
index bb58e15d7..96ead1ee0 100644
--- a/lib/monotonic.c
+++ b/lib/monotonic.c
@@ -52,12 +52,8 @@ int gettime_monotonic(struct timeval *tv)
int ret;
struct timespec ts;
-# ifdef CLOCK_MONOTONIC_RAW
/* Linux specific, can't slew */
- if (!(ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts))) {
-# else
- if (!(ret = clock_gettime(CLOCK_MONOTONIC, &ts))) {
-# endif
+ if (!(ret = clock_gettime(UL_CLOCK_MONOTONIC, &ts))) {
tv->tv_sec = ts.tv_sec;
tv->tv_usec = ts.tv_nsec / 1000;
}
diff --git a/lib/path.c b/lib/path.c
index 9cc2e3e2e..a9c47f2a1 100644
--- a/lib/path.c
+++ b/lib/path.c
@@ -94,8 +94,7 @@ void ul_unref_path(struct path_cxt *pc)
DBG(CXT, ul_debugobj(pc, "dealloc"));
if (pc->dialect)
pc->free_dialect(pc);
- if (pc->dir_fd >= 0)
- close(pc->dir_fd);
+ ul_path_close_dirfd(pc);
free(pc->dir_path);
free(pc->prefix);
free(pc);
@@ -212,6 +211,23 @@ int ul_path_get_dirfd(struct path_cxt *pc)
return pc->dir_fd;
}
+/* Note that next ul_path_get_dirfd() will reopen the directory */
+void ul_path_close_dirfd(struct path_cxt *pc)
+{
+ assert(pc);
+
+ if (pc->dir_fd >= 0) {
+ DBG(CXT, ul_debugobj(pc, "closing dir: '%s'", pc->dir_path));
+ close(pc->dir_fd);
+ pc->dir_fd = -1;
+ }
+}
+
+int ul_path_isopen_dirfd(struct path_cxt *pc)
+{
+ return pc && pc->dir_fd >= 0;
+}
+
static const char *ul_path_mkpath(struct path_cxt *pc, const char *path, va_list ap)
{
int rc = vsnprintf(pc->path_buffer, sizeof(pc->path_buffer), path, ap);
@@ -301,7 +317,7 @@ int ul_path_open(struct path_cxt *pc, int flags, const char *path)
if (!pc) {
fd = open(path, flags);
- DBG(CXT, ul_debug("opening '%s'", path));
+ DBG(CXT, ul_debug("opening '%s' [no context]", path));
} else {
int fdx;
int dir = ul_path_get_dirfd(pc);
@@ -567,9 +583,9 @@ int ul_path_read_string(struct path_cxt *pc, char **str, const char *path)
rc = ul_path_read(pc, buf, sizeof(buf) - 1, path);
if (rc < 0 || !str)
- return rc;;
+ return rc;
- /* Remove tailing newline (usuall in sysfs) */
+ /* Remove tailing newline (usual in sysfs) */
if (rc > 0 && *(buf + rc - 1) == '\n')
--rc;
@@ -600,9 +616,9 @@ int ul_path_read_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const char
{
int rc = ul_path_read(pc, buf, bufsz - 1, path);
if (rc < 0)
- return rc;;
+ return rc;
- /* Remove tailing newline (usuall in sysfs) */
+ /* Remove tailing newline (usual in sysfs) */
if (rc > 0 && *(buf + rc - 1) == '\n')
--rc;
@@ -687,7 +703,7 @@ int ul_path_readf_s64(struct path_cxt *pc, int64_t *res, const char *path, ...)
va_end(ap);
if (!p)
- return -EINVAL;;
+ return -EINVAL;
return ul_path_read_s64(pc, res, p);
}
@@ -834,6 +850,28 @@ int ul_path_writef_string(struct path_cxt *pc, const char *str, const char *path
return ul_path_write_string(pc, str, p);
}
+int ul_path_write_s64(struct path_cxt *pc, int64_t num, const char *path)
+{
+ char buf[sizeof(stringify_value(LLONG_MAX))];
+ int rc, errsv;
+ int fd, len;
+
+ fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path);
+ if (fd < 0)
+ return -errno;
+
+ len = snprintf(buf, sizeof(buf), "%" PRId64, num);
+ if (len < 0 || (size_t) len >= sizeof(buf))
+ rc = len < 0 ? -errno : -E2BIG;
+ else
+ rc = write_all(fd, buf, len);
+
+ errsv = errno;
+ close(fd);
+ errno = errsv;
+ return rc;
+}
+
int ul_path_write_u64(struct path_cxt *pc, uint64_t num, const char *path)
{
char buf[sizeof(stringify_value(ULLONG_MAX))];
diff --git a/lib/strutils.c b/lib/strutils.c
index b71dde596..369d50159 100644
--- a/lib/strutils.c
+++ b/lib/strutils.c
@@ -551,6 +551,7 @@ char *size_to_human_string(int options, uint64_t bytes)
if (options & SIZE_SUFFIX_SPACE)
*psuf++ = ' ';
+
exp = get_exp(bytes);
c = *(letters + (exp ? exp / 10 : 0));
dec = exp ? bytes / (1ULL << exp) : bytes;
@@ -569,11 +570,17 @@ char *size_to_human_string(int options, uint64_t bytes)
* exp, suffix[0], dec, frac);
*/
+ /* round */
if (frac) {
- /* round */
- frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
- if (frac == 10)
- dec++, frac = 0;
+ if (options & SIZE_DECIMAL_2DIGITS) {
+ frac = (frac / (1ULL << (exp - 10)) + 5) / 10;
+ if (frac % 10 == 0)
+ frac /= 10; /* convert N.90 to N.9 */
+ } else {
+ frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
+ if (frac == 10)
+ dec++, frac = 0;
+ }
}
if (frac) {
diff --git a/lib/sysfs.c b/lib/sysfs.c
index 626451bdd..6916c2584 100644
--- a/lib/sysfs.c
+++ b/lib/sysfs.c
@@ -999,6 +999,20 @@ char *sysfs_devno_to_devname(dev_t devno, char *buf, size_t bufsiz)
return res;
}
+int sysfs_devno_count_partitions(dev_t devno)
+{
+ struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL);
+ int n = 0;
+
+ if (pc) {
+ char buf[PATH_MAX + 1];
+ char *name = sysfs_blkdev_get_name(pc, buf, sizeof(buf));
+
+ n = sysfs_blkdev_count_partitions(pc, name);
+ ul_unref_path(pc);
+ }
+ return n;
+}
#ifdef TEST_PROGRAM_SYSFS
diff --git a/lib/timer.c b/lib/timer.c
index 210c726cb..c1ea54eb8 100644
--- a/lib/timer.c
+++ b/lib/timer.c
@@ -27,7 +27,9 @@
* The applications need to ensure that they can tolerate multiple signal
* deliveries.
*/
-int setup_timer(timer_t * t_id, struct itimerval *timeout,
+#ifdef HAVE_TIMER_CREATE
+int setup_timer(struct ul_timer *timer,
+ struct itimerval *timeout,
void (*timeout_handler)(int, siginfo_t *, void *))
{
time_t sec = timeout->it_value.tv_sec;
@@ -52,14 +54,42 @@ int setup_timer(timer_t * t_id, struct itimerval *timeout,
if (sigaction(SIGALRM, &sig_a, NULL))
return 1;
- if (timer_create(CLOCK_MONOTONIC, &sig_e, t_id))
+ if (timer_create(CLOCK_MONOTONIC, &sig_e, &timer->t_id))
return 1;
- if (timer_settime(*t_id, 0, &val, NULL))
+ if (timer_settime(timer->t_id, 0, &val, NULL))
return 1;
return 0;
}
+void cancel_timer(struct ul_timer *timer)
+{
+ timer_delete(timer->t_id);
+}
+
+#else /* !HAVE_TIMER_CREATE */
+
+int setup_timer(struct ul_timer *timer,
+ struct itimerval *timeout,
+ void (*timeout_handler)(int, siginfo_t *, void *))
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ memset(timer, 0, sizeof(*timer));
-void cancel_timer(timer_t *t_id)
+ sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
+ sa.sa_sigaction = timeout_handler;
+
+ if (sigaction(SIGALRM, &sa, &timer->old_sa))
+ return 1;
+ if (setitimer(ITIMER_REAL, timeout, &timer->old_timer) != 0)
+ return 1;
+ return 0;
+}
+
+void cancel_timer(struct ul_timer *timer)
{
- timer_delete(*t_id);
+ setitimer(ITIMER_REAL, &timer->old_timer, NULL);
+ sigaction(SIGALRM, &timer->old_sa, NULL);
+
}
+#endif /* !HAVE_TIMER_CREATE */
diff --git a/lib/timeutils.c b/lib/timeutils.c
index 9c286aebc..d403ced90 100644
--- a/lib/timeutils.c
+++ b/lib/timeutils.c
@@ -503,34 +503,37 @@ int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz)
}
/* relative time functions */
-int time_is_today(const time_t *t, struct timeval *now)
+static inline int time_is_thisyear(struct tm const *const tm,
+ struct tm const *const tmnow)
{
- if (now->tv_sec == 0)
- gettimeofday(now, NULL);
- return *t / (3600 * 24) == now->tv_sec / (3600 * 24);
+ return tm->tm_year == tmnow->tm_year;
}
-int time_is_thisyear(const time_t *t, struct timeval *now)
+static inline int time_is_today(struct tm const *const tm,
+ struct tm const *const tmnow)
{
- if (now->tv_sec == 0)
- gettimeofday(now, NULL);
- return *t / (3600 * 24 * 365) == now->tv_sec / (3600 * 24 * 365);
+ return (tm->tm_yday == tmnow->tm_yday &&
+ time_is_thisyear(tm, tmnow));
}
int strtime_short(const time_t *t, struct timeval *now, int flags, char *buf, size_t bufsz)
{
- struct tm tm;
+ struct tm tm, tmnow;
int rc = 0;
- localtime_r(t, &tm);
+ if (now->tv_sec == 0)
+ gettimeofday(now, NULL);
+
+ localtime_r(t, &tm);
+ localtime_r(&now->tv_sec, &tmnow);
- if (time_is_today(t, now)) {
+ if (time_is_today(&tm, &tmnow)) {
rc = snprintf(buf, bufsz, "%02d:%02d", tm.tm_hour, tm.tm_min);
if (rc < 0 || (size_t) rc > bufsz)
return -1;
rc = 1;
- } else if (time_is_thisyear(t, now)) {
+ } else if (time_is_thisyear(&tm, &tmnow)) {
if (flags & UL_SHORTTIME_THISYEAR_HHMM)
rc = strftime(buf, bufsz, "%b%d/%H:%M", &tm);
else