xref: /openbmc/debug-trigger/main.c (revision db47cd7f6440c810e05e44d0fcc334502e4a9a81)
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 
17*db47cd7fSAndrew Jeffery static void process_debug(int sink)
18*db47cd7fSAndrew Jeffery {
19*db47cd7fSAndrew Jeffery 	static const char action = 'c';
20*db47cd7fSAndrew Jeffery 	ssize_t rc;
21*db47cd7fSAndrew Jeffery 
22*db47cd7fSAndrew Jeffery 	sync();
23*db47cd7fSAndrew Jeffery 
24*db47cd7fSAndrew Jeffery 	if ((rc = write(sink, &action, sizeof(action))) == sizeof(action))
25*db47cd7fSAndrew Jeffery 		return;
26*db47cd7fSAndrew Jeffery 
27*db47cd7fSAndrew Jeffery 	if (rc == -1) {
28*db47cd7fSAndrew Jeffery 		warn("Failed to execute debug command");
29*db47cd7fSAndrew Jeffery 	} else {
30*db47cd7fSAndrew Jeffery 		warnx("Failed to execute debug command: %zd", rc);
31*db47cd7fSAndrew Jeffery 	}
32*db47cd7fSAndrew Jeffery }
33*db47cd7fSAndrew Jeffery 
3411cd254bSAndrew Jeffery static int process(int source, int sink)
3511cd254bSAndrew Jeffery {
3611cd254bSAndrew Jeffery 	ssize_t ingress;
3711cd254bSAndrew Jeffery 	char command;
3811cd254bSAndrew Jeffery 
3911cd254bSAndrew Jeffery 	while ((ingress = read(source, &command, sizeof(command))) == sizeof(command)) {
4011cd254bSAndrew Jeffery 		ssize_t rc;
4111cd254bSAndrew Jeffery 
4211cd254bSAndrew Jeffery 		switch (command) {
43*db47cd7fSAndrew Jeffery 		case 'D':
44*db47cd7fSAndrew Jeffery 			process_debug(sink);
4511cd254bSAndrew Jeffery 			break;
4611cd254bSAndrew Jeffery 		case 'R':
4711cd254bSAndrew Jeffery 			sync();
4811cd254bSAndrew Jeffery 
4911cd254bSAndrew Jeffery 			if ((rc = reboot(LINUX_REBOOT_CMD_RESTART))) {
5011cd254bSAndrew Jeffery 				if (rc == -1)
5111cd254bSAndrew Jeffery 					warn("Failed to reboot BMC");
5211cd254bSAndrew Jeffery 				else
5311cd254bSAndrew Jeffery 					warnx("Failed to reboot BMC: %zd", rc);
5411cd254bSAndrew Jeffery 			}
5511cd254bSAndrew Jeffery 			break;
5611cd254bSAndrew Jeffery 		default:
5711cd254bSAndrew Jeffery 			warnx("Unexpected command: 0x%02x (%c)", command, command);
5811cd254bSAndrew Jeffery 		}
5911cd254bSAndrew Jeffery 	}
6011cd254bSAndrew Jeffery 
6111cd254bSAndrew Jeffery 	if (ingress == -1)
6211cd254bSAndrew Jeffery 		warn("Failed to read from source");
6311cd254bSAndrew Jeffery 
6411cd254bSAndrew Jeffery 	return ingress;
6511cd254bSAndrew Jeffery }
6611cd254bSAndrew Jeffery 
6711cd254bSAndrew Jeffery int main(int argc, char * const argv[])
6811cd254bSAndrew Jeffery {
6911cd254bSAndrew Jeffery 	char devnode[PATH_MAX];
7011cd254bSAndrew Jeffery 	char *devid;
7111cd254bSAndrew Jeffery 	int source;
7211cd254bSAndrew Jeffery 	int sink;
7311cd254bSAndrew Jeffery 
7411cd254bSAndrew Jeffery 	while (1) {
7511cd254bSAndrew Jeffery 		static struct option long_options[] = {
7611cd254bSAndrew Jeffery 			{0, 0, 0, 0},
7711cd254bSAndrew Jeffery 		};
7811cd254bSAndrew Jeffery 		int c;
7911cd254bSAndrew Jeffery 
8011cd254bSAndrew Jeffery 		c = getopt_long(argc, argv, "", long_options, NULL);
8111cd254bSAndrew Jeffery 		if (c == -1)
8211cd254bSAndrew Jeffery 			break;
8311cd254bSAndrew Jeffery 	}
8411cd254bSAndrew Jeffery 
8511cd254bSAndrew Jeffery 	source = 0;
8611cd254bSAndrew Jeffery 	sink = 1;
8711cd254bSAndrew Jeffery 
8811cd254bSAndrew Jeffery 	if (optind < argc) {
8911cd254bSAndrew Jeffery 		char devpath[PATH_MAX];
9011cd254bSAndrew Jeffery 
9111cd254bSAndrew Jeffery 		strncpy(devpath, argv[optind], sizeof(devpath));
9211cd254bSAndrew Jeffery 		devpath[PATH_MAX - 1] = '\0';
9311cd254bSAndrew Jeffery 		devid = basename(devpath);
9411cd254bSAndrew Jeffery 
9511cd254bSAndrew Jeffery 		strncpy(devnode, "/dev/", sizeof(devnode));
9611cd254bSAndrew Jeffery 		strncat(devnode, devid, sizeof(devnode));
9711cd254bSAndrew Jeffery 		devnode[PATH_MAX - 1] = '\0';
9811cd254bSAndrew Jeffery 
9911cd254bSAndrew Jeffery 		if ((source = open(devnode, O_RDONLY)) == -1)
10011cd254bSAndrew Jeffery 			err(EXIT_FAILURE, "Failed to open %s", devnode);
10111cd254bSAndrew Jeffery 
10211cd254bSAndrew Jeffery 		optind++;
10311cd254bSAndrew Jeffery 	}
10411cd254bSAndrew Jeffery 
10511cd254bSAndrew Jeffery 	if (optind < argc) {
10611cd254bSAndrew Jeffery 		if ((sink = open(argv[optind], O_WRONLY)) == -1)
10711cd254bSAndrew Jeffery 			err(EXIT_FAILURE, "Failed to open %s", argv[optind]);
10811cd254bSAndrew Jeffery 
10911cd254bSAndrew Jeffery 		optind++;
11011cd254bSAndrew Jeffery 	}
11111cd254bSAndrew Jeffery 
11211cd254bSAndrew Jeffery 	if (optind < argc)
11311cd254bSAndrew Jeffery 		err(EXIT_FAILURE, "Found %d unexpected arguments", argc - optind);
11411cd254bSAndrew Jeffery 
11511cd254bSAndrew Jeffery 	if (process(source, sink) < 0)
11611cd254bSAndrew Jeffery 		errx(EXIT_FAILURE, "Failure while processing command stream");
11711cd254bSAndrew Jeffery 
11811cd254bSAndrew Jeffery 	return 0;
11911cd254bSAndrew Jeffery }
120