123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- /*
- * Copyright (c) 2020 Nick Ward
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include <stdlib.h>
- #include <shell/shell.h>
- #include <init.h>
- #include <string.h>
- #include <posix/time.h>
- #include <sys/timeutil.h>
- #define HELP_NONE "[none]"
- #define HELP_DATE_SET "[Y-m-d] <H:M:S>"
- static void date_print(const struct shell *shell, struct tm *tm)
- {
- shell_print(shell,
- "%d-%02u-%02u "
- "%02u:%02u:%02u UTC",
- tm->tm_year + 1900,
- tm->tm_mon + 1,
- tm->tm_mday,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- }
- static int get_y_m_d(const struct shell *shell, struct tm *tm, char *date_str)
- {
- int year;
- int month;
- int day;
- char *endptr;
- endptr = NULL;
- year = strtol(date_str, &endptr, 10);
- if ((endptr == date_str) || (*endptr != '-')) {
- return -EINVAL;
- }
- date_str = endptr + 1;
- endptr = NULL;
- month = strtol(date_str, &endptr, 10);
- if ((endptr == date_str) || (*endptr != '-')) {
- return -EINVAL;
- }
- if ((month < 1) || (month > 12)) {
- shell_error(shell, "Invalid month");
- return -EINVAL;
- }
- date_str = endptr + 1;
- endptr = NULL;
- day = strtol(date_str, &endptr, 10);
- if ((endptr == date_str) || (*endptr != '\0')) {
- return -EINVAL;
- }
- /* Check day against maximum month length */
- if ((day < 1) || (day > 31)) {
- shell_error(shell, "Invalid day");
- return -EINVAL;
- }
- tm->tm_year = year - 1900;
- tm->tm_mon = month - 1;
- tm->tm_mday = day;
- return 0;
- }
- /*
- * For user convenience of small adjustments to time the time argument will
- * accept H:M:S, :M:S or ::S where the missing field(s) will be filled in by
- * the previous time state.
- */
- static int get_h_m_s(const struct shell *shell, struct tm *tm, char *time_str)
- {
- char *endptr;
- if (*time_str == ':') {
- time_str++;
- } else {
- endptr = NULL;
- tm->tm_hour = strtol(time_str, &endptr, 10);
- if (endptr == time_str) {
- return -EINVAL;
- } else if (*endptr == ':') {
- if ((tm->tm_hour < 0) || (tm->tm_hour > 23)) {
- shell_error(shell, "Invalid hour");
- return -EINVAL;
- }
- time_str = endptr + 1;
- } else {
- return -EINVAL;
- }
- }
- if (*time_str == ':') {
- time_str++;
- } else {
- endptr = NULL;
- tm->tm_min = strtol(time_str, &endptr, 10);
- if (endptr == time_str) {
- return -EINVAL;
- } else if (*endptr == ':') {
- if ((tm->tm_min < 0) || (tm->tm_min > 59)) {
- shell_error(shell, "Invalid minute");
- return -EINVAL;
- }
- time_str = endptr + 1;
- } else {
- return -EINVAL;
- }
- }
- endptr = NULL;
- tm->tm_sec = strtol(time_str, &endptr, 10);
- if ((endptr == time_str) || (*endptr != '\0')) {
- return -EINVAL;
- }
- /* Note range allows for a leap second */
- if ((tm->tm_sec < 0) || (tm->tm_sec > 60)) {
- shell_error(shell, "Invalid second");
- return -EINVAL;
- }
- return 0;
- }
- static int cmd_date_set(const struct shell *shell, size_t argc, char **argv)
- {
- struct timespec tp;
- struct tm tm;
- int ret;
- clock_gettime(CLOCK_REALTIME, &tp);
- gmtime_r(&tp.tv_sec, &tm);
- if (argc == 3) {
- ret = get_y_m_d(shell, &tm, argv[1]);
- if (ret != 0) {
- shell_help(shell);
- return -EINVAL;
- }
- ret = get_h_m_s(shell, &tm, argv[2]);
- if (ret != 0) {
- shell_help(shell);
- return -EINVAL;
- }
- } else if (argc == 2) {
- ret = get_h_m_s(shell, &tm, argv[1]);
- if (ret != 0) {
- shell_help(shell);
- return -EINVAL;
- }
- } else {
- shell_help(shell);
- return -EINVAL;
- }
- tp.tv_sec = timeutil_timegm(&tm);
- if (tp.tv_sec == -1) {
- shell_error(shell, "Failed to calculate seconds since Epoch");
- return -EINVAL;
- }
- tp.tv_nsec = 0;
- ret = clock_settime(CLOCK_REALTIME, &tp);
- if (ret != 0) {
- shell_error(shell, "Could not set date %d", ret);
- return -EINVAL;
- }
- date_print(shell, &tm);
- return 0;
- }
- static int cmd_date_get(const struct shell *shell, size_t argc, char **argv)
- {
- struct timespec tp;
- struct tm tm;
- clock_gettime(CLOCK_REALTIME, &tp);
- gmtime_r(&tp.tv_sec, &tm);
- date_print(shell, &tm);
- return 0;
- }
- SHELL_STATIC_SUBCMD_SET_CREATE(sub_date,
- SHELL_CMD(set, NULL, HELP_DATE_SET, cmd_date_set),
- SHELL_CMD(get, NULL, HELP_NONE, cmd_date_get),
- SHELL_SUBCMD_SET_END /* Array terminated. */
- );
- SHELL_CMD_REGISTER(date, &sub_date, "Date commands", NULL);
|