Skip to content

Commit

Permalink
Added timezone to the CalendarSpec and the parser/formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
zerkms committed Sep 6, 2017
1 parent c70b51a commit 367325a
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
79 changes: 79 additions & 0 deletions src/basic/calendarspec.c
Expand Up @@ -25,6 +25,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <time.h>

#include "alloc-util.h"
Expand Down Expand Up @@ -59,6 +61,7 @@ void calendar_spec_free(CalendarSpec *c) {
free_chain(c->hour);
free_chain(c->minute);
free_chain(c->microsecond);
free(c->timezone);

free(c);
}
Expand Down Expand Up @@ -363,6 +366,11 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
}
}

if (c->timezone != NULL) {
fputc_unlocked(' ', f);
fputs_unlocked(c->timezone, f);
}

r = fflush_and_check(f);
if (r < 0) {
free(buf);
Expand Down Expand Up @@ -876,6 +884,53 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
return r;
}

static int is_valid_timezone(char *tz, bool *result)
{
pid_t pid;

if (tz == NULL || strlen(tz) == 0) {
*result = false;
return 0;
}

bool *shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);

if (shared == MAP_FAILED) {
return log_error_errno(errno, "mmap() failed: %m");
}

pid = fork();

if (pid == -1) {
munmap(shared, sizeof *shared);
return log_error_errno(errno, "Failed to fork: %m");
}

if (pid == 0) {
setenv("TZ", tz, 1);
tzset();

*shared = strlen(tzname[1]) > 0;

_exit(0);
}

if (waitpid(pid, NULL, 0) == -1) {
int waitpid_errno = errno;
munmap(shared, sizeof *shared);
return log_error_errno(waitpid_errno, "waitpid() failed: %m");;
}

bool tmp_result = *shared;
if (munmap(shared, sizeof *shared) != 0) {
return log_error_errno(errno, "munmap() failed: %m");;
}

*result = tmp_result;

return 0;
}

int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
const char *utc;
CalendarSpec *c;
Expand All @@ -888,6 +943,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (!c)
return -ENOMEM;
c->dst = -1;
c->timezone = NULL;

utc = endswith_no_case(p, " UTC");
if (utc) {
Expand Down Expand Up @@ -919,6 +975,29 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (IN_SET(j, 0, 1)) {
p = strndupa(p, e - p - 1);
c->dst = j;
} else {
char *last_space = strrchr(p, ' ');

if (last_space != NULL) {
char *timezone = last_space + 1;

bool timezone_is_valid;
if (is_valid_timezone(timezone, &timezone_is_valid) != 0) {
r = -EINVAL;
goto fail;
}

if (timezone_is_valid) {
c->timezone = malloc(strlen(timezone) + 1);
if (c->timezone == NULL) {
r = -EINVAL;
goto fail;
}

strcpy(c->timezone, timezone);
p = strndupa(p, last_space - p);
}
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/basic/calendarspec.h
Expand Up @@ -40,6 +40,7 @@ typedef struct CalendarSpec {
bool end_of_month;
bool utc;
int dst;
char *timezone;

CalendarComponent *year;
CalendarComponent *month;
Expand Down
2 changes: 2 additions & 0 deletions src/test/test-calendarspec.c
Expand Up @@ -170,6 +170,8 @@ int main(int argc, char* argv[]) {
test_one("annually", "*-01-01 00:00:00");
test_one("*:2/3", "*-*-* *:02/3:00");
test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC");
test_one("2015-10-25 01:00:00 Asia/Vladivostok", "2015-10-25 01:00:00 Asia/Vladivostok");
test_one("weekly Pacific/Auckland", "Mon *-*-* 00:00:00 Pacific/Auckland");
test_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001");
test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000");
test_one("9..11,13:00,30", "*-*-* 09..11,13:00,30:00");
Expand Down

0 comments on commit 367325a

Please sign in to comment.