xref: /openbmc/debug-trigger/main.c (revision 210ad6361b666108b862903b241b5ec78b8907f7)
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 {
19db47cd7fSAndrew Jeffery 	static const char action = 'c';
20db47cd7fSAndrew Jeffery 	ssize_t rc;
21db47cd7fSAndrew Jeffery 
22db47cd7fSAndrew Jeffery 	sync();
23db47cd7fSAndrew Jeffery 
24db47cd7fSAndrew Jeffery 	if ((rc = write(sink, &action, sizeof(action))) == sizeof(action))
25db47cd7fSAndrew Jeffery 		return;
26db47cd7fSAndrew Jeffery 
27db47cd7fSAndrew Jeffery 	if (rc == -1) {
28db47cd7fSAndrew Jeffery 		warn("Failed to execute debug command");
29db47cd7fSAndrew Jeffery 	} else {
30db47cd7fSAndrew Jeffery 		warnx("Failed to execute debug command: %zd", rc);
31db47cd7fSAndrew Jeffery 	}
32db47cd7fSAndrew Jeffery }
33db47cd7fSAndrew Jeffery 
34*210ad636SAndrew Jeffery static void process_reboot(int sink __attribute__((unused)))
3511cd254bSAndrew Jeffery {
3611cd254bSAndrew Jeffery 	ssize_t rc;
3711cd254bSAndrew Jeffery 
3811cd254bSAndrew Jeffery 	sync();
3911cd254bSAndrew Jeffery 
4011cd254bSAndrew Jeffery 	if ((rc = reboot(LINUX_REBOOT_CMD_RESTART))) {
4111cd254bSAndrew Jeffery 		if (rc == -1)
4211cd254bSAndrew Jeffery 			warn("Failed to reboot BMC");
4311cd254bSAndrew Jeffery 		else
4411cd254bSAndrew Jeffery 			warnx("Failed to reboot BMC: %zd", rc);
4511cd254bSAndrew Jeffery 	}
46*210ad636SAndrew Jeffery }
47*210ad636SAndrew Jeffery 
48*210ad636SAndrew Jeffery static int process(int source, int sink)
49*210ad636SAndrew Jeffery {
50*210ad636SAndrew Jeffery 	ssize_t ingress;
51*210ad636SAndrew Jeffery 	char command;
52*210ad636SAndrew Jeffery 
53*210ad636SAndrew Jeffery 	while ((ingress = read(source, &command, sizeof(command))) == sizeof(command)) {
54*210ad636SAndrew Jeffery 		switch (command) {
55*210ad636SAndrew Jeffery 		case 'D':
56*210ad636SAndrew Jeffery 			process_debug(sink);
57*210ad636SAndrew Jeffery 			break;
58*210ad636SAndrew Jeffery 		case 'R':
59*210ad636SAndrew Jeffery 			process_reboot(sink);
6011cd254bSAndrew Jeffery 			break;
6111cd254bSAndrew Jeffery 		default:
6211cd254bSAndrew Jeffery 			warnx("Unexpected command: 0x%02x (%c)", command, command);
6311cd254bSAndrew Jeffery 		}
6411cd254bSAndrew Jeffery 	}
6511cd254bSAndrew Jeffery 
6611cd254bSAndrew Jeffery 	if (ingress == -1)
6711cd254bSAndrew Jeffery 		warn("Failed to read from source");
6811cd254bSAndrew Jeffery 
6911cd254bSAndrew Jeffery 	return ingress;
7011cd254bSAndrew Jeffery }
7111cd254bSAndrew Jeffery 
7211cd254bSAndrew Jeffery int main(int argc, char * const argv[])
7311cd254bSAndrew Jeffery {
7411cd254bSAndrew Jeffery 	char devnode[PATH_MAX];
7511cd254bSAndrew Jeffery 	char *devid;
7611cd254bSAndrew Jeffery 	int source;
7711cd254bSAndrew Jeffery 	int sink;
7811cd254bSAndrew Jeffery 
7911cd254bSAndrew Jeffery 	while (1) {
8011cd254bSAndrew Jeffery 		static struct option long_options[] = {
8111cd254bSAndrew Jeffery 			{0, 0, 0, 0},
8211cd254bSAndrew Jeffery 		};
8311cd254bSAndrew Jeffery 		int c;
8411cd254bSAndrew Jeffery 
8511cd254bSAndrew Jeffery 		c = getopt_long(argc, argv, "", long_options, NULL);
8611cd254bSAndrew Jeffery 		if (c == -1)
8711cd254bSAndrew Jeffery 			break;
8811cd254bSAndrew Jeffery 	}
8911cd254bSAndrew Jeffery 
9011cd254bSAndrew Jeffery 	source = 0;
9111cd254bSAndrew Jeffery 	sink = 1;
9211cd254bSAndrew Jeffery 
9311cd254bSAndrew Jeffery 	if (optind < argc) {
9411cd254bSAndrew Jeffery 		char devpath[PATH_MAX];
9511cd254bSAndrew Jeffery 
9611cd254bSAndrew Jeffery 		strncpy(devpath, argv[optind], sizeof(devpath));
9711cd254bSAndrew Jeffery 		devpath[PATH_MAX - 1] = '\0';
9811cd254bSAndrew Jeffery 		devid = basename(devpath);
9911cd254bSAndrew Jeffery 
10011cd254bSAndrew Jeffery 		strncpy(devnode, "/dev/", sizeof(devnode));
10111cd254bSAndrew Jeffery 		strncat(devnode, devid, sizeof(devnode));
10211cd254bSAndrew Jeffery 		devnode[PATH_MAX - 1] = '\0';
10311cd254bSAndrew Jeffery 
10411cd254bSAndrew Jeffery 		if ((source = open(devnode, O_RDONLY)) == -1)
10511cd254bSAndrew Jeffery 			err(EXIT_FAILURE, "Failed to open %s", devnode);
10611cd254bSAndrew Jeffery 
10711cd254bSAndrew Jeffery 		optind++;
10811cd254bSAndrew Jeffery 	}
10911cd254bSAndrew Jeffery 
11011cd254bSAndrew Jeffery 	if (optind < argc) {
11111cd254bSAndrew Jeffery 		if ((sink = open(argv[optind], O_WRONLY)) == -1)
11211cd254bSAndrew Jeffery 			err(EXIT_FAILURE, "Failed to open %s", argv[optind]);
11311cd254bSAndrew Jeffery 
11411cd254bSAndrew Jeffery 		optind++;
11511cd254bSAndrew Jeffery 	}
11611cd254bSAndrew Jeffery 
11711cd254bSAndrew Jeffery 	if (optind < argc)
11811cd254bSAndrew Jeffery 		err(EXIT_FAILURE, "Found %d unexpected arguments", argc - optind);
11911cd254bSAndrew Jeffery 
12011cd254bSAndrew Jeffery 	if (process(source, sink) < 0)
12111cd254bSAndrew Jeffery 		errx(EXIT_FAILURE, "Failure while processing command stream");
12211cd254bSAndrew Jeffery 
12311cd254bSAndrew Jeffery 	return 0;
12411cd254bSAndrew Jeffery }
125