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