14483eaadba149a5286a26a292f72631793b4826aAshwini Sharma/* hwclock.c - get and set the hwclock 24483eaadba149a5286a26a292f72631793b4826aAshwini Sharma * 34483eaadba149a5286a26a292f72631793b4826aAshwini Sharma * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com> 44483eaadba149a5286a26a292f72631793b4826aAshwini Sharma * 5c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley * No standard, but see Documentation/rtc.txt in the linux kernel source.. 64483eaadba149a5286a26a292f72631793b4826aAshwini Sharma * 72c9b0e3009cf76e9d7fca772945711675678d181Rob LandleyUSE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]", TOYFLAG_USR|TOYFLAG_BIN)) 84483eaadba149a5286a26a292f72631793b4826aAshwini Sharma 94483eaadba149a5286a26a292f72631793b4826aAshwini Sharmaconfig HWCLOCK 104483eaadba149a5286a26a292f72631793b4826aAshwini Sharma bool "hwclock" 114483eaadba149a5286a26a292f72631793b4826aAshwini Sharma default n 124483eaadba149a5286a26a292f72631793b4826aAshwini Sharma help 1372f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley usage: hwclock [-rswtluf] 1472f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley 15c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley -f FILE Use specified device file instead of /dev/rtc (--rtc) 1672f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley -l Hardware clock uses localtime (--localtime) 1772f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley -r Show hardware clock time (--show) 1872f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley -s Set system time from hardware clock (--hctosys) 1972f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley -t Set the system time based on the current timezone (--systz) 2072f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley -u Hardware clock uses UTC (--utc) 2172f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley -w Set hardware clock from system time (--systohc) 224483eaadba149a5286a26a292f72631793b4826aAshwini Sharma*/ 23c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley 244483eaadba149a5286a26a292f72631793b4826aAshwini Sharma#define FOR_hwclock 254483eaadba149a5286a26a292f72631793b4826aAshwini Sharma#include "toys.h" 264483eaadba149a5286a26a292f72631793b4826aAshwini Sharma#include <linux/rtc.h> 274483eaadba149a5286a26a292f72631793b4826aAshwini Sharma 284483eaadba149a5286a26a292f72631793b4826aAshwini SharmaGLOBALS( 294483eaadba149a5286a26a292f72631793b4826aAshwini Sharma char *fname; 304483eaadba149a5286a26a292f72631793b4826aAshwini Sharma 314483eaadba149a5286a26a292f72631793b4826aAshwini Sharma int utc; 324483eaadba149a5286a26a292f72631793b4826aAshwini Sharma) 334483eaadba149a5286a26a292f72631793b4826aAshwini Sharma 34c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landleystatic int rtc_find(struct dirtree* node) 35ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes{ 36ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes FILE *fp; 37ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes 38ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes if (!node->parent) return DIRTREE_RECURSE; 39ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes 40ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes snprintf(toybuf, sizeof(toybuf), "/sys/class/rtc/%s/hctosys", node->name); 41ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes fp = fopen(toybuf, "r"); 42ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes if (fp) { 43c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley int hctosys = 0, items = fscanf(fp, "%d", &hctosys); 44c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley 45ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes fclose(fp); 46ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes if (items == 1 && hctosys == 1) { 47ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes snprintf(toybuf, sizeof(toybuf), "/dev/%s", node->name); 48ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes TT.fname = toybuf; 49c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley 50ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes return DIRTREE_ABORT; 51ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes } 52ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes } 53ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes 54c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley return 0; 55ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes} 56ef0546d4f536f42a57af4c32bd37f7fd752d10c2Elliott Hughes 5772f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landleyvoid hwclock_main() 584483eaadba149a5286a26a292f72631793b4826aAshwini Sharma{ 59c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley struct timezone tzone; 60c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley struct timeval timeval; 612c9b0e3009cf76e9d7fca772945711675678d181Rob Landley struct tm tm; 622c9b0e3009cf76e9d7fca772945711675678d181Rob Landley time_t time; 632c9b0e3009cf76e9d7fca772945711675678d181Rob Landley int fd = -1; 64c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley 65c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley // check for Grenich Mean Time 66c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley if (toys.optflags & FLAG_u) TT.utc = 1; 67c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley else { 682c9b0e3009cf76e9d7fca772945711675678d181Rob Landley FILE *fp; 692c9b0e3009cf76e9d7fca772945711675678d181Rob Landley char *s = 0; 7072f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley 712c9b0e3009cf76e9d7fca772945711675678d181Rob Landley for (fp = fopen("/etc/adjtime", "r"); 722c9b0e3009cf76e9d7fca772945711675678d181Rob Landley fp && getline(&s, (void *)toybuf, fp)>0; 732c9b0e3009cf76e9d7fca772945711675678d181Rob Landley free(s), s = 0) TT.utc += !strncmp(s, "UTC", 3); 742c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (fp) fclose(fp); 752c9b0e3009cf76e9d7fca772945711675678d181Rob Landley } 762c9b0e3009cf76e9d7fca772945711675678d181Rob Landley 772c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (!(toys.optflags&FLAG_t)) { 782c9b0e3009cf76e9d7fca772945711675678d181Rob Landley int w = toys.optflags & FLAG_w, flag = O_WRONLY*w; 79c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley 802c9b0e3009cf76e9d7fca772945711675678d181Rob Landley // Open /dev/rtc (if your system has no /dev/rtc symlink, search for it). 812c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (!TT.fname && (fd = open("/dev/rtc", flag)) == -1) { 822c9b0e3009cf76e9d7fca772945711675678d181Rob Landley dirtree_read("/sys/class/rtc", rtc_find); 832c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (!TT.fname) TT.fname = "/dev/misc/rtc"; 842c9b0e3009cf76e9d7fca772945711675678d181Rob Landley } 852c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (fd == -1) fd = xopen(TT.fname, flag); 862c9b0e3009cf76e9d7fca772945711675678d181Rob Landley 872c9b0e3009cf76e9d7fca772945711675678d181Rob Landley // Get current time in seconds from rtc device. todo: get subsecond time 882c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (!w) { 892c9b0e3009cf76e9d7fca772945711675678d181Rob Landley char *s = s; 902c9b0e3009cf76e9d7fca772945711675678d181Rob Landley 912c9b0e3009cf76e9d7fca772945711675678d181Rob Landley xioctl(fd, RTC_RD_TIME, &tm); 922c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (TT.utc) s = xtzset("UTC0"); 932c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if ((time = mktime(&tm)) < 0) goto bad; 942c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (TT.utc) { 952c9b0e3009cf76e9d7fca772945711675678d181Rob Landley free(xtzset(s)); 962c9b0e3009cf76e9d7fca772945711675678d181Rob Landley free(s); 974483eaadba149a5286a26a292f72631793b4826aAshwini Sharma } 984483eaadba149a5286a26a292f72631793b4826aAshwini Sharma } 99c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley } 100c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley 101fb49bf09694439102959fbce896404ab819bdf99Rob Landley if (toys.optflags & (FLAG_w|FLAG_t)) 1022c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (gettimeofday(&timeval, 0) 1032c9b0e3009cf76e9d7fca772945711675678d181Rob Landley || (TT.utc ? gmtime_r : localtime_r)(&timeval.tv_sec, &tm)) goto bad; 104c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley 105fb49bf09694439102959fbce896404ab819bdf99Rob Landley if (toys.optflags & FLAG_w) { 106c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley /* The value of tm_isdst will positive if daylight saving time is in effect, 107c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley * zero if it is not and negative if the information is not available. 1082c9b0e3009cf76e9d7fca772945711675678d181Rob Landley * todo: so why isn't this negative...? */ 109c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley tm.tm_isdst = 0; 110c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley xioctl(fd, RTC_SET_TIME, &time); 111c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley } else if (toys.optflags & FLAG_s) { 112c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley tzone.tz_minuteswest = timezone / 60 - 60 * daylight; 1132c9b0e3009cf76e9d7fca772945711675678d181Rob Landley timeval.tv_sec = time; 114fb49bf09694439102959fbce896404ab819bdf99Rob Landley timeval.tv_usec = 0; // todo: fixit 115c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley } else if (toys.optflags & FLAG_t) { 1162c9b0e3009cf76e9d7fca772945711675678d181Rob Landley // Adjust seconds for timezone and daylight saving time 117c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley // extern long timezone is defined in header sys/time.h 118c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley tzone.tz_minuteswest = timezone / 60; 1192c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (tm.tm_isdst) tzone.tz_minuteswest -= 60; 120c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley if (!TT.utc) timeval.tv_sec += tzone.tz_minuteswest * 60; 121c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley } else { 1222c9b0e3009cf76e9d7fca772945711675678d181Rob Landley char *c = ctime(&time), *s = strrchr(c, '\n'); 123c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley 124c277f347bba2417106b32212d9d40aceb4a88fb5Rob Landley if (s) *s = '\0'; 12572f8a5f7fedeb81c99044d3443872ae91b5ecfecRob Landley // TODO: implement this. 1262c9b0e3009cf76e9d7fca772945711675678d181Rob Landley xprintf("%s 0.000000 seconds\n", c); 1274483eaadba149a5286a26a292f72631793b4826aAshwini Sharma } 128fb49bf09694439102959fbce896404ab819bdf99Rob Landley if (toys.optflags & (FLAG_t|FLAG_s)) { 129fb49bf09694439102959fbce896404ab819bdf99Rob Landley tzone.tz_dsttime = 0; 130fb49bf09694439102959fbce896404ab819bdf99Rob Landley if (settimeofday(&timeval, &tzone)) goto bad; 131fb49bf09694439102959fbce896404ab819bdf99Rob Landley } 1322c9b0e3009cf76e9d7fca772945711675678d181Rob Landley 1332c9b0e3009cf76e9d7fca772945711675678d181Rob Landley if (fd != -1) close(fd); 1342c9b0e3009cf76e9d7fca772945711675678d181Rob Landley 1352c9b0e3009cf76e9d7fca772945711675678d181Rob Landley return; 1362c9b0e3009cf76e9d7fca772945711675678d181Rob Landleybad: 1372c9b0e3009cf76e9d7fca772945711675678d181Rob Landley perror_exit("failed"); 1384483eaadba149a5286a26a292f72631793b4826aAshwini Sharma} 139