]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - LinuxGUI/Ventoy2Disk/Core/ventoy_disk.c
1. change icon from * to a lock icon
[Ventoy.git] / LinuxGUI / Ventoy2Disk / Core / ventoy_disk.c
1 /******************************************************************************
2 * ventoy_disk.c ---- ventoy disk
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 <errno.h>
24 #include <ctype.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #include <sys/ioctl.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <linux/fs.h>
32 #include <dirent.h>
33 #include <time.h>
34 #include <ventoy_define.h>
35 #include <ventoy_disk.h>
36 #include <ventoy_util.h>
37 #include <fat_filelib.h>
38
39 int g_disk_num = 0;
40 static int g_fatlib_media_fd = 0;
41 static uint64_t g_fatlib_media_offset = 0;
42 ventoy_disk *g_disk_list = NULL;
43
44 static const char *g_ventoy_dev_type_str[VTOY_DEVICE_END] =
45 {
46 "unknown", "scsi", "USB", "ide", "dac960",
47 "cpqarray", "file", "ataraid", "i2o",
48 "ubd", "dasd", "viodasd", "sx8", "dm",
49 "xvd", "sd/mmc", "virtblk", "aoe",
50 "md", "loopback", "nvme", "brd", "pmem"
51 };
52
53 static const char * ventoy_get_dev_type_name(ventoy_dev_type type)
54 {
55 return (type < VTOY_DEVICE_END) ? g_ventoy_dev_type_str[type] : "unknown";
56 }
57
58 static int ventoy_check_blk_major(int major, const char *type)
59 {
60 int flag = 0;
61 int valid = 0;
62 int devnum = 0;
63 int len = 0;
64 char line[64];
65 char *pos = NULL;
66 FILE *fp = NULL;
67
68 fp = fopen("/proc/devices", "r");
69 if (!fp)
70 {
71 return 0;
72 }
73
74 len = (int)strlen(type);
75 while (fgets(line, sizeof(line), fp))
76 {
77 if (flag)
78 {
79 pos = strchr(line, ' ');
80 if (pos)
81 {
82 devnum = (int)strtol(line, NULL, 10);
83 if (devnum == major)
84 {
85 if (strncmp(pos + 1, type, len) == 0)
86 {
87 valid = 1;
88 }
89 break;
90 }
91 }
92 }
93 else if (strncmp(line, "Block devices:", 14) == 0)
94 {
95 flag = 1;
96 }
97 }
98
99 fclose(fp);
100 return valid;
101 }
102
103 static int ventoy_get_disk_devnum(const char *name, int *major, int* minor)
104 {
105 int rc;
106 char *pos;
107 char devnum[16] = {0};
108
109 rc = ventoy_get_sys_file_line(devnum, sizeof(devnum), "/sys/block/%s/dev", name);
110 if (rc)
111 {
112 return 1;
113 }
114
115 pos = strstr(devnum, ":");
116 if (!pos)
117 {
118 return 1;
119 }
120
121 *major = (int)strtol(devnum, NULL, 10);
122 *minor = (int)strtol(pos + 1, NULL, 10);
123
124 return 0;
125 }
126
127 static ventoy_dev_type ventoy_get_dev_type(const char *name, int major, int minor)
128 {
129 int rc;
130 char syspath[128];
131 char dstpath[256];
132
133 memset(syspath, 0, sizeof(syspath));
134 memset(dstpath, 0, sizeof(dstpath));
135
136 scnprintf(syspath, "/sys/block/%s", name);
137 rc = readlink(syspath, dstpath, sizeof(dstpath) - 1);
138 if (rc > 0 && strstr(dstpath, "/usb"))
139 {
140 return VTOY_DEVICE_USB;
141 }
142
143 if (SCSI_BLK_MAJOR(major) && (minor % 0x10 == 0))
144 {
145 return VTOY_DEVICE_SCSI;
146 }
147 else if (IDE_BLK_MAJOR(major) && (minor % 0x40 == 0))
148 {
149 return VTOY_DEVICE_IDE;
150 }
151 else if (major == DAC960_MAJOR && (minor % 0x8 == 0))
152 {
153 return VTOY_DEVICE_DAC960;
154 }
155 else if (major == ATARAID_MAJOR && (minor % 0x10 == 0))
156 {
157 return VTOY_DEVICE_ATARAID;
158 }
159 else if (major == AOE_MAJOR && (minor % 0x10 == 0))
160 {
161 return VTOY_DEVICE_AOE;
162 }
163 else if (major == DASD_MAJOR && (minor % 0x4 == 0))
164 {
165 return VTOY_DEVICE_DASD;
166 }
167 else if (major == VIODASD_MAJOR && (minor % 0x8 == 0))
168 {
169 return VTOY_DEVICE_VIODASD;
170 }
171 else if (SX8_BLK_MAJOR(major) && (minor % 0x20 == 0))
172 {
173 return VTOY_DEVICE_SX8;
174 }
175 else if (I2O_BLK_MAJOR(major) && (minor % 0x10 == 0))
176 {
177 return VTOY_DEVICE_I2O;
178 }
179 else if (CPQARRAY_BLK_MAJOR(major) && (minor % 0x10 == 0))
180 {
181 return VTOY_DEVICE_CPQARRAY;
182 }
183 else if (UBD_MAJOR == major && (minor % 0x10 == 0))
184 {
185 return VTOY_DEVICE_UBD;
186 }
187 else if (XVD_MAJOR == major && (minor % 0x10 == 0))
188 {
189 return VTOY_DEVICE_XVD;
190 }
191 else if (SDMMC_MAJOR == major && (minor % 0x8 == 0))
192 {
193 return VTOY_DEVICE_SDMMC;
194 }
195 else if (ventoy_check_blk_major(major, "virtblk"))
196 {
197 return VTOY_DEVICE_VIRTBLK;
198 }
199 else if (major == LOOP_MAJOR)
200 {
201 return VTOY_DEVICE_LOOP;
202 }
203 else if (major == MD_MAJOR)
204 {
205 return VTOY_DEVICE_MD;
206 }
207 else if (major == RAM_MAJOR)
208 {
209 return VTOY_DEVICE_RAM;
210 }
211 else if (strstr(name, "nvme") && ventoy_check_blk_major(major, "blkext"))
212 {
213 return VTOY_DEVICE_NVME;
214 }
215 else if (strstr(name, "pmem") && ventoy_check_blk_major(major, "blkext"))
216 {
217 return VTOY_DEVICE_PMEM;
218 }
219
220 return VTOY_DEVICE_END;
221 }
222
223 static int ventoy_is_possible_blkdev(const char *name)
224 {
225 if (name[0] == '.')
226 {
227 return 0;
228 }
229
230 /* /dev/ramX */
231 if (name[0] == 'r' && name[1] == 'a' && name[2] == 'm')
232 {
233 return 0;
234 }
235
236 /* /dev/loopX */
237 if (name[0] == 'l' && name[1] == 'o' && name[2] == 'o' && name[3] == 'p')
238 {
239 return 0;
240 }
241
242 /* /dev/dm-X */
243 if (name[0] == 'd' && name[1] == 'm' && name[2] == '-' && isdigit(name[3]))
244 {
245 return 0;
246 }
247
248 /* /dev/srX */
249 if (name[0] == 's' && name[1] == 'r' && isdigit(name[2]))
250 {
251 return 0;
252 }
253
254 return 1;
255 }
256
257 uint64_t ventoy_get_disk_size_in_byte(const char *disk)
258 {
259 int fd;
260 int rc;
261 unsigned long long size = 0;
262 char diskpath[256] = {0};
263 char sizebuf[64] = {0};
264
265 // Try 1: get size from sysfs
266 snprintf(diskpath, sizeof(diskpath) - 1, "/sys/block/%s/size", disk);
267 if (access(diskpath, F_OK) >= 0)
268 {
269 vdebug("get disk size from sysfs for %s\n", disk);
270
271 fd = open(diskpath, O_RDONLY | O_BINARY);
272 if (fd >= 0)
273 {
274 read(fd, sizebuf, sizeof(sizebuf));
275 size = strtoull(sizebuf, NULL, 10);
276 close(fd);
277 return (uint64_t)(size * 512);
278 }
279 }
280 else
281 {
282 vdebug("%s not exist \n", diskpath);
283 }
284
285 // Try 2: get size from ioctl
286 snprintf(diskpath, sizeof(diskpath) - 1, "/dev/%s", disk);
287 fd = open(diskpath, O_RDONLY);
288 if (fd >= 0)
289 {
290 vdebug("get disk size from ioctl for %s\n", disk);
291 rc = ioctl(fd, BLKGETSIZE64, &size);
292 if (rc == -1)
293 {
294 size = 0;
295 vdebug("failed to ioctl %d\n", rc);
296 }
297 close(fd);
298 }
299 else
300 {
301 vdebug("failed to open %s %d\n", diskpath, errno);
302 }
303
304 vdebug("disk %s size %llu bytes\n", disk, size);
305 return size;
306 }
307
308 int ventoy_get_disk_vendor(const char *name, char *vendorbuf, int bufsize)
309 {
310 return ventoy_get_sys_file_line(vendorbuf, bufsize, "/sys/block/%s/device/vendor", name);
311 }
312
313 int ventoy_get_disk_model(const char *name, char *modelbuf, int bufsize)
314 {
315 return ventoy_get_sys_file_line(modelbuf, bufsize, "/sys/block/%s/device/model", name);
316 }
317
318 static int fatlib_media_sector_read(uint32 sector, uint8 *buffer, uint32 sector_count)
319 {
320 lseek(g_fatlib_media_fd, (sector + g_fatlib_media_offset) * 512ULL, SEEK_SET);
321 read(g_fatlib_media_fd, buffer, sector_count * 512);
322
323 return 1;
324 }
325
326 static int fatlib_is_secure_boot_enable(void)
327 {
328 void *flfile = NULL;
329
330 flfile = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
331 if (flfile)
332 {
333 fl_fclose(flfile);
334 return 1;
335 }
336 else
337 {
338 vlog("/EFI/BOOT/grubx64_real.efi not exist\n");
339 }
340
341 return 0;
342 }
343
344 static int fatlib_get_ventoy_version(char *verbuf, int bufsize)
345 {
346 int rc = 1;
347 int size = 0;
348 char *buf = NULL;
349 char *pos = NULL;
350 char *end = NULL;
351 void *flfile = NULL;
352
353 flfile = fl_fopen("/grub/grub.cfg", "rb");
354 if (flfile)
355 {
356 fl_fseek(flfile, 0, SEEK_END);
357 size = (int)fl_ftell(flfile);
358
359 fl_fseek(flfile, 0, SEEK_SET);
360
361 buf = malloc(size + 1);
362 if (buf)
363 {
364 fl_fread(buf, 1, size, flfile);
365 buf[size] = 0;
366
367 pos = strstr(buf, "VENTOY_VERSION=");
368 if (pos)
369 {
370 pos += strlen("VENTOY_VERSION=");
371 if (*pos == '"')
372 {
373 pos++;
374 }
375
376 end = pos;
377 while (*end != 0 && *end != '"' && *end != '\r' && *end != '\n')
378 {
379 end++;
380 }
381
382 *end = 0;
383
384 snprintf(verbuf, bufsize - 1, "%s", pos);
385 rc = 0;
386 }
387 free(buf);
388 }
389
390 fl_fclose(flfile);
391 }
392 else
393 {
394 vdebug("No grub.cfg found\n");
395 }
396
397 return rc;
398 }
399
400 int ventoy_get_vtoy_data(ventoy_disk *info, int *ppartstyle)
401 {
402 int i;
403 int fd;
404 int len;
405 int rc = 1;
406 int ret = 1;
407 int part_style;
408 uint64_t part1_start_sector;
409 uint64_t part1_sector_count;
410 uint64_t part2_start_sector;
411 uint64_t part2_sector_count;
412 uint64_t preserved_space;
413 char name[64] = {0};
414 disk_ventoy_data *vtoy = NULL;
415 VTOY_GPT_INFO *gpt = NULL;
416
417 vtoy = &(info->vtoydata);
418 gpt = &(vtoy->gptinfo);
419 memset(vtoy, 0, sizeof(disk_ventoy_data));
420
421 vdebug("ventoy_get_vtoy_data %s\n", info->disk_path);
422
423 if (info->size_in_byte < (2 * VTOYEFI_PART_BYTES))
424 {
425 vdebug("disk %s is too small %llu\n", info->disk_path, (_ull)info->size_in_byte);
426 return 1;
427 }
428
429 fd = open(info->disk_path, O_RDONLY | O_BINARY);
430 if (fd < 0)
431 {
432 vdebug("failed to open %s %d\n", info->disk_path, errno);
433 return 1;
434 }
435
436 len = (int)read(fd, &(vtoy->gptinfo), sizeof(VTOY_GPT_INFO));
437 if (len != sizeof(VTOY_GPT_INFO))
438 {
439 vdebug("failed to read %s %d\n", info->disk_path, errno);
440 goto end;
441 }
442
443 if (gpt->MBR.Byte55 != 0x55 || gpt->MBR.ByteAA != 0xAA)
444 {
445 vdebug("Invalid mbr magic 0x%x 0x%x\n", gpt->MBR.Byte55, gpt->MBR.ByteAA);
446 goto end;
447 }
448
449 if (gpt->MBR.PartTbl[0].FsFlag == 0xEE && strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
450 {
451 part_style = GPT_PART_STYLE;
452 if (ppartstyle)
453 {
454 *ppartstyle = part_style;
455 }
456
457 if (gpt->PartTbl[0].StartLBA == 0 || gpt->PartTbl[1].StartLBA == 0)
458 {
459 vdebug("NO ventoy efi part layout <%llu %llu>\n",
460 (_ull)gpt->PartTbl[0].StartLBA,
461 (_ull)gpt->PartTbl[1].StartLBA);
462 goto end;
463 }
464
465 for (i = 0; i < 36; i++)
466 {
467 name[i] = (char)(gpt->PartTbl[1].Name[i]);
468 }
469 if (strcmp(name, "VTOYEFI"))
470 {
471 vdebug("Invalid efi part2 name <%s>\n", name);
472 goto end;
473 }
474
475 part1_start_sector = gpt->PartTbl[0].StartLBA;
476 part1_sector_count = gpt->PartTbl[0].LastLBA - part1_start_sector + 1;
477 part2_start_sector = gpt->PartTbl[1].StartLBA;
478 part2_sector_count = gpt->PartTbl[1].LastLBA - part2_start_sector + 1;
479
480 preserved_space = info->size_in_byte - (part2_start_sector + part2_sector_count + 33) * 512;
481 }
482 else
483 {
484 part_style = MBR_PART_STYLE;
485 if (ppartstyle)
486 {
487 *ppartstyle = part_style;
488 }
489
490 part1_start_sector = gpt->MBR.PartTbl[0].StartSectorId;
491 part1_sector_count = gpt->MBR.PartTbl[0].SectorCount;
492 part2_start_sector = gpt->MBR.PartTbl[1].StartSectorId;
493 part2_sector_count = gpt->MBR.PartTbl[1].SectorCount;
494
495 preserved_space = info->size_in_byte - (part2_start_sector + part2_sector_count) * 512;
496 }
497
498 if (part1_start_sector != VTOYIMG_PART_START_SECTOR ||
499 part2_sector_count != VTOYEFI_PART_SECTORS ||
500 (part1_start_sector + part1_sector_count) != part2_start_sector)
501 {
502 vdebug("Not valid ventoy partition layout [%llu %llu] [%llu %llu]\n",
503 part1_start_sector, part1_sector_count, part2_start_sector, part2_sector_count);
504 goto end;
505 }
506
507 vdebug("now check secure boot ...\n");
508
509 g_fatlib_media_fd = fd;
510 g_fatlib_media_offset = part2_start_sector;
511 fl_init();
512
513 if (0 == fl_attach_media(fatlib_media_sector_read, NULL))
514 {
515 ret = fatlib_get_ventoy_version(vtoy->ventoy_ver, sizeof(vtoy->ventoy_ver));
516 if (ret == 0 && vtoy->ventoy_ver[0])
517 {
518 vtoy->secure_boot_flag = fatlib_is_secure_boot_enable();
519 vtoy->ventoy_valid = 1;
520 }
521 else
522 {
523 vdebug("fatlib_get_ventoy_version failed %d\n", ret);
524 }
525 }
526 else
527 {
528 vdebug("fl_attach_media failed\n");
529 }
530
531 fl_shutdown();
532 g_fatlib_media_fd = -1;
533 g_fatlib_media_offset = 0;
534
535 if (0 == vtoy->ventoy_valid)
536 {
537 goto end;
538 }
539
540 lseek(fd, 2040 * 512, SEEK_SET);
541 read(fd, vtoy->rsvdata, sizeof(vtoy->rsvdata));
542
543 vtoy->preserved_space = preserved_space;
544 vtoy->partition_style = part_style;
545 vtoy->part2_start_sector = part2_start_sector;
546
547 rc = 0;
548 end:
549 close(fd);
550 return rc;
551 }
552
553 int ventoy_get_disk_info(const char *name, ventoy_disk *info)
554 {
555 char vendor[64] = {0};
556 char model[128] = {0};
557
558 vdebug("get disk info %s\n", name);
559
560 strlcpy(info->disk_name, name);
561 scnprintf(info->disk_path, "/dev/%s", name);
562
563 if (strstr(name, "nvme") || strstr(name, "mmc") || strstr(name, "nbd"))
564 {
565 scnprintf(info->part1_name, "%sp1", name);
566 scnprintf(info->part1_path, "/dev/%sp1", name);
567 scnprintf(info->part2_name, "%sp2", name);
568 scnprintf(info->part2_path, "/dev/%sp2", name);
569 }
570 else
571 {
572 scnprintf(info->part1_name, "%s1", name);
573 scnprintf(info->part1_path, "/dev/%s1", name);
574 scnprintf(info->part2_name, "%s2", name);
575 scnprintf(info->part2_path, "/dev/%s2", name);
576 }
577
578 info->size_in_byte = ventoy_get_disk_size_in_byte(name);
579
580 ventoy_get_disk_devnum(name, &info->major, &info->minor);
581 info->type = ventoy_get_dev_type(name, info->major, info->minor);
582 ventoy_get_disk_vendor(name, vendor, sizeof(vendor));
583 ventoy_get_disk_model(name, model, sizeof(model));
584
585 scnprintf(info->human_readable_size, "%llu GB", (_ull)ventoy_get_human_readable_gb(info->size_in_byte));
586 scnprintf(info->disk_model, "%s %s (%s)", vendor, model, ventoy_get_dev_type_name(info->type));
587
588 ventoy_get_vtoy_data(info, &(info->partstyle));
589
590 vdebug("disk:<%s %d:%d> model:<%s> size:%llu (%s)\n",
591 info->disk_path, info->major, info->minor, info->disk_model, info->size_in_byte, info->human_readable_size);
592
593 if (info->vtoydata.ventoy_valid)
594 {
595 vdebug("%s Ventoy:<%s> %s secureboot:%d preserve:%llu\n", info->disk_path, info->vtoydata.ventoy_ver,
596 info->vtoydata.partition_style == MBR_PART_STYLE ? "MBR" : "GPT",
597 info->vtoydata.secure_boot_flag, (_ull)(info->vtoydata.preserved_space));
598 }
599 else
600 {
601 vdebug("%s NO Ventoy detected\n", info->disk_path);
602 }
603
604 return 0;
605 }
606
607 static int ventoy_disk_compare(const ventoy_disk *disk1, const ventoy_disk *disk2)
608 {
609 if (disk1->type == VTOY_DEVICE_USB && disk2->type == VTOY_DEVICE_USB)
610 {
611 return strcmp(disk1->disk_name, disk2->disk_name);
612 }
613 else if (disk1->type == VTOY_DEVICE_USB)
614 {
615 return -1;
616 }
617 else if (disk2->type == VTOY_DEVICE_USB)
618 {
619 return 1;
620 }
621 else
622 {
623 return strcmp(disk1->disk_name, disk2->disk_name);
624 }
625 }
626
627 static int ventoy_disk_sort(void)
628 {
629 int i, j;
630 ventoy_disk *tmp;
631
632 tmp = malloc(sizeof(ventoy_disk));
633 if (!tmp)
634 {
635 return 1;
636 }
637
638 for (i = 0; i < g_disk_num; i++)
639 for (j = i + 1; j < g_disk_num; j++)
640 {
641 if (ventoy_disk_compare(g_disk_list + i, g_disk_list + j) > 0)
642 {
643 memcpy(tmp, g_disk_list + i, sizeof(ventoy_disk));
644 memcpy(g_disk_list + i, g_disk_list + j, sizeof(ventoy_disk));
645 memcpy(g_disk_list + j, tmp, sizeof(ventoy_disk));
646 }
647 }
648
649 free(tmp);
650 return 0;
651 }
652
653 int ventoy_disk_enumerate_all(void)
654 {
655 int rc = 0;
656 DIR* dir = NULL;
657 struct dirent* p = NULL;
658
659 vdebug("ventoy_disk_enumerate_all\n");
660
661 dir = opendir("/sys/block");
662 if (!dir)
663 {
664 vlog("Failed to open /sys/block %d\n", errno);
665 return 1;
666 }
667
668 while (((p = readdir(dir)) != NULL) && (g_disk_num < MAX_DISK_NUM))
669 {
670 if (ventoy_is_possible_blkdev(p->d_name))
671 {
672 memset(g_disk_list + g_disk_num, 0, sizeof(ventoy_disk));
673 if (0 == ventoy_get_disk_info(p->d_name, g_disk_list + g_disk_num))
674 {
675 g_disk_num++;
676 }
677 }
678 }
679 closedir(dir);
680
681 ventoy_disk_sort();
682
683 return rc;
684 }
685
686 void ventoy_disk_dump(ventoy_disk *cur)
687 {
688 if (cur->vtoydata.ventoy_valid)
689 {
690 vdebug("%s [%s] %s\tVentoy: %s %s secureboot:%d preserve:%llu\n",
691 cur->disk_path, cur->human_readable_size, cur->disk_model,
692 cur->vtoydata.ventoy_ver, cur->vtoydata.partition_style == MBR_PART_STYLE ? "MBR" : "GPT",
693 cur->vtoydata.secure_boot_flag, (_ull)(cur->vtoydata.preserved_space));
694 }
695 else
696 {
697 vdebug("%s [%s] %s\tVentoy: NA\n", cur->disk_path, cur->human_readable_size, cur->disk_model);
698 }
699 }
700
701 void ventoy_disk_dump_all(void)
702 {
703 int i;
704
705 vdebug("============= DISK DUMP ============\n");
706 for (i = 0; i < g_disk_num; i++)
707 {
708 ventoy_disk_dump(g_disk_list + i);
709 }
710 }
711
712 int ventoy_disk_install(ventoy_disk *disk, void *efipartimg)
713 {
714 return 0;
715 }
716
717
718 int ventoy_disk_init(void)
719 {
720 g_disk_list = malloc(sizeof(ventoy_disk) * MAX_DISK_NUM);
721
722 ventoy_disk_enumerate_all();
723 ventoy_disk_dump_all();
724
725 return 0;
726 }
727
728 void ventoy_disk_exit(void)
729 {
730 check_free(g_disk_list);
731 g_disk_list = NULL;
732 g_disk_num = 0;
733 }
734
735