/* * Checks that disk->partition contains part. This function assumes that the * start of part is relative to the start of disk->partition. Returns 1 if * disk->partition is null. */ static int grub_partition_check_containment (const grub_disk_t disk, const grub_partition_t part) { if (disk->partition == NULL) return 1; if (part->start + part->len > disk->partition->len) { char *partname; partname = grub_partition_get_name (disk->partition); grub_dprintf ("partition", "sub-partition %s%d of (%s,%s) ends after parent.\n", part->partmap->name, part->number + 1, disk->name, partname); #ifdef GRUB_UTIL grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)", disk->name, partname, part->partmap->name, part->number + 1); #endif grub_free (partname); return 0; } return 1; }
static char * get_mdadm_uuid (const char *os_dev) { const char *argv[5]; int fd; pid_t pid; FILE *mdadm; char *buf = NULL; size_t len = 0; char *name = NULL; argv[0] = "mdadm"; argv[1] = "--detail"; argv[2] = "--export"; argv[3] = os_dev; argv[4] = NULL; pid = grub_util_exec_pipe (argv, &fd); if (!pid) return NULL; /* Parent. Read mdadm's output. */ mdadm = fdopen (fd, "r"); if (! mdadm) { grub_util_warn (_("Unable to open stream from %s: %s"), "mdadm", strerror (errno)); goto out; } while (getline (&buf, &len, mdadm) > 0) { if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0) { char *name_start, *ptri, *ptro; free (name); name_start = buf + sizeof ("MD_UUID=") - 1; ptro = name = xmalloc (strlen (name_start) + 1); for (ptri = name_start; *ptri && *ptri != '\n' && *ptri != '\r'; ptri++) if ((*ptri >= '0' && *ptri <= '9') || (*ptri >= 'a' && *ptri <= 'f') || (*ptri >= 'A' && *ptri <= 'F')) *ptro++ = *ptri; *ptro = 0; } } out: close (fd); waitpid (pid, NULL, 0); free (buf); return name; }
void grub_util_pull_lvm_by_command (const char *os_dev) { const char *argv[8]; int fd; pid_t pid; FILE *vgs; char *buf = NULL; size_t len = 0; char *vgname = NULL; const char *iptr; char *optr; char *vgid = NULL; grub_size_t vgidlen = 0; vgid = grub_util_get_vg_uuid (os_dev); if (vgid) vgidlen = grub_strlen (vgid); if (!vgid) { if (strncmp (os_dev, LVM_DEV_MAPPER_STRING, sizeof (LVM_DEV_MAPPER_STRING) - 1) != 0) return; vgname = xmalloc (strlen (os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1) + 1); for (iptr = os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1, optr = vgname; *iptr; ) if (*iptr != '-') *optr++ = *iptr++; else if (iptr[0] == '-' && iptr[1] == '-') { iptr += 2; *optr++ = '-'; } else break; *optr = '\0'; } /* by default PV name is left aligned in 10 character field, meaning that we do not know where name ends. Using dummy --separator disables alignment. We have a single field, so separator itself is not output */ argv[0] = "vgs"; argv[1] = "--options"; if (vgid) argv[2] = "vg_uuid,pv_name"; else argv[2] = "pv_name"; argv[3] = "--noheadings"; argv[4] = "--separator"; argv[5] = ":"; argv[6] = vgname; argv[7] = NULL; pid = grub_util_exec_pipe (argv, &fd); free (vgname); if (!pid) return; /* Parent. Read vgs' output. */ vgs = fdopen (fd, "r"); if (! vgs) { grub_util_warn (_("Unable to open stream from %s: %s"), "vgs", strerror (errno)); goto out; } while (getline (&buf, &len, vgs) > 0) { char *ptr; /* LVM adds two spaces as standard prefix */ for (ptr = buf; ptr < buf + 2 && *ptr == ' '; ptr++); if (vgid && (grub_strncmp (vgid, ptr, vgidlen) != 0 || ptr[vgidlen] != ':')) continue; if (vgid) ptr += vgidlen + 1; if (*ptr == '\0') continue; *(ptr + strlen (ptr) - 1) = '\0'; grub_util_pull_device (ptr); } out: close (fd); waitpid (pid, NULL, 0); free (buf); }
static int grub_util_is_imsm (const char *os_dev) { int retry; int is_imsm = 0; int container_seen = 0; const char *dev = os_dev; do { const char *argv[5]; int fd; pid_t pid; FILE *mdadm; char *buf = NULL; size_t len = 0; retry = 0; /* We'll do one more pass if device is part of container */ argv[0] = "mdadm"; argv[1] = "--detail"; argv[2] = "--export"; argv[3] = dev; argv[4] = NULL; pid = grub_util_exec_pipe (argv, &fd); if (!pid) { if (dev != os_dev) free ((void *) dev); return 0; } /* Parent. Read mdadm's output. */ mdadm = fdopen (fd, "r"); if (! mdadm) { grub_util_warn (_("Unable to open stream from %s: %s"), "mdadm", strerror (errno)); close (fd); waitpid (pid, NULL, 0); if (dev != os_dev) free ((void *) dev); return 0; } while (getline (&buf, &len, mdadm) > 0) { if (strncmp (buf, "MD_CONTAINER=", sizeof ("MD_CONTAINER=") - 1) == 0 && !container_seen) { char *newdev, *ptr; newdev = xstrdup (buf + sizeof ("MD_CONTAINER=") - 1); ptr = newdev + strlen (newdev) - 1; for (; ptr >= newdev && (*ptr == '\n' || *ptr == '\r'); ptr--); ptr[1] = 0; grub_util_info ("Container of %s is %s", dev, newdev); dev = newdev; container_seen = retry = 1; break; } if (strncmp (buf, "MD_METADATA=imsm", sizeof ("MD_METADATA=imsm") - 1) == 0) { is_imsm = 1; grub_util_info ("%s is imsm", dev); break; } } free (buf); close (fd); waitpid (pid, NULL, 0); } while (retry); if (dev != os_dev) free ((void *) dev); return is_imsm; }
static grub_err_t bsdlabel_partition_map_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition_bsd_disk_label label; struct grub_partition p; grub_disk_addr_t delta = 0; unsigned pos; /* Read the BSD label. */ if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, sizeof (label), &label)) return grub_errno; /* Check if it is valid. */ if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); /* A kludge to determine a base of be.offset. */ if (GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION < grub_cpu_to_le16 (label.num_partitions)) { struct grub_partition_bsd_entry whole_disk_be; pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR * GRUB_DISK_SECTOR_SIZE + sizeof (struct grub_partition_bsd_entry) * GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION; if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE, pos % GRUB_DISK_SECTOR_SIZE, sizeof (whole_disk_be), &whole_disk_be)) return grub_errno; delta = grub_le_to_cpu32 (whole_disk_be.offset); } pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR * GRUB_DISK_SECTOR_SIZE; for (p.number = 0; p.number < grub_cpu_to_le16 (label.num_partitions); p.number++, pos += sizeof (struct grub_partition_bsd_entry)) { struct grub_partition_bsd_entry be; if (p.number == GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION) continue; p.offset = pos / GRUB_DISK_SECTOR_SIZE; p.index = pos % GRUB_DISK_SECTOR_SIZE; if (grub_disk_read (disk, p.offset, p.index, sizeof (be), &be)) return grub_errno; p.start = grub_le_to_cpu32 (be.offset); p.len = grub_le_to_cpu32 (be.size); p.partmap = &grub_bsdlabel_partition_map; grub_dprintf ("partition", "partition %d: type 0x%x, start 0x%llx, len 0x%llx\n", p.number, be.fs_type, (unsigned long long) p.start, (unsigned long long) p.len); if (p.len == 0) continue; if (p.start < delta) { #ifdef GRUB_UTIL char *partname; #endif grub_dprintf ("partition", "partition %d: invalid start (found 0x%llx, wanted >= 0x%llx)\n", p.number, (unsigned long long) p.start, (unsigned long long) delta); #ifdef GRUB_UTIL /* disk->partition != NULL as 0 < delta */ partname = grub_partition_get_name (disk->partition); grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)", disk->name, partname, p.partmap->name, p.number + 1); grub_free (partname); #endif continue; } p.start -= delta; if (hook (disk, &p)) return grub_errno; } return GRUB_ERR_NONE; }
static void read_device_map (const char *dev_map) { FILE *fp; char buf[1024]; /* XXX */ int lineno = 0; if (dev_map[0] == '\0') { grub_util_info ("no device.map"); return; } fp = grub_util_fopen (dev_map, "r"); if (! fp) { grub_util_info (_("cannot open `%s': %s"), dev_map, strerror (errno)); return; } while (fgets (buf, sizeof (buf), fp)) { char *p = buf; char *e; char *drive_e, *drive_p; int drive; lineno++; /* Skip leading spaces. */ while (*p && grub_isspace (*p)) p++; /* If the first character is `#' or NUL, skip this line. */ if (*p == '\0' || *p == '#') continue; if (*p != '(') { char *tmp; tmp = xasprintf (_("missing `%c' symbol"), '('); grub_util_error ("%s:%d: %s", dev_map, lineno, tmp); } p++; /* Find a free slot. */ drive = find_free_slot (); if (drive < 0) grub_util_error ("%s:%d: %s", dev_map, lineno, _("device count exceeds limit")); e = p; p = strchr (p, ')'); if (! p) { char *tmp; tmp = xasprintf (_("missing `%c' symbol"), ')'); grub_util_error ("%s:%d: %s", dev_map, lineno, tmp); } map[drive].drive = 0; if ((e[0] == 'f' || e[0] == 'h' || e[0] == 'c') && e[1] == 'd') { char *ptr; for (ptr = e + 2; ptr < p; ptr++) if (!grub_isdigit (*ptr)) break; if (ptr == p) { map[drive].drive = xmalloc (p - e + sizeof ('\0')); strncpy (map[drive].drive, e, p - e + sizeof ('\0')); map[drive].drive[p - e] = '\0'; } if (*ptr == ',') { *p = 0; /* TRANSLATORS: Only one entry is ignored. However the suggestion is to correct/delete the whole file. device.map is a file indicating which devices are available at boot time. Fedora populated it with entries like (hd0,1) /dev/sda1 which would mean that every partition is a separate disk for BIOS. Such entries were inactive in GRUB due to its bug which is now gone. Without this additional check these entries would be harmful now. */ grub_util_warn (_("the device.map entry `%s' is invalid. " "Ignoring it. Please correct or " "delete your device.map"), e); continue; } } drive_e = e; drive_p = p; map[drive].device_map = 1; p++; /* Skip leading spaces. */ while (*p && grub_isspace (*p)) p++; if (*p == '\0') grub_util_error ("%s:%d: %s", dev_map, lineno, _("filename expected")); /* NUL-terminate the filename. */ e = p; while (*e && ! grub_isspace (*e)) e++; *e = '\0'; if (!grub_util_check_file_presence (p)) { free (map[drive].drive); map[drive].drive = NULL; grub_util_info ("Cannot stat `%s', skipping", p); continue; } /* On Linux, the devfs uses symbolic links horribly, and that confuses the interface very much, so use realpath to expand symbolic links. */ map[drive].device = canonicalize_file_name (p); if (! map[drive].device) map[drive].device = xstrdup (p); if (!map[drive].drive) { char c; map[drive].drive = xmalloc (sizeof ("hostdisk/") + strlen (p)); memcpy (map[drive].drive, "hostdisk/", sizeof ("hostdisk/") - 1); strcpy (map[drive].drive + sizeof ("hostdisk/") - 1, p); c = *drive_p; *drive_p = 0; /* TRANSLATORS: device.map is a filename. Not to be translated. device.map specifies disk correspondance overrides. Previously one could create any kind of device name with this. Due to some problems we decided to limit it to just a handful possibilities. */ grub_util_warn (_("the drive name `%s' in device.map is incorrect. " "Using %s instead. " "Please use the form [hfc]d[0-9]* " "(E.g. `hd0' or `cd')"), drive_e, map[drive].drive); *drive_p = c; } grub_util_info ("adding `%s' -> `%s' from device.map", map[drive].drive, map[drive].device); grub_hostdisk_flush_initial_buffer (map[drive].device); } fclose (fp); }