/* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2004,2007 Free Software Foundation, Inc. * * VAS_EBOOT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VAS_EBOOT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VAS_EBOOT. If not, see . */ #include #include #include #include #include #ifdef VAS_EBOOT_UTIL #include #endif VasEBoot_partition_map_t VasEBoot_partition_map_list; #define MAX_RECURSION_DEPTH 32 static unsigned int recursion_depth = 0; /* * 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 VasEBoot_partition_check_containment (const VasEBoot_disk_t disk, const VasEBoot_partition_t part) { if (disk->partition == NULL) return 1; if (part->start + part->len > disk->partition->len) { char *partname; partname = VasEBoot_partition_get_name (disk->partition); VasEBoot_dprintf ("partition", "sub-partition %s%d of (%s,%s) ends after parent.\n", part->partmap->name, part->number + 1, disk->name, partname); #ifdef VAS_EBOOT_UTIL VasEBoot_util_warn (_("Discarding improperly nested partition (%s,%s,%s%d)"), disk->name, partname, part->partmap->name, part->number + 1); #endif VasEBoot_free (partname); return 0; } return 1; } /* Context for VasEBoot_partition_map_probe. */ struct VasEBoot_partition_map_probe_ctx { int partnum; VasEBoot_partition_t p; }; /* Helper for VasEBoot_partition_map_probe. */ static int probe_iter (VasEBoot_disk_t dsk, const VasEBoot_partition_t partition, void *data) { struct VasEBoot_partition_map_probe_ctx *ctx = data; if (ctx->partnum != partition->number) return 0; if (!(VasEBoot_partition_check_containment (dsk, partition))) return 0; ctx->p = (VasEBoot_partition_t) VasEBoot_malloc (sizeof (*ctx->p)); if (! ctx->p) return 1; VasEBoot_memcpy (ctx->p, partition, sizeof (*ctx->p)); return 1; } static VasEBoot_partition_t VasEBoot_partition_map_probe (const VasEBoot_partition_map_t partmap, VasEBoot_disk_t disk, int partnum) { struct VasEBoot_partition_map_probe_ctx ctx = { .partnum = partnum, .p = 0 }; partmap->iterate (disk, probe_iter, &ctx); if (VasEBoot_errno) goto fail; return ctx.p; fail: VasEBoot_free (ctx.p); return 0; } VasEBoot_partition_t VasEBoot_partition_probe (struct VasEBoot_disk *disk, const char *str) { VasEBoot_partition_t part; VasEBoot_partition_t curpart = 0; VasEBoot_partition_t tail; const char *ptr; if (str == NULL) return 0; part = tail = disk->partition; for (ptr = str; *ptr;) { VasEBoot_partition_map_t partmap; unsigned long num; const char *partname, *partname_end; partname = ptr; while (*ptr && VasEBoot_isalpha (*ptr)) ptr++; partname_end = ptr; num = VasEBoot_strtoul (ptr, &ptr, 0); if (num == 0 || num > VAS_EBOOT_INT_MAX) { VasEBoot_error (VAS_EBOOT_ERR_BAD_NUMBER, N_("invalid partition number")); return 0; } num -= 1; curpart = 0; /* Use the first partition map type found. */ FOR_PARTITION_MAPS(partmap) { if (partname_end != partname && (VasEBoot_strncmp (partmap->name, partname, partname_end - partname) != 0 || partmap->name[partname_end - partname] != 0)) continue; disk->partition = part; curpart = VasEBoot_partition_map_probe (partmap, disk, num); disk->partition = tail; if (curpart) break; if (VasEBoot_errno == VAS_EBOOT_ERR_BAD_PART_TABLE) { /* Continue to next partition map type. */ VasEBoot_errno = VAS_EBOOT_ERR_NONE; continue; } break; } if (! curpart) { while (part) { curpart = part->parent; VasEBoot_free (part); part = curpart; } return 0; } curpart->parent = part; part = curpart; if (! ptr || *ptr != ',') break; ptr++; } return part; } /* Context for VasEBoot_partition_iterate. */ struct VasEBoot_partition_iterate_ctx { int ret; VasEBoot_partition_iterate_hook_t hook; void *hook_data; }; /* Helper for VasEBoot_partition_iterate. */ static int part_iterate (VasEBoot_disk_t dsk, const VasEBoot_partition_t partition, void *data) { struct VasEBoot_partition_iterate_ctx *ctx = data; struct VasEBoot_partition p = *partition; if (!(VasEBoot_partition_check_containment (dsk, partition))) return 0; p.parent = dsk->partition; dsk->partition = 0; if (ctx->hook (dsk, &p, ctx->hook_data)) { ctx->ret = 1; return 1; } if (p.start != 0) { const struct VasEBoot_partition_map *partmap; dsk->partition = &p; FOR_PARTITION_MAPS(partmap) { VasEBoot_err_t err; recursion_depth++; if (recursion_depth <= MAX_RECURSION_DEPTH) err = partmap->iterate (dsk, part_iterate, ctx); else err = VasEBoot_error (VAS_EBOOT_ERR_RECURSION_DEPTH, "maximum recursion depth exceeded"); recursion_depth--; if (err) VasEBoot_errno = VAS_EBOOT_ERR_NONE; if (ctx->ret) break; } } dsk->partition = p.parent; return ctx->ret; } int VasEBoot_partition_iterate (struct VasEBoot_disk *disk, VasEBoot_partition_iterate_hook_t hook, void *hook_data) { struct VasEBoot_partition_iterate_ctx ctx = { .ret = 0, .hook = hook, .hook_data = hook_data }; const struct VasEBoot_partition_map *partmap; FOR_PARTITION_MAPS(partmap) { VasEBoot_err_t err; err = partmap->iterate (disk, part_iterate, &ctx); if (err) VasEBoot_errno = VAS_EBOOT_ERR_NONE; if (ctx.ret) break; } return ctx.ret; } char * VasEBoot_partition_get_name (const VasEBoot_partition_t partition) { char *out = 0, *ptr; VasEBoot_size_t needlen = 0; VasEBoot_partition_t part; if (!partition) return VasEBoot_strdup (""); for (part = partition; part; part = part->parent) /* Even on 64-bit machines this buffer is enough to hold longest number. */ needlen += VasEBoot_strlen (part->partmap->name) + 1 + 27; out = VasEBoot_malloc (needlen + 1); if (!out) return NULL; ptr = out + needlen; *ptr = 0; for (part = partition; part; part = part->parent) { char buf[27]; VasEBoot_size_t len; VasEBoot_snprintf (buf, sizeof (buf), "%d", part->number + 1); len = VasEBoot_strlen (buf); ptr -= len; VasEBoot_memcpy (ptr, buf, len); len = VasEBoot_strlen (part->partmap->name); ptr -= len; VasEBoot_memcpy (ptr, part->partmap->name, len); *--ptr = ','; } VasEBoot_memmove (out, ptr + 1, out + needlen - ptr); return out; }