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