xref: /openbmc/debug-trigger/main.c (revision 30b6496a)
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