]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Plugson/src/Core/ventoy_disk_linux.c
Fix the egrep warning. (#2083)
[Ventoy.git] / Plugson / src / Core / ventoy_disk_linux.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 static int g_fatlib_media_fd = 0;
40 static uint64_t g_fatlib_media_offset = 0;
41
42 static const char *g_ventoy_dev_type_str[VTOY_DEVICE_END] =
43 {
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"
49 };
50
51 static const char * ventoy_get_dev_type_name(ventoy_dev_type type)
52 {
53 return (type < VTOY_DEVICE_END) ? g_ventoy_dev_type_str[type] : "unknown";
54 }
55
56 static int ventoy_check_blk_major(int major, const char *type)
57 {
58 int flag = 0;
59 int valid = 0;
60 int devnum = 0;
61 int len = 0;
62 char line[64];
63 char *pos = NULL;
64 FILE *fp = NULL;
65
66 fp = fopen("/proc/devices", "r");
67 if (!fp)
68 {
69 return 0;
70 }
71
72 len = (int)strlen(type);
73 while (fgets(line, sizeof(line), fp))
74 {
75 if (flag)
76 {
77 pos = strchr(line, ' ');
78 if (pos)
79 {
80 devnum = (int)strtol(line, NULL, 10);
81 if (devnum == major)
82 {
83 if (strncmp(pos + 1, type, len) == 0)
84 {
85 valid = 1;
86 }
87 break;
88 }
89 }
90 }
91 else if (strncmp(line, "Block devices:", 14) == 0)
92 {
93 flag = 1;
94 }
95 }
96
97 fclose(fp);
98 return valid;
99 }
100
101 static int ventoy_get_disk_devnum(const char *name, int *major, int* minor)
102 {
103 int rc;
104 char *pos;
105 char devnum[16] = {0};
106
107 rc = ventoy_get_sys_file_line(devnum, sizeof(devnum), "/sys/block/%s/dev", name);
108 if (rc)
109 {
110 return 1;
111 }
112
113 pos = strstr(devnum, ":");
114 if (!pos)
115 {
116 return 1;
117 }
118
119 *major = (int)strtol(devnum, NULL, 10);
120 *minor = (int)strtol(pos + 1, NULL, 10);
121
122 return 0;
123 }
124
125 static ventoy_dev_type ventoy_get_dev_type(const char *name, int major, int minor)
126 {
127 int rc;
128 char syspath[128];
129 char dstpath[256];
130
131 memset(syspath, 0, sizeof(syspath));
132 memset(dstpath, 0, sizeof(dstpath));
133
134 scnprintf(syspath, sizeof(syspath), "/sys/block/%s", name);
135 rc = readlink(syspath, dstpath, sizeof(dstpath) - 1);
136 if (rc > 0 && strstr(dstpath, "/usb"))
137 {
138 return VTOY_DEVICE_USB;
139 }
140
141 if (SCSI_BLK_MAJOR(major) && (minor % 0x10 == 0))
142 {
143 return VTOY_DEVICE_SCSI;
144 }
145 else if (IDE_BLK_MAJOR(major) && (minor % 0x40 == 0))
146 {
147 return VTOY_DEVICE_IDE;
148 }
149 else if (major == DAC960_MAJOR && (minor % 0x8 == 0))
150 {
151 return VTOY_DEVICE_DAC960;
152 }
153 else if (major == ATARAID_MAJOR && (minor % 0x10 == 0))
154 {
155 return VTOY_DEVICE_ATARAID;
156 }
157 else if (major == AOE_MAJOR && (minor % 0x10 == 0))
158 {
159 return VTOY_DEVICE_AOE;
160 }
161 else if (major == DASD_MAJOR && (minor % 0x4 == 0))
162 {
163 return VTOY_DEVICE_DASD;
164 }
165 else if (major == VIODASD_MAJOR && (minor % 0x8 == 0))
166 {
167 return VTOY_DEVICE_VIODASD;
168 }
169 else if (SX8_BLK_MAJOR(major) && (minor % 0x20 == 0))
170 {
171 return VTOY_DEVICE_SX8;
172 }
173 else if (I2O_BLK_MAJOR(major) && (minor % 0x10 == 0))
174 {
175 return VTOY_DEVICE_I2O;
176 }
177 else if (CPQARRAY_BLK_MAJOR(major) && (minor % 0x10 == 0))
178 {
179 return VTOY_DEVICE_CPQARRAY;
180 }
181 else if (UBD_MAJOR == major && (minor % 0x10 == 0))
182 {
183 return VTOY_DEVICE_UBD;
184 }
185 else if (XVD_MAJOR == major && (minor % 0x10 == 0))
186 {
187 return VTOY_DEVICE_XVD;
188 }
189 else if (SDMMC_MAJOR == major && (minor % 0x8 == 0))
190 {
191 return VTOY_DEVICE_SDMMC;
192 }
193 else if (ventoy_check_blk_major(major, "virtblk"))
194 {
195 return VTOY_DEVICE_VIRTBLK;
196 }
197 else if (major == LOOP_MAJOR)
198 {
199 return VTOY_DEVICE_LOOP;
200 }
201 else if (major == MD_MAJOR)
202 {
203 return VTOY_DEVICE_MD;
204 }
205 else if (major == RAM_MAJOR)
206 {
207 return VTOY_DEVICE_RAM;
208 }
209 else if (strstr(name, "nvme") && ventoy_check_blk_major(major, "blkext"))
210 {
211 return VTOY_DEVICE_NVME;
212 }
213 else if (strstr(name, "pmem") && ventoy_check_blk_major(major, "blkext"))
214 {
215 return VTOY_DEVICE_PMEM;
216 }
217
218 return VTOY_DEVICE_END;
219 }
220
221 static int ventoy_is_possible_blkdev(const char *name)
222 {
223 if (name[0] == '.')
224 {
225 return 0;
226 }
227
228 /* /dev/ramX */
229 if (name[0] == 'r' && name[1] == 'a' && name[2] == 'm')
230 {
231 return 0;
232 }
233
234 /* /dev/zramX */
235 if (name[0] == 'z' && name[1] == 'r' && name[2] == 'a' && name[3] == 'm')
236 {
237 return 0;
238 }
239
240 /* /dev/loopX */
241 if (name[0] == 'l' && name[1] == 'o' && name[2] == 'o' && name[3] == 'p')
242 {
243 return 0;
244 }
245
246 /* /dev/dm-X */
247 if (name[0] == 'd' && name[1] == 'm' && name[2] == '-' && isdigit(name[3]))
248 {
249 return 0;
250 }
251
252 /* /dev/srX */
253 if (name[0] == 's' && name[1] == 'r' && isdigit(name[2]))
254 {
255 return 0;
256 }
257
258 return 1;
259 }
260
261 uint64_t ventoy_get_disk_size_in_byte(const char *disk)
262 {
263 int fd;
264 int rc;
265 unsigned long long size = 0;
266 char diskpath[256] = {0};
267 char sizebuf[64] = {0};
268
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)
272 {
273 vdebug("get disk size from sysfs for %s\n", disk);
274
275 fd = open(diskpath, O_RDONLY | O_BINARY);
276 if (fd >= 0)
277 {
278 read(fd, sizebuf, sizeof(sizebuf));
279 size = strtoull(sizebuf, NULL, 10);
280 close(fd);
281 return (uint64_t)(size * 512);
282 }
283 }
284 else
285 {
286 vdebug("%s not exist \n", diskpath);
287 }
288
289 // Try 2: get size from ioctl
290 scnprintf(diskpath, sizeof(diskpath) - 1, "/dev/%s", disk);
291 fd = open(diskpath, O_RDONLY);
292 if (fd >= 0)
293 {
294 vdebug("get disk size from ioctl for %s\n", disk);
295 rc = ioctl(fd, BLKGETSIZE64, &size);
296 if (rc == -1)
297 {
298 size = 0;
299 vdebug("failed to ioctl %d\n", rc);
300 }
301 close(fd);
302 }
303 else
304 {
305 vdebug("failed to open %s %d\n", diskpath, errno);
306 }
307
308 vdebug("disk %s size %llu bytes\n", disk, size);
309 return size;
310 }
311
312 int ventoy_get_disk_vendor(const char *name, char *vendorbuf, int bufsize)
313 {
314 if (strncmp(name, "loop", 4) == 0)
315 {
316 scnprintf(vendorbuf, bufsize, "Local");
317 return 0;
318 }
319
320 return ventoy_get_sys_file_line(vendorbuf, bufsize, "/sys/block/%s/device/vendor", name);
321 }
322
323 int ventoy_get_disk_model(const char *name, char *modelbuf, int bufsize)
324 {
325 if (strncmp(name, "loop", 4) == 0)
326 {
327 scnprintf(modelbuf, bufsize, "Loop Device");
328 return 0;
329 }
330
331 return ventoy_get_sys_file_line(modelbuf, bufsize, "/sys/block/%s/device/model", name);
332 }
333
334 static int fatlib_media_sector_read(uint32 sector, uint8 *buffer, uint32 sector_count)
335 {
336 lseek(g_fatlib_media_fd, (sector + g_fatlib_media_offset) * 512ULL, SEEK_SET);
337 read(g_fatlib_media_fd, buffer, sector_count * 512);
338
339 return 1;
340 }
341
342 static int fatlib_is_secure_boot_enable(void)
343 {
344 void *flfile = NULL;
345
346 flfile = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
347 if (flfile)
348 {
349 vlog("/EFI/BOOT/grubx64_real.efi find, secure boot in enabled\n");
350 fl_fclose(flfile);
351 return 1;
352 }
353 else
354 {
355 vlog("/EFI/BOOT/grubx64_real.efi not exist\n");
356 }
357
358 return 0;
359 }
360
361 static int fatlib_get_ventoy_version(char *verbuf, int bufsize)
362 {
363 int rc = 1;
364 int size = 0;
365 char *buf = NULL;
366 char *pos = NULL;
367 char *end = NULL;
368 void *flfile = NULL;
369
370 flfile = fl_fopen("/grub/grub.cfg", "rb");
371 if (flfile)
372 {
373 fl_fseek(flfile, 0, SEEK_END);
374 size = (int)fl_ftell(flfile);
375
376 fl_fseek(flfile, 0, SEEK_SET);
377
378 buf = malloc(size + 1);
379 if (buf)
380 {
381 fl_fread(buf, 1, size, flfile);
382 buf[size] = 0;
383
384 pos = strstr(buf, "VENTOY_VERSION=");
385 if (pos)
386 {
387 pos += strlen("VENTOY_VERSION=");
388 if (*pos == '"')
389 {
390 pos++;
391 }
392
393 end = pos;
394 while (*end != 0 && *end != '"' && *end != '\r' && *end != '\n')
395 {
396 end++;
397 }
398
399 *end = 0;
400
401 scnprintf(verbuf, bufsize - 1, "%s", pos);
402 rc = 0;
403 }
404 free(buf);
405 }
406
407 fl_fclose(flfile);
408 }
409 else
410 {
411 vdebug("No grub.cfg found\n");
412 }
413
414 return rc;
415 }
416
417 /* <BEGIN>: Deleted by longpanda, 20211028 PN:XX LABEL:XX */
418 #if 0
419 int ventoy_get_vtoy_data(ventoy_disk *info, int *ppartstyle)
420 {
421 int i;
422 int fd;
423 int len;
424 int rc = 1;
425 int ret = 1;
426 int part_style;
427 uint64_t part1_start_sector;
428 uint64_t part1_sector_count;
429 uint64_t part2_start_sector;
430 uint64_t part2_sector_count;
431 uint64_t preserved_space;
432 char name[64] = {0};
433 disk_ventoy_data *vtoy = NULL;
434 VTOY_GPT_INFO *gpt = NULL;
435
436 vtoy = &(info->vtoydata);
437 gpt = &(vtoy->gptinfo);
438 memset(vtoy, 0, sizeof(disk_ventoy_data));
439
440 vdebug("ventoy_get_vtoy_data %s\n", info->disk_path);
441
442 if (info->size_in_byte < (2 * VTOYEFI_PART_BYTES))
443 {
444 vdebug("disk %s is too small %llu\n", info->disk_path, (_ull)info->size_in_byte);
445 return 1;
446 }
447
448 fd = open(info->disk_path, O_RDONLY | O_BINARY);
449 if (fd < 0)
450 {
451 vdebug("failed to open %s %d\n", info->disk_path, errno);
452 return 1;
453 }
454
455 len = (int)read(fd, &(vtoy->gptinfo), sizeof(VTOY_GPT_INFO));
456 if (len != sizeof(VTOY_GPT_INFO))
457 {
458 vdebug("failed to read %s %d\n", info->disk_path, errno);
459 goto end;
460 }
461
462 if (gpt->MBR.Byte55 != 0x55 || gpt->MBR.ByteAA != 0xAA)
463 {
464 vdebug("Invalid mbr magic 0x%x 0x%x\n", gpt->MBR.Byte55, gpt->MBR.ByteAA);
465 goto end;
466 }
467
468 if (gpt->MBR.PartTbl[0].FsFlag == 0xEE && strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
469 {
470 part_style = GPT_PART_STYLE;
471 if (ppartstyle)
472 {
473 *ppartstyle = part_style;
474 }
475
476 if (gpt->PartTbl[0].StartLBA == 0 || gpt->PartTbl[1].StartLBA == 0)
477 {
478 vdebug("NO ventoy efi part layout <%llu %llu>\n",
479 (_ull)gpt->PartTbl[0].StartLBA,
480 (_ull)gpt->PartTbl[1].StartLBA);
481 goto end;
482 }
483
484 for (i = 0; i < 36; i++)
485 {
486 name[i] = (char)(gpt->PartTbl[1].Name[i]);
487 }
488 if (strcmp(name, "VTOYEFI"))
489 {
490 vdebug("Invalid efi part2 name <%s>\n", name);
491 goto end;
492 }
493
494 part1_start_sector = gpt->PartTbl[0].StartLBA;
495 part1_sector_count = gpt->PartTbl[0].LastLBA - part1_start_sector + 1;
496 part2_start_sector = gpt->PartTbl[1].StartLBA;
497 part2_sector_count = gpt->PartTbl[1].LastLBA - part2_start_sector + 1;
498
499 preserved_space = info->size_in_byte - (part2_start_sector + part2_sector_count + 33) * 512;
500 }
501 else
502 {
503 part_style = MBR_PART_STYLE;
504 if (ppartstyle)
505 {
506 *ppartstyle = part_style;
507 }
508
509 part1_start_sector = gpt->MBR.PartTbl[0].StartSectorId;
510 part1_sector_count = gpt->MBR.PartTbl[0].SectorCount;
511 part2_start_sector = gpt->MBR.PartTbl[1].StartSectorId;
512 part2_sector_count = gpt->MBR.PartTbl[1].SectorCount;
513
514 preserved_space = info->size_in_byte - (part2_start_sector + part2_sector_count) * 512;
515 }
516
517 if (part1_start_sector != VTOYIMG_PART_START_SECTOR ||
518 part2_sector_count != VTOYEFI_PART_SECTORS ||
519 (part1_start_sector + part1_sector_count) != part2_start_sector)
520 {
521 vdebug("Not valid ventoy partition layout [%llu %llu] [%llu %llu]\n",
522 part1_start_sector, part1_sector_count, part2_start_sector, part2_sector_count);
523 goto end;
524 }
525
526 vdebug("ventoy partition layout check OK: [%llu %llu] [%llu %llu]\n",
527 part1_start_sector, part1_sector_count, part2_start_sector, part2_sector_count);
528
529 vtoy->ventoy_valid = 1;
530
531 vdebug("now check secure boot for %s ...\n", info->disk_path);
532
533 g_fatlib_media_fd = fd;
534 g_fatlib_media_offset = part2_start_sector;
535 fl_init();
536
537 if (0 == fl_attach_media(fatlib_media_sector_read, NULL))
538 {
539 ret = fatlib_get_ventoy_version(vtoy->ventoy_ver, sizeof(vtoy->ventoy_ver));
540 if (ret == 0 && vtoy->ventoy_ver[0])
541 {
542 vtoy->secure_boot_flag = fatlib_is_secure_boot_enable();
543 }
544 else
545 {
546 vdebug("fatlib_get_ventoy_version failed %d\n", ret);
547 }
548 }
549 else
550 {
551 vdebug("fl_attach_media failed\n");
552 }
553
554 fl_shutdown();
555 g_fatlib_media_fd = -1;
556 g_fatlib_media_offset = 0;
557
558 if (vtoy->ventoy_ver[0] == 0)
559 {
560 vtoy->ventoy_ver[0] = '?';
561 }
562
563 if (0 == vtoy->ventoy_valid)
564 {
565 goto end;
566 }
567
568 lseek(fd, 2040 * 512, SEEK_SET);
569 read(fd, vtoy->rsvdata, sizeof(vtoy->rsvdata));
570
571 vtoy->preserved_space = preserved_space;
572 vtoy->partition_style = part_style;
573 vtoy->part2_start_sector = part2_start_sector;
574
575 rc = 0;
576 end:
577 vtoy_safe_close_fd(fd);
578 return rc;
579 }
580 #endif /* #if 0 */
581 /* <END> : Deleted by longpanda, 20211028 PN:XX LABEL:XX */
582
583
584 int ventoy_get_disk_info(char **argv)
585 {
586 uint64_t size;
587 char vendor[128];
588 char model[128];
589 char *disk = argv[4];
590
591 if (strncmp(argv[4], "/dev/", 5) == 0)
592 {
593 disk += 5;
594 }
595 ventoy_get_disk_vendor(disk, vendor, sizeof(vendor));
596 ventoy_get_disk_model(disk, model, sizeof(model));
597
598 scnprintf(g_sysinfo.cur_model, sizeof(g_sysinfo.cur_model), "%s %s [%s]", vendor, model, argv[4]);
599 strlcpy(g_sysinfo.cur_ventoy_ver, argv[5]);
600 strlcpy(g_sysinfo.cur_fsname, argv[6]);
601 g_sysinfo.cur_part_style = (int)strtol(argv[7], NULL, 10);
602 g_sysinfo.cur_secureboot = (int)strtol(argv[8], NULL, 10);
603
604 size = ventoy_get_disk_size_in_byte(disk);
605 scnprintf(g_sysinfo.cur_capacity, sizeof(g_sysinfo.cur_capacity), "%dGB", (int)ventoy_get_human_readable_gb(size));
606
607 return 0;
608 }
609
610 int ventoy_disk_init(void)
611 {
612 return 0;
613 }
614
615 void ventoy_disk_exit(void)
616 {
617 }
618
619