111cd254bSAndrew Jeffery // SPDX-License-Identifier: Apache-2.0 211cd254bSAndrew Jeffery // Copyright (C) 2021 IBM Corp. 311cd254bSAndrew Jeffery 411cd254bSAndrew Jeffery #include <err.h> 511cd254bSAndrew Jeffery #include <fcntl.h> 611cd254bSAndrew Jeffery #include <getopt.h> 711cd254bSAndrew Jeffery #include <libgen.h> 811cd254bSAndrew Jeffery #include <limits.h> 911cd254bSAndrew Jeffery #include <linux/reboot.h> 1011cd254bSAndrew Jeffery #include <stdlib.h> 1111cd254bSAndrew Jeffery #include <string.h> 1211cd254bSAndrew Jeffery #include <sys/reboot.h> 1311cd254bSAndrew Jeffery #include <sys/stat.h> 1411cd254bSAndrew Jeffery #include <sys/types.h> 1511cd254bSAndrew Jeffery #include <unistd.h> 1611cd254bSAndrew Jeffery 17db47cd7fSAndrew Jeffery static void process_debug(int sink) 18db47cd7fSAndrew Jeffery { 19*30b6496aSAndrew Jeffery /* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/sysrq.rst?h=v5.16#n93 */ 20db47cd7fSAndrew Jeffery static const char action = 'c'; 21db47cd7fSAndrew Jeffery ssize_t rc; 22db47cd7fSAndrew Jeffery 23db47cd7fSAndrew Jeffery sync(); 24db47cd7fSAndrew Jeffery 25db47cd7fSAndrew Jeffery if ((rc = write(sink, &action, sizeof(action))) == sizeof(action)) 26db47cd7fSAndrew Jeffery return; 27db47cd7fSAndrew Jeffery 28db47cd7fSAndrew Jeffery if (rc == -1) { 29db47cd7fSAndrew Jeffery warn("Failed to execute debug command"); 30db47cd7fSAndrew Jeffery } else { 31db47cd7fSAndrew Jeffery warnx("Failed to execute debug command: %zd", rc); 32db47cd7fSAndrew Jeffery } 33db47cd7fSAndrew Jeffery } 34db47cd7fSAndrew Jeffery 35*30b6496aSAndrew Jeffery static void process_reboot(int sink) 3611cd254bSAndrew Jeffery { 37*30b6496aSAndrew Jeffery /* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/sysrq.rst?h=v5.16#n90 */ 38*30b6496aSAndrew Jeffery static const char action = 'b'; 3911cd254bSAndrew Jeffery ssize_t rc; 4011cd254bSAndrew Jeffery 4111cd254bSAndrew Jeffery sync(); 4211cd254bSAndrew Jeffery 43*30b6496aSAndrew Jeffery if ((rc = write(sink, &action, sizeof(action))) == sizeof(action)) 44*30b6496aSAndrew Jeffery return; 45*30b6496aSAndrew Jeffery 46*30b6496aSAndrew Jeffery if (rc == -1) { 4711cd254bSAndrew Jeffery warn("Failed to reboot BMC"); 48*30b6496aSAndrew Jeffery } else { 4911cd254bSAndrew Jeffery warnx("Failed to reboot BMC: %zd", rc); 5011cd254bSAndrew Jeffery } 51210ad636SAndrew Jeffery } 52210ad636SAndrew Jeffery 53210ad636SAndrew Jeffery static int process(int source, int sink) 54210ad636SAndrew Jeffery { 55210ad636SAndrew Jeffery ssize_t ingress; 56210ad636SAndrew Jeffery char command; 57210ad636SAndrew Jeffery 58210ad636SAndrew Jeffery while ((ingress = read(source, &command, sizeof(command))) == sizeof(command)) { 59210ad636SAndrew Jeffery switch (command) { 60210ad636SAndrew Jeffery case 'D': 61210ad636SAndrew Jeffery process_debug(sink); 62210ad636SAndrew Jeffery break; 63210ad636SAndrew Jeffery case 'R': 64210ad636SAndrew Jeffery process_reboot(sink); 6511cd254bSAndrew Jeffery break; 6611cd254bSAndrew Jeffery default: 6711cd254bSAndrew Jeffery warnx("Unexpected command: 0x%02x (%c)", command, command); 6811cd254bSAndrew Jeffery } 6911cd254bSAndrew Jeffery } 7011cd254bSAndrew Jeffery 7111cd254bSAndrew Jeffery if (ingress == -1) 7211cd254bSAndrew Jeffery warn("Failed to read from source"); 7311cd254bSAndrew Jeffery 7411cd254bSAndrew Jeffery return ingress; 7511cd254bSAndrew Jeffery } 7611cd254bSAndrew Jeffery 7711cd254bSAndrew Jeffery int main(int argc, char * const argv[]) 7811cd254bSAndrew Jeffery { 7911cd254bSAndrew Jeffery char devnode[PATH_MAX]; 8011cd254bSAndrew Jeffery char *devid; 8111cd254bSAndrew Jeffery int source; 8211cd254bSAndrew Jeffery int sink; 8311cd254bSAndrew Jeffery 8411cd254bSAndrew Jeffery while (1) { 8511cd254bSAndrew Jeffery static struct option long_options[] = { 8611cd254bSAndrew Jeffery {0, 0, 0, 0}, 8711cd254bSAndrew Jeffery }; 8811cd254bSAndrew Jeffery int c; 8911cd254bSAndrew Jeffery 9011cd254bSAndrew Jeffery c = getopt_long(argc, argv, "", long_options, NULL); 9111cd254bSAndrew Jeffery if (c == -1) 9211cd254bSAndrew Jeffery break; 9311cd254bSAndrew Jeffery } 9411cd254bSAndrew Jeffery 9511cd254bSAndrew Jeffery source = 0; 9611cd254bSAndrew Jeffery sink = 1; 9711cd254bSAndrew Jeffery 9811cd254bSAndrew Jeffery if (optind < argc) { 9911cd254bSAndrew Jeffery char devpath[PATH_MAX]; 10011cd254bSAndrew Jeffery 10111cd254bSAndrew Jeffery strncpy(devpath, argv[optind], sizeof(devpath)); 10211cd254bSAndrew Jeffery devpath[PATH_MAX - 1] = '\0'; 10311cd254bSAndrew Jeffery devid = basename(devpath); 10411cd254bSAndrew Jeffery 10511cd254bSAndrew Jeffery strncpy(devnode, "/dev/", sizeof(devnode)); 10611cd254bSAndrew Jeffery strncat(devnode, devid, sizeof(devnode)); 10711cd254bSAndrew Jeffery devnode[PATH_MAX - 1] = '\0'; 10811cd254bSAndrew Jeffery 10911cd254bSAndrew Jeffery if ((source = open(devnode, O_RDONLY)) == -1) 11011cd254bSAndrew Jeffery err(EXIT_FAILURE, "Failed to open %s", devnode); 11111cd254bSAndrew Jeffery 11211cd254bSAndrew Jeffery optind++; 11311cd254bSAndrew Jeffery } 11411cd254bSAndrew Jeffery 11511cd254bSAndrew Jeffery if (optind < argc) { 11611cd254bSAndrew Jeffery if ((sink = open(argv[optind], O_WRONLY)) == -1) 11711cd254bSAndrew Jeffery err(EXIT_FAILURE, "Failed to open %s", argv[optind]); 11811cd254bSAndrew Jeffery 11911cd254bSAndrew Jeffery optind++; 12011cd254bSAndrew Jeffery } 12111cd254bSAndrew Jeffery 12211cd254bSAndrew Jeffery if (optind < argc) 12311cd254bSAndrew Jeffery err(EXIT_FAILURE, "Found %d unexpected arguments", argc - optind); 12411cd254bSAndrew Jeffery 12511cd254bSAndrew Jeffery if (process(source, sink) < 0) 12611cd254bSAndrew Jeffery errx(EXIT_FAILURE, "Failure while processing command stream"); 12711cd254bSAndrew Jeffery 12811cd254bSAndrew Jeffery return 0; 12911cd254bSAndrew Jeffery } 130