xref: /freebsd/usr.sbin/efiwake/efiwake.c (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2023 Johannes Totz
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/efiio.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sysexits.h>
37 #include <unistd.h>
38 
39 static void
40 usage(void)
41 {
42 	fprintf(stderr, "Usage:\n"
43 	    "  efiwake                          -- print out current "
44 	        "EFI time and wake time\n"
45 	    "  efiwake -d                       -- disable wake time\n"
46 	    "  efiwake -e yyyy-mm-ddThh:mm:ss   -- enable wake time\n"
47 	);
48 	exit(EX_USAGE);
49 }
50 
51 int
52 main(int argc, char **argv)
53 {
54 	struct efi_tm now;
55 	struct efi_waketime_ioc	waketime;
56 	int ch, error, efi_fd;
57 	bool disable = false, enable = false;
58 
59 	memset(&waketime, 0, sizeof(waketime));
60 
61 	while ((ch = getopt(argc, argv, "de:")) != -1) {
62 		switch (ch) {
63 		case 'd':
64 			disable = true;
65 			break;
66 		case 'e':
67 			if (sscanf(optarg,
68 			    "%hu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu",
69 			    &waketime.waketime.tm_year,
70 			    &waketime.waketime.tm_mon,
71 			    &waketime.waketime.tm_mday,
72 			    &waketime.waketime.tm_hour,
73 			    &waketime.waketime.tm_min,
74 			    &waketime.waketime.tm_sec) != 6) {
75 				usage();
76 			}
77 			enable = true;
78 			break;
79 		case '?':
80 		default:
81 			usage();
82 		}
83 	}
84 	argc -= optind;
85 	argv += optind;
86 
87 	if (argc > 0)
88 		usage();
89 	if (disable && enable)
90 		usage();
91 
92 	efi_fd = open("/dev/efi", O_RDWR);
93 	if (efi_fd < 0)
94 		err(EX_OSERR, "cannot open /dev/efi");
95 
96 	error = ioctl(efi_fd, EFIIOC_GET_TIME, &now);
97 	if (error != 0)
98 		err(EX_OSERR, "cannot get EFI time");
99 
100 	/* EFI's time can be different from kernel's time. */
101 	printf("Current EFI time: %u-%02u-%02uT%02u:%02u:%02u\n",
102 	    now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min,
103 	    now.tm_sec);
104 
105 	if (disable) {
106 		/*
107 		 * It's tempting to preserve the current timer value.
108 		 * However, wonky EFI implementations sometimes return bogus
109 		 * dates for the wake timer and would then fail disabling it
110 		 * here.
111 		 * A safe timer value is the current EFI time.
112 		 */
113 		waketime.waketime = now;
114 		waketime.enabled = 0;
115 		error = ioctl(efi_fd, EFIIOC_SET_WAKETIME, &waketime);
116 		if (error != 0)
117 			err(EX_OSERR, "cannot disable EFI wake time");
118 	}
119 	if (enable) {
120 		waketime.enabled = 1;
121 		error = ioctl(efi_fd, EFIIOC_SET_WAKETIME, &waketime);
122 		if (error != 0)
123 			err(EX_OSERR, "cannot enable EFI wake time");
124 	}
125 
126 	/* Confirm to user what the wake time has been set to. */
127 	error = ioctl(efi_fd, EFIIOC_GET_WAKETIME, &waketime);
128 	if (error != 0)
129 		err(EX_OSERR, "cannot get EFI wake time");
130 
131 	printf("EFI wake time: %u-%02u-%02uT%02u:%02u:%02u; "
132 	    "enabled=%i, pending=%i\n",
133 	    waketime.waketime.tm_year, waketime.waketime.tm_mon,
134 	    waketime.waketime.tm_mday, waketime.waketime.tm_hour,
135 	    waketime.waketime.tm_min, waketime.waketime.tm_sec,
136 	    waketime.enabled, waketime.pending);
137 
138 	close(efi_fd);
139 	return (0);
140 }
141