// SPDX-License-Identifier: GPL-2.0 /* * Real Time Clock tool * * Copyright (c) 2018 Alexandre Belloni */ #include #include #include #include #include #include #include #include #include #include #include static char *rtc_file = "/dev/rtc0"; #define IOCTL(f, r, d, rc) rc = ioctl(f, r, d); \ if (rc) { \ fprintf(stderr, "%s returned %s (%d) at line %d\n", #r, \ strerror(errno), errno, __LINE__); \ exit(errno); \ } #define ISODATEFMT "%04d-%02d-%02dT%02d:%02d:%02d" #define ISODATE(tm) tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \ tm.tm_hour, tm.tm_min, tm.tm_sec static void usage(char *name) { fprintf(stderr, "Usage: %s \n", name); fprintf(stderr, " %s rd [rtc]\n", name); fprintf(stderr, " %s set YYYY-MM-DDThh:mm:ss [rtc]\n", name); fprintf(stderr, " %s wkalmrd [rtc]\n", name); fprintf(stderr, " %s wkalmset YYYY-MM-DDThh:mm:ss [rtc]\n", name); fprintf(stderr, " %s almread [rtc]\n", name); fprintf(stderr, " %s almset YYYY-MM-DDThh:mm:ss [rtc]\n", name); fprintf(stderr, " %s aieon [rtc]\n", name); fprintf(stderr, " %s aieoff [rtc]\n", name); exit(EINVAL); } int main(int argc, char **argv) { struct rtc_time tm; struct rtc_wkalrm alm; int fd, rc, cmd = 0; if (argc < 2) usage(argv[0]); if (!strcmp(argv[1], "rd")) { if (argc > 2) rtc_file = argv[2]; cmd = RTC_RD_TIME; } else if (!strcmp(argv[1], "set")) { if (argc < 3) usage(argv[0]); if (argc > 3) rtc_file = argv[3]; cmd = RTC_SET_TIME; rc = sscanf(argv[2], "%d-%d-%dT%d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); tm.tm_year -= 1900; tm.tm_mon -= 1; } else if (!strcmp(argv[1], "wkalmrd")) { if (argc > 2) rtc_file = argv[2]; cmd = RTC_WKALM_RD; } else if (!strcmp(argv[1], "wkalmset")) { if (argc < 3) usage(argv[0]); if (argc > 3) rtc_file = argv[3]; cmd = RTC_WKALM_SET; rc = sscanf(argv[2], "%d-%d-%dT%d:%d:%d", &alm.time.tm_year, &alm.time.tm_mon, &alm.time.tm_mday, &alm.time.tm_hour, &alm.time.tm_min, &alm.time.tm_sec); alm.time.tm_year -= 1900; alm.time.tm_mon -= 1; alm.enabled = 1; } else if (!strcmp(argv[1], "aieon")) { if (argc > 2) rtc_file = argv[2]; cmd = RTC_AIE_ON; } else if (!strcmp(argv[1], "aieoff")) { if (argc > 2) rtc_file = argv[2]; cmd = RTC_AIE_OFF; } else if (!strcmp(argv[1], "almread")) { if (argc > 2) rtc_file = argv[2]; cmd = RTC_ALM_READ; } else if (!strcmp(argv[1], "almset")) { if (argc < 3) usage(argv[0]); if (argc > 3) rtc_file = argv[3]; cmd = RTC_ALM_SET; rc = sscanf(argv[2], "%d-%d-%dT%d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); alm.time.tm_year -= 1900; alm.time.tm_mon -= 1; alm.enabled = 1; } if (!cmd) usage(argv[0]); fd = open(rtc_file, O_RDONLY); if (fd == -1) { perror(rtc_file); exit(errno); } switch (cmd) { case RTC_RD_TIME: IOCTL(fd, RTC_RD_TIME, &tm, rc); printf("%s: " ISODATEFMT "\n", rtc_file, ISODATE(tm)); break; case RTC_SET_TIME: IOCTL(fd, RTC_SET_TIME, &tm, rc); break; case RTC_WKALM_RD: IOCTL(fd, RTC_WKALM_RD, &alm, rc); printf("%s: " ISODATEFMT "\n", rtc_file, ISODATE(alm.time)); break; case RTC_WKALM_SET: IOCTL(fd, RTC_WKALM_SET, &alm, rc); break; case RTC_ALM_READ: IOCTL(fd, RTC_ALM_READ, &tm, rc); printf("%s: " ISODATEFMT "\n", rtc_file, ISODATE(tm)); break; case RTC_ALM_SET: IOCTL(fd, RTC_ALM_SET, &tm, rc); break; case RTC_AIE_ON: IOCTL(fd, RTC_AIE_ON, 0, rc); break; case RTC_AIE_OFF: IOCTL(fd, RTC_AIE_OFF, 0, rc); break; } close(fd); return 0; }