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 pthread_mutex_t g_api_mutex
;
44 static char g_cur_language
[128];
45 static int g_cur_part_style
= 0;
46 static char g_cur_server_token
[64];
47 static struct mg_context
*g_ventoy_http_ctx
= NULL
;
49 static uint32_t g_efi_part_offset
= 0;
50 static uint8_t *g_efi_part_raw_img
= NULL
;
51 static uint8_t *g_grub_stg1_raw_img
= NULL
;
53 static char g_cur_process_diskname
[64];
54 static char g_cur_process_type
[64];
55 static int g_cur_process_result
= 0;
56 static PROGRESS_POINT g_current_progress
= PT_FINISH
;
58 static int ventoy_load_mbr_template(void)
62 fp
= fopen("boot/boot.img", "rb");
65 vlog("Failed to open file boot/boot.img\n");
69 fread(g_mbr_template
, 1, 512, fp
);
72 ventoy_gen_preudo_uuid(g_mbr_template
+ 0x180);
76 static int ventoy_disk_xz_flush(void *src
, unsigned int size
)
78 memcpy(g_efi_part_raw_img
+ g_efi_part_offset
, src
, size
);
79 g_efi_part_offset
+= size
;
81 g_current_progress
= PT_LOAD_DISK_IMG
+ (g_efi_part_offset
/ SIZE_1MB
);
85 static int ventoy_unxz_efipart_img(void)
93 rc
= ventoy_read_file_to_buf(VENTOY_FILE_DISK_IMG
, 0, &xzbuf
, &xzlen
);
94 vdebug("read disk.img.xz rc:%d len:%d\n", rc
, xzlen
);
96 if (g_efi_part_raw_img
)
98 buf
= g_efi_part_raw_img
;
102 buf
= malloc(VTOYEFI_PART_BYTES
);
110 g_efi_part_offset
= 0;
111 g_efi_part_raw_img
= buf
;
113 rc
= unxz(xzbuf
, xzlen
, NULL
, ventoy_disk_xz_flush
, buf
, &inlen
, NULL
);
114 vdebug("ventoy_unxz_efipart_img len:%d rc:%d unxzlen:%u\n", inlen
, rc
, g_efi_part_offset
);
120 static int ventoy_unxz_stg1_img(void)
128 rc
= ventoy_read_file_to_buf(VENTOY_FILE_STG1_IMG
, 0, &xzbuf
, &xzlen
);
129 vdebug("read core.img.xz rc:%d len:%d\n", rc
, xzlen
);
131 if (g_grub_stg1_raw_img
)
133 buf
= g_grub_stg1_raw_img
;
137 buf
= zalloc(SIZE_1MB
);
145 rc
= unxz(xzbuf
, xzlen
, NULL
, NULL
, buf
, &inlen
, NULL
);
146 vdebug("ventoy_unxz_stg1_img len:%d rc:%d\n", inlen
, rc
);
148 g_grub_stg1_raw_img
= buf
;
155 static int ventoy_http_save_cfg(void)
159 fp
= fopen("./Ventoy2Disk.ini", "w");
165 fprintf(fp
, "[Ventoy]\nLanguage=%s\nPartStyle=%d\n", g_cur_language
, g_cur_part_style
);
171 static int ventoy_http_load_cfg(void)
178 fp
= fopen("./Ventoy2Disk.ini", "r");
184 while (fgets(line
, sizeof(line
), fp
))
186 len
= (int)strlen(line
);
187 for (i
= len
- 1; i
>= 0; i
--)
189 if (line
[i
] == ' ' || line
[i
] == '\t' || line
[i
] == '\r' || line
[i
] == '\n')
199 len
= (int)strlen("Language=");
200 if (strncmp(line
, "Language=", len
) == 0)
202 scnprintf(g_cur_language
, "%s", line
+ len
);
204 else if (strncmp(line
, "PartStyle=", strlen("PartStyle=")) == 0)
206 g_cur_part_style
= (int)strtol(line
+ strlen("PartStyle="), NULL
, 10);
215 static int ventoy_json_result(struct mg_connection
*conn
, const char *err
)
218 "HTTP/1.1 200 OK \r\n"
219 "Content-Type: application/json\r\n"
220 "Content-Length: %d\r\n"
222 (int)strlen(err
), err
);
226 static int ventoy_json_buffer(struct mg_connection
*conn
, const char *json_buf
, int json_len
)
229 "HTTP/1.1 200 OK \r\n"
230 "Content-Type: application/json\r\n"
231 "Content-Length: %d\r\n"
237 static int ventoy_api_sysinfo(struct mg_connection
*conn
, VTOY_JSON
*json
)
246 busy
= (g_current_progress
== PT_FINISH
) ? 0 : 1;
248 buflen
= sizeof(buf
) - 1;
249 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
250 VTOY_JSON_FMT_OBJ_BEGIN();
251 VTOY_JSON_FMT_STRN("token", g_cur_server_token
);
252 VTOY_JSON_FMT_STRN("language", g_cur_language
);
253 VTOY_JSON_FMT_STRN("ventoy_ver", ventoy_get_local_version());
254 VTOY_JSON_FMT_UINT("partstyle", g_cur_part_style
);
255 VTOY_JSON_FMT_BOOL("busy", busy
);
256 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname
);
257 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type
);
258 VTOY_JSON_FMT_OBJ_END();
259 VTOY_JSON_FMT_END(pos
);
261 ventoy_json_buffer(conn
, buf
, pos
);
265 static int ventoy_api_get_percent(struct mg_connection
*conn
, VTOY_JSON
*json
)
274 percent
= g_current_progress
* 100 / PT_FINISH
;
276 buflen
= sizeof(buf
) - 1;
277 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
278 VTOY_JSON_FMT_OBJ_BEGIN();
279 VTOY_JSON_FMT_STRN("result", g_cur_process_result
? "failed" : "success");
280 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname
);
281 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type
);
282 VTOY_JSON_FMT_UINT("percent", percent
);
283 VTOY_JSON_FMT_OBJ_END();
284 VTOY_JSON_FMT_END(pos
);
286 ventoy_json_buffer(conn
, buf
, pos
);
290 static int ventoy_api_set_language(struct mg_connection
*conn
, VTOY_JSON
*json
)
292 const char *lang
= NULL
;
294 lang
= vtoy_json_get_string_ex(json
, "language");
297 scnprintf(g_cur_language
, "%s", lang
);
298 ventoy_http_save_cfg();
301 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
305 static int ventoy_api_set_partstyle(struct mg_connection
*conn
, VTOY_JSON
*json
)
310 ret
= vtoy_json_get_int(json
, "partstyle", &style
);
311 if (JSON_SUCCESS
== ret
)
313 if ((style
== 0) || (style
== 1))
315 g_cur_part_style
= style
;
316 ventoy_http_save_cfg();
320 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
324 static int ventoy_clean_disk(int fd
, uint64_t size
)
331 vdebug("ventoy_clean_disk fd:%d size:%llu\n", fd
, (_ull
)size
);
334 buf
= zalloc(zerolen
);
337 vlog("failed to alloc clean buffer\n");
341 offset
= lseek(fd
, 0, SEEK_SET
);
342 len
= write(fd
, buf
, zerolen
);
343 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull
)offset
, (_ll
)len
, zerolen
);
345 offset
= lseek(fd
, size
- zerolen
, SEEK_SET
);
346 len
= write(fd
, buf
, zerolen
);
347 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull
)offset
, (_ll
)len
, zerolen
);
355 static int ventoy_write_legacy_grub(int fd
, int partstyle
)
362 vlog("Write GPT stage1 ...\n");
364 offset
= lseek(fd
, 512 * 34, SEEK_SET
);
366 g_grub_stg1_raw_img
[500] = 35;//update blocklist
367 len
= write(fd
, g_grub_stg1_raw_img
, SIZE_1MB
- 512 * 34);
369 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull
)offset
, 512 * 34, (_ull
)len
, SIZE_1MB
- 512 * 34);
370 if (SIZE_1MB
- 512 * 34 != len
)
372 vlog("write length error\n");
378 vlog("Write MBR stage1 ...\n");
379 offset
= lseek(fd
, 512, SEEK_SET
);
380 len
= write(fd
, g_grub_stg1_raw_img
, SIZE_1MB
- 512);
382 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull
)offset
, 512, (_ull
)len
, SIZE_1MB
- 512);
383 if (SIZE_1MB
- 512 != len
)
385 vlog("write length error\n");
393 static int VentoyFatMemRead(uint32 Sector
, uint8
*Buffer
, uint32 SectorCount
)
398 for (i
= 0; i
< SectorCount
; i
++)
400 offset
= (Sector
+ i
) * 512;
401 memcpy(Buffer
+ i
* 512, g_efi_part_raw_img
+ offset
, 512);
407 static int VentoyFatMemWrite(uint32 Sector
, uint8
*Buffer
, uint32 SectorCount
)
412 for (i
= 0; i
< SectorCount
; i
++)
414 offset
= (Sector
+ i
) * 512;
415 memcpy(g_efi_part_raw_img
+ offset
, Buffer
+ i
* 512, 512);
421 static int VentoyProcSecureBoot(int SecureBoot
)
425 char *filebuf
= NULL
;
428 vlog("VentoyProcSecureBoot %d ...\n", SecureBoot
);
432 vlog("Secure boot is enabled ...\n");
438 if (0 == fl_attach_media(VentoyFatMemRead
, VentoyFatMemWrite
))
440 file
= fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
441 vlog("Open ventoy efi file %p \n", file
);
444 fl_fseek(file
, 0, SEEK_END
);
445 size
= (int)fl_ftell(file
);
446 fl_fseek(file
, 0, SEEK_SET
);
448 vlog("ventoy efi file size %d ...\n", size
);
450 filebuf
= (char *)malloc(size
);
453 fl_fread(filebuf
, 1, size
, file
);
458 vlog("Now delete all efi files ...\n");
459 fl_remove("/EFI/BOOT/BOOTX64.EFI");
460 fl_remove("/EFI/BOOT/grubx64.efi");
461 fl_remove("/EFI/BOOT/grubx64_real.efi");
462 fl_remove("/EFI/BOOT/MokManager.efi");
463 fl_remove("/ENROLL_THIS_KEY_IN_MOKMANAGER.cer");
465 file
= fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");
466 vlog("Open bootx64 efi file %p \n", file
);
471 fl_fwrite(filebuf
, 1, size
, file
);
484 file
= fl_fopen("/EFI/BOOT/grubia32_real.efi", "rb");
485 vlog("Open ventoy efi file %p\n", file
);
488 fl_fseek(file
, 0, SEEK_END
);
489 size
= (int)fl_ftell(file
);
490 fl_fseek(file
, 0, SEEK_SET
);
492 vlog("ventoy efi file size %d ...\n", size
);
494 filebuf
= (char *)malloc(size
);
497 fl_fread(filebuf
, 1, size
, file
);
502 vlog("Now delete all efi files ...\n");
503 fl_remove("/EFI/BOOT/BOOTIA32.EFI");
504 fl_remove("/EFI/BOOT/grubia32.efi");
505 fl_remove("/EFI/BOOT/grubia32_real.efi");
506 fl_remove("/EFI/BOOT/mmia32.efi");
508 file
= fl_fopen("/EFI/BOOT/BOOTIA32.EFI", "wb");
509 vlog("Open bootia32 efi file %p\n", file
);
514 fl_fwrite(filebuf
, 1, size
, file
);
538 static int ventoy_check_efi_part_data(int fd
, uint64_t offset
)
544 buf
= malloc(SIZE_1MB
);
550 lseek(fd
, offset
, SEEK_SET
);
551 for (i
= 0; i
< 32; i
++)
553 len
= read(fd
, buf
, SIZE_1MB
);
554 if (len
!= SIZE_1MB
|| memcmp(buf
, g_efi_part_raw_img
+ i
* SIZE_1MB
, SIZE_1MB
))
556 vlog("part2 data check failed i=%d len:%llu\n", i
, (_ull
)len
);
560 g_current_progress
= PT_CHECK_PART2
+ (i
/ 4);
566 static int ventoy_write_efipart(int fd
, uint64_t offset
, uint32_t secureboot
)
571 vlog("Formatting part2 EFI offset:%llu ...\n", (_ull
)offset
);
572 lseek(fd
, offset
, SEEK_SET
);
574 VentoyProcSecureBoot((int)secureboot
);
576 g_current_progress
= PT_WRITE_VENTOY_START
;
577 for (i
= 0; i
< 32; i
++)
579 len
= write(fd
, g_efi_part_raw_img
+ i
* SIZE_1MB
, SIZE_1MB
);
580 vlog("write disk writelen:%lld datalen:%d [ %s ]\n",
581 (_ll
)len
, SIZE_1MB
, (len
== SIZE_1MB
) ? "success" : "failed");
585 vlog("failed to format part2 EFI\n");
589 g_current_progress
= PT_WRITE_VENTOY_START
+ i
/ 4;
595 static int VentoyFillBackupGptHead(VTOY_GPT_INFO
*pInfo
, VTOY_GPT_HDR
*pHead
)
600 memcpy(pHead
, &pInfo
->Head
, sizeof(VTOY_GPT_HDR
));
602 LBA
= pHead
->EfiStartLBA
;
603 BackupLBA
= pHead
->EfiBackupLBA
;
605 pHead
->EfiStartLBA
= BackupLBA
;
606 pHead
->EfiBackupLBA
= LBA
;
607 pHead
->PartTblStartLBA
= BackupLBA
+ 1 - 33;
610 pHead
->Crc
= ventoy_crc32(pHead
, pHead
->Length
);
615 static int ventoy_write_gpt_part_table(int fd
, uint64_t disksize
, VTOY_GPT_INFO
*gpt
)
619 VTOY_GPT_HDR BackupHead
;
621 VentoyFillBackupGptHead(gpt
, &BackupHead
);
623 offset
= lseek(fd
, disksize
- 512, SEEK_SET
);
624 len
= write(fd
, &BackupHead
, sizeof(VTOY_GPT_HDR
));
625 vlog("write backup gpt part table off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
626 if (offset
!= disksize
- 512 || len
!= sizeof(VTOY_GPT_HDR
))
631 offset
= lseek(fd
, disksize
- 512 * 33, SEEK_SET
);
632 len
= write(fd
, gpt
->PartTbl
, sizeof(gpt
->PartTbl
));
633 vlog("write main gpt part table off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
634 if (offset
!= disksize
- 512 * 33 || len
!= sizeof(gpt
->PartTbl
))
639 offset
= lseek(fd
, 0, SEEK_SET
);
640 len
= write(fd
, gpt
, sizeof(VTOY_GPT_INFO
));
641 vlog("write gpt part head off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
642 if (offset
!= 0 || len
!= sizeof(VTOY_GPT_INFO
))
650 static void * ventoy_update_thread(void *data
)
656 ventoy_disk
*disk
= NULL
;
657 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
659 vdebug("ventoy_update_thread run ...\n");
664 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
665 vdebug("check disk %s\n", disk
->disk_name
);
666 if (ventoy_is_disk_mounted(disk
->disk_path
))
668 vlog("disk is mounted, now try to unmount it ...\n");
669 ventoy_try_umount_disk(disk
->disk_path
);
672 if (ventoy_is_disk_mounted(disk
->disk_path
))
674 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
679 vlog("disk is not mounted now, we can do continue ...\n");
682 g_current_progress
= PT_LOAD_CORE_IMG
;
683 ventoy_unxz_stg1_img();
685 g_current_progress
= PT_LOAD_DISK_IMG
;
686 ventoy_unxz_efipart_img();
688 g_current_progress
= PT_FORMAT_PART2
;
690 vlog("Formatting part2 EFI ...\n");
691 if (0 != ventoy_write_efipart(fd
, disk
->vtoydata
.part2_start_sector
* 512, thread
->secure_boot
))
693 vlog("Failed to format part2 efi ...\n");
697 g_current_progress
= PT_WRITE_STG1_IMG
;
699 vlog("Writing legacy grub ...\n");
700 if (0 != ventoy_write_legacy_grub(fd
, disk
->vtoydata
.partition_style
))
702 vlog("ventoy_write_legacy_grub failed ...\n");
706 offset
= lseek(fd
, 512 * 2040, SEEK_SET
);
707 len
= write(fd
, disk
->vtoydata
.rsvdata
, sizeof(disk
->vtoydata
.rsvdata
));
708 vlog("Writing reserve data offset:%llu len:%llu ...\n", (_ull
)offset
, (_ull
)len
);
710 memcpy(&MBR
, &(disk
->vtoydata
.gptinfo
.MBR
), 512);
711 if (disk
->vtoydata
.partition_style
== 0 && MBR
.PartTbl
[0].Active
== 0)
713 MBR
.PartTbl
[0].Active
= 0x80;
714 MBR
.PartTbl
[1].Active
= 0;
715 MBR
.PartTbl
[2].Active
= 0;
716 MBR
.PartTbl
[3].Active
= 0;
718 offset
= lseek(fd
, 0, SEEK_SET
);
719 len
= write(fd
, &MBR
, 512);
720 vlog("set MBR partition 1 active flag enabled offset:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
723 g_current_progress
= PT_SYNC_DATA1
;
725 vlog("fsync data1...\n");
727 vtoy_safe_close_fd(fd
);
729 g_current_progress
= PT_SYNC_DATA2
;
731 vlog("====================================\n");
732 vlog("====== ventoy update success ======\n");
733 vlog("====================================\n");
737 g_cur_process_result
= 1;
738 vtoy_safe_close_fd(fd
);
741 g_current_progress
= PT_FINISH
;
748 static void * ventoy_install_thread(void *data
)
754 ventoy_disk
*disk
= NULL
;
755 VTOY_GPT_INFO
*gpt
= NULL
;
756 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
757 uint64_t Part1StartSector
= 0;
758 uint64_t Part1SectorCount
= 0;
759 uint64_t Part2StartSector
= 0;
761 vdebug("ventoy_install_thread run ...\n");
766 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
767 vdebug("check disk %s\n", disk
->disk_name
);
768 if (ventoy_is_disk_mounted(disk
->disk_path
))
770 vlog("disk is mounted, now try to unmount it ...\n");
771 ventoy_try_umount_disk(disk
->disk_path
);
774 if (ventoy_is_disk_mounted(disk
->disk_path
))
776 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
781 vlog("disk is not mounted now, we can do continue ...\n");
784 g_current_progress
= PT_DEL_ALL_PART
;
785 ventoy_clean_disk(fd
, disk
->size_in_byte
);
787 g_current_progress
= PT_LOAD_CORE_IMG
;
788 ventoy_unxz_stg1_img();
790 g_current_progress
= PT_LOAD_DISK_IMG
;
791 ventoy_unxz_efipart_img();
793 if (thread
->partstyle
)
795 vdebug("Fill GPT part table\n");
796 gpt
= zalloc(sizeof(VTOY_GPT_INFO
));
797 ventoy_fill_gpt(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, gpt
);
798 Part1StartSector
= gpt
->PartTbl
[0].StartLBA
;
799 Part1SectorCount
= gpt
->PartTbl
[0].LastLBA
- Part1StartSector
+ 1;
800 Part2StartSector
= gpt
->PartTbl
[1].StartLBA
;
804 vdebug("Fill MBR part table\n");
805 ventoy_fill_mbr(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, &MBR
);
806 Part1StartSector
= MBR
.PartTbl
[0].StartSectorId
;
807 Part1SectorCount
= MBR
.PartTbl
[0].SectorCount
;
808 Part2StartSector
= MBR
.PartTbl
[1].StartSectorId
;
811 vlog("Part1StartSector:%llu Part1SectorCount:%llu Part2StartSector:%llu\n",
812 (_ull
)Part1StartSector
, (_ull
)Part1SectorCount
, (_ull
)Part2StartSector
);
814 if (thread
->partstyle
!= disk
->partstyle
)
816 vlog("Wait for format part1 (partstyle changed) ...\n");
820 g_current_progress
= PT_FORMAT_PART1
;
821 vlog("Formatting part1 exFAT %s ...\n", disk
->disk_path
);
822 if (0 != mkexfat_main(disk
->disk_path
, fd
, Part1SectorCount
))
824 vlog("Failed to format exfat ...\n");
828 g_current_progress
= PT_FORMAT_PART2
;
829 vlog("Formatting part2 EFI ...\n");
830 if (0 != ventoy_write_efipart(fd
, Part2StartSector
* 512, thread
->secure_boot
))
832 vlog("Failed to format part2 efi ...\n");
836 g_current_progress
= PT_WRITE_STG1_IMG
;
837 vlog("Writing legacy grub ...\n");
838 if (0 != ventoy_write_legacy_grub(fd
, thread
->partstyle
))
840 vlog("ventoy_write_legacy_grub failed ...\n");
844 g_current_progress
= PT_SYNC_DATA1
;
845 vlog("fsync data1...\n");
847 vtoy_safe_close_fd(fd
);
849 /* reopen for check part2 data */
850 vlog("Checking part2 efi data %s ...\n", disk
->disk_path
);
851 g_current_progress
= PT_CHECK_PART2
;
852 fd
= open(disk
->disk_path
, O_RDONLY
| O_BINARY
);
855 vlog("failed to open %s for check fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
859 if (0 == ventoy_check_efi_part_data(fd
, Part2StartSector
* 512))
861 vlog("efi part data check success\n");
865 vlog("efi part data check failed\n");
869 vtoy_safe_close_fd(fd
);
871 /* reopen for write part table */
872 g_current_progress
= PT_WRITE_PART_TABLE
;
873 vlog("Writting Partition Table style:%d...\n", thread
->partstyle
);
875 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
878 vlog("failed to open %s for part table fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
882 if (thread
->partstyle
)
884 ventoy_write_gpt_part_table(fd
, disk
->size_in_byte
, gpt
);
888 offset
= lseek(fd
, 0, SEEK_SET
);
889 len
= write(fd
, &MBR
, 512);
890 vlog("Writting MBR Partition Table %llu %llu\n", (_ull
)offset
, (_ull
)len
);
891 if (offset
!= 0 || len
!= 512)
897 g_current_progress
= PT_SYNC_DATA2
;
898 vlog("fsync data2...\n");
900 vtoy_safe_close_fd(fd
);
903 vlog("====================================\n");
904 vlog("====== ventoy install success ======\n");
905 vlog("====================================\n");
909 g_cur_process_result
= 1;
910 vtoy_safe_close_fd(fd
);
913 g_current_progress
= PT_FINISH
;
921 static int ventoy_api_clean(struct mg_connection
*conn
, VTOY_JSON
*json
)
925 ventoy_disk
*disk
= NULL
;
926 const char *diskname
= NULL
;
929 if (g_current_progress
!= PT_FINISH
)
931 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
935 diskname
= vtoy_json_get_string_ex(json
, "disk");
936 if (diskname
== NULL
)
938 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
942 for (i
= 0; i
< g_disk_num
; i
++)
944 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
946 disk
= g_disk_list
+ i
;
953 vlog("disk %s not found\n", diskname
);
954 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
958 scnprintf(path
, "/sys/block/%s", diskname
);
959 if (access(path
, F_OK
) < 0)
961 vlog("File %s not exist anymore\n", path
);
962 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
966 vlog("==================================\n");
967 vlog("===== ventoy clean %s =====\n", disk
->disk_path
);
968 vlog("==================================\n");
970 if (ventoy_is_disk_mounted(disk
->disk_path
))
972 vlog("disk is mounted, now try to unmount it ...\n");
973 ventoy_try_umount_disk(disk
->disk_path
);
976 if (ventoy_is_disk_mounted(disk
->disk_path
))
978 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
979 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
984 vlog("disk is not mounted now, we can do the clean ...\n");
987 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
990 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
991 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
995 vdebug("start clean %s ...\n", disk
->disk_model
);
996 ventoy_clean_disk(fd
, disk
->size_in_byte
);
998 vtoy_safe_close_fd(fd
);
1000 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1004 static int ventoy_api_install(struct mg_connection
*conn
, VTOY_JSON
*json
)
1009 uint32_t align4kb
= 0;
1011 uint32_t secure_boot
= 0;
1012 uint64_t reserveBytes
= 0;
1013 ventoy_disk
*disk
= NULL
;
1014 const char *diskname
= NULL
;
1015 const char *reserve_space
= NULL
;
1016 ventoy_thread_data
*thread
= NULL
;
1019 if (g_current_progress
!= PT_FINISH
)
1021 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1025 diskname
= vtoy_json_get_string_ex(json
, "disk");
1026 reserve_space
= vtoy_json_get_string_ex(json
, "reserve_space");
1027 ret
+= vtoy_json_get_uint(json
, "partstyle", &style
);
1028 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1029 ret
+= vtoy_json_get_uint(json
, "align_4kb", &align4kb
);
1031 if (diskname
== NULL
|| reserve_space
== NULL
|| ret
!= JSON_SUCCESS
)
1033 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1037 reserveBytes
= (uint64_t)strtoull(reserve_space
, NULL
, 10);
1039 for (i
= 0; i
< g_disk_num
; i
++)
1041 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1043 disk
= g_disk_list
+ i
;
1050 vlog("disk %s not found\n", diskname
);
1051 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1055 scnprintf(path
, "/sys/block/%s", diskname
);
1056 if (access(path
, F_OK
) < 0)
1058 vlog("File %s not exist anymore\n", path
);
1059 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1063 if (disk
->size_in_byte
> 2199023255552ULL && style
== 0)
1065 vlog("disk %s is more than 2TB and GPT is needed\n", path
);
1066 ventoy_json_result(conn
, VTOY_JSON_MBR_2TB_RET
);
1070 if ((reserveBytes
+ VTOYEFI_PART_BYTES
* 2) > disk
->size_in_byte
)
1072 vlog("reserve space %llu is too big for disk %s %llu\n", (_ull
)reserveBytes
, path
, (_ull
)disk
->size_in_byte
);
1073 ventoy_json_result(conn
, VTOY_JSON_INVALID_RSV_RET
);
1077 vlog("==================================================================================\n");
1078 vlog("===== ventoy install %s style:%s secureboot:%u align4K:%u reserve:%llu =========\n",
1079 disk
->disk_path
, (style
? "GPT" : "MBR"), secure_boot
, align4kb
, (_ull
)reserveBytes
);
1080 vlog("==================================================================================\n");
1082 if (ventoy_is_disk_mounted(disk
->disk_path
))
1084 vlog("disk is mounted, now try to unmount it ...\n");
1085 ventoy_try_umount_disk(disk
->disk_path
);
1088 if (ventoy_is_disk_mounted(disk
->disk_path
))
1090 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1091 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1096 vlog("disk is not mounted now, we can do the install ...\n");
1099 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1102 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1103 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1107 vdebug("start install thread %s ...\n", disk
->disk_model
);
1108 thread
= zalloc(sizeof(ventoy_thread_data
));
1111 vtoy_safe_close_fd(fd
);
1112 vlog("failed to alloc thread data err:%d\n", errno
);
1113 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1117 g_current_progress
= PT_START
;
1118 g_cur_process_result
= 0;
1119 scnprintf(g_cur_process_type
, "%s", "install");
1120 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1122 thread
->disk
= disk
;
1123 thread
->diskfd
= fd
;
1124 thread
->align4kb
= align4kb
;
1125 thread
->partstyle
= style
;
1126 thread
->secure_boot
= secure_boot
;
1127 thread
->reserveBytes
= reserveBytes
;
1129 mg_start_thread(ventoy_install_thread
, thread
);
1131 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1135 static int ventoy_api_update(struct mg_connection
*conn
, VTOY_JSON
*json
)
1140 uint32_t secure_boot
= 0;
1141 ventoy_disk
*disk
= NULL
;
1142 const char *diskname
= NULL
;
1143 ventoy_thread_data
*thread
= NULL
;
1146 if (g_current_progress
!= PT_FINISH
)
1148 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1152 diskname
= vtoy_json_get_string_ex(json
, "disk");
1153 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1154 if (diskname
== NULL
|| ret
!= JSON_SUCCESS
)
1156 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1160 for (i
= 0; i
< g_disk_num
; i
++)
1162 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1164 disk
= g_disk_list
+ i
;
1171 vlog("disk %s not found\n", diskname
);
1172 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1176 if (disk
->vtoydata
.ventoy_valid
== 0)
1178 vlog("disk %s is not ventoy disk\n", diskname
);
1179 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1183 scnprintf(path
, "/sys/block/%s", diskname
);
1184 if (access(path
, F_OK
) < 0)
1186 vlog("File %s not exist anymore\n", path
);
1187 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1191 vlog("==========================================================\n");
1192 vlog("===== ventoy update %s new_secureboot:%u =========\n", disk
->disk_path
, secure_boot
);
1193 vlog("==========================================================\n");
1195 vlog("%s version:%s partstyle:%u oldsecureboot:%u reserve:%llu\n",
1196 disk
->disk_path
, disk
->vtoydata
.ventoy_ver
,
1197 disk
->vtoydata
.partition_style
,
1198 disk
->vtoydata
.secure_boot_flag
,
1199 (_ull
)(disk
->vtoydata
.preserved_space
)
1202 if (ventoy_is_disk_mounted(disk
->disk_path
))
1204 vlog("disk is mounted, now try to unmount it ...\n");
1205 ventoy_try_umount_disk(disk
->disk_path
);
1208 if (ventoy_is_disk_mounted(disk
->disk_path
))
1210 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1211 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1216 vlog("disk is not mounted now, we can do the update ...\n");
1219 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1222 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1223 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1227 vdebug("start update thread %s ...\n", disk
->disk_model
);
1228 thread
= zalloc(sizeof(ventoy_thread_data
));
1231 vtoy_safe_close_fd(fd
);
1232 vlog("failed to alloc thread data err:%d\n", errno
);
1233 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1237 g_current_progress
= PT_START
;
1238 g_cur_process_result
= 0;
1239 scnprintf(g_cur_process_type
, "%s", "update");
1240 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1242 thread
->disk
= disk
;
1243 thread
->diskfd
= fd
;
1244 thread
->secure_boot
= secure_boot
;
1246 mg_start_thread(ventoy_update_thread
, thread
);
1248 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1253 static int ventoy_api_refresh_device(struct mg_connection
*conn
, VTOY_JSON
*json
)
1257 if (g_current_progress
== PT_FINISH
)
1260 ventoy_disk_enumerate_all();
1263 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1267 static int ventoy_api_get_dev_list(struct mg_connection
*conn
, VTOY_JSON
*json
)
1273 uint32_t alldev
= 0;
1275 ventoy_disk
*cur
= NULL
;
1277 rc
= vtoy_json_get_uint(json
, "alldev", &alldev
);
1278 if (JSON_SUCCESS
!= rc
)
1283 buflen
= g_disk_num
* 1024;
1284 buf
= (char *)malloc(buflen
+ 1024);
1287 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1291 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
1292 VTOY_JSON_FMT_OBJ_BEGIN();
1293 VTOY_JSON_FMT_KEY("list");
1294 VTOY_JSON_FMT_ARY_BEGIN();
1296 for (i
= 0; i
< g_disk_num
; i
++)
1298 cur
= g_disk_list
+ i
;
1300 if (alldev
== 0 && cur
->type
!= VTOY_DEVICE_USB
)
1305 VTOY_JSON_FMT_OBJ_BEGIN();
1306 VTOY_JSON_FMT_STRN("name", cur
->disk_name
);
1307 VTOY_JSON_FMT_STRN("model", cur
->disk_model
);
1308 VTOY_JSON_FMT_STRN("size", cur
->human_readable_size
);
1309 VTOY_JSON_FMT_UINT("vtoy_valid", cur
->vtoydata
.ventoy_valid
);
1310 VTOY_JSON_FMT_STRN("vtoy_ver", cur
->vtoydata
.ventoy_ver
);
1311 VTOY_JSON_FMT_UINT("vtoy_secure_boot", cur
->vtoydata
.secure_boot_flag
);
1312 VTOY_JSON_FMT_UINT("vtoy_partstyle", cur
->vtoydata
.partition_style
);
1313 VTOY_JSON_FMT_OBJ_ENDEX();
1316 VTOY_JSON_FMT_ARY_END();
1317 VTOY_JSON_FMT_OBJ_END();
1318 VTOY_JSON_FMT_END(pos
);
1320 ventoy_json_buffer(conn
, buf
, pos
);
1324 static JSON_CB g_ventoy_json_cb
[] =
1326 { "sysinfo", ventoy_api_sysinfo
},
1327 { "sel_language", ventoy_api_set_language
},
1328 { "sel_partstyle", ventoy_api_set_partstyle
},
1329 { "refresh_device", ventoy_api_refresh_device
},
1330 { "get_dev_list", ventoy_api_get_dev_list
},
1331 { "install", ventoy_api_install
},
1332 { "update", ventoy_api_update
},
1333 { "clean", ventoy_api_clean
},
1334 { "get_percent", ventoy_api_get_percent
},
1337 static int ventoy_json_handler(struct mg_connection
*conn
, VTOY_JSON
*json
)
1340 const char *token
= NULL
;
1341 const char *method
= NULL
;
1343 method
= vtoy_json_get_string_ex(json
, "method");
1346 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1350 if (strcmp(method
, "sysinfo"))
1352 token
= vtoy_json_get_string_ex(json
, "token");
1353 if (token
== NULL
|| strcmp(token
, g_cur_server_token
))
1355 ventoy_json_result(conn
, VTOY_JSON_TOKEN_ERR_RET
);
1360 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1362 if (strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1364 g_ventoy_json_cb
[i
].callback(conn
, json
);
1372 static int ventoy_request_handler(struct mg_connection
*conn
)
1376 VTOY_JSON
*json
= NULL
;
1377 char *post_data_buf
= NULL
;
1378 const struct mg_request_info
*ri
= NULL
;
1379 char stack_buf
[512];
1381 ri
= mg_get_request_info(conn
);
1383 if (strcmp(ri
->uri
, "/vtoy/json") == 0)
1385 if (ri
->content_length
> 500)
1387 post_data_buf
= malloc(ri
->content_length
+ 4);
1388 post_buf_len
= ri
->content_length
+ 1;
1392 post_data_buf
= stack_buf
;
1393 post_buf_len
= sizeof(stack_buf
);
1396 post_data_len
= mg_read(conn
, post_data_buf
, post_buf_len
);
1397 post_data_buf
[post_data_len
] = 0;
1399 json
= vtoy_json_create();
1400 if (JSON_SUCCESS
== vtoy_json_parse(json
, post_data_buf
))
1402 pthread_mutex_lock(&g_api_mutex
);
1403 ventoy_json_handler(conn
, json
->pstChild
);
1404 pthread_mutex_unlock(&g_api_mutex
);
1408 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1411 vtoy_json_destroy(json
);
1413 if (post_data_buf
!= stack_buf
)
1415 free(post_data_buf
);
1425 int ventoy_http_start(const char *ip
, const char *port
)
1429 struct mg_callbacks callbacks
;
1430 const char *options
[] =
1432 "listening_ports", "24680",
1433 "document_root", "WebUI",
1434 "error_log_file", VTOY_LOG_FILE
,
1435 "request_timeout_ms", "10000",
1440 ventoy_gen_preudo_uuid(uuid
);
1441 scnprintf(g_cur_server_token
, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1442 uuid
[0], uuid
[1], uuid
[2], uuid
[3], uuid
[4], uuid
[5], uuid
[6], uuid
[7],
1443 uuid
[8], uuid
[9], uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
1446 scnprintf(addr
, "%s:%s", ip
, port
);
1449 memset(&callbacks
, 0, sizeof(callbacks
));
1450 callbacks
.begin_request
= ventoy_request_handler
;
1451 g_ventoy_http_ctx
= mg_start(&callbacks
, NULL
, options
);
1453 return g_ventoy_http_ctx
? 0 : 1;
1456 int ventoy_http_stop(void)
1458 if (g_ventoy_http_ctx
)
1460 mg_stop(g_ventoy_http_ctx
);
1465 int ventoy_http_init(void)
1467 pthread_mutex_init(&g_api_mutex
, NULL
);
1469 ventoy_http_load_cfg();
1471 ventoy_load_mbr_template();
1476 void ventoy_http_exit(void)
1478 pthread_mutex_destroy(&g_api_mutex
);
1480 check_free(g_efi_part_raw_img
);
1481 g_efi_part_raw_img
= NULL
;