1 /******************************************************************************
2 * ventoy_disk.c ---- ventoy disk
3 * Copyright (c) 2021, longpanda <admin@ventoy.net>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 3 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
27 #include <sys/types.h>
28 #include <sys/ioctl.h>
30 #include <sys/types.h>
34 #include <ventoy_define.h>
35 #include <ventoy_disk.h>
36 #include <ventoy_util.h>
37 #include <fat_filelib.h>
39 static int g_fatlib_media_fd
= 0;
40 static uint64_t g_fatlib_media_offset
= 0;
42 static const char *g_ventoy_dev_type_str
[VTOY_DEVICE_END
] =
44 "unknown", "scsi", "USB", "ide", "dac960",
45 "cpqarray", "file", "ataraid", "i2o",
46 "ubd", "dasd", "viodasd", "sx8", "dm",
47 "xvd", "sd/mmc", "virtblk", "aoe",
48 "md", "loopback", "nvme", "brd", "pmem"
51 static const char * ventoy_get_dev_type_name(ventoy_dev_type type
)
53 return (type
< VTOY_DEVICE_END
) ? g_ventoy_dev_type_str
[type
] : "unknown";
56 static int ventoy_check_blk_major(int major
, const char *type
)
66 fp
= fopen("/proc/devices", "r");
72 len
= (int)strlen(type
);
73 while (fgets(line
, sizeof(line
), fp
))
77 pos
= strchr(line
, ' ');
80 devnum
= (int)strtol(line
, NULL
, 10);
83 if (strncmp(pos
+ 1, type
, len
) == 0)
91 else if (strncmp(line
, "Block devices:", 14) == 0)
101 static int ventoy_get_disk_devnum(const char *name
, int *major
, int* minor
)
105 char devnum
[16] = {0};
107 rc
= ventoy_get_sys_file_line(devnum
, sizeof(devnum
), "/sys/block/%s/dev", name
);
113 pos
= strstr(devnum
, ":");
119 *major
= (int)strtol(devnum
, NULL
, 10);
120 *minor
= (int)strtol(pos
+ 1, NULL
, 10);
125 static ventoy_dev_type
ventoy_get_dev_type(const char *name
, int major
, int minor
)
131 memset(syspath
, 0, sizeof(syspath
));
132 memset(dstpath
, 0, sizeof(dstpath
));
134 scnprintf(syspath
, sizeof(syspath
), "/sys/block/%s", name
);
135 rc
= readlink(syspath
, dstpath
, sizeof(dstpath
) - 1);
136 if (rc
> 0 && strstr(dstpath
, "/usb"))
138 return VTOY_DEVICE_USB
;
141 if (SCSI_BLK_MAJOR(major
) && (minor
% 0x10 == 0))
143 return VTOY_DEVICE_SCSI
;
145 else if (IDE_BLK_MAJOR(major
) && (minor
% 0x40 == 0))
147 return VTOY_DEVICE_IDE
;
149 else if (major
== DAC960_MAJOR
&& (minor
% 0x8 == 0))
151 return VTOY_DEVICE_DAC960
;
153 else if (major
== ATARAID_MAJOR
&& (minor
% 0x10 == 0))
155 return VTOY_DEVICE_ATARAID
;
157 else if (major
== AOE_MAJOR
&& (minor
% 0x10 == 0))
159 return VTOY_DEVICE_AOE
;
161 else if (major
== DASD_MAJOR
&& (minor
% 0x4 == 0))
163 return VTOY_DEVICE_DASD
;
165 else if (major
== VIODASD_MAJOR
&& (minor
% 0x8 == 0))
167 return VTOY_DEVICE_VIODASD
;
169 else if (SX8_BLK_MAJOR(major
) && (minor
% 0x20 == 0))
171 return VTOY_DEVICE_SX8
;
173 else if (I2O_BLK_MAJOR(major
) && (minor
% 0x10 == 0))
175 return VTOY_DEVICE_I2O
;
177 else if (CPQARRAY_BLK_MAJOR(major
) && (minor
% 0x10 == 0))
179 return VTOY_DEVICE_CPQARRAY
;
181 else if (UBD_MAJOR
== major
&& (minor
% 0x10 == 0))
183 return VTOY_DEVICE_UBD
;
185 else if (XVD_MAJOR
== major
&& (minor
% 0x10 == 0))
187 return VTOY_DEVICE_XVD
;
189 else if (SDMMC_MAJOR
== major
&& (minor
% 0x8 == 0))
191 return VTOY_DEVICE_SDMMC
;
193 else if (ventoy_check_blk_major(major
, "virtblk"))
195 return VTOY_DEVICE_VIRTBLK
;
197 else if (major
== LOOP_MAJOR
)
199 return VTOY_DEVICE_LOOP
;
201 else if (major
== MD_MAJOR
)
203 return VTOY_DEVICE_MD
;
205 else if (major
== RAM_MAJOR
)
207 return VTOY_DEVICE_RAM
;
209 else if (strstr(name
, "nvme") && ventoy_check_blk_major(major
, "blkext"))
211 return VTOY_DEVICE_NVME
;
213 else if (strstr(name
, "pmem") && ventoy_check_blk_major(major
, "blkext"))
215 return VTOY_DEVICE_PMEM
;
218 return VTOY_DEVICE_END
;
221 static int ventoy_is_possible_blkdev(const char *name
)
229 if (name
[0] == 'r' && name
[1] == 'a' && name
[2] == 'm')
235 if (name
[0] == 'z' && name
[1] == 'r' && name
[2] == 'a' && name
[3] == 'm')
241 if (name
[0] == 'l' && name
[1] == 'o' && name
[2] == 'o' && name
[3] == 'p')
247 if (name
[0] == 'd' && name
[1] == 'm' && name
[2] == '-' && isdigit(name
[3]))
253 if (name
[0] == 's' && name
[1] == 'r' && isdigit(name
[2]))
261 uint64_t ventoy_get_disk_size_in_byte(const char *disk
)
265 unsigned long long size
= 0;
266 char diskpath
[256] = {0};
267 char sizebuf
[64] = {0};
269 // Try 1: get size from sysfs
270 scnprintf(diskpath
, sizeof(diskpath
) - 1, "/sys/block/%s/size", disk
);
271 if (access(diskpath
, F_OK
) >= 0)
273 vdebug("get disk size from sysfs for %s\n", disk
);
275 fd
= open(diskpath
, O_RDONLY
| O_BINARY
);
278 read(fd
, sizebuf
, sizeof(sizebuf
));
279 size
= strtoull(sizebuf
, NULL
, 10);
281 return (uint64_t)(size
* 512);
286 vdebug("%s not exist \n", diskpath
);
289 // Try 2: get size from ioctl
290 scnprintf(diskpath
, sizeof(diskpath
) - 1, "/dev/%s", disk
);
291 fd
= open(diskpath
, O_RDONLY
);
294 vdebug("get disk size from ioctl for %s\n", disk
);
295 rc
= ioctl(fd
, BLKGETSIZE64
, &size
);
299 vdebug("failed to ioctl %d\n", rc
);
305 vdebug("failed to open %s %d\n", diskpath
, errno
);
308 vdebug("disk %s size %llu bytes\n", disk
, size
);
312 int ventoy_get_disk_vendor(const char *name
, char *vendorbuf
, int bufsize
)
314 return ventoy_get_sys_file_line(vendorbuf
, bufsize
, "/sys/block/%s/device/vendor", name
);
317 int ventoy_get_disk_model(const char *name
, char *modelbuf
, int bufsize
)
319 return ventoy_get_sys_file_line(modelbuf
, bufsize
, "/sys/block/%s/device/model", name
);
322 static int fatlib_media_sector_read(uint32 sector
, uint8
*buffer
, uint32 sector_count
)
324 lseek(g_fatlib_media_fd
, (sector
+ g_fatlib_media_offset
) * 512ULL, SEEK_SET
);
325 read(g_fatlib_media_fd
, buffer
, sector_count
* 512);
330 static int fatlib_is_secure_boot_enable(void)
334 flfile
= fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
337 vlog("/EFI/BOOT/grubx64_real.efi find, secure boot in enabled\n");
343 vlog("/EFI/BOOT/grubx64_real.efi not exist\n");
349 static int fatlib_get_ventoy_version(char *verbuf
, int bufsize
)
358 flfile
= fl_fopen("/grub/grub.cfg", "rb");
361 fl_fseek(flfile
, 0, SEEK_END
);
362 size
= (int)fl_ftell(flfile
);
364 fl_fseek(flfile
, 0, SEEK_SET
);
366 buf
= malloc(size
+ 1);
369 fl_fread(buf
, 1, size
, flfile
);
372 pos
= strstr(buf
, "VENTOY_VERSION=");
375 pos
+= strlen("VENTOY_VERSION=");
382 while (*end
!= 0 && *end
!= '"' && *end
!= '\r' && *end
!= '\n')
389 scnprintf(verbuf
, bufsize
- 1, "%s", pos
);
399 vdebug("No grub.cfg found\n");
405 /* <BEGIN>: Deleted by longpanda, 20211028 PN:XX LABEL:XX */
407 int ventoy_get_vtoy_data(ventoy_disk
*info
, int *ppartstyle
)
415 uint64_t part1_start_sector
;
416 uint64_t part1_sector_count
;
417 uint64_t part2_start_sector
;
418 uint64_t part2_sector_count
;
419 uint64_t preserved_space
;
421 disk_ventoy_data
*vtoy
= NULL
;
422 VTOY_GPT_INFO
*gpt
= NULL
;
424 vtoy
= &(info
->vtoydata
);
425 gpt
= &(vtoy
->gptinfo
);
426 memset(vtoy
, 0, sizeof(disk_ventoy_data
));
428 vdebug("ventoy_get_vtoy_data %s\n", info
->disk_path
);
430 if (info
->size_in_byte
< (2 * VTOYEFI_PART_BYTES
))
432 vdebug("disk %s is too small %llu\n", info
->disk_path
, (_ull
)info
->size_in_byte
);
436 fd
= open(info
->disk_path
, O_RDONLY
| O_BINARY
);
439 vdebug("failed to open %s %d\n", info
->disk_path
, errno
);
443 len
= (int)read(fd
, &(vtoy
->gptinfo
), sizeof(VTOY_GPT_INFO
));
444 if (len
!= sizeof(VTOY_GPT_INFO
))
446 vdebug("failed to read %s %d\n", info
->disk_path
, errno
);
450 if (gpt
->MBR
.Byte55
!= 0x55 || gpt
->MBR
.ByteAA
!= 0xAA)
452 vdebug("Invalid mbr magic 0x%x 0x%x\n", gpt
->MBR
.Byte55
, gpt
->MBR
.ByteAA
);
456 if (gpt
->MBR
.PartTbl
[0].FsFlag
== 0xEE && strncmp(gpt
->Head
.Signature
, "EFI PART", 8) == 0)
458 part_style
= GPT_PART_STYLE
;
461 *ppartstyle
= part_style
;
464 if (gpt
->PartTbl
[0].StartLBA
== 0 || gpt
->PartTbl
[1].StartLBA
== 0)
466 vdebug("NO ventoy efi part layout <%llu %llu>\n",
467 (_ull
)gpt
->PartTbl
[0].StartLBA
,
468 (_ull
)gpt
->PartTbl
[1].StartLBA
);
472 for (i
= 0; i
< 36; i
++)
474 name
[i
] = (char)(gpt
->PartTbl
[1].Name
[i
]);
476 if (strcmp(name
, "VTOYEFI"))
478 vdebug("Invalid efi part2 name <%s>\n", name
);
482 part1_start_sector
= gpt
->PartTbl
[0].StartLBA
;
483 part1_sector_count
= gpt
->PartTbl
[0].LastLBA
- part1_start_sector
+ 1;
484 part2_start_sector
= gpt
->PartTbl
[1].StartLBA
;
485 part2_sector_count
= gpt
->PartTbl
[1].LastLBA
- part2_start_sector
+ 1;
487 preserved_space
= info
->size_in_byte
- (part2_start_sector
+ part2_sector_count
+ 33) * 512;
491 part_style
= MBR_PART_STYLE
;
494 *ppartstyle
= part_style
;
497 part1_start_sector
= gpt
->MBR
.PartTbl
[0].StartSectorId
;
498 part1_sector_count
= gpt
->MBR
.PartTbl
[0].SectorCount
;
499 part2_start_sector
= gpt
->MBR
.PartTbl
[1].StartSectorId
;
500 part2_sector_count
= gpt
->MBR
.PartTbl
[1].SectorCount
;
502 preserved_space
= info
->size_in_byte
- (part2_start_sector
+ part2_sector_count
) * 512;
505 if (part1_start_sector
!= VTOYIMG_PART_START_SECTOR
||
506 part2_sector_count
!= VTOYEFI_PART_SECTORS
||
507 (part1_start_sector
+ part1_sector_count
) != part2_start_sector
)
509 vdebug("Not valid ventoy partition layout [%llu %llu] [%llu %llu]\n",
510 part1_start_sector
, part1_sector_count
, part2_start_sector
, part2_sector_count
);
514 vdebug("ventoy partition layout check OK: [%llu %llu] [%llu %llu]\n",
515 part1_start_sector
, part1_sector_count
, part2_start_sector
, part2_sector_count
);
517 vtoy
->ventoy_valid
= 1;
519 vdebug("now check secure boot for %s ...\n", info
->disk_path
);
521 g_fatlib_media_fd
= fd
;
522 g_fatlib_media_offset
= part2_start_sector
;
525 if (0 == fl_attach_media(fatlib_media_sector_read
, NULL
))
527 ret
= fatlib_get_ventoy_version(vtoy
->ventoy_ver
, sizeof(vtoy
->ventoy_ver
));
528 if (ret
== 0 && vtoy
->ventoy_ver
[0])
530 vtoy
->secure_boot_flag
= fatlib_is_secure_boot_enable();
534 vdebug("fatlib_get_ventoy_version failed %d\n", ret
);
539 vdebug("fl_attach_media failed\n");
543 g_fatlib_media_fd
= -1;
544 g_fatlib_media_offset
= 0;
546 if (vtoy
->ventoy_ver
[0] == 0)
548 vtoy
->ventoy_ver
[0] = '?';
551 if (0 == vtoy
->ventoy_valid
)
556 lseek(fd
, 2040 * 512, SEEK_SET
);
557 read(fd
, vtoy
->rsvdata
, sizeof(vtoy
->rsvdata
));
559 vtoy
->preserved_space
= preserved_space
;
560 vtoy
->partition_style
= part_style
;
561 vtoy
->part2_start_sector
= part2_start_sector
;
565 vtoy_safe_close_fd(fd
);
569 /* <END> : Deleted by longpanda, 20211028 PN:XX LABEL:XX */
572 int ventoy_get_disk_info(char **argv
)
577 char *disk
= argv
[4];
579 if (strncmp(argv
[4], "/dev/", 4) == 0)
583 ventoy_get_disk_vendor(disk
, vendor
, sizeof(vendor
));
584 ventoy_get_disk_model(disk
, model
, sizeof(model
));
586 scnprintf(g_sysinfo
.cur_model
, sizeof(g_sysinfo
.cur_model
), "%s %s [%s]", vendor
, model
, argv
[4]);
587 strlcpy(g_sysinfo
.cur_ventoy_ver
, argv
[5]);
588 strlcpy(g_sysinfo
.cur_fsname
, argv
[6]);
589 g_sysinfo
.cur_part_style
= (int)strtol(argv
[7], NULL
, 10);
590 g_sysinfo
.cur_secureboot
= (int)strtol(argv
[8], NULL
, 10);
592 size
= ventoy_get_disk_size_in_byte(disk
);
593 scnprintf(g_sysinfo
.cur_capacity
, sizeof(g_sysinfo
.cur_capacity
), "%dGB", (int)ventoy_get_human_readable_gb(size
));
598 int ventoy_disk_init(void)
603 void ventoy_disk_exit(void)