xref: /linux/tools/testing/selftests/liveupdate/init.c (revision 7b24dd46a70e94d8db83b50a04d46690fac216d0)
1*89dd1421SPasha Tatashin // SPDX-License-Identifier: GPL-2.0
2*89dd1421SPasha Tatashin 
3*89dd1421SPasha Tatashin /*
4*89dd1421SPasha Tatashin  * Copyright (c) 2025, Google LLC.
5*89dd1421SPasha Tatashin  * Pasha Tatashin <pasha.tatashin@soleen.com>
6*89dd1421SPasha Tatashin  */
7*89dd1421SPasha Tatashin #include <fcntl.h>
8*89dd1421SPasha Tatashin #include <linux/kexec.h>
9*89dd1421SPasha Tatashin #include <stdio.h>
10*89dd1421SPasha Tatashin #include <stdlib.h>
11*89dd1421SPasha Tatashin #include <string.h>
12*89dd1421SPasha Tatashin #include <sys/mount.h>
13*89dd1421SPasha Tatashin #include <sys/reboot.h>
14*89dd1421SPasha Tatashin #include <sys/syscall.h>
15*89dd1421SPasha Tatashin #include <sys/wait.h>
16*89dd1421SPasha Tatashin #include <unistd.h>
17*89dd1421SPasha Tatashin 
18*89dd1421SPasha Tatashin #define COMMAND_LINE_SIZE 2048
19*89dd1421SPasha Tatashin #define KERNEL_IMAGE "/kernel"
20*89dd1421SPasha Tatashin #define INITRD_IMAGE "/initrd.img"
21*89dd1421SPasha Tatashin #define TEST_BINARY "/test_binary"
22*89dd1421SPasha Tatashin 
23*89dd1421SPasha Tatashin static int mount_filesystems(void)
24*89dd1421SPasha Tatashin {
25*89dd1421SPasha Tatashin 	if (mount("devtmpfs", "/dev", "devtmpfs", 0, NULL) < 0) {
26*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: Warning: Failed to mount devtmpfs\n");
27*89dd1421SPasha Tatashin 		return -1;
28*89dd1421SPasha Tatashin 	}
29*89dd1421SPasha Tatashin 
30*89dd1421SPasha Tatashin 	if (mount("debugfs", "/debugfs", "debugfs", 0, NULL) < 0) {
31*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: Failed to mount debugfs\n");
32*89dd1421SPasha Tatashin 		return -1;
33*89dd1421SPasha Tatashin 	}
34*89dd1421SPasha Tatashin 
35*89dd1421SPasha Tatashin 	if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
36*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: Failed to mount proc\n");
37*89dd1421SPasha Tatashin 		return -1;
38*89dd1421SPasha Tatashin 	}
39*89dd1421SPasha Tatashin 
40*89dd1421SPasha Tatashin 	return 0;
41*89dd1421SPasha Tatashin }
42*89dd1421SPasha Tatashin 
43*89dd1421SPasha Tatashin static long kexec_file_load(int kernel_fd, int initrd_fd,
44*89dd1421SPasha Tatashin 			    unsigned long cmdline_len, const char *cmdline,
45*89dd1421SPasha Tatashin 			    unsigned long flags)
46*89dd1421SPasha Tatashin {
47*89dd1421SPasha Tatashin 	return syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len,
48*89dd1421SPasha Tatashin 		       cmdline, flags);
49*89dd1421SPasha Tatashin }
50*89dd1421SPasha Tatashin 
51*89dd1421SPasha Tatashin static int kexec_load(void)
52*89dd1421SPasha Tatashin {
53*89dd1421SPasha Tatashin 	char cmdline[COMMAND_LINE_SIZE];
54*89dd1421SPasha Tatashin 	int kernel_fd, initrd_fd, err;
55*89dd1421SPasha Tatashin 	ssize_t len;
56*89dd1421SPasha Tatashin 	int fd;
57*89dd1421SPasha Tatashin 
58*89dd1421SPasha Tatashin 	fd = open("/proc/cmdline", O_RDONLY);
59*89dd1421SPasha Tatashin 	if (fd < 0) {
60*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: Failed to read /proc/cmdline\n");
61*89dd1421SPasha Tatashin 
62*89dd1421SPasha Tatashin 		return -1;
63*89dd1421SPasha Tatashin 	}
64*89dd1421SPasha Tatashin 
65*89dd1421SPasha Tatashin 	len = read(fd, cmdline, sizeof(cmdline) - 1);
66*89dd1421SPasha Tatashin 	close(fd);
67*89dd1421SPasha Tatashin 	if (len < 0)
68*89dd1421SPasha Tatashin 		return -1;
69*89dd1421SPasha Tatashin 
70*89dd1421SPasha Tatashin 	cmdline[len] = 0;
71*89dd1421SPasha Tatashin 	if (len > 0 && cmdline[len - 1] == '\n')
72*89dd1421SPasha Tatashin 		cmdline[len - 1] = 0;
73*89dd1421SPasha Tatashin 
74*89dd1421SPasha Tatashin 	strncat(cmdline, " luo_stage=2", sizeof(cmdline) - strlen(cmdline) - 1);
75*89dd1421SPasha Tatashin 
76*89dd1421SPasha Tatashin 	kernel_fd = open(KERNEL_IMAGE, O_RDONLY);
77*89dd1421SPasha Tatashin 	if (kernel_fd < 0) {
78*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: Failed to open kernel image\n");
79*89dd1421SPasha Tatashin 		return -1;
80*89dd1421SPasha Tatashin 	}
81*89dd1421SPasha Tatashin 
82*89dd1421SPasha Tatashin 	initrd_fd = open(INITRD_IMAGE, O_RDONLY);
83*89dd1421SPasha Tatashin 	if (initrd_fd < 0) {
84*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: Failed to open initrd image\n");
85*89dd1421SPasha Tatashin 		close(kernel_fd);
86*89dd1421SPasha Tatashin 		return -1;
87*89dd1421SPasha Tatashin 	}
88*89dd1421SPasha Tatashin 
89*89dd1421SPasha Tatashin 	err = kexec_file_load(kernel_fd, initrd_fd, strlen(cmdline) + 1,
90*89dd1421SPasha Tatashin 			      cmdline, 0);
91*89dd1421SPasha Tatashin 
92*89dd1421SPasha Tatashin 	close(initrd_fd);
93*89dd1421SPasha Tatashin 	close(kernel_fd);
94*89dd1421SPasha Tatashin 
95*89dd1421SPasha Tatashin 	return err;
96*89dd1421SPasha Tatashin }
97*89dd1421SPasha Tatashin 
98*89dd1421SPasha Tatashin static int run_test(int stage)
99*89dd1421SPasha Tatashin {
100*89dd1421SPasha Tatashin 	char stage_arg[32];
101*89dd1421SPasha Tatashin 	int status;
102*89dd1421SPasha Tatashin 	pid_t pid;
103*89dd1421SPasha Tatashin 
104*89dd1421SPasha Tatashin 	snprintf(stage_arg, sizeof(stage_arg), "%d", stage);
105*89dd1421SPasha Tatashin 
106*89dd1421SPasha Tatashin 	pid = fork();
107*89dd1421SPasha Tatashin 	if (pid < 0)
108*89dd1421SPasha Tatashin 		return -1;
109*89dd1421SPasha Tatashin 
110*89dd1421SPasha Tatashin 	if (!pid) {
111*89dd1421SPasha Tatashin 		char *const argv[] = {TEST_BINARY, "-s", stage_arg, NULL};
112*89dd1421SPasha Tatashin 
113*89dd1421SPasha Tatashin 		execve(TEST_BINARY, argv, NULL);
114*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: execve failed\n");
115*89dd1421SPasha Tatashin 		_exit(1);
116*89dd1421SPasha Tatashin 	}
117*89dd1421SPasha Tatashin 
118*89dd1421SPasha Tatashin 	waitpid(pid, &status, 0);
119*89dd1421SPasha Tatashin 
120*89dd1421SPasha Tatashin 	return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : -1;
121*89dd1421SPasha Tatashin }
122*89dd1421SPasha Tatashin 
123*89dd1421SPasha Tatashin static int get_current_stage(void)
124*89dd1421SPasha Tatashin {
125*89dd1421SPasha Tatashin 	char cmdline[COMMAND_LINE_SIZE];
126*89dd1421SPasha Tatashin 	ssize_t len;
127*89dd1421SPasha Tatashin 	int fd;
128*89dd1421SPasha Tatashin 
129*89dd1421SPasha Tatashin 	fd = open("/proc/cmdline", O_RDONLY);
130*89dd1421SPasha Tatashin 	if (fd < 0)
131*89dd1421SPasha Tatashin 		return -1;
132*89dd1421SPasha Tatashin 
133*89dd1421SPasha Tatashin 	len = read(fd, cmdline, sizeof(cmdline) - 1);
134*89dd1421SPasha Tatashin 	close(fd);
135*89dd1421SPasha Tatashin 
136*89dd1421SPasha Tatashin 	if (len < 0)
137*89dd1421SPasha Tatashin 		return -1;
138*89dd1421SPasha Tatashin 
139*89dd1421SPasha Tatashin 	cmdline[len] = 0;
140*89dd1421SPasha Tatashin 
141*89dd1421SPasha Tatashin 	return strstr(cmdline, "luo_stage=2") ? 2 : 1;
142*89dd1421SPasha Tatashin }
143*89dd1421SPasha Tatashin 
144*89dd1421SPasha Tatashin int main(int argc, char *argv[])
145*89dd1421SPasha Tatashin {
146*89dd1421SPasha Tatashin 	int current_stage;
147*89dd1421SPasha Tatashin 	int err;
148*89dd1421SPasha Tatashin 
149*89dd1421SPasha Tatashin 	if (mount_filesystems())
150*89dd1421SPasha Tatashin 		goto err_reboot;
151*89dd1421SPasha Tatashin 
152*89dd1421SPasha Tatashin 	current_stage = get_current_stage();
153*89dd1421SPasha Tatashin 	if (current_stage < 0) {
154*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: Failed to read cmdline");
155*89dd1421SPasha Tatashin 		goto err_reboot;
156*89dd1421SPasha Tatashin 	}
157*89dd1421SPasha Tatashin 
158*89dd1421SPasha Tatashin 	printf("INIT: Starting Stage %d\n", current_stage);
159*89dd1421SPasha Tatashin 
160*89dd1421SPasha Tatashin 	if (current_stage == 1 && kexec_load()) {
161*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: Failed to load kexec kernel\n");
162*89dd1421SPasha Tatashin 		goto err_reboot;
163*89dd1421SPasha Tatashin 	}
164*89dd1421SPasha Tatashin 
165*89dd1421SPasha Tatashin 	if (run_test(current_stage)) {
166*89dd1421SPasha Tatashin 		fprintf(stderr, "INIT: Test binary returned failure\n");
167*89dd1421SPasha Tatashin 		goto err_reboot;
168*89dd1421SPasha Tatashin 	}
169*89dd1421SPasha Tatashin 
170*89dd1421SPasha Tatashin 	printf("INIT: Stage %d completed successfully.\n", current_stage);
171*89dd1421SPasha Tatashin 	reboot(current_stage == 1 ? RB_KEXEC : RB_AUTOBOOT);
172*89dd1421SPasha Tatashin 
173*89dd1421SPasha Tatashin 	return 0;
174*89dd1421SPasha Tatashin 
175*89dd1421SPasha Tatashin err_reboot:
176*89dd1421SPasha Tatashin 	reboot(RB_AUTOBOOT);
177*89dd1421SPasha Tatashin 
178*89dd1421SPasha Tatashin 	return -1;
179*89dd1421SPasha Tatashin }
180