source: mainline/uspace/app/date/date.c@ 2e6293b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2e6293b was 2e6293b, checked in by Maurizio Lombardi <m.lombardi85@…>, 13 years ago

date: fix typo

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Copyright (c) 2012 Maurizio Lombardi
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29
30#include <stdio.h>
31#include <device/clock_dev.h>
32#include <errno.h>
33#include <loc.h>
34#include <time.h>
35#include <malloc.h>
36#include <ipc/clock_ctl.h>
37#include <getopt.h>
38#include <ctype.h>
39
40#define NAME "date"
41
42static int read_date_from_arg(char *wdate, struct tm *t);
43static int read_time_from_arg(char *wdate, struct tm *t);
44static int read_num_from_str(char *str, size_t len, int *n);
45static int tm_sanity_check(struct tm *t);
46static bool is_leap_year(int year);
47
48static void usage(void);
49
50static int days_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
51
52int
53main(int argc, char **argv)
54{
55 int rc, c;
56 category_id_t cat_id;
57 size_t svc_cnt;
58 service_id_t *svc_ids = NULL;
59 service_id_t svc_id;
60 char *svc_name = NULL;
61 bool read_only = true;
62 char *wdate = NULL;
63 char *wtime = NULL;
64 sysarg_t battery_ok;
65 struct tm t;
66 int n_args = argc;
67
68 while ((c = getopt(argc, argv, "hd:t:")) != -1) {
69 switch (c) {
70 case 'h':
71 usage();
72 return 0;
73 case 'd':
74 if (wdate) {
75 usage();
76 return 1;
77 }
78 wdate = (char *)optarg;
79 read_only = false;
80 n_args -= 2;
81 break;
82 case 't':
83 if (wtime) {
84 usage();
85 return 1;
86 }
87 wtime = (char *)optarg;
88 read_only = false;
89 n_args -= 2;
90 break;
91 case '?':
92 usage();
93 return 1;
94 }
95 }
96
97 if (n_args != 1) {
98 printf(NAME ": Unrecognized parameter\n");
99 usage();
100 return 1;
101 }
102
103 /* Get the id of the clock category */
104 rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
105 if (rc != EOK) {
106 printf(NAME ": Cannot get clock category id\n");
107 goto exit;
108 }
109
110 /* Get the list of available services in the clock category */
111 rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
112 if (rc != EOK) {
113 printf(NAME ": Cannot get the list of services in the clock \
114 category\n");
115 goto exit;
116 }
117
118 /* Check if there are available services in the clock category */
119 if (svc_cnt == 0) {
120 printf(NAME ": No available service found in \
121 the clock category\n");
122 goto exit;
123 }
124
125 /* Get the name of the clock service */
126 rc = loc_service_get_name(svc_ids[0], &svc_name);
127 if (rc != EOK) {
128 printf(NAME ": Cannot get the name of the service\n");
129 goto exit;
130 }
131
132 /* Get the service id for the device */
133 rc = loc_service_get_id(svc_name, &svc_id, 0);
134 if (rc != EOK) {
135 printf(NAME ": Cannot get the service id for device %s",
136 svc_name);
137 goto exit;
138 }
139
140 /* Connect to the device */
141 async_sess_t *sess = loc_service_connect(EXCHANGE_SERIALIZE,
142 svc_id, 0);
143 if (!sess) {
144 printf(NAME ": Cannot connect to the device\n");
145 goto exit;
146 }
147
148 /* Check the battery status (if present) */
149 async_exch_t *exch = async_exchange_begin(sess);
150 rc = async_req_0_1(exch, CLOCK_GET_BATTERY_STATUS, &battery_ok);
151 async_exchange_end(exch);
152
153 if (rc == EOK && !battery_ok)
154 printf(NAME ": Warning! RTC battery dead\n");
155
156 /* Read the current date/time */
157 rc = clock_dev_time_get(sess, &t);
158 if (rc != EOK) {
159 printf(NAME ": Cannot read the current time\n");
160 goto exit;
161 }
162
163 if (read_only) {
164 /* Print the current time and exit */
165 printf("%02d/%02d/%d ", t.tm_mday,
166 t.tm_mon + 1, 1900 + t.tm_year);
167 printf("%02d:%02d:%02d\n", t.tm_hour, t.tm_min, t.tm_sec);
168 } else {
169 if (wdate) {
170 rc = read_date_from_arg(wdate, &t);
171 if (rc != EOK) {
172 printf(NAME ": error, date format not "
173 "recognized\n");
174 usage();
175 goto exit;
176 }
177 }
178 if (wtime) {
179 rc = read_time_from_arg(wtime, &t);
180 if (rc != EOK) {
181 printf(NAME ": error, time format not "
182 "recognized\n");
183 usage();
184 goto exit;
185 }
186 }
187
188 rc = tm_sanity_check(&t);
189 if (rc != EOK) {
190 printf(NAME ": error, invalid date/time\n");
191 goto exit;
192 }
193
194 rc = clock_dev_time_set(sess, &t);
195 if (rc != EOK) {
196 printf(NAME ": error, Unable to set date/time\n");
197 goto exit;
198 }
199 }
200
201exit:
202 free(svc_name);
203 free(svc_ids);
204 return rc;
205}
206
207/** Read the day, month and year from a string
208 * with the following format: DD/MM/YYYY
209 */
210static int
211read_date_from_arg(char *wdate, struct tm *t)
212{
213 int rc;
214
215 if (str_size(wdate) != 10) /* str_size("DD/MM/YYYY") == 10 */
216 return EINVAL;
217
218 if (wdate[2] != '/' ||
219 wdate[5] != '/') {
220 return EINVAL;
221 }
222
223 rc = read_num_from_str(&wdate[0], 2, &t->tm_mday);
224 if (rc != EOK)
225 return rc;
226
227 rc = read_num_from_str(&wdate[3], 2, &t->tm_mon);
228 if (rc != EOK)
229 return rc;
230 t->tm_mon--;
231
232 rc = read_num_from_str(&wdate[6], 4, &t->tm_year);
233 t->tm_year -= 1900;
234 return rc;
235}
236
237/** Read the hours, minutes and seconds from a string
238 * with the following format: HH:MM:SS or HH:MM
239 */
240static int
241read_time_from_arg(char *wtime, struct tm *t)
242{
243 int rc;
244 size_t len = str_size(wtime);
245 bool sec_present = len == 8;
246
247 /* str_size("HH:MM") == 5 */
248 /* str_size("HH:MM:SS") == 8 */
249 if (len != 8 && len != 5)
250 return EINVAL;
251
252 if (sec_present && wtime[5] != ':')
253 return EINVAL;
254
255 if (wtime[2] != ':')
256 return EINVAL;
257
258 rc = read_num_from_str(&wtime[0], 2, &t->tm_hour);
259 if (rc != EOK)
260 return rc;
261
262 rc = read_num_from_str(&wtime[3], 2, &t->tm_min);
263 if (rc != EOK)
264 return rc;
265
266 if (sec_present)
267 rc = read_num_from_str(&wtime[6], 2, &t->tm_sec);
268 else
269 t->tm_sec = 0;
270
271 return rc;
272}
273
274static int
275read_num_from_str(char *str, size_t len, int *n)
276{
277 size_t i;
278
279 *n = 0;
280
281 for (i = 0; i < len; ++i, ++str) {
282 if (!isdigit(*str))
283 return EINVAL;
284 *n *= 10;
285 *n += *str - '0';
286 }
287
288 return EOK;
289}
290
291/** Check if the tm structure contains valid values
292 *
293 * @param t The tm structure to check
294 *
295 * @return EOK on success or EINVAL
296 */
297static int
298tm_sanity_check(struct tm *t)
299{
300 int ndays;
301
302 if (t->tm_sec < 0 || t->tm_sec > 59)
303 return EINVAL;
304 else if (t->tm_min < 0 || t->tm_min > 59)
305 return EINVAL;
306 else if (t->tm_hour < 0 || t->tm_hour > 23)
307 return EINVAL;
308 else if (t->tm_mday < 1 || t->tm_mday > 31)
309 return EINVAL;
310 else if (t->tm_mon < 0 || t->tm_mon > 11)
311 return EINVAL;
312 else if (t->tm_year < 0 || t->tm_year > 199)
313 return EINVAL;
314
315 if (t->tm_mon == 1/* FEB */ && is_leap_year(t->tm_year))
316 ndays = 29;
317 else
318 ndays = days_month[t->tm_mon];
319
320 if (t->tm_mday > ndays)
321 return EINVAL;
322
323 return EOK;
324}
325
326/** Check if a year is a leap year
327 *
328 * @param year The year to check
329 *
330 * @return true if it is a leap year, false otherwise
331 */
332static bool
333is_leap_year(int year)
334{
335 bool r = false;
336
337 if (year % 4 == 0) {
338 if (year % 100 == 0)
339 r = year % 400 == 0;
340 else
341 r = true;
342 }
343
344 return r;
345}
346
347static void
348usage(void)
349{
350 printf("Usage: date [-d DD/MM/YYYY] [-t HH:MM[:SS]]\n");
351 printf(" -d Change the current date\n");
352 printf(" -t Change the current time\n");
353 printf(" -h Display this information\n");
354}
355
Note: See TracBrowser for help on using the repository browser.