示例#1
0
static int read_distro_hostname(char **hn) {

#if defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
        int r;
        _cleanup_fclose_ FILE *f = NULL;

        assert(hn);

        f = fopen(FILENAME, "re");
        if (!f)
                return -errno;

        for (;;) {
                char line[LINE_MAX];
                char *s, *k;

                if (!fgets(line, sizeof(line), f)) {
                        if (feof(f))
                                break;

                        r = -errno;
                        goto finish;
                }

                s = strstrip(line);

                if (!startswith_no_case(s, "HOSTNAME="))
                        continue;

                k = strdup(s+9);
                if (!k) {
                        r = -ENOMEM;
                        goto finish;
                }

                hostname_cleanup(k);

                if (isempty(k)) {
                        free(k);
                        r = -ENOENT;
                        goto finish;
                }

                *hn = k;
                r = 0;
                goto finish;
        }

        r = -ENOENT;

finish:
        return r;

#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
        return read_and_strip_hostname(FILENAME, hn);
#else
        return -ENOENT;
#endif
}
示例#2
0
static int remove_boot_efi(const char *esp_path) {
        char *p;
        _cleanup_closedir_ DIR *d = NULL;
        struct dirent *de;
        int r, c = 0;

        p = strjoina(esp_path, "/EFI/Boot");
        d = opendir(p);
        if (!d) {
                if (errno == ENOENT)
                        return 0;

                return log_error_errno(errno, "Failed to open directory \"%s\": %m", p);
        }

        while ((de = readdir(d))) {
                _cleanup_close_ int fd = -1;
                _cleanup_free_ char *v = NULL;

                if (de->d_name[0] == '.')
                        continue;

                if (!endswith_no_case(de->d_name, ".efi"))
                        continue;

                if (!startswith_no_case(de->d_name, "Boot"))
                        continue;

                fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
                if (fd < 0)
                        return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);

                r = get_file_version(fd, &v);
                if (r < 0)
                        return r;
                if (r > 0 && startswith(v, "systemd-boot ")) {
                        r = unlinkat(dirfd(d), de->d_name, 0);
                        if (r < 0)
                                return log_error_errno(errno, "Failed to remove \"%s/%s\": %m", p, de->d_name);

                        log_info("Removed \"%s/%s\".", p, de->d_name);
                }

                c++;
        }

        return c;
}
示例#3
0
static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
        char *p;
        _cleanup_closedir_ DIR *d = NULL;
        struct dirent *de;
        int r = 0, c = 0;

        p = strjoina(esp_path, "/", path);
        d = opendir(p);
        if (!d) {
                if (errno == ENOENT)
                        return 0;

                return log_error_errno(errno, "Failed to read \"%s\": %m", p);
        }

        while ((de = readdir(d))) {
                _cleanup_close_ int fd = -1;
                _cleanup_free_ char *v = NULL;

                if (de->d_name[0] == '.')
                        continue;

                if (!endswith_no_case(de->d_name, ".efi"))
                        continue;

                if (prefix && !startswith_no_case(de->d_name, prefix))
                        continue;

                fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
                if (fd < 0)
                        return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);

                r = get_file_version(fd, &v);
                if (r < 0)
                        return r;
                if (r > 0)
                        printf("         File: └─/%s/%s (%s)\n", path, de->d_name, v);
                else
                        printf("         File: └─/%s/%s\n", path, de->d_name);
                c++;
        }

        return c;
}
示例#4
0
int dns_type_from_string(const char *s) {
        const struct dns_type_name *sc;

        assert(s);

        sc = lookup_dns_type(s, strlen(s));
        if (sc)
                return sc->id;

        s = startswith_no_case(s, "TYPE");
        if (s) {
                unsigned x;

                if (safe_atou(s, &x) >= 0 &&
                    x <= UINT16_MAX)
                        return (int) x;
        }

        return _DNS_TYPE_INVALID;
}
示例#5
0
static int parse_weekdays(const char **p, CalendarSpec *c) {
        static const struct {
                const char *name;
                const int nr;
        } day_nr[] = {
                { "Monday",    0 },
                { "Mon",       0 },
                { "Tuesday",   1 },
                { "Tue",       1 },
                { "Wednesday", 2 },
                { "Wed",       2 },
                { "Thursday",  3 },
                { "Thu",       3 },
                { "Friday",    4 },
                { "Fri",       4 },
                { "Saturday",  5 },
                { "Sat",       5 },
                { "Sunday",    6 },
                { "Sun",       6 }
        };

        int l = -1;
        bool first = true;

        assert(p);
        assert(*p);
        assert(c);

        for (;;) {
                unsigned i;

                if (!first && **p == ' ')
                        return 0;

                for (i = 0; i < ELEMENTSOF(day_nr); i++) {
                        size_t skip;

                        if (!startswith_no_case(*p, day_nr[i].name))
                                continue;

                        skip = strlen(day_nr[i].name);

                        if ((*p)[skip] != '-' &&
                            (*p)[skip] != ',' &&
                            (*p)[skip] != ' ' &&
                            (*p)[skip] != 0)
                                return -EINVAL;

                        c->weekdays_bits |= 1 << day_nr[i].nr;

                        if (l >= 0) {
                                int j;

                                if (l > day_nr[i].nr)
                                        return -EINVAL;

                                for (j = l + 1; j < day_nr[i].nr; j++)
                                        c->weekdays_bits |= 1 << j;
                        }

                        *p += skip;
                        break;
                }

                /* Couldn't find this prefix, so let's assume the
                   weekday was not specified and let's continue with
                   the date */
                if (i >= ELEMENTSOF(day_nr))
                        return first ? 0 : -EINVAL;

                /* We reached the end of the string */
                if (**p == 0)
                        return 0;

                /* We reached the end of the weekday spec part */
                if (**p == ' ') {
                        *p += strspn(*p, " ");
                        return 0;
                }

                if (**p == '-') {
                        if (l >= 0)
                                return -EINVAL;

                        l = day_nr[i].nr;
                } else
                        l = -1;

                *p += 1;
                first = false;
        }
}
示例#6
0
static int parse_weekdays(const char **p, CalendarSpec *c) {
        static const struct {
                const char *name;
                const int nr;
        } day_nr[] = {
                { "Monday",    0 },
                { "Mon",       0 },
                { "Tuesday",   1 },
                { "Tue",       1 },
                { "Wednesday", 2 },
                { "Wed",       2 },
                { "Thursday",  3 },
                { "Thu",       3 },
                { "Friday",    4 },
                { "Fri",       4 },
                { "Saturday",  5 },
                { "Sat",       5 },
                { "Sunday",    6 },
                { "Sun",       6 }
        };

        int l = -1;
        bool first = true;

        assert(p);
        assert(*p);
        assert(c);

        for (;;) {
                unsigned i;

                for (i = 0; i < ELEMENTSOF(day_nr); i++) {
                        size_t skip;

                        if (!startswith_no_case(*p, day_nr[i].name))
                                continue;

                        skip = strlen(day_nr[i].name);

                        if (!IN_SET((*p)[skip], 0, '-', '.', ',', ' '))
                                return -EINVAL;

                        c->weekdays_bits |= 1 << day_nr[i].nr;

                        if (l >= 0) {
                                int j;

                                if (l > day_nr[i].nr)
                                        return -EINVAL;

                                for (j = l + 1; j < day_nr[i].nr; j++)
                                        c->weekdays_bits |= 1 << j;
                        }

                        *p += skip;
                        break;
                }

                /* Couldn't find this prefix, so let's assume the
                   weekday was not specified and let's continue with
                   the date */
                if (i >= ELEMENTSOF(day_nr))
                        return first ? 0 : -EINVAL;

                /* We reached the end of the string */
                if (**p == 0)
                        return 0;

                /* We reached the end of the weekday spec part */
                if (**p == ' ') {
                        *p += strspn(*p, " ");
                        return 0;
                }

                if (**p == '.') {
                        if (l >= 0)
                                return -EINVAL;

                        if ((*p)[1] != '.')
                                return -EINVAL;

                        l = day_nr[i].nr;
                        *p += 2;

                /* Support ranges with "-" for backwards compatibility */
                } else if (**p == '-') {
                        if (l >= 0)
                                return -EINVAL;

                        l = day_nr[i].nr;
                        *p += 1;

                } else if (**p == ',') {
                        l = -1;
                        *p += 1;
                }

                /* Allow a trailing comma but not an open range */
                if (IN_SET(**p, 0, ' ')) {
                        *p += strspn(*p, " ");
                        return l < 0 ? 0 : -EINVAL;
                }

                first = false;
        }
}
示例#7
0
int parse_timestamp(const char *t, usec_t *usec)
{
	 static const struct {
		const char *name;
		const int nr;
	 } day_nr[] = {
		{ "Sunday",	0 },
		{ "Sun",	0 },
		{ "Monday",	1 },
		{ "Mon",	1 },
		{ "Tuesday",	2 },
		{ "Tue",	2 },
		{ "Wednesday",	3 },
		{ "Wed",	3 },
		{ "Thursday",	4 },
		{ "Thu",	4 },
		{ "Friday",	5 },
		{ "Fri",	5 },
		{ "Saturday",	6 },
		{ "Sat",	6 },
	 };

	const char *k;
	struct tm tm, copy;
	time_t x;
	usec_t plus = 0, minus = 0, ret;
	int r, weekday = -1;
	unsigned i;

	/*
	 * Allowed syntaxes:
	 *
	 *   2012-09-22 16:34:22
	 *   2012-09-22 16:34	  (seconds will be set to 0)
	 *   2012-09-22		  (time will be set to 00:00:00)
	 *   16:34:22		  (date will be set to today)
	 *   16:34		  (date will be set to today, seconds to 0)
	 *   now
	 *   yesterday		  (time is set to 00:00:00)
	 *   today		  (time is set to 00:00:00)
	 *   tomorrow		  (time is set to 00:00:00)
	 *   +5min
	 *   -5days
	 *
	 */

	assert(t);
	assert(usec);

	x = time(NULL);
	localtime_r(&x, &tm);
	tm.tm_isdst = -1;

	if (streq(t, "now"))
		goto finish;

	else if (streq(t, "today")) {
		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
		goto finish;

	} else if (streq(t, "yesterday")) {
		tm.tm_mday--;
		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
		goto finish;

	} else if (streq(t, "tomorrow")) {
		tm.tm_mday++;
		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
		goto finish;

	} else if (t[0] == '+') {

		r = parse_sec(t + 1, &plus);
		if (r < 0)
			return r;

		goto finish;
	} else if (t[0] == '-') {

		r = parse_sec(t + 1, &minus);
		if (r < 0)
			return r;

		goto finish;

	} else if (endswith(t, " ago")) {
		char *z;

		z = strndup(t, strlen(t) - 4);
		if (!z)
			return -ENOMEM;

		r = parse_sec(z, &minus);
		if (r < 0)
			return r;

		goto finish;
	}

	for (i = 0; i < ARRAY_SIZE(day_nr); i++) {
		size_t skip;

		if (!startswith_no_case(t, day_nr[i].name))
			continue;

		skip = strlen(day_nr[i].name);
		if (t[skip] != ' ')
			continue;

		weekday = day_nr[i].nr;
		t += skip + 1;
		break;
	}

	copy = tm;
	k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
	if (k && *k == 0)
		goto finish;

	tm = copy;
	k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
	if (k && *k == 0)
		goto finish;

	tm = copy;
	k = strptime(t, "%y-%m-%d %H:%M", &tm);
	if (k && *k == 0) {
		tm.tm_sec = 0;
		goto finish;
	}

	tm = copy;
	k = strptime(t, "%Y-%m-%d %H:%M", &tm);
	if (k && *k == 0) {
		tm.tm_sec = 0;
		goto finish;
	}

	tm = copy;
	k = strptime(t, "%y-%m-%d", &tm);
	if (k && *k == 0) {
		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
		goto finish;
	}

	tm = copy;
	k = strptime(t, "%Y-%m-%d", &tm);
	if (k && *k == 0) {
		tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
		goto finish;
	}

	tm = copy;
	k = strptime(t, "%H:%M:%S", &tm);
	if (k && *k == 0)
		goto finish;

	tm = copy;
	k = strptime(t, "%H:%M", &tm);
	if (k && *k == 0) {
		tm.tm_sec = 0;
		goto finish;
	}

	tm = copy;
	k = strptime(t, "%Y%m%d%H%M%S", &tm);
	if (k && *k == 0) {
		tm.tm_sec = 0;
		goto finish;
	}

	return -EINVAL;

 finish:
	x = mktime(&tm);
	if (x == (time_t)-1)
		return -EINVAL;

	if (weekday >= 0 && tm.tm_wday != weekday)
		return -EINVAL;

	ret = (usec_t) x *USEC_PER_SEC;

	ret += plus;
	if (ret > minus)
		ret -= minus;
	else
		ret = 0;

	*usec = ret;

	return 0;
}
示例#8
0
int parse_timestamp(const char *t, usec_t *usec) {
        static const struct {
                const char *name;
                const int nr;
        } day_nr[] = {
                { "Sunday",    0 },
                { "Sun",       0 },
                { "Monday",    1 },
                { "Mon",       1 },
                { "Tuesday",   2 },
                { "Tue",       2 },
                { "Wednesday", 3 },
                { "Wed",       3 },
                { "Thursday",  4 },
                { "Thu",       4 },
                { "Friday",    5 },
                { "Fri",       5 },
                { "Saturday",  6 },
                { "Sat",       6 },
        };

        const char *k;
        const char *utc;
        struct tm tm, copy;
        time_t x;
        usec_t x_usec, plus = 0, minus = 0, ret;
        int r, weekday = -1;
        unsigned i;

        /*
         * Allowed syntaxes:
         *
         *   2012-09-22 16:34:22
         *   2012-09-22 16:34     (seconds will be set to 0)
         *   2012-09-22           (time will be set to 00:00:00)
         *   16:34:22             (date will be set to today)
         *   16:34                (date will be set to today, seconds to 0)
         *   now
         *   yesterday            (time is set to 00:00:00)
         *   today                (time is set to 00:00:00)
         *   tomorrow             (time is set to 00:00:00)
         *   +5min
         *   -5days
         *   @2147483647          (seconds since epoch)
         *
         */

        assert(t);
        assert(usec);

        if (t[0] == '@')
                return parse_sec(t + 1, usec);

        ret = now(CLOCK_REALTIME);

        if (streq(t, "now"))
                goto finish;

        else if (t[0] == '+') {
                r = parse_sec(t+1, &plus);
                if (r < 0)
                        return r;

                goto finish;

        } else if (t[0] == '-') {
                r = parse_sec(t+1, &minus);
                if (r < 0)
                        return r;

                goto finish;

        } else if ((k = endswith(t, " ago"))) {
                t = strndupa(t, k - t);

                r = parse_sec(t, &minus);
                if (r < 0)
                        return r;

                goto finish;

        } else if ((k = endswith(t, " left"))) {
                t = strndupa(t, k - t);

                r = parse_sec(t, &plus);
                if (r < 0)
                        return r;

                goto finish;
        }

        utc = endswith_no_case(t, " UTC");
        if (utc)
                t = strndupa(t, utc - t);

        x = ret / USEC_PER_SEC;
        x_usec = 0;

        assert_se(localtime_or_gmtime_r(&x, &tm, utc));
        tm.tm_isdst = -1;

        if (streq(t, "today")) {
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;

        } else if (streq(t, "yesterday")) {
                tm.tm_mday --;
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;

        } else if (streq(t, "tomorrow")) {
                tm.tm_mday ++;
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;
        }


        for (i = 0; i < ELEMENTSOF(day_nr); i++) {
                size_t skip;

                if (!startswith_no_case(t, day_nr[i].name))
                        continue;

                skip = strlen(day_nr[i].name);
                if (t[skip] != ' ')
                        continue;

                weekday = day_nr[i].nr;
                t += skip + 1;
                break;
        }

        copy = tm;
        k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
        if (k) {
                if (*k == '.')
                        goto parse_usec;
                else if (*k == 0)
                        goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
        if (k) {
                if (*k == '.')
                        goto parse_usec;
                else if (*k == 0)
                        goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%y-%m-%d %H:%M", &tm);
        if (k && *k == 0) {
                tm.tm_sec = 0;
                goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%Y-%m-%d %H:%M", &tm);
        if (k && *k == 0) {
                tm.tm_sec = 0;
                goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%y-%m-%d", &tm);
        if (k && *k == 0) {
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%Y-%m-%d", &tm);
        if (k && *k == 0) {
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%H:%M:%S", &tm);
        if (k) {
                if (*k == '.')
                        goto parse_usec;
                else if (*k == 0)
                        goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%H:%M", &tm);
        if (k && *k == 0) {
                tm.tm_sec = 0;
                goto from_tm;
        }

        return -EINVAL;

parse_usec:
        {
                unsigned add;

                k++;
                r = parse_fractional_part_u(&k, 6, &add);
                if (r < 0)
                        return -EINVAL;

                if (*k)
                        return -EINVAL;

                x_usec = add;

        }

from_tm:
        x = mktime_or_timegm(&tm, utc);
        if (x == (time_t) -1)
                return -EINVAL;

        if (weekday >= 0 && tm.tm_wday != weekday)
                return -EINVAL;

        ret = (usec_t) x * USEC_PER_SEC + x_usec;

finish:
        ret += plus;
        if (ret > minus)
                ret -= minus;
        else
                ret = 0;

        *usec = ret;

        return 0;
}
示例#9
0
int parse_timestamp(const char *t, usec_t *usec) {
        static const struct {
                const char *name;
                const int nr;
        } day_nr[] = {
                { "Sunday",    0 },
                { "Sun",       0 },
                { "Monday",    1 },
                { "Mon",       1 },
                { "Tuesday",   2 },
                { "Tue",       2 },
                { "Wednesday", 3 },
                { "Wed",       3 },
                { "Thursday",  4 },
                { "Thu",       4 },
                { "Friday",    5 },
                { "Fri",       5 },
                { "Saturday",  6 },
                { "Sat",       6 },
        };

        const char *k, *utc, *tzn = NULL;
        struct tm tm, copy;
        time_t x;
        usec_t x_usec, plus = 0, minus = 0, ret;
        int r, weekday = -1, dst = -1;
        unsigned i;

        /*
         * Allowed syntaxes:
         *
         *   2012-09-22 16:34:22
         *   2012-09-22 16:34     (seconds will be set to 0)
         *   2012-09-22           (time will be set to 00:00:00)
         *   16:34:22             (date will be set to today)
         *   16:34                (date will be set to today, seconds to 0)
         *   now
         *   yesterday            (time is set to 00:00:00)
         *   today                (time is set to 00:00:00)
         *   tomorrow             (time is set to 00:00:00)
         *   +5min
         *   -5days
         *   @2147483647          (seconds since epoch)
         *
         */

        assert(t);
        assert(usec);

        if (t[0] == '@')
                return parse_sec(t + 1, usec);

        ret = now(CLOCK_REALTIME);

        if (streq(t, "now"))
                goto finish;

        else if (t[0] == '+') {
                r = parse_sec(t+1, &plus);
                if (r < 0)
                        return r;

                goto finish;

        } else if (t[0] == '-') {
                r = parse_sec(t+1, &minus);
                if (r < 0)
                        return r;

                goto finish;

        } else if ((k = endswith(t, " ago"))) {
                t = strndupa(t, k - t);

                r = parse_sec(t, &minus);
                if (r < 0)
                        return r;

                goto finish;

        } else if ((k = endswith(t, " left"))) {
                t = strndupa(t, k - t);

                r = parse_sec(t, &plus);
                if (r < 0)
                        return r;

                goto finish;
        }

        /* See if the timestamp is suffixed with UTC */
        utc = endswith_no_case(t, " UTC");
        if (utc)
                t = strndupa(t, utc - t);
        else {
                const char *e = NULL;
                int j;

                tzset();

                /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
                 * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
                 * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
                 * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
                 * support arbitrary timezone specifications.  */

                for (j = 0; j <= 1; j++) {

                        if (isempty(tzname[j]))
                                continue;

                        e = endswith_no_case(t, tzname[j]);
                        if (!e)
                                continue;
                        if (e == t)
                                continue;
                        if (e[-1] != ' ')
                                continue;

                        break;
                }

                if (IN_SET(j, 0, 1)) {
                        /* Found one of the two timezones specified. */
                        t = strndupa(t, e - t - 1);
                        dst = j;
                        tzn = tzname[j];
                }
        }

        x = (time_t) (ret / USEC_PER_SEC);
        x_usec = 0;

        if (!localtime_or_gmtime_r(&x, &tm, utc))
                return -EINVAL;

        tm.tm_isdst = dst;
        if (tzn)
                tm.tm_zone = tzn;

        if (streq(t, "today")) {
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;

        } else if (streq(t, "yesterday")) {
                tm.tm_mday--;
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;

        } else if (streq(t, "tomorrow")) {
                tm.tm_mday++;
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;
        }

        for (i = 0; i < ELEMENTSOF(day_nr); i++) {
                size_t skip;

                if (!startswith_no_case(t, day_nr[i].name))
                        continue;

                skip = strlen(day_nr[i].name);
                if (t[skip] != ' ')
                        continue;

                weekday = day_nr[i].nr;
                t += skip + 1;
                break;
        }

        copy = tm;
        k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
        if (k) {
                if (*k == '.')
                        goto parse_usec;
                else if (*k == 0)
                        goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
        if (k) {
                if (*k == '.')
                        goto parse_usec;
                else if (*k == 0)
                        goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%y-%m-%d %H:%M", &tm);
        if (k && *k == 0) {
                tm.tm_sec = 0;
                goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%Y-%m-%d %H:%M", &tm);
        if (k && *k == 0) {
                tm.tm_sec = 0;
                goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%y-%m-%d", &tm);
        if (k && *k == 0) {
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%Y-%m-%d", &tm);
        if (k && *k == 0) {
                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
                goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%H:%M:%S", &tm);
        if (k) {
                if (*k == '.')
                        goto parse_usec;
                else if (*k == 0)
                        goto from_tm;
        }

        tm = copy;
        k = strptime(t, "%H:%M", &tm);
        if (k && *k == 0) {
                tm.tm_sec = 0;
                goto from_tm;
        }

        return -EINVAL;

parse_usec:
        {
                unsigned add;

                k++;
                r = parse_fractional_part_u(&k, 6, &add);
                if (r < 0)
                        return -EINVAL;

                if (*k)
                        return -EINVAL;

                x_usec = add;
        }

from_tm:
        x = mktime_or_timegm(&tm, utc);
        if (x == (time_t) -1)
                return -EINVAL;

        if (weekday >= 0 && tm.tm_wday != weekday)
                return -EINVAL;

        ret = (usec_t) x * USEC_PER_SEC + x_usec;

finish:
        ret += plus;
        if (ret > minus)
                ret -= minus;
        else
                ret = 0;

        *usec = ret;

        return 0;
}