]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - LinuxGUI/Ventoy2Disk/Web/ventoy_http.c
Add Linux native GUI program for Ventoy2Disk.
[Ventoy.git] / LinuxGUI / Ventoy2Disk / Web / ventoy_http.c
1 /******************************************************************************
2 * ventoy_http.c ---- ventoy http
3 * Copyright (c) 2021, longpanda <admin@ventoy.net>
4 *
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.
9 *
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.
14 *
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/>.
17 *
18 */
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/mount.h>
33 #include <linux/fs.h>
34 #include <dirent.h>
35 #include <pthread.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"
42
43 static char *g_pub_out_buf = NULL;
44 static int g_pub_out_max = 0;
45
46 static pthread_mutex_t g_api_mutex;
47 static char g_cur_language[128];
48 static int g_cur_part_style = 0;
49 static int g_cur_show_all = 0;
50 static char g_cur_server_token[64];
51 static struct mg_context *g_ventoy_http_ctx = NULL;
52
53 static uint32_t g_efi_part_offset = 0;
54 static uint8_t *g_efi_part_raw_img = NULL;
55 static uint8_t *g_grub_stg1_raw_img = NULL;
56
57 static char g_cur_process_diskname[64];
58 static char g_cur_process_type[64];
59 static volatile int g_cur_process_result = 0;
60 static volatile PROGRESS_POINT g_current_progress = PT_FINISH;
61
62 static int ventoy_load_mbr_template(void)
63 {
64 FILE *fp = NULL;
65
66 fp = fopen("boot/boot.img", "rb");
67 if (fp == NULL)
68 {
69 vlog("Failed to open file boot/boot.img\n");
70 return 1;
71 }
72
73 fread(g_mbr_template, 1, 512, fp);
74 fclose(fp);
75
76 ventoy_gen_preudo_uuid(g_mbr_template + 0x180);
77 return 0;
78 }
79
80 static int ventoy_disk_xz_flush(void *src, unsigned int size)
81 {
82 memcpy(g_efi_part_raw_img + g_efi_part_offset, src, size);
83 g_efi_part_offset += size;
84
85 g_current_progress = PT_LOAD_DISK_IMG + (g_efi_part_offset / SIZE_1MB);
86 return (int)size;
87 }
88
89 static int ventoy_unxz_efipart_img(void)
90 {
91 int rc;
92 int inlen;
93 int xzlen;
94 void *xzbuf = NULL;
95 uint8_t *buf = NULL;
96
97 rc = ventoy_read_file_to_buf(VENTOY_FILE_DISK_IMG, 0, &xzbuf, &xzlen);
98 vdebug("read disk.img.xz rc:%d len:%d\n", rc, xzlen);
99
100 if (g_efi_part_raw_img)
101 {
102 buf = g_efi_part_raw_img;
103 }
104 else
105 {
106 buf = malloc(VTOYEFI_PART_BYTES);
107 if (!buf)
108 {
109 check_free(xzbuf);
110 return 1;
111 }
112 }
113
114 g_efi_part_offset = 0;
115 g_efi_part_raw_img = buf;
116
117 rc = unxz(xzbuf, xzlen, NULL, ventoy_disk_xz_flush, buf, &inlen, NULL);
118 vdebug("ventoy_unxz_efipart_img len:%d rc:%d unxzlen:%u\n", inlen, rc, g_efi_part_offset);
119
120 check_free(xzbuf);
121 return 0;
122 }
123
124 static int ventoy_unxz_stg1_img(void)
125 {
126 int rc;
127 int inlen;
128 int xzlen;
129 void *xzbuf = NULL;
130 uint8_t *buf = NULL;
131
132 rc = ventoy_read_file_to_buf(VENTOY_FILE_STG1_IMG, 0, &xzbuf, &xzlen);
133 vdebug("read core.img.xz rc:%d len:%d\n", rc, xzlen);
134
135 if (g_grub_stg1_raw_img)
136 {
137 buf = g_grub_stg1_raw_img;
138 }
139 else
140 {
141 buf = zalloc(SIZE_1MB);
142 if (!buf)
143 {
144 check_free(xzbuf);
145 return 1;
146 }
147 }
148
149 rc = unxz(xzbuf, xzlen, NULL, NULL, buf, &inlen, NULL);
150 vdebug("ventoy_unxz_stg1_img len:%d rc:%d\n", inlen, rc);
151
152 g_grub_stg1_raw_img = buf;
153
154 check_free(xzbuf);
155 return 0;
156 }
157
158
159 static int ventoy_http_save_cfg(void)
160 {
161 FILE *fp;
162
163 fp = fopen("./Ventoy2Disk.ini", "w");
164 if (!fp)
165 {
166 return 0;
167 }
168
169 fprintf(fp, "[Ventoy]\nLanguage=%s\nPartStyle=%d\nShowAllDevice=%d\n",
170 g_cur_language, g_cur_part_style, g_cur_show_all);
171
172 fclose(fp);
173 return 0;
174 }
175
176 static int ventoy_http_load_cfg(void)
177 {
178 int i;
179 int len;
180 char line[256];
181 FILE *fp;
182
183 fp = fopen("./Ventoy2Disk.ini", "r");
184 if (!fp)
185 {
186 return 0;
187 }
188
189 while (fgets(line, sizeof(line), fp))
190 {
191 len = (int)strlen(line);
192 for (i = len - 1; i >= 0; i--)
193 {
194 if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r' || line[i] == '\n')
195 {
196 line[i] = 0;
197 }
198 else
199 {
200 break;
201 }
202 }
203
204 len = (int)strlen("Language=");
205 if (strncmp(line, "Language=", len) == 0)
206 {
207 scnprintf(g_cur_language, "%s", line + len);
208 }
209 else if (strncmp(line, "PartStyle=", strlen("PartStyle=")) == 0)
210 {
211 g_cur_part_style = (int)strtol(line + strlen("PartStyle="), NULL, 10);
212 }
213 else if (strncmp(line, "ShowAllDevice=", strlen("ShowAllDevice=")) == 0)
214 {
215 g_cur_show_all = (int)strtol(line + strlen("ShowAllDevice="), NULL, 10);
216 }
217 }
218
219 fclose(fp);
220 return 0;
221 }
222
223
224 static int ventoy_json_result(struct mg_connection *conn, const char *err)
225 {
226 if (conn)
227 {
228 mg_printf(conn,
229 "HTTP/1.1 200 OK \r\n"
230 "Content-Type: application/json\r\n"
231 "Content-Length: %d\r\n"
232 "\r\n%s",
233 (int)strlen(err), err);
234 }
235 else
236 {
237 memcpy(g_pub_out_buf, err, (int)strlen(err) + 1);
238 }
239
240 return 0;
241 }
242
243 static int ventoy_json_buffer(struct mg_connection *conn, const char *json_buf, int json_len)
244 {
245 if (conn)
246 {
247 mg_printf(conn,
248 "HTTP/1.1 200 OK \r\n"
249 "Content-Type: application/json\r\n"
250 "Content-Length: %d\r\n"
251 "\r\n%s",
252 json_len, json_buf);
253 }
254 else
255 {
256 if (json_len >= g_pub_out_max)
257 {
258 vlog("json buffer overflow\n");
259 }
260 else
261 {
262 memcpy(g_pub_out_buf, json_buf, json_len);
263 g_pub_out_buf[json_len] = 0;
264 }
265 }
266
267 return 0;
268 }
269
270 static int ventoy_api_sysinfo(struct mg_connection *conn, VTOY_JSON *json)
271 {
272 int busy = 0;
273 int pos = 0;
274 int buflen = 0;
275 char buf[512];
276
277 (void)json;
278
279 busy = (g_current_progress == PT_FINISH) ? 0 : 1;
280
281 buflen = sizeof(buf) - 1;
282 VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
283 VTOY_JSON_FMT_OBJ_BEGIN();
284 VTOY_JSON_FMT_STRN("token", g_cur_server_token);
285 VTOY_JSON_FMT_STRN("language", g_cur_language);
286 VTOY_JSON_FMT_STRN("ventoy_ver", ventoy_get_local_version());
287 VTOY_JSON_FMT_UINT("partstyle", g_cur_part_style);
288 VTOY_JSON_FMT_BOOL("busy", busy);
289 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname);
290 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type);
291 VTOY_JSON_FMT_OBJ_END();
292 VTOY_JSON_FMT_END(pos);
293
294 ventoy_json_buffer(conn, buf, pos);
295 return 0;
296 }
297
298 static int ventoy_api_get_percent(struct mg_connection *conn, VTOY_JSON *json)
299 {
300 int pos = 0;
301 int buflen = 0;
302 int percent = 0;
303 char buf[128];
304
305 (void)json;
306
307 percent = g_current_progress * 100 / PT_FINISH;
308
309 buflen = sizeof(buf) - 1;
310 VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
311 VTOY_JSON_FMT_OBJ_BEGIN();
312 VTOY_JSON_FMT_STRN("result", g_cur_process_result ? "failed" : "success");
313 VTOY_JSON_FMT_STRN("process_disk", g_cur_process_diskname);
314 VTOY_JSON_FMT_STRN("process_type", g_cur_process_type);
315 VTOY_JSON_FMT_UINT("percent", percent);
316 VTOY_JSON_FMT_OBJ_END();
317 VTOY_JSON_FMT_END(pos);
318
319 ventoy_json_buffer(conn, buf, pos);
320 return 0;
321 }
322
323 static int ventoy_api_set_language(struct mg_connection *conn, VTOY_JSON *json)
324 {
325 const char *lang = NULL;
326
327 lang = vtoy_json_get_string_ex(json, "language");
328 if (lang)
329 {
330 scnprintf(g_cur_language, "%s", lang);
331 ventoy_http_save_cfg();
332 }
333
334 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
335 return 0;
336 }
337
338 static int ventoy_api_set_partstyle(struct mg_connection *conn, VTOY_JSON *json)
339 {
340 int ret;
341 int style = 0;
342
343 ret = vtoy_json_get_int(json, "partstyle", &style);
344 if (JSON_SUCCESS == ret)
345 {
346 if ((style == 0) || (style == 1))
347 {
348 g_cur_part_style = style;
349 ventoy_http_save_cfg();
350 }
351 }
352
353 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
354 return 0;
355 }
356
357 static int ventoy_clean_disk(int fd, uint64_t size)
358 {
359 int zerolen;
360 ssize_t len;
361 off_t offset;
362 void *buf = NULL;
363
364 vdebug("ventoy_clean_disk fd:%d size:%llu\n", fd, (_ull)size);
365
366 zerolen = 64 * 1024;
367 buf = zalloc(zerolen);
368 if (!buf)
369 {
370 vlog("failed to alloc clean buffer\n");
371 return 1;
372 }
373
374 offset = lseek(fd, 0, SEEK_SET);
375 len = write(fd, buf, zerolen);
376 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull)offset, (_ll)len, zerolen);
377
378 offset = lseek(fd, size - zerolen, SEEK_SET);
379 len = write(fd, buf, zerolen);
380 vdebug("write disk at off:%llu writelen:%lld datalen:%d\n", (_ull)offset, (_ll)len, zerolen);
381
382 fsync(fd);
383
384 free(buf);
385 return 0;
386 }
387
388 static int ventoy_write_legacy_grub(int fd, int partstyle)
389 {
390 ssize_t len;
391 off_t offset;
392
393 if (partstyle)
394 {
395 vlog("Write GPT stage1 ...\n");
396
397 offset = lseek(fd, 512 * 34, SEEK_SET);
398
399 g_grub_stg1_raw_img[500] = 35;//update blocklist
400 len = write(fd, g_grub_stg1_raw_img, SIZE_1MB - 512 * 34);
401
402 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull)offset, 512 * 34, (_ull)len, SIZE_1MB - 512 * 34);
403 if (SIZE_1MB - 512 * 34 != len)
404 {
405 vlog("write length error\n");
406 return 1;
407 }
408 }
409 else
410 {
411 vlog("Write MBR stage1 ...\n");
412 offset = lseek(fd, 512, SEEK_SET);
413 len = write(fd, g_grub_stg1_raw_img, SIZE_1MB - 512);
414
415 vlog("lseek offset:%llu(%u) writelen:%llu(%u)\n", (_ull)offset, 512, (_ull)len, SIZE_1MB - 512);
416 if (SIZE_1MB - 512 != len)
417 {
418 vlog("write length error\n");
419 return 1;
420 }
421 }
422
423 return 0;
424 }
425
426 static int VentoyFatMemRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
427 {
428 uint32 i;
429 uint32 offset;
430
431 for (i = 0; i < SectorCount; i++)
432 {
433 offset = (Sector + i) * 512;
434 memcpy(Buffer + i * 512, g_efi_part_raw_img + offset, 512);
435 }
436
437 return 1;
438 }
439
440 static int VentoyFatMemWrite(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
441 {
442 uint32 i;
443 uint32 offset;
444
445 for (i = 0; i < SectorCount; i++)
446 {
447 offset = (Sector + i) * 512;
448 memcpy(g_efi_part_raw_img + offset, Buffer + i * 512, 512);
449 }
450
451 return 1;
452 }
453
454 static int VentoyProcSecureBoot(int SecureBoot)
455 {
456 int rc = 0;
457 int size;
458 char *filebuf = NULL;
459 void *file = NULL;
460
461 vlog("VentoyProcSecureBoot %d ...\n", SecureBoot);
462
463 if (SecureBoot)
464 {
465 vlog("Secure boot is enabled ...\n");
466 return 0;
467 }
468
469 fl_init();
470
471 if (0 == fl_attach_media(VentoyFatMemRead, VentoyFatMemWrite))
472 {
473 file = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
474 vlog("Open ventoy efi file %p \n", file);
475 if (file)
476 {
477 fl_fseek(file, 0, SEEK_END);
478 size = (int)fl_ftell(file);
479 fl_fseek(file, 0, SEEK_SET);
480
481 vlog("ventoy efi file size %d ...\n", size);
482
483 filebuf = (char *)malloc(size);
484 if (filebuf)
485 {
486 fl_fread(filebuf, 1, size, file);
487 }
488
489 fl_fclose(file);
490
491 vlog("Now delete all efi files ...\n");
492 fl_remove("/EFI/BOOT/BOOTX64.EFI");
493 fl_remove("/EFI/BOOT/grubx64.efi");
494 fl_remove("/EFI/BOOT/grubx64_real.efi");
495 fl_remove("/EFI/BOOT/MokManager.efi");
496 fl_remove("/ENROLL_THIS_KEY_IN_MOKMANAGER.cer");
497
498 file = fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");
499 vlog("Open bootx64 efi file %p \n", file);
500 if (file)
501 {
502 if (filebuf)
503 {
504 fl_fwrite(filebuf, 1, size, file);
505 }
506
507 fl_fflush(file);
508 fl_fclose(file);
509 }
510
511 if (filebuf)
512 {
513 free(filebuf);
514 }
515 }
516
517 file = fl_fopen("/EFI/BOOT/grubia32_real.efi", "rb");
518 vlog("Open ventoy efi file %p\n", file);
519 if (file)
520 {
521 fl_fseek(file, 0, SEEK_END);
522 size = (int)fl_ftell(file);
523 fl_fseek(file, 0, SEEK_SET);
524
525 vlog("ventoy efi file size %d ...\n", size);
526
527 filebuf = (char *)malloc(size);
528 if (filebuf)
529 {
530 fl_fread(filebuf, 1, size, file);
531 }
532
533 fl_fclose(file);
534
535 vlog("Now delete all efi files ...\n");
536 fl_remove("/EFI/BOOT/BOOTIA32.EFI");
537 fl_remove("/EFI/BOOT/grubia32.efi");
538 fl_remove("/EFI/BOOT/grubia32_real.efi");
539 fl_remove("/EFI/BOOT/mmia32.efi");
540
541 file = fl_fopen("/EFI/BOOT/BOOTIA32.EFI", "wb");
542 vlog("Open bootia32 efi file %p\n", file);
543 if (file)
544 {
545 if (filebuf)
546 {
547 fl_fwrite(filebuf, 1, size, file);
548 }
549
550 fl_fflush(file);
551 fl_fclose(file);
552 }
553
554 if (filebuf)
555 {
556 free(filebuf);
557 }
558 }
559
560 }
561 else
562 {
563 rc = 1;
564 }
565
566 fl_shutdown();
567
568 return rc;
569 }
570
571 static int ventoy_check_efi_part_data(int fd, uint64_t offset)
572 {
573 int i;
574 ssize_t len;
575 char *buf;
576
577 buf = malloc(SIZE_1MB);
578 if (!buf)
579 {
580 return 0;
581 }
582
583 lseek(fd, offset, SEEK_SET);
584 for (i = 0; i < 32; i++)
585 {
586 len = read(fd, buf, SIZE_1MB);
587 if (len != SIZE_1MB || memcmp(buf, g_efi_part_raw_img + i * SIZE_1MB, SIZE_1MB))
588 {
589 vlog("part2 data check failed i=%d len:%llu\n", i, (_ull)len);
590 return 1;
591 }
592
593 g_current_progress = PT_CHECK_PART2 + (i / 4);
594 }
595
596 return 0;
597 }
598
599 static int ventoy_write_efipart(int fd, uint64_t offset, uint32_t secureboot)
600 {
601 int i;
602 ssize_t len;
603
604 vlog("Formatting part2 EFI offset:%llu ...\n", (_ull)offset);
605 lseek(fd, offset, SEEK_SET);
606
607 VentoyProcSecureBoot((int)secureboot);
608
609 g_current_progress = PT_WRITE_VENTOY_START;
610 for (i = 0; i < 32; i++)
611 {
612 len = write(fd, g_efi_part_raw_img + i * SIZE_1MB, SIZE_1MB);
613 vlog("write disk writelen:%lld datalen:%d [ %s ]\n",
614 (_ll)len, SIZE_1MB, (len == SIZE_1MB) ? "success" : "failed");
615
616 if (len != SIZE_1MB)
617 {
618 vlog("failed to format part2 EFI\n");
619 return 1;
620 }
621
622 g_current_progress = PT_WRITE_VENTOY_START + i / 4;
623 }
624
625 return 0;
626 }
627
628 static int VentoyFillBackupGptHead(VTOY_GPT_INFO *pInfo, VTOY_GPT_HDR *pHead)
629 {
630 uint64_t LBA;
631 uint64_t BackupLBA;
632
633 memcpy(pHead, &pInfo->Head, sizeof(VTOY_GPT_HDR));
634
635 LBA = pHead->EfiStartLBA;
636 BackupLBA = pHead->EfiBackupLBA;
637
638 pHead->EfiStartLBA = BackupLBA;
639 pHead->EfiBackupLBA = LBA;
640 pHead->PartTblStartLBA = BackupLBA + 1 - 33;
641
642 pHead->Crc = 0;
643 pHead->Crc = ventoy_crc32(pHead, pHead->Length);
644
645 return 0;
646 }
647
648 static int ventoy_write_gpt_part_table(int fd, uint64_t disksize, VTOY_GPT_INFO *gpt)
649 {
650 ssize_t len;
651 off_t offset;
652 VTOY_GPT_HDR BackupHead;
653
654 VentoyFillBackupGptHead(gpt, &BackupHead);
655
656 offset = lseek(fd, disksize - 512, SEEK_SET);
657 len = write(fd, &BackupHead, sizeof(VTOY_GPT_HDR));
658 vlog("write backup gpt part table off:%llu len:%llu\n", (_ull)offset, (_ull)len);
659 if (offset != disksize - 512 || len != sizeof(VTOY_GPT_HDR))
660 {
661 return 1;
662 }
663
664 offset = lseek(fd, disksize - 512 * 33, SEEK_SET);
665 len = write(fd, gpt->PartTbl, sizeof(gpt->PartTbl));
666 vlog("write main gpt part table off:%llu len:%llu\n", (_ull)offset, (_ull)len);
667 if (offset != disksize - 512 * 33 || len != sizeof(gpt->PartTbl))
668 {
669 return 1;
670 }
671
672 offset = lseek(fd, 0, SEEK_SET);
673 len = write(fd, gpt, sizeof(VTOY_GPT_INFO));
674 vlog("write gpt part head off:%llu len:%llu\n", (_ull)offset, (_ull)len);
675 if (offset != 0 || len != sizeof(VTOY_GPT_INFO))
676 {
677 return 1;
678 }
679
680 return 0;
681 }
682
683 static void * ventoy_update_thread(void *data)
684 {
685 int fd;
686 ssize_t len;
687 off_t offset;
688 MBR_HEAD MBR;
689 ventoy_disk *disk = NULL;
690 ventoy_thread_data *thread = (ventoy_thread_data *)data;
691
692 vdebug("ventoy_update_thread run ...\n");
693
694 fd = thread->diskfd;
695 disk = thread->disk;
696
697 g_current_progress = PT_PRAPARE_FOR_CLEAN;
698 vdebug("check disk %s\n", disk->disk_name);
699 if (ventoy_is_disk_mounted(disk->disk_path))
700 {
701 vlog("disk is mounted, now try to unmount it ...\n");
702 ventoy_try_umount_disk(disk->disk_path);
703 }
704
705 if (ventoy_is_disk_mounted(disk->disk_path))
706 {
707 vlog("%s is mounted and can't umount!\n", disk->disk_path);
708 goto err;
709 }
710 else
711 {
712 vlog("disk is not mounted now, we can do continue ...\n");
713 }
714
715 g_current_progress = PT_LOAD_CORE_IMG;
716 ventoy_unxz_stg1_img();
717
718 g_current_progress = PT_LOAD_DISK_IMG;
719 ventoy_unxz_efipart_img();
720
721 g_current_progress = PT_FORMAT_PART2;
722
723 vlog("Formatting part2 EFI ...\n");
724 if (0 != ventoy_write_efipart(fd, disk->vtoydata.part2_start_sector * 512, thread->secure_boot))
725 {
726 vlog("Failed to format part2 efi ...\n");
727 goto err;
728 }
729
730 g_current_progress = PT_WRITE_STG1_IMG;
731
732 vlog("Writing legacy grub ...\n");
733 if (0 != ventoy_write_legacy_grub(fd, disk->vtoydata.partition_style))
734 {
735 vlog("ventoy_write_legacy_grub failed ...\n");
736 goto err;
737 }
738
739 offset = lseek(fd, 512 * 2040, SEEK_SET);
740 len = write(fd, disk->vtoydata.rsvdata, sizeof(disk->vtoydata.rsvdata));
741 vlog("Writing reserve data offset:%llu len:%llu ...\n", (_ull)offset, (_ull)len);
742
743 memcpy(&MBR, &(disk->vtoydata.gptinfo.MBR), 512);
744 if (disk->vtoydata.partition_style == 0 && MBR.PartTbl[0].Active == 0)
745 {
746 MBR.PartTbl[0].Active = 0x80;
747 MBR.PartTbl[1].Active = 0;
748 MBR.PartTbl[2].Active = 0;
749 MBR.PartTbl[3].Active = 0;
750
751 offset = lseek(fd, 0, SEEK_SET);
752 len = write(fd, &MBR, 512);
753 vlog("set MBR partition 1 active flag enabled offset:%llu len:%llu\n", (_ull)offset, (_ull)len);
754 }
755
756 g_current_progress = PT_SYNC_DATA1;
757
758 vlog("fsync data1...\n");
759 fsync(fd);
760 vtoy_safe_close_fd(fd);
761
762 g_current_progress = PT_SYNC_DATA2;
763
764 vlog("====================================\n");
765 vlog("====== ventoy update success ======\n");
766 vlog("====================================\n");
767 goto end;
768
769 err:
770 g_cur_process_result = 1;
771 vtoy_safe_close_fd(fd);
772
773 end:
774 g_current_progress = PT_FINISH;
775
776 check_free(thread);
777
778 return NULL;
779 }
780
781 static void * ventoy_install_thread(void *data)
782 {
783 int fd;
784 ssize_t len;
785 off_t offset;
786 MBR_HEAD MBR;
787 ventoy_disk *disk = NULL;
788 VTOY_GPT_INFO *gpt = NULL;
789 ventoy_thread_data *thread = (ventoy_thread_data *)data;
790 uint64_t Part1StartSector = 0;
791 uint64_t Part1SectorCount = 0;
792 uint64_t Part2StartSector = 0;
793
794 vdebug("ventoy_install_thread run ...\n");
795
796 fd = thread->diskfd;
797 disk = thread->disk;
798
799 g_current_progress = PT_PRAPARE_FOR_CLEAN;
800 vdebug("check disk %s\n", disk->disk_name);
801 if (ventoy_is_disk_mounted(disk->disk_path))
802 {
803 vlog("disk is mounted, now try to unmount it ...\n");
804 ventoy_try_umount_disk(disk->disk_path);
805 }
806
807 if (ventoy_is_disk_mounted(disk->disk_path))
808 {
809 vlog("%s is mounted and can't umount!\n", disk->disk_path);
810 goto err;
811 }
812 else
813 {
814 vlog("disk is not mounted now, we can do continue ...\n");
815 }
816
817 g_current_progress = PT_DEL_ALL_PART;
818 ventoy_clean_disk(fd, disk->size_in_byte);
819
820 g_current_progress = PT_LOAD_CORE_IMG;
821 ventoy_unxz_stg1_img();
822
823 g_current_progress = PT_LOAD_DISK_IMG;
824 ventoy_unxz_efipart_img();
825
826 if (thread->partstyle)
827 {
828 vdebug("Fill GPT part table\n");
829 gpt = zalloc(sizeof(VTOY_GPT_INFO));
830 ventoy_fill_gpt(disk->size_in_byte, thread->reserveBytes, thread->align4kb, gpt);
831 Part1StartSector = gpt->PartTbl[0].StartLBA;
832 Part1SectorCount = gpt->PartTbl[0].LastLBA - Part1StartSector + 1;
833 Part2StartSector = gpt->PartTbl[1].StartLBA;
834 }
835 else
836 {
837 vdebug("Fill MBR part table\n");
838 ventoy_fill_mbr(disk->size_in_byte, thread->reserveBytes, thread->align4kb, &MBR);
839 Part1StartSector = MBR.PartTbl[0].StartSectorId;
840 Part1SectorCount = MBR.PartTbl[0].SectorCount;
841 Part2StartSector = MBR.PartTbl[1].StartSectorId;
842 }
843
844 vlog("Part1StartSector:%llu Part1SectorCount:%llu Part2StartSector:%llu\n",
845 (_ull)Part1StartSector, (_ull)Part1SectorCount, (_ull)Part2StartSector);
846
847 if (thread->partstyle != disk->partstyle)
848 {
849 vlog("Wait for format part1 (partstyle changed) ...\n");
850 sleep(1);
851 }
852
853 g_current_progress = PT_FORMAT_PART1;
854 vlog("Formatting part1 exFAT %s ...\n", disk->disk_path);
855 if (0 != mkexfat_main(disk->disk_path, fd, Part1SectorCount))
856 {
857 vlog("Failed to format exfat ...\n");
858 goto err;
859 }
860
861 g_current_progress = PT_FORMAT_PART2;
862 vlog("Formatting part2 EFI ...\n");
863 if (0 != ventoy_write_efipart(fd, Part2StartSector * 512, thread->secure_boot))
864 {
865 vlog("Failed to format part2 efi ...\n");
866 goto err;
867 }
868
869 g_current_progress = PT_WRITE_STG1_IMG;
870 vlog("Writing legacy grub ...\n");
871 if (0 != ventoy_write_legacy_grub(fd, thread->partstyle))
872 {
873 vlog("ventoy_write_legacy_grub failed ...\n");
874 goto err;
875 }
876
877 g_current_progress = PT_SYNC_DATA1;
878 vlog("fsync data1...\n");
879 fsync(fd);
880 vtoy_safe_close_fd(fd);
881
882 /* reopen for check part2 data */
883 vlog("Checking part2 efi data %s ...\n", disk->disk_path);
884 g_current_progress = PT_CHECK_PART2;
885 fd = open(disk->disk_path, O_RDONLY | O_BINARY);
886 if (fd < 0)
887 {
888 vlog("failed to open %s for check fd:%d err:%d\n", disk->disk_path, fd, errno);
889 goto err;
890 }
891
892 if (0 == ventoy_check_efi_part_data(fd, Part2StartSector * 512))
893 {
894 vlog("efi part data check success\n");
895 }
896 else
897 {
898 vlog("efi part data check failed\n");
899 goto err;
900 }
901
902 vtoy_safe_close_fd(fd);
903
904 /* reopen for write part table */
905 g_current_progress = PT_WRITE_PART_TABLE;
906 vlog("Writting Partition Table style:%d...\n", thread->partstyle);
907
908 fd = open(disk->disk_path, O_RDWR | O_BINARY);
909 if (fd < 0)
910 {
911 vlog("failed to open %s for part table fd:%d err:%d\n", disk->disk_path, fd, errno);
912 goto err;
913 }
914
915 if (thread->partstyle)
916 {
917 ventoy_write_gpt_part_table(fd, disk->size_in_byte, gpt);
918 }
919 else
920 {
921 offset = lseek(fd, 0, SEEK_SET);
922 len = write(fd, &MBR, 512);
923 vlog("Writting MBR Partition Table %llu %llu\n", (_ull)offset, (_ull)len);
924 if (offset != 0 || len != 512)
925 {
926 goto err;
927 }
928 }
929
930 g_current_progress = PT_SYNC_DATA2;
931 vlog("fsync data2...\n");
932 fsync(fd);
933 vtoy_safe_close_fd(fd);
934
935
936 vlog("====================================\n");
937 vlog("====== ventoy install success ======\n");
938 vlog("====================================\n");
939 goto end;
940
941 err:
942 g_cur_process_result = 1;
943 vtoy_safe_close_fd(fd);
944
945 end:
946 g_current_progress = PT_FINISH;
947
948 check_free(gpt);
949 check_free(thread);
950
951 return NULL;
952 }
953
954 static int ventoy_api_clean(struct mg_connection *conn, VTOY_JSON *json)
955 {
956 int i = 0;
957 int fd = 0;
958 ventoy_disk *disk = NULL;
959 const char *diskname = NULL;
960 char path[128];
961
962 if (g_current_progress != PT_FINISH)
963 {
964 ventoy_json_result(conn, VTOY_JSON_BUSY_RET);
965 return 0;
966 }
967
968 diskname = vtoy_json_get_string_ex(json, "disk");
969 if (diskname == NULL)
970 {
971 ventoy_json_result(conn, VTOY_JSON_INVALID_RET);
972 return 0;
973 }
974
975 for (i = 0; i < g_disk_num; i++)
976 {
977 if (strcmp(g_disk_list[i].disk_name, diskname) == 0)
978 {
979 disk = g_disk_list + i;
980 break;
981 }
982 }
983
984 if (disk == NULL)
985 {
986 vlog("disk %s not found\n", diskname);
987 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
988 return 0;
989 }
990
991 scnprintf(path, "/sys/block/%s", diskname);
992 if (access(path, F_OK) < 0)
993 {
994 vlog("File %s not exist anymore\n", path);
995 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
996 return 0;
997 }
998
999 vlog("==================================\n");
1000 vlog("===== ventoy clean %s =====\n", disk->disk_path);
1001 vlog("==================================\n");
1002
1003 if (ventoy_is_disk_mounted(disk->disk_path))
1004 {
1005 vlog("disk is mounted, now try to unmount it ...\n");
1006 ventoy_try_umount_disk(disk->disk_path);
1007 }
1008
1009 if (ventoy_is_disk_mounted(disk->disk_path))
1010 {
1011 vlog("%s is mounted and can't umount!\n", disk->disk_path);
1012 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1013 return 0;
1014 }
1015 else
1016 {
1017 vlog("disk is not mounted now, we can do the clean ...\n");
1018 }
1019
1020 fd = open(disk->disk_path, O_RDWR | O_BINARY);
1021 if (fd < 0)
1022 {
1023 vlog("failed to open %s fd:%d err:%d\n", disk->disk_path, fd, errno);
1024 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1025 return 0;
1026 }
1027
1028 vdebug("start clean %s ...\n", disk->disk_model);
1029 ventoy_clean_disk(fd, disk->size_in_byte);
1030
1031 vtoy_safe_close_fd(fd);
1032
1033 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1034 return 0;
1035 }
1036
1037 static int ventoy_api_install(struct mg_connection *conn, VTOY_JSON *json)
1038 {
1039 int i = 0;
1040 int ret = 0;
1041 int fd = 0;
1042 uint32_t align4kb = 0;
1043 uint32_t style = 0;
1044 uint32_t secure_boot = 0;
1045 uint64_t reserveBytes = 0;
1046 ventoy_disk *disk = NULL;
1047 const char *diskname = NULL;
1048 const char *reserve_space = NULL;
1049 ventoy_thread_data *thread = NULL;
1050 char path[128];
1051
1052 if (g_current_progress != PT_FINISH)
1053 {
1054 ventoy_json_result(conn, VTOY_JSON_BUSY_RET);
1055 return 0;
1056 }
1057
1058 diskname = vtoy_json_get_string_ex(json, "disk");
1059 reserve_space = vtoy_json_get_string_ex(json, "reserve_space");
1060 ret += vtoy_json_get_uint(json, "partstyle", &style);
1061 ret += vtoy_json_get_uint(json, "secure_boot", &secure_boot);
1062 ret += vtoy_json_get_uint(json, "align_4kb", &align4kb);
1063
1064 if (diskname == NULL || reserve_space == NULL || ret != JSON_SUCCESS)
1065 {
1066 ventoy_json_result(conn, VTOY_JSON_INVALID_RET);
1067 return 0;
1068 }
1069
1070 reserveBytes = (uint64_t)strtoull(reserve_space, NULL, 10);
1071
1072 for (i = 0; i < g_disk_num; i++)
1073 {
1074 if (strcmp(g_disk_list[i].disk_name, diskname) == 0)
1075 {
1076 disk = g_disk_list + i;
1077 break;
1078 }
1079 }
1080
1081 if (disk == NULL)
1082 {
1083 vlog("disk %s not found\n", diskname);
1084 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
1085 return 0;
1086 }
1087
1088 scnprintf(path, "/sys/block/%s", diskname);
1089 if (access(path, F_OK) < 0)
1090 {
1091 vlog("File %s not exist anymore\n", path);
1092 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
1093 return 0;
1094 }
1095
1096 if (disk->size_in_byte > 2199023255552ULL && style == 0)
1097 {
1098 vlog("disk %s is more than 2TB and GPT is needed\n", path);
1099 ventoy_json_result(conn, VTOY_JSON_MBR_2TB_RET);
1100 return 0;
1101 }
1102
1103 if ((reserveBytes + VTOYEFI_PART_BYTES * 2) > disk->size_in_byte)
1104 {
1105 vlog("reserve space %llu is too big for disk %s %llu\n", (_ull)reserveBytes, path, (_ull)disk->size_in_byte);
1106 ventoy_json_result(conn, VTOY_JSON_INVALID_RSV_RET);
1107 return 0;
1108 }
1109
1110 vlog("==================================================================================\n");
1111 vlog("===== ventoy install %s style:%s secureboot:%u align4K:%u reserve:%llu =========\n",
1112 disk->disk_path, (style ? "GPT" : "MBR"), secure_boot, align4kb, (_ull)reserveBytes);
1113 vlog("==================================================================================\n");
1114
1115 if (ventoy_is_disk_mounted(disk->disk_path))
1116 {
1117 vlog("disk is mounted, now try to unmount it ...\n");
1118 ventoy_try_umount_disk(disk->disk_path);
1119 }
1120
1121 if (ventoy_is_disk_mounted(disk->disk_path))
1122 {
1123 vlog("%s is mounted and can't umount!\n", disk->disk_path);
1124 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1125 return 0;
1126 }
1127 else
1128 {
1129 vlog("disk is not mounted now, we can do the install ...\n");
1130 }
1131
1132 fd = open(disk->disk_path, O_RDWR | O_BINARY);
1133 if (fd < 0)
1134 {
1135 vlog("failed to open %s fd:%d err:%d\n", disk->disk_path, fd, errno);
1136 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1137 return 0;
1138 }
1139
1140 vdebug("start install thread %s ...\n", disk->disk_model);
1141 thread = zalloc(sizeof(ventoy_thread_data));
1142 if (!thread)
1143 {
1144 vtoy_safe_close_fd(fd);
1145 vlog("failed to alloc thread data err:%d\n", errno);
1146 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1147 return 0;
1148 }
1149
1150 g_current_progress = PT_START;
1151 g_cur_process_result = 0;
1152 scnprintf(g_cur_process_type, "%s", "install");
1153 scnprintf(g_cur_process_diskname, "%s", disk->disk_name);
1154
1155 thread->disk = disk;
1156 thread->diskfd = fd;
1157 thread->align4kb = align4kb;
1158 thread->partstyle = style;
1159 thread->secure_boot = secure_boot;
1160 thread->reserveBytes = reserveBytes;
1161
1162 mg_start_thread(ventoy_install_thread, thread);
1163
1164 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1165 return 0;
1166 }
1167
1168 static int ventoy_api_update(struct mg_connection *conn, VTOY_JSON *json)
1169 {
1170 int i = 0;
1171 int ret = 0;
1172 int fd = 0;
1173 uint32_t secure_boot = 0;
1174 ventoy_disk *disk = NULL;
1175 const char *diskname = NULL;
1176 ventoy_thread_data *thread = NULL;
1177 char path[128];
1178
1179 if (g_current_progress != PT_FINISH)
1180 {
1181 ventoy_json_result(conn, VTOY_JSON_BUSY_RET);
1182 return 0;
1183 }
1184
1185 diskname = vtoy_json_get_string_ex(json, "disk");
1186 ret += vtoy_json_get_uint(json, "secure_boot", &secure_boot);
1187 if (diskname == NULL || ret != JSON_SUCCESS)
1188 {
1189 ventoy_json_result(conn, VTOY_JSON_INVALID_RET);
1190 return 0;
1191 }
1192
1193 for (i = 0; i < g_disk_num; i++)
1194 {
1195 if (strcmp(g_disk_list[i].disk_name, diskname) == 0)
1196 {
1197 disk = g_disk_list + i;
1198 break;
1199 }
1200 }
1201
1202 if (disk == NULL)
1203 {
1204 vlog("disk %s not found\n", diskname);
1205 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
1206 return 0;
1207 }
1208
1209 if (disk->vtoydata.ventoy_valid == 0)
1210 {
1211 vlog("disk %s is not ventoy disk\n", diskname);
1212 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1213 return 0;
1214 }
1215
1216 scnprintf(path, "/sys/block/%s", diskname);
1217 if (access(path, F_OK) < 0)
1218 {
1219 vlog("File %s not exist anymore\n", path);
1220 ventoy_json_result(conn, VTOY_JSON_NOTFOUND_RET);
1221 return 0;
1222 }
1223
1224 vlog("==========================================================\n");
1225 vlog("===== ventoy update %s new_secureboot:%u =========\n", disk->disk_path, secure_boot);
1226 vlog("==========================================================\n");
1227
1228 vlog("%s version:%s partstyle:%u oldsecureboot:%u reserve:%llu\n",
1229 disk->disk_path, disk->vtoydata.ventoy_ver,
1230 disk->vtoydata.partition_style,
1231 disk->vtoydata.secure_boot_flag,
1232 (_ull)(disk->vtoydata.preserved_space)
1233 );
1234
1235 if (ventoy_is_disk_mounted(disk->disk_path))
1236 {
1237 vlog("disk is mounted, now try to unmount it ...\n");
1238 ventoy_try_umount_disk(disk->disk_path);
1239 }
1240
1241 if (ventoy_is_disk_mounted(disk->disk_path))
1242 {
1243 vlog("%s is mounted and can't umount!\n", disk->disk_path);
1244 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1245 return 0;
1246 }
1247 else
1248 {
1249 vlog("disk is not mounted now, we can do the update ...\n");
1250 }
1251
1252 fd = open(disk->disk_path, O_RDWR | O_BINARY);
1253 if (fd < 0)
1254 {
1255 vlog("failed to open %s fd:%d err:%d\n", disk->disk_path, fd, errno);
1256 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1257 return 0;
1258 }
1259
1260 vdebug("start update thread %s ...\n", disk->disk_model);
1261 thread = zalloc(sizeof(ventoy_thread_data));
1262 if (!thread)
1263 {
1264 vtoy_safe_close_fd(fd);
1265 vlog("failed to alloc thread data err:%d\n", errno);
1266 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1267 return 0;
1268 }
1269
1270 g_current_progress = PT_START;
1271 g_cur_process_result = 0;
1272 scnprintf(g_cur_process_type, "%s", "update");
1273 scnprintf(g_cur_process_diskname, "%s", disk->disk_name);
1274
1275 thread->disk = disk;
1276 thread->diskfd = fd;
1277 thread->secure_boot = secure_boot;
1278
1279 mg_start_thread(ventoy_update_thread, thread);
1280
1281 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1282 return 0;
1283 }
1284
1285
1286 static int ventoy_api_refresh_device(struct mg_connection *conn, VTOY_JSON *json)
1287 {
1288 (void)json;
1289
1290 if (g_current_progress == PT_FINISH)
1291 {
1292 g_disk_num = 0;
1293 ventoy_disk_enumerate_all();
1294 }
1295
1296 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1297 return 0;
1298 }
1299
1300 static int ventoy_api_get_dev_list(struct mg_connection *conn, VTOY_JSON *json)
1301 {
1302 int i = 0;
1303 int rc = 0;
1304 int pos = 0;
1305 int buflen = 0;
1306 uint32_t alldev = 0;
1307 char *buf = NULL;
1308 ventoy_disk *cur = NULL;
1309
1310 rc = vtoy_json_get_uint(json, "alldev", &alldev);
1311 if (JSON_SUCCESS != rc)
1312 {
1313 alldev = 0;
1314 }
1315
1316 buflen = g_disk_num * 1024;
1317 buf = (char *)malloc(buflen + 1024);
1318 if (!buf)
1319 {
1320 ventoy_json_result(conn, VTOY_JSON_FAILED_RET);
1321 return 0;
1322 }
1323
1324 VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
1325 VTOY_JSON_FMT_OBJ_BEGIN();
1326 VTOY_JSON_FMT_KEY("list");
1327 VTOY_JSON_FMT_ARY_BEGIN();
1328
1329 for (i = 0; i < g_disk_num; i++)
1330 {
1331 cur = g_disk_list + i;
1332
1333 if (alldev == 0 && cur->type != VTOY_DEVICE_USB)
1334 {
1335 continue;
1336 }
1337
1338 VTOY_JSON_FMT_OBJ_BEGIN();
1339 VTOY_JSON_FMT_STRN("name", cur->disk_name);
1340 VTOY_JSON_FMT_STRN("model", cur->disk_model);
1341 VTOY_JSON_FMT_STRN("size", cur->human_readable_size);
1342 VTOY_JSON_FMT_UINT("vtoy_valid", cur->vtoydata.ventoy_valid);
1343 VTOY_JSON_FMT_STRN("vtoy_ver", cur->vtoydata.ventoy_ver);
1344 VTOY_JSON_FMT_UINT("vtoy_secure_boot", cur->vtoydata.secure_boot_flag);
1345 VTOY_JSON_FMT_UINT("vtoy_partstyle", cur->vtoydata.partition_style);
1346 VTOY_JSON_FMT_OBJ_ENDEX();
1347 }
1348
1349 VTOY_JSON_FMT_ARY_END();
1350 VTOY_JSON_FMT_OBJ_END();
1351 VTOY_JSON_FMT_END(pos);
1352
1353 ventoy_json_buffer(conn, buf, pos);
1354 return 0;
1355 }
1356
1357 static JSON_CB g_ventoy_json_cb[] =
1358 {
1359 { "sysinfo", ventoy_api_sysinfo },
1360 { "sel_language", ventoy_api_set_language },
1361 { "sel_partstyle", ventoy_api_set_partstyle },
1362 { "refresh_device", ventoy_api_refresh_device },
1363 { "get_dev_list", ventoy_api_get_dev_list },
1364 { "install", ventoy_api_install },
1365 { "update", ventoy_api_update },
1366 { "clean", ventoy_api_clean },
1367 { "get_percent", ventoy_api_get_percent },
1368 };
1369
1370 static int ventoy_json_handler(struct mg_connection *conn, VTOY_JSON *json)
1371 {
1372 int i;
1373 const char *token = NULL;
1374 const char *method = NULL;
1375
1376 method = vtoy_json_get_string_ex(json, "method");
1377 if (!method)
1378 {
1379 ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
1380 return 0;
1381 }
1382
1383 if (strcmp(method, "sysinfo"))
1384 {
1385 token = vtoy_json_get_string_ex(json, "token");
1386 if (token == NULL || strcmp(token, g_cur_server_token))
1387 {
1388 ventoy_json_result(conn, VTOY_JSON_TOKEN_ERR_RET);
1389 return 0;
1390 }
1391 }
1392
1393 for (i = 0; i < (int)(sizeof(g_ventoy_json_cb) / sizeof(g_ventoy_json_cb[0])); i++)
1394 {
1395 if (strcmp(method, g_ventoy_json_cb[i].method) == 0)
1396 {
1397 g_ventoy_json_cb[i].callback(conn, json);
1398 break;
1399 }
1400 }
1401
1402 return 0;
1403 }
1404
1405 int ventoy_func_handler(const char *jsonstr, char *jsonbuf, int buflen)
1406 {
1407 int i;
1408 const char *method = NULL;
1409 VTOY_JSON *json = NULL;
1410
1411 g_pub_out_buf = jsonbuf;
1412 g_pub_out_max = buflen;
1413
1414 json = vtoy_json_create();
1415 if (JSON_SUCCESS == vtoy_json_parse(json, jsonstr))
1416 {
1417 pthread_mutex_lock(&g_api_mutex);
1418
1419 method = vtoy_json_get_string_ex(json->pstChild, "method");
1420 for (i = 0; i < (int)(sizeof(g_ventoy_json_cb) / sizeof(g_ventoy_json_cb[0])); i++)
1421 {
1422 if (method && strcmp(method, g_ventoy_json_cb[i].method) == 0)
1423 {
1424 g_ventoy_json_cb[i].callback(NULL, json->pstChild);
1425 break;
1426 }
1427 }
1428
1429 pthread_mutex_unlock(&g_api_mutex);
1430 }
1431 else
1432 {
1433 ventoy_json_result(NULL, VTOY_JSON_INVALID_RET);
1434 }
1435
1436 vtoy_json_destroy(json);
1437 return 0;
1438 }
1439
1440 static int ventoy_request_handler(struct mg_connection *conn)
1441 {
1442 int post_data_len;
1443 int post_buf_len;
1444 VTOY_JSON *json = NULL;
1445 char *post_data_buf = NULL;
1446 const struct mg_request_info *ri = NULL;
1447 char stack_buf[512];
1448
1449 ri = mg_get_request_info(conn);
1450
1451 if (strcmp(ri->uri, "/vtoy/json") == 0)
1452 {
1453 if (ri->content_length > 500)
1454 {
1455 post_data_buf = malloc(ri->content_length + 4);
1456 post_buf_len = ri->content_length + 1;
1457 }
1458 else
1459 {
1460 post_data_buf = stack_buf;
1461 post_buf_len = sizeof(stack_buf);
1462 }
1463
1464 post_data_len = mg_read(conn, post_data_buf, post_buf_len);
1465 post_data_buf[post_data_len] = 0;
1466
1467 json = vtoy_json_create();
1468 if (JSON_SUCCESS == vtoy_json_parse(json, post_data_buf))
1469 {
1470 pthread_mutex_lock(&g_api_mutex);
1471 ventoy_json_handler(conn, json->pstChild);
1472 pthread_mutex_unlock(&g_api_mutex);
1473 }
1474 else
1475 {
1476 ventoy_json_result(conn, VTOY_JSON_INVALID_RET);
1477 }
1478
1479 vtoy_json_destroy(json);
1480
1481 if (post_data_buf != stack_buf)
1482 {
1483 free(post_data_buf);
1484 }
1485 return 1;
1486 }
1487 else
1488 {
1489 return 0;
1490 }
1491 }
1492
1493 int ventoy_http_start(const char *ip, const char *port)
1494 {
1495 uint8_t uuid[16];
1496 char addr[128];
1497 struct mg_callbacks callbacks;
1498 const char *options[] =
1499 {
1500 "listening_ports", "24680",
1501 "document_root", "WebUI",
1502 "error_log_file", VTOY_LOG_FILE,
1503 "request_timeout_ms", "10000",
1504 NULL
1505 };
1506
1507 /* unique token */
1508 ventoy_gen_preudo_uuid(uuid);
1509 scnprintf(g_cur_server_token, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1510 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
1511 uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
1512
1513 /* option */
1514 scnprintf(addr, "%s:%s", ip, port);
1515 options[1] = addr;
1516
1517 memset(&callbacks, 0, sizeof(callbacks));
1518 callbacks.begin_request = ventoy_request_handler;
1519 g_ventoy_http_ctx = mg_start(&callbacks, NULL, options);
1520
1521 return g_ventoy_http_ctx ? 0 : 1;
1522 }
1523
1524 int ventoy_http_stop(void)
1525 {
1526 if (g_ventoy_http_ctx)
1527 {
1528 mg_stop(g_ventoy_http_ctx);
1529 }
1530 return 0;
1531 }
1532
1533 int ventoy_http_init(void)
1534 {
1535 pthread_mutex_init(&g_api_mutex, NULL);
1536
1537 ventoy_http_load_cfg();
1538
1539 ventoy_load_mbr_template();
1540
1541 return 0;
1542 }
1543
1544 void ventoy_http_exit(void)
1545 {
1546 pthread_mutex_destroy(&g_api_mutex);
1547
1548 check_free(g_efi_part_raw_img);
1549 g_efi_part_raw_img = NULL;
1550 }
1551
1552
1553 const char * ventoy_code_get_cur_language(void)
1554 {
1555 return g_cur_language;
1556 }
1557
1558 int ventoy_code_get_cur_part_style(void)
1559 {
1560 return g_cur_part_style;
1561 }
1562
1563 void ventoy_code_set_cur_part_style(int style)
1564 {
1565 pthread_mutex_lock(&g_api_mutex);
1566
1567 g_cur_part_style = style;
1568 ventoy_http_save_cfg();
1569
1570 pthread_mutex_unlock(&g_api_mutex);
1571 }
1572
1573 int ventoy_code_get_cur_show_all(void)
1574 {
1575 return g_cur_show_all;
1576 }
1577
1578 void ventoy_code_set_cur_show_all(int show_all)
1579 {
1580 pthread_mutex_lock(&g_api_mutex);
1581
1582 g_cur_show_all = show_all;
1583 ventoy_http_save_cfg();
1584
1585 pthread_mutex_unlock(&g_api_mutex);
1586 }
1587
1588 void ventoy_code_set_cur_language(const char *lang)
1589 {
1590 pthread_mutex_lock(&g_api_mutex);
1591
1592 scnprintf(g_cur_language, "%s", lang);
1593 ventoy_http_save_cfg();
1594
1595 pthread_mutex_unlock(&g_api_mutex);
1596 }
1597
1598 void ventoy_code_refresh_device(void)
1599 {
1600 if (g_current_progress == PT_FINISH)
1601 {
1602 g_disk_num = 0;
1603 ventoy_disk_enumerate_all();
1604 }
1605 }
1606
1607 int ventoy_code_is_busy(void)
1608 {
1609 return (g_current_progress == PT_FINISH) ? 0 : 1;
1610 }
1611
1612 int ventoy_code_get_percent(void)
1613 {
1614 return g_current_progress * 100 / PT_FINISH;
1615 }
1616
1617 int ventoy_code_get_result(void)
1618 {
1619 return g_cur_process_result;
1620 }
1621
1622 void ventoy_code_save_cfg(void)
1623 {
1624 ventoy_http_save_cfg();
1625 }