1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <zircon/device/rtc.h> 6 7#include <ctype.h> 8#include <dirent.h> 9#include <fcntl.h> 10#include <getopt.h> 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14#include <sys/types.h> 15 16int usage(const char* cmd) { 17 fprintf( 18 stderr, 19 "Interact with the real-time clock:\n" 20 " %s Print the time\n" 21 " %s --help Print this message\n" 22 " %s --set YYYY-mm-ddThh:mm:ss Set the time\n" 23 " optionally specify an RTC device with --dev PATH_TO_DEVICE_NODE\n", 24 cmd, 25 cmd, 26 cmd); 27 return -1; 28} 29 30char *guess_dev(void) { 31 char path[19]; // strlen("/dev/class/rtc/###") + 1 32 DIR *d = opendir("/dev/class/rtc"); 33 if (!d) { 34 return NULL; 35 } 36 37 struct dirent *de; 38 while ((de = readdir(d)) != NULL) { 39 if (strlen(de->d_name) != 3) { 40 continue; 41 } 42 43 if (isdigit(de->d_name[0]) && 44 isdigit(de->d_name[1]) && 45 isdigit(de->d_name[2])) { 46 sprintf(path, "/dev/class/rtc/%.3s", de->d_name); 47 closedir(d); 48 return strdup(path); 49 } 50 } 51 52 closedir(d); 53 return NULL; 54} 55 56int open_rtc(const char *path, int mode) { 57 int rtc_fd = open(path, mode); 58 if (rtc_fd < 0) { 59 printf("Can not open RTC device\n"); 60 } 61 return rtc_fd; 62} 63 64int print_rtc(const char *path) { 65 int rtc_fd = open_rtc(path, O_RDONLY); 66 if (rtc_fd < 0) { 67 return -1; 68 } 69 rtc_t rtc; 70 ssize_t n = ioctl_rtc_get(rtc_fd, &rtc); 71 if (n < (ssize_t)sizeof(rtc_t)) { 72 return -1; 73 } 74 printf( 75 "%04d-%02d-%02dT%02d:%02d:%02d\n", 76 rtc.year, 77 rtc.month, 78 rtc.day, 79 rtc.hours, 80 rtc.minutes, 81 rtc.seconds); 82 return 0; 83} 84 85int set_rtc(const char *path, const char* time) { 86 rtc_t rtc; 87 int n = sscanf( 88 time, 89 "%04hd-%02hhd-%02hhdT%02hhd:%02hhd:%02hhd", 90 &rtc.year, 91 &rtc.month, 92 &rtc.day, 93 &rtc.hours, 94 &rtc.minutes, 95 &rtc.seconds); 96 if (n != 6) { 97 printf("Bad time format.\n"); 98 return -1; 99 } 100 int rtc_fd = open_rtc(path, O_WRONLY); 101 if (rtc_fd < 0) { 102 printf("Can not open RTC device\n"); 103 return -1; 104 } 105 ssize_t written = ioctl_rtc_set(rtc_fd, &rtc); 106 return (written == sizeof(rtc)) ? 0 : written; 107} 108 109int main(int argc, char** argv) { 110 int err; 111 const char* cmd = basename(argv[0]); 112 char *path = NULL; 113 char *set = NULL; 114 static const struct option opts[] = { 115 {"set", required_argument, NULL, 's'}, 116 {"dev", required_argument, NULL, 'd'}, 117 {"help", no_argument, NULL, 'h'}, 118 {0}, 119 }; 120 for (int opt; (opt = getopt_long(argc, argv, "", opts, NULL)) != -1;) { 121 switch (opt) { 122 case 's': 123 set = strdup(optarg); 124 break; 125 case 'd': 126 path = strdup(optarg); 127 break; 128 case 'h': 129 usage(cmd); 130 err = 0; 131 goto done; 132 default: 133 err = usage(cmd); 134 goto done; 135 } 136 } 137 138 argv += optind; 139 argc -= optind; 140 141 if (argc != 0) { 142 err = usage(cmd); 143 goto done; 144 } 145 146 if (!path) { 147 path = guess_dev(); 148 if (!path) { 149 fprintf(stderr, "No RTC found.\n"); 150 err = usage(cmd); 151 goto done; 152 } 153 } 154 155 if (set) { 156 err = set_rtc(path, set); 157 if (err) { 158 printf("Set RTC failed.\n"); 159 usage(cmd); 160 } 161 goto done; 162 } 163 164 err = print_rtc(path); 165 if (err) { 166 usage(cmd); 167 } 168 169done: 170 free(path); 171 free(set); 172 return err; 173} 174