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