]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/loader/linux.c
1.1.07 release
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / loader / linux.c
1 #include <grub/types.h>
2 #include <grub/err.h>
3 #include <grub/linux.h>
4 #include <grub/misc.h>
5 #include <grub/file.h>
6 #include <grub/mm.h>
7 #include <grub/env.h>
8 #include <grub/term.h>
9
10 struct newc_head
11 {
12 char magic[6];
13 char ino[8];
14 char mode[8];
15 char uid[8];
16 char gid[8];
17 char nlink[8];
18 char mtime[8];
19 char filesize[8];
20 char devmajor[8];
21 char devminor[8];
22 char rdevmajor[8];
23 char rdevminor[8];
24 char namesize[8];
25 char check[8];
26 } GRUB_PACKED;
27
28 struct grub_linux_initrd_component
29 {
30 grub_file_t file;
31 char *newc_name;
32 grub_off_t size;
33 };
34
35 struct dir
36 {
37 char *name;
38 struct dir *next;
39 struct dir *child;
40 };
41
42 static char
43 hex (grub_uint8_t val)
44 {
45 if (val < 10)
46 return '0' + val;
47 return 'a' + val - 10;
48 }
49
50 static void
51 set_field (char *var, grub_uint32_t val)
52 {
53 int i;
54 char *ptr = var;
55 for (i = 28; i >= 0; i -= 4)
56 *ptr++ = hex((val >> i) & 0xf);
57 }
58
59 static grub_uint8_t *
60 make_header (grub_uint8_t *ptr,
61 const char *name, grub_size_t len,
62 grub_uint32_t mode,
63 grub_off_t fsize)
64 {
65 struct newc_head *head = (struct newc_head *) ptr;
66 grub_uint8_t *optr;
67 grub_size_t oh = 0;
68 grub_memcpy (head->magic, "070701", 6);
69 set_field (head->ino, 0);
70 set_field (head->mode, mode);
71 set_field (head->uid, 0);
72 set_field (head->gid, 0);
73 set_field (head->nlink, 1);
74 set_field (head->mtime, 0);
75 set_field (head->filesize, fsize);
76 set_field (head->devmajor, 0);
77 set_field (head->devminor, 0);
78 set_field (head->rdevmajor, 0);
79 set_field (head->rdevminor, 0);
80 set_field (head->namesize, len);
81 set_field (head->check, 0);
82 optr = ptr;
83 ptr += sizeof (struct newc_head);
84 grub_memcpy (ptr, name, len);
85 ptr += len;
86 oh = ALIGN_UP_OVERHEAD (ptr - optr, 4);
87 grub_memset (ptr, 0, oh);
88 ptr += oh;
89 return ptr;
90 }
91
92 static void
93 free_dir (struct dir *root)
94 {
95 if (!root)
96 return;
97 free_dir (root->next);
98 free_dir (root->child);
99 grub_free (root->name);
100 grub_free (root);
101 }
102
103 static grub_size_t
104 insert_dir (const char *name, struct dir **root,
105 grub_uint8_t *ptr)
106 {
107 struct dir *cur, **head = root;
108 const char *cb, *ce = name;
109 grub_size_t size = 0;
110 while (1)
111 {
112 for (cb = ce; *cb == '/'; cb++);
113 for (ce = cb; *ce && *ce != '/'; ce++);
114 if (!*ce)
115 break;
116
117 for (cur = *root; cur; cur = cur->next)
118 if (grub_memcmp (cur->name, cb, ce - cb)
119 && cur->name[ce - cb] == 0)
120 break;
121 if (!cur)
122 {
123 struct dir *n;
124 n = grub_zalloc (sizeof (*n));
125 if (!n)
126 return 0;
127 n->next = *head;
128 n->name = grub_strndup (cb, ce - cb);
129 if (ptr)
130 {
131 /*
132 * Create the substring with the trailing NUL byte
133 * to be included in the cpio header.
134 */
135 char *tmp_name = grub_strndup (name, ce - name);
136 if (!tmp_name) {
137 grub_free (n->name);
138 grub_free (n);
139 return grub_errno;
140 }
141 grub_dprintf ("linux", "Creating directory %s, %s\n", name, ce);
142 ptr = make_header (ptr, tmp_name, ce - name + 1,
143 040777, 0);
144 grub_free (tmp_name);
145 }
146 size += ALIGN_UP ((ce - (char *) name + 1)
147 + sizeof (struct newc_head), 4);
148 *head = n;
149 cur = n;
150 }
151 root = &cur->next;
152 }
153 return size;
154 }
155
156 grub_err_t
157 grub_initrd_init (int argc, char *argv[],
158 struct grub_linux_initrd_context *initrd_ctx)
159 {
160 int i;
161 int newc = 0;
162 struct dir *root = 0;
163
164 initrd_ctx->nfiles = 0;
165 initrd_ctx->components = 0;
166
167 initrd_ctx->components = grub_zalloc (argc
168 * sizeof (initrd_ctx->components[0]));
169 if (!initrd_ctx->components)
170 return grub_errno;
171
172 initrd_ctx->size = 0;
173
174 for (i = 0; i < argc; i++)
175 {
176 const char *fname = argv[i];
177
178 initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
179
180 if (grub_memcmp (argv[i], "newc:", 5) == 0)
181 {
182 const char *ptr, *eptr;
183 ptr = argv[i] + 5;
184 while (*ptr == '/')
185 ptr++;
186 eptr = grub_strchr (ptr, ':');
187 if (eptr)
188 {
189 initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr);
190 if (!initrd_ctx->components[i].newc_name)
191 {
192 grub_initrd_close (initrd_ctx);
193 return grub_errno;
194 }
195 initrd_ctx->size
196 += ALIGN_UP (sizeof (struct newc_head)
197 + grub_strlen (initrd_ctx->components[i].newc_name) + 1,
198 4);
199 initrd_ctx->size += insert_dir (initrd_ctx->components[i].newc_name,
200 &root, 0);
201 newc = 1;
202 fname = eptr + 1;
203 }
204 }
205 else if (newc)
206 {
207 initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
208 + sizeof ("TRAILER!!!"), 4);
209 free_dir (root);
210 root = 0;
211 newc = 0;
212 }
213 initrd_ctx->components[i].file = grub_file_open (fname,
214 GRUB_FILE_TYPE_LINUX_INITRD
215 | GRUB_FILE_TYPE_NO_DECOMPRESS);
216 if (!initrd_ctx->components[i].file)
217 {
218 grub_initrd_close (initrd_ctx);
219 return grub_errno;
220 }
221 initrd_ctx->nfiles++;
222 initrd_ctx->components[i].size
223 = grub_file_size (initrd_ctx->components[i].file);
224 initrd_ctx->size += initrd_ctx->components[i].size;
225 }
226
227 if (newc)
228 {
229 initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
230 initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
231 + sizeof ("TRAILER!!!"), 4);
232 free_dir (root);
233 root = 0;
234 }
235
236 return GRUB_ERR_NONE;
237 }
238
239 grub_size_t
240 grub_get_initrd_size (struct grub_linux_initrd_context *initrd_ctx)
241 {
242 return initrd_ctx->size;
243 }
244
245 void
246 grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx)
247 {
248 int i;
249 if (!initrd_ctx->components)
250 return;
251 for (i = 0; i < initrd_ctx->nfiles; i++)
252 {
253 grub_free (initrd_ctx->components[i].newc_name);
254 grub_file_close (initrd_ctx->components[i].file);
255 }
256 grub_free (initrd_ctx->components);
257 initrd_ctx->components = 0;
258 }
259
260 extern int ventoy_need_prompt_load_file(void);
261 extern grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size);
262 grub_err_t
263 grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
264 char *argv[], void *target)
265 {
266 grub_uint8_t *ptr = target;
267 int i;
268 int newc = 0;
269 struct dir *root = 0;
270 grub_ssize_t cursize = 0;
271 grub_ssize_t readsize = 0;
272
273 for (i = 0; i < initrd_ctx->nfiles; i++)
274 {
275 grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
276 ptr += ALIGN_UP_OVERHEAD (cursize, 4);
277
278 if (initrd_ctx->components[i].newc_name)
279 {
280 ptr += insert_dir (initrd_ctx->components[i].newc_name,
281 &root, ptr);
282 ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
283 grub_strlen (initrd_ctx->components[i].newc_name) + 1,
284 0100777,
285 initrd_ctx->components[i].size);
286 newc = 1;
287 }
288 else if (newc)
289 {
290 ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"),
291 0, 0);
292 free_dir (root);
293 root = 0;
294 newc = 0;
295 }
296
297 cursize = initrd_ctx->components[i].size;
298 if (ventoy_need_prompt_load_file() && initrd_ctx->components[i].newc_name &&
299 grub_strcmp(initrd_ctx->components[i].newc_name, "boot.wim") == 0)
300 {
301 readsize = ventoy_load_file_with_prompt(initrd_ctx->components[i].file, ptr, cursize);
302 }
303 else
304 {
305 readsize = grub_file_read (initrd_ctx->components[i].file, ptr, cursize);
306 }
307
308 if (readsize != cursize)
309 {
310 if (!grub_errno)
311 grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
312 argv[i]);
313 grub_initrd_close (initrd_ctx);
314 return grub_errno;
315 }
316 ptr += cursize;
317 }
318 if (newc)
319 {
320 grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
321 ptr += ALIGN_UP_OVERHEAD (cursize, 4);
322 ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"), 0, 0);
323 }
324 free_dir (root);
325 root = 0;
326 return GRUB_ERR_NONE;
327 }