int main(int argc, char **argv) { char *devname = DEFAULT_DEVICE; unsigned seconds = 0; char *suspend = DEFAULT_MODE; int t; int fd; time_t alarm = 0; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); progname = basename(argv[0]); while ((t = getopt_long(argc, argv, "ahd:lm:s:t:uVv", long_options, NULL)) != EOF) { switch (t) { case 'a': /* CM_AUTO is default */ break; case 'd': devname = strdup(optarg); break; case 'l': clock_mode = CM_LOCAL; break; /* what system power mode to use? for now handle only * standardized mode names; eventually when systems * define their own state names, parse * /sys/power/state. * * "on" is used just to test the RTC alarm mechanism, * bypassing all the wakeup-from-sleep infrastructure. */ case 'm': if (strcmp(optarg, "standby") == 0 || strcmp(optarg, "mem") == 0 || strcmp(optarg, "disk") == 0 || strcmp(optarg, "on") == 0 || strcmp(optarg, "no") == 0 ) { suspend = strdup(optarg); break; } fprintf(stderr, _("%s: unrecognized suspend state '%s'\n"), progname, optarg); usage(EXIT_FAILURE); /* alarm time, seconds-to-sleep (relative) */ case 's': t = atoi(optarg); if (t < 0) { fprintf(stderr, _("%s: illegal interval %s seconds\n"), progname, optarg); usage(EXIT_FAILURE); } seconds = t; break; /* alarm time, time_t (absolute, seconds since * 1/1 1970 UTC) */ case 't': t = atoi(optarg); if (t < 0) { fprintf(stderr, _("%s: illegal time_t value %s\n"), progname, optarg); usage(EXIT_FAILURE); } alarm = t; break; case 'u': clock_mode = CM_UTC; break; case 'v': verbose++; break; case 'V': printf(_("%s: version %s\n"), progname, VERSION_STRING); exit(EXIT_SUCCESS); case 'h': usage(EXIT_SUCCESS); default: usage(EXIT_FAILURE); } } if (clock_mode == CM_AUTO) { if (read_clock_mode() < 0) { printf(_("%s: assuming RTC uses UTC ...\n"), progname); clock_mode = CM_UTC; } } if (verbose) printf(clock_mode == CM_UTC ? _("Using UTC time.\n") : _("Using local time.\n")); if (!alarm && !seconds) { fprintf(stderr, _("%s: must provide wake time\n"), progname); usage(EXIT_FAILURE); } /* when devname doesn't start with /dev, append it */ if (strncmp(devname, "/dev/", strlen("/dev/")) != 0) { char *new_devname; new_devname = malloc(strlen(devname) + strlen("/dev/") + 1); if (!new_devname) { perror(_("malloc() failed")); exit(EXIT_FAILURE); } strcpy(new_devname, "/dev/"); strcat(new_devname, devname); free(devname); devname = new_devname; } if (strcmp(suspend, "on") != 0 && strcmp(suspend, "no") != 0 && !is_wakeup_enabled(devname)) { fprintf(stderr, _("%s: %s not enabled for wakeup events\n"), progname, devname); exit(EXIT_FAILURE); } /* this RTC must exist and (if we'll sleep) be wakeup-enabled */ fd = open(devname, O_RDONLY); if (fd < 0) { perror(devname); exit(EXIT_FAILURE); } /* relative or absolute alarm time, normalized to time_t */ if (get_basetimes(fd) < 0) exit(EXIT_FAILURE); if (verbose) printf(_("alarm %ld, sys_time %ld, rtc_time %ld, seconds %u\n"), alarm, sys_time, rtc_time, seconds); if (alarm) { if (alarm < sys_time) { fprintf(stderr, _("%s: time doesn't go backward to %s\n"), progname, ctime(&alarm)); exit(EXIT_FAILURE); } alarm += sys_time - rtc_time; } else alarm = rtc_time + seconds + 1; if (setup_alarm(fd, &alarm) < 0) exit(EXIT_FAILURE); printf(_("%s: wakeup from \"%s\" using %s at %s\n"), progname, suspend, devname, ctime(&alarm)); fflush(stdout); usleep(10 * 1000); if (strcmp(suspend, "no") == 0) exit(EXIT_SUCCESS); else if (strcmp(suspend, "on") != 0) { sync(); suspend_system(suspend); } else { unsigned long data; do { t = read(fd, &data, sizeof data); if (t < 0) { perror(_("rtc read")); break; } if (verbose) printf("... %s: %03lx\n", devname, data); } while (!(data & RTC_AF)); } if (ioctl(fd, RTC_AIE_OFF, 0) < 0) perror(_("disable rtc alarm interrupt")); close(fd); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { struct rtcwake_control ctl = { .mode_str = "suspend", /* default mode */ .adjfile = _PATH_ADJTIME, .clock_mode = CM_AUTO }; char *devname = DEFAULT_RTC_DEVICE; unsigned seconds = 0; int suspend = SYSFS_MODE; int rc = EXIT_SUCCESS; int t; int fd; time_t alarm = 0; enum { OPT_DATE = CHAR_MAX + 1, OPT_LIST }; static const struct option long_options[] = { {"adjfile", required_argument, 0, 'A'}, {"auto", no_argument, 0, 'a'}, {"dry-run", no_argument, 0, 'n'}, {"local", no_argument, 0, 'l'}, {"utc", no_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"mode", required_argument, 0, 'm'}, {"device", required_argument, 0, 'd'}, {"seconds", required_argument, 0, 's'}, {"time", required_argument, 0, 't'}, {"date", required_argument, 0, OPT_DATE}, {"list-modes", no_argument, 0, OPT_LIST}, {0, 0, 0, 0 } }; static const ul_excl_t excl[] = { { 'a', 'l', 'u' }, { 's', 't', OPT_DATE }, }; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); atexit(close_stdout); while ((t = getopt_long(argc, argv, "A:ahd:lm:ns:t:uVv", long_options, NULL)) != EOF) { err_exclusive_options(t, long_options, excl, excl_st); switch (t) { case 'A': /* for better compatibility with hwclock */ ctl.adjfile = optarg; break; case 'a': ctl.clock_mode = CM_AUTO; break; case 'd': devname = optarg; break; case 'l': ctl.clock_mode = CM_LOCAL; break; case OPT_LIST: list_modes(&ctl); return EXIT_SUCCESS; case 'm': if ((suspend = get_rtc_mode(&ctl, optarg)) < 0) errx(EXIT_FAILURE, _("unrecognized suspend state '%s'"), optarg); ctl.mode_str = optarg; break; case 'n': ctl.dryrun = 1; break; case 's': /* alarm time, seconds-to-sleep (relative) */ seconds = strtou32_or_err(optarg, _("invalid seconds argument")); break; case 't': /* alarm time, time_t (absolute, seconds since epoch) */ alarm = strtou32_or_err(optarg, _("invalid time argument")); break; case OPT_DATE: { /* alarm time, see timestamp format from manual */ usec_t p; if (parse_timestamp(optarg, &p) < 0) errx(EXIT_FAILURE, _("invalid time value \"%s\""), optarg); alarm = (time_t) (p / 1000000); break; } case 'u': ctl.clock_mode = CM_UTC; break; case 'v': ctl.verbose = 1; break; case 'V': printf(UTIL_LINUX_VERSION); exit(EXIT_SUCCESS); case 'h': usage(stdout); default: usage(stderr); } } if (ctl.clock_mode == CM_AUTO) { if (read_clock_mode(&ctl) < 0) { printf(_("%s: assuming RTC uses UTC ...\n"), program_invocation_short_name); ctl.clock_mode = CM_UTC; } } if (ctl.verbose) printf("%s", ctl.clock_mode == CM_UTC ? _("Using UTC time.\n") : _("Using local time.\n")); if (!alarm && !seconds && suspend != DISABLE_MODE && suspend != SHOW_MODE) errx(EXIT_FAILURE, _("must provide wake time (see --seconds, --time and --date options)")); /* device must exist and (if we'll sleep) be wakeup-enabled */ fd = open_dev_rtc(devname); if (suspend != ON_MODE && suspend != NO_MODE && !is_wakeup_enabled(devname)) errx(EXIT_FAILURE, _("%s not enabled for wakeup events"), devname); /* relative or absolute alarm time, normalized to time_t */ if (get_basetimes(&ctl, fd) < 0) exit(EXIT_FAILURE); if (ctl.verbose) printf(_("alarm %ld, sys_time %ld, rtc_time %ld, seconds %u\n"), alarm, ctl.sys_time, ctl.rtc_time, seconds); if (suspend != DISABLE_MODE && suspend != SHOW_MODE) { /* perform alarm setup when the show or disable modes are not set */ if (alarm) { if (alarm < ctl.sys_time) errx(EXIT_FAILURE, _("time doesn't go backward to %s"), ctime(&alarm)); alarm += ctl.sys_time - ctl.rtc_time; } else alarm = ctl.rtc_time + seconds + 1; if (setup_alarm(&ctl, fd, &alarm) < 0) exit(EXIT_FAILURE); if (suspend == NO_MODE || suspend == ON_MODE) printf(_("%s: wakeup using %s at %s"), program_invocation_short_name, devname, ctime(&alarm)); else printf(_("%s: wakeup from \"%s\" using %s at %s"), program_invocation_short_name, ctl.mode_str, devname, ctime(&alarm)); fflush(stdout); xusleep(10 * 1000); } switch (suspend) { case NO_MODE: if (ctl.verbose) printf(_("suspend mode: no; leaving\n")); ctl.dryrun = 1; /* to skip disabling alarm at the end */ break; case OFF_MODE: { char *arg[5]; int i = 0; if (ctl.verbose) printf(_("suspend mode: off; executing %s\n"), _PATH_SHUTDOWN); arg[i++] = _PATH_SHUTDOWN; arg[i++] = "-h"; arg[i++] = "-P"; arg[i++] = "now"; arg[i] = NULL; if (!ctl.dryrun) { execv(arg[0], arg); warn(_("failed to execute %s"), _PATH_SHUTDOWN); rc = EXIT_FAILURE; } break; } case ON_MODE: { unsigned long data; if (ctl.verbose) printf(_("suspend mode: on; reading rtc\n")); if (!ctl.dryrun) { do { t = read(fd, &data, sizeof data); if (t < 0) { warn(_("rtc read failed")); break; } if (ctl.verbose) printf("... %s: %03lx\n", devname, data); } while (!(data & RTC_AF)); } break; } case DISABLE_MODE: /* just break, alarm gets disabled in the end */ if (ctl.verbose) printf(_("suspend mode: disable; disabling alarm\n")); break; case SHOW_MODE: if (ctl.verbose) printf(_("suspend mode: show; printing alarm info\n")); if (print_alarm(&ctl, fd)) rc = EXIT_FAILURE; ctl.dryrun = 1; /* don't really disable alarm in the end, just show */ break; default: if (ctl.verbose) printf(_("suspend mode: %s; suspending system\n"), ctl.mode_str); sync(); suspend_system(&ctl); } if (!ctl.dryrun) { struct rtc_wkalrm wake; if (ioctl(fd, RTC_WKALM_RD, &wake) < 0) { warn(_("read rtc alarm failed")); rc = EXIT_FAILURE; } else { wake.enabled = 0; if (ioctl(fd, RTC_WKALM_SET, &wake) < 0) { warn(_("disable rtc alarm interrupt failed")); rc = EXIT_FAILURE; } } } close(fd); return rc; }