]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - LinuxGUI/Ventoy2Disk/Web/ventoy_http.c
Set hidden attribute for VTOYEFI part in GPT partition style
[Ventoy.git] / LinuxGUI / Ventoy2Disk / Web / ventoy_http.c
1 /******************************************************************************
2 * ventoy_http.c ---- ventoy http
3 * Copyright (c) 2021, longpanda <admin@ventoy.net>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/mount.h>
33 #include <linux/fs.h>
34 #include <dirent.h>
35 #include <pthread.h>
36 #include <ventoy_define.h>
37 #include <ventoy_json.h>
38 #include <ventoy_util.h>
39 #include <ventoy_disk.h>
40 #include <ventoy_http.h>
41 #include "fat_filelib.h"
42
43 static pthread_mutex_t g_api_mutex;
44 static char g_cur_language[128];
45 static int g_cur_part_style = 0;
46 static char g_cur_server_token[64];
47 static struct mg_context *g_ventoy_http_ctx = NULL;
48
49 static uint32_t g_efi_part_offset = 0;
50 static uint8_t *g_efi_part_raw_img = NULL;
51 static uint8_t *g_grub_stg1_raw_img = NULL;
52
53 static char g_cur_process_diskname[64];
54 static char g_cur_process_type[64];
55 static int g_cur_process_result = 0;
56 static PROGRESS_POINT g_current_progress = PT_FINISH;
57
58 static int ventoy_load_mbr_template(void)
59 {
60 FILE *fp = NULL;
61
62 fp = fopen("boot/boot.img", "rb");
63 if (fp == NULL)
64 {
65 vlog("Failed to open file boot/boot.img\n");
66 return 1;
67 }
68
69 fread(g_mbr_template, 1, 512, fp);
70 fclose(fp);
71
72 ventoy_gen_preudo_uuid(g_mbr_template + 0x180);
73 return 0;
74 }
75
76 static int ventoy_disk_xz_flush(void *src, unsigned int size)
77 {
78 memcpy(g_efi_part_raw_img + g_efi_part_offset, src, size);
79 g_efi_part_offset += size;
80
81 g_current_progress = PT_LOAD_DISK_IMG + (g_efi_part_offset / SIZE_1MB);
82 return (int)size;
83 }
84
85 static int ventoy_unxz_efipart_img(void)
86 {
87 int rc;
88 int inlen;
89 int xzlen;
90 void *xzbuf = NULL;
91 uint8_t *buf = NULL;
92
93 rc = ventoy_read_file_to_buf(VENTOY_FILE_DISK_IMG, 0, &xzbuf, &xzlen);
94 vdebug("read disk.img.xz rc:%d len:%d\n", rc, xzlen);
95
96 if (g_efi_part_raw_img)
97 {
98 buf = g_efi_part_raw_img;
99 }
100 else
101 {
102 buf = malloc(VTOYEFI_PART_BYTES);
103 if (!buf)
104 {
105 check_free(xzbuf);
106 return 1;
107 }
108 }
109
110 g_efi_part_offset = 0;
111 g_efi_part_raw_img = buf;
112
113 rc = unxz(xzbuf, xzlen, NULL, ventoy_disk_xz_flush, buf, &inlen, NULL);
114 vdebug("ventoy_unxz_efipart_img len:%d rc:%d unxzlen:%u\n", inlen, rc, g_efi_part_offset);
115
116 check_free(xzbuf);
117 return 0;
118 }
119
120 static int ventoy_unxz_stg1_img(void)
121 {
122 int rc;
123 int inlen;
124 int xzlen;
125 void *xzbuf = NULL;
126 uint8_t *buf = NULL;
127
128 rc = ventoy_read_file_to_buf(VENTOY_FILE_STG1_IMG, 0, &xzbuf, &xzlen);
129 vdebug("read core.img.xz rc:%d len:%d\n", rc, xzlen);
130
131 if (g_grub_stg1_raw_img)
132 {
133 buf = g_grub_stg1_raw_img;
134 }
135 else
136 {
137 buf = zalloc(SIZE_1MB);
138 if (!buf)
139 {
140 check_free(xzbuf);
141 return 1;
142 }
143 }
144
145 rc = unxz(xzbuf, xzlen, NULL, NULL, buf, &inlen, NULL);
146 vdebug("ventoy_unxz_stg1_img len:%d rc:%d\n", inlen, rc);
147
148 g_grub_stg1_raw_img = buf;
149
150 check_free(xzbuf);
151 return 0;
152 }
153
154
155 static int ventoy_http_save_cfg(void)
156 {
157 FILE *fp;
158
159 fp = fopen("./Ventoy2Disk.ini", "w");
160 if (!fp)
161 {
162 return 0;
163 }
164
165 fprintf(fp, "[Ventoy]\nLanguage=%s\nPartStyle=%d\n", g_cur_language, g_cur_part_style);
166
167 fclose(fp);
168 return 0;
169 }
170
171 static int ventoy_http_load_cfg(void)
172 {
173 int i;
174 int len;
175 char line[256];
176 FILE *fp;
177
178 fp = fopen("./Ventoy2Disk.ini", "r");
179 if (!fp)
180 {
181 return 0;
182 }
183
184 while (fgets(line, sizeof(line), fp))
185 {
186 len = (int)strlen(line);
187 for (i = len - 1; i >= 0; i--)
188 {
189 if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r' || line[i] == '\n')
190 {
191 line[i] = 0;
192 }
193 else
194 {
195 break;
196 }
197 }
198
199 len = (int)strlen("Language=");
200 if (strncmp(line, "Language=", len) == 0)
201 {
202 scnprintf(g_cur_language, "%s", line + len);
203 }
204 else if (strncmp(line, "PartStyle=", strlen("PartStyle=")) == 0)
205 {
206 g_cur_part_style = (int)strtol(line + strlen("PartStyle="), NULL, 10);
207 }
208 }
209
210 fclose(fp);
211 return 0;
212 }
213
214
215 static int ventoy_json_result(struct mg_connection *conn, const char *err)
216 {
217 mg_printf(conn,
218 "HTTP/1.1 200 OK \r\n"
219 "Content-Type: application/json\r\n"
220 "Content-Length: %d\r\n"
221 "\r\n%s",
222 (int)strlen(err), err);
223 return 0;
224 }
225
226 static int ventoy_json_buffer(struct mg_connection *conn, const char *json_buf, int json_len)
227 {
228 mg_printf(conn,
229 "HTTP/1.1 200 OK \r\n"
230 "Content-Type: application/json\r\n"
231 "Content-Length: %d\r\n"
232 "\r\n%s",
233 json_len, json_buf);
234 return 0;
235 }
236
237 static int ventoy_api_sysinfo(struct mg_connection *conn, VTOY_JSON *json)
238 {
239 int busy = 0;
240 int pos = 0;
241 int buflen = 0;
242 char buf[512];
243
244 (void)json;
245
246 busy = (g_current_progress == PT_FINISH) ? 0 : 1;
247
248 buflen = sizeof(buf) - 1;
249 VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
250 VTOY_JSON_FMT_OBJ_BEGIN();
251 VTOY_JSON_FMT_STRN("token", g_cur_server_token);
252 VTOY_JSON_FMT_STRN("language", g_cur_language);
253 VTOY_JSON_FMT_STRN("ventoy_ver", ventoy_get_local_version());
254 VTOY_JSON_FMT_UINT("partstyle", g_cur_part_style);
255 VTOY_JSON_FMT_BOOL("busy", busy);
256 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname);
257 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type);
258 VTOY_JSON_FMT_OBJ_END();
259 VTOY_JSON_FMT_END(pos);
260
261 ventoy_json_buffer(conn, buf, pos);
262 return 0;
263 }
264
265 static int ventoy_api_get_percent(struct mg_connection *conn, VTOY_JSON *json)
266 {
267 int pos = 0;
268 int buflen = 0;
269 int percent = 0;
270 char buf[128];
271
272 (void)json;
273
274 percent = g_current_progress * 100 / PT_FINISH;
275
276 buflen = sizeof(buf) - 1;
277 VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
278 VTOY_JSON_FMT_OBJ_BEGIN();
279 VTOY_JSON_FMT_STRN("result", g_cur_process_result ? "failed" : "success");
280 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname);
281 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type);
282 VTOY_JSON_FMT_UINT("percent", percent);
283 VTOY_JSON_FMT_OBJ_END();
284 VTOY_JSON_FMT_END(pos);
285
286 ventoy_json_buffer(conn, buf, pos);
287 return 0;
288 }
289
290 static int ventoy_api_set_language(struct mg_connection *conn, VTOY_JSON *json)
291 {
292 const char *lang = NULL;
293
294 lang = vtoy_json_get_string_ex(json, "language");
295 if (lang)
296 {
297 scnprintf(g_cur_language, "%s", lang);
298 ventoy_http_save_cfg();
299 }
300
301 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
302 return 0;
303 }
304
305 static int ventoy_api_set_partstyle(struct mg_connection *conn, VTOY_JSON *json)
306 {
307 int ret;
308 int style = 0;
309
310 ret = vtoy_json_get_int(json, "partstyle", &style);
311 if (JSON_SUCCESS == ret)
312 {
313 if ((style == 0) || (style == 1))
314 {
315 g_cur_part_style = style;
316 ventoy_http_save_cfg();
317 }
318 }
319
320 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
321 return 0;
322 }
323
324 static int ventoy_clean_disk(int fd, uint64_t size)
325 {
326 int zerolen;
327 ssize_t len;
328 off_t offset;
329 void *buf = NULL;
330
331 vdebug("ventoy_clean_disk fd:%d size:%llu\n", fd, (_ull)size);
332
333 zerolen = 64 * 1024;
334 buf = zalloc(zerolen);
335 if (!buf)
336 {
337 vlog("failed to alloc clean buffer\n");
338 return 1;
339 }
340
341 offset = lseek(fd, 0, SEEK_SET);
342 len = write(fd, buf, zerolen);
343 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull)offset, (_ll)len, zerolen);
344
345 offset = lseek(fd, size - zerolen, SEEK_SET);
346 len = write(fd, buf, zerolen);
347 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull)offset, (_ll)len, zerolen);
348
349 fsync(fd);
350
351 free(buf);
352 return 0;
353 }
354
355 static int ventoy_write_legacy_grub(int fd, int partstyle)
356 {
357 ssize_t len;
358 off_t offset;
359
360 if (partstyle)
361 {
362 vlog("Write GPT stage1 ...\n");
363
364 offset = lseek(fd, 512 * 34, SEEK_SET);
365
366 g_grub_stg1_raw_img[500] = 35;//update blocklist
367 len = write(fd, g_grub_stg1_raw_img, SIZE_1MB - 512 * 34);
368
369 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull)offset, 512 * 34, (_ull)len, SIZE_1MB - 512 * 34);
370 if (SIZE_1MB - 512 * 34 != len)
371 {
372 vlog("write length error\n");
373 return 1;
374 }
375 }
376 else
377 {
378 vlog("Write MBR stage1 ...\n");
379 offset = lseek(fd, 512, SEEK_SET);
380 len = write(fd, g_grub_stg1_raw_img, SIZE_1MB - 512);
381
382 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull)offset, 512, (_ull)len, SIZE_1MB - 512);
383 if (SIZE_1MB - 512 != len)
384 {
385 vlog("write length error\n");
386 return 1;
387 }
388 }
389
390 return 0;
391 }
392
393 static int VentoyFatMemRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
394 {
395 uint32 i;
396 uint32 offset;
397
398 for (i = 0; i < SectorCount; i++)
399 {
400 offset = (Sector + i) * 512;
401 memcpy(Buffer + i * 512, g_efi_part_raw_img + offset, 512);
402 }
403
404 return 1;
405 }
406
407 static int VentoyFatMemWrite(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
408 {
409 uint32 i;
410 uint32 offset;
411
412 for (i = 0; i < SectorCount; i++)
413 {
414 offset = (Sector + i) * 512;
415 memcpy(g_efi_part_raw_img + offset, Buffer + i * 512, 512);
416 }
417
418 return 1;
419 }
420
421 static int VentoyProcSecureBoot(int SecureBoot)
422 {
423 int rc = 0;
424 int size;
425 char *filebuf = NULL;
426 void *file = NULL;
427
428 vlog("VentoyProcSecureBoot %d ...\n", SecureBoot);
429
430 if (SecureBoot)
431 {
432 vlog("Secure boot is enabled ...\n");
433 return 0;
434 }
435
436 fl_init();
437
438 if (0 == fl_attach_media(VentoyFatMemRead, VentoyFatMemWrite))
439 {
440 file = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
441 vlog("Open ventoy efi file %p \n", file);
442 if (file)
443 {
444 fl_fseek(file, 0, SEEK_END);
445 size = (int)fl_ftell(file);
446 fl_fseek(file, 0, SEEK_SET);
447
448 vlog("ventoy efi file size %d ...\n", size);
449
450 filebuf = (char *)malloc(size);
451 if (filebuf)
452 {
453 fl_fread(filebuf, 1, size, file);
454 }
455
456 fl_fclose(file);
457
458 vlog("Now delete all efi files ...\n");
459 fl_remove("/EFI/BOOT/BOOTX64.EFI");
460 fl_remove("/EFI/BOOT/grubx64.efi");
461 fl_remove("/EFI/BOOT/grubx64_real.efi");
462 fl_remove("/EFI/BOOT/MokManager.efi");
463 fl_remove("/ENROLL_THIS_KEY_IN_MOKMANAGER.cer");
464
465 file = fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");
466 vlog("Open bootx64 efi file %p \n", file);
467 if (file)
468 {
469 if (filebuf)
470 {
471 fl_fwrite(filebuf, 1, size, file);
472 }
473
474 fl_fflush(file);
475 fl_fclose(file);
476 }
477
478 if (filebuf)
479 {
480 free(filebuf);
481 }
482 }
483
484 file = fl_fopen("/EFI/BOOT/grubia32_real.efi", "rb");
485 vlog("Open ventoy efi file %p\n", file);
486 if (file)
487 {
488 fl_fseek(file, 0, SEEK_END);
489 size = (int)fl_ftell(file);
490 fl_fseek(file, 0, SEEK_SET);
491
492 vlog("ventoy efi file size %d ...\n", size);
493
494 filebuf = (char *)malloc(size);
495 if (filebuf)
496 {
497 fl_fread(filebuf, 1, size, file);
498 }
499
500 fl_fclose(file);
501
502 vlog("Now delete all efi files ...\n");
503 fl_remove("/EFI/BOOT/BOOTIA32.EFI");
504 fl_remove("/EFI/BOOT/grubia32.efi");
505 fl_remove("/EFI/BOOT/grubia32_real.efi");
506 fl_remove("/EFI/BOOT/mmia32.efi");
507
508 file = fl_fopen("/EFI/BOOT/BOOTIA32.EFI", "wb");
509 vlog("Open bootia32 efi file %p\n", file);
510 if (file)
511 {
512 if (filebuf)
513 {
514 fl_fwrite(filebuf, 1, size, file);
515 }
516
517 fl_fflush(file);
518 fl_fclose(file);
519 }
520
521 if (filebuf)
522 {
523 free(filebuf);
524 }
525 }
526
527 }
528 else
529 {
530 rc = 1;
531 }
532
533 fl_shutdown();
534
535 return rc;
536 }
537
538 static int ventoy_check_efi_part_data(int fd, uint64_t offset)
539 {
540 int i;
541 ssize_t len;
542 char *buf;
543
544 buf = malloc(SIZE_1MB);
545 if (!buf)
546 {
547 return 0;
548 }
549
550 lseek(fd, offset, SEEK_SET);
551 for (i = 0; i < 32; i++)
552 {
553 len = read(fd, buf, SIZE_1MB);
554 if (len != SIZE_1MB || memcmp(buf, g_efi_part_raw_img + i * SIZE_1MB, SIZE_1MB))
555 {
556 vlog("part2 data check failed i=%d len:%llu\n", i, (_ull)len);
557 return 1;
558 }
559
560 g_current_progress = PT_CHECK_PART2 + (i / 4);
561 }
562
563 return 0;
564 }
565
566 static int ventoy_write_efipart(int fd, uint64_t offset, uint32_t secureboot)
567 {
568 int i;
569 ssize_t len;
570
571 vlog("Formatting part2 EFI offset:%llu ...\n", (_ull)offset);
572 lseek(fd, offset, SEEK_SET);
573
574 VentoyProcSecureBoot((int)secureboot);
575
576 g_current_progress = PT_WRITE_VENTOY_START;
577 for (i = 0; i < 32; i++)
578 {
579 len = write(fd, g_efi_part_raw_img + i * SIZE_1MB, SIZE_1MB);
580 vlog("write disk writelen:%lld datalen:%d [ %s ]\n",
581 (_ll)len, SIZE_1MB, (len == SIZE_1MB) ? "success" : "failed");
582
583 if (len != SIZE_1MB)
584 {
585 vlog("failed to format part2 EFI\n");
586 return 1;
587 }
588
589 g_current_progress = PT_WRITE_VENTOY_START + i / 4;
590 }
591
592 return 0;
593 }
594
595 static int VentoyFillBackupGptHead(VTOY_GPT_INFO *pInfo, VTOY_GPT_HDR *pHead)
596 {
597 uint64_t LBA;
598 uint64_t BackupLBA;
599
600 memcpy(pHead, &pInfo->Head, sizeof(VTOY_GPT_HDR));
601
602 LBA = pHead->EfiStartLBA;
603 BackupLBA = pHead->EfiBackupLBA;
604
605 pHead->EfiStartLBA = BackupLBA;
606 pHead->EfiBackupLBA = LBA;
607 pHead->PartTblStartLBA = BackupLBA + 1 - 33;
608
609 pHead->Crc = 0;
610 pHead->Crc = ventoy_crc32(pHead, pHead->Length);
611
612 return 0;
613 }
614
615 static int ventoy_write_gpt_part_table(int fd, uint64_t disksize, VTOY_GPT_INFO *gpt)
616 {
617 ssize_t len;
618 off_t offset;
619 VTOY_GPT_HDR BackupHead;
620
621 VentoyFillBackupGptHead(gpt, &BackupHead);
622
623 offset = lseek(fd, disksize - 512, SEEK_SET);
624 len = write(fd, &BackupHead, sizeof(VTOY_GPT_HDR));
625 vlog("write backup gpt part table off:%llu len:%llu\n", (_ull)offset, (_ull)len);
626 if (offset != disksize - 512 || len != sizeof(VTOY_GPT_HDR))
627 {
628 return 1;
629 }
630
631 offset = lseek(fd, disksize - 512 * 33, SEEK_SET);
632 len = write(fd, gpt->PartTbl, sizeof(gpt->PartTbl));
633 vlog("write main gpt part table off:%llu len:%llu\n", (_ull)offset, (_ull)len);
634 if (offset != disksize - 512 * 33 || len != sizeof(gpt->PartTbl))
635 {
636 return 1;
637 }
638
639 offset = lseek(fd, 0, SEEK_SET);
640 len = write(fd, gpt, sizeof(VTOY_GPT_INFO));
641 vlog("write gpt part head off:%llu len:%llu\n", (_ull)offset, (_ull)len);
642 if (offset != 0 || len != sizeof(VTOY_GPT_INFO))
643 {
644 return 1;
645 }
646
647 return 0;
648 }
649
650 static void * ventoy_update_thread(void *data)
651 {
652 int fd;
653 ssize_t len;
654 off_t offset;
655 MBR_HEAD MBR;
656 ventoy_disk *disk = NULL;
657 ventoy_thread_data *thread = (ventoy_thread_data *)data;
658
659 vdebug("ventoy_update_thread run ...\n");
660
661 fd = thread->diskfd;
662 disk = thread->disk;
663
664 g_current_progress = PT_PRAPARE_FOR_CLEAN;
665 vdebug("check disk %s\n", disk->disk_name);
666 if (ventoy_is_disk_mounted(disk->disk_path))
667 {
668 vlog("disk is mounted, now try to unmount it ...\n");
669 ventoy_try_umount_disk(disk->disk_path);
670 }
671
672 if (ventoy_is_disk_mounted(disk->disk_path))
673 {
674 vlog("%s is mounted and can't umount!\n", disk->disk_path);
675 goto err;
676 }
677 else
678 {
679 vlog("disk is not mounted now, we can do continue ...\n");
680 }
681
682 g_current_progress = PT_LOAD_CORE_IMG;
683 ventoy_unxz_stg1_img();
684
685 g_current_progress = PT_LOAD_DISK_IMG;
686 ventoy_unxz_efipart_img();
687
688 g_current_progress = PT_FORMAT_PART2;
689
690 vlog("Formatting part2 EFI ...\n");
691 if (0 != ventoy_write_efipart(fd, disk->vtoydata.part2_start_sector * 512, thread->secure_boot))
692 {
693 vlog("Failed to format part2 efi ...\n");
694 goto err;
695 }
696
697 g_current_progress = PT_WRITE_STG1_IMG;
698
699 vlog("Writing legacy grub ...\n");
700 if (0 != ventoy_write_legacy_grub(fd, disk->vtoydata.partition_style))
701 {
702 vlog("ventoy_write_legacy_grub failed ...\n");
703 goto err;
704 }
705
706 offset = lseek(fd, 512 * 2040, SEEK_SET);
707 len = write(fd, disk->vtoydata.rsvdata, sizeof(disk->vtoydata.rsvdata));
708 vlog("Writing reserve data offset:%llu len:%llu ...\n", (_ull)offset, (_ull)len);
709
710 memcpy(&MBR, &(disk->vtoydata.gptinfo.MBR), 512);
711 if (disk->vtoydata.partition_style == 0 && MBR.PartTbl[0].Active == 0)
712 {
713 MBR.PartTbl[0].Active = 0x80;
714 MBR.PartTbl[1].Active = 0;
715 MBR.PartTbl[2].Active = 0;
716 MBR.PartTbl[3].Active = 0;
717
718 offset = lseek(fd, 0, SEEK_SET);
719 len = write(fd, &MBR, 512);
720 vlog("set MBR partition 1 active flag enabled offset:%llu len:%llu\n", (_ull)offset, (_ull)len);
721 }
722
723 g_current_progress = PT_SYNC_DATA1;
724
725 vlog("fsync data1...\n");
726 fsync(fd);
727 vtoy_safe_close_fd(fd);
728
729 g_current_progress = PT_SYNC_DATA2;
730
731 vlog("====================================\n");
732 vlog("====== ventoy update success ======\n");
733 vlog("====================================\n");
734 goto end;
735
736 err:
737 g_cur_process_result = 1;
738 vtoy_safe_close_fd(fd);
739
740 end:
741 g_current_progress = PT_FINISH;
742
743 check_free(thread);
744
745 return NULL;
746 }
747
748 static void * ventoy_install_thread(void *data)
749 {
750 int fd;
751 ssize_t len;
752 off_t offset;
753 MBR_HEAD MBR;
754 ventoy_disk *disk = NULL;
755 VTOY_GPT_INFO *gpt = NULL;
756 ventoy_thread_data *thread = (ventoy_thread_data *)data;
757 uint64_t Part1StartSector = 0;
758 uint64_t Part1SectorCount = 0;
759 uint64_t Part2StartSector = 0;
760
761 vdebug("ventoy_install_thread run ...\n");
762
763 fd = thread->diskfd;
764 disk = thread->disk;
765
766 g_current_progress = PT_PRAPARE_FOR_CLEAN;
767 vdebug("check disk %s\n", disk->disk_name);
768 if (ventoy_is_disk_mounted(disk->disk_path))
769 {
770 vlog("disk is mounted, now try to unmount it ...\n");
771 ventoy_try_umount_disk(disk->disk_path);
772 }
773
774 if (ventoy_is_disk_mounted(disk->disk_path))
775 {
776 vlog("%s is mounted and can't umount!\n", disk->disk_path);
777 goto err;
778 }
779 else
780 {
781 vlog("disk is not mounted now, we can do continue ...\n");
782 }
783
784 g_current_progress = PT_DEL_ALL_PART;
785 ventoy_clean_disk(fd, disk->size_in_byte);
786
787 g_current_progress = PT_LOAD_CORE_IMG;
788 ventoy_unxz_stg1_img();
789
790 g_current_progress = PT_LOAD_DISK_IMG;
791 ventoy_unxz_efipart_img();
792
793 if (thread->partstyle)
794 {
795 vdebug("Fill GPT part table\n");
796 gpt = zalloc(sizeof(VTOY_GPT_INFO));
797 ventoy_fill_gpt(disk->size_in_byte, thread->reserveBytes, thread->align4kb, gpt);
798 Part1StartSector = gpt->PartTbl[0].StartLBA;
799 Part1SectorCount = gpt->PartTbl[0].LastLBA - Part1StartSector + 1;
800 Part2StartSector = gpt->PartTbl[1].StartLBA;
801 }
802 else
803 {
804 vdebug("Fill MBR part table\n");
805 ventoy_fill_mbr(disk->size_in_byte, thread->reserveBytes, thread->align4kb, &MBR);
806 Part1StartSector = MBR.PartTbl[0].StartSectorId;
807 Part1SectorCount = MBR.PartTbl[0].SectorCount;
808 Part2StartSector = MBR.PartTbl[1].StartSectorId;
809 }
810
811 vlog("Part1StartSector:%llu Part1SectorCount:%llu Part2StartSector:%llu\n",
812 (_ull)Part1StartSector, (_ull)Part1SectorCount, (_ull)Part2StartSector);
813
814 if (thread->partstyle != disk->partstyle)
815 {
816 vlog("Wait for format part1 (partstyle changed) ...\n");
817 sleep(1);
818 }
819
820 g_current_progress = PT_FORMAT_PART1;
821 vlog("Formatting part1 exFAT %s ...\n", disk->disk_path);
822 if (0 != mkexfat_main(disk->disk_path, fd, Part1SectorCount))
823 {
824 vlog("Failed to format exfat ...\n");
825 goto err;
826 }
827
828 g_current_progress = PT_FORMAT_PART2;
829 vlog("Formatting part2 EFI ...\n");
830 if (0 != ventoy_write_efipart(fd, Part2StartSector * 512, thread->secure_boot))
831 {
832 vlog("Failed to format part2 efi ...\n");
833 goto err;
834 }
835
836 g_current_progress = PT_WRITE_STG1_IMG;
837 vlog("Writing legacy grub ...\n");
838 if (0 != ventoy_write_legacy_grub(fd, thread->partstyle))
839 {
840 vlog("ventoy_write_legacy_grub failed ...\n");
841 goto err;
842 }
843
844 g_current_progress = PT_SYNC_DATA1;
845 vlog("fsync data1...\n");
846 fsync(fd);
847 vtoy_safe_close_fd(fd);
848
849 /* reopen for check part2 data */
850 vlog("Checking part2 efi data %s ...\n", disk->disk_path);
851 g_current_progress = PT_CHECK_PART2;
852 fd = open(disk->disk_path, O_RDONLY | O_BINARY);
853 if (fd < 0)
854 {
855 vlog("failed to open %s for check fd:%d err:%d\n", disk->disk_path, fd, errno);
856 goto err;
857 }
858
859 if (0 == ventoy_check_efi_part_data(fd, Part2StartSector * 512))
860 {
861 vlog("efi part data check success\n");
862 }
863 else
864 {
865 vlog("efi part data check failed\n");
866 goto err;
867 }
868
869 vtoy_safe_close_fd(fd);
870
871 /* reopen for write part table */
872 g_current_progress = PT_WRITE_PART_TABLE;
873 vlog("Writting Partition Table style:%d...\n", thread->partstyle);
874
875 fd = open(disk->disk_path, O_RDWR | O_BINARY);
876 if (fd < 0)
877 {
878 vlog("failed to open %s for part table fd:%d err:%d\n", disk->disk_path, fd, errno);
879 goto err;
880 }
881
882 if (thread->partstyle)
883 {
884 ventoy_write_gpt_part_table(fd, disk->size_in_byte, gpt);
885 }
886 else
887 {
888 offset = lseek(fd, 0, SEEK_SET);
889 len = write(fd, &MBR, 512);
890 vlog("Writting MBR Partition Table %llu %llu\n", (_ull)offset, (_ull)len);
891 if (offset != 0 || len != 512)
892 {
893 goto err;
894 }
895 }
896
897 g_current_progress = PT_SYNC_DATA2;
898 vlog("fsync data2...\n");
899 fsync(fd);
900 vtoy_safe_close_fd(fd);
901
902
903 vlog("====================================\n");
904 vlog("====== ventoy install success ======\n");
905 vlog("====================================\n");
906 goto end;
907
908 err:
909 g_cur_process_result = 1;
910 vtoy_safe_close_fd(fd);
911
912 end:
913 g_current_progress = PT_FINISH;
914
915 check_free(gpt);
916 check_free(thread);
917
918 return NULL;
919 }
920
921 static int ventoy_api_clean(struct mg_connection *conn, VTOY_JSON *json)
922 {
923 int i = 0;
924 int fd = 0;
925 ventoy_disk *disk = NULL;
926 const char *diskname = NULL;
927 char path[128];
928
929 if (g_current_progress != PT_FINISH)
930 {
931 ventoy_json_result(conn, VTOY_JSON_BUSY_RET);
932 return 0;
933 }
934
935 diskname = vtoy_json_get_string_ex(json, "disk");
936 if (diskname == NULL)
937 {
938 ventoy_json_result(conn, VTOY_JSON_INVALID_RET);
939 return 0;
940 }
941
942 for (i = 0; i < g_disk_num; i++)
943 {
944 if (strcmp(g_disk_list[i].disk_name, diskname) == 0)
945 {
946 disk = g_disk_list + i;
947 break;
948 }
949 }
950
951 if (disk == NULL)
952 {
953 vlog("disk %s not found\n", diskname);
954 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
955 return 0;
956 }
957
958 scnprintf(path, "/sys/block/%s", diskname);
959 if (access(path, F_OK) < 0)
960 {
961 vlog("File %s not exist anymore\n", path);
962 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
963 return 0;
964 }
965
966 vlog("==================================\n");
967 vlog("===== ventoy clean %s =====\n", disk->disk_path);
968 vlog("==================================\n");
969
970 if (ventoy_is_disk_mounted(disk->disk_path))
971 {
972 vlog("disk is mounted, now try to unmount it ...\n");
973 ventoy_try_umount_disk(disk->disk_path);
974 }
975
976 if (ventoy_is_disk_mounted(disk->disk_path))
977 {
978 vlog("%s is mounted and can't umount!\n", disk->disk_path);
979 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
980 return 0;
981 }
982 else
983 {
984 vlog("disk is not mounted now, we can do the clean ...\n");
985 }
986
987 fd = open(disk->disk_path, O_RDWR | O_BINARY);
988 if (fd < 0)
989 {
990 vlog("failed to open %s fd:%d err:%d\n", disk->disk_path, fd, errno);
991 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
992 return 0;
993 }
994
995 vdebug("start clean %s ...\n", disk->disk_model);
996 ventoy_clean_disk(fd, disk->size_in_byte);
997
998 vtoy_safe_close_fd(fd);
999
1000 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1001 return 0;
1002 }
1003
1004 static int ventoy_api_install(struct mg_connection *conn, VTOY_JSON *json)
1005 {
1006 int i = 0;
1007 int ret = 0;
1008 int fd = 0;
1009 uint32_t align4kb = 0;
1010 uint32_t style = 0;
1011 uint32_t secure_boot = 0;
1012 uint64_t reserveBytes = 0;
1013 ventoy_disk *disk = NULL;
1014 const char *diskname = NULL;
1015 const char *reserve_space = NULL;
1016 ventoy_thread_data *thread = NULL;
1017 char path[128];
1018
1019 if (g_current_progress != PT_FINISH)
1020 {
1021 ventoy_json_result(conn, VTOY_JSON_BUSY_RET);
1022 return 0;
1023 }
1024
1025 diskname = vtoy_json_get_string_ex(json, "disk");
1026 reserve_space = vtoy_json_get_string_ex(json, "reserve_space");
1027 ret += vtoy_json_get_uint(json, "partstyle", &style);
1028 ret += vtoy_json_get_uint(json, "secure_boot", &secure_boot);
1029 ret += vtoy_json_get_uint(json, "align_4kb", &align4kb);
1030
1031 if (diskname == NULL || reserve_space == NULL || ret != JSON_SUCCESS)
1032 {
1033 ventoy_json_result(conn, VTOY_JSON_INVALID_RET);
1034 return 0;
1035 }
1036
1037 reserveBytes = (uint64_t)strtoull(reserve_space, NULL, 10);
1038
1039 for (i = 0; i < g_disk_num; i++)
1040 {
1041 if (strcmp(g_disk_list[i].disk_name, diskname) == 0)
1042 {
1043 disk = g_disk_list + i;
1044 break;
1045 }
1046 }
1047
1048 if (disk == NULL)
1049 {
1050 vlog("disk %s not found\n", diskname);
1051 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
1052 return 0;
1053 }
1054
1055 scnprintf(path, "/sys/block/%s", diskname);
1056 if (access(path, F_OK) < 0)
1057 {
1058 vlog("File %s not exist anymore\n", path);
1059 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
1060 return 0;
1061 }
1062
1063 if (disk->size_in_byte > 2199023255552ULL && style == 0)
1064 {
1065 vlog("disk %s is more than 2TB and GPT is needed\n", path);
1066 ventoy_json_result(conn, VTOY_JSON_MBR_2TB_RET);
1067 return 0;
1068 }
1069
1070 if ((reserveBytes + VTOYEFI_PART_BYTES * 2) > disk->size_in_byte)
1071 {
1072 vlog("reserve space %llu is too big for disk %s %llu\n", (_ull)reserveBytes, path, (_ull)disk->size_in_byte);
1073 ventoy_json_result(conn, VTOY_JSON_INVALID_RSV_RET);
1074 return 0;
1075 }
1076
1077 vlog("==================================================================================\n");
1078 vlog("===== ventoy install %s style:%s secureboot:%u align4K:%u reserve:%llu =========\n",
1079 disk->disk_path, (style ? "GPT" : "MBR"), secure_boot, align4kb, (_ull)reserveBytes);
1080 vlog("==================================================================================\n");
1081
1082 if (ventoy_is_disk_mounted(disk->disk_path))
1083 {
1084 vlog("disk is mounted, now try to unmount it ...\n");
1085 ventoy_try_umount_disk(disk->disk_path);
1086 }
1087
1088 if (ventoy_is_disk_mounted(disk->disk_path))
1089 {
1090 vlog("%s is mounted and can't umount!\n", disk->disk_path);
1091 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1092 return 0;
1093 }
1094 else
1095 {
1096 vlog("disk is not mounted now, we can do the install ...\n");
1097 }
1098
1099 fd = open(disk->disk_path, O_RDWR | O_BINARY);
1100 if (fd < 0)
1101 {
1102 vlog("failed to open %s fd:%d err:%d\n", disk->disk_path, fd, errno);
1103 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1104 return 0;
1105 }
1106
1107 vdebug("start install thread %s ...\n", disk->disk_model);
1108 thread = zalloc(sizeof(ventoy_thread_data));
1109 if (!thread)
1110 {
1111 vtoy_safe_close_fd(fd);
1112 vlog("failed to alloc thread data err:%d\n", errno);
1113 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1114 return 0;
1115 }
1116
1117 g_current_progress = PT_START;
1118 g_cur_process_result = 0;
1119 scnprintf(g_cur_process_type, "%s", "install");
1120 scnprintf(g_cur_process_diskname, "%s", disk->disk_name);
1121
1122 thread->disk = disk;
1123 thread->diskfd = fd;
1124 thread->align4kb = align4kb;
1125 thread->partstyle = style;
1126 thread->secure_boot = secure_boot;
1127 thread->reserveBytes = reserveBytes;
1128
1129 mg_start_thread(ventoy_install_thread, thread);
1130
1131 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1132 return 0;
1133 }
1134
1135 static int ventoy_api_update(struct mg_connection *conn, VTOY_JSON *json)
1136 {
1137 int i = 0;
1138 int ret = 0;
1139 int fd = 0;
1140 uint32_t secure_boot = 0;
1141 ventoy_disk *disk = NULL;
1142 const char *diskname = NULL;
1143 ventoy_thread_data *thread = NULL;
1144 char path[128];
1145
1146 if (g_current_progress != PT_FINISH)
1147 {
1148 ventoy_json_result(conn, VTOY_JSON_BUSY_RET);
1149 return 0;
1150 }
1151
1152 diskname = vtoy_json_get_string_ex(json, "disk");
1153 ret += vtoy_json_get_uint(json, "secure_boot", &secure_boot);
1154 if (diskname == NULL || ret != JSON_SUCCESS)
1155 {
1156 ventoy_json_result(conn, VTOY_JSON_INVALID_RET);
1157 return 0;
1158 }
1159
1160 for (i = 0; i < g_disk_num; i++)
1161 {
1162 if (strcmp(g_disk_list[i].disk_name, diskname) == 0)
1163 {
1164 disk = g_disk_list + i;
1165 break;
1166 }
1167 }
1168
1169 if (disk == NULL)
1170 {
1171 vlog("disk %s not found\n", diskname);
1172 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
1173 return 0;
1174 }
1175
1176 if (disk->vtoydata.ventoy_valid == 0)
1177 {
1178 vlog("disk %s is not ventoy disk\n", diskname);
1179 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1180 return 0;
1181 }
1182
1183 scnprintf(path, "/sys/block/%s", diskname);
1184 if (access(path, F_OK) < 0)
1185 {
1186 vlog("File %s not exist anymore\n", path);
1187 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
1188 return 0;
1189 }
1190
1191 vlog("==========================================================\n");
1192 vlog("===== ventoy update %s new_secureboot:%u =========\n", disk->disk_path, secure_boot);
1193 vlog("==========================================================\n");
1194
1195 vlog("%s version:%s partstyle:%u oldsecureboot:%u reserve:%llu\n",
1196 disk->disk_path, disk->vtoydata.ventoy_ver,
1197 disk->vtoydata.partition_style,
1198 disk->vtoydata.secure_boot_flag,
1199 (_ull)(disk->vtoydata.preserved_space)
1200 );
1201
1202 if (ventoy_is_disk_mounted(disk->disk_path))
1203 {
1204 vlog("disk is mounted, now try to unmount it ...\n");
1205 ventoy_try_umount_disk(disk->disk_path);
1206 }
1207
1208 if (ventoy_is_disk_mounted(disk->disk_path))
1209 {
1210 vlog("%s is mounted and can't umount!\n", disk->disk_path);
1211 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1212 return 0;
1213 }
1214 else
1215 {
1216 vlog("disk is not mounted now, we can do the update ...\n");
1217 }
1218
1219 fd = open(disk->disk_path, O_RDWR | O_BINARY);
1220 if (fd < 0)
1221 {
1222 vlog("failed to open %s fd:%d err:%d\n", disk->disk_path, fd, errno);
1223 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1224 return 0;
1225 }
1226
1227 vdebug("start update thread %s ...\n", disk->disk_model);
1228 thread = zalloc(sizeof(ventoy_thread_data));
1229 if (!thread)
1230 {
1231 vtoy_safe_close_fd(fd);
1232 vlog("failed to alloc thread data err:%d\n", errno);
1233 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1234 return 0;
1235 }
1236
1237 g_current_progress = PT_START;
1238 g_cur_process_result = 0;
1239 scnprintf(g_cur_process_type, "%s", "update");
1240 scnprintf(g_cur_process_diskname, "%s", disk->disk_name);
1241
1242 thread->disk = disk;
1243 thread->diskfd = fd;
1244 thread->secure_boot = secure_boot;
1245
1246 mg_start_thread(ventoy_update_thread, thread);
1247
1248 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1249 return 0;
1250 }
1251
1252
1253 static int ventoy_api_refresh_device(struct mg_connection *conn, VTOY_JSON *json)
1254 {
1255 (void)json;
1256
1257 if (g_current_progress == PT_FINISH)
1258 {
1259 g_disk_num = 0;
1260 ventoy_disk_enumerate_all();
1261 }
1262
1263 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1264 return 0;
1265 }
1266
1267 static int ventoy_api_get_dev_list(struct mg_connection *conn, VTOY_JSON *json)
1268 {
1269 int i = 0;
1270 int rc = 0;
1271 int pos = 0;
1272 int buflen = 0;
1273 uint32_t alldev = 0;
1274 char *buf = NULL;
1275 ventoy_disk *cur = NULL;
1276
1277 rc = vtoy_json_get_uint(json, "alldev", &alldev);
1278 if (JSON_SUCCESS != rc)
1279 {
1280 alldev = 0;
1281 }
1282
1283 buflen = g_disk_num * 1024;
1284 buf = (char *)malloc(buflen + 1024);
1285 if (!buf)
1286 {
1287 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1288 return 0;
1289 }
1290
1291 VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
1292 VTOY_JSON_FMT_OBJ_BEGIN();
1293 VTOY_JSON_FMT_KEY("list");
1294 VTOY_JSON_FMT_ARY_BEGIN();
1295
1296 for (i = 0; i < g_disk_num; i++)
1297 {
1298 cur = g_disk_list + i;
1299
1300 if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
1301 {
1302 continue;
1303 }
1304
1305 VTOY_JSON_FMT_OBJ_BEGIN();
1306 VTOY_JSON_FMT_STRN("name", cur->disk_name);
1307 VTOY_JSON_FMT_STRN("model", cur->disk_model);
1308 VTOY_JSON_FMT_STRN("size", cur->human_readable_size);
1309 VTOY_JSON_FMT_UINT("vtoy_valid", cur->vtoydata.ventoy_valid);
1310 VTOY_JSON_FMT_STRN("vtoy_ver", cur->vtoydata.ventoy_ver);
1311 VTOY_JSON_FMT_UINT("vtoy_secure_boot", cur->vtoydata.secure_boot_flag);
1312 VTOY_JSON_FMT_UINT("vtoy_partstyle", cur->vtoydata.partition_style);
1313 VTOY_JSON_FMT_OBJ_ENDEX();
1314 }
1315
1316 VTOY_JSON_FMT_ARY_END();
1317 VTOY_JSON_FMT_OBJ_END();
1318 VTOY_JSON_FMT_END(pos);
1319
1320 ventoy_json_buffer(conn, buf, pos);
1321 return 0;
1322 }
1323
1324 static JSON_CB g_ventoy_json_cb[] =
1325 {
1326 { "sysinfo", ventoy_api_sysinfo },
1327 { "sel_language", ventoy_api_set_language },
1328 { "sel_partstyle", ventoy_api_set_partstyle },
1329 { "refresh_device", ventoy_api_refresh_device },
1330 { "get_dev_list", ventoy_api_get_dev_list },
1331 { "install", ventoy_api_install },
1332 { "update", ventoy_api_update },
1333 { "clean", ventoy_api_clean },
1334 { "get_percent", ventoy_api_get_percent },
1335 };
1336
1337 static int ventoy_json_handler(struct mg_connection *conn, VTOY_JSON *json)
1338 {
1339 int i;
1340 const char *token = NULL;
1341 const char *method = NULL;
1342
1343 method = vtoy_json_get_string_ex(json, "method");
1344 if (!method)
1345 {
1346 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1347 return 0;
1348 }
1349
1350 if (strcmp(method, "sysinfo"))
1351 {
1352 token = vtoy_json_get_string_ex(json, "token");
1353 if (token == NULL || strcmp(token, g_cur_server_token))
1354 {
1355 ventoy_json_result(conn, VTOY_JSON_TOKEN_ERR_RET);
1356 return 0;
1357 }
1358 }
1359
1360 for (i = 0; i < (int)(sizeof(g_ventoy_json_cb) / sizeof(g_ventoy_json_cb[0])); i++)
1361 {
1362 if (strcmp(method, g_ventoy_json_cb[i].method) == 0)
1363 {
1364 g_ventoy_json_cb[i].callback(conn, json);
1365 break;
1366 }
1367 }
1368
1369 return 0;
1370 }
1371
1372 static int ventoy_request_handler(struct mg_connection *conn)
1373 {
1374 int post_data_len;
1375 int post_buf_len;
1376 VTOY_JSON *json = NULL;
1377 char *post_data_buf = NULL;
1378 const struct mg_request_info *ri = NULL;
1379 char stack_buf[512];
1380
1381 ri = mg_get_request_info(conn);
1382
1383 if (strcmp(ri->uri, "/vtoy/json") == 0)
1384 {
1385 if (ri->content_length > 500)
1386 {
1387 post_data_buf = malloc(ri->content_length + 4);
1388 post_buf_len = ri->content_length + 1;
1389 }
1390 else
1391 {
1392 post_data_buf = stack_buf;
1393 post_buf_len = sizeof(stack_buf);
1394 }
1395
1396 post_data_len = mg_read(conn, post_data_buf, post_buf_len);
1397 post_data_buf[post_data_len] = 0;
1398
1399 json = vtoy_json_create();
1400 if (JSON_SUCCESS == vtoy_json_parse(json, post_data_buf))
1401 {
1402 pthread_mutex_lock(&g_api_mutex);
1403 ventoy_json_handler(conn, json->pstChild);
1404 pthread_mutex_unlock(&g_api_mutex);
1405 }
1406 else
1407 {
1408 ventoy_json_result(conn, VTOY_JSON_INVALID_RET);
1409 }
1410
1411 vtoy_json_destroy(json);
1412
1413 if (post_data_buf != stack_buf)
1414 {
1415 free(post_data_buf);
1416 }
1417 return 1;
1418 }
1419 else
1420 {
1421 return 0;
1422 }
1423 }
1424
1425 int ventoy_http_start(const char *ip, const char *port)
1426 {
1427 uint8_t uuid[16];
1428 char addr[128];
1429 struct mg_callbacks callbacks;
1430 const char *options[] =
1431 {
1432 "listening_ports", "24680",
1433 "document_root", "WebUI",
1434 "error_log_file", VTOY_LOG_FILE,
1435 "request_timeout_ms", "10000",
1436 NULL
1437 };
1438
1439 /* unique token */
1440 ventoy_gen_preudo_uuid(uuid);
1441 scnprintf(g_cur_server_token, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1442 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
1443 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
1444
1445 /* option */
1446 scnprintf(addr, "%s:%s", ip, port);
1447 options[1] = addr;
1448
1449 memset(&callbacks, 0, sizeof(callbacks));
1450 callbacks.begin_request = ventoy_request_handler;
1451 g_ventoy_http_ctx = mg_start(&callbacks, NULL, options);
1452
1453 return g_ventoy_http_ctx ? 0 : 1;
1454 }
1455
1456 int ventoy_http_stop(void)
1457 {
1458 if (g_ventoy_http_ctx)
1459 {
1460 mg_stop(g_ventoy_http_ctx);
1461 }
1462 return 0;
1463 }
1464
1465 int ventoy_http_init(void)
1466 {
1467 pthread_mutex_init(&g_api_mutex, NULL);
1468
1469 ventoy_http_load_cfg();
1470
1471 ventoy_load_mbr_template();
1472
1473 return 0;
1474 }
1475
1476 void ventoy_http_exit(void)
1477 {
1478 pthread_mutex_destroy(&g_api_mutex);
1479
1480 check_free(g_efi_part_raw_img);
1481 g_efi_part_raw_img = NULL;
1482 }
1483