1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright (C) 2021 IBM Corp. 3 4 #include <err.h> 5 #include <fcntl.h> 6 #include <getopt.h> 7 #include <libgen.h> 8 #include <limits.h> 9 #include <linux/reboot.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <sys/reboot.h> 13 #include <sys/stat.h> 14 #include <sys/types.h> 15 #include <unistd.h> 16 17 static void process_debug(int sink) 18 { 19 /* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/sysrq.rst?h=v5.16#n93 */ 20 static const char action = 'c'; 21 ssize_t rc; 22 23 sync(); 24 25 if ((rc = write(sink, &action, sizeof(action))) == sizeof(action)) 26 return; 27 28 if (rc == -1) { 29 warn("Failed to execute debug command"); 30 } else { 31 warnx("Failed to execute debug command: %zd", rc); 32 } 33 } 34 35 static void process_reboot(int sink) 36 { 37 /* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/sysrq.rst?h=v5.16#n90 */ 38 static const char action = 'b'; 39 ssize_t rc; 40 41 sync(); 42 43 if ((rc = write(sink, &action, sizeof(action))) == sizeof(action)) 44 return; 45 46 if (rc == -1) { 47 warn("Failed to reboot BMC"); 48 } else { 49 warnx("Failed to reboot BMC: %zd", rc); 50 } 51 } 52 53 static int process(int source, int sink) 54 { 55 ssize_t ingress; 56 char command; 57 58 while ((ingress = read(source, &command, sizeof(command))) == sizeof(command)) { 59 switch (command) { 60 case 'D': 61 process_debug(sink); 62 break; 63 case 'R': 64 process_reboot(sink); 65 break; 66 default: 67 warnx("Unexpected command: 0x%02x (%c)", command, command); 68 } 69 } 70 71 if (ingress == -1) 72 warn("Failed to read from source"); 73 74 return ingress; 75 } 76 77 int main(int argc, char * const argv[]) 78 { 79 char devnode[PATH_MAX]; 80 char *devid; 81 int source; 82 int sink; 83 84 while (1) { 85 static struct option long_options[] = { 86 {0, 0, 0, 0}, 87 }; 88 int c; 89 90 c = getopt_long(argc, argv, "", long_options, NULL); 91 if (c == -1) 92 break; 93 } 94 95 source = 0; 96 sink = 1; 97 98 if (optind < argc) { 99 char devpath[PATH_MAX]; 100 101 strncpy(devpath, argv[optind], sizeof(devpath)); 102 devpath[PATH_MAX - 1] = '\0'; 103 devid = basename(devpath); 104 105 strncpy(devnode, "/dev/", sizeof(devnode)); 106 strncat(devnode, devid, sizeof(devnode)); 107 devnode[PATH_MAX - 1] = '\0'; 108 109 if ((source = open(devnode, O_RDONLY)) == -1) 110 err(EXIT_FAILURE, "Failed to open %s", devnode); 111 112 optind++; 113 } 114 115 if (optind < argc) { 116 if ((sink = open(argv[optind], O_WRONLY)) == -1) 117 err(EXIT_FAILURE, "Failed to open %s", argv[optind]); 118 119 optind++; 120 } 121 122 if (optind < argc) 123 err(EXIT_FAILURE, "Found %d unexpected arguments", argc - optind); 124 125 if (process(source, sink) < 0) 126 errx(EXIT_FAILURE, "Failure while processing command stream"); 127 128 return 0; 129 } 130