3 |
* |
* |
4 |
* This version was taken from util-linux and scrubbed down for busybox. |
* This version was taken from util-linux and scrubbed down for busybox. |
5 |
* |
* |
6 |
|
* Licensed under GPLv2, see file LICENSE in this tarball for details. |
7 |
|
* |
8 |
* This uses cross-platform Linux interfaces to enter a system sleep state, |
* This uses cross-platform Linux interfaces to enter a system sleep state, |
9 |
* and leave it no later than a specified time. It uses any RTC framework |
* and leave it no later than a specified time. It uses any RTC framework |
10 |
* driver that supports standard driver model wakeup flags. |
* driver that supports standard driver model wakeup flags. |
30 |
#define SYS_POWER_PATH "/sys/power/state" |
#define SYS_POWER_PATH "/sys/power/state" |
31 |
#define DEFAULT_MODE "standby" |
#define DEFAULT_MODE "standby" |
32 |
|
|
33 |
static time_t rtc_time; |
static NOINLINE bool may_wakeup(const char *rtcname) |
|
|
|
|
static bool may_wakeup(const char *rtcname) |
|
34 |
{ |
{ |
35 |
ssize_t ret; |
ssize_t ret; |
36 |
char buf[128]; |
char buf[128]; |
48 |
return strncmp(buf, "enabled\n", 8) == 0; |
return strncmp(buf, "enabled\n", 8) == 0; |
49 |
} |
} |
50 |
|
|
51 |
static void setup_alarm(int fd, time_t *wakeup) |
static NOINLINE void setup_alarm(int fd, time_t *wakeup, time_t rtc_time) |
52 |
{ |
{ |
53 |
struct tm *tm; |
struct tm *ptm; |
54 |
struct linux_rtc_wkalrm wake; |
struct linux_rtc_wkalrm wake; |
55 |
|
|
56 |
/* The wakeup time is in POSIX time (more or less UTC). |
/* The wakeup time is in POSIX time (more or less UTC). |
63 |
* Else mode is local so the time given to the RTC |
* Else mode is local so the time given to the RTC |
64 |
* will instead use the local time zone. |
* will instead use the local time zone. |
65 |
*/ |
*/ |
66 |
tm = localtime(wakeup); |
ptm = localtime(wakeup); |
67 |
|
|
68 |
wake.time.tm_sec = tm->tm_sec; |
wake.time.tm_sec = ptm->tm_sec; |
69 |
wake.time.tm_min = tm->tm_min; |
wake.time.tm_min = ptm->tm_min; |
70 |
wake.time.tm_hour = tm->tm_hour; |
wake.time.tm_hour = ptm->tm_hour; |
71 |
wake.time.tm_mday = tm->tm_mday; |
wake.time.tm_mday = ptm->tm_mday; |
72 |
wake.time.tm_mon = tm->tm_mon; |
wake.time.tm_mon = ptm->tm_mon; |
73 |
wake.time.tm_year = tm->tm_year; |
wake.time.tm_year = ptm->tm_year; |
74 |
/* wday, yday, and isdst fields are unused by Linux */ |
/* wday, yday, and isdst fields are unused by Linux */ |
75 |
wake.time.tm_wday = -1; |
wake.time.tm_wday = -1; |
76 |
wake.time.tm_yday = -1; |
wake.time.tm_yday = -1; |
100 |
int rtcwake_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int rtcwake_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
101 |
int rtcwake_main(int argc UNUSED_PARAM, char **argv) |
int rtcwake_main(int argc UNUSED_PARAM, char **argv) |
102 |
{ |
{ |
103 |
|
time_t rtc_time; |
104 |
|
|
105 |
unsigned opt; |
unsigned opt; |
106 |
const char *rtcname = NULL; |
const char *rtcname = NULL; |
107 |
const char *suspend; |
const char *suspend; |
114 |
int utc = -1; |
int utc = -1; |
115 |
int fd; |
int fd; |
116 |
|
|
117 |
#if ENABLE_GETOPT_LONG |
#if ENABLE_LONG_OPTS |
118 |
static const char rtcwake_longopts[] ALIGN1 = |
static const char rtcwake_longopts[] ALIGN1 = |
119 |
"auto\0" No_argument "a" |
"auto\0" No_argument "a" |
120 |
"local\0" No_argument "l" |
"local\0" No_argument "l" |
141 |
seconds = xatoi(opt_seconds); |
seconds = xatoi(opt_seconds); |
142 |
if (opt & RTCWAKE_OPT_TIME) |
if (opt & RTCWAKE_OPT_TIME) |
143 |
/* alarm time, time_t (absolute, seconds since 1/1 1970 UTC) */ |
/* alarm time, time_t (absolute, seconds since 1/1 1970 UTC) */ |
144 |
alarm_time = xatoi(opt_time); |
alarm_time = xatol(opt_time); |
145 |
|
|
146 |
if (!alarm_time && !seconds) |
if (!alarm_time && !seconds) |
147 |
bb_error_msg_and_die("must provide wake time"); |
bb_error_msg_and_die("must provide wake time"); |
159 |
bb_error_msg_and_die("%s not enabled for wakeup events", rtcname); |
bb_error_msg_and_die("%s not enabled for wakeup events", rtcname); |
160 |
|
|
161 |
/* relative or absolute alarm time, normalized to time_t */ |
/* relative or absolute alarm time, normalized to time_t */ |
162 |
sys_time = time(0); |
sys_time = time(NULL); |
163 |
if (sys_time == (time_t)-1) |
{ |
164 |
bb_perror_msg_and_die("read system time"); |
struct tm tm_time; |
165 |
rtc_time = rtc_read_time(fd, utc); |
rtc_read_tm(&tm_time, fd); |
166 |
|
rtc_time = rtc_tm2time(&tm_time, utc); |
167 |
|
} |
168 |
|
|
169 |
|
|
170 |
if (alarm_time) { |
if (alarm_time) { |
171 |
if (alarm_time < sys_time) |
if (alarm_time < sys_time) |
173 |
alarm_time += sys_time - rtc_time; |
alarm_time += sys_time - rtc_time; |
174 |
} else |
} else |
175 |
alarm_time = rtc_time + seconds + 1; |
alarm_time = rtc_time + seconds + 1; |
176 |
setup_alarm(fd, &alarm_time); |
setup_alarm(fd, &alarm_time, rtc_time); |
177 |
|
|
178 |
sync(); |
sync(); |
179 |
printf("wakeup from \"%s\" at %s", suspend, ctime(&alarm_time)); |
printf("wakeup from \"%s\" at %s", suspend, ctime(&alarm_time)); |
180 |
fflush(stdout); |
fflush_all(); |
181 |
usleep(10 * 1000); |
usleep(10 * 1000); |
182 |
|
|
183 |
if (strcmp(suspend, "on")) |
if (strcmp(suspend, "on")) |