]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/loader/linux.c
keep up with 1.0.67 (#1464)
[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 grub_dprintf ("linux", "Creating directory %s, %s\n", name, ce);
132 ptr = make_header (ptr, name, ce - name,
133 040777, 0);
134 }
135 size += ALIGN_UP ((ce - (char *) name)
136 + sizeof (struct newc_head), 4);
137 *head = n;
138 cur = n;
139 }
140 root = &cur->next;
141 }
142 return size;
143 }
144
145 grub_err_t
146 grub_initrd_init (int argc, char *argv[],
147 struct grub_linux_initrd_context *initrd_ctx)
148 {
149 int i;
150 int newc = 0;
151 struct dir *root = 0;
152
153 initrd_ctx->nfiles = 0;
154 initrd_ctx->components = 0;
155
156 initrd_ctx->components = grub_zalloc (argc
157 * sizeof (initrd_ctx->components[0]));
158 if (!initrd_ctx->components)
159 return grub_errno;
160
161 initrd_ctx->size = 0;
162
163 for (i = 0; i < argc; i++)
164 {
165 const char *fname = argv[i];
166
167 initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
168
169 if (grub_memcmp (argv[i], "newc:", 5) == 0)
170 {
171 const char *ptr, *eptr;
172 ptr = argv[i] + 5;
173 while (*ptr == '/')
174 ptr++;
175 eptr = grub_strchr (ptr, ':');
176 if (eptr)
177 {
178 initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr);
179 if (!initrd_ctx->components[i].newc_name)
180 {
181 grub_initrd_close (initrd_ctx);
182 return grub_errno;
183 }
184 initrd_ctx->size
185 += ALIGN_UP (sizeof (struct newc_head)
186 + grub_strlen (initrd_ctx->components[i].newc_name),
187 4);
188 initrd_ctx->size += insert_dir (initrd_ctx->components[i].newc_name,
189 &root, 0);
190 newc = 1;
191 fname = eptr + 1;
192 }
193 }
194 else if (newc)
195 {
196 initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
197 + sizeof ("TRAILER!!!") - 1, 4);
198 free_dir (root);
199 root = 0;
200 newc = 0;
201 }
202 initrd_ctx->components[i].file = grub_file_open (fname,
203 GRUB_FILE_TYPE_LINUX_INITRD
204 | GRUB_FILE_TYPE_NO_DECOMPRESS);
205 if (!initrd_ctx->components[i].file)
206 {
207 grub_initrd_close (initrd_ctx);
208 return grub_errno;
209 }
210 initrd_ctx->nfiles++;
211 initrd_ctx->components[i].size
212 = grub_file_size (initrd_ctx->components[i].file);
213 initrd_ctx->size += initrd_ctx->components[i].size;
214 }
215
216 if (newc)
217 {
218 initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
219 initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
220 + sizeof ("TRAILER!!!") - 1, 4);
221 free_dir (root);
222 root = 0;
223 }
224
225 return GRUB_ERR_NONE;
226 }
227
228 grub_size_t
229 grub_get_initrd_size (struct grub_linux_initrd_context *initrd_ctx)
230 {
231 return initrd_ctx->size;
232 }
233
234 void
235 grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx)
236 {
237 int i;
238 if (!initrd_ctx->components)
239 return;
240 for (i = 0; i < initrd_ctx->nfiles; i++)
241 {
242 grub_free (initrd_ctx->components[i].newc_name);
243 grub_file_close (initrd_ctx->components[i].file);
244 }
245 grub_free (initrd_ctx->components);
246 initrd_ctx->components = 0;
247 }
248
249 extern int ventoy_need_prompt_load_file(void);
250 extern grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size);
251 grub_err_t
252 grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
253 char *argv[], void *target)
254 {
255 grub_uint8_t *ptr = target;
256 int i;
257 int newc = 0;
258 struct dir *root = 0;
259 grub_ssize_t cursize = 0;
260 grub_ssize_t readsize = 0;
261
262 for (i = 0; i < initrd_ctx->nfiles; i++)
263 {
264 grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
265 ptr += ALIGN_UP_OVERHEAD (cursize, 4);
266
267 if (initrd_ctx->components[i].newc_name)
268 {
269 ptr += insert_dir (initrd_ctx->components[i].newc_name,
270 &root, ptr);
271 ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
272 grub_strlen (initrd_ctx->components[i].newc_name),
273 0100777,
274 initrd_ctx->components[i].size);
275 newc = 1;
276 }
277 else if (newc)
278 {
279 ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1,
280 0, 0);
281 free_dir (root);
282 root = 0;
283 newc = 0;
284 }
285
286 cursize = initrd_ctx->components[i].size;
287 if (ventoy_need_prompt_load_file() && initrd_ctx->components[i].newc_name &&
288 grub_strcmp(initrd_ctx->components[i].newc_name, "boot.wim") == 0)
289 {
290 readsize = ventoy_load_file_with_prompt(initrd_ctx->components[i].file, ptr, cursize);
291 }
292 else
293 {
294 readsize = grub_file_read (initrd_ctx->components[i].file, ptr, cursize);
295 }
296
297 if (readsize != cursize)
298 {
299 if (!grub_errno)
300 grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
301 argv[i]);
302 grub_initrd_close (initrd_ctx);
303 return grub_errno;
304 }
305 ptr += cursize;
306 }
307 if (newc)
308 {
309 grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
310 ptr += ALIGN_UP_OVERHEAD (cursize, 4);
311 ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1, 0, 0);
312 }
313 free_dir (root);
314 root = 0;
315 return GRUB_ERR_NONE;
316 }