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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b19131c5 was f9b2cb4c, checked in by Martin Decky <martin@…>, 10 years ago

unify interface API

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