blob: b2978a4a19720983baba3c8cf611d1aec65fa371 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <zircon/device/rtc.h>
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
int usage(const char* cmd) {
fprintf(
stderr,
"Interact with the real-time clock:\n"
" %s Print the time\n"
" %s --help Print this message\n"
" %s --set YYYY-mm-ddThh:mm:ss Set the time\n"
" optionally specify an RTC device with --dev PATH_TO_DEVICE_NODE\n",
cmd,
cmd,
cmd);
return -1;
}
char *guess_dev(void) {
char path[19]; // strlen("/dev/class/rtc/###") + 1
DIR *d = opendir("/dev/class/rtc");
if (!d) {
return NULL;
}
struct dirent *de;
while ((de = readdir(d)) != NULL) {
if (strlen(de->d_name) != 3) {
continue;
}
if (isdigit(de->d_name[0]) &&
isdigit(de->d_name[1]) &&
isdigit(de->d_name[2])) {
sprintf(path, "/dev/class/rtc/%.3s", de->d_name);
closedir(d);
return strdup(path);
}
}
closedir(d);
return NULL;
}
int open_rtc(const char *path, int mode) {
int rtc_fd = open(path, mode);
if (rtc_fd < 0) {
printf("Can not open RTC device\n");
}
return rtc_fd;
}
int print_rtc(const char *path) {
int rtc_fd = open_rtc(path, O_RDONLY);
if (rtc_fd < 0) {
return -1;
}
rtc_t rtc;
ssize_t n = ioctl_rtc_get(rtc_fd, &rtc);
if (n < (ssize_t)sizeof(rtc_t)) {
return -1;
}
printf(
"%04d-%02d-%02dT%02d:%02d:%02d\n",
rtc.year,
rtc.month,
rtc.day,
rtc.hours,
rtc.minutes,
rtc.seconds);
return 0;
}
int set_rtc(const char *path, const char* time) {
rtc_t rtc;
int n = sscanf(
time,
"%04hd-%02hhd-%02hhdT%02hhd:%02hhd:%02hhd",
&rtc.year,
&rtc.month,
&rtc.day,
&rtc.hours,
&rtc.minutes,
&rtc.seconds);
if (n != 6) {
printf("Bad time format.\n");
return -1;
}
int rtc_fd = open_rtc(path, O_WRONLY);
if (rtc_fd < 0) {
printf("Can not open RTC device\n");
return -1;
}
ssize_t written = ioctl_rtc_set(rtc_fd, &rtc);
return (written == sizeof(rtc)) ? 0 : written;
}
int main(int argc, char** argv) {
int err;
const char* cmd = basename(argv[0]);
char *path = NULL;
char *set = NULL;
static const struct option opts[] = {
{"set", required_argument, NULL, 's'},
{"dev", required_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
{0},
};
for (int opt; (opt = getopt_long(argc, argv, "", opts, NULL)) != -1;) {
switch (opt) {
case 's':
set = strdup(optarg);
break;
case 'd':
path = strdup(optarg);
break;
case 'h':
usage(cmd);
err = 0;
goto done;
default:
err = usage(cmd);
goto done;
}
}
argv += optind;
argc -= optind;
if (argc != 0) {
err = usage(cmd);
goto done;
}
if (!path) {
path = guess_dev();
if (!path) {
fprintf(stderr, "No RTC found.\n");
err = usage(cmd);
goto done;
}
}
if (set) {
err = set_rtc(path, set);
if (err) {
printf("Set RTC failed.\n");
usage(cmd);
}
goto done;
}
err = print_rtc(path);
if (err) {
usage(cmd);
}
done:
free(path);
free(set);
return err;
}