/* * Copyright (c) 2012 Maurizio Lombardi * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #define NAME "date" static errno_t read_date_from_arg(char *wdate, struct tm *t); static errno_t read_time_from_arg(char *wdate, struct tm *t); static errno_t tm_sanity_check(struct tm *t); static bool is_leap_year(int year); static void usage(void); static int days_month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int main(int argc, char **argv) { errno_t rc; int c; category_id_t cat_id; size_t svc_cnt; service_id_t *svc_ids = NULL; service_id_t svc_id; char *svc_name = NULL; bool read_only = true; char *wdate = NULL; char *wtime = NULL; struct tm t; int n_args = argc; while ((c = getopt(argc, argv, "hd:t:")) != -1) { switch (c) { case 'h': usage(); return 0; case 'd': if (wdate) { usage(); return 1; } wdate = (char *)optarg; read_only = false; n_args -= 2; break; case 't': if (wtime) { usage(); return 1; } wtime = (char *)optarg; read_only = false; n_args -= 2; break; case '?': usage(); return 1; } } if (n_args != 1) { printf(NAME ": Unrecognized parameter\n"); usage(); return 1; } /* Get the id of the clock category */ rc = loc_category_get_id("clock", &cat_id, IPC_FLAG_BLOCKING); if (rc != EOK) { printf(NAME ": Cannot get clock category id\n"); goto exit; } /* Get the list of available services in the clock category */ rc = loc_category_get_svcs(cat_id, &svc_ids, &svc_cnt); if (rc != EOK) { printf(NAME ": Cannot get the list of services in the clock " "category\n"); goto exit; } /* Check if there are available services in the clock category */ if (svc_cnt == 0) { printf(NAME ": No available service found in " "the clock category\n"); goto exit; } /* Get the name of the clock service */ rc = loc_service_get_name(svc_ids[0], &svc_name); if (rc != EOK) { printf(NAME ": Cannot get the name of the service\n"); goto exit; } /* Get the service id for the device */ rc = loc_service_get_id(svc_name, &svc_id, 0); if (rc != EOK) { printf(NAME ": Cannot get the service id for device %s", svc_name); goto exit; } /* Connect to the device */ async_sess_t *sess = loc_service_connect(svc_id, INTERFACE_DDF, 0); if (!sess) { printf(NAME ": Cannot connect to the device\n"); goto exit; } /* Read the current date/time */ rc = clock_dev_time_get(sess, &t); if (rc != EOK) { printf(NAME ": Cannot read the current time\n"); goto exit; } if (read_only) { /* Print the current time and exit */ printf("%02d/%02d/%d ", t.tm_mday, t.tm_mon + 1, 1900 + t.tm_year); printf("%02d:%02d:%02d\n", t.tm_hour, t.tm_min, t.tm_sec); } else { if (wdate) { rc = read_date_from_arg(wdate, &t); if (rc != EOK) { printf(NAME ": error, date format not " "recognized\n"); usage(); goto exit; } } if (wtime) { rc = read_time_from_arg(wtime, &t); if (rc != EOK) { printf(NAME ": error, time format not " "recognized\n"); usage(); goto exit; } } rc = tm_sanity_check(&t); if (rc != EOK) { printf(NAME ": error, invalid date/time\n"); goto exit; } rc = clock_dev_time_set(sess, &t); if (rc != EOK) { printf(NAME ": error, Unable to set date/time\n"); goto exit; } } exit: free(svc_name); free(svc_ids); return rc; } /** Read the day, month and year from a string * with the following format: DD/MM/YYYY */ static errno_t read_date_from_arg(char *wdate, struct tm *t) { errno_t rc; uint32_t tmp; if (str_size(wdate) != 10) /* str_size("DD/MM/YYYY") == 10 */ return EINVAL; if (wdate[2] != '/' || wdate[5] != '/') { return EINVAL; } rc = str_uint32_t(&wdate[0], NULL, 10, false, &tmp); if (rc != EOK) return rc; t->tm_mday = tmp; rc = str_uint32_t(&wdate[3], NULL, 10, false, &tmp); if (rc != EOK) return rc; t->tm_mon = tmp - 1; rc = str_uint32_t(&wdate[6], NULL, 10, false, &tmp); t->tm_year = tmp - 1900; return rc; } /** Read the hours, minutes and seconds from a string * with the following format: HH:MM:SS or HH:MM */ static errno_t read_time_from_arg(char *wtime, struct tm *t) { errno_t rc; size_t len = str_size(wtime); bool sec_present = len == 8; uint32_t tmp; /* str_size("HH:MM") == 5 */ /* str_size("HH:MM:SS") == 8 */ if (len != 8 && len != 5) return EINVAL; if (sec_present && wtime[5] != ':') return EINVAL; if (wtime[2] != ':') return EINVAL; rc = str_uint32_t(&wtime[0], NULL, 10, false, &tmp); if (rc != EOK) return rc; t->tm_hour = tmp; rc = str_uint32_t(&wtime[3], NULL, 10, false, &tmp); if (rc != EOK) return rc; t->tm_min = tmp; if (sec_present) { rc = str_uint32_t(&wtime[6], NULL, 10, false, &tmp); t->tm_sec = tmp; } else t->tm_sec = 0; return rc; } /** Check if the tm structure contains valid values * * @param t The tm structure to check * * @return EOK on success or EINVAL */ static errno_t tm_sanity_check(struct tm *t) { int ndays; if (t->tm_sec < 0 || t->tm_sec > 59) return EINVAL; else if (t->tm_min < 0 || t->tm_min > 59) return EINVAL; else if (t->tm_hour < 0 || t->tm_hour > 23) return EINVAL; else if (t->tm_mday < 1 || t->tm_mday > 31) return EINVAL; else if (t->tm_mon < 0 || t->tm_mon > 11) return EINVAL; else if (t->tm_year < 0 || t->tm_year > 199) return EINVAL; if (t->tm_mon == 1/* FEB */ && is_leap_year(t->tm_year)) ndays = 29; else ndays = days_month[t->tm_mon]; if (t->tm_mday > ndays) return EINVAL; return EOK; } /** Check if a year is a leap year * * @param year The year to check * * @return true if it is a leap year, false otherwise */ static bool is_leap_year(int year) { bool r = false; if (year % 4 == 0) { if (year % 100 == 0) r = year % 400 == 0; else r = true; } return r; } static void usage(void) { printf("Usage: date [-d DD/MM/YYYY] [-t HH:MM[:SS]]\n"); printf(" -d Change the current date\n"); printf(" -t Change the current time\n"); printf(" -h Display this information\n"); }