diff options
| author | Mike Frysinger <vapier@gentoo.org> | 2008-02-15 02:27:19 +0000 |
|---|---|---|
| committer | Mike Frysinger <vapier@gentoo.org> | 2008-02-15 02:27:19 +0000 |
| commit | 6b160e490d4d77596c1603d34d0a1ca0579a82da (patch) | |
| tree | 653ab55714a0373751b619144e56b5ea163938f2 /util-linux | |
| parent | be7d2a8ded621a6d62f8caa76f7c51185b166ab1 (diff) | |
| download | busybox-w32-6b160e490d4d77596c1603d34d0a1ca0579a82da.tar.gz busybox-w32-6b160e490d4d77596c1603d34d0a1ca0579a82da.tar.bz2 busybox-w32-6b160e490d4d77596c1603d34d0a1ca0579a82da.zip | |
split some rtc funcs out of hwclock and into an rtc header/lib so that the new rtcwake applet as well as hwclock can utilize the same code
Diffstat (limited to 'util-linux')
| -rw-r--r-- | util-linux/Config.in | 6 | ||||
| -rw-r--r-- | util-linux/Kbuild | 1 | ||||
| -rw-r--r-- | util-linux/hwclock.c | 115 | ||||
| -rw-r--r-- | util-linux/rtcwake.c | 209 |
4 files changed, 232 insertions, 99 deletions
diff --git a/util-linux/Config.in b/util-linux/Config.in index e97f84062..d1688e8c9 100644 --- a/util-linux/Config.in +++ b/util-linux/Config.in | |||
| @@ -458,6 +458,12 @@ config READPROFILE | |||
| 458 | help | 458 | help |
| 459 | This allows you to parse /proc/profile for basic profiling. | 459 | This allows you to parse /proc/profile for basic profiling. |
| 460 | 460 | ||
| 461 | config RTCWAKE | ||
| 462 | bool "rtcwake" | ||
| 463 | default n | ||
| 464 | help | ||
| 465 | Enter a system sleep state until specified wakeup time. | ||
| 466 | |||
| 461 | config SETARCH | 467 | config SETARCH |
| 462 | bool "setarch" | 468 | bool "setarch" |
| 463 | default n | 469 | default n |
diff --git a/util-linux/Kbuild b/util-linux/Kbuild index cc1d0e05d..4a18ff21f 100644 --- a/util-linux/Kbuild +++ b/util-linux/Kbuild | |||
| @@ -26,6 +26,7 @@ lib-$(CONFIG_MOUNT) +=mount.o | |||
| 26 | lib-$(CONFIG_PIVOT_ROOT) +=pivot_root.o | 26 | lib-$(CONFIG_PIVOT_ROOT) +=pivot_root.o |
| 27 | lib-$(CONFIG_RDATE) +=rdate.o | 27 | lib-$(CONFIG_RDATE) +=rdate.o |
| 28 | lib-$(CONFIG_READPROFILE) +=readprofile.o | 28 | lib-$(CONFIG_READPROFILE) +=readprofile.o |
| 29 | lib-$(CONFIG_RTCWAKE) +=rtcwake.o | ||
| 29 | lib-$(CONFIG_SETARCH) +=setarch.o | 30 | lib-$(CONFIG_SETARCH) +=setarch.o |
| 30 | lib-$(CONFIG_SWAPONOFF) +=swaponoff.o | 31 | lib-$(CONFIG_SWAPONOFF) +=swaponoff.o |
| 31 | lib-$(CONFIG_SWITCH_ROOT) +=switch_root.o | 32 | lib-$(CONFIG_SWITCH_ROOT) +=switch_root.o |
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c index f91379bed..b581d2604 100644 --- a/util-linux/hwclock.c +++ b/util-linux/hwclock.c | |||
| @@ -10,22 +10,7 @@ | |||
| 10 | #include <sys/utsname.h> | 10 | #include <sys/utsname.h> |
| 11 | #include <getopt.h> | 11 | #include <getopt.h> |
| 12 | #include "libbb.h" | 12 | #include "libbb.h" |
| 13 | 13 | #include "rtc_.h" | |
| 14 | /* Copied from linux/rtc.h to eliminate the kernel dependency */ | ||
| 15 | struct linux_rtc_time { | ||
| 16 | int tm_sec; | ||
| 17 | int tm_min; | ||
| 18 | int tm_hour; | ||
| 19 | int tm_mday; | ||
| 20 | int tm_mon; | ||
| 21 | int tm_year; | ||
| 22 | int tm_wday; | ||
| 23 | int tm_yday; | ||
| 24 | int tm_isdst; | ||
| 25 | }; | ||
| 26 | |||
| 27 | #define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */ | ||
| 28 | #define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */ | ||
| 29 | 14 | ||
| 30 | #if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS | 15 | #if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS |
| 31 | # ifndef _GNU_SOURCE | 16 | # ifndef _GNU_SOURCE |
| @@ -35,56 +20,22 @@ struct linux_rtc_time { | |||
| 35 | 20 | ||
| 36 | static const char *rtcname; | 21 | static const char *rtcname; |
| 37 | 22 | ||
| 38 | static int xopen_rtc(int flags) | ||
| 39 | { | ||
| 40 | int rtc; | ||
| 41 | |||
| 42 | if (!rtcname) { | ||
| 43 | rtc = open("/dev/rtc", flags); | ||
| 44 | if (rtc >= 0) | ||
| 45 | return rtc; | ||
| 46 | rtc = open("/dev/rtc0", flags); | ||
| 47 | if (rtc >= 0) | ||
| 48 | return rtc; | ||
| 49 | rtcname = "/dev/misc/rtc"; | ||
| 50 | } | ||
| 51 | return xopen(rtcname, flags); | ||
| 52 | } | ||
| 53 | |||
| 54 | static time_t read_rtc(int utc) | 23 | static time_t read_rtc(int utc) |
| 55 | { | 24 | { |
| 56 | struct tm tm; | 25 | time_t ret; |
| 57 | char *oldtz = 0; | 26 | int fd; |
| 58 | time_t t = 0; | ||
| 59 | int rtc = xopen_rtc(O_RDONLY); | ||
| 60 | 27 | ||
| 61 | memset(&tm, 0, sizeof(struct tm)); | 28 | fd = rtc_xopen(rtcname, O_RDONLY); |
| 62 | xioctl(rtc, RTC_RD_TIME, &tm); | 29 | ret = rtc_read_time(fd, utc); |
| 63 | tm.tm_isdst = -1; /* not known */ | 30 | close(fd); |
| 64 | 31 | ||
| 65 | close(rtc); | 32 | return ret; |
| 66 | |||
| 67 | if (utc) { | ||
| 68 | oldtz = getenv("TZ"); | ||
| 69 | putenv((char*)"TZ=UTC0"); | ||
| 70 | tzset(); | ||
| 71 | } | ||
| 72 | |||
| 73 | t = mktime(&tm); | ||
| 74 | |||
| 75 | if (utc) { | ||
| 76 | unsetenv("TZ"); | ||
| 77 | if (oldtz) | ||
| 78 | putenv(oldtz - 3); | ||
| 79 | tzset(); | ||
| 80 | } | ||
| 81 | return t; | ||
| 82 | } | 33 | } |
| 83 | 34 | ||
| 84 | static void write_rtc(time_t t, int utc) | 35 | static void write_rtc(time_t t, int utc) |
| 85 | { | 36 | { |
| 86 | struct tm tm; | 37 | struct tm tm; |
| 87 | int rtc = xopen_rtc(O_WRONLY); | 38 | int rtc = rtc_xopen(rtcname, O_WRONLY); |
| 88 | 39 | ||
| 89 | tm = *(utc ? gmtime(&t) : localtime(&t)); | 40 | tm = *(utc ? gmtime(&t) : localtime(&t)); |
| 90 | tm.tm_isdst = 0; | 41 | tm.tm_isdst = 0; |
| @@ -132,38 +83,6 @@ static void from_sys_clock(int utc) | |||
| 132 | write_rtc(tv.tv_sec, utc); | 83 | write_rtc(tv.tv_sec, utc); |
| 133 | } | 84 | } |
| 134 | 85 | ||
| 135 | #if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS | ||
| 136 | # define ADJTIME_PATH "/var/lib/hwclock/adjtime" | ||
| 137 | #else | ||
| 138 | # define ADJTIME_PATH "/etc/adjtime" | ||
| 139 | #endif | ||
| 140 | static int check_utc(void) | ||
| 141 | { | ||
| 142 | int utc = 0; | ||
| 143 | FILE *f = fopen(ADJTIME_PATH, "r"); | ||
| 144 | |||
| 145 | if (f) { | ||
| 146 | RESERVE_CONFIG_BUFFER(buffer, 128); | ||
| 147 | |||
| 148 | while (fgets(buffer, sizeof(buffer), f)) { | ||
| 149 | int len = strlen(buffer); | ||
| 150 | |||
| 151 | while (len && isspace(buffer[len - 1])) | ||
| 152 | len--; | ||
| 153 | |||
| 154 | buffer[len] = 0; | ||
| 155 | |||
| 156 | if (strncmp(buffer, "UTC", 3) == 0) { | ||
| 157 | utc = 1; | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | fclose(f); | ||
| 162 | RELEASE_CONFIG_BUFFER(buffer); | ||
| 163 | } | ||
| 164 | return utc; | ||
| 165 | } | ||
| 166 | |||
| 167 | #define HWCLOCK_OPT_LOCALTIME 0x01 | 86 | #define HWCLOCK_OPT_LOCALTIME 0x01 |
| 168 | #define HWCLOCK_OPT_UTC 0x02 | 87 | #define HWCLOCK_OPT_UTC 0x02 |
| 169 | #define HWCLOCK_OPT_SHOW 0x04 | 88 | #define HWCLOCK_OPT_SHOW 0x04 |
| @@ -193,19 +112,17 @@ int hwclock_main(int argc, char **argv) | |||
| 193 | 112 | ||
| 194 | /* If -u or -l wasn't given check if we are using utc */ | 113 | /* If -u or -l wasn't given check if we are using utc */ |
| 195 | if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME)) | 114 | if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME)) |
| 196 | utc = opt & HWCLOCK_OPT_UTC; | 115 | utc = (opt & HWCLOCK_OPT_UTC); |
| 197 | else | 116 | else |
| 198 | utc = check_utc(); | 117 | utc = rtc_adjtime_is_utc(); |
| 199 | 118 | ||
| 200 | if (opt & HWCLOCK_OPT_HCTOSYS) { | 119 | if (opt & HWCLOCK_OPT_HCTOSYS) |
| 201 | to_sys_clock(utc); | 120 | to_sys_clock(utc); |
| 202 | return 0; | 121 | else if (opt & HWCLOCK_OPT_SYSTOHC) |
| 203 | } | ||
| 204 | if (opt & HWCLOCK_OPT_SYSTOHC) { | ||
| 205 | from_sys_clock(utc); | 122 | from_sys_clock(utc); |
| 206 | return 0; | 123 | else |
| 207 | } | 124 | /* default HWCLOCK_OPT_SHOW */ |
| 208 | /* default HWCLOCK_OPT_SHOW */ | 125 | show_clock(utc); |
| 209 | show_clock(utc); | 126 | |
| 210 | return 0; | 127 | return 0; |
| 211 | } | 128 | } |
diff --git a/util-linux/rtcwake.c b/util-linux/rtcwake.c new file mode 100644 index 000000000..718f43d45 --- /dev/null +++ b/util-linux/rtcwake.c | |||
| @@ -0,0 +1,209 @@ | |||
| 1 | /* | ||
| 2 | * rtcwake -- enter a system sleep state until specified wakeup time. | ||
| 3 | * | ||
| 4 | * This version was taken from util-linux and scrubbed down for busybox. | ||
| 5 | * | ||
| 6 | * This uses cross-platform Linux interfaces to enter a system sleep state, | ||
| 7 | * and leave it no later than a specified time. It uses any RTC framework | ||
| 8 | * driver that supports standard driver model wakeup flags. | ||
| 9 | * | ||
| 10 | * This is normally used like the old "apmsleep" utility, to wake from a | ||
| 11 | * suspend state like ACPI S1 (standby) or S3 (suspend-to-RAM). Most | ||
| 12 | * platforms can implement those without analogues of BIOS, APM, or ACPI. | ||
| 13 | * | ||
| 14 | * On some systems, this can also be used like "nvram-wakeup", waking | ||
| 15 | * from states like ACPI S4 (suspend to disk). Not all systems have | ||
| 16 | * persistent media that are appropriate for such suspend modes. | ||
| 17 | * | ||
| 18 | * The best way to set the system's RTC is so that it holds the current | ||
| 19 | * time in UTC. Use the "-l" flag to tell this program that the system | ||
| 20 | * RTC uses a local timezone instead (maybe you dual-boot MS-Windows). | ||
| 21 | * That flag should not be needed on systems with adjtime support. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include "libbb.h" | ||
| 25 | #include "rtc_.h" | ||
| 26 | |||
| 27 | #define SYS_RTC_PATH "/sys/class/rtc/%s/device/power/wakeup" | ||
| 28 | #define SYS_POWER_PATH "/sys/power/state" | ||
| 29 | #define DEFAULT_MODE "suspend" | ||
| 30 | |||
| 31 | static time_t rtc_time; | ||
| 32 | |||
| 33 | static int may_wakeup(const char *rtcname) | ||
| 34 | { | ||
| 35 | ssize_t ret; | ||
| 36 | char buf[128]; | ||
| 37 | |||
| 38 | /* strip the '/dev/' from the rtcname here */ | ||
| 39 | if (!strncmp(rtcname, "/dev/", 5)) | ||
| 40 | rtcname += 5; | ||
| 41 | |||
| 42 | snprintf(buf, sizeof(buf), SYS_RTC_PATH, rtcname); | ||
| 43 | ret = open_read_close(buf, buf, sizeof(buf)); | ||
| 44 | if (ret < 0) | ||
| 45 | return 0; | ||
| 46 | |||
| 47 | /* wakeup events could be disabled or not supported */ | ||
| 48 | return strcmp(buf, "enabled\n") == 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | static void setup_alarm(int fd, time_t *wakeup) | ||
| 52 | { | ||
| 53 | struct tm *tm; | ||
| 54 | struct linux_rtc_wkalrm wake; | ||
| 55 | |||
| 56 | /* The wakeup time is in POSIX time (more or less UTC). | ||
| 57 | * Ideally RTCs use that same time; but PCs can't do that | ||
| 58 | * if they need to boot MS-Windows. Messy... | ||
| 59 | * | ||
| 60 | * When running in utc mode this process's timezone is UTC, | ||
| 61 | * so we'll pass a UTC date to the RTC. | ||
| 62 | * | ||
| 63 | * Else mode is local so the time given to the RTC | ||
| 64 | * will instead use the local time zone. | ||
| 65 | */ | ||
| 66 | tm = localtime(wakeup); | ||
| 67 | |||
| 68 | wake.time.tm_sec = tm->tm_sec; | ||
| 69 | wake.time.tm_min = tm->tm_min; | ||
| 70 | wake.time.tm_hour = tm->tm_hour; | ||
| 71 | wake.time.tm_mday = tm->tm_mday; | ||
| 72 | wake.time.tm_mon = tm->tm_mon; | ||
| 73 | wake.time.tm_year = tm->tm_year; | ||
| 74 | /* wday, yday, and isdst fields are unused by Linux */ | ||
| 75 | wake.time.tm_wday = -1; | ||
| 76 | wake.time.tm_yday = -1; | ||
| 77 | wake.time.tm_isdst = -1; | ||
| 78 | |||
| 79 | /* many rtc alarms only support up to 24 hours from 'now', | ||
| 80 | * so use the "more than 24 hours" request only if we must | ||
| 81 | */ | ||
| 82 | if ((rtc_time + (24 * 60 * 60)) > *wakeup) { | ||
| 83 | xioctl(fd, RTC_ALM_SET, &wake.time); | ||
| 84 | xioctl(fd, RTC_AIE_ON, 0); | ||
| 85 | } else { | ||
| 86 | /* avoid an extra AIE_ON call */ | ||
| 87 | wake.enabled = 1; | ||
| 88 | xioctl(fd, RTC_WKALM_SET, &wake); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | static void suspend_system(const char *suspend) | ||
| 93 | { | ||
| 94 | FILE *f = xfopen(SYS_POWER_PATH, "w"); | ||
| 95 | fprintf(f, "%s\n", suspend); | ||
| 96 | fflush(f); | ||
| 97 | /* this executes after wake from suspend */ | ||
| 98 | fclose(f); | ||
| 99 | } | ||
| 100 | |||
| 101 | #define RTCWAKE_OPT_AUTO 0x01 | ||
| 102 | #define RTCWAKE_OPT_LOCAL 0x02 | ||
| 103 | #define RTCWAKE_OPT_UTC 0x04 | ||
| 104 | #define RTCWAKE_OPT_DEVICE 0x08 | ||
| 105 | #define RTCWAKE_OPT_SUSPEND_MODE 0x10 | ||
| 106 | #define RTCWAKE_OPT_SECONDS 0x20 | ||
| 107 | #define RTCWAKE_OPT_TIME 0x40 | ||
| 108 | |||
| 109 | int rtcwake_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
| 110 | int rtcwake_main(int argc, char **argv) | ||
| 111 | { | ||
| 112 | unsigned opt; | ||
| 113 | const char *rtcname = NULL; | ||
| 114 | const char *suspend; | ||
| 115 | const char *opt_seconds; | ||
| 116 | const char *opt_time; | ||
| 117 | |||
| 118 | time_t sys_time; | ||
| 119 | time_t alarm_time = 0; | ||
| 120 | unsigned seconds = 0; | ||
| 121 | int utc = -1; | ||
| 122 | int fd; | ||
| 123 | |||
| 124 | #if ENABLE_GETOPT_LONG | ||
| 125 | static const char rtcwake_longopts[] ALIGN1 = | ||
| 126 | "auto\0" No_argument "a" | ||
| 127 | "local\0" No_argument "l" | ||
| 128 | "utc\0" No_argument "u" | ||
| 129 | "device\0" Required_argument "d" | ||
| 130 | "mode\0" Required_argument "m" | ||
| 131 | "seconds\0" Required_argument "s" | ||
| 132 | "time\0" Required_argument "t" | ||
| 133 | ; | ||
| 134 | applet_long_options = rtcwake_longopts; | ||
| 135 | } | ||
| 136 | #endif | ||
| 137 | opt = getopt32(argv, "alud:m:s:t:", &rtcname, &suspend, &opt_seconds, &opt_time); | ||
| 138 | |||
| 139 | /* this is the default | ||
| 140 | if (opt & RTCWAKE_OPT_AUTO) | ||
| 141 | utc = -1; | ||
| 142 | */ | ||
| 143 | if (opt & (RTCWAKE_OPT_UTC | RTCWAKE_OPT_LOCAL)) | ||
| 144 | utc = opt & RTCWAKE_OPT_UTC; | ||
| 145 | if (!(opt & RTCWAKE_OPT_SUSPEND_MODE)) | ||
| 146 | suspend = DEFAULT_MODE; | ||
| 147 | if (opt & RTCWAKE_OPT_SECONDS) | ||
| 148 | /* alarm time, seconds-to-sleep (relative) */ | ||
| 149 | seconds = xatoi(opt_seconds); | ||
| 150 | if (opt & RTCWAKE_OPT_TIME) | ||
| 151 | /* alarm time, time_t (absolute, seconds since 1/1 1970 UTC) */ | ||
| 152 | alarm_time = xatoi(opt_time); | ||
| 153 | |||
| 154 | if (!alarm_time && !seconds) | ||
| 155 | bb_error_msg_and_die("must provide wake time"); | ||
| 156 | |||
| 157 | if (utc == -1) | ||
| 158 | utc = rtc_adjtime_is_utc(); | ||
| 159 | |||
| 160 | /* the rtcname is relative to /dev */ | ||
| 161 | xchdir("/dev"); | ||
| 162 | |||
| 163 | if (strcmp(suspend, "on") != 0 && !may_wakeup(rtcname)) | ||
| 164 | bb_error_msg_and_die("%s not enabled for wakeup events", rtcname); | ||
| 165 | |||
| 166 | /* this RTC must exist and (if we'll sleep) be wakeup-enabled */ | ||
| 167 | fd = rtc_xopen(rtcname, O_RDONLY); | ||
| 168 | |||
| 169 | /* relative or absolute alarm time, normalized to time_t */ | ||
| 170 | sys_time = time(0); | ||
| 171 | if (sys_time == (time_t)-1) | ||
| 172 | bb_perror_msg_and_die("read system time"); | ||
| 173 | rtc_time = rtc_read_time(fd, utc); | ||
| 174 | |||
| 175 | if (alarm_time) { | ||
| 176 | if (alarm_time < sys_time) | ||
| 177 | bb_error_msg_and_die("time doesn't go backward to %s", ctime(&alarm_time)); | ||
| 178 | alarm_time += sys_time - rtc_time; | ||
| 179 | } else | ||
| 180 | alarm_time = rtc_time + seconds + 1; | ||
| 181 | setup_alarm(fd, &alarm_time); | ||
| 182 | |||
| 183 | sync(); | ||
| 184 | printf("wakeup from \"%s\" at %s", suspend, ctime(&alarm_time)); | ||
| 185 | fflush(stdout); | ||
| 186 | usleep(10 * 1000); | ||
| 187 | |||
| 188 | if (!strcmp(suspend, "on")) | ||
| 189 | suspend_system(suspend); | ||
| 190 | else { | ||
| 191 | /* "fake" suspend ... we'll do the delay ourselves */ | ||
| 192 | unsigned long data; | ||
| 193 | |||
| 194 | do { | ||
| 195 | ssize_t ret = safe_read(fd, &data, sizeof(data)); | ||
| 196 | if (ret < 0) { | ||
| 197 | bb_perror_msg("rtc read"); | ||
| 198 | break; | ||
| 199 | } | ||
| 200 | } while (!(data & RTC_AF)); | ||
| 201 | } | ||
| 202 | |||
| 203 | xioctl(fd, RTC_AIE_OFF, 0); | ||
| 204 | |||
| 205 | if (ENABLE_FEATURE_CLEAN_UP) | ||
| 206 | close(fd); | ||
| 207 | |||
| 208 | return EXIT_SUCCESS; | ||
| 209 | } | ||
