1515 * You should have received a copy of the GNU General Public License
1616 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
1717 */
18-
1918#include <grub/loader.h>
2019#include <grub/dl.h>
2120#include <grub/command.h>
@@ -33,6 +32,196 @@ static char *kernel_path;
3332static char * initrd_path ;
3433static char * boot_cmdline ;
3534
35+ static grub_err_t
36+ grub_switch_root (void )
37+ {
38+ char * tmp = NULL ;
39+ char * options_cmd = NULL ;
40+ char * options = NULL ;
41+ char * subvol = NULL ;
42+ char * root_uuid = NULL ;
43+ char * kernel_release = NULL ;
44+ grub_err_t rc = GRUB_ERR_NONE ;
45+ const char * subvol_param = "subvol=" ;
46+ const char * kernel_release_prefix = "/boot/vmlinuz-" ;
47+ const char * root_prefix = "root=" ;
48+ const char * systemctl [] = {"systemctl" , "--force" , "switch-root" , "/sysroot" , NULL };
49+ const char * mountrootfs [] = {"mount" , root_uuid , "/sysroot" , options_cmd , options , NULL };
50+ const char * unamer [] = {"uname" , "-r" , NULL };
51+ char * uname_buf = NULL ;
52+ int i = 0 ;
53+
54+ /* Extract the kernel release tag from kernel_path */
55+ if (!kernel_path )
56+ {
57+ rc = GRUB_ERR_BAD_ARGUMENT ;
58+ grub_dprintf ("linux" , "switch_root: No kernel_path found\n" );
59+ goto out ;
60+ }
61+
62+ if ((kernel_release = grub_xasprintf ("%s" , (kernel_path + grub_strlen (kernel_release_prefix )))) == NULL )
63+ {
64+ grub_dprintf ("linux" , "switch_root: Failed to allocate memory\n" );
65+ rc = GRUB_ERR_BAD_ARGUMENT ;
66+ goto out ;
67+ }
68+
69+
70+ /* Check for kernel mismatch */
71+ /* Retrieve the current kernel relase tag */
72+ grub_util_exec_redirect (unamer , NULL , "/tmp/version" );
73+
74+ grub_file_t f = grub_file_open ("/tmp/version" , GRUB_FILE_TYPE_FS_SEARCH );
75+
76+ if (f == NULL )
77+ {
78+ grub_dprintf ("linux" , "failed opening file.\n" );
79+ rc = GRUB_ERR_FILE_NOT_FOUND ;
80+ goto out ;
81+ }
82+
83+ if ((uname_buf = grub_malloc (f -> size )) == NULL )
84+ {
85+ grub_dprintf ("linux" , "switch_root: Failed to allocate memory\n" );
86+ rc = GRUB_ERR_OUT_OF_MEMORY ;
87+ goto out ;
88+ }
89+
90+ if (grub_file_read (f , uname_buf , f -> size ) < 0 )
91+ {
92+ grub_dprintf ("linux" , "switch_root: failed to read from file\n" );
93+ rc = GRUB_ERR_FILE_READ_ERROR ;
94+ goto out ;
95+ }
96+
97+ grub_file_close (f );
98+
99+ if (grub_strstr (uname_buf , kernel_release ) == NULL )
100+ {
101+ grub_dprintf ("linux" , "switch_root: kernel mismatch, not performing switch-root ...\n" );
102+ rc = GRUB_ERR_NO_KERNEL ;
103+ goto out ;
104+ }
105+
106+ /* Extract the root partition from boot_cmdline */
107+ if (!boot_cmdline )
108+ {
109+ rc = GRUB_ERR_BAD_ARGUMENT ;
110+ goto out ;
111+ }
112+
113+ tmp = grub_strdup (boot_cmdline );
114+
115+ if (tmp == NULL )
116+ {
117+ rc = GRUB_ERR_OUT_OF_MEMORY ;
118+ goto out ;
119+ }
120+
121+ if ((root_uuid = grub_strstr (tmp , root_prefix )) == NULL )
122+ {
123+ rc = GRUB_ERR_BAD_ARGUMENT ;
124+ grub_dprintf ("linux" , "switch_root: Can't find rootfs\n" );
125+ goto out ;
126+ }
127+
128+ root_uuid += grub_strlen (root_prefix );
129+
130+ while (root_uuid [i ] != ' ' && root_uuid [i ] != '\0' )
131+ i ++ ;
132+
133+ root_uuid [i ] = '\0' ;
134+
135+ /* Allocate a new buffer holding root_uuid */
136+ root_uuid = grub_xasprintf ("%s" , root_uuid );
137+
138+ if (root_uuid == NULL )
139+ {
140+ grub_dprintf ("linux" , "switch_root: Failed to allocated memory\n" );
141+ rc = GRUB_ERR_OUT_OF_MEMORY ;
142+ goto out ;
143+ }
144+
145+ /* Check for subvol parameter */
146+ grub_strcpy (tmp , boot_cmdline );
147+
148+ if ((subvol = grub_strstr (tmp , subvol_param )) != NULL )
149+ {
150+ i = 0 ;
151+
152+ while (subvol [i ] != ' ' && subvol [i ] != '\0' )
153+ i ++ ;
154+
155+ subvol [i ] = '\0' ;
156+
157+ /* Allocate a new buffer holding subvol */
158+ subvol = grub_xasprintf ("%s" , subvol );
159+
160+ if (subvol == NULL )
161+ {
162+ grub_dprintf ("linux" , "switch_root: Failed to allocated memory\n" );
163+ rc = GRUB_ERR_OUT_OF_MEMORY ;
164+ goto out ;
165+ }
166+
167+ options_cmd = grub_xasprintf ("%s" , "-o" );
168+ options = grub_xasprintf ("%s" , subvol );
169+ }
170+
171+ if (options == NULL )
172+ {
173+ mountrootfs [3 ] = NULL ;
174+ }
175+ else
176+ {
177+ mountrootfs [3 ] = options_cmd ;
178+ mountrootfs [4 ] = options ;
179+ }
180+
181+ mountrootfs [1 ] = root_uuid ;
182+
183+ grub_dprintf ("linux" , "Executing:\n" );
184+ grub_dprintf ("linux" , "%s %s %s %s %s\n" , mountrootfs [0 ], mountrootfs [1 ],
185+ mountrootfs [2 ], mountrootfs [3 ], mountrootfs [4 ]);
186+
187+ /* Mount the rootfs */
188+ rc = grub_util_exec (mountrootfs );
189+
190+ if (rc != GRUB_ERR_NONE )
191+ {
192+ grub_dprintf ("linux" , "switch_root: Failed.\n" );
193+ rc = GRUB_ERR_INVALID_COMMAND ;
194+ goto out ;
195+ }
196+
197+ grub_dprintf ("linux" , "Done.\n" );
198+
199+ grub_dprintf ("linux" , "%s %s %s %s\n" , systemctl [0 ], systemctl [1 ],
200+ systemctl [2 ], systemctl [3 ]);
201+
202+ /* Switch root */
203+ rc = grub_util_exec (systemctl );
204+
205+ if (rc != GRUB_ERR_NONE )
206+ {
207+ grub_dprintf ("linux" , "switch_root: Failed.\n" );
208+ rc = GRUB_ERR_INVALID_COMMAND ;
209+ goto out ;
210+ }
211+
212+ grub_dprintf ("linux" , "Done.\n" );
213+
214+ out :
215+ grub_free (tmp );
216+ grub_free (options_cmd );
217+ grub_free (options );
218+ grub_free (subvol );
219+ grub_free (root_uuid );
220+ grub_free (uname_buf );
221+ grub_free (kernel_release );
222+ return rc ;
223+ }
224+
36225static grub_err_t
37226grub_linux_boot (void )
38227{
@@ -51,12 +240,20 @@ grub_linux_boot (void)
51240 else
52241 initrd_param = grub_xasprintf ("%s" , "" );
53242
54- grub_dprintf ("linux" , "%serforming 'kexec -la %s %s %s'\n" ,
55- (kexecute ) ? "P" : "Not p" ,
56- kernel_path , initrd_param , boot_cmdline );
243+ if (grub_util_get_switch_root () == 1 )
244+ {
245+ rc = grub_switch_root ();
246+ if (rc != GRUB_ERR_NONE )
247+ grub_fatal (N_ ("Failed to execute switch_root\n" ));
248+ }
249+ else if (kexecute )
250+ {
251+ grub_dprintf ("linux" , "%serforming 'kexec -la %s %s %s'\n" ,
252+ (kexecute ) ? "P" : "Not p" ,
253+ kernel_path , initrd_param , boot_cmdline );
57254
58- if ( kexecute )
59- rc = grub_util_exec ( kexec );
255+ rc = grub_util_exec ( kexec );
256+ }
60257
61258 grub_free (initrd_param );
62259
0 commit comments