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>
34 #include <linux/limits.h>
37 #include <ventoy_define.h>
38 #include <ventoy_json.h>
39 #include <ventoy_util.h>
40 #include <ventoy_disk.h>
41 #include <ventoy_http.h>
42 #include "fat_filelib.h"
44 static char *g_pub_out_buf
= NULL
;
45 static int g_pub_out_max
= 0;
47 static pthread_mutex_t g_api_mutex
;
48 static char g_cur_language
[128];
49 static int g_cur_part_style
= 0;
50 static int g_cur_show_all
= 0;
51 static char g_cur_server_token
[64];
52 static struct mg_context
*g_ventoy_http_ctx
= NULL
;
54 static uint32_t g_efi_part_offset
= 0;
55 static uint8_t *g_efi_part_raw_img
= NULL
;
56 static uint8_t *g_grub_stg1_raw_img
= NULL
;
58 static char g_cur_process_diskname
[64];
59 static char g_cur_process_type
[64];
60 static volatile int g_cur_process_result
= 0;
61 static volatile PROGRESS_POINT g_current_progress
= PT_FINISH
;
63 static int ventoy_load_mbr_template(void)
67 fp
= fopen("boot/boot.img", "rb");
70 vlog("Failed to open file boot/boot.img\n");
74 fread(g_mbr_template
, 1, 512, fp
);
77 ventoy_gen_preudo_uuid(g_mbr_template
+ 0x180);
81 static int ventoy_disk_xz_flush(void *src
, unsigned int size
)
83 memcpy(g_efi_part_raw_img
+ g_efi_part_offset
, src
, size
);
84 g_efi_part_offset
+= size
;
86 g_current_progress
= PT_LOAD_DISK_IMG
+ (g_efi_part_offset
/ SIZE_1MB
);
90 static int ventoy_unxz_efipart_img(void)
98 rc
= ventoy_read_file_to_buf(VENTOY_FILE_DISK_IMG
, 0, &xzbuf
, &xzlen
);
99 vdebug("read disk.img.xz rc:%d len:%d\n", rc
, xzlen
);
101 if (g_efi_part_raw_img
)
103 buf
= g_efi_part_raw_img
;
107 buf
= malloc(VTOYEFI_PART_BYTES
);
115 g_efi_part_offset
= 0;
116 g_efi_part_raw_img
= buf
;
118 rc
= unxz(xzbuf
, xzlen
, NULL
, ventoy_disk_xz_flush
, buf
, &inlen
, NULL
);
119 vdebug("ventoy_unxz_efipart_img len:%d rc:%d unxzlen:%u\n", inlen
, rc
, g_efi_part_offset
);
125 static int ventoy_unxz_stg1_img(void)
133 rc
= ventoy_read_file_to_buf(VENTOY_FILE_STG1_IMG
, 0, &xzbuf
, &xzlen
);
134 vdebug("read core.img.xz rc:%d len:%d\n", rc
, xzlen
);
136 if (g_grub_stg1_raw_img
)
138 buf
= g_grub_stg1_raw_img
;
142 buf
= zalloc(SIZE_1MB
);
150 rc
= unxz(xzbuf
, xzlen
, NULL
, NULL
, buf
, &inlen
, NULL
);
151 vdebug("ventoy_unxz_stg1_img len:%d rc:%d\n", inlen
, rc
);
153 g_grub_stg1_raw_img
= buf
;
160 static int ventoy_http_save_cfg(void)
164 fp
= fopen(g_ini_file
, "w");
167 vlog("Failed to open %s code:%d\n", g_ini_file
, errno
);
171 fprintf(fp
, "[Ventoy]\nLanguage=%s\nPartStyle=%d\nShowAllDevice=%d\n",
172 g_cur_language
, g_cur_part_style
, g_cur_show_all
);
178 static int ventoy_http_load_cfg(void)
185 fp
= fopen(g_ini_file
, "r");
191 while (fgets(line
, sizeof(line
), fp
))
193 len
= (int)strlen(line
);
194 for (i
= len
- 1; i
>= 0; i
--)
196 if (line
[i
] == ' ' || line
[i
] == '\t' || line
[i
] == '\r' || line
[i
] == '\n')
206 len
= (int)strlen("Language=");
207 if (strncmp(line
, "Language=", len
) == 0)
209 scnprintf(g_cur_language
, "%s", line
+ len
);
211 else if (strncmp(line
, "PartStyle=", strlen("PartStyle=")) == 0)
213 g_cur_part_style
= (int)strtol(line
+ strlen("PartStyle="), NULL
, 10);
215 else if (strncmp(line
, "ShowAllDevice=", strlen("ShowAllDevice=")) == 0)
217 g_cur_show_all
= (int)strtol(line
+ strlen("ShowAllDevice="), NULL
, 10);
226 static int ventoy_json_result(struct mg_connection
*conn
, const char *err
)
231 "HTTP/1.1 200 OK \r\n"
232 "Content-Type: application/json\r\n"
233 "Content-Length: %d\r\n"
235 (int)strlen(err
), err
);
239 memcpy(g_pub_out_buf
, err
, (int)strlen(err
) + 1);
245 static int ventoy_json_buffer(struct mg_connection
*conn
, const char *json_buf
, int json_len
)
250 "HTTP/1.1 200 OK \r\n"
251 "Content-Type: application/json\r\n"
252 "Content-Length: %d\r\n"
258 if (json_len
>= g_pub_out_max
)
260 vlog("json buffer overflow\n");
264 memcpy(g_pub_out_buf
, json_buf
, json_len
);
265 g_pub_out_buf
[json_len
] = 0;
272 static int ventoy_api_sysinfo(struct mg_connection
*conn
, VTOY_JSON
*json
)
281 busy
= (g_current_progress
== PT_FINISH
) ? 0 : 1;
283 buflen
= sizeof(buf
) - 1;
284 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
285 VTOY_JSON_FMT_OBJ_BEGIN();
286 VTOY_JSON_FMT_STRN("token", g_cur_server_token
);
287 VTOY_JSON_FMT_STRN("language", g_cur_language
);
288 VTOY_JSON_FMT_STRN("ventoy_ver", ventoy_get_local_version());
289 VTOY_JSON_FMT_UINT("partstyle", g_cur_part_style
);
290 VTOY_JSON_FMT_BOOL("busy", busy
);
291 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname
);
292 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type
);
293 VTOY_JSON_FMT_OBJ_END();
294 VTOY_JSON_FMT_END(pos
);
296 ventoy_json_buffer(conn
, buf
, pos
);
300 static int ventoy_api_get_percent(struct mg_connection
*conn
, VTOY_JSON
*json
)
309 percent
= g_current_progress
* 100 / PT_FINISH
;
311 buflen
= sizeof(buf
) - 1;
312 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
313 VTOY_JSON_FMT_OBJ_BEGIN();
314 VTOY_JSON_FMT_STRN("result", g_cur_process_result
? "failed" : "success");
315 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname
);
316 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type
);
317 VTOY_JSON_FMT_UINT("percent", percent
);
318 VTOY_JSON_FMT_OBJ_END();
319 VTOY_JSON_FMT_END(pos
);
321 ventoy_json_buffer(conn
, buf
, pos
);
325 static int ventoy_api_set_language(struct mg_connection
*conn
, VTOY_JSON
*json
)
327 const char *lang
= NULL
;
329 lang
= vtoy_json_get_string_ex(json
, "language");
332 scnprintf(g_cur_language
, "%s", lang
);
333 ventoy_http_save_cfg();
336 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
340 static int ventoy_api_set_partstyle(struct mg_connection
*conn
, VTOY_JSON
*json
)
345 ret
= vtoy_json_get_int(json
, "partstyle", &style
);
346 if (JSON_SUCCESS
== ret
)
348 if ((style
== 0) || (style
== 1))
350 g_cur_part_style
= style
;
351 ventoy_http_save_cfg();
355 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
359 static int ventoy_clean_disk(int fd
, uint64_t size
)
366 vdebug("ventoy_clean_disk fd:%d size:%llu\n", fd
, (_ull
)size
);
369 buf
= zalloc(zerolen
);
372 vlog("failed to alloc clean buffer\n");
376 offset
= lseek(fd
, 0, SEEK_SET
);
377 len
= write(fd
, buf
, zerolen
);
378 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull
)offset
, (_ll
)len
, zerolen
);
380 offset
= lseek(fd
, size
- zerolen
, SEEK_SET
);
381 len
= write(fd
, buf
, zerolen
);
382 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull
)offset
, (_ll
)len
, zerolen
);
390 static int ventoy_write_legacy_grub(int fd
, int partstyle
)
397 vlog("Write GPT stage1 ...\n");
399 offset
= lseek(fd
, 512 * 34, SEEK_SET
);
401 g_grub_stg1_raw_img
[500] = 35;//update blocklist
402 len
= write(fd
, g_grub_stg1_raw_img
, SIZE_1MB
- 512 * 34);
404 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull
)offset
, 512 * 34, (_ull
)len
, SIZE_1MB
- 512 * 34);
405 if (SIZE_1MB
- 512 * 34 != len
)
407 vlog("write length error\n");
413 vlog("Write MBR stage1 ...\n");
414 offset
= lseek(fd
, 512, SEEK_SET
);
415 len
= write(fd
, g_grub_stg1_raw_img
, SIZE_1MB
- 512);
417 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull
)offset
, 512, (_ull
)len
, SIZE_1MB
- 512);
418 if (SIZE_1MB
- 512 != len
)
420 vlog("write length error\n");
428 static int VentoyFatMemRead(uint32 Sector
, uint8
*Buffer
, uint32 SectorCount
)
433 for (i
= 0; i
< SectorCount
; i
++)
435 offset
= (Sector
+ i
) * 512;
436 memcpy(Buffer
+ i
* 512, g_efi_part_raw_img
+ offset
, 512);
442 static int VentoyFatMemWrite(uint32 Sector
, uint8
*Buffer
, uint32 SectorCount
)
447 for (i
= 0; i
< SectorCount
; i
++)
449 offset
= (Sector
+ i
) * 512;
450 memcpy(g_efi_part_raw_img
+ offset
, Buffer
+ i
* 512, 512);
456 static int VentoyProcSecureBoot(int SecureBoot
)
460 char *filebuf
= NULL
;
463 vlog("VentoyProcSecureBoot %d ...\n", SecureBoot
);
467 vlog("Secure boot is enabled ...\n");
473 if (0 == fl_attach_media(VentoyFatMemRead
, VentoyFatMemWrite
))
475 file
= fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
476 vlog("Open ventoy efi file %p \n", file
);
479 fl_fseek(file
, 0, SEEK_END
);
480 size
= (int)fl_ftell(file
);
481 fl_fseek(file
, 0, SEEK_SET
);
483 vlog("ventoy efi file size %d ...\n", size
);
485 filebuf
= (char *)malloc(size
);
488 fl_fread(filebuf
, 1, size
, file
);
493 vlog("Now delete all efi files ...\n");
494 fl_remove("/EFI/BOOT/BOOTX64.EFI");
495 fl_remove("/EFI/BOOT/grubx64.efi");
496 fl_remove("/EFI/BOOT/grubx64_real.efi");
497 fl_remove("/EFI/BOOT/MokManager.efi");
498 fl_remove("/EFI/BOOT/mmx64.efi");
499 fl_remove("/ENROLL_THIS_KEY_IN_MOKMANAGER.cer");
501 file
= fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");
502 vlog("Open bootx64 efi file %p \n", file
);
507 fl_fwrite(filebuf
, 1, size
, file
);
520 file
= fl_fopen("/EFI/BOOT/grubia32_real.efi", "rb");
521 vlog("Open ventoy efi file %p\n", file
);
524 fl_fseek(file
, 0, SEEK_END
);
525 size
= (int)fl_ftell(file
);
526 fl_fseek(file
, 0, SEEK_SET
);
528 vlog("ventoy efi file size %d ...\n", size
);
530 filebuf
= (char *)malloc(size
);
533 fl_fread(filebuf
, 1, size
, file
);
538 vlog("Now delete all efi files ...\n");
539 fl_remove("/EFI/BOOT/BOOTIA32.EFI");
540 fl_remove("/EFI/BOOT/grubia32.efi");
541 fl_remove("/EFI/BOOT/grubia32_real.efi");
542 fl_remove("/EFI/BOOT/mmia32.efi");
544 file
= fl_fopen("/EFI/BOOT/BOOTIA32.EFI", "wb");
545 vlog("Open bootia32 efi file %p\n", file
);
550 fl_fwrite(filebuf
, 1, size
, file
);
574 static int ventoy_check_efi_part_data(int fd
, uint64_t offset
)
580 buf
= malloc(SIZE_1MB
);
586 lseek(fd
, offset
, SEEK_SET
);
587 for (i
= 0; i
< 32; i
++)
589 len
= read(fd
, buf
, SIZE_1MB
);
590 if (len
!= SIZE_1MB
|| memcmp(buf
, g_efi_part_raw_img
+ i
* SIZE_1MB
, SIZE_1MB
))
592 vlog("part2 data check failed i=%d len:%llu\n", i
, (_ull
)len
);
596 g_current_progress
= PT_CHECK_PART2
+ (i
/ 4);
602 static int ventoy_write_efipart(int fd
, uint64_t offset
, uint32_t secureboot
)
607 vlog("Formatting part2 EFI offset:%llu ...\n", (_ull
)offset
);
608 lseek(fd
, offset
, SEEK_SET
);
610 VentoyProcSecureBoot((int)secureboot
);
612 g_current_progress
= PT_WRITE_VENTOY_START
;
613 for (i
= 0; i
< 32; i
++)
615 len
= write(fd
, g_efi_part_raw_img
+ i
* SIZE_1MB
, SIZE_1MB
);
616 vlog("write disk writelen:%lld datalen:%d [ %s ]\n",
617 (_ll
)len
, SIZE_1MB
, (len
== SIZE_1MB
) ? "success" : "failed");
621 vlog("failed to format part2 EFI\n");
625 g_current_progress
= PT_WRITE_VENTOY_START
+ i
/ 4;
631 static int VentoyFillBackupGptHead(VTOY_GPT_INFO
*pInfo
, VTOY_GPT_HDR
*pHead
)
636 memcpy(pHead
, &pInfo
->Head
, sizeof(VTOY_GPT_HDR
));
638 LBA
= pHead
->EfiStartLBA
;
639 BackupLBA
= pHead
->EfiBackupLBA
;
641 pHead
->EfiStartLBA
= BackupLBA
;
642 pHead
->EfiBackupLBA
= LBA
;
643 pHead
->PartTblStartLBA
= BackupLBA
+ 1 - 33;
646 pHead
->Crc
= ventoy_crc32(pHead
, pHead
->Length
);
651 static int ventoy_write_gpt_part_table(int fd
, uint64_t disksize
, VTOY_GPT_INFO
*gpt
)
655 VTOY_GPT_HDR BackupHead
;
657 VentoyFillBackupGptHead(gpt
, &BackupHead
);
659 offset
= lseek(fd
, disksize
- 512, SEEK_SET
);
660 len
= write(fd
, &BackupHead
, sizeof(VTOY_GPT_HDR
));
661 vlog("write backup gpt part table off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
662 if (offset
!= disksize
- 512 || len
!= sizeof(VTOY_GPT_HDR
))
667 offset
= lseek(fd
, disksize
- 512 * 33, SEEK_SET
);
668 len
= write(fd
, gpt
->PartTbl
, sizeof(gpt
->PartTbl
));
669 vlog("write main gpt part table off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
670 if (offset
!= disksize
- 512 * 33 || len
!= sizeof(gpt
->PartTbl
))
675 offset
= lseek(fd
, 0, SEEK_SET
);
676 len
= write(fd
, gpt
, sizeof(VTOY_GPT_INFO
));
677 vlog("write gpt part head off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
678 if (offset
!= 0 || len
!= sizeof(VTOY_GPT_INFO
))
686 static int ventoy_mbr_need_update(ventoy_disk
*disk
, MBR_HEAD
*mbr
)
692 partition_style
= disk
->vtoydata
.partition_style
;
693 memcpy(mbr
, &(disk
->vtoydata
.gptinfo
.MBR
), 512);
695 VentoyGetLocalBootImg(&LocalMBR
);
696 memcpy(LocalMBR
.BootCode
+ 0x180, mbr
->BootCode
+ 0x180, 16);
699 LocalMBR
.BootCode
[92] = 0x22;
702 if (memcmp(LocalMBR
.BootCode
, mbr
->BootCode
, 440))
704 memcpy(mbr
->BootCode
, LocalMBR
.BootCode
, 440);
705 vlog("MBR boot code different, must update it.\n");
709 if (partition_style
== 0 && mbr
->PartTbl
[0].Active
== 0)
711 mbr
->PartTbl
[0].Active
= 0x80;
712 mbr
->PartTbl
[1].Active
= 0;
713 mbr
->PartTbl
[2].Active
= 0;
714 mbr
->PartTbl
[3].Active
= 0;
715 vlog("set MBR partition 1 active flag enabled\n");
722 static void * ventoy_update_thread(void *data
)
728 ventoy_disk
*disk
= NULL
;
729 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
730 VTOY_GPT_INFO
*pstGPT
= NULL
;
732 vdebug("ventoy_update_thread run ...\n");
737 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
738 vdebug("check disk %s\n", disk
->disk_name
);
739 if (ventoy_is_disk_mounted(disk
->disk_path
))
741 vlog("disk is mounted, now try to unmount it ...\n");
742 ventoy_try_umount_disk(disk
->disk_path
);
745 if (ventoy_is_disk_mounted(disk
->disk_path
))
747 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
752 vlog("disk is not mounted now, we can do continue ...\n");
755 g_current_progress
= PT_LOAD_CORE_IMG
;
756 ventoy_unxz_stg1_img();
758 g_current_progress
= PT_LOAD_DISK_IMG
;
759 ventoy_unxz_efipart_img();
761 g_current_progress
= PT_FORMAT_PART2
;
763 vlog("Formatting part2 EFI ...\n");
764 if (0 != ventoy_write_efipart(fd
, disk
->vtoydata
.part2_start_sector
* 512, thread
->secure_boot
))
766 vlog("Failed to format part2 efi ...\n");
770 g_current_progress
= PT_WRITE_STG1_IMG
;
772 vlog("Writing legacy grub ...\n");
773 if (0 != ventoy_write_legacy_grub(fd
, disk
->vtoydata
.partition_style
))
775 vlog("ventoy_write_legacy_grub failed ...\n");
779 offset
= lseek(fd
, 512 * 2040, SEEK_SET
);
780 len
= write(fd
, disk
->vtoydata
.rsvdata
, sizeof(disk
->vtoydata
.rsvdata
));
781 vlog("Writing reserve data offset:%llu len:%llu ...\n", (_ull
)offset
, (_ull
)len
);
783 if (ventoy_mbr_need_update(disk
, &MBR
))
785 offset
= lseek(fd
, 0, SEEK_SET
);
786 len
= write(fd
, &MBR
, 512);
787 vlog("update MBR offset:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
791 vlog("No need to update MBR\n");
795 if (disk
->vtoydata
.partition_style
)
797 pstGPT
= (VTOY_GPT_INFO
*)malloc(sizeof(VTOY_GPT_INFO
));
798 memset(pstGPT
, 0, sizeof(VTOY_GPT_INFO
));
800 offset
= lseek(fd
, 0, SEEK_SET
);
801 len
= read(fd
, pstGPT
, sizeof(VTOY_GPT_INFO
));
802 vlog("Read GPT table offset:%llu len:%llu ...\n", (_ull
)offset
, (_ull
)len
);
804 if (pstGPT
->PartTbl
[1].Attr
!= 0x8000000000000000ULL
)
806 vlog("Update EFI part attr from 0x%016llx to 0x%016llx\n",
807 pstGPT
->PartTbl
[1].Attr
, 0x8000000000000000ULL
);
809 pstGPT
->PartTbl
[1].Attr
= 0x8000000000000000ULL
;
810 pstGPT
->Head
.Crc
= 0;
811 pstGPT
->Head
.Crc
= ventoy_crc32(&(pstGPT
->Head
), pstGPT
->Head
.Length
);
812 ventoy_write_gpt_part_table(fd
, disk
->size_in_byte
, pstGPT
);
816 vlog("No need to update EFI part attr\n");
822 g_current_progress
= PT_SYNC_DATA1
;
824 vlog("fsync data1...\n");
826 vtoy_safe_close_fd(fd
);
828 g_current_progress
= PT_SYNC_DATA2
;
830 vlog("====================================\n");
831 vlog("====== ventoy update success ======\n");
832 vlog("====================================\n");
836 g_cur_process_result
= 1;
837 vtoy_safe_close_fd(fd
);
840 g_current_progress
= PT_FINISH
;
847 static void * ventoy_install_thread(void *data
)
853 ventoy_disk
*disk
= NULL
;
854 VTOY_GPT_INFO
*gpt
= NULL
;
855 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
856 uint64_t Part1StartSector
= 0;
857 uint64_t Part1SectorCount
= 0;
858 uint64_t Part2StartSector
= 0;
860 vdebug("ventoy_install_thread run ...\n");
865 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
866 vdebug("check disk %s\n", disk
->disk_name
);
867 if (ventoy_is_disk_mounted(disk
->disk_path
))
869 vlog("disk is mounted, now try to unmount it ...\n");
870 ventoy_try_umount_disk(disk
->disk_path
);
873 if (ventoy_is_disk_mounted(disk
->disk_path
))
875 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
880 vlog("disk is not mounted now, we can do continue ...\n");
883 g_current_progress
= PT_DEL_ALL_PART
;
884 ventoy_clean_disk(fd
, disk
->size_in_byte
);
886 g_current_progress
= PT_LOAD_CORE_IMG
;
887 ventoy_unxz_stg1_img();
889 g_current_progress
= PT_LOAD_DISK_IMG
;
890 ventoy_unxz_efipart_img();
892 if (thread
->partstyle
)
894 vdebug("Fill GPT part table\n");
895 gpt
= zalloc(sizeof(VTOY_GPT_INFO
));
896 ventoy_fill_gpt(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, gpt
);
897 Part1StartSector
= gpt
->PartTbl
[0].StartLBA
;
898 Part1SectorCount
= gpt
->PartTbl
[0].LastLBA
- Part1StartSector
+ 1;
899 Part2StartSector
= gpt
->PartTbl
[1].StartLBA
;
903 vdebug("Fill MBR part table\n");
904 ventoy_fill_mbr(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, &MBR
);
905 Part1StartSector
= MBR
.PartTbl
[0].StartSectorId
;
906 Part1SectorCount
= MBR
.PartTbl
[0].SectorCount
;
907 Part2StartSector
= MBR
.PartTbl
[1].StartSectorId
;
910 vlog("Part1StartSector:%llu Part1SectorCount:%llu Part2StartSector:%llu\n",
911 (_ull
)Part1StartSector
, (_ull
)Part1SectorCount
, (_ull
)Part2StartSector
);
913 if (thread
->partstyle
!= disk
->partstyle
)
915 vlog("Wait for format part1 (partstyle changed) ...\n");
919 g_current_progress
= PT_FORMAT_PART1
;
920 vlog("Formatting part1 exFAT %s ...\n", disk
->disk_path
);
921 if (0 != mkexfat_main(disk
->disk_path
, fd
, Part1SectorCount
))
923 vlog("Failed to format exfat ...\n");
927 g_current_progress
= PT_FORMAT_PART2
;
928 vlog("Formatting part2 EFI ...\n");
929 if (0 != ventoy_write_efipart(fd
, Part2StartSector
* 512, thread
->secure_boot
))
931 vlog("Failed to format part2 efi ...\n");
935 g_current_progress
= PT_WRITE_STG1_IMG
;
936 vlog("Writing legacy grub ...\n");
937 if (0 != ventoy_write_legacy_grub(fd
, thread
->partstyle
))
939 vlog("ventoy_write_legacy_grub failed ...\n");
943 g_current_progress
= PT_SYNC_DATA1
;
944 vlog("fsync data1...\n");
946 vtoy_safe_close_fd(fd
);
948 /* reopen for check part2 data */
949 vlog("Checking part2 efi data %s ...\n", disk
->disk_path
);
950 g_current_progress
= PT_CHECK_PART2
;
951 fd
= open(disk
->disk_path
, O_RDONLY
| O_BINARY
);
954 vlog("failed to open %s for check fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
958 if (0 == ventoy_check_efi_part_data(fd
, Part2StartSector
* 512))
960 vlog("efi part data check success\n");
964 vlog("efi part data check failed\n");
968 vtoy_safe_close_fd(fd
);
970 /* reopen for write part table */
971 g_current_progress
= PT_WRITE_PART_TABLE
;
972 vlog("Writting Partition Table style:%d...\n", thread
->partstyle
);
974 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
977 vlog("failed to open %s for part table fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
981 if (thread
->partstyle
)
983 ventoy_write_gpt_part_table(fd
, disk
->size_in_byte
, gpt
);
987 offset
= lseek(fd
, 0, SEEK_SET
);
988 len
= write(fd
, &MBR
, 512);
989 vlog("Writting MBR Partition Table %llu %llu\n", (_ull
)offset
, (_ull
)len
);
990 if (offset
!= 0 || len
!= 512)
996 g_current_progress
= PT_SYNC_DATA2
;
997 vlog("fsync data2...\n");
999 vtoy_safe_close_fd(fd
);
1002 vlog("====================================\n");
1003 vlog("====== ventoy install success ======\n");
1004 vlog("====================================\n");
1008 g_cur_process_result
= 1;
1009 vtoy_safe_close_fd(fd
);
1012 g_current_progress
= PT_FINISH
;
1020 static int ventoy_api_clean(struct mg_connection
*conn
, VTOY_JSON
*json
)
1024 ventoy_disk
*disk
= NULL
;
1025 const char *diskname
= NULL
;
1028 if (g_current_progress
!= PT_FINISH
)
1030 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1034 diskname
= vtoy_json_get_string_ex(json
, "disk");
1035 if (diskname
== NULL
)
1037 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1041 for (i
= 0; i
< g_disk_num
; i
++)
1043 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1045 disk
= g_disk_list
+ i
;
1052 vlog("disk %s not found\n", diskname
);
1053 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1057 scnprintf(path
, "/sys/block/%s", diskname
);
1058 if (access(path
, F_OK
) < 0)
1060 vlog("File %s not exist anymore\n", path
);
1061 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1065 vlog("==================================\n");
1066 vlog("===== ventoy clean %s =====\n", disk
->disk_path
);
1067 vlog("==================================\n");
1069 if (ventoy_is_disk_mounted(disk
->disk_path
))
1071 vlog("disk is mounted, now try to unmount it ...\n");
1072 ventoy_try_umount_disk(disk
->disk_path
);
1075 if (ventoy_is_disk_mounted(disk
->disk_path
))
1077 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1078 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1083 vlog("disk is not mounted now, we can do the clean ...\n");
1086 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1089 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1090 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1094 vdebug("start clean %s ...\n", disk
->disk_model
);
1095 ventoy_clean_disk(fd
, disk
->size_in_byte
);
1097 vtoy_safe_close_fd(fd
);
1099 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1103 static int ventoy_api_install(struct mg_connection
*conn
, VTOY_JSON
*json
)
1108 uint32_t align4kb
= 0;
1110 uint32_t secure_boot
= 0;
1111 uint64_t reserveBytes
= 0;
1112 ventoy_disk
*disk
= NULL
;
1113 const char *diskname
= NULL
;
1114 const char *reserve_space
= NULL
;
1115 ventoy_thread_data
*thread
= NULL
;
1118 if (g_current_progress
!= PT_FINISH
)
1120 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1124 diskname
= vtoy_json_get_string_ex(json
, "disk");
1125 reserve_space
= vtoy_json_get_string_ex(json
, "reserve_space");
1126 ret
+= vtoy_json_get_uint(json
, "partstyle", &style
);
1127 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1128 ret
+= vtoy_json_get_uint(json
, "align_4kb", &align4kb
);
1130 if (diskname
== NULL
|| reserve_space
== NULL
|| ret
!= JSON_SUCCESS
)
1132 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1136 reserveBytes
= (uint64_t)strtoull(reserve_space
, NULL
, 10);
1138 for (i
= 0; i
< g_disk_num
; i
++)
1140 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1142 disk
= g_disk_list
+ i
;
1149 vlog("disk %s not found\n", diskname
);
1150 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1156 vlog("disk %s is 4k native, not supported.\n", diskname
);
1157 ventoy_json_result(conn
, VTOY_JSON_4KN_RET
);
1161 scnprintf(path
, "/sys/block/%s", diskname
);
1162 if (access(path
, F_OK
) < 0)
1164 vlog("File %s not exist anymore\n", path
);
1165 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1169 if (disk
->size_in_byte
> 2199023255552ULL && style
== 0)
1171 vlog("disk %s is more than 2TB and GPT is needed\n", path
);
1172 ventoy_json_result(conn
, VTOY_JSON_MBR_2TB_RET
);
1176 if ((reserveBytes
+ VTOYEFI_PART_BYTES
* 2) > disk
->size_in_byte
)
1178 vlog("reserve space %llu is too big for disk %s %llu\n", (_ull
)reserveBytes
, path
, (_ull
)disk
->size_in_byte
);
1179 ventoy_json_result(conn
, VTOY_JSON_INVALID_RSV_RET
);
1183 vlog("==================================================================================\n");
1184 vlog("===== ventoy install %s style:%s secureboot:%u align4K:%u reserve:%llu =========\n",
1185 disk
->disk_path
, (style
? "GPT" : "MBR"), secure_boot
, align4kb
, (_ull
)reserveBytes
);
1186 vlog("==================================================================================\n");
1188 if (ventoy_is_disk_mounted(disk
->disk_path
))
1190 vlog("disk is mounted, now try to unmount it ...\n");
1191 ventoy_try_umount_disk(disk
->disk_path
);
1194 if (ventoy_is_disk_mounted(disk
->disk_path
))
1196 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1197 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1202 vlog("disk is not mounted now, we can do the install ...\n");
1205 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1208 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1209 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1213 vdebug("start install thread %s ...\n", disk
->disk_model
);
1214 thread
= zalloc(sizeof(ventoy_thread_data
));
1217 vtoy_safe_close_fd(fd
);
1218 vlog("failed to alloc thread data err:%d\n", errno
);
1219 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1223 g_current_progress
= PT_START
;
1224 g_cur_process_result
= 0;
1225 scnprintf(g_cur_process_type
, "%s", "install");
1226 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1228 thread
->disk
= disk
;
1229 thread
->diskfd
= fd
;
1230 thread
->align4kb
= align4kb
;
1231 thread
->partstyle
= style
;
1232 thread
->secure_boot
= secure_boot
;
1233 thread
->reserveBytes
= reserveBytes
;
1235 mg_start_thread(ventoy_install_thread
, thread
);
1237 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1241 static int ventoy_api_update(struct mg_connection
*conn
, VTOY_JSON
*json
)
1246 uint32_t secure_boot
= 0;
1247 ventoy_disk
*disk
= NULL
;
1248 const char *diskname
= NULL
;
1249 ventoy_thread_data
*thread
= NULL
;
1252 if (g_current_progress
!= PT_FINISH
)
1254 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1258 diskname
= vtoy_json_get_string_ex(json
, "disk");
1259 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1260 if (diskname
== NULL
|| ret
!= JSON_SUCCESS
)
1262 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1266 for (i
= 0; i
< g_disk_num
; i
++)
1268 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1270 disk
= g_disk_list
+ i
;
1277 vlog("disk %s not found\n", diskname
);
1278 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1282 if (disk
->vtoydata
.ventoy_valid
== 0)
1284 vlog("disk %s is not ventoy disk\n", diskname
);
1285 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1289 scnprintf(path
, "/sys/block/%s", diskname
);
1290 if (access(path
, F_OK
) < 0)
1292 vlog("File %s not exist anymore\n", path
);
1293 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1297 vlog("==========================================================\n");
1298 vlog("===== ventoy update %s new_secureboot:%u =========\n", disk
->disk_path
, secure_boot
);
1299 vlog("==========================================================\n");
1301 vlog("%s version:%s partstyle:%u oldsecureboot:%u reserve:%llu\n",
1302 disk
->disk_path
, disk
->vtoydata
.ventoy_ver
,
1303 disk
->vtoydata
.partition_style
,
1304 disk
->vtoydata
.secure_boot_flag
,
1305 (_ull
)(disk
->vtoydata
.preserved_space
)
1308 if (ventoy_is_disk_mounted(disk
->disk_path
))
1310 vlog("disk is mounted, now try to unmount it ...\n");
1311 ventoy_try_umount_disk(disk
->disk_path
);
1314 if (ventoy_is_disk_mounted(disk
->disk_path
))
1316 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1317 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1322 vlog("disk is not mounted now, we can do the update ...\n");
1325 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1328 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1329 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1333 vdebug("start update thread %s ...\n", disk
->disk_model
);
1334 thread
= zalloc(sizeof(ventoy_thread_data
));
1337 vtoy_safe_close_fd(fd
);
1338 vlog("failed to alloc thread data err:%d\n", errno
);
1339 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1343 g_current_progress
= PT_START
;
1344 g_cur_process_result
= 0;
1345 scnprintf(g_cur_process_type
, "%s", "update");
1346 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1348 thread
->disk
= disk
;
1349 thread
->diskfd
= fd
;
1350 thread
->secure_boot
= secure_boot
;
1352 mg_start_thread(ventoy_update_thread
, thread
);
1354 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1359 static int ventoy_api_refresh_device(struct mg_connection
*conn
, VTOY_JSON
*json
)
1363 if (g_current_progress
== PT_FINISH
)
1366 ventoy_disk_enumerate_all();
1369 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1373 static int ventoy_api_get_dev_list(struct mg_connection
*conn
, VTOY_JSON
*json
)
1379 uint32_t alldev
= 0;
1381 ventoy_disk
*cur
= NULL
;
1383 rc
= vtoy_json_get_uint(json
, "alldev", &alldev
);
1384 if (JSON_SUCCESS
!= rc
)
1389 buflen
= g_disk_num
* 1024;
1390 buf
= (char *)malloc(buflen
+ 1024);
1393 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1397 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
1398 VTOY_JSON_FMT_OBJ_BEGIN();
1399 VTOY_JSON_FMT_KEY("list");
1400 VTOY_JSON_FMT_ARY_BEGIN();
1402 for (i
= 0; i
< g_disk_num
; i
++)
1404 cur
= g_disk_list
+ i
;
1406 if (alldev
== 0 && cur
->type
!= VTOY_DEVICE_USB
)
1411 VTOY_JSON_FMT_OBJ_BEGIN();
1412 VTOY_JSON_FMT_STRN("name", cur
->disk_name
);
1413 VTOY_JSON_FMT_STRN("model", cur
->disk_model
);
1414 VTOY_JSON_FMT_STRN("size", cur
->human_readable_size
);
1415 VTOY_JSON_FMT_UINT("vtoy_valid", cur
->vtoydata
.ventoy_valid
);
1416 VTOY_JSON_FMT_STRN("vtoy_ver", cur
->vtoydata
.ventoy_ver
);
1417 VTOY_JSON_FMT_UINT("vtoy_secure_boot", cur
->vtoydata
.secure_boot_flag
);
1418 VTOY_JSON_FMT_UINT("vtoy_partstyle", cur
->vtoydata
.partition_style
);
1419 VTOY_JSON_FMT_OBJ_ENDEX();
1422 VTOY_JSON_FMT_ARY_END();
1423 VTOY_JSON_FMT_OBJ_END();
1424 VTOY_JSON_FMT_END(pos
);
1426 ventoy_json_buffer(conn
, buf
, pos
);
1430 static JSON_CB g_ventoy_json_cb
[] =
1432 { "sysinfo", ventoy_api_sysinfo
},
1433 { "sel_language", ventoy_api_set_language
},
1434 { "sel_partstyle", ventoy_api_set_partstyle
},
1435 { "refresh_device", ventoy_api_refresh_device
},
1436 { "get_dev_list", ventoy_api_get_dev_list
},
1437 { "install", ventoy_api_install
},
1438 { "update", ventoy_api_update
},
1439 { "clean", ventoy_api_clean
},
1440 { "get_percent", ventoy_api_get_percent
},
1443 static int ventoy_json_handler(struct mg_connection
*conn
, VTOY_JSON
*json
)
1446 const char *token
= NULL
;
1447 const char *method
= NULL
;
1449 method
= vtoy_json_get_string_ex(json
, "method");
1452 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1456 if (strcmp(method
, "sysinfo"))
1458 token
= vtoy_json_get_string_ex(json
, "token");
1459 if (token
== NULL
|| strcmp(token
, g_cur_server_token
))
1461 ventoy_json_result(conn
, VTOY_JSON_TOKEN_ERR_RET
);
1466 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1468 if (strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1470 g_ventoy_json_cb
[i
].callback(conn
, json
);
1478 int ventoy_func_handler(const char *jsonstr
, char *jsonbuf
, int buflen
)
1481 const char *method
= NULL
;
1482 VTOY_JSON
*json
= NULL
;
1484 g_pub_out_buf
= jsonbuf
;
1485 g_pub_out_max
= buflen
;
1487 json
= vtoy_json_create();
1488 if (JSON_SUCCESS
== vtoy_json_parse(json
, jsonstr
))
1490 pthread_mutex_lock(&g_api_mutex
);
1492 method
= vtoy_json_get_string_ex(json
->pstChild
, "method");
1493 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1495 if (method
&& strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1497 g_ventoy_json_cb
[i
].callback(NULL
, json
->pstChild
);
1502 pthread_mutex_unlock(&g_api_mutex
);
1506 ventoy_json_result(NULL
, VTOY_JSON_INVALID_RET
);
1509 vtoy_json_destroy(json
);
1513 static int ventoy_request_handler(struct mg_connection
*conn
)
1517 VTOY_JSON
*json
= NULL
;
1518 char *post_data_buf
= NULL
;
1519 const struct mg_request_info
*ri
= NULL
;
1520 char stack_buf
[512];
1522 ri
= mg_get_request_info(conn
);
1524 if (strcmp(ri
->uri
, "/vtoy/json") == 0)
1526 if (ri
->content_length
> 500)
1528 post_data_buf
= malloc(ri
->content_length
+ 4);
1529 post_buf_len
= ri
->content_length
+ 1;
1533 post_data_buf
= stack_buf
;
1534 post_buf_len
= sizeof(stack_buf
);
1537 post_data_len
= mg_read(conn
, post_data_buf
, post_buf_len
);
1538 post_data_buf
[post_data_len
] = 0;
1540 json
= vtoy_json_create();
1541 if (JSON_SUCCESS
== vtoy_json_parse(json
, post_data_buf
))
1543 pthread_mutex_lock(&g_api_mutex
);
1544 ventoy_json_handler(conn
, json
->pstChild
);
1545 pthread_mutex_unlock(&g_api_mutex
);
1549 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1552 vtoy_json_destroy(json
);
1554 if (post_data_buf
!= stack_buf
)
1556 free(post_data_buf
);
1566 int ventoy_http_start(const char *ip
, const char *port
)
1570 struct mg_callbacks callbacks
;
1571 const char *options
[] =
1573 "listening_ports", "24680",
1574 "document_root", "WebUI",
1575 "error_log_file", g_log_file
,
1576 "request_timeout_ms", "10000",
1581 ventoy_gen_preudo_uuid(uuid
);
1582 scnprintf(g_cur_server_token
, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1583 uuid
[0], uuid
[1], uuid
[2], uuid
[3], uuid
[4], uuid
[5], uuid
[6], uuid
[7],
1584 uuid
[8], uuid
[9], uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
1587 scnprintf(addr
, "%s:%s", ip
, port
);
1590 memset(&callbacks
, 0, sizeof(callbacks
));
1591 callbacks
.begin_request
= ventoy_request_handler
;
1592 g_ventoy_http_ctx
= mg_start(&callbacks
, NULL
, options
);
1594 return g_ventoy_http_ctx
? 0 : 1;
1597 int ventoy_http_stop(void)
1599 if (g_ventoy_http_ctx
)
1601 mg_stop(g_ventoy_http_ctx
);
1606 int ventoy_http_init(void)
1608 pthread_mutex_init(&g_api_mutex
, NULL
);
1610 ventoy_http_load_cfg();
1612 ventoy_load_mbr_template();
1617 void ventoy_http_exit(void)
1619 pthread_mutex_destroy(&g_api_mutex
);
1621 check_free(g_efi_part_raw_img
);
1622 g_efi_part_raw_img
= NULL
;
1626 const char * ventoy_code_get_cur_language(void)
1628 return g_cur_language
;
1631 int ventoy_code_get_cur_part_style(void)
1633 return g_cur_part_style
;
1636 void ventoy_code_set_cur_part_style(int style
)
1638 pthread_mutex_lock(&g_api_mutex
);
1640 g_cur_part_style
= style
;
1641 ventoy_http_save_cfg();
1643 pthread_mutex_unlock(&g_api_mutex
);
1646 int ventoy_code_get_cur_show_all(void)
1648 return g_cur_show_all
;
1651 void ventoy_code_set_cur_show_all(int show_all
)
1653 pthread_mutex_lock(&g_api_mutex
);
1655 g_cur_show_all
= show_all
;
1656 ventoy_http_save_cfg();
1658 pthread_mutex_unlock(&g_api_mutex
);
1661 void ventoy_code_set_cur_language(const char *lang
)
1663 pthread_mutex_lock(&g_api_mutex
);
1665 scnprintf(g_cur_language
, "%s", lang
);
1666 ventoy_http_save_cfg();
1668 pthread_mutex_unlock(&g_api_mutex
);
1671 void ventoy_code_refresh_device(void)
1673 if (g_current_progress
== PT_FINISH
)
1676 ventoy_disk_enumerate_all();
1680 int ventoy_code_is_busy(void)
1682 return (g_current_progress
== PT_FINISH
) ? 0 : 1;
1685 int ventoy_code_get_percent(void)
1687 return g_current_progress
* 100 / PT_FINISH
;
1690 int ventoy_code_get_result(void)
1692 return g_cur_process_result
;
1695 void ventoy_code_save_cfg(void)
1697 ventoy_http_save_cfg();