Coverage Report

Created: 2026-10-13 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/commands/hwclock.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-only
2
3
#include <common.h>
4
#include <command.h>
5
#include <getopt.h>
6
#include <linux/err.h>
7
#include <linux/ctype.h>
8
#include <rtc.h>
9
#include <sntp.h>
10
#include <linux/rtc.h>
11
#include <string.h>
12
#include <environment.h>
13
14
static int sscanf_two_digits(char *s, int *res)
15
0
{
16
0
  char buf[3];
17
0
  unsigned long t;
18
19
0
  if (!isdigit(s[0]) || !isdigit(s[1])) {
20
0
    return -EINVAL;
21
0
  }
22
23
0
  buf[0] = s[0];
24
0
  buf[1] = s[1];
25
0
  buf[2] = '\0';
26
27
0
  t = simple_strtoul(buf, NULL, 10);
28
0
  *res = t;
29
30
0
  return 0;
31
0
}
32
33
static int parse_datestr(char *date_str, struct rtc_time *ptm)
34
0
{
35
0
  char end = '\0';
36
0
  int len = strchrnul(date_str, '.') - date_str;
37
0
  int year;
38
39
  /* ccyymmddHHMM[.SS] */
40
0
  if (len != 12) {
41
0
    return -EINVAL;
42
0
  }
43
44
0
  if (sscanf_two_digits(date_str, &year) ||
45
0
    sscanf_two_digits(&date_str[2], &ptm->tm_year)) {
46
0
    return -EINVAL;
47
0
  }
48
49
0
  ptm->tm_year = year * 100 + ptm->tm_year;
50
51
  /* Adjust years */
52
0
  ptm->tm_year -= 1900;
53
54
0
  if (sscanf_two_digits(&date_str[4], &ptm->tm_mon) ||
55
0
    sscanf_two_digits(&date_str[6], &ptm->tm_mday) ||
56
0
    sscanf_two_digits(&date_str[8], &ptm->tm_hour) ||
57
0
    sscanf_two_digits(&date_str[10], &ptm->tm_min)) {
58
0
    return -EINVAL;
59
0
  }
60
61
  /* Adjust month from 1-12 to 0-11 */
62
0
  ptm->tm_mon -= 1;
63
64
0
  end = date_str[12];
65
66
0
  if (end == '.') {
67
    /* xxx.SS */
68
0
    if (!sscanf_two_digits(&date_str[13], &ptm->tm_sec)) {
69
0
      end = '\0';
70
0
    }
71
    /* else end != NUL and we error out */
72
0
  }
73
74
0
  if (end != '\0') {
75
0
    return -EINVAL;
76
0
  }
77
78
0
  return 0;
79
0
}
80
81
static int do_hwclock(int argc, char *argv[])
82
0
{
83
0
  struct rtc_device *r;
84
0
  struct rtc_time tm;
85
0
  struct rtc_time stm;
86
0
  const char *rtc_name = "rtc0";
87
0
  char *env_name = NULL;
88
0
  int opt;
89
0
  int set = 0;
90
0
  int ret;
91
0
  int ntp_to_hw = 0;
92
0
  char *ntpserver = NULL;
93
94
0
  while ((opt = getopt(argc, argv, "f:s:e:n:")) > 0) {
95
96
0
    switch (opt) {
97
0
    case 'f':
98
0
      rtc_name = optarg;
99
0
      break;
100
0
    case 's':
101
0
      memset(&stm, 0, sizeof(stm));
102
103
0
      ret = parse_datestr(optarg, &stm);
104
0
      if (ret)
105
0
        return ret;
106
107
0
      ret = rtc_valid_tm(&stm);
108
0
      if (ret)
109
0
        return ret;
110
111
0
      set = 1;
112
0
      break;
113
0
    case 'e':
114
0
      env_name = optarg;
115
0
      break;
116
0
    case 'n':
117
0
      ntp_to_hw = 1;
118
0
      ntpserver = optarg;
119
0
      break;
120
0
    default:
121
0
      return COMMAND_ERROR_USAGE;
122
0
    }
123
0
  }
124
125
0
  r = rtc_lookup(rtc_name);
126
0
  if (IS_ERR(r))
127
0
    return PTR_ERR(r);
128
129
0
  if (set) {
130
0
    return rtc_set_time(r, &stm);
131
0
  }
132
133
0
  if (ntp_to_hw) {
134
0
    s64 now;
135
136
0
    if (!IS_ENABLED(CONFIG_NET_SNTP)) {
137
0
      printf("SNTP support is disabled\n");
138
0
      return 1;
139
0
    }
140
141
0
    now = sntp(ntpserver);
142
0
    if (now < 0)
143
0
      return now;
144
145
0
    rtc_time_to_tm(now, &stm);
146
0
    printf("%s\n", time_str(&stm));
147
0
    return rtc_set_time(r, &stm);
148
0
  }
149
150
0
  ret = rtc_read_time(r, &tm);
151
0
  if (ret < 0)
152
0
    return ret;
153
154
0
  if (env_name) {
155
0
    unsigned long time;
156
157
0
    rtc_tm_to_time(&tm, &time);
158
0
    pr_setenv(env_name, "%lu", time);
159
0
  } else {
160
0
    printf("%s\n", time_str(&tm));
161
0
  }
162
163
0
  return 0;
164
0
}
165
166
BAREBOX_CMD_HELP_START(hwclock)
167
BAREBOX_CMD_HELP_TEXT("Options:")
168
BAREBOX_CMD_HELP_OPT ("-f NAME\t\t\t", "RTC device name (default rtc0)")
169
BAREBOX_CMD_HELP_OPT ("-e VARNAME\t\t", "store RTC readout into variable VARNAME")
170
BAREBOX_CMD_HELP_OPT ("-n NTPSERVER\t\t", "set RTC from NTP server")
171
BAREBOX_CMD_HELP_OPT ("-s ccyymmddHHMM[.SS]\t", "set time")
172
BAREBOX_CMD_HELP_END
173
174
BAREBOX_CMD_START(hwclock)
175
  .cmd    = do_hwclock,
176
  BAREBOX_CMD_DESC("query or set the hardware clock (RTC)")
177
  BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
178
  BAREBOX_CMD_HELP(cmd_hwclock_help)
179
BAREBOX_CMD_END