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
;
811 pstGPT
->Head
.PartTblCrc
= ventoy_crc32(pstGPT
->PartTbl
, sizeof(pstGPT
->PartTbl
));
812 pstGPT
->Head
.Crc
= 0;
813 pstGPT
->Head
.Crc
= ventoy_crc32(&(pstGPT
->Head
), pstGPT
->Head
.Length
);
814 ventoy_write_gpt_part_table(fd
, disk
->size_in_byte
, pstGPT
);
818 vlog("No need to update EFI part attr\n");
824 g_current_progress
= PT_SYNC_DATA1
;
826 vlog("fsync data1...\n");
828 vtoy_safe_close_fd(fd
);
830 g_current_progress
= PT_SYNC_DATA2
;
832 vlog("====================================\n");
833 vlog("====== ventoy update success ======\n");
834 vlog("====================================\n");
838 g_cur_process_result
= 1;
839 vtoy_safe_close_fd(fd
);
842 g_current_progress
= PT_FINISH
;
849 static void * ventoy_install_thread(void *data
)
855 ventoy_disk
*disk
= NULL
;
856 VTOY_GPT_INFO
*gpt
= NULL
;
857 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
858 uint64_t Part1StartSector
= 0;
859 uint64_t Part1SectorCount
= 0;
860 uint64_t Part2StartSector
= 0;
862 vdebug("ventoy_install_thread run ...\n");
867 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
868 vdebug("check disk %s\n", disk
->disk_name
);
869 if (ventoy_is_disk_mounted(disk
->disk_path
))
871 vlog("disk is mounted, now try to unmount it ...\n");
872 ventoy_try_umount_disk(disk
->disk_path
);
875 if (ventoy_is_disk_mounted(disk
->disk_path
))
877 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
882 vlog("disk is not mounted now, we can do continue ...\n");
885 g_current_progress
= PT_DEL_ALL_PART
;
886 ventoy_clean_disk(fd
, disk
->size_in_byte
);
888 g_current_progress
= PT_LOAD_CORE_IMG
;
889 ventoy_unxz_stg1_img();
891 g_current_progress
= PT_LOAD_DISK_IMG
;
892 ventoy_unxz_efipart_img();
894 if (thread
->partstyle
)
896 vdebug("Fill GPT part table\n");
897 gpt
= zalloc(sizeof(VTOY_GPT_INFO
));
898 ventoy_fill_gpt(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, gpt
);
899 Part1StartSector
= gpt
->PartTbl
[0].StartLBA
;
900 Part1SectorCount
= gpt
->PartTbl
[0].LastLBA
- Part1StartSector
+ 1;
901 Part2StartSector
= gpt
->PartTbl
[1].StartLBA
;
905 vdebug("Fill MBR part table\n");
906 ventoy_fill_mbr(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, &MBR
);
907 Part1StartSector
= MBR
.PartTbl
[0].StartSectorId
;
908 Part1SectorCount
= MBR
.PartTbl
[0].SectorCount
;
909 Part2StartSector
= MBR
.PartTbl
[1].StartSectorId
;
912 vlog("Part1StartSector:%llu Part1SectorCount:%llu Part2StartSector:%llu\n",
913 (_ull
)Part1StartSector
, (_ull
)Part1SectorCount
, (_ull
)Part2StartSector
);
915 if (thread
->partstyle
!= disk
->partstyle
)
917 vlog("Wait for format part1 (partstyle changed) ...\n");
921 g_current_progress
= PT_FORMAT_PART1
;
922 vlog("Formatting part1 exFAT %s ...\n", disk
->disk_path
);
923 if (0 != mkexfat_main(disk
->disk_path
, fd
, Part1SectorCount
))
925 vlog("Failed to format exfat ...\n");
929 g_current_progress
= PT_FORMAT_PART2
;
930 vlog("Formatting part2 EFI ...\n");
931 if (0 != ventoy_write_efipart(fd
, Part2StartSector
* 512, thread
->secure_boot
))
933 vlog("Failed to format part2 efi ...\n");
937 g_current_progress
= PT_WRITE_STG1_IMG
;
938 vlog("Writing legacy grub ...\n");
939 if (0 != ventoy_write_legacy_grub(fd
, thread
->partstyle
))
941 vlog("ventoy_write_legacy_grub failed ...\n");
945 g_current_progress
= PT_SYNC_DATA1
;
946 vlog("fsync data1...\n");
948 vtoy_safe_close_fd(fd
);
950 /* reopen for check part2 data */
951 vlog("Checking part2 efi data %s ...\n", disk
->disk_path
);
952 g_current_progress
= PT_CHECK_PART2
;
953 fd
= open(disk
->disk_path
, O_RDONLY
| O_BINARY
);
956 vlog("failed to open %s for check fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
960 if (0 == ventoy_check_efi_part_data(fd
, Part2StartSector
* 512))
962 vlog("efi part data check success\n");
966 vlog("efi part data check failed\n");
970 vtoy_safe_close_fd(fd
);
972 /* reopen for write part table */
973 g_current_progress
= PT_WRITE_PART_TABLE
;
974 vlog("Writting Partition Table style:%d...\n", thread
->partstyle
);
976 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
979 vlog("failed to open %s for part table fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
983 if (thread
->partstyle
)
985 ventoy_write_gpt_part_table(fd
, disk
->size_in_byte
, gpt
);
989 offset
= lseek(fd
, 0, SEEK_SET
);
990 len
= write(fd
, &MBR
, 512);
991 vlog("Writting MBR Partition Table %llu %llu\n", (_ull
)offset
, (_ull
)len
);
992 if (offset
!= 0 || len
!= 512)
998 g_current_progress
= PT_SYNC_DATA2
;
999 vlog("fsync data2...\n");
1001 vtoy_safe_close_fd(fd
);
1004 vlog("====================================\n");
1005 vlog("====== ventoy install success ======\n");
1006 vlog("====================================\n");
1010 g_cur_process_result
= 1;
1011 vtoy_safe_close_fd(fd
);
1014 g_current_progress
= PT_FINISH
;
1022 static int ventoy_api_clean(struct mg_connection
*conn
, VTOY_JSON
*json
)
1026 ventoy_disk
*disk
= NULL
;
1027 const char *diskname
= NULL
;
1030 if (g_current_progress
!= PT_FINISH
)
1032 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1036 diskname
= vtoy_json_get_string_ex(json
, "disk");
1037 if (diskname
== NULL
)
1039 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1043 for (i
= 0; i
< g_disk_num
; i
++)
1045 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1047 disk
= g_disk_list
+ i
;
1054 vlog("disk %s not found\n", diskname
);
1055 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1059 scnprintf(path
, "/sys/block/%s", diskname
);
1060 if (access(path
, F_OK
) < 0)
1062 vlog("File %s not exist anymore\n", path
);
1063 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1067 vlog("==================================\n");
1068 vlog("===== ventoy clean %s =====\n", disk
->disk_path
);
1069 vlog("==================================\n");
1071 if (ventoy_is_disk_mounted(disk
->disk_path
))
1073 vlog("disk is mounted, now try to unmount it ...\n");
1074 ventoy_try_umount_disk(disk
->disk_path
);
1077 if (ventoy_is_disk_mounted(disk
->disk_path
))
1079 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1080 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1085 vlog("disk is not mounted now, we can do the clean ...\n");
1088 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1091 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1092 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1096 vdebug("start clean %s ...\n", disk
->disk_model
);
1097 ventoy_clean_disk(fd
, disk
->size_in_byte
);
1099 vtoy_safe_close_fd(fd
);
1101 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1105 static int ventoy_api_install(struct mg_connection
*conn
, VTOY_JSON
*json
)
1110 uint32_t align4kb
= 0;
1112 uint32_t secure_boot
= 0;
1113 uint64_t reserveBytes
= 0;
1114 ventoy_disk
*disk
= NULL
;
1115 const char *diskname
= NULL
;
1116 const char *reserve_space
= NULL
;
1117 ventoy_thread_data
*thread
= NULL
;
1120 if (g_current_progress
!= PT_FINISH
)
1122 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1126 diskname
= vtoy_json_get_string_ex(json
, "disk");
1127 reserve_space
= vtoy_json_get_string_ex(json
, "reserve_space");
1128 ret
+= vtoy_json_get_uint(json
, "partstyle", &style
);
1129 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1130 ret
+= vtoy_json_get_uint(json
, "align_4kb", &align4kb
);
1132 if (diskname
== NULL
|| reserve_space
== NULL
|| ret
!= JSON_SUCCESS
)
1134 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1138 reserveBytes
= (uint64_t)strtoull(reserve_space
, NULL
, 10);
1140 for (i
= 0; i
< g_disk_num
; i
++)
1142 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1144 disk
= g_disk_list
+ i
;
1151 vlog("disk %s not found\n", diskname
);
1152 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1158 vlog("disk %s is 4k native, not supported.\n", diskname
);
1159 ventoy_json_result(conn
, VTOY_JSON_4KN_RET
);
1163 scnprintf(path
, "/sys/block/%s", diskname
);
1164 if (access(path
, F_OK
) < 0)
1166 vlog("File %s not exist anymore\n", path
);
1167 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1171 if (disk
->size_in_byte
> 2199023255552ULL && style
== 0)
1173 vlog("disk %s is more than 2TB and GPT is needed\n", path
);
1174 ventoy_json_result(conn
, VTOY_JSON_MBR_2TB_RET
);
1178 if ((reserveBytes
+ VTOYEFI_PART_BYTES
* 2) > disk
->size_in_byte
)
1180 vlog("reserve space %llu is too big for disk %s %llu\n", (_ull
)reserveBytes
, path
, (_ull
)disk
->size_in_byte
);
1181 ventoy_json_result(conn
, VTOY_JSON_INVALID_RSV_RET
);
1185 vlog("==================================================================================\n");
1186 vlog("===== ventoy install %s style:%s secureboot:%u align4K:%u reserve:%llu =========\n",
1187 disk
->disk_path
, (style
? "GPT" : "MBR"), secure_boot
, align4kb
, (_ull
)reserveBytes
);
1188 vlog("==================================================================================\n");
1190 if (ventoy_is_disk_mounted(disk
->disk_path
))
1192 vlog("disk is mounted, now try to unmount it ...\n");
1193 ventoy_try_umount_disk(disk
->disk_path
);
1196 if (ventoy_is_disk_mounted(disk
->disk_path
))
1198 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1199 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1204 vlog("disk is not mounted now, we can do the install ...\n");
1207 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1210 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1211 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1215 vdebug("start install thread %s ...\n", disk
->disk_model
);
1216 thread
= zalloc(sizeof(ventoy_thread_data
));
1219 vtoy_safe_close_fd(fd
);
1220 vlog("failed to alloc thread data err:%d\n", errno
);
1221 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1225 g_current_progress
= PT_START
;
1226 g_cur_process_result
= 0;
1227 scnprintf(g_cur_process_type
, "%s", "install");
1228 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1230 thread
->disk
= disk
;
1231 thread
->diskfd
= fd
;
1232 thread
->align4kb
= align4kb
;
1233 thread
->partstyle
= style
;
1234 thread
->secure_boot
= secure_boot
;
1235 thread
->reserveBytes
= reserveBytes
;
1237 mg_start_thread(ventoy_install_thread
, thread
);
1239 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1243 static int ventoy_api_update(struct mg_connection
*conn
, VTOY_JSON
*json
)
1248 uint32_t secure_boot
= 0;
1249 ventoy_disk
*disk
= NULL
;
1250 const char *diskname
= NULL
;
1251 ventoy_thread_data
*thread
= NULL
;
1254 if (g_current_progress
!= PT_FINISH
)
1256 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1260 diskname
= vtoy_json_get_string_ex(json
, "disk");
1261 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1262 if (diskname
== NULL
|| ret
!= JSON_SUCCESS
)
1264 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1268 for (i
= 0; i
< g_disk_num
; i
++)
1270 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1272 disk
= g_disk_list
+ i
;
1279 vlog("disk %s not found\n", diskname
);
1280 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1284 if (disk
->vtoydata
.ventoy_valid
== 0)
1286 vlog("disk %s is not ventoy disk\n", diskname
);
1287 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1291 scnprintf(path
, "/sys/block/%s", diskname
);
1292 if (access(path
, F_OK
) < 0)
1294 vlog("File %s not exist anymore\n", path
);
1295 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1299 vlog("==========================================================\n");
1300 vlog("===== ventoy update %s new_secureboot:%u =========\n", disk
->disk_path
, secure_boot
);
1301 vlog("==========================================================\n");
1303 vlog("%s version:%s partstyle:%u oldsecureboot:%u reserve:%llu\n",
1304 disk
->disk_path
, disk
->vtoydata
.ventoy_ver
,
1305 disk
->vtoydata
.partition_style
,
1306 disk
->vtoydata
.secure_boot_flag
,
1307 (_ull
)(disk
->vtoydata
.preserved_space
)
1310 if (ventoy_is_disk_mounted(disk
->disk_path
))
1312 vlog("disk is mounted, now try to unmount it ...\n");
1313 ventoy_try_umount_disk(disk
->disk_path
);
1316 if (ventoy_is_disk_mounted(disk
->disk_path
))
1318 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1319 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1324 vlog("disk is not mounted now, we can do the update ...\n");
1327 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1330 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1331 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1335 vdebug("start update thread %s ...\n", disk
->disk_model
);
1336 thread
= zalloc(sizeof(ventoy_thread_data
));
1339 vtoy_safe_close_fd(fd
);
1340 vlog("failed to alloc thread data err:%d\n", errno
);
1341 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1345 g_current_progress
= PT_START
;
1346 g_cur_process_result
= 0;
1347 scnprintf(g_cur_process_type
, "%s", "update");
1348 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1350 thread
->disk
= disk
;
1351 thread
->diskfd
= fd
;
1352 thread
->secure_boot
= secure_boot
;
1354 mg_start_thread(ventoy_update_thread
, thread
);
1356 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1361 static int ventoy_api_refresh_device(struct mg_connection
*conn
, VTOY_JSON
*json
)
1365 if (g_current_progress
== PT_FINISH
)
1368 ventoy_disk_enumerate_all();
1371 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1375 static int ventoy_api_get_dev_list(struct mg_connection
*conn
, VTOY_JSON
*json
)
1381 uint32_t alldev
= 0;
1383 ventoy_disk
*cur
= NULL
;
1385 rc
= vtoy_json_get_uint(json
, "alldev", &alldev
);
1386 if (JSON_SUCCESS
!= rc
)
1391 buflen
= g_disk_num
* 1024;
1392 buf
= (char *)malloc(buflen
+ 1024);
1395 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1399 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
1400 VTOY_JSON_FMT_OBJ_BEGIN();
1401 VTOY_JSON_FMT_KEY("list");
1402 VTOY_JSON_FMT_ARY_BEGIN();
1404 for (i
= 0; i
< g_disk_num
; i
++)
1406 cur
= g_disk_list
+ i
;
1408 if (alldev
== 0 && cur
->type
!= VTOY_DEVICE_USB
)
1413 VTOY_JSON_FMT_OBJ_BEGIN();
1414 VTOY_JSON_FMT_STRN("name", cur
->disk_name
);
1415 VTOY_JSON_FMT_STRN("model", cur
->disk_model
);
1416 VTOY_JSON_FMT_STRN("size", cur
->human_readable_size
);
1417 VTOY_JSON_FMT_UINT("vtoy_valid", cur
->vtoydata
.ventoy_valid
);
1418 VTOY_JSON_FMT_STRN("vtoy_ver", cur
->vtoydata
.ventoy_ver
);
1419 VTOY_JSON_FMT_UINT("vtoy_secure_boot", cur
->vtoydata
.secure_boot_flag
);
1420 VTOY_JSON_FMT_UINT("vtoy_partstyle", cur
->vtoydata
.partition_style
);
1421 VTOY_JSON_FMT_OBJ_ENDEX();
1424 VTOY_JSON_FMT_ARY_END();
1425 VTOY_JSON_FMT_OBJ_END();
1426 VTOY_JSON_FMT_END(pos
);
1428 ventoy_json_buffer(conn
, buf
, pos
);
1432 static JSON_CB g_ventoy_json_cb
[] =
1434 { "sysinfo", ventoy_api_sysinfo
},
1435 { "sel_language", ventoy_api_set_language
},
1436 { "sel_partstyle", ventoy_api_set_partstyle
},
1437 { "refresh_device", ventoy_api_refresh_device
},
1438 { "get_dev_list", ventoy_api_get_dev_list
},
1439 { "install", ventoy_api_install
},
1440 { "update", ventoy_api_update
},
1441 { "clean", ventoy_api_clean
},
1442 { "get_percent", ventoy_api_get_percent
},
1445 static int ventoy_json_handler(struct mg_connection
*conn
, VTOY_JSON
*json
)
1448 const char *token
= NULL
;
1449 const char *method
= NULL
;
1451 method
= vtoy_json_get_string_ex(json
, "method");
1454 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1458 if (strcmp(method
, "sysinfo"))
1460 token
= vtoy_json_get_string_ex(json
, "token");
1461 if (token
== NULL
|| strcmp(token
, g_cur_server_token
))
1463 ventoy_json_result(conn
, VTOY_JSON_TOKEN_ERR_RET
);
1468 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1470 if (strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1472 g_ventoy_json_cb
[i
].callback(conn
, json
);
1480 int ventoy_func_handler(const char *jsonstr
, char *jsonbuf
, int buflen
)
1483 const char *method
= NULL
;
1484 VTOY_JSON
*json
= NULL
;
1486 g_pub_out_buf
= jsonbuf
;
1487 g_pub_out_max
= buflen
;
1489 json
= vtoy_json_create();
1490 if (JSON_SUCCESS
== vtoy_json_parse(json
, jsonstr
))
1492 pthread_mutex_lock(&g_api_mutex
);
1494 method
= vtoy_json_get_string_ex(json
->pstChild
, "method");
1495 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1497 if (method
&& strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1499 g_ventoy_json_cb
[i
].callback(NULL
, json
->pstChild
);
1504 pthread_mutex_unlock(&g_api_mutex
);
1508 ventoy_json_result(NULL
, VTOY_JSON_INVALID_RET
);
1511 vtoy_json_destroy(json
);
1515 static int ventoy_request_handler(struct mg_connection
*conn
)
1519 VTOY_JSON
*json
= NULL
;
1520 char *post_data_buf
= NULL
;
1521 const struct mg_request_info
*ri
= NULL
;
1522 char stack_buf
[512];
1524 ri
= mg_get_request_info(conn
);
1526 if (strcmp(ri
->uri
, "/vtoy/json") == 0)
1528 if (ri
->content_length
> 500)
1530 post_data_buf
= malloc(ri
->content_length
+ 4);
1531 post_buf_len
= ri
->content_length
+ 1;
1535 post_data_buf
= stack_buf
;
1536 post_buf_len
= sizeof(stack_buf
);
1539 post_data_len
= mg_read(conn
, post_data_buf
, post_buf_len
);
1540 post_data_buf
[post_data_len
] = 0;
1542 json
= vtoy_json_create();
1543 if (JSON_SUCCESS
== vtoy_json_parse(json
, post_data_buf
))
1545 pthread_mutex_lock(&g_api_mutex
);
1546 ventoy_json_handler(conn
, json
->pstChild
);
1547 pthread_mutex_unlock(&g_api_mutex
);
1551 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1554 vtoy_json_destroy(json
);
1556 if (post_data_buf
!= stack_buf
)
1558 free(post_data_buf
);
1568 int ventoy_http_start(const char *ip
, const char *port
)
1572 struct mg_callbacks callbacks
;
1573 const char *options
[] =
1575 "listening_ports", "24680",
1576 "document_root", "WebUI",
1577 "error_log_file", g_log_file
,
1578 "request_timeout_ms", "10000",
1583 ventoy_gen_preudo_uuid(uuid
);
1584 scnprintf(g_cur_server_token
, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1585 uuid
[0], uuid
[1], uuid
[2], uuid
[3], uuid
[4], uuid
[5], uuid
[6], uuid
[7],
1586 uuid
[8], uuid
[9], uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
1589 scnprintf(addr
, "%s:%s", ip
, port
);
1592 memset(&callbacks
, 0, sizeof(callbacks
));
1593 callbacks
.begin_request
= ventoy_request_handler
;
1594 g_ventoy_http_ctx
= mg_start(&callbacks
, NULL
, options
);
1596 return g_ventoy_http_ctx
? 0 : 1;
1599 int ventoy_http_stop(void)
1601 if (g_ventoy_http_ctx
)
1603 mg_stop(g_ventoy_http_ctx
);
1608 int ventoy_http_init(void)
1610 pthread_mutex_init(&g_api_mutex
, NULL
);
1612 ventoy_http_load_cfg();
1614 ventoy_load_mbr_template();
1619 void ventoy_http_exit(void)
1621 pthread_mutex_destroy(&g_api_mutex
);
1623 check_free(g_efi_part_raw_img
);
1624 g_efi_part_raw_img
= NULL
;
1628 const char * ventoy_code_get_cur_language(void)
1630 return g_cur_language
;
1633 int ventoy_code_get_cur_part_style(void)
1635 return g_cur_part_style
;
1638 void ventoy_code_set_cur_part_style(int style
)
1640 pthread_mutex_lock(&g_api_mutex
);
1642 g_cur_part_style
= style
;
1643 ventoy_http_save_cfg();
1645 pthread_mutex_unlock(&g_api_mutex
);
1648 int ventoy_code_get_cur_show_all(void)
1650 return g_cur_show_all
;
1653 void ventoy_code_set_cur_show_all(int show_all
)
1655 pthread_mutex_lock(&g_api_mutex
);
1657 g_cur_show_all
= show_all
;
1658 ventoy_http_save_cfg();
1660 pthread_mutex_unlock(&g_api_mutex
);
1663 void ventoy_code_set_cur_language(const char *lang
)
1665 pthread_mutex_lock(&g_api_mutex
);
1667 scnprintf(g_cur_language
, "%s", lang
);
1668 ventoy_http_save_cfg();
1670 pthread_mutex_unlock(&g_api_mutex
);
1673 void ventoy_code_refresh_device(void)
1675 if (g_current_progress
== PT_FINISH
)
1678 ventoy_disk_enumerate_all();
1682 int ventoy_code_is_busy(void)
1684 return (g_current_progress
== PT_FINISH
) ? 0 : 1;
1687 int ventoy_code_get_percent(void)
1689 return g_current_progress
* 100 / PT_FINISH
;
1692 int ventoy_code_get_result(void)
1694 return g_cur_process_result
;
1697 void ventoy_code_save_cfg(void)
1699 ventoy_http_save_cfg();