int grub_util_biosdisk_is_floppy (grub_disk_t disk) { struct stat st; int fd; const char *dname; dname = grub_util_biosdisk_get_osdev (disk); if (!dname) return 0; fd = open (dname, O_RDONLY); /* Shouldn't happen. */ if (fd == -1) return 0; /* Shouldn't happen either. */ if (fstat (fd, &st) < 0) { close (fd); return 0; } close (fd); #if defined(__NetBSD__) if (major(st.st_rdev) == RAW_FLOPPY_MAJOR) return 1; #endif #if defined(FLOPPY_MAJOR) if (major(st.st_rdev) == FLOPPY_MAJOR) #else /* Some kernels (e.g. kFreeBSD) don't have a static major number for floppies, but they still use a "fd[0-9]" pathname. */ if (dname[5] == 'f' && dname[6] == 'd' && dname[7] >= '0' && dname[7] <= '9') #endif return 1; return 0; }
static void probe (const char *path, char **device_names, char delim) { char **drives_names = NULL; char **curdev, **curdrive; char *grub_path = NULL; int ndev = 0; if (path != NULL) { grub_path = canonicalize_file_name (path); if (! grub_path) grub_util_error (_("failed to get canonical path of `%s'"), path); device_names = grub_guess_root_devices (grub_path); free (grub_path); } if (! device_names) grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path); if (print == PRINT_DEVICE) { for (curdev = device_names; *curdev; curdev++) { printf ("%s", *curdev); putchar (delim); } return; } if (print == PRINT_DISK) { for (curdev = device_names; *curdev; curdev++) { char *disk; disk = grub_util_get_os_disk (*curdev); if (!disk) { grub_print_error (); continue; } printf ("%s", disk); putchar (delim); } return; } for (curdev = device_names; *curdev; curdev++) { grub_util_pull_device (*curdev); ndev++; } drives_names = xmalloc (sizeof (drives_names[0]) * (ndev + 1)); for (curdev = device_names, curdrive = drives_names; *curdev; curdev++, curdrive++) { *curdrive = grub_util_get_grub_dev (*curdev); if (! *curdrive) grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), *curdev); } *curdrive = 0; if (print == PRINT_DRIVE) { for (curdrive = drives_names; *curdrive; curdrive++) { printf ("(%s)", *curdrive); putchar (delim); } goto end; } if (print == PRINT_ZERO_CHECK) { for (curdev = drives_names; *curdev; curdev++) { grub_device_t dev = NULL; grub_uint32_t buffer[32768]; grub_disk_addr_t addr; grub_disk_addr_t dsize; grub_util_info ("opening %s", *curdev); dev = grub_device_open (*curdev); if (! dev || !dev->disk) grub_util_error ("%s", grub_errmsg); dsize = grub_disk_get_size (dev->disk); for (addr = 0; addr < dsize; addr += sizeof (buffer) / GRUB_DISK_SECTOR_SIZE) { grub_size_t sz = sizeof (buffer); grub_uint32_t *ptr; if (sizeof (buffer) / GRUB_DISK_SECTOR_SIZE > dsize - addr) sz = (dsize - addr) * GRUB_DISK_SECTOR_SIZE; grub_disk_read (dev->disk, addr, 0, sz, buffer); for (ptr = buffer; ptr < buffer + sz / sizeof (*buffer); ptr++) if (*ptr) { grub_printf ("false\n"); grub_device_close (dev); goto end; } } grub_device_close (dev); } grub_printf ("true\n"); } if (print == PRINT_FS || print == PRINT_FS_UUID || print == PRINT_FS_LABEL) { grub_device_t dev = NULL; grub_fs_t fs; grub_util_info ("opening %s", drives_names[0]); dev = grub_device_open (drives_names[0]); if (! dev) grub_util_error ("%s", grub_errmsg); fs = grub_fs_probe (dev); if (! fs) grub_util_error ("%s", grub_errmsg); if (print == PRINT_FS) { printf ("%s", fs->name); putchar (delim); } else if (print == PRINT_FS_UUID) { char *uuid; if (! fs->uuid) grub_util_error (_("%s does not support UUIDs"), fs->name); if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE) grub_util_error ("%s", grub_errmsg); printf ("%s", uuid); putchar (delim); } else if (print == PRINT_FS_LABEL) { char *label; if (! fs->label) grub_util_error (_("filesystem `%s' does not support labels"), fs->name); if (fs->label (dev, &label) != GRUB_ERR_NONE) grub_util_error ("%s", grub_errmsg); printf ("%s", label); putchar (delim); } grub_device_close (dev); goto end; } for (curdrive = drives_names, curdev = device_names; *curdrive; curdrive++, curdev++) { grub_device_t dev = NULL; grub_util_info ("opening %s", *curdrive); dev = grub_device_open (*curdrive); if (! dev) grub_util_error ("%s", grub_errmsg); if (print == PRINT_HINT_STR) { const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); const char *ofpath = osdev ? grub_util_devname_to_ofpath (osdev) : 0; char *biosname, *bare, *efi; const char *map; if (ofpath) { char *tmp = xmalloc (strlen (ofpath) + sizeof ("ieee1275/")); char *p; p = grub_stpcpy (tmp, "ieee1275/"); strcpy (p, ofpath); printf ("--hint-ieee1275='"); print_full_name (tmp, dev); printf ("' "); free (tmp); } biosname = guess_bios_drive (*curdev); if (biosname) { printf ("--hint-bios="); print_full_name (biosname, dev); printf (" "); } free (biosname); efi = guess_efi_drive (*curdev); if (efi) { printf ("--hint-efi="); print_full_name (efi, dev); printf (" "); } free (efi); bare = guess_baremetal_drive (*curdev); if (bare) { printf ("--hint-baremetal="); print_full_name (bare, dev); printf (" "); } free (bare); /* FIXME: Add ARC hint. */ map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { printf ("--hint='"); print_full_name (map, dev); printf ("' "); } if (curdrive[1]) printf (" "); else printf ("\n"); grub_device_close (dev); continue; } if ((print == PRINT_COMPATIBILITY_HINT || print == PRINT_BIOS_HINT || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT) && dev->disk->dev->id != GRUB_DISK_DEVICE_HOSTDISK_ID) { print_full_name (dev->disk->name, dev); putchar (delim); continue; } if (print == PRINT_COMPATIBILITY_HINT) { const char *map; char *biosname; map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); grub_device_close (dev); /* Compatibility hint is one device only. */ break; } biosname = guess_bios_drive (*curdev); if (biosname) { print_full_name (biosname, dev); putchar (delim); } free (biosname); grub_device_close (dev); /* Compatibility hint is one device only. */ if (biosname) break; continue; } if (print == PRINT_BIOS_HINT) { char *biosname; biosname = guess_bios_drive (*curdev); if (biosname) { print_full_name (biosname, dev); putchar (delim); } free (biosname); grub_device_close (dev); continue; } if (print == PRINT_IEEE1275_HINT) { const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); const char *ofpath = grub_util_devname_to_ofpath (osdev); const char *map; map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); } if (ofpath) { char *tmp = xmalloc (strlen (ofpath) + sizeof ("ieee1275/")); char *p; p = grub_stpcpy (tmp, "ieee1275/"); strcpy (p, ofpath); print_full_name (tmp, dev); free (tmp); putchar (delim); } grub_device_close (dev); continue; } if (print == PRINT_EFI_HINT) { char *biosname; const char *map; biosname = guess_efi_drive (*curdev); map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); } if (biosname) { print_full_name (biosname, dev); putchar (delim); } free (biosname); grub_device_close (dev); continue; } if (print == PRINT_BAREMETAL_HINT) { char *biosname; const char *map; biosname = guess_baremetal_drive (*curdev); map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); } if (biosname) { print_full_name (biosname, dev); putchar (delim); } free (biosname); grub_device_close (dev); continue; } if (print == PRINT_ARC_HINT) { const char *map; map = grub_util_biosdisk_get_compatibility_hint (dev->disk); if (map) { print_full_name (map, dev); putchar (delim); } /* FIXME */ grub_device_close (dev); continue; } if (print == PRINT_ABSTRACTION) { probe_abstraction (dev->disk); putchar (delim); grub_device_close (dev); continue; } if (print == PRINT_CRYPTODISK_UUID) { probe_cryptodisk_uuid (dev->disk); putchar (delim); grub_device_close (dev); continue; } if (print == PRINT_PARTMAP) { /* Check if dev->disk itself is contained in a partmap. */ probe_partmap (dev->disk); putchar (delim); grub_device_close (dev); continue; } if (print == PRINT_MSDOS_PARTTYPE) { if (dev->disk->partition && strcmp(dev->disk->partition->partmap->name, "msdos") == 0) printf ("%02x", dev->disk->partition->msdostype); putchar (delim); grub_device_close (dev); continue; } if (print == PRINT_GPT_PARTTYPE) { if (dev->disk->partition && strcmp (dev->disk->partition->partmap->name, "gpt") == 0) { struct grub_gpt_partentry gptdata; grub_partition_t p = dev->disk->partition; dev->disk->partition = dev->disk->partition->parent; if (grub_disk_read (dev->disk, p->offset, p->index, sizeof (gptdata), &gptdata) == 0) { grub_gpt_part_type_t gpttype; gpttype.data1 = grub_le_to_cpu32 (gptdata.type.data1); gpttype.data2 = grub_le_to_cpu16 (gptdata.type.data2); gpttype.data3 = grub_le_to_cpu16 (gptdata.type.data3); grub_memcpy (gpttype.data4, gptdata.type.data4, 8); grub_printf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", gpttype.data1, gpttype.data2, gpttype.data3, gpttype.data4[0], gpttype.data4[1], gpttype.data4[2], gpttype.data4[3], gpttype.data4[4], gpttype.data4[5], gpttype.data4[6], gpttype.data4[7]); } dev->disk->partition = p; } putchar (delim); grub_device_close (dev); continue; } } end: for (curdrive = drives_names; *curdrive; curdrive++) free (*curdrive); free (drives_names); }
int grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags, grub_disk_addr_t *max) { grub_util_fd_t fd; struct grub_util_hostdisk_data *data = disk->data; *max = ~0ULL; #ifdef O_LARGEFILE flags |= O_LARGEFILE; #endif #ifdef O_SYNC flags |= O_SYNC; #endif #ifdef O_FSYNC flags |= O_FSYNC; #endif #ifdef O_BINARY flags |= O_BINARY; #endif /* Linux has a bug that the disk cache for a whole disk is not consistent with the one for a partition of the disk. */ { int is_partition = 0; char dev[PATH_MAX]; grub_disk_addr_t part_start = 0; part_start = grub_partition_get_start (disk->partition); strcpy (dev, grub_util_biosdisk_get_osdev (disk)); if (disk->partition && strncmp (dev, "/dev/", 5) == 0) { if (sector >= part_start) is_partition = grub_hostdisk_linux_find_partition (dev, part_start); else *max = part_start - sector; } reopen: if (data->dev && strcmp (data->dev, dev) == 0 && data->access_mode == (flags & O_ACCMODE)) { grub_dprintf ("hostdisk", "reusing open device `%s'\n", dev); fd = data->fd; } else { free (data->dev); data->dev = 0; if (data->fd != -1) { if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY) { fsync (data->fd); if (data->is_disk) ioctl (data->fd, BLKFLSBUF, 0); } close (data->fd); data->fd = -1; } /* Open the partition. */ grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev); fd = open (dev, flags); if (fd < 0) { grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"), dev, strerror (errno)); return -1; } data->dev = xstrdup (dev); data->access_mode = (flags & O_ACCMODE); data->fd = fd; if (data->is_disk) ioctl (data->fd, BLKFLSBUF, 0); } if (is_partition) { *max = grub_util_get_fd_size (fd, dev, 0); *max >>= disk->log_sector_size; if (sector - part_start >= *max) { *max = disk->partition->len - (sector - part_start); if (*max == 0) *max = ~0ULL; is_partition = 0; strcpy (dev, grub_util_biosdisk_get_osdev (disk)); goto reopen; } sector -= part_start; *max -= sector; } } if (grub_util_fd_seek (fd, sector << disk->log_sector_size)) { close (fd); grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"), grub_util_biosdisk_get_osdev (disk), strerror (errno)); return -1; } return fd; }