10f66f451Sopenharmony_ci/* hwclock.c - get and set the hwclock 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * No standard, but see Documentation/rtc.txt in the linux kernel source.. 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ciUSE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]", TOYFLAG_SBIN)) 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciconfig HWCLOCK 100f66f451Sopenharmony_ci bool "hwclock" 110f66f451Sopenharmony_ci default y 120f66f451Sopenharmony_ci help 130f66f451Sopenharmony_ci usage: hwclock [-rswtluf] 140f66f451Sopenharmony_ci 150f66f451Sopenharmony_ci Get/set the hardware clock. 160f66f451Sopenharmony_ci 170f66f451Sopenharmony_ci -f FILE Use specified device file instead of /dev/rtc (--rtc) 180f66f451Sopenharmony_ci -l Hardware clock uses localtime (--localtime) 190f66f451Sopenharmony_ci -r Show hardware clock time (--show) 200f66f451Sopenharmony_ci -s Set system time from hardware clock (--hctosys) 210f66f451Sopenharmony_ci -t Set the system time based on the current timezone (--systz) 220f66f451Sopenharmony_ci -u Hardware clock uses UTC (--utc) 230f66f451Sopenharmony_ci -w Set hardware clock from system time (--systohc) 240f66f451Sopenharmony_ci*/ 250f66f451Sopenharmony_ci 260f66f451Sopenharmony_ci#define FOR_hwclock 270f66f451Sopenharmony_ci#include "toys.h" 280f66f451Sopenharmony_ci#include <linux/rtc.h> 290f66f451Sopenharmony_ci 300f66f451Sopenharmony_ciGLOBALS( 310f66f451Sopenharmony_ci char *f; 320f66f451Sopenharmony_ci 330f66f451Sopenharmony_ci int utc; 340f66f451Sopenharmony_ci) 350f66f451Sopenharmony_ci 360f66f451Sopenharmony_cistatic int rtc_find(struct dirtree* node) 370f66f451Sopenharmony_ci{ 380f66f451Sopenharmony_ci FILE *fp; 390f66f451Sopenharmony_ci 400f66f451Sopenharmony_ci if (!node->parent) return DIRTREE_RECURSE; 410f66f451Sopenharmony_ci 420f66f451Sopenharmony_ci sprintf(toybuf, "/sys/class/rtc/%s/hctosys", node->name); 430f66f451Sopenharmony_ci fp = fopen(toybuf, "r"); 440f66f451Sopenharmony_ci if (fp) { 450f66f451Sopenharmony_ci int hctosys = 0, items = fscanf(fp, "%d", &hctosys); 460f66f451Sopenharmony_ci 470f66f451Sopenharmony_ci fclose(fp); 480f66f451Sopenharmony_ci if (items == 1 && hctosys == 1) { 490f66f451Sopenharmony_ci sprintf(toybuf, "/dev/%s", node->name); 500f66f451Sopenharmony_ci TT.f = toybuf; 510f66f451Sopenharmony_ci 520f66f451Sopenharmony_ci return DIRTREE_ABORT; 530f66f451Sopenharmony_ci } 540f66f451Sopenharmony_ci } 550f66f451Sopenharmony_ci 560f66f451Sopenharmony_ci return 0; 570f66f451Sopenharmony_ci} 580f66f451Sopenharmony_ci 590f66f451Sopenharmony_civoid hwclock_main() 600f66f451Sopenharmony_ci{ 610f66f451Sopenharmony_ci struct timezone tzone; 620f66f451Sopenharmony_ci struct timeval timeval; 630f66f451Sopenharmony_ci struct tm tm; 640f66f451Sopenharmony_ci time_t time; 650f66f451Sopenharmony_ci int fd = -1; 660f66f451Sopenharmony_ci 670f66f451Sopenharmony_ci // check for Grenich Mean Time 680f66f451Sopenharmony_ci if (toys.optflags & FLAG_u) TT.utc = 1; 690f66f451Sopenharmony_ci else { 700f66f451Sopenharmony_ci FILE *fp; 710f66f451Sopenharmony_ci char *s = 0; 720f66f451Sopenharmony_ci 730f66f451Sopenharmony_ci for (fp = fopen("/etc/adjtime", "r"); 740f66f451Sopenharmony_ci fp && getline(&s, (void *)toybuf, fp)>0; 750f66f451Sopenharmony_ci free(s), s = 0) TT.utc += !strncmp(s, "UTC", 3); 760f66f451Sopenharmony_ci if (fp) fclose(fp); 770f66f451Sopenharmony_ci } 780f66f451Sopenharmony_ci 790f66f451Sopenharmony_ci if (!(toys.optflags&FLAG_t)) { 800f66f451Sopenharmony_ci int w = toys.optflags & FLAG_w, flag = O_WRONLY*w; 810f66f451Sopenharmony_ci 820f66f451Sopenharmony_ci // Open /dev/rtc (if your system has no /dev/rtc symlink, search for it). 830f66f451Sopenharmony_ci if (!TT.f && (fd = open("/dev/rtc", flag)) == -1) { 840f66f451Sopenharmony_ci dirtree_read("/sys/class/rtc", rtc_find); 850f66f451Sopenharmony_ci if (!TT.f) TT.f = "/dev/misc/rtc"; 860f66f451Sopenharmony_ci } 870f66f451Sopenharmony_ci if (fd == -1) fd = xopen(TT.f, flag); 880f66f451Sopenharmony_ci 890f66f451Sopenharmony_ci // Get current time in seconds from rtc device. todo: get subsecond time 900f66f451Sopenharmony_ci if (!w) { 910f66f451Sopenharmony_ci char *s = s; 920f66f451Sopenharmony_ci 930f66f451Sopenharmony_ci xioctl(fd, RTC_RD_TIME, &tm); 940f66f451Sopenharmony_ci if (TT.utc) s = xtzset("UTC0"); 950f66f451Sopenharmony_ci if ((time = mktime(&tm)) < 0) error_exit("mktime failed"); 960f66f451Sopenharmony_ci if (TT.utc) { 970f66f451Sopenharmony_ci free(xtzset(s)); 980f66f451Sopenharmony_ci free(s); 990f66f451Sopenharmony_ci } 1000f66f451Sopenharmony_ci } 1010f66f451Sopenharmony_ci } 1020f66f451Sopenharmony_ci 1030f66f451Sopenharmony_ci if (toys.optflags & (FLAG_w|FLAG_t)) { 1040f66f451Sopenharmony_ci if (gettimeofday(&timeval, 0)) perror_exit("gettimeofday failed"); 1050f66f451Sopenharmony_ci if (!(TT.utc ? gmtime_r : localtime_r)(&timeval.tv_sec, &tm)) 1060f66f451Sopenharmony_ci error_exit(TT.utc ? "gmtime_r failed" : "localtime_r failed"); 1070f66f451Sopenharmony_ci } 1080f66f451Sopenharmony_ci 1090f66f451Sopenharmony_ci if (toys.optflags & FLAG_w) { 1100f66f451Sopenharmony_ci /* The value of tm_isdst is positive if daylight saving time is in effect, 1110f66f451Sopenharmony_ci * zero if it is not and negative if the information is not available. 1120f66f451Sopenharmony_ci * todo: so why isn't this negative...? */ 1130f66f451Sopenharmony_ci tm.tm_isdst = 0; 1140f66f451Sopenharmony_ci xioctl(fd, RTC_SET_TIME, &tm); 1150f66f451Sopenharmony_ci } else if (toys.optflags & FLAG_s) { 1160f66f451Sopenharmony_ci tzone.tz_minuteswest = timezone / 60 - 60 * daylight; 1170f66f451Sopenharmony_ci timeval.tv_sec = time; 1180f66f451Sopenharmony_ci timeval.tv_usec = 0; // todo: fixit 1190f66f451Sopenharmony_ci } else if (toys.optflags & FLAG_t) { 1200f66f451Sopenharmony_ci // Adjust seconds for timezone and daylight saving time 1210f66f451Sopenharmony_ci // extern long timezone is defined in header sys/time.h 1220f66f451Sopenharmony_ci tzone.tz_minuteswest = timezone / 60; 1230f66f451Sopenharmony_ci if (tm.tm_isdst) tzone.tz_minuteswest -= 60; 1240f66f451Sopenharmony_ci if (!TT.utc) timeval.tv_sec += tzone.tz_minuteswest * 60; 1250f66f451Sopenharmony_ci } else { 1260f66f451Sopenharmony_ci char *c = ctime(&time), *s = strrchr(c, '\n'); 1270f66f451Sopenharmony_ci 1280f66f451Sopenharmony_ci if (s) *s = '\0'; 1290f66f451Sopenharmony_ci // TODO: implement this. 1300f66f451Sopenharmony_ci xprintf("%s 0.000000 seconds\n", c); 1310f66f451Sopenharmony_ci } 1320f66f451Sopenharmony_ci if (toys.optflags & (FLAG_t|FLAG_s)) { 1330f66f451Sopenharmony_ci tzone.tz_dsttime = 0; 1340f66f451Sopenharmony_ci if (settimeofday(&timeval, &tzone)) perror_exit("settimeofday failed"); 1350f66f451Sopenharmony_ci } 1360f66f451Sopenharmony_ci 1370f66f451Sopenharmony_ci if (fd != -1) close(fd); 1380f66f451Sopenharmony_ci} 139