source: mainline/uspace/app/date/date.c

Last change on this file was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 7.6 KB
RevLine 
[cca5c8d]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#include <stdio.h>
[cf00f2e4]30#include <device/clock_dev.h>
31#include <errno.h>
32#include <loc.h>
[9f1328cd]33#include <time.h>
[38d150e]34#include <stdlib.h>
[f4ebaf3c]35#include <getopt.h>
36#include <ctype.h>
[1d6dd2a]37#include <str.h>
[cf00f2e4]38
39#define NAME "date"
[cca5c8d]40
[b7fd2a0]41static errno_t read_date_from_arg(char *wdate, struct tm *t);
42static errno_t read_time_from_arg(char *wdate, struct tm *t);
43static errno_t tm_sanity_check(struct tm *t);
[fa18523]44static bool is_leap_year(int year);
45
[f4ebaf3c]46static void usage(void);
47
[18b6a88]48static int days_month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
[fa18523]49
[cca5c8d]50int
51main(int argc, char **argv)
52{
[b7fd2a0]53 errno_t rc;
[d5c1051]54 int c;
[cf00f2e4]55 category_id_t cat_id;
[f4ebaf3c]56 size_t svc_cnt;
[cf00f2e4]57 service_id_t *svc_ids = NULL;
[f4ebaf3c]58 service_id_t svc_id;
59 char *svc_name = NULL;
60 bool read_only = true;
61 char *wdate = NULL;
62 char *wtime = NULL;
63 struct tm t;
[0885f7e]64 int n_args = argc;
[751cabc]65
[e341110]66 while ((c = getopt(argc, argv, "hd:t:")) != -1) {
[f4ebaf3c]67 switch (c) {
[e341110]68 case 'h':
69 usage();
70 return 0;
[f4ebaf3c]71 case 'd':
[0885f7e]72 if (wdate) {
73 usage();
74 return 1;
75 }
[f4ebaf3c]76 wdate = (char *)optarg;
77 read_only = false;
[0885f7e]78 n_args -= 2;
[f4ebaf3c]79 break;
80 case 't':
[0885f7e]81 if (wtime) {
82 usage();
83 return 1;
84 }
[f4ebaf3c]85 wtime = (char *)optarg;
86 read_only = false;
[0885f7e]87 n_args -= 2;
[f4ebaf3c]88 break;
89 case '?':
90 usage();
91 return 1;
92 }
93 }
[cf00f2e4]94
[0885f7e]95 if (n_args != 1) {
96 printf(NAME ": Unrecognized parameter\n");
97 usage();
98 return 1;
99 }
100
[cf00f2e4]101 /* Get the id of the clock category */
102 rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING);
103 if (rc != EOK) {
104 printf(NAME ": Cannot get clock category id\n");
105 goto exit;
106 }
107
108 /* Get the list of available services in the clock category */
109 rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt);
110 if (rc != EOK) {
[ae827d0]111 printf(NAME ": Cannot get the list of services in the clock "
112 "category\n");
[cf00f2e4]113 goto exit;
114 }
115
[1789023]116 /* Check if there are available services in the clock category */
[cf00f2e4]117 if (svc_cnt == 0) {
[ae827d0]118 printf(NAME ": No available service found in "
119 "the clock category\n");
[cf00f2e4]120 goto exit;
121 }
122
123 /* Get the name of the clock service */
124 rc = loc_service_get_name(svc_ids[0], &svc_name);
125 if (rc != EOK) {
126 printf(NAME ": Cannot get the name of the service\n");
127 goto exit;
128 }
129
[8354ca6]130 /* Get the service id for the device */
131 rc = loc_service_get_id(svc_name, &svc_id, 0);
[9f1328cd]132 if (rc != EOK) {
[8354ca6]133 printf(NAME ": Cannot get the service id for device %s",
134 svc_name);
[9f1328cd]135 goto exit;
136 }
137
[8354ca6]138 /* Connect to the device */
[f9b2cb4c]139 async_sess_t *sess = loc_service_connect(svc_id, INTERFACE_DDF, 0);
[9f1328cd]140 if (!sess) {
141 printf(NAME ": Cannot connect to the device\n");
142 goto exit;
143 }
144
[8354ca6]145 /* Read the current date/time */
[9f1328cd]146 rc = clock_dev_time_get(sess, &t);
147 if (rc != EOK) {
148 printf(NAME ": Cannot read the current time\n");
149 goto exit;
150 }
151
[f4ebaf3c]152 if (read_only) {
153 /* Print the current time and exit */
154 printf("%02d/%02d/%d ", t.tm_mday,
155 t.tm_mon + 1, 1900 + t.tm_year);
156 printf("%02d:%02d:%02d\n", t.tm_hour, t.tm_min, t.tm_sec);
157 } else {
158 if (wdate) {
159 rc = read_date_from_arg(wdate, &t);
160 if (rc != EOK) {
161 printf(NAME ": error, date format not "
162 "recognized\n");
163 usage();
164 goto exit;
165 }
166 }
167 if (wtime) {
168 rc = read_time_from_arg(wtime, &t);
169 if (rc != EOK) {
170 printf(NAME ": error, time format not "
171 "recognized\n");
172 usage();
173 goto exit;
174 }
175 }
176
[fa18523]177 rc = tm_sanity_check(&t);
178 if (rc != EOK) {
179 printf(NAME ": error, invalid date/time\n");
180 goto exit;
181 }
182
[f4ebaf3c]183 rc = clock_dev_time_set(sess, &t);
184 if (rc != EOK) {
185 printf(NAME ": error, Unable to set date/time\n");
186 goto exit;
187 }
188 }
[d73a56d]189
[cf00f2e4]190exit:
191 free(svc_name);
192 free(svc_ids);
193 return rc;
[cca5c8d]194}
195
[ad2718d]196/** Read the day, month and year from a string
197 * with the following format: DD/MM/YYYY
198 */
[b7fd2a0]199static errno_t
[f4ebaf3c]200read_date_from_arg(char *wdate, struct tm *t)
201{
[b7fd2a0]202 errno_t rc;
[df7f9fb5]203 uint32_t tmp;
[f4ebaf3c]204
[ad2718d]205 if (str_size(wdate) != 10) /* str_size("DD/MM/YYYY") == 10 */
[f4ebaf3c]206 return EINVAL;
207
208 if (wdate[2] != '/' ||
209 wdate[5] != '/') {
210 return EINVAL;
211 }
212
[df7f9fb5]213 rc = str_uint32_t(&wdate[0], NULL, 10, false, &tmp);
[f4ebaf3c]214 if (rc != EOK)
215 return rc;
216
[df7f9fb5]217 t->tm_mday = tmp;
218
219 rc = str_uint32_t(&wdate[3], NULL, 10, false, &tmp);
[f4ebaf3c]220 if (rc != EOK)
221 return rc;
222
[df7f9fb5]223 t->tm_mon = tmp - 1;
224
225 rc = str_uint32_t(&wdate[6], NULL, 10, false, &tmp);
226 t->tm_year = tmp - 1900;
227
[f4ebaf3c]228 return rc;
229}
230
[ad2718d]231/** Read the hours, minutes and seconds from a string
232 * with the following format: HH:MM:SS or HH:MM
233 */
[b7fd2a0]234static errno_t
[f4ebaf3c]235read_time_from_arg(char *wtime, struct tm *t)
236{
[b7fd2a0]237 errno_t rc;
[f4ebaf3c]238 size_t len = str_size(wtime);
[ad2718d]239 bool sec_present = len == 8;
[df7f9fb5]240 uint32_t tmp;
[f4ebaf3c]241
[ad2718d]242 /* str_size("HH:MM") == 5 */
243 /* str_size("HH:MM:SS") == 8 */
244 if (len != 8 && len != 5)
[f4ebaf3c]245 return EINVAL;
246
247 if (sec_present && wtime[5] != ':')
248 return EINVAL;
249
250 if (wtime[2] != ':')
251 return EINVAL;
252
[df7f9fb5]253 rc = str_uint32_t(&wtime[0], NULL, 10, false, &tmp);
[f4ebaf3c]254 if (rc != EOK)
255 return rc;
256
[df7f9fb5]257 t->tm_hour = tmp;
258
259 rc = str_uint32_t(&wtime[3], NULL, 10, false, &tmp);
[f4ebaf3c]260 if (rc != EOK)
261 return rc;
262
[df7f9fb5]263 t->tm_min = tmp;
264
265 if (sec_present) {
266 rc = str_uint32_t(&wtime[6], NULL, 10, false, &tmp);
267 t->tm_sec = tmp;
268 } else
[f4ebaf3c]269 t->tm_sec = 0;
270
271 return rc;
272}
273
[fa18523]274/** Check if the tm structure contains valid values
275 *
276 * @param t The tm structure to check
277 *
278 * @return EOK on success or EINVAL
279 */
[b7fd2a0]280static errno_t
[fa18523]281tm_sanity_check(struct tm *t)
282{
283 int ndays;
284
285 if (t->tm_sec < 0 || t->tm_sec > 59)
286 return EINVAL;
287 else if (t->tm_min < 0 || t->tm_min > 59)
288 return EINVAL;
289 else if (t->tm_hour < 0 || t->tm_hour > 23)
290 return EINVAL;
291 else if (t->tm_mday < 1 || t->tm_mday > 31)
292 return EINVAL;
293 else if (t->tm_mon < 0 || t->tm_mon > 11)
294 return EINVAL;
295 else if (t->tm_year < 0 || t->tm_year > 199)
296 return EINVAL;
297
298 if (t->tm_mon == 1/* FEB */ && is_leap_year(t->tm_year))
299 ndays = 29;
300 else
301 ndays = days_month[t->tm_mon];
302
303 if (t->tm_mday > ndays)
304 return EINVAL;
305
306 return EOK;
307}
308
309/** Check if a year is a leap year
310 *
311 * @param year The year to check
312 *
313 * @return true if it is a leap year, false otherwise
314 */
315static bool
316is_leap_year(int year)
317{
318 bool r = false;
319
320 if (year % 4 == 0) {
321 if (year % 100 == 0)
322 r = year % 400 == 0;
323 else
324 r = true;
325 }
326
327 return r;
328}
329
[f4ebaf3c]330static void
331usage(void)
332{
333 printf("Usage: date [-d DD/MM/YYYY] [-t HH:MM[:SS]]\n");
334 printf(" -d Change the current date\n");
335 printf(" -t Change the current time\n");
[a8b8086]336 printf(" -h Display this information\n");
[f4ebaf3c]337}
Note: See TracBrowser for help on using the repository browser.