diff --git a/Makefile.am b/Makefile.am index 6f72aea..73f7761 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,16 @@ AM_CFLAGS = $(WARN_CFLAGS) sbin_PROGRAMS = gcrond -gcrond_SOURCES = gcrond.c gcrond.h rdcron.c crontab.c cronscan.c rdline.c +gcrond_SOURCES = gcrond.c gcrond.h rdcron.c crontab.c cronscan.c +gcrond_CPPFLAGS = $(AM_CPPFLAGS) +gcrond_CFLAGS = $(AM_CFLAGS) +gcrond_LDADD = + +if HAVE_LIBBSD +gcrond_CPPFLAGS += -DHAVE_LIBBSD +gcrond_CFLAGS += $(LIBBSD_CFLAGS) +gcrond_LDADD += $(LIBBSD_LIBS) +endif crontabdir = @GCRONDIR@ crontab_DATA = crontab/0-example diff --git a/configure.ac b/configure.ac index 62e94cf..1e89c14 100644 --- a/configure.ac +++ b/configure.ac @@ -8,6 +8,23 @@ AC_PROG_CC AC_PROG_CC_C99 AC_PROG_INSTALL AC_PROG_RANLIB +AC_CANONICAL_HOST + +m4_ifndef([PKG_PROG_PKG_CONFIG], + [m4_fatal([Could not locate the pkg-config autoconf + macros. These are usually located in /usr/share/aclocal/pkg.m4. + If your macros are in a different location, try setting the + environment variable AL_OPTS="-I/other/macro/dir" before running + ./autogen.sh or autoreconf again. Make sure pkg-config is installed.])]) +PKG_PROG_PKG_CONFIG + +case "${host_os}" in +linux*) + AM_CONDITIONAL([HAVE_LIBBSD], [true]) + PKG_CHECK_MODULES(LIBBSD, [libbsd], [], + [AC_MSG_ERROR([missing libbsd])]) + ;; +esac UL_WARN_ADD([-Wall]) UL_WARN_ADD([-Wextra]) diff --git a/gcrond.h b/gcrond.h index c6f3071..9fe816d 100644 --- a/gcrond.h +++ b/gcrond.h @@ -21,6 +21,10 @@ #include #include +#ifdef HAVE_LIBBSD +#include +#endif + #include "config.h" #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -43,14 +47,6 @@ typedef struct { char *line; } rdline_t; -int rdline_init(rdline_t *t, int dirfd, const char *filename); - -void rdline_complain(rdline_t *t, const char *msg, ...); - -void rdline_cleanup(rdline_t *t); - -int rdline(rdline_t *t); - crontab_t *rdcron(int dirfd, const char *filename); void delcron(crontab_t *cron); diff --git a/rdcron.c b/rdcron.c index 9a9171e..91be4d0 100644 --- a/rdcron.c +++ b/rdcron.c @@ -96,6 +96,10 @@ static const struct { /*****************************************************************************/ +#define complainf(rd, msg, ...) \ + fprintf(stderr, "%s: %zu: " msg "\n", \ + rd->filename, rd->lineno, __VA_ARGS__) + static char *readnum(char *line, int *out, int minval, int maxval, const enum_map_t *mnemonic, rdline_t *rd) { @@ -113,7 +117,7 @@ static char *readnum(char *line, int *out, int minval, int maxval, } if (ev->name == NULL) { - rdline_complain(rd, "unexpected '%.*s'", i, line); + complainf(rd, "unexpected '%.*s'", i, line); return NULL; } @@ -138,13 +142,14 @@ static char *readnum(char *line, int *out, int minval, int maxval, *out = value; return line; fail_of: - rdline_complain(rd, "value exceeds maximum (%d > %d)", value, maxval); + complainf(rd, "value exceeds maximum (%d > %d)", value, maxval); return NULL; fail_uf: - rdline_complain(rd, "value too small (%d < %d)", value, minval); + complainf(rd, "value too small (%d < %d)", value, minval); return NULL; fail_mn: - rdline_complain(rd, "expected numeric value"); + fprintf(stderr, "%s: %zu: expected numeric value\n", + rd->filename, rd->lineno); return NULL; } @@ -201,7 +206,8 @@ next: return line; fail: - rdline_complain(rd, "invalid time range expression"); + fprintf(stderr, "%s: %zu: invalid time range expression\n", + rd->filename, rd->lineno); return NULL; } @@ -229,7 +235,7 @@ static char *cron_interval(crontab_t *cron, rdline_t *rd) *cron = intervals[i].tab; return rd->line + j; fail: - rdline_complain(rd, "unknown interval '%.*s'", (int)j, rd->line); + complainf(rd, "unknown interval '%.*s'", (int)j, rd->line); return NULL; } @@ -266,14 +272,39 @@ crontab_t *rdcron(int dirfd, const char *filename) crontab_t *cron, *list = NULL; rdline_t rd; char *ptr; + int fd; - if (rdline_init(&rd, dirfd, filename)) + memset(&rd, 0, sizeof(rd)); + rd.filename = filename; + + fd = openat(dirfd, filename, O_RDONLY); + if (fd == -1) { + perror(filename); return NULL; + } + + rd.fp = fdopen(fd, "r"); + if (rd.fp == NULL) { + perror("fdopen"); + close(fd); + return NULL; + } + + for (;;) { + free(rd.line); + errno = 0; + + rd.line = fparseln(rd.fp, NULL, &rd.lineno, NULL, 0); + + if (rd.line == NULL) { + if (errno) + perror(filename); + break; + } - while (rdline(&rd) == 0) { cron = calloc(1, sizeof(*cron)); if (cron == NULL) { - rdline_complain(&rd, strerror(errno)); + perror(filename); break; } @@ -293,7 +324,7 @@ crontab_t *rdcron(int dirfd, const char *filename) cron->exec = strdup(ptr); if (cron->exec == NULL) { - rdline_complain(&rd, strerror(errno)); + perror(filename); free(cron); continue; } @@ -302,6 +333,6 @@ crontab_t *rdcron(int dirfd, const char *filename) list = cron; } - rdline_cleanup(&rd); + fclose(rd.fp); return list; } diff --git a/rdline.c b/rdline.c deleted file mode 100644 index 99b4f4e..0000000 --- a/rdline.c +++ /dev/null @@ -1,77 +0,0 @@ -/* SPDX-License-Identifier: ISC */ -#include "gcrond.h" - -int rdline(rdline_t *t) -{ - size_t i, len; - - do { - free(t->line); - t->line = NULL; - errno = 0; - len = 0; - - if (getline(&t->line, &len, t->fp) < 0) { - if (errno) { - rdline_complain(t, strerror(errno)); - return -1; - } - return 1; - } - - t->lineno += 1; - - for (i = 0; isspace(t->line[i]); ++i) - ; - - if (t->line[i] == '\0' || t->line[i] == '#') { - t->line[0] = '\0'; - } else if (i) { - memmove(t->line, t->line + i, len - i + 1); - } - } while (t->line[0] == '\0'); - - return 0; -} - -void rdline_complain(rdline_t *t, const char *msg, ...) -{ - va_list ap; - - fprintf(stderr, "%s: %zu: ", t->filename, t->lineno); - - va_start(ap, msg); - vfprintf(stderr, msg, ap); - va_end(ap); - - fputc('\n', stderr); -} - -int rdline_init(rdline_t *t, int dirfd, const char *filename) -{ - int fd; - - memset(t, 0, sizeof(*t)); - - fd = openat(dirfd, filename, O_RDONLY); - if (fd == -1) { - perror(filename); - return -1; - } - - t->fp = fdopen(fd, "r"); - if (t->fp == NULL) { - perror("fdopen"); - close(fd); - return -1; - } - - t->filename = filename; - return 0; -} - -void rdline_cleanup(rdline_t *t) -{ - free(t->line); - fclose(t->fp); -}