source: mainline/uspace/app/date/date.c@ 6c089a9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6c089a9 was 18b6a88, checked in by Jiri Svoboda <jiri@…>, 8 years ago

More ccheck fixes, sometimes with manual intervention.

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