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
);
353 static int ventoy_write_legacy_grub(int fd
, int partstyle
)
360 vlog("Write GPT stage1 ...\n");
362 offset
= lseek(fd
, 512 * 34, SEEK_SET
);
364 g_grub_stg1_raw_img
[500] = 35;//update blocklist
365 len
= write(fd
, g_grub_stg1_raw_img
, SIZE_1MB
- 512 * 34);
367 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull
)offset
, 512 * 34, (_ull
)len
, SIZE_1MB
- 512 * 34);
368 if (SIZE_1MB
- 512 * 34 != len
)
370 vlog("write length error\n");
376 vlog("Write MBR stage1 ...\n");
377 offset
= lseek(fd
, 512, SEEK_SET
);
378 len
= write(fd
, g_grub_stg1_raw_img
, SIZE_1MB
- 512);
380 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull
)offset
, 512, (_ull
)len
, SIZE_1MB
- 512);
381 if (SIZE_1MB
- 512 != len
)
383 vlog("write length error\n");
391 static int VentoyFatMemRead(uint32 Sector
, uint8
*Buffer
, uint32 SectorCount
)
396 for (i
= 0; i
< SectorCount
; i
++)
398 offset
= (Sector
+ i
) * 512;
399 memcpy(Buffer
+ i
* 512, g_efi_part_raw_img
+ offset
, 512);
405 static int VentoyFatMemWrite(uint32 Sector
, uint8
*Buffer
, uint32 SectorCount
)
410 for (i
= 0; i
< SectorCount
; i
++)
412 offset
= (Sector
+ i
) * 512;
413 memcpy(g_efi_part_raw_img
+ offset
, Buffer
+ i
* 512, 512);
419 static int VentoyProcSecureBoot(int SecureBoot
)
423 char *filebuf
= NULL
;
426 vlog("VentoyProcSecureBoot %d ...\n", SecureBoot
);
430 vlog("Secure boot is enabled ...\n");
436 if (0 == fl_attach_media(VentoyFatMemRead
, VentoyFatMemWrite
))
438 file
= fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
439 vlog("Open ventoy efi file %p \n", file
);
442 fl_fseek(file
, 0, SEEK_END
);
443 size
= (int)fl_ftell(file
);
444 fl_fseek(file
, 0, SEEK_SET
);
446 vlog("ventoy efi file size %d ...\n", size
);
448 filebuf
= (char *)malloc(size
);
451 fl_fread(filebuf
, 1, size
, file
);
456 vlog("Now delete all efi files ...\n");
457 fl_remove("/EFI/BOOT/BOOTX64.EFI");
458 fl_remove("/EFI/BOOT/grubx64.efi");
459 fl_remove("/EFI/BOOT/grubx64_real.efi");
460 fl_remove("/EFI/BOOT/MokManager.efi");
461 fl_remove("/ENROLL_THIS_KEY_IN_MOKMANAGER.cer");
463 file
= fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");
464 vlog("Open bootx64 efi file %p \n", file
);
469 fl_fwrite(filebuf
, 1, size
, file
);
482 file
= fl_fopen("/EFI/BOOT/grubia32_real.efi", "rb");
483 vlog("Open ventoy efi file %p\n", file
);
486 fl_fseek(file
, 0, SEEK_END
);
487 size
= (int)fl_ftell(file
);
488 fl_fseek(file
, 0, SEEK_SET
);
490 vlog("ventoy efi file size %d ...\n", size
);
492 filebuf
= (char *)malloc(size
);
495 fl_fread(filebuf
, 1, size
, file
);
500 vlog("Now delete all efi files ...\n");
501 fl_remove("/EFI/BOOT/BOOTIA32.EFI");
502 fl_remove("/EFI/BOOT/grubia32.efi");
503 fl_remove("/EFI/BOOT/grubia32_real.efi");
504 fl_remove("/EFI/BOOT/mmia32.efi");
506 file
= fl_fopen("/EFI/BOOT/BOOTIA32.EFI", "wb");
507 vlog("Open bootia32 efi file %p\n", file
);
512 fl_fwrite(filebuf
, 1, size
, file
);
536 static int ventoy_check_efi_part_data(int fd
, uint64_t offset
)
542 buf
= malloc(SIZE_1MB
);
548 lseek(fd
, offset
, SEEK_SET
);
549 for (i
= 0; i
< 32; i
++)
551 len
= read(fd
, buf
, SIZE_1MB
);
552 if (len
!= SIZE_1MB
|| memcmp(buf
, g_efi_part_raw_img
+ i
* SIZE_1MB
, SIZE_1MB
))
554 vlog("part2 data check failed i=%d len:%llu\n", i
, (_ull
)len
);
558 g_current_progress
= PT_CHECK_PART2
+ (i
/ 4);
564 static int ventoy_write_efipart(int fd
, uint64_t offset
, uint32_t secureboot
)
569 vlog("Formatting part2 EFI offset:%llu ...\n", (_ull
)offset
);
570 lseek(fd
, offset
, SEEK_SET
);
572 VentoyProcSecureBoot((int)secureboot
);
574 g_current_progress
= PT_WRITE_VENTOY_START
;
575 for (i
= 0; i
< 32; i
++)
577 len
= write(fd
, g_efi_part_raw_img
+ i
* SIZE_1MB
, SIZE_1MB
);
578 vlog("write disk writelen:%lld datalen:%d [ %s ]\n",
579 (_ll
)len
, SIZE_1MB
, (len
== SIZE_1MB
) ? "success" : "failed");
583 vlog("failed to format part2 EFI\n");
587 g_current_progress
= PT_WRITE_VENTOY_START
+ i
/ 4;
593 static int VentoyFillBackupGptHead(VTOY_GPT_INFO
*pInfo
, VTOY_GPT_HDR
*pHead
)
598 memcpy(pHead
, &pInfo
->Head
, sizeof(VTOY_GPT_HDR
));
600 LBA
= pHead
->EfiStartLBA
;
601 BackupLBA
= pHead
->EfiBackupLBA
;
603 pHead
->EfiStartLBA
= BackupLBA
;
604 pHead
->EfiBackupLBA
= LBA
;
605 pHead
->PartTblStartLBA
= BackupLBA
+ 1 - 33;
608 pHead
->Crc
= ventoy_crc32(pHead
, pHead
->Length
);
613 static int ventoy_write_gpt_part_table(int fd
, uint64_t disksize
, VTOY_GPT_INFO
*gpt
)
617 VTOY_GPT_HDR BackupHead
;
619 VentoyFillBackupGptHead(gpt
, &BackupHead
);
621 offset
= lseek(fd
, disksize
- 512, SEEK_SET
);
622 len
= write(fd
, &BackupHead
, sizeof(VTOY_GPT_HDR
));
623 vlog("write backup gpt part table off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
624 if (offset
!= disksize
- 512 || len
!= sizeof(VTOY_GPT_HDR
))
629 offset
= lseek(fd
, disksize
- 512 * 33, SEEK_SET
);
630 len
= write(fd
, gpt
->PartTbl
, sizeof(gpt
->PartTbl
));
631 vlog("write main gpt part table off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
632 if (offset
!= disksize
- 512 * 33 || len
!= sizeof(gpt
->PartTbl
))
637 offset
= lseek(fd
, 0, SEEK_SET
);
638 len
= write(fd
, gpt
, sizeof(VTOY_GPT_INFO
));
639 vlog("write gpt part head off:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
640 if (offset
!= 0 || len
!= sizeof(VTOY_GPT_INFO
))
648 static void * ventoy_update_thread(void *data
)
654 ventoy_disk
*disk
= NULL
;
655 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
657 vdebug("ventoy_update_thread run ...\n");
662 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
663 vdebug("check disk %s\n", disk
->disk_name
);
664 if (ventoy_is_disk_mounted(disk
->disk_path
))
666 vlog("disk is mounted, now try to unmount it ...\n");
667 ventoy_try_umount_disk(disk
->disk_path
);
670 if (ventoy_is_disk_mounted(disk
->disk_path
))
672 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
677 vlog("disk is not mounted now, we can do continue ...\n");
680 g_current_progress
= PT_LOAD_CORE_IMG
;
681 ventoy_unxz_stg1_img();
683 g_current_progress
= PT_LOAD_DISK_IMG
;
684 ventoy_unxz_efipart_img();
686 g_current_progress
= PT_FORMAT_PART2
;
688 vlog("Formatting part2 EFI ...\n");
689 if (0 != ventoy_write_efipart(fd
, disk
->vtoydata
.part2_start_sector
* 512, thread
->secure_boot
))
691 vlog("Failed to format part2 efi ...\n");
695 g_current_progress
= PT_WRITE_STG1_IMG
;
697 vlog("Writing legacy grub ...\n");
698 if (0 != ventoy_write_legacy_grub(fd
, disk
->vtoydata
.partition_style
))
700 vlog("ventoy_write_legacy_grub failed ...\n");
704 offset
= lseek(fd
, 512 * 2040, SEEK_SET
);
705 len
= write(fd
, disk
->vtoydata
.rsvdata
, sizeof(disk
->vtoydata
.rsvdata
));
706 vlog("Writing reserve data offset:%llu len:%llu ...\n", (_ull
)offset
, (_ull
)len
);
708 memcpy(&MBR
, &(disk
->vtoydata
.gptinfo
.MBR
), 512);
709 if (disk
->vtoydata
.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;
716 offset
= lseek(fd
, 0, SEEK_SET
);
717 len
= write(fd
, &MBR
, 512);
718 vlog("set MBR partition 1 active flag enabled offset:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
721 g_current_progress
= PT_SYNC_DATA1
;
723 vlog("fsync data1...\n");
725 vtoy_safe_close_fd(fd
);
727 g_current_progress
= PT_SYNC_DATA2
;
729 vlog("====================================\n");
730 vlog("====== ventoy update success ======\n");
731 vlog("====================================\n");
735 g_cur_process_result
= 1;
736 vtoy_safe_close_fd(fd
);
739 g_current_progress
= PT_FINISH
;
746 static void * ventoy_install_thread(void *data
)
752 ventoy_disk
*disk
= NULL
;
753 VTOY_GPT_INFO
*gpt
= NULL
;
754 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
755 uint64_t Part1StartSector
= 0;
756 uint64_t Part1SectorCount
= 0;
757 uint64_t Part2StartSector
= 0;
759 vdebug("ventoy_install_thread run ...\n");
764 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
765 vdebug("check disk %s\n", disk
->disk_name
);
766 if (ventoy_is_disk_mounted(disk
->disk_path
))
768 vlog("disk is mounted, now try to unmount it ...\n");
769 ventoy_try_umount_disk(disk
->disk_path
);
772 if (ventoy_is_disk_mounted(disk
->disk_path
))
774 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
779 vlog("disk is not mounted now, we can do continue ...\n");
782 g_current_progress
= PT_DEL_ALL_PART
;
783 ventoy_clean_disk(fd
, disk
->size_in_byte
);
785 g_current_progress
= PT_LOAD_CORE_IMG
;
786 ventoy_unxz_stg1_img();
788 g_current_progress
= PT_LOAD_DISK_IMG
;
789 ventoy_unxz_efipart_img();
791 if (thread
->partstyle
)
793 vdebug("Fill GPT part table\n");
794 gpt
= zalloc(sizeof(VTOY_GPT_INFO
));
795 ventoy_fill_gpt(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, gpt
);
796 Part1StartSector
= gpt
->PartTbl
[0].StartLBA
;
797 Part1SectorCount
= gpt
->PartTbl
[0].LastLBA
- Part1StartSector
+ 1;
798 Part2StartSector
= gpt
->PartTbl
[1].StartLBA
;
802 vdebug("Fill MBR part table\n");
803 ventoy_fill_mbr(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, 0, &MBR
);
804 Part1StartSector
= MBR
.PartTbl
[0].StartSectorId
;
805 Part1SectorCount
= MBR
.PartTbl
[0].SectorCount
;
806 Part2StartSector
= MBR
.PartTbl
[1].StartSectorId
;
809 vlog("Part1StartSector:%llu Part1SectorCount:%llu Part2StartSector:%llu\n",
810 (_ull
)Part1StartSector
, (_ull
)Part1SectorCount
, (_ull
)Part2StartSector
);
812 if (thread
->partstyle
!= disk
->partstyle
)
814 vlog("Wait for format part1 (partstyle changed) ...\n");
818 g_current_progress
= PT_FORMAT_PART1
;
819 vlog("Formatting part1 exFAT %s ...\n", disk
->disk_path
);
820 if (0 != mkexfat_main(disk
->disk_path
, fd
, Part1SectorCount
))
822 vlog("Failed to format exfat ...\n");
826 g_current_progress
= PT_FORMAT_PART2
;
827 vlog("Formatting part2 EFI ...\n");
828 if (0 != ventoy_write_efipart(fd
, Part2StartSector
* 512, thread
->secure_boot
))
830 vlog("Failed to format part2 efi ...\n");
834 g_current_progress
= PT_WRITE_STG1_IMG
;
835 vlog("Writing legacy grub ...\n");
836 if (0 != ventoy_write_legacy_grub(fd
, thread
->partstyle
))
838 vlog("ventoy_write_legacy_grub failed ...\n");
842 g_current_progress
= PT_SYNC_DATA1
;
843 vlog("fsync data1...\n");
845 vtoy_safe_close_fd(fd
);
847 /* reopen for check part2 data */
848 vlog("Checking part2 efi data %s ...\n", disk
->disk_path
);
849 g_current_progress
= PT_CHECK_PART2
;
850 fd
= open(disk
->disk_path
, O_RDONLY
| O_BINARY
);
853 vlog("failed to open %s for check fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
857 if (0 == ventoy_check_efi_part_data(fd
, Part2StartSector
* 512))
859 vlog("efi part data check success\n");
863 vlog("efi part data check failed\n");
867 vtoy_safe_close_fd(fd
);
869 /* reopen for write part table */
870 g_current_progress
= PT_WRITE_PART_TABLE
;
871 vlog("Writting Partition Table style:%d...\n", thread
->partstyle
);
873 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
876 vlog("failed to open %s for part table fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
880 if (thread
->partstyle
)
882 ventoy_write_gpt_part_table(fd
, disk
->size_in_byte
, gpt
);
886 offset
= lseek(fd
, 0, SEEK_SET
);
887 len
= write(fd
, &MBR
, 512);
888 vlog("Writting MBR Partition Table %llu %llu\n", (_ull
)offset
, (_ull
)len
);
889 if (offset
!= 0 || len
!= 512)
895 g_current_progress
= PT_SYNC_DATA2
;
896 vlog("fsync data2...\n");
898 vtoy_safe_close_fd(fd
);
901 vlog("====================================\n");
902 vlog("====== ventoy install success ======\n");
903 vlog("====================================\n");
907 g_cur_process_result
= 1;
908 vtoy_safe_close_fd(fd
);
911 g_current_progress
= PT_FINISH
;
919 static int ventoy_api_clean(struct mg_connection
*conn
, VTOY_JSON
*json
)
923 ventoy_disk
*disk
= NULL
;
924 const char *diskname
= NULL
;
927 if (g_current_progress
!= PT_FINISH
)
929 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
933 diskname
= vtoy_json_get_string_ex(json
, "disk");
934 if (diskname
== NULL
)
936 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
940 for (i
= 0; i
< g_disk_num
; i
++)
942 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
944 disk
= g_disk_list
+ i
;
951 vlog("disk %s not found\n", diskname
);
952 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
956 scnprintf(path
, "/sys/block/%s", diskname
);
957 if (access(path
, F_OK
) < 0)
959 vlog("File %s not exist anymore\n", path
);
960 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
964 vlog("==================================\n");
965 vlog("===== ventoy clean %s =====\n", disk
->disk_path
);
966 vlog("==================================\n");
968 if (ventoy_is_disk_mounted(disk
->disk_path
))
970 vlog("disk is mounted, now try to unmount it ...\n");
971 ventoy_try_umount_disk(disk
->disk_path
);
974 if (ventoy_is_disk_mounted(disk
->disk_path
))
976 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
977 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
982 vlog("disk is not mounted now, we can do the clean ...\n");
985 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
988 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
989 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
993 vdebug("start clean %s ...\n", disk
->disk_model
);
994 ventoy_clean_disk(fd
, disk
->size_in_byte
);
996 vtoy_safe_close_fd(fd
);
998 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1002 static int ventoy_api_install(struct mg_connection
*conn
, VTOY_JSON
*json
)
1007 uint32_t align4kb
= 0;
1009 uint32_t secure_boot
= 0;
1010 uint64_t reserveBytes
= 0;
1011 ventoy_disk
*disk
= NULL
;
1012 const char *diskname
= NULL
;
1013 const char *reserve_space
= NULL
;
1014 ventoy_thread_data
*thread
= NULL
;
1017 if (g_current_progress
!= PT_FINISH
)
1019 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1023 diskname
= vtoy_json_get_string_ex(json
, "disk");
1024 reserve_space
= vtoy_json_get_string_ex(json
, "reserve_space");
1025 ret
+= vtoy_json_get_uint(json
, "partstyle", &style
);
1026 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1027 ret
+= vtoy_json_get_uint(json
, "align_4kb", &align4kb
);
1029 if (diskname
== NULL
|| reserve_space
== NULL
|| ret
!= JSON_SUCCESS
)
1031 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1035 reserveBytes
= (uint64_t)strtoull(reserve_space
, NULL
, 10);
1037 for (i
= 0; i
< g_disk_num
; i
++)
1039 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1041 disk
= g_disk_list
+ i
;
1048 vlog("disk %s not found\n", diskname
);
1049 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1053 scnprintf(path
, "/sys/block/%s", diskname
);
1054 if (access(path
, F_OK
) < 0)
1056 vlog("File %s not exist anymore\n", path
);
1057 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1061 if (disk
->size_in_byte
> 2199023255552ULL && style
== 0)
1063 vlog("disk %s is more than 2TB and GPT is needed\n", path
);
1064 ventoy_json_result(conn
, VTOY_JSON_MBR_2TB_RET
);
1068 if ((reserveBytes
+ VTOYEFI_PART_BYTES
* 2) > disk
->size_in_byte
)
1070 vlog("reserve space %llu is too big for disk %s %llu\n", (_ull
)reserveBytes
, path
, (_ull
)disk
->size_in_byte
);
1071 ventoy_json_result(conn
, VTOY_JSON_INVALID_RSV_RET
);
1075 vlog("==================================================================================\n");
1076 vlog("===== ventoy install %s style:%s secureboot:%u align4K:%u reserve:%llu =========\n",
1077 disk
->disk_path
, (style
? "GPT" : "MBR"), secure_boot
, align4kb
, (_ull
)reserveBytes
);
1078 vlog("==================================================================================\n");
1080 if (ventoy_is_disk_mounted(disk
->disk_path
))
1082 vlog("disk is mounted, now try to unmount it ...\n");
1083 ventoy_try_umount_disk(disk
->disk_path
);
1086 if (ventoy_is_disk_mounted(disk
->disk_path
))
1088 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1089 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1094 vlog("disk is not mounted now, we can do the install ...\n");
1097 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1100 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1101 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1105 vdebug("start install thread %s ...\n", disk
->disk_model
);
1106 thread
= zalloc(sizeof(ventoy_thread_data
));
1109 vtoy_safe_close_fd(fd
);
1110 vlog("failed to alloc thread data err:%d\n", errno
);
1111 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1115 g_current_progress
= PT_START
;
1116 g_cur_process_result
= 0;
1117 scnprintf(g_cur_process_type
, "%s", "install");
1118 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1120 thread
->disk
= disk
;
1121 thread
->diskfd
= fd
;
1122 thread
->align4kb
= align4kb
;
1123 thread
->partstyle
= style
;
1124 thread
->secure_boot
= secure_boot
;
1125 thread
->reserveBytes
= reserveBytes
;
1127 mg_start_thread(ventoy_install_thread
, thread
);
1129 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1133 static int ventoy_api_update(struct mg_connection
*conn
, VTOY_JSON
*json
)
1138 uint32_t secure_boot
= 0;
1139 ventoy_disk
*disk
= NULL
;
1140 const char *diskname
= NULL
;
1141 ventoy_thread_data
*thread
= NULL
;
1144 if (g_current_progress
!= PT_FINISH
)
1146 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1150 diskname
= vtoy_json_get_string_ex(json
, "disk");
1151 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1152 if (diskname
== NULL
|| ret
!= JSON_SUCCESS
)
1154 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1158 for (i
= 0; i
< g_disk_num
; i
++)
1160 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1162 disk
= g_disk_list
+ i
;
1169 vlog("disk %s not found\n", diskname
);
1170 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1174 if (disk
->vtoydata
.ventoy_valid
== 0)
1176 vlog("disk %s is not ventoy disk\n", diskname
);
1177 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1181 scnprintf(path
, "/sys/block/%s", diskname
);
1182 if (access(path
, F_OK
) < 0)
1184 vlog("File %s not exist anymore\n", path
);
1185 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1189 vlog("==========================================================\n");
1190 vlog("===== ventoy update %s new_secureboot:%u =========\n", disk
->disk_path
, secure_boot
);
1191 vlog("==========================================================\n");
1193 vlog("%s version:%s partstyle:%u oldsecureboot:%u reserve:%llu\n",
1194 disk
->disk_path
, disk
->vtoydata
.ventoy_ver
,
1195 disk
->vtoydata
.partition_style
,
1196 disk
->vtoydata
.secure_boot_flag
,
1197 (_ull
)(disk
->vtoydata
.preserved_space
)
1200 if (ventoy_is_disk_mounted(disk
->disk_path
))
1202 vlog("disk is mounted, now try to unmount it ...\n");
1203 ventoy_try_umount_disk(disk
->disk_path
);
1206 if (ventoy_is_disk_mounted(disk
->disk_path
))
1208 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1209 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1214 vlog("disk is not mounted now, we can do the update ...\n");
1217 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1220 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1221 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1225 vdebug("start update thread %s ...\n", disk
->disk_model
);
1226 thread
= zalloc(sizeof(ventoy_thread_data
));
1229 vtoy_safe_close_fd(fd
);
1230 vlog("failed to alloc thread data err:%d\n", errno
);
1231 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1235 g_current_progress
= PT_START
;
1236 g_cur_process_result
= 0;
1237 scnprintf(g_cur_process_type
, "%s", "update");
1238 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1240 thread
->disk
= disk
;
1241 thread
->diskfd
= fd
;
1242 thread
->secure_boot
= secure_boot
;
1244 mg_start_thread(ventoy_update_thread
, thread
);
1246 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1251 static int ventoy_api_refresh_device(struct mg_connection
*conn
, VTOY_JSON
*json
)
1255 if (g_current_progress
== PT_FINISH
)
1258 ventoy_disk_enumerate_all();
1261 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1265 static int ventoy_api_get_dev_list(struct mg_connection
*conn
, VTOY_JSON
*json
)
1271 uint32_t alldev
= 0;
1273 ventoy_disk
*cur
= NULL
;
1275 rc
= vtoy_json_get_uint(json
, "alldev", &alldev
);
1276 if (JSON_SUCCESS
!= rc
)
1281 buflen
= g_disk_num
* 1024;
1282 buf
= (char *)malloc(buflen
+ 1024);
1285 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1289 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
1290 VTOY_JSON_FMT_OBJ_BEGIN();
1291 VTOY_JSON_FMT_KEY("list");
1292 VTOY_JSON_FMT_ARY_BEGIN();
1294 for (i
= 0; i
< g_disk_num
; i
++)
1296 cur
= g_disk_list
+ i
;
1298 if (alldev
== 0 && cur
->type
!= VTOY_DEVICE_USB
)
1303 VTOY_JSON_FMT_OBJ_BEGIN();
1304 VTOY_JSON_FMT_STRN("name", cur
->disk_name
);
1305 VTOY_JSON_FMT_STRN("model", cur
->disk_model
);
1306 VTOY_JSON_FMT_STRN("size", cur
->human_readable_size
);
1307 VTOY_JSON_FMT_UINT("vtoy_valid", cur
->vtoydata
.ventoy_valid
);
1308 VTOY_JSON_FMT_STRN("vtoy_ver", cur
->vtoydata
.ventoy_ver
);
1309 VTOY_JSON_FMT_UINT("vtoy_secure_boot", cur
->vtoydata
.secure_boot_flag
);
1310 VTOY_JSON_FMT_UINT("vtoy_partstyle", cur
->vtoydata
.partition_style
);
1311 VTOY_JSON_FMT_OBJ_ENDEX();
1314 VTOY_JSON_FMT_ARY_END();
1315 VTOY_JSON_FMT_OBJ_END();
1316 VTOY_JSON_FMT_END(pos
);
1318 ventoy_json_buffer(conn
, buf
, pos
);
1322 static JSON_CB g_ventoy_json_cb
[] =
1324 { "sysinfo", ventoy_api_sysinfo
},
1325 { "sel_language", ventoy_api_set_language
},
1326 { "sel_partstyle", ventoy_api_set_partstyle
},
1327 { "refresh_device", ventoy_api_refresh_device
},
1328 { "get_dev_list", ventoy_api_get_dev_list
},
1329 { "install", ventoy_api_install
},
1330 { "update", ventoy_api_update
},
1331 { "clean", ventoy_api_clean
},
1332 { "get_percent", ventoy_api_get_percent
},
1335 static int ventoy_json_handler(struct mg_connection
*conn
, VTOY_JSON
*json
)
1338 const char *token
= NULL
;
1339 const char *method
= NULL
;
1341 method
= vtoy_json_get_string_ex(json
, "method");
1344 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1348 if (strcmp(method
, "sysinfo"))
1350 token
= vtoy_json_get_string_ex(json
, "token");
1351 if (token
== NULL
|| strcmp(token
, g_cur_server_token
))
1353 ventoy_json_result(conn
, VTOY_JSON_TOKEN_ERR_RET
);
1358 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1360 if (strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1362 g_ventoy_json_cb
[i
].callback(conn
, json
);
1370 static int ventoy_request_handler(struct mg_connection
*conn
)
1374 VTOY_JSON
*json
= NULL
;
1375 char *post_data_buf
= NULL
;
1376 const struct mg_request_info
*ri
= NULL
;
1377 char stack_buf
[512];
1379 ri
= mg_get_request_info(conn
);
1381 if (strcmp(ri
->uri
, "/vtoy/json") == 0)
1383 if (ri
->content_length
> 500)
1385 post_data_buf
= malloc(ri
->content_length
+ 4);
1386 post_buf_len
= ri
->content_length
+ 1;
1390 post_data_buf
= stack_buf
;
1391 post_buf_len
= sizeof(stack_buf
);
1394 post_data_len
= mg_read(conn
, post_data_buf
, post_buf_len
);
1395 post_data_buf
[post_data_len
] = 0;
1397 json
= vtoy_json_create();
1398 if (JSON_SUCCESS
== vtoy_json_parse(json
, post_data_buf
))
1400 pthread_mutex_lock(&g_api_mutex
);
1401 ventoy_json_handler(conn
, json
->pstChild
);
1402 pthread_mutex_unlock(&g_api_mutex
);
1406 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1409 vtoy_json_destroy(json
);
1411 if (post_data_buf
!= stack_buf
)
1413 free(post_data_buf
);
1423 int ventoy_http_start(const char *ip
, const char *port
)
1427 struct mg_callbacks callbacks
;
1428 const char *options
[] =
1430 "listening_ports", "24680",
1431 "document_root", "WebUI",
1432 "error_log_file", VTOY_LOG_FILE
,
1433 "request_timeout_ms", "10000",
1438 ventoy_gen_preudo_uuid(uuid
);
1439 scnprintf(g_cur_server_token
, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1440 uuid
[0], uuid
[1], uuid
[2], uuid
[3], uuid
[4], uuid
[5], uuid
[6], uuid
[7],
1441 uuid
[8], uuid
[9], uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
1444 scnprintf(addr
, "%s:%s", ip
, port
);
1447 memset(&callbacks
, 0, sizeof(callbacks
));
1448 callbacks
.begin_request
= ventoy_request_handler
;
1449 g_ventoy_http_ctx
= mg_start(&callbacks
, NULL
, options
);
1451 return g_ventoy_http_ctx
? 0 : 1;
1454 int ventoy_http_stop(void)
1456 if (g_ventoy_http_ctx
)
1458 mg_stop(g_ventoy_http_ctx
);
1463 int ventoy_http_init(void)
1465 pthread_mutex_init(&g_api_mutex
, NULL
);
1467 ventoy_http_load_cfg();
1469 ventoy_load_mbr_template();
1474 void ventoy_http_exit(void)
1476 pthread_mutex_destroy(&g_api_mutex
);
1478 check_free(g_efi_part_raw_img
);
1479 g_efi_part_raw_img
= NULL
;