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