1 /******************************************************************************
2 * ventoy_http.c ---- ventoy http
3 * Copyright (c) 2021, longpanda <admin@ventoy.net>
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.
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.
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/>.
28 #include <sys/types.h>
29 #include <sys/ioctl.h>
31 #include <sys/types.h>
32 #include <sys/mount.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"
43 static char *g_pub_out_buf
= NULL
;
44 static int g_pub_out_max
= 0;
46 static pthread_mutex_t g_api_mutex
;
47 static char g_cur_language
[128];
48 static int g_cur_part_style
= 0;
49 static int g_cur_show_all
= 0;
50 static char g_cur_server_token
[64];
51 static struct mg_context
*g_ventoy_http_ctx
= NULL
;
53 static uint32_t g_efi_part_offset
= 0;
54 static uint8_t *g_efi_part_raw_img
= NULL
;
55 static uint8_t *g_grub_stg1_raw_img
= NULL
;
57 static char g_cur_process_diskname
[64];
58 static char g_cur_process_type
[64];
59 static volatile int g_cur_process_result
= 0;
60 static volatile PROGRESS_POINT g_current_progress
= PT_FINISH
;
62 static int ventoy_load_mbr_template(void)
66 fp
= fopen("boot/boot.img", "rb");
69 vlog("Failed to open file boot/boot.img\n");
73 fread(g_mbr_template
, 1, 512, fp
);
76 ventoy_gen_preudo_uuid(g_mbr_template
+ 0x180);
80 static int ventoy_disk_xz_flush(void *src
, unsigned int size
)
82 memcpy(g_efi_part_raw_img
+ g_efi_part_offset
, src
, size
);
83 g_efi_part_offset
+= size
;
85 g_current_progress
= PT_LOAD_DISK_IMG
+ (g_efi_part_offset
/ SIZE_1MB
);
89 static int ventoy_unxz_efipart_img(void)
97 rc
= ventoy_read_file_to_buf(VENTOY_FILE_DISK_IMG
, 0, &xzbuf
, &xzlen
);
98 vdebug("read disk.img.xz rc:%d len:%d\n", rc
, xzlen
);
100 if (g_efi_part_raw_img
)
102 buf
= g_efi_part_raw_img
;
106 buf
= malloc(VTOYEFI_PART_BYTES
);
114 g_efi_part_offset
= 0;
115 g_efi_part_raw_img
= buf
;
117 rc
= unxz(xzbuf
, xzlen
, NULL
, ventoy_disk_xz_flush
, buf
, &inlen
, NULL
);
118 vdebug("ventoy_unxz_efipart_img len:%d rc:%d unxzlen:%u\n", inlen
, rc
, g_efi_part_offset
);
124 static int ventoy_unxz_stg1_img(void)
132 rc
= ventoy_read_file_to_buf(VENTOY_FILE_STG1_IMG
, 0, &xzbuf
, &xzlen
);
133 vdebug("read core.img.xz rc:%d len:%d\n", rc
, xzlen
);
135 if (g_grub_stg1_raw_img
)
137 buf
= g_grub_stg1_raw_img
;
141 buf
= zalloc(SIZE_1MB
);
149 rc
= unxz(xzbuf
, xzlen
, NULL
, NULL
, buf
, &inlen
, NULL
);
150 vdebug("ventoy_unxz_stg1_img len:%d rc:%d\n", inlen
, rc
);
152 g_grub_stg1_raw_img
= buf
;
159 static int ventoy_http_save_cfg(void)
163 fp
= fopen("./Ventoy2Disk.ini", "w");
169 fprintf(fp
, "[Ventoy]\nLanguage=%s\nPartStyle=%d\nShowAllDevice=%d\n",
170 g_cur_language
, g_cur_part_style
, g_cur_show_all
);
176 static int ventoy_http_load_cfg(void)
183 fp
= fopen("./Ventoy2Disk.ini", "r");
189 while (fgets(line
, sizeof(line
), fp
))
191 len
= (int)strlen(line
);
192 for (i
= len
- 1; i
>= 0; i
--)
194 if (line
[i
] == ' ' || line
[i
] == '\t' || line
[i
] == '\r' || line
[i
] == '\n')
204 len
= (int)strlen("Language=");
205 if (strncmp(line
, "Language=", len
) == 0)
207 scnprintf(g_cur_language
, "%s", line
+ len
);
209 else if (strncmp(line
, "PartStyle=", strlen("PartStyle=")) == 0)
211 g_cur_part_style
= (int)strtol(line
+ strlen("PartStyle="), NULL
, 10);
213 else if (strncmp(line
, "ShowAllDevice=", strlen("ShowAllDevice=")) == 0)
215 g_cur_show_all
= (int)strtol(line
+ strlen("ShowAllDevice="), NULL
, 10);
224 static int ventoy_json_result(struct mg_connection
*conn
, const char *err
)
229 "HTTP/1.1 200 OK \r\n"
230 "Content-Type: application/json\r\n"
231 "Content-Length: %d\r\n"
233 (int)strlen(err
), err
);
237 memcpy(g_pub_out_buf
, err
, (int)strlen(err
) + 1);
243 static int ventoy_json_buffer(struct mg_connection
*conn
, const char *json_buf
, int json_len
)
248 "HTTP/1.1 200 OK \r\n"
249 "Content-Type: application/json\r\n"
250 "Content-Length: %d\r\n"
256 if (json_len
>= g_pub_out_max
)
258 vlog("json buffer overflow\n");
262 memcpy(g_pub_out_buf
, json_buf
, json_len
);
263 g_pub_out_buf
[json_len
] = 0;
270 static int ventoy_api_sysinfo(struct mg_connection
*conn
, VTOY_JSON
*json
)
279 busy
= (g_current_progress
== PT_FINISH
) ? 0 : 1;
281 buflen
= sizeof(buf
) - 1;
282 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
283 VTOY_JSON_FMT_OBJ_BEGIN();
284 VTOY_JSON_FMT_STRN("token", g_cur_server_token
);
285 VTOY_JSON_FMT_STRN("language", g_cur_language
);
286 VTOY_JSON_FMT_STRN("ventoy_ver", ventoy_get_local_version());
287 VTOY_JSON_FMT_UINT("partstyle", g_cur_part_style
);
288 VTOY_JSON_FMT_BOOL("busy", busy
);
289 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname
);
290 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type
);
291 VTOY_JSON_FMT_OBJ_END();
292 VTOY_JSON_FMT_END(pos
);
294 ventoy_json_buffer(conn
, buf
, pos
);
298 static int ventoy_api_get_percent(struct mg_connection
*conn
, VTOY_JSON
*json
)
307 percent
= g_current_progress
* 100 / PT_FINISH
;
309 buflen
= sizeof(buf
) - 1;
310 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
311 VTOY_JSON_FMT_OBJ_BEGIN();
312 VTOY_JSON_FMT_STRN("result", g_cur_process_result
? "failed" : "success");
313 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname
);
314 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type
);
315 VTOY_JSON_FMT_UINT("percent", percent
);
316 VTOY_JSON_FMT_OBJ_END();
317 VTOY_JSON_FMT_END(pos
);
319 ventoy_json_buffer(conn
, buf
, pos
);
323 static int ventoy_api_set_language(struct mg_connection
*conn
, VTOY_JSON
*json
)
325 const char *lang
= NULL
;
327 lang
= vtoy_json_get_string_ex(json
, "language");
330 scnprintf(g_cur_language
, "%s", lang
);
331 ventoy_http_save_cfg();
334 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
338 static int ventoy_api_set_partstyle(struct mg_connection
*conn
, VTOY_JSON
*json
)
343 ret
= vtoy_json_get_int(json
, "partstyle", &style
);
344 if (JSON_SUCCESS
== ret
)
346 if ((style
== 0) || (style
== 1))
348 g_cur_part_style
= style
;
349 ventoy_http_save_cfg();
353 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
357 static int ventoy_clean_disk(int fd
, uint64_t size
)
364 vdebug("ventoy_clean_disk fd:%d size:%llu\n", fd
, (_ull
)size
);
367 buf
= zalloc(zerolen
);
370 vlog("failed to alloc clean buffer\n");
374 offset
= lseek(fd
, 0, SEEK_SET
);
375 len
= write(fd
, buf
, zerolen
);
376 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull
)offset
, (_ll
)len
, zerolen
);
378 offset
= lseek(fd
, size
- zerolen
, SEEK_SET
);
379 len
= write(fd
, buf
, zerolen
);
380 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull
)offset
, (_ll
)len
, zerolen
);
388 static int ventoy_write_legacy_grub(int fd
, int partstyle
)
395 vlog("Write GPT stage1 ...\n");
397 offset
= lseek(fd
, 512 * 34, SEEK_SET
);
399 g_grub_stg1_raw_img
[500] = 35;//update blocklist
400 len
= write(fd
, g_grub_stg1_raw_img
, SIZE_1MB
- 512 * 34);
402 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull
)offset
, 512 * 34, (_ull
)len
, SIZE_1MB
- 512 * 34);
403 if (SIZE_1MB
- 512 * 34 != len
)
405 vlog("write length error\n");
411 vlog("Write MBR stage1 ...\n");
412 offset
= lseek(fd
, 512, SEEK_SET
);
413 len
= write(fd
, g_grub_stg1_raw_img
, SIZE_1MB
- 512);
415 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull
)offset
, 512, (_ull
)len
, SIZE_1MB
- 512);
416 if (SIZE_1MB
- 512 != len
)
418 vlog("write length error\n");
426 static int VentoyFatMemRead(uint32 Sector
, uint8
*Buffer
, uint32 SectorCount
)
431 for (i
= 0; i
< SectorCount
; i
++)
433 offset
= (Sector
+ i
) * 512;
434 memcpy(Buffer
+ i
* 512, g_efi_part_raw_img
+ offset
, 512);
440 static int VentoyFatMemWrite(uint32 Sector
, uint8
*Buffer
, uint32 SectorCount
)
445 for (i
= 0; i
< SectorCount
; i
++)
447 offset
= (Sector
+ i
) * 512;
448 memcpy(g_efi_part_raw_img
+ offset
, Buffer
+ i
* 512, 512);
454 static int VentoyProcSecureBoot(int SecureBoot
)
458 char *filebuf
= NULL
;
461 vlog("VentoyProcSecureBoot %d ...\n", SecureBoot
);
465 vlog("Secure boot is enabled ...\n");
471 if (0 == fl_attach_media(VentoyFatMemRead
, VentoyFatMemWrite
))
473 file
= fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
474 vlog("Open ventoy efi file %p \n", file
);
477 fl_fseek(file
, 0, SEEK_END
);
478 size
= (int)fl_ftell(file
);
479 fl_fseek(file
, 0, SEEK_SET
);
481 vlog("ventoy efi file size %d ...\n", size
);
483 filebuf
= (char *)malloc(size
);
486 fl_fread(filebuf
, 1, size
, file
);
491 vlog("Now delete all efi files ...\n");
492 fl_remove("/EFI/BOOT/BOOTX64.EFI");
493 fl_remove("/EFI/BOOT/grubx64.efi");
494 fl_remove("/EFI/BOOT/grubx64_real.efi");
495 fl_remove("/EFI/BOOT/MokManager.efi");
496 fl_remove("/ENROLL_THIS_KEY_IN_MOKMANAGER.cer");
498 file
= fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");
499 vlog("Open bootx64 efi file %p \n", file
);
504 fl_fwrite(filebuf
, 1, size
, file
);
517 file
= fl_fopen("/EFI/BOOT/grubia32_real.efi", "rb");
518 vlog("Open ventoy efi file %p\n", file
);
521 fl_fseek(file
, 0, SEEK_END
);
522 size
= (int)fl_ftell(file
);
523 fl_fseek(file
, 0, SEEK_SET
);
525 vlog("ventoy efi file size %d ...\n", size
);
527 filebuf
= (char *)malloc(size
);
530 fl_fread(filebuf
, 1, size
, file
);
535 vlog("Now delete all efi files ...\n");
536 fl_remove("/EFI/BOOT/BOOTIA32.EFI");
537 fl_remove("/EFI/BOOT/grubia32.efi");
538 fl_remove("/EFI/BOOT/grubia32_real.efi");
539 fl_remove("/EFI/BOOT/mmia32.efi");
541 file
= fl_fopen("/EFI/BOOT/BOOTIA32.EFI", "wb");
542 vlog("Open bootia32 efi file %p\n", file
);
547 fl_fwrite(filebuf
, 1, size
, file
);
571 static int ventoy_check_efi_part_data(int fd
, uint64_t offset
)
577 buf
= malloc(SIZE_1MB
);
583 lseek(fd
, offset
, SEEK_SET
);
584 for (i
= 0; i
< 32; i
++)
586 len
= read(fd
, buf
, SIZE_1MB
);
587 if (len
!= SIZE_1MB
|| memcmp(buf
, g_efi_part_raw_img
+ i
* SIZE_1MB
, SIZE_1MB
))
589 vlog("part2 data check failed i=%d len:%llu\n", i
, (_ull
)len
);
593 g_current_progress
= PT_CHECK_PART2
+ (i
/ 4);
599 static int ventoy_write_efipart(int fd
, uint64_t offset
, uint32_t secureboot
)
604 vlog("Formatting part2 EFI offset:%llu ...\n", (_ull
)offset
);
605 lseek(fd
, offset
, SEEK_SET
);
607 VentoyProcSecureBoot((int)secureboot
);
609 g_current_progress
= PT_WRITE_VENTOY_START
;
610 for (i
= 0; i
< 32; i
++)
612 len
= write(fd
, g_efi_part_raw_img
+ i
* SIZE_1MB
, SIZE_1MB
);
613 vlog("write disk writelen:%lld datalen:%d [ %s ]\n",
614 (_ll
)len
, SIZE_1MB
, (len
== SIZE_1MB
) ? "success" : "failed");
618 vlog("failed to format part2 EFI\n");
622 g_current_progress
= PT_WRITE_VENTOY_START
+ i
/ 4;
628 static int VentoyFillBackupGptHead(VTOY_GPT_INFO
*pInfo
, VTOY_GPT_HDR
*pHead
)
633 memcpy(pHead
, &pInfo
->Head
, sizeof(VTOY_GPT_HDR
));
635 LBA
= pHead
->EfiStartLBA
;
636 BackupLBA
= pHead
->EfiBackupLBA
;
638 pHead
->EfiStartLBA
= BackupLBA
;
639 pHead
->EfiBackupLBA
= LBA
;
640 pHead
->PartTblStartLBA
= BackupLBA
+ 1 - 33;
643 pHead
->Crc
= ventoy_crc32(pHead
, pHead
->Length
);
648 static int ventoy_write_gpt_part_table(int fd
, uint64_t disksize
, VTOY_GPT_INFO
*gpt
)
652 VTOY_GPT_HDR BackupHead
;
654 VentoyFillBackupGptHead(gpt
, &BackupHead
);
656 offset
= lseek(fd
, disksize
- 512, SEEK_SET
);
657 len
= write(fd
, &BackupHead
, sizeof(VTOY_GPT_HDR
));
658 vlog("write backup gpt part table off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
659 if (offset
!= disksize
- 512 || len
!= sizeof(VTOY_GPT_HDR
))
664 offset
= lseek(fd
, disksize
- 512 * 33, SEEK_SET
);
665 len
= write(fd
, gpt
->PartTbl
, sizeof(gpt
->PartTbl
));
666 vlog("write main gpt part table off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
667 if (offset
!= disksize
- 512 * 33 || len
!= sizeof(gpt
->PartTbl
))
672 offset
= lseek(fd
, 0, SEEK_SET
);
673 len
= write(fd
, gpt
, sizeof(VTOY_GPT_INFO
));
674 vlog("write gpt part head off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
675 if (offset
!= 0 || len
!= sizeof(VTOY_GPT_INFO
))
683 static void * ventoy_update_thread(void *data
)
689 ventoy_disk
*disk
= NULL
;
690 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
692 vdebug("ventoy_update_thread run ...\n");
697 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
698 vdebug("check disk %s\n", disk
->disk_name
);
699 if (ventoy_is_disk_mounted(disk
->disk_path
))
701 vlog("disk is mounted, now try to unmount it ...\n");
702 ventoy_try_umount_disk(disk
->disk_path
);
705 if (ventoy_is_disk_mounted(disk
->disk_path
))
707 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
712 vlog("disk is not mounted now, we can do continue ...\n");
715 g_current_progress
= PT_LOAD_CORE_IMG
;
716 ventoy_unxz_stg1_img();
718 g_current_progress
= PT_LOAD_DISK_IMG
;
719 ventoy_unxz_efipart_img();
721 g_current_progress
= PT_FORMAT_PART2
;
723 vlog("Formatting part2 EFI ...\n");
724 if (0 != ventoy_write_efipart(fd
, disk
->vtoydata
.part2_start_sector
* 512, thread
->secure_boot
))
726 vlog("Failed to format part2 efi ...\n");
730 g_current_progress
= PT_WRITE_STG1_IMG
;
732 vlog("Writing legacy grub ...\n");
733 if (0 != ventoy_write_legacy_grub(fd
, disk
->vtoydata
.partition_style
))
735 vlog("ventoy_write_legacy_grub failed ...\n");
739 offset
= lseek(fd
, 512 * 2040, SEEK_SET
);
740 len
= write(fd
, disk
->vtoydata
.rsvdata
, sizeof(disk
->vtoydata
.rsvdata
));
741 vlog("Writing reserve data offset:%llu len:%llu ...\n", (_ull
)offset
, (_ull
)len
);
743 memcpy(&MBR
, &(disk
->vtoydata
.gptinfo
.MBR
), 512);
744 if (disk
->vtoydata
.partition_style
== 0 && MBR
.PartTbl
[0].Active
== 0)
746 MBR
.PartTbl
[0].Active
= 0x80;
747 MBR
.PartTbl
[1].Active
= 0;
748 MBR
.PartTbl
[2].Active
= 0;
749 MBR
.PartTbl
[3].Active
= 0;
751 offset
= lseek(fd
, 0, SEEK_SET
);
752 len
= write(fd
, &MBR
, 512);
753 vlog("set MBR partition 1 active flag enabled offset:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
756 g_current_progress
= PT_SYNC_DATA1
;
758 vlog("fsync data1...\n");
760 vtoy_safe_close_fd(fd
);
762 g_current_progress
= PT_SYNC_DATA2
;
764 vlog("====================================\n");
765 vlog("====== ventoy update success ======\n");
766 vlog("====================================\n");
770 g_cur_process_result
= 1;
771 vtoy_safe_close_fd(fd
);
774 g_current_progress
= PT_FINISH
;
781 static void * ventoy_install_thread(void *data
)
787 ventoy_disk
*disk
= NULL
;
788 VTOY_GPT_INFO
*gpt
= NULL
;
789 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
790 uint64_t Part1StartSector
= 0;
791 uint64_t Part1SectorCount
= 0;
792 uint64_t Part2StartSector
= 0;
794 vdebug("ventoy_install_thread run ...\n");
799 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
800 vdebug("check disk %s\n", disk
->disk_name
);
801 if (ventoy_is_disk_mounted(disk
->disk_path
))
803 vlog("disk is mounted, now try to unmount it ...\n");
804 ventoy_try_umount_disk(disk
->disk_path
);
807 if (ventoy_is_disk_mounted(disk
->disk_path
))
809 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
814 vlog("disk is not mounted now, we can do continue ...\n");
817 g_current_progress
= PT_DEL_ALL_PART
;
818 ventoy_clean_disk(fd
, disk
->size_in_byte
);
820 g_current_progress
= PT_LOAD_CORE_IMG
;
821 ventoy_unxz_stg1_img();
823 g_current_progress
= PT_LOAD_DISK_IMG
;
824 ventoy_unxz_efipart_img();
826 if (thread
->partstyle
)
828 vdebug("Fill GPT part table\n");
829 gpt
= zalloc(sizeof(VTOY_GPT_INFO
));
830 ventoy_fill_gpt(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, gpt
);
831 Part1StartSector
= gpt
->PartTbl
[0].StartLBA
;
832 Part1SectorCount
= gpt
->PartTbl
[0].LastLBA
- Part1StartSector
+ 1;
833 Part2StartSector
= gpt
->PartTbl
[1].StartLBA
;
837 vdebug("Fill MBR part table\n");
838 ventoy_fill_mbr(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, &MBR
);
839 Part1StartSector
= MBR
.PartTbl
[0].StartSectorId
;
840 Part1SectorCount
= MBR
.PartTbl
[0].SectorCount
;
841 Part2StartSector
= MBR
.PartTbl
[1].StartSectorId
;
844 vlog("Part1StartSector:%llu Part1SectorCount:%llu Part2StartSector:%llu\n",
845 (_ull
)Part1StartSector
, (_ull
)Part1SectorCount
, (_ull
)Part2StartSector
);
847 if (thread
->partstyle
!= disk
->partstyle
)
849 vlog("Wait for format part1 (partstyle changed) ...\n");
853 g_current_progress
= PT_FORMAT_PART1
;
854 vlog("Formatting part1 exFAT %s ...\n", disk
->disk_path
);
855 if (0 != mkexfat_main(disk
->disk_path
, fd
, Part1SectorCount
))
857 vlog("Failed to format exfat ...\n");
861 g_current_progress
= PT_FORMAT_PART2
;
862 vlog("Formatting part2 EFI ...\n");
863 if (0 != ventoy_write_efipart(fd
, Part2StartSector
* 512, thread
->secure_boot
))
865 vlog("Failed to format part2 efi ...\n");
869 g_current_progress
= PT_WRITE_STG1_IMG
;
870 vlog("Writing legacy grub ...\n");
871 if (0 != ventoy_write_legacy_grub(fd
, thread
->partstyle
))
873 vlog("ventoy_write_legacy_grub failed ...\n");
877 g_current_progress
= PT_SYNC_DATA1
;
878 vlog("fsync data1...\n");
880 vtoy_safe_close_fd(fd
);
882 /* reopen for check part2 data */
883 vlog("Checking part2 efi data %s ...\n", disk
->disk_path
);
884 g_current_progress
= PT_CHECK_PART2
;
885 fd
= open(disk
->disk_path
, O_RDONLY
| O_BINARY
);
888 vlog("failed to open %s for check fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
892 if (0 == ventoy_check_efi_part_data(fd
, Part2StartSector
* 512))
894 vlog("efi part data check success\n");
898 vlog("efi part data check failed\n");
902 vtoy_safe_close_fd(fd
);
904 /* reopen for write part table */
905 g_current_progress
= PT_WRITE_PART_TABLE
;
906 vlog("Writting Partition Table style:%d...\n", thread
->partstyle
);
908 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
911 vlog("failed to open %s for part table fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
915 if (thread
->partstyle
)
917 ventoy_write_gpt_part_table(fd
, disk
->size_in_byte
, gpt
);
921 offset
= lseek(fd
, 0, SEEK_SET
);
922 len
= write(fd
, &MBR
, 512);
923 vlog("Writting MBR Partition Table %llu %llu\n", (_ull
)offset
, (_ull
)len
);
924 if (offset
!= 0 || len
!= 512)
930 g_current_progress
= PT_SYNC_DATA2
;
931 vlog("fsync data2...\n");
933 vtoy_safe_close_fd(fd
);
936 vlog("====================================\n");
937 vlog("====== ventoy install success ======\n");
938 vlog("====================================\n");
942 g_cur_process_result
= 1;
943 vtoy_safe_close_fd(fd
);
946 g_current_progress
= PT_FINISH
;
954 static int ventoy_api_clean(struct mg_connection
*conn
, VTOY_JSON
*json
)
958 ventoy_disk
*disk
= NULL
;
959 const char *diskname
= NULL
;
962 if (g_current_progress
!= PT_FINISH
)
964 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
968 diskname
= vtoy_json_get_string_ex(json
, "disk");
969 if (diskname
== NULL
)
971 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
975 for (i
= 0; i
< g_disk_num
; i
++)
977 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
979 disk
= g_disk_list
+ i
;
986 vlog("disk %s not found\n", diskname
);
987 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
991 scnprintf(path
, "/sys/block/%s", diskname
);
992 if (access(path
, F_OK
) < 0)
994 vlog("File %s not exist anymore\n", path
);
995 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
999 vlog("==================================\n");
1000 vlog("===== ventoy clean %s =====\n", disk
->disk_path
);
1001 vlog("==================================\n");
1003 if (ventoy_is_disk_mounted(disk
->disk_path
))
1005 vlog("disk is mounted, now try to unmount it ...\n");
1006 ventoy_try_umount_disk(disk
->disk_path
);
1009 if (ventoy_is_disk_mounted(disk
->disk_path
))
1011 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1012 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1017 vlog("disk is not mounted now, we can do the clean ...\n");
1020 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1023 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1024 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1028 vdebug("start clean %s ...\n", disk
->disk_model
);
1029 ventoy_clean_disk(fd
, disk
->size_in_byte
);
1031 vtoy_safe_close_fd(fd
);
1033 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1037 static int ventoy_api_install(struct mg_connection
*conn
, VTOY_JSON
*json
)
1042 uint32_t align4kb
= 0;
1044 uint32_t secure_boot
= 0;
1045 uint64_t reserveBytes
= 0;
1046 ventoy_disk
*disk
= NULL
;
1047 const char *diskname
= NULL
;
1048 const char *reserve_space
= NULL
;
1049 ventoy_thread_data
*thread
= NULL
;
1052 if (g_current_progress
!= PT_FINISH
)
1054 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1058 diskname
= vtoy_json_get_string_ex(json
, "disk");
1059 reserve_space
= vtoy_json_get_string_ex(json
, "reserve_space");
1060 ret
+= vtoy_json_get_uint(json
, "partstyle", &style
);
1061 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1062 ret
+= vtoy_json_get_uint(json
, "align_4kb", &align4kb
);
1064 if (diskname
== NULL
|| reserve_space
== NULL
|| ret
!= JSON_SUCCESS
)
1066 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1070 reserveBytes
= (uint64_t)strtoull(reserve_space
, NULL
, 10);
1072 for (i
= 0; i
< g_disk_num
; i
++)
1074 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1076 disk
= g_disk_list
+ i
;
1083 vlog("disk %s not found\n", diskname
);
1084 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1088 scnprintf(path
, "/sys/block/%s", diskname
);
1089 if (access(path
, F_OK
) < 0)
1091 vlog("File %s not exist anymore\n", path
);
1092 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1096 if (disk
->size_in_byte
> 2199023255552ULL && style
== 0)
1098 vlog("disk %s is more than 2TB and GPT is needed\n", path
);
1099 ventoy_json_result(conn
, VTOY_JSON_MBR_2TB_RET
);
1103 if ((reserveBytes
+ VTOYEFI_PART_BYTES
* 2) > disk
->size_in_byte
)
1105 vlog("reserve space %llu is too big for disk %s %llu\n", (_ull
)reserveBytes
, path
, (_ull
)disk
->size_in_byte
);
1106 ventoy_json_result(conn
, VTOY_JSON_INVALID_RSV_RET
);
1110 vlog("==================================================================================\n");
1111 vlog("===== ventoy install %s style:%s secureboot:%u align4K:%u reserve:%llu =========\n",
1112 disk
->disk_path
, (style
? "GPT" : "MBR"), secure_boot
, align4kb
, (_ull
)reserveBytes
);
1113 vlog("==================================================================================\n");
1115 if (ventoy_is_disk_mounted(disk
->disk_path
))
1117 vlog("disk is mounted, now try to unmount it ...\n");
1118 ventoy_try_umount_disk(disk
->disk_path
);
1121 if (ventoy_is_disk_mounted(disk
->disk_path
))
1123 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1124 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1129 vlog("disk is not mounted now, we can do the install ...\n");
1132 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1135 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1136 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1140 vdebug("start install thread %s ...\n", disk
->disk_model
);
1141 thread
= zalloc(sizeof(ventoy_thread_data
));
1144 vtoy_safe_close_fd(fd
);
1145 vlog("failed to alloc thread data err:%d\n", errno
);
1146 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1150 g_current_progress
= PT_START
;
1151 g_cur_process_result
= 0;
1152 scnprintf(g_cur_process_type
, "%s", "install");
1153 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1155 thread
->disk
= disk
;
1156 thread
->diskfd
= fd
;
1157 thread
->align4kb
= align4kb
;
1158 thread
->partstyle
= style
;
1159 thread
->secure_boot
= secure_boot
;
1160 thread
->reserveBytes
= reserveBytes
;
1162 mg_start_thread(ventoy_install_thread
, thread
);
1164 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1168 static int ventoy_api_update(struct mg_connection
*conn
, VTOY_JSON
*json
)
1173 uint32_t secure_boot
= 0;
1174 ventoy_disk
*disk
= NULL
;
1175 const char *diskname
= NULL
;
1176 ventoy_thread_data
*thread
= NULL
;
1179 if (g_current_progress
!= PT_FINISH
)
1181 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1185 diskname
= vtoy_json_get_string_ex(json
, "disk");
1186 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1187 if (diskname
== NULL
|| ret
!= JSON_SUCCESS
)
1189 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1193 for (i
= 0; i
< g_disk_num
; i
++)
1195 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1197 disk
= g_disk_list
+ i
;
1204 vlog("disk %s not found\n", diskname
);
1205 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1209 if (disk
->vtoydata
.ventoy_valid
== 0)
1211 vlog("disk %s is not ventoy disk\n", diskname
);
1212 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1216 scnprintf(path
, "/sys/block/%s", diskname
);
1217 if (access(path
, F_OK
) < 0)
1219 vlog("File %s not exist anymore\n", path
);
1220 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1224 vlog("==========================================================\n");
1225 vlog("===== ventoy update %s new_secureboot:%u =========\n", disk
->disk_path
, secure_boot
);
1226 vlog("==========================================================\n");
1228 vlog("%s version:%s partstyle:%u oldsecureboot:%u reserve:%llu\n",
1229 disk
->disk_path
, disk
->vtoydata
.ventoy_ver
,
1230 disk
->vtoydata
.partition_style
,
1231 disk
->vtoydata
.secure_boot_flag
,
1232 (_ull
)(disk
->vtoydata
.preserved_space
)
1235 if (ventoy_is_disk_mounted(disk
->disk_path
))
1237 vlog("disk is mounted, now try to unmount it ...\n");
1238 ventoy_try_umount_disk(disk
->disk_path
);
1241 if (ventoy_is_disk_mounted(disk
->disk_path
))
1243 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1244 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1249 vlog("disk is not mounted now, we can do the update ...\n");
1252 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1255 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1256 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1260 vdebug("start update thread %s ...\n", disk
->disk_model
);
1261 thread
= zalloc(sizeof(ventoy_thread_data
));
1264 vtoy_safe_close_fd(fd
);
1265 vlog("failed to alloc thread data err:%d\n", errno
);
1266 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1270 g_current_progress
= PT_START
;
1271 g_cur_process_result
= 0;
1272 scnprintf(g_cur_process_type
, "%s", "update");
1273 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1275 thread
->disk
= disk
;
1276 thread
->diskfd
= fd
;
1277 thread
->secure_boot
= secure_boot
;
1279 mg_start_thread(ventoy_update_thread
, thread
);
1281 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1286 static int ventoy_api_refresh_device(struct mg_connection
*conn
, VTOY_JSON
*json
)
1290 if (g_current_progress
== PT_FINISH
)
1293 ventoy_disk_enumerate_all();
1296 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1300 static int ventoy_api_get_dev_list(struct mg_connection
*conn
, VTOY_JSON
*json
)
1306 uint32_t alldev
= 0;
1308 ventoy_disk
*cur
= NULL
;
1310 rc
= vtoy_json_get_uint(json
, "alldev", &alldev
);
1311 if (JSON_SUCCESS
!= rc
)
1316 buflen
= g_disk_num
* 1024;
1317 buf
= (char *)malloc(buflen
+ 1024);
1320 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1324 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
1325 VTOY_JSON_FMT_OBJ_BEGIN();
1326 VTOY_JSON_FMT_KEY("list");
1327 VTOY_JSON_FMT_ARY_BEGIN();
1329 for (i
= 0; i
< g_disk_num
; i
++)
1331 cur
= g_disk_list
+ i
;
1333 if (alldev
== 0 && cur
->type
!= VTOY_DEVICE_USB
)
1338 VTOY_JSON_FMT_OBJ_BEGIN();
1339 VTOY_JSON_FMT_STRN("name", cur
->disk_name
);
1340 VTOY_JSON_FMT_STRN("model", cur
->disk_model
);
1341 VTOY_JSON_FMT_STRN("size", cur
->human_readable_size
);
1342 VTOY_JSON_FMT_UINT("vtoy_valid", cur
->vtoydata
.ventoy_valid
);
1343 VTOY_JSON_FMT_STRN("vtoy_ver", cur
->vtoydata
.ventoy_ver
);
1344 VTOY_JSON_FMT_UINT("vtoy_secure_boot", cur
->vtoydata
.secure_boot_flag
);
1345 VTOY_JSON_FMT_UINT("vtoy_partstyle", cur
->vtoydata
.partition_style
);
1346 VTOY_JSON_FMT_OBJ_ENDEX();
1349 VTOY_JSON_FMT_ARY_END();
1350 VTOY_JSON_FMT_OBJ_END();
1351 VTOY_JSON_FMT_END(pos
);
1353 ventoy_json_buffer(conn
, buf
, pos
);
1357 static JSON_CB g_ventoy_json_cb
[] =
1359 { "sysinfo", ventoy_api_sysinfo
},
1360 { "sel_language", ventoy_api_set_language
},
1361 { "sel_partstyle", ventoy_api_set_partstyle
},
1362 { "refresh_device", ventoy_api_refresh_device
},
1363 { "get_dev_list", ventoy_api_get_dev_list
},
1364 { "install", ventoy_api_install
},
1365 { "update", ventoy_api_update
},
1366 { "clean", ventoy_api_clean
},
1367 { "get_percent", ventoy_api_get_percent
},
1370 static int ventoy_json_handler(struct mg_connection
*conn
, VTOY_JSON
*json
)
1373 const char *token
= NULL
;
1374 const char *method
= NULL
;
1376 method
= vtoy_json_get_string_ex(json
, "method");
1379 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1383 if (strcmp(method
, "sysinfo"))
1385 token
= vtoy_json_get_string_ex(json
, "token");
1386 if (token
== NULL
|| strcmp(token
, g_cur_server_token
))
1388 ventoy_json_result(conn
, VTOY_JSON_TOKEN_ERR_RET
);
1393 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1395 if (strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1397 g_ventoy_json_cb
[i
].callback(conn
, json
);
1405 int ventoy_func_handler(const char *jsonstr
, char *jsonbuf
, int buflen
)
1408 const char *method
= NULL
;
1409 VTOY_JSON
*json
= NULL
;
1411 g_pub_out_buf
= jsonbuf
;
1412 g_pub_out_max
= buflen
;
1414 json
= vtoy_json_create();
1415 if (JSON_SUCCESS
== vtoy_json_parse(json
, jsonstr
))
1417 pthread_mutex_lock(&g_api_mutex
);
1419 method
= vtoy_json_get_string_ex(json
->pstChild
, "method");
1420 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1422 if (method
&& strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1424 g_ventoy_json_cb
[i
].callback(NULL
, json
->pstChild
);
1429 pthread_mutex_unlock(&g_api_mutex
);
1433 ventoy_json_result(NULL
, VTOY_JSON_INVALID_RET
);
1436 vtoy_json_destroy(json
);
1440 static int ventoy_request_handler(struct mg_connection
*conn
)
1444 VTOY_JSON
*json
= NULL
;
1445 char *post_data_buf
= NULL
;
1446 const struct mg_request_info
*ri
= NULL
;
1447 char stack_buf
[512];
1449 ri
= mg_get_request_info(conn
);
1451 if (strcmp(ri
->uri
, "/vtoy/json") == 0)
1453 if (ri
->content_length
> 500)
1455 post_data_buf
= malloc(ri
->content_length
+ 4);
1456 post_buf_len
= ri
->content_length
+ 1;
1460 post_data_buf
= stack_buf
;
1461 post_buf_len
= sizeof(stack_buf
);
1464 post_data_len
= mg_read(conn
, post_data_buf
, post_buf_len
);
1465 post_data_buf
[post_data_len
] = 0;
1467 json
= vtoy_json_create();
1468 if (JSON_SUCCESS
== vtoy_json_parse(json
, post_data_buf
))
1470 pthread_mutex_lock(&g_api_mutex
);
1471 ventoy_json_handler(conn
, json
->pstChild
);
1472 pthread_mutex_unlock(&g_api_mutex
);
1476 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1479 vtoy_json_destroy(json
);
1481 if (post_data_buf
!= stack_buf
)
1483 free(post_data_buf
);
1493 int ventoy_http_start(const char *ip
, const char *port
)
1497 struct mg_callbacks callbacks
;
1498 const char *options
[] =
1500 "listening_ports", "24680",
1501 "document_root", "WebUI",
1502 "error_log_file", VTOY_LOG_FILE
,
1503 "request_timeout_ms", "10000",
1508 ventoy_gen_preudo_uuid(uuid
);
1509 scnprintf(g_cur_server_token
, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1510 uuid
[0], uuid
[1], uuid
[2], uuid
[3], uuid
[4], uuid
[5], uuid
[6], uuid
[7],
1511 uuid
[8], uuid
[9], uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
1514 scnprintf(addr
, "%s:%s", ip
, port
);
1517 memset(&callbacks
, 0, sizeof(callbacks
));
1518 callbacks
.begin_request
= ventoy_request_handler
;
1519 g_ventoy_http_ctx
= mg_start(&callbacks
, NULL
, options
);
1521 return g_ventoy_http_ctx
? 0 : 1;
1524 int ventoy_http_stop(void)
1526 if (g_ventoy_http_ctx
)
1528 mg_stop(g_ventoy_http_ctx
);
1533 int ventoy_http_init(void)
1535 pthread_mutex_init(&g_api_mutex
, NULL
);
1537 ventoy_http_load_cfg();
1539 ventoy_load_mbr_template();
1544 void ventoy_http_exit(void)
1546 pthread_mutex_destroy(&g_api_mutex
);
1548 check_free(g_efi_part_raw_img
);
1549 g_efi_part_raw_img
= NULL
;
1553 const char * ventoy_code_get_cur_language(void)
1555 return g_cur_language
;
1558 int ventoy_code_get_cur_part_style(void)
1560 return g_cur_part_style
;
1563 void ventoy_code_set_cur_part_style(int style
)
1565 pthread_mutex_lock(&g_api_mutex
);
1567 g_cur_part_style
= style
;
1568 ventoy_http_save_cfg();
1570 pthread_mutex_unlock(&g_api_mutex
);
1573 int ventoy_code_get_cur_show_all(void)
1575 return g_cur_show_all
;
1578 void ventoy_code_set_cur_show_all(int show_all
)
1580 pthread_mutex_lock(&g_api_mutex
);
1582 g_cur_show_all
= show_all
;
1583 ventoy_http_save_cfg();
1585 pthread_mutex_unlock(&g_api_mutex
);
1588 void ventoy_code_set_cur_language(const char *lang
)
1590 pthread_mutex_lock(&g_api_mutex
);
1592 scnprintf(g_cur_language
, "%s", lang
);
1593 ventoy_http_save_cfg();
1595 pthread_mutex_unlock(&g_api_mutex
);
1598 void ventoy_code_refresh_device(void)
1600 if (g_current_progress
== PT_FINISH
)
1603 ventoy_disk_enumerate_all();
1607 int ventoy_code_is_busy(void)
1609 return (g_current_progress
== PT_FINISH
) ? 0 : 1;
1612 int ventoy_code_get_percent(void)
1614 return g_current_progress
* 100 / PT_FINISH
;
1617 int ventoy_code_get_result(void)
1619 return g_cur_process_result
;
1622 void ventoy_code_save_cfg(void)
1624 ventoy_http_save_cfg();