blob: 1f00ada9beb057fa6a1709cfdfebd090564a3ce5 [file] [log] [blame]
Andrew Jeffery11cd2542021-05-03 11:03:30 +09301// 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
Andrew Jefferydb47cd72022-01-13 14:14:41 +103017static void process_debug(int sink)
18{
Andrew Jeffery30b64962022-01-19 16:58:28 +103019 /* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/sysrq.rst?h=v5.16#n93 */
Andrew Jefferydb47cd72022-01-13 14:14:41 +103020 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
Andrew Jeffery30b64962022-01-19 16:58:28 +103035static void process_reboot(int sink)
Andrew Jeffery210ad632022-01-13 14:16:53 +103036{
Andrew Jeffery30b64962022-01-19 16:58:28 +103037 /* 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';
Andrew Jeffery210ad632022-01-13 14:16:53 +103039 ssize_t rc;
40
41 sync();
42
Andrew Jeffery30b64962022-01-19 16:58:28 +103043 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);
Andrew Jeffery210ad632022-01-13 14:16:53 +103050 }
51}
52
Andrew Jeffery11cd2542021-05-03 11:03:30 +093053static 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)) {
Andrew Jeffery11cd2542021-05-03 11:03:30 +093059 switch (command) {
Andrew Jefferydb47cd72022-01-13 14:14:41 +103060 case 'D':
61 process_debug(sink);
Andrew Jeffery11cd2542021-05-03 11:03:30 +093062 break;
63 case 'R':
Andrew Jeffery210ad632022-01-13 14:16:53 +103064 process_reboot(sink);
Andrew Jeffery11cd2542021-05-03 11:03:30 +093065 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
77int 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}