Example #1
0
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);
}
Example #2
0
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;
}