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
;
731 vdebug("ventoy_update_thread run ...\n");
736 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
737 vdebug("check disk %s\n", disk
->disk_name
);
738 if (ventoy_is_disk_mounted(disk
->disk_path
))
740 vlog("disk is mounted, now try to unmount it ...\n");
741 ventoy_try_umount_disk(disk
->disk_path
);
744 if (ventoy_is_disk_mounted(disk
->disk_path
))
746 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
751 vlog("disk is not mounted now, we can do continue ...\n");
754 g_current_progress
= PT_LOAD_CORE_IMG
;
755 ventoy_unxz_stg1_img();
757 g_current_progress
= PT_LOAD_DISK_IMG
;
758 ventoy_unxz_efipart_img();
760 g_current_progress
= PT_FORMAT_PART2
;
762 vlog("Formatting part2 EFI ...\n");
763 if (0 != ventoy_write_efipart(fd
, disk
->vtoydata
.part2_start_sector
* 512, thread
->secure_boot
))
765 vlog("Failed to format part2 efi ...\n");
769 g_current_progress
= PT_WRITE_STG1_IMG
;
771 vlog("Writing legacy grub ...\n");
772 if (0 != ventoy_write_legacy_grub(fd
, disk
->vtoydata
.partition_style
))
774 vlog("ventoy_write_legacy_grub failed ...\n");
778 offset
= lseek(fd
, 512 * 2040, SEEK_SET
);
779 len
= write(fd
, disk
->vtoydata
.rsvdata
, sizeof(disk
->vtoydata
.rsvdata
));
780 vlog("Writing reserve data offset:%llu len:%llu ...\n", (_ull
)offset
, (_ull
)len
);
782 if (ventoy_mbr_need_update(disk
, &MBR
))
784 offset
= lseek(fd
, 0, SEEK_SET
);
785 len
= write(fd
, &MBR
, 512);
786 vlog("update MBR offset:%llu len:%llu\n", (_ull
)offset
, (_ull
)len
);
790 vlog("No need to update MBR\n");
793 g_current_progress
= PT_SYNC_DATA1
;
795 vlog("fsync data1...\n");
797 vtoy_safe_close_fd(fd
);
799 g_current_progress
= PT_SYNC_DATA2
;
801 vlog("====================================\n");
802 vlog("====== ventoy update success ======\n");
803 vlog("====================================\n");
807 g_cur_process_result
= 1;
808 vtoy_safe_close_fd(fd
);
811 g_current_progress
= PT_FINISH
;
818 static void * ventoy_install_thread(void *data
)
824 ventoy_disk
*disk
= NULL
;
825 VTOY_GPT_INFO
*gpt
= NULL
;
826 ventoy_thread_data
*thread
= (ventoy_thread_data
*)data
;
827 uint64_t Part1StartSector
= 0;
828 uint64_t Part1SectorCount
= 0;
829 uint64_t Part2StartSector
= 0;
831 vdebug("ventoy_install_thread run ...\n");
836 g_current_progress
= PT_PRAPARE_FOR_CLEAN
;
837 vdebug("check disk %s\n", disk
->disk_name
);
838 if (ventoy_is_disk_mounted(disk
->disk_path
))
840 vlog("disk is mounted, now try to unmount it ...\n");
841 ventoy_try_umount_disk(disk
->disk_path
);
844 if (ventoy_is_disk_mounted(disk
->disk_path
))
846 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
851 vlog("disk is not mounted now, we can do continue ...\n");
854 g_current_progress
= PT_DEL_ALL_PART
;
855 ventoy_clean_disk(fd
, disk
->size_in_byte
);
857 g_current_progress
= PT_LOAD_CORE_IMG
;
858 ventoy_unxz_stg1_img();
860 g_current_progress
= PT_LOAD_DISK_IMG
;
861 ventoy_unxz_efipart_img();
863 if (thread
->partstyle
)
865 vdebug("Fill GPT part table\n");
866 gpt
= zalloc(sizeof(VTOY_GPT_INFO
));
867 ventoy_fill_gpt(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, gpt
);
868 Part1StartSector
= gpt
->PartTbl
[0].StartLBA
;
869 Part1SectorCount
= gpt
->PartTbl
[0].LastLBA
- Part1StartSector
+ 1;
870 Part2StartSector
= gpt
->PartTbl
[1].StartLBA
;
874 vdebug("Fill MBR part table\n");
875 ventoy_fill_mbr(disk
->size_in_byte
, thread
->reserveBytes
, thread
->align4kb
, &MBR
);
876 Part1StartSector
= MBR
.PartTbl
[0].StartSectorId
;
877 Part1SectorCount
= MBR
.PartTbl
[0].SectorCount
;
878 Part2StartSector
= MBR
.PartTbl
[1].StartSectorId
;
881 vlog("Part1StartSector:%llu Part1SectorCount:%llu Part2StartSector:%llu\n",
882 (_ull
)Part1StartSector
, (_ull
)Part1SectorCount
, (_ull
)Part2StartSector
);
884 if (thread
->partstyle
!= disk
->partstyle
)
886 vlog("Wait for format part1 (partstyle changed) ...\n");
890 g_current_progress
= PT_FORMAT_PART1
;
891 vlog("Formatting part1 exFAT %s ...\n", disk
->disk_path
);
892 if (0 != mkexfat_main(disk
->disk_path
, fd
, Part1SectorCount
))
894 vlog("Failed to format exfat ...\n");
898 g_current_progress
= PT_FORMAT_PART2
;
899 vlog("Formatting part2 EFI ...\n");
900 if (0 != ventoy_write_efipart(fd
, Part2StartSector
* 512, thread
->secure_boot
))
902 vlog("Failed to format part2 efi ...\n");
906 g_current_progress
= PT_WRITE_STG1_IMG
;
907 vlog("Writing legacy grub ...\n");
908 if (0 != ventoy_write_legacy_grub(fd
, thread
->partstyle
))
910 vlog("ventoy_write_legacy_grub failed ...\n");
914 g_current_progress
= PT_SYNC_DATA1
;
915 vlog("fsync data1...\n");
917 vtoy_safe_close_fd(fd
);
919 /* reopen for check part2 data */
920 vlog("Checking part2 efi data %s ...\n", disk
->disk_path
);
921 g_current_progress
= PT_CHECK_PART2
;
922 fd
= open(disk
->disk_path
, O_RDONLY
| O_BINARY
);
925 vlog("failed to open %s for check fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
929 if (0 == ventoy_check_efi_part_data(fd
, Part2StartSector
* 512))
931 vlog("efi part data check success\n");
935 vlog("efi part data check failed\n");
939 vtoy_safe_close_fd(fd
);
941 /* reopen for write part table */
942 g_current_progress
= PT_WRITE_PART_TABLE
;
943 vlog("Writting Partition Table style:%d...\n", thread
->partstyle
);
945 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
948 vlog("failed to open %s for part table fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
952 if (thread
->partstyle
)
954 ventoy_write_gpt_part_table(fd
, disk
->size_in_byte
, gpt
);
958 offset
= lseek(fd
, 0, SEEK_SET
);
959 len
= write(fd
, &MBR
, 512);
960 vlog("Writting MBR Partition Table %llu %llu\n", (_ull
)offset
, (_ull
)len
);
961 if (offset
!= 0 || len
!= 512)
967 g_current_progress
= PT_SYNC_DATA2
;
968 vlog("fsync data2...\n");
970 vtoy_safe_close_fd(fd
);
973 vlog("====================================\n");
974 vlog("====== ventoy install success ======\n");
975 vlog("====================================\n");
979 g_cur_process_result
= 1;
980 vtoy_safe_close_fd(fd
);
983 g_current_progress
= PT_FINISH
;
991 static int ventoy_api_clean(struct mg_connection
*conn
, VTOY_JSON
*json
)
995 ventoy_disk
*disk
= NULL
;
996 const char *diskname
= NULL
;
999 if (g_current_progress
!= PT_FINISH
)
1001 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1005 diskname
= vtoy_json_get_string_ex(json
, "disk");
1006 if (diskname
== NULL
)
1008 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1012 for (i
= 0; i
< g_disk_num
; i
++)
1014 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1016 disk
= g_disk_list
+ i
;
1023 vlog("disk %s not found\n", diskname
);
1024 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1028 scnprintf(path
, "/sys/block/%s", diskname
);
1029 if (access(path
, F_OK
) < 0)
1031 vlog("File %s not exist anymore\n", path
);
1032 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1036 vlog("==================================\n");
1037 vlog("===== ventoy clean %s =====\n", disk
->disk_path
);
1038 vlog("==================================\n");
1040 if (ventoy_is_disk_mounted(disk
->disk_path
))
1042 vlog("disk is mounted, now try to unmount it ...\n");
1043 ventoy_try_umount_disk(disk
->disk_path
);
1046 if (ventoy_is_disk_mounted(disk
->disk_path
))
1048 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1049 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1054 vlog("disk is not mounted now, we can do the clean ...\n");
1057 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1060 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1061 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1065 vdebug("start clean %s ...\n", disk
->disk_model
);
1066 ventoy_clean_disk(fd
, disk
->size_in_byte
);
1068 vtoy_safe_close_fd(fd
);
1070 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1074 static int ventoy_api_install(struct mg_connection
*conn
, VTOY_JSON
*json
)
1079 uint32_t align4kb
= 0;
1081 uint32_t secure_boot
= 0;
1082 uint64_t reserveBytes
= 0;
1083 ventoy_disk
*disk
= NULL
;
1084 const char *diskname
= NULL
;
1085 const char *reserve_space
= NULL
;
1086 ventoy_thread_data
*thread
= NULL
;
1089 if (g_current_progress
!= PT_FINISH
)
1091 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1095 diskname
= vtoy_json_get_string_ex(json
, "disk");
1096 reserve_space
= vtoy_json_get_string_ex(json
, "reserve_space");
1097 ret
+= vtoy_json_get_uint(json
, "partstyle", &style
);
1098 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1099 ret
+= vtoy_json_get_uint(json
, "align_4kb", &align4kb
);
1101 if (diskname
== NULL
|| reserve_space
== NULL
|| ret
!= JSON_SUCCESS
)
1103 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1107 reserveBytes
= (uint64_t)strtoull(reserve_space
, NULL
, 10);
1109 for (i
= 0; i
< g_disk_num
; i
++)
1111 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1113 disk
= g_disk_list
+ i
;
1120 vlog("disk %s not found\n", diskname
);
1121 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1125 scnprintf(path
, "/sys/block/%s", diskname
);
1126 if (access(path
, F_OK
) < 0)
1128 vlog("File %s not exist anymore\n", path
);
1129 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1133 if (disk
->size_in_byte
> 2199023255552ULL && style
== 0)
1135 vlog("disk %s is more than 2TB and GPT is needed\n", path
);
1136 ventoy_json_result(conn
, VTOY_JSON_MBR_2TB_RET
);
1140 if ((reserveBytes
+ VTOYEFI_PART_BYTES
* 2) > disk
->size_in_byte
)
1142 vlog("reserve space %llu is too big for disk %s %llu\n", (_ull
)reserveBytes
, path
, (_ull
)disk
->size_in_byte
);
1143 ventoy_json_result(conn
, VTOY_JSON_INVALID_RSV_RET
);
1147 vlog("==================================================================================\n");
1148 vlog("===== ventoy install %s style:%s secureboot:%u align4K:%u reserve:%llu =========\n",
1149 disk
->disk_path
, (style
? "GPT" : "MBR"), secure_boot
, align4kb
, (_ull
)reserveBytes
);
1150 vlog("==================================================================================\n");
1152 if (ventoy_is_disk_mounted(disk
->disk_path
))
1154 vlog("disk is mounted, now try to unmount it ...\n");
1155 ventoy_try_umount_disk(disk
->disk_path
);
1158 if (ventoy_is_disk_mounted(disk
->disk_path
))
1160 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1161 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1166 vlog("disk is not mounted now, we can do the install ...\n");
1169 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1172 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1173 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1177 vdebug("start install thread %s ...\n", disk
->disk_model
);
1178 thread
= zalloc(sizeof(ventoy_thread_data
));
1181 vtoy_safe_close_fd(fd
);
1182 vlog("failed to alloc thread data err:%d\n", errno
);
1183 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1187 g_current_progress
= PT_START
;
1188 g_cur_process_result
= 0;
1189 scnprintf(g_cur_process_type
, "%s", "install");
1190 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1192 thread
->disk
= disk
;
1193 thread
->diskfd
= fd
;
1194 thread
->align4kb
= align4kb
;
1195 thread
->partstyle
= style
;
1196 thread
->secure_boot
= secure_boot
;
1197 thread
->reserveBytes
= reserveBytes
;
1199 mg_start_thread(ventoy_install_thread
, thread
);
1201 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1205 static int ventoy_api_update(struct mg_connection
*conn
, VTOY_JSON
*json
)
1210 uint32_t secure_boot
= 0;
1211 ventoy_disk
*disk
= NULL
;
1212 const char *diskname
= NULL
;
1213 ventoy_thread_data
*thread
= NULL
;
1216 if (g_current_progress
!= PT_FINISH
)
1218 ventoy_json_result(conn
, VTOY_JSON_BUSY_RET
);
1222 diskname
= vtoy_json_get_string_ex(json
, "disk");
1223 ret
+= vtoy_json_get_uint(json
, "secure_boot", &secure_boot
);
1224 if (diskname
== NULL
|| ret
!= JSON_SUCCESS
)
1226 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1230 for (i
= 0; i
< g_disk_num
; i
++)
1232 if (strcmp(g_disk_list
[i
].disk_name
, diskname
) == 0)
1234 disk
= g_disk_list
+ i
;
1241 vlog("disk %s not found\n", diskname
);
1242 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1246 if (disk
->vtoydata
.ventoy_valid
== 0)
1248 vlog("disk %s is not ventoy disk\n", diskname
);
1249 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1253 scnprintf(path
, "/sys/block/%s", diskname
);
1254 if (access(path
, F_OK
) < 0)
1256 vlog("File %s not exist anymore\n", path
);
1257 ventoy_json_result(conn
, VTOY_JSON_NOTFOUND_RET
);
1261 vlog("==========================================================\n");
1262 vlog("===== ventoy update %s new_secureboot:%u =========\n", disk
->disk_path
, secure_boot
);
1263 vlog("==========================================================\n");
1265 vlog("%s version:%s partstyle:%u oldsecureboot:%u reserve:%llu\n",
1266 disk
->disk_path
, disk
->vtoydata
.ventoy_ver
,
1267 disk
->vtoydata
.partition_style
,
1268 disk
->vtoydata
.secure_boot_flag
,
1269 (_ull
)(disk
->vtoydata
.preserved_space
)
1272 if (ventoy_is_disk_mounted(disk
->disk_path
))
1274 vlog("disk is mounted, now try to unmount it ...\n");
1275 ventoy_try_umount_disk(disk
->disk_path
);
1278 if (ventoy_is_disk_mounted(disk
->disk_path
))
1280 vlog("%s is mounted and can't umount!\n", disk
->disk_path
);
1281 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1286 vlog("disk is not mounted now, we can do the update ...\n");
1289 fd
= open(disk
->disk_path
, O_RDWR
| O_BINARY
);
1292 vlog("failed to open %s fd:%d err:%d\n", disk
->disk_path
, fd
, errno
);
1293 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1297 vdebug("start update thread %s ...\n", disk
->disk_model
);
1298 thread
= zalloc(sizeof(ventoy_thread_data
));
1301 vtoy_safe_close_fd(fd
);
1302 vlog("failed to alloc thread data err:%d\n", errno
);
1303 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1307 g_current_progress
= PT_START
;
1308 g_cur_process_result
= 0;
1309 scnprintf(g_cur_process_type
, "%s", "update");
1310 scnprintf(g_cur_process_diskname
, "%s", disk
->disk_name
);
1312 thread
->disk
= disk
;
1313 thread
->diskfd
= fd
;
1314 thread
->secure_boot
= secure_boot
;
1316 mg_start_thread(ventoy_update_thread
, thread
);
1318 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1323 static int ventoy_api_refresh_device(struct mg_connection
*conn
, VTOY_JSON
*json
)
1327 if (g_current_progress
== PT_FINISH
)
1330 ventoy_disk_enumerate_all();
1333 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1337 static int ventoy_api_get_dev_list(struct mg_connection
*conn
, VTOY_JSON
*json
)
1343 uint32_t alldev
= 0;
1345 ventoy_disk
*cur
= NULL
;
1347 rc
= vtoy_json_get_uint(json
, "alldev", &alldev
);
1348 if (JSON_SUCCESS
!= rc
)
1353 buflen
= g_disk_num
* 1024;
1354 buf
= (char *)malloc(buflen
+ 1024);
1357 ventoy_json_result(conn
, VTOY_JSON_FAILED_RET
);
1361 VTOY_JSON_FMT_BEGIN(pos
, buf
, buflen
);
1362 VTOY_JSON_FMT_OBJ_BEGIN();
1363 VTOY_JSON_FMT_KEY("list");
1364 VTOY_JSON_FMT_ARY_BEGIN();
1366 for (i
= 0; i
< g_disk_num
; i
++)
1368 cur
= g_disk_list
+ i
;
1370 if (alldev
== 0 && cur
->type
!= VTOY_DEVICE_USB
)
1375 VTOY_JSON_FMT_OBJ_BEGIN();
1376 VTOY_JSON_FMT_STRN("name", cur
->disk_name
);
1377 VTOY_JSON_FMT_STRN("model", cur
->disk_model
);
1378 VTOY_JSON_FMT_STRN("size", cur
->human_readable_size
);
1379 VTOY_JSON_FMT_UINT("vtoy_valid", cur
->vtoydata
.ventoy_valid
);
1380 VTOY_JSON_FMT_STRN("vtoy_ver", cur
->vtoydata
.ventoy_ver
);
1381 VTOY_JSON_FMT_UINT("vtoy_secure_boot", cur
->vtoydata
.secure_boot_flag
);
1382 VTOY_JSON_FMT_UINT("vtoy_partstyle", cur
->vtoydata
.partition_style
);
1383 VTOY_JSON_FMT_OBJ_ENDEX();
1386 VTOY_JSON_FMT_ARY_END();
1387 VTOY_JSON_FMT_OBJ_END();
1388 VTOY_JSON_FMT_END(pos
);
1390 ventoy_json_buffer(conn
, buf
, pos
);
1394 static JSON_CB g_ventoy_json_cb
[] =
1396 { "sysinfo", ventoy_api_sysinfo
},
1397 { "sel_language", ventoy_api_set_language
},
1398 { "sel_partstyle", ventoy_api_set_partstyle
},
1399 { "refresh_device", ventoy_api_refresh_device
},
1400 { "get_dev_list", ventoy_api_get_dev_list
},
1401 { "install", ventoy_api_install
},
1402 { "update", ventoy_api_update
},
1403 { "clean", ventoy_api_clean
},
1404 { "get_percent", ventoy_api_get_percent
},
1407 static int ventoy_json_handler(struct mg_connection
*conn
, VTOY_JSON
*json
)
1410 const char *token
= NULL
;
1411 const char *method
= NULL
;
1413 method
= vtoy_json_get_string_ex(json
, "method");
1416 ventoy_json_result(conn
, VTOY_JSON_SUCCESS_RET
);
1420 if (strcmp(method
, "sysinfo"))
1422 token
= vtoy_json_get_string_ex(json
, "token");
1423 if (token
== NULL
|| strcmp(token
, g_cur_server_token
))
1425 ventoy_json_result(conn
, VTOY_JSON_TOKEN_ERR_RET
);
1430 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1432 if (strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1434 g_ventoy_json_cb
[i
].callback(conn
, json
);
1442 int ventoy_func_handler(const char *jsonstr
, char *jsonbuf
, int buflen
)
1445 const char *method
= NULL
;
1446 VTOY_JSON
*json
= NULL
;
1448 g_pub_out_buf
= jsonbuf
;
1449 g_pub_out_max
= buflen
;
1451 json
= vtoy_json_create();
1452 if (JSON_SUCCESS
== vtoy_json_parse(json
, jsonstr
))
1454 pthread_mutex_lock(&g_api_mutex
);
1456 method
= vtoy_json_get_string_ex(json
->pstChild
, "method");
1457 for (i
= 0; i
< (int)(sizeof(g_ventoy_json_cb
) / sizeof(g_ventoy_json_cb
[0])); i
++)
1459 if (method
&& strcmp(method
, g_ventoy_json_cb
[i
].method
) == 0)
1461 g_ventoy_json_cb
[i
].callback(NULL
, json
->pstChild
);
1466 pthread_mutex_unlock(&g_api_mutex
);
1470 ventoy_json_result(NULL
, VTOY_JSON_INVALID_RET
);
1473 vtoy_json_destroy(json
);
1477 static int ventoy_request_handler(struct mg_connection
*conn
)
1481 VTOY_JSON
*json
= NULL
;
1482 char *post_data_buf
= NULL
;
1483 const struct mg_request_info
*ri
= NULL
;
1484 char stack_buf
[512];
1486 ri
= mg_get_request_info(conn
);
1488 if (strcmp(ri
->uri
, "/vtoy/json") == 0)
1490 if (ri
->content_length
> 500)
1492 post_data_buf
= malloc(ri
->content_length
+ 4);
1493 post_buf_len
= ri
->content_length
+ 1;
1497 post_data_buf
= stack_buf
;
1498 post_buf_len
= sizeof(stack_buf
);
1501 post_data_len
= mg_read(conn
, post_data_buf
, post_buf_len
);
1502 post_data_buf
[post_data_len
] = 0;
1504 json
= vtoy_json_create();
1505 if (JSON_SUCCESS
== vtoy_json_parse(json
, post_data_buf
))
1507 pthread_mutex_lock(&g_api_mutex
);
1508 ventoy_json_handler(conn
, json
->pstChild
);
1509 pthread_mutex_unlock(&g_api_mutex
);
1513 ventoy_json_result(conn
, VTOY_JSON_INVALID_RET
);
1516 vtoy_json_destroy(json
);
1518 if (post_data_buf
!= stack_buf
)
1520 free(post_data_buf
);
1530 int ventoy_http_start(const char *ip
, const char *port
)
1534 struct mg_callbacks callbacks
;
1535 const char *options
[] =
1537 "listening_ports", "24680",
1538 "document_root", "WebUI",
1539 "error_log_file", g_log_file
,
1540 "request_timeout_ms", "10000",
1545 ventoy_gen_preudo_uuid(uuid
);
1546 scnprintf(g_cur_server_token
, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1547 uuid
[0], uuid
[1], uuid
[2], uuid
[3], uuid
[4], uuid
[5], uuid
[6], uuid
[7],
1548 uuid
[8], uuid
[9], uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14], uuid
[15]);
1551 scnprintf(addr
, "%s:%s", ip
, port
);
1554 memset(&callbacks
, 0, sizeof(callbacks
));
1555 callbacks
.begin_request
= ventoy_request_handler
;
1556 g_ventoy_http_ctx
= mg_start(&callbacks
, NULL
, options
);
1558 return g_ventoy_http_ctx
? 0 : 1;
1561 int ventoy_http_stop(void)
1563 if (g_ventoy_http_ctx
)
1565 mg_stop(g_ventoy_http_ctx
);
1570 int ventoy_http_init(void)
1572 pthread_mutex_init(&g_api_mutex
, NULL
);
1574 ventoy_http_load_cfg();
1576 ventoy_load_mbr_template();
1581 void ventoy_http_exit(void)
1583 pthread_mutex_destroy(&g_api_mutex
);
1585 check_free(g_efi_part_raw_img
);
1586 g_efi_part_raw_img
= NULL
;
1590 const char * ventoy_code_get_cur_language(void)
1592 return g_cur_language
;
1595 int ventoy_code_get_cur_part_style(void)
1597 return g_cur_part_style
;
1600 void ventoy_code_set_cur_part_style(int style
)
1602 pthread_mutex_lock(&g_api_mutex
);
1604 g_cur_part_style
= style
;
1605 ventoy_http_save_cfg();
1607 pthread_mutex_unlock(&g_api_mutex
);
1610 int ventoy_code_get_cur_show_all(void)
1612 return g_cur_show_all
;
1615 void ventoy_code_set_cur_show_all(int show_all
)
1617 pthread_mutex_lock(&g_api_mutex
);
1619 g_cur_show_all
= show_all
;
1620 ventoy_http_save_cfg();
1622 pthread_mutex_unlock(&g_api_mutex
);
1625 void ventoy_code_set_cur_language(const char *lang
)
1627 pthread_mutex_lock(&g_api_mutex
);
1629 scnprintf(g_cur_language
, "%s", lang
);
1630 ventoy_http_save_cfg();
1632 pthread_mutex_unlock(&g_api_mutex
);
1635 void ventoy_code_refresh_device(void)
1637 if (g_current_progress
== PT_FINISH
)
1640 ventoy_disk_enumerate_all();
1644 int ventoy_code_is_busy(void)
1646 return (g_current_progress
== PT_FINISH
) ? 0 : 1;
1649 int ventoy_code_get_percent(void)
1651 return g_current_progress
* 100 / PT_FINISH
;
1654 int ventoy_code_get_result(void)
1656 return g_cur_process_result
;
1659 void ventoy_code_save_cfg(void)
1661 ventoy_http_save_cfg();