/* Register a preboot hook. */ struct grub_preboot * grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int flags), grub_err_t (*preboot_rest_func) (void), grub_loader_preboot_hook_prio_t prio) { struct grub_preboot *cur, *new_preboot; if (! preboot_func && ! preboot_rest_func) return 0; new_preboot = (struct grub_preboot *) grub_malloc (sizeof (struct grub_preboot)); if (! new_preboot) return 0; new_preboot->preboot_func = preboot_func; new_preboot->preboot_rest_func = preboot_rest_func; new_preboot->prio = prio; for (cur = preboots_head; cur && cur->prio > prio; cur = cur->next); if (cur) { new_preboot->next = cur; new_preboot->prev = cur->prev; cur->prev = new_preboot; } else { new_preboot->next = 0; new_preboot->prev = preboots_tail; preboots_tail = new_preboot; } if (new_preboot->prev) new_preboot->prev->next = new_preboot; else preboots_head = new_preboot; return new_preboot; }
static void insert_bootpath (void) { char *bootpath; grub_ssize_t bootpath_size; char *type; if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath", &bootpath_size) || bootpath_size <= 0) { /* Should never happen. */ grub_printf ("/chosen/bootpath property missing!\n"); return; } bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); if (! bootpath) { grub_print_error (); return; } grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", bootpath, (grub_size_t) bootpath_size + 1, 0); bootpath[bootpath_size] = '\0'; /* Transform an OF device path to a GRUB path. */ type = grub_ieee1275_get_device_type (bootpath); if (!(type && grub_strcmp (type, "network") == 0)) { struct ofdisk_hash_ent *op; char *device = grub_ieee1275_get_devname (bootpath); op = ofdisk_hash_add (device, NULL); op->is_boot = 1; } grub_free (type); grub_free (bootpath); }
static char * grub_gettext_getstring_from_position (int position) { int internal_position; int length, offset; char *original; /* Get position for string i. */ internal_position = grub_gettext_offsetoriginal + (position * 8); /* Get the length of the string i. */ grub_gettext_pread (fd_mo, (char *) &length, 4, internal_position); /* Get the offset of the string i. */ grub_gettext_pread (fd_mo, (char *) &offset, 4, internal_position + 4); /* Get the string i. */ original = grub_malloc (length + 1); grub_gettext_getstring_from_offset (offset, length, original); return original; }
char * grub_legacy_escape (const char *in, grub_size_t len) { char *ptr; char *ret; char saved; int overhead = 0; for (ptr = (char*)in; ptr < in + len && *ptr; ptr++) if (*ptr == '\'') overhead += 3; ret = grub_malloc (ptr - in + overhead + 1); if (!ret) return NULL; ptr = (char*)in; saved = ptr[len]; ptr[len] = '\0'; grub_strchrsub (ret, ptr, '\'', "'\\''"); ptr[len] = saved; return ret; }
static char * grub_cpio_get_link_target (struct grub_archelp_data *data) { char *ret; grub_err_t err; if (data->size == 0) return grub_strdup (""); ret = grub_malloc (data->size + 1); if (!ret) return NULL; err = grub_disk_read (data->disk, 0, data->dofs, data->size, ret); if (err) { grub_free (ret); return NULL; } ret[data->size] = '\0'; return ret; }
/* Duplicate a device path. */ static grub_efi_device_path_t * duplicate_device_path (const grub_efi_device_path_t *dp) { grub_efi_device_path_t *p; grub_size_t total_size = 0; for (p = (grub_efi_device_path_t *) dp; ; p = GRUB_EFI_NEXT_DEVICE_PATH (p)) { total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p); if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p)) break; } p = grub_malloc (total_size); if (! p) return 0; grub_memcpy (p, dp, total_size); return p; }
static char * grub_ext2_read_symlink (grub_fshelp_node_t node) { char *symlink; struct grub_fshelp_node *diro = node; if (! diro->inode_read) { grub_ext2_read_inode (diro->data, diro->ino, &diro->inode); if (grub_errno) return 0; } symlink = grub_malloc (grub_le_to_cpu32 (diro->inode.size) + 1); if (! symlink) return 0; /* If the filesize of the symlink is bigger than 60 the symlink is stored in a separate block, otherwise it is stored in the inode. */ if (grub_le_to_cpu32 (diro->inode.size) <= 60) grub_strncpy (symlink, diro->inode.symlink, grub_le_to_cpu32 (diro->inode.size)); else { grub_ext2_read_file (diro, 0, 0, grub_le_to_cpu32 (diro->inode.size), symlink); if (grub_errno) { grub_free (symlink); return 0; } } symlink[grub_le_to_cpu32 (diro->inode.size)] = '\0'; return symlink; }
static int grub_affs_iterate_dir (grub_fshelp_node_t dir, int NESTED_FUNC_ATTR (*hook) (const char *filename, enum grub_fshelp_filetype filetype, grub_fshelp_node_t node)) { int i; struct grub_affs_file file; struct grub_fshelp_node *node = 0; struct grub_affs_data *data = dir->data; grub_uint32_t *hashtable; auto int NESTED_FUNC_ATTR grub_affs_create_node (const char *name, int block, int size, int type); int NESTED_FUNC_ATTR grub_affs_create_node (const char *name, int block, int size, int type) { node = grub_malloc (sizeof (*node)); if (!node) { grub_free (hashtable); return 1; } node->data = data; node->size = size; node->block = block; node->parent = grub_be_to_cpu32 (file.parent); if (hook (name, type, node)) { grub_free (hashtable); return 1; } return 0; }
grub_device_t grub_device_open (const char *name) { grub_device_t dev = 0; if (! name) { name = grub_env_get ("root"); if (name == NULL || *name == '\0') { grub_error (GRUB_ERR_BAD_DEVICE, N_("variable `%s' isn't set"), "root"); goto fail; } } dev = grub_malloc (sizeof (*dev)); if (! dev) goto fail; dev->net = NULL; /* Try to open a disk. */ dev->disk = grub_disk_open (name); if (dev->disk) return dev; if (grub_net_open && grub_errno == GRUB_ERR_UNKNOWN_DEVICE) { grub_errno = GRUB_ERR_NONE; dev->net = grub_net_open (name); } if (dev->net) return dev; fail: grub_free (dev); return 0; }
static struct grub_font_glyph * ascii_glyph_lookup (grub_uint32_t code) { #if HAVE_FONT_SOURCE static int ascii_failback_initialized = 0; if (code >= 0x80) return NULL; if (ascii_failback_initialized == 0) { int current; for (current = 0; current < 0x80; current++) { ascii_font_glyph[current] = grub_malloc (sizeof (struct grub_font_glyph) + ASCII_BITMAP_SIZE); ascii_font_glyph[current]->width = 8; ascii_font_glyph[current]->height = 16; ascii_font_glyph[current]->offset_x = 0; ascii_font_glyph[current]->offset_y = -2; ascii_font_glyph[current]->device_width = 8; ascii_font_glyph[current]->font = NULL; grub_memcpy (ascii_font_glyph[current]->bitmap, &ascii_bitmaps[current * ASCII_BITMAP_SIZE], ASCII_BITMAP_SIZE); } ascii_failback_initialized = 1; } return ascii_font_glyph[code]; #else (void) code; return NULL; #endif }
grub_device_t grub_device_open (const char *name) { grub_disk_t disk = 0; grub_device_t dev = 0; if (! name) { name = grub_env_get ("root"); if (*name == '\0') { grub_error (GRUB_ERR_BAD_DEVICE, "no device is set"); goto fail; } } dev = grub_malloc (sizeof (*dev)); if (! dev) goto fail; /* Try to open a disk. */ disk = grub_disk_open (name); if (! disk) goto fail; dev->disk = disk; dev->net = 0; /* FIXME */ return dev; fail: if (disk) grub_disk_close (disk); grub_free (dev); return 0; }
static char* wildcard_escape (const char *s) { int i; int len; char ch; char *p; len = grub_strlen (s); p = grub_malloc (len * 2 + 1); if (! p) return NULL; i = 0; while ((ch = *s++)) { if (ch == '*' || ch == '\\' || ch == '?') p[i++] = '\\'; p[i++] = ch; } p[i] = '\0'; return p; }
static const char * grub_gettext_gettranslation_from_position (int position) { int offsettranslation; int internal_position; grub_uint32_t length, offset; char *translation; offsettranslation = grub_gettext_get_info (GETTEXT_OFFSET_TRANSLATION); internal_position = offsettranslation + position * 8; grub_gettext_pread (fd_mo, (char *) &length, 4, internal_position); length = grub_cpu_to_le32 (length); grub_gettext_pread (fd_mo, (char *) &offset, 4, internal_position + 4); offset = grub_cpu_to_le32 (offset); translation = grub_malloc (length + 1); grub_gettext_getstring_from_offset (offset, length, translation); return translation; }
/* Find the optimal number of pages for the memory map. Is it better to move this code to efi/mm.c? */ static grub_efi_uintn_t find_efi_mmap_size (void) { static grub_efi_uintn_t mmap_size = 0; if (mmap_size != 0) return mmap_size; mmap_size = (1 << 12); while (1) { int ret; grub_efi_memory_descriptor_t *mmap; grub_efi_uintn_t desc_size; mmap = grub_malloc (mmap_size); if (! mmap) return 0; ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); grub_free (mmap); if (ret < 0) grub_fatal ("cannot get memory map"); else if (ret > 0) break; mmap_size += (1 << 12); } /* Increase the size a bit for safety, because GRUB allocates more on later, and EFI itself may allocate more. */ mmap_size += (1 << 12); mmap_size = page_align (mmap_size); return mmap_size; }
static grub_envblk_t read_envblk_file (grub_file_t file) { grub_off_t offset = 0; char *buf; grub_size_t size = grub_file_size (file); grub_envblk_t envblk; buf = grub_malloc (size); if (! buf) return 0; while (size > 0) { grub_ssize_t ret; ret = grub_file_read (file, buf + offset, size); if (ret <= 0) { grub_free (buf); return 0; } size -= ret; offset += ret; } envblk = grub_envblk_open (buf, offset); if (! envblk) { grub_free (buf); grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); return 0; } return envblk; }
/* Try to load an icon for the specified CLASS_NAME in the directory DIR. Returns 0 if the icon could not be loaded, or returns a pointer to a new bitmap if it was successful. */ static struct grub_video_bitmap * try_loading_icon (grub_gfxmenu_icon_manager_t mgr, const char *dir, const char *class_name) { char *path, *ptr; path = grub_malloc (grub_strlen (dir) + grub_strlen (class_name) + grub_strlen (icon_extension) + 3); if (! path) return 0; ptr = grub_stpcpy (path, dir); if (path == ptr || ptr[-1] != '/') *ptr++ = '/'; ptr = grub_stpcpy (ptr, class_name); ptr = grub_stpcpy (ptr, icon_extension); *ptr = '\0'; struct grub_video_bitmap *raw_bitmap; grub_video_bitmap_load (&raw_bitmap, path); grub_free (path); grub_errno = GRUB_ERR_NONE; /* Critical to clear the error!! */ if (! raw_bitmap) return 0; struct grub_video_bitmap *scaled_bitmap; grub_video_bitmap_create_scaled (&scaled_bitmap, mgr->icon_width, mgr->icon_height, raw_bitmap, GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); grub_video_bitmap_destroy (raw_bitmap); if (! scaled_bitmap) return 0; return scaled_bitmap; }
grub_err_t grub_gpt_part_label (grub_device_t device, char **label) { struct grub_gpt_partentry entry; const grub_size_t name_len = ARRAY_SIZE (entry.name); const grub_size_t label_len = name_len * GRUB_MAX_UTF8_PER_UTF16 + 1; grub_size_t i; grub_uint8_t *end; if (grub_gpt_device_partentry (device, &entry)) return grub_errno; *label = grub_malloc (label_len); if (!*label) return grub_errno; for (i = 0; i < name_len; i++) entry.name[i] = grub_le_to_cpu16 (entry.name[i]); end = grub_utf16_to_utf8 ((grub_uint8_t *) *label, entry.name, name_len); *end = '\0'; return GRUB_ERR_NONE; }
static grub_err_t grub_elf32_load_phdrs (grub_elf_t elf) { grub_ssize_t phdrs_size; phdrs_size = elf->ehdr.ehdr32.e_phnum * elf->ehdr.ehdr32.e_phentsize; grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%lx.\n", (unsigned long long) elf->ehdr.ehdr32.e_phoff, (unsigned long) phdrs_size); elf->phdrs = grub_malloc (phdrs_size); if (! elf->phdrs) return grub_errno; if ((grub_file_seek (elf->file, elf->ehdr.ehdr32.e_phoff) == (grub_off_t) -1) || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size)) { grub_error_push (); return grub_error (GRUB_ERR_READ_ERROR, "cannot read program headers"); } return GRUB_ERR_NONE; }
/* The command to add and remove loopback devices. */ static grub_err_t grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) { struct grub_arg_list *state = state = cmd->state; grub_file_t file; struct grub_loopback *newdev; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); /* Check if `-d' was used. */ if (state[0].set) return delete_loopback (args[0]); if (argc < 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); file = grub_file_open (args[1]); if (! file) return grub_errno; /* First try to replace the old device. */ for (newdev = loopback_list; newdev; newdev = newdev->next) if (grub_strcmp (newdev->devname, args[0]) == 0) break; if (newdev) { char *newname = grub_strdup (args[1]); if (! newname) goto fail; grub_free (newdev->filename); newdev->filename = newname; grub_file_close (newdev->file); newdev->file = file; /* Set has_partitions when `--partitions' was used. */ newdev->has_partitions = state[1].set; return 0; } /* Unable to replace it, make a new entry. */ newdev = grub_malloc (sizeof (struct grub_loopback)); if (! newdev) goto fail; newdev->devname = grub_strdup (args[0]); if (! newdev->devname) { grub_free (newdev); goto fail; } newdev->filename = grub_strdup (args[1]); if (! newdev->filename) { grub_free (newdev->devname); grub_free (newdev); goto fail; } newdev->file = file; /* Set has_partitions when `--partitions' was used. */ newdev->has_partitions = state[1].set; /* Add the new entry to the list. */ newdev->next = loopback_list; loopback_list = newdev; return 0; fail: grub_file_close (file); return grub_errno; }
static struct grub_affs_data * grub_affs_mount (grub_disk_t disk) { struct grub_affs_data *data; grub_uint32_t *rootblock = 0; struct grub_affs_rblock *rblock; int checksum = 0; int checksumr = 0; int blocksize = 0; data = grub_malloc (sizeof (struct grub_affs_data)); if (!data) return 0; /* Read the bootblock. */ grub_disk_read (disk, 0, 0, sizeof (struct grub_affs_bblock), &data->bblock); if (grub_errno) goto fail; /* Make sure this is an affs filesystem. */ if (grub_strncmp ((char *) (data->bblock.type), "DOS", 3)) { grub_error (GRUB_ERR_BAD_FS, "not an AFFS filesystem"); goto fail; } /* Test if the filesystem is a OFS filesystem. */ if (! (data->bblock.flags & GRUB_AFFS_FLAG_FFS)) { grub_error (GRUB_ERR_BAD_FS, "OFS not yet supported"); goto fail; } /* Read the bootblock. */ grub_disk_read (disk, 0, 0, sizeof (struct grub_affs_bblock), &data->bblock); if (grub_errno) goto fail; /* No sane person uses more than 8KB for a block. At least I hope for that person because in that case this won't work. */ rootblock = grub_malloc (GRUB_DISK_SECTOR_SIZE * 16); if (!rootblock) goto fail; rblock = (struct grub_affs_rblock *) rootblock; /* Read the rootblock. */ grub_disk_read (disk, grub_be_to_cpu32 (data->bblock.rootblock), 0, GRUB_DISK_SECTOR_SIZE * 16, rootblock); if (grub_errno) goto fail; /* The filesystem blocksize is not stored anywhere in the filesystem itself. One way to determine it is reading blocks for the rootblock until the checksum is correct. */ checksumr = grub_be_to_cpu32 (rblock->checksum); rblock->checksum = 0; for (blocksize = 0; blocksize < 8; blocksize++) { grub_uint32_t *currblock = rootblock + GRUB_DISK_SECTOR_SIZE * blocksize; unsigned int i; for (i = 0; i < GRUB_DISK_SECTOR_SIZE / sizeof (*currblock); i++) checksum += grub_be_to_cpu32 (currblock[i]); if (checksumr == -checksum) break; } if (-checksum != checksumr) { grub_error (GRUB_ERR_BAD_FS, "AFFS blocksize couldn't be determined"); goto fail; } blocksize++; data->blocksize = blocksize; data->disk = disk; data->htsize = grub_be_to_cpu32 (rblock->htsize); data->diropen.data = data; data->diropen.block = grub_be_to_cpu32 (data->bblock.rootblock); grub_free (rootblock); return data; fail: if (grub_errno == GRUB_ERR_OUT_OF_RANGE) grub_error (GRUB_ERR_BAD_FS, "not an AFFS filesystem"); grub_free (data); grub_free (rootblock); return 0; }
} node->data = data; node->size = size; node->block = block; node->parent = grub_be_to_cpu32 (file.parent); if (hook (name, type, node)) { grub_free (hashtable); return 1; } return 0; } hashtable = grub_malloc (data->htsize * sizeof (*hashtable)); if (!hashtable) return 1; grub_disk_read (data->disk, dir->block, GRUB_AFFS_HASHTABLE_OFFSET, data->htsize * sizeof (*hashtable), (char *) hashtable); if (grub_errno) goto fail; /* Create the directory entries for `.' and `..'. */ if (grub_affs_create_node (".", dir->block, dir->size, GRUB_FSHELP_DIR)) return 1; if (grub_affs_create_node ("..", dir->parent ? dir->parent : dir->block, dir->size, GRUB_FSHELP_DIR)) return 1;
/* Mount the filesystem on the disk DISK. */ static struct grub_hfs_data * grub_hfs_mount (grub_disk_t disk) { struct grub_hfs_data *data; struct grub_hfs_catalog_key key; struct grub_hfs_dirrec dir; int first_block; struct { struct grub_hfs_node node; struct grub_hfs_treeheader head; } treehead; data = grub_malloc (sizeof (struct grub_hfs_data)); if (!data) return 0; /* Read the superblock. */ if (grub_disk_read (disk, GRUB_HFS_SBLOCK, 0, sizeof (struct grub_hfs_sblock), &data->sblock)) goto fail; /* Check if this is a HFS filesystem. */ if (grub_be_to_cpu16 (data->sblock.magic) != GRUB_HFS_MAGIC) { grub_error (GRUB_ERR_BAD_FS, "not an HFS filesystem"); goto fail; } /* Check if this is an embedded HFS+ filesystem. */ if (grub_be_to_cpu16 (data->sblock.embed_sig) == GRUB_HFS_EMBED_HFSPLUS_SIG) { grub_error (GRUB_ERR_BAD_FS, "embedded HFS+ filesystem"); goto fail; } data->blksz = grub_be_to_cpu32 (data->sblock.blksz); data->disk = disk; /* Lookup the root node of the extent overflow tree. */ first_block = ((grub_be_to_cpu16 (data->sblock.extent_recs[0].first_block) * GRUB_HFS_BLKS) + grub_be_to_cpu16 (data->sblock.first_block)); if (grub_disk_read (data->disk, first_block, 0, sizeof (treehead), &treehead)) goto fail; data->ext_root = grub_be_to_cpu32 (treehead.head.root_node); data->ext_size = grub_be_to_cpu16 (treehead.head.node_size); /* Lookup the root node of the catalog tree. */ first_block = ((grub_be_to_cpu16 (data->sblock.catalog_recs[0].first_block) * GRUB_HFS_BLKS) + grub_be_to_cpu16 (data->sblock.first_block)); if (grub_disk_read (data->disk, first_block, 0, sizeof (treehead), &treehead)) goto fail; data->cat_root = grub_be_to_cpu32 (treehead.head.root_node); data->cat_size = grub_be_to_cpu16 (treehead.head.node_size); /* Lookup the root directory node in the catalog tree using the volume name. */ key.parent_dir = grub_cpu_to_be32 (1); key.strlen = data->sblock.volname[0]; grub_strcpy ((char *) key.str, (char *) (data->sblock.volname + 1)); if (grub_hfs_find_node (data, (char *) &key, data->cat_root, 0, (char *) &dir, sizeof (dir)) == 0) { grub_error (GRUB_ERR_BAD_FS, "cannot find the HFS root directory"); goto fail; } if (grub_errno) goto fail; data->rootdir = grub_be_to_cpu32 (dir.dirid); return data; fail: grub_free (data); if (grub_errno == GRUB_ERR_OUT_OF_RANGE) grub_error (GRUB_ERR_BAD_FS, "not a HFS filesystem"); return 0; }
grub_err_t grub_mmap_iterate (int (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t, void *), void *closure) { /* This function resolves overlapping regions and sorts the memory map. It uses scanline (sweeping) algorithm. */ /* If same page is used by multiple types it's resolved according to priority: 1 - free memory 2 - memory usable by firmware-aware code 3 - unusable memory 4 - a range deliberately empty */ int priority[GRUB_MACHINE_MEMORY_MAX_TYPE + 2] = { #ifdef GRUB_MACHINE_MEMORY_AVAILABLE [GRUB_MACHINE_MEMORY_AVAILABLE] = 1, #endif #if defined (GRUB_MACHINE_MEMORY_RESERVED) && GRUB_MACHINE_MEMORY_RESERVED != GRUB_MACHINE_MEMORY_HOLE [GRUB_MACHINE_MEMORY_RESERVED] = 3, #endif #ifdef GRUB_MACHINE_MEMORY_ACPI [GRUB_MACHINE_MEMORY_ACPI] = 2, #endif #ifdef GRUB_MACHINE_MEMORY_CODE [GRUB_MACHINE_MEMORY_CODE] = 3, #endif #ifdef GRUB_MACHINE_MEMORY_NVS [GRUB_MACHINE_MEMORY_NVS] = 3, #endif [GRUB_MACHINE_MEMORY_HOLE] = 4, }; int i, k, done; struct grub_mmap_scan *scanline_events; struct grub_mmap_scan t; /* Previous scanline event. */ grub_uint64_t lastaddr; int lasttype; /* Current scanline event. */ int curtype; /* How many regions of given type overlap at current location? */ int present[GRUB_MACHINE_MEMORY_MAX_TYPE + 2]; /* Number of mmap chunks. */ int mmap_num; struct grub_mmap_iterate_closure c; #ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE struct grub_mmap_region *cur; #endif mmap_num = 0; #ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE for (cur = grub_mmap_overlays; cur; cur = cur->next) mmap_num++; #endif grub_machine_mmap_iterate (count_hook, &mmap_num); /* Initialize variables. */ grub_memset (present, 0, sizeof (present)); scanline_events = (struct grub_mmap_scan *) grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num); if (! scanline_events) { return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate space for new memory map"); } i = 0; #ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE /* Register scanline events. */ for (cur = grub_mmap_overlays; cur; cur = cur->next) { scanline_events[i].pos = cur->start; scanline_events[i].type = 0; if (cur->type == GRUB_MACHINE_MEMORY_HOLE || (cur->type >= 0 && cur->type <= GRUB_MACHINE_MEMORY_MAX_TYPE && priority[cur->type])) scanline_events[i].memtype = cur->type; else scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED; i++; scanline_events[i].pos = cur->end; scanline_events[i].type = 1; scanline_events[i].memtype = scanline_events[i - 1].memtype; i++; } #endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */ c.i = i; c.scanline_events = scanline_events; c.priority = priority; grub_machine_mmap_iterate (fill_hook, &c); /* Primitive bubble sort. It has complexity O(n^2) but since we're unlikely to have more than 100 chunks it's probably one of the fastest for one purpose. */ done = 1; while (done) { done = 0; for (i = 0; i < 2 * mmap_num - 1; i++) if (scanline_events[i + 1].pos < scanline_events[i].pos || (scanline_events[i + 1].pos == scanline_events[i].pos && scanline_events[i + 1].type == 0 && scanline_events[i].type == 1)) { t = scanline_events[i + 1]; scanline_events[i + 1] = scanline_events[i]; scanline_events[i] = t; done = 1; } } lastaddr = scanline_events[0].pos; lasttype = scanline_events[0].memtype; for (i = 0; i < 2 * mmap_num; i++) { /* Process event. */ if (scanline_events[i].type) present[scanline_events[i].memtype]--; else present[scanline_events[i].memtype]++; /* Determine current region type. */ curtype = -1; for (k = 0; k <= GRUB_MACHINE_MEMORY_MAX_TYPE + 1; k++) if (present[k] && (curtype == -1 || priority[k] > priority[curtype])) curtype = k; /* Announce region to the hook if necessary. */ if ((curtype == -1 || curtype != lasttype) && lastaddr != scanline_events[i].pos && lasttype != -1 && lasttype != GRUB_MACHINE_MEMORY_HOLE && hook (lastaddr, scanline_events[i].pos - lastaddr, lasttype, closure)) { grub_free (scanline_events); return GRUB_ERR_NONE; } /* Update last values if necessary. */ if (curtype == -1 || curtype != lasttype) { lasttype = curtype; lastaddr = scanline_events[i].pos; } } grub_free (scanline_events); return GRUB_ERR_NONE; }
grub_command_t grub_register_command (const char *name, grub_err_t (*func) (struct grub_arg_list *state, int argc, char **args), unsigned flags, const char *summary, const char *description, const struct grub_arg_option *options) { grub_command_t cmd, *p; cmd = (grub_command_t) grub_malloc (sizeof (*cmd)); if (! cmd) return 0; cmd->name = grub_strdup (name); if (! cmd->name) { grub_free (cmd); return 0; } cmd->func = func; cmd->flags = flags; cmd->summary = summary; cmd->description = description; cmd->options = options; cmd->module_name = 0; /* Keep the list sorted for simplicity. */ p = &grub_command_list; while (*p) { if (grub_strcmp ((*p)->name, name) >= 0) break; p = &((*p)->next); } if (*p && grub_strcmp ((*p)->name, name) == 0) { grub_command_t q; q = *p; if (q->flags & GRUB_COMMAND_FLAG_NOT_LOADED) { q->func = cmd->func; q->flags = cmd->flags; q->summary = cmd->summary; q->description = cmd->description; q->options = cmd->options; grub_free (cmd->name); grub_free (cmd->module_name); grub_free (cmd); cmd = q; } else { grub_free (cmd->name); grub_free (cmd); cmd = 0; } } else { cmd->next = *p; *p = cmd; } return cmd; }
/* Creates new bitmap, saves created bitmap on success to *bitmap. */ grub_err_t grub_video_bitmap_create (struct grub_video_bitmap **bitmap, unsigned int width, unsigned int height, enum grub_video_blit_format blit_format) { struct grub_video_mode_info *mode_info; unsigned int size; if (!bitmap) return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); *bitmap = 0; if (width == 0 || height == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); *bitmap = (struct grub_video_bitmap *)grub_malloc (sizeof (struct grub_video_bitmap)); if (! *bitmap) return grub_errno; mode_info = &((*bitmap)->mode_info); /* Populate mode_info. */ mode_info->width = width; mode_info->height = height; mode_info->blit_format = blit_format; switch (blit_format) { case GRUB_VIDEO_BLIT_FORMAT_RGBA_8888: mode_info->mode_type = GRUB_VIDEO_MODE_TYPE_RGB | GRUB_VIDEO_MODE_TYPE_ALPHA; mode_info->bpp = 32; mode_info->bytes_per_pixel = 4; mode_info->number_of_colors = 256; mode_info->red_mask_size = 8; mode_info->red_field_pos = 0; mode_info->green_mask_size = 8; mode_info->green_field_pos = 8; mode_info->blue_mask_size = 8; mode_info->blue_field_pos = 16; mode_info->reserved_mask_size = 8; mode_info->reserved_field_pos = 24; break; case GRUB_VIDEO_BLIT_FORMAT_RGB_888: mode_info->mode_type = GRUB_VIDEO_MODE_TYPE_RGB; mode_info->bpp = 24; mode_info->bytes_per_pixel = 3; mode_info->number_of_colors = 256; mode_info->red_mask_size = 8; mode_info->red_field_pos = 0; mode_info->green_mask_size = 8; mode_info->green_field_pos = 8; mode_info->blue_mask_size = 8; mode_info->blue_field_pos = 16; mode_info->reserved_mask_size = 0; mode_info->reserved_field_pos = 0; break; case GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR: mode_info->mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; mode_info->bpp = 8; mode_info->bytes_per_pixel = 1; mode_info->number_of_colors = 256; mode_info->red_mask_size = 0; mode_info->red_field_pos = 0; mode_info->green_mask_size = 0; mode_info->green_field_pos = 0; mode_info->blue_mask_size = 0; mode_info->blue_field_pos = 0; mode_info->reserved_mask_size = 0; mode_info->reserved_field_pos = 0; break; default: grub_free (*bitmap); *bitmap = 0; return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported bitmap format"); } mode_info->pitch = width * mode_info->bytes_per_pixel; /* Calculate size needed for the data. */ size = (width * mode_info->bytes_per_pixel) * height; (*bitmap)->data = grub_zalloc (size); if (! (*bitmap)->data) { grub_free (*bitmap); *bitmap = 0; return grub_errno; } return GRUB_ERR_NONE; }
static grub_err_t grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, char *buf, grub_disk_addr_t sector, int size) { int i, q, pos; int err[2], nerr; char *pbuf = 0, *qbuf = 0; size <<= GRUB_DISK_SECTOR_BITS; pbuf = grub_malloc (size); if (!pbuf) goto quit; qbuf = grub_malloc (size); if (!qbuf) goto quit; q = p + 1; if (q == (int) array->total_devs) q = 0; grub_memset (pbuf, 0, size); grub_memset (qbuf, 0, size); pos = q + 1; if (pos == (int) array->total_devs) pos = 0; nerr = 1; for (i = 0; i < (int) array->total_devs - 2; i++) { if (pos == disknr) err[0] = i; else { if ((array->device[pos]) && (! grub_disk_read (array->device[pos], sector, 0, size, buf))) { grub_raid_block_xor (pbuf, buf, size); grub_raid_block_mul (raid6_table2[i][i], buf, size); grub_raid_block_xor (qbuf, buf, size); } else { if (nerr >= 2) goto quit; err[nerr++] = i; grub_errno = GRUB_ERR_NONE; } } pos++; if (pos == (int) array->total_devs) pos = 0; } if (nerr == 1) { if ((array->device[p]) && (! grub_disk_read (array->device[p], sector, 0, size, buf))) { grub_raid_block_xor (buf, pbuf, size); goto quit; } if (! array->device[q]) { grub_error (GRUB_ERR_READ_ERROR, "Not enough disk to restore"); goto quit; } grub_errno = GRUB_ERR_NONE; if (grub_disk_read (array->device[q], sector, 0, size, buf)) goto quit; grub_raid_block_xor (buf, qbuf, size); grub_raid_block_mul (raid6_table2[255 - err[0]][255 - err[0]], buf, size); } else { grub_uint8_t c; if ((! array->device[p]) || (! array->device[q])) { grub_error (GRUB_ERR_READ_ERROR, "Not enough disk to restore"); goto quit; } if (grub_disk_read (array->device[p], sector, 0, size, buf)) goto quit; grub_raid_block_xor (pbuf, buf, size); if (grub_disk_read (array->device[q], sector, 0, size, buf)) goto quit; grub_raid_block_xor (qbuf, buf, size); c = raid6_table2[err[1]][err[0]]; grub_raid_block_mul (c, qbuf, size); c = raid6_table1[raid6_table2[err[1]][err[1]]][c]; grub_raid_block_mul (c, pbuf, size); grub_raid_block_xor (pbuf, qbuf, size); grub_memcpy (buf, pbuf, size); } quit: grub_free (pbuf); grub_free (qbuf); return grub_errno; }
static int huft_build (unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ unsigned n, /* number of codes (assumed <= N_MAX) */ unsigned s, /* number of simple-valued codes (0..s-1) */ ush * d, /* list of base values for non-simple codes */ ush * e, /* list of extra bits for non-simple codes */ struct huft **t, /* result: starting table */ int *m) /* maximum lookup bits, returns actual */ { unsigned a; /* counter for codes of length k */ unsigned c[BMAX + 1]; /* bit length count table */ unsigned f; /* i repeats in table every f entries */ int g; /* maximum code length */ int h; /* table level */ register unsigned i; /* counter, current code */ register unsigned j; /* counter */ register int k; /* number of bits in current code */ int l; /* bits per table (returned in m) */ register unsigned *p; /* pointer into c[], b[], or v[] */ register struct huft *q; /* points to current table */ struct huft r; /* table entry for structure assignment */ struct huft *u[BMAX]; /* table stack */ unsigned v[N_MAX]; /* values in order of bit length */ register int w; /* bits before this table == (l * h) */ unsigned x[BMAX + 1]; /* bit offsets, then code stack */ unsigned *xp; /* pointer into x */ int y; /* number of dummy codes added */ unsigned z; /* number of entries in current table */ /* Generate counts for each bit length */ grub_memset ((char *) c, 0, sizeof (c)); p = b; i = n; do { c[*p]++; /* assume all entries <= BMAX */ p++; /* Can't combine with above line (Solaris bug) */ } while (--i); if (c[0] == n) /* null input--all zero length codes */ { *t = (struct huft *) NULL; *m = 0; return 0; } /* Find minimum and maximum length, bound *m by those */ l = *m; for (j = 1; j <= BMAX; j++) if (c[j]) break; k = j; /* minimum code length */ if ((unsigned) l < j) l = j; for (i = BMAX; i; i--) if (c[i]) break; g = i; /* maximum code length */ if ((unsigned) l > i) l = i; *m = l; /* Adjust last length count to fill out codes, if needed */ for (y = 1 << j; j < i; j++, y <<= 1) if ((y -= c[j]) < 0) return 2; /* bad input: more codes than bits */ if ((y -= c[i]) < 0) return 2; c[i] += y; /* Generate starting offsets into the value table for each length */ x[1] = j = 0; p = c + 1; xp = x + 2; while (--i) { /* note that i == g from above */ *xp++ = (j += *p++); } /* Make a table of values in order of bit lengths */ p = b; i = 0; do { if ((j = *p++) != 0) v[x[j]++] = i; } while (++i < n); /* Generate the Huffman codes and for each, make the table entries */ x[0] = i = 0; /* first Huffman code is zero */ p = v; /* grab values in bit order */ h = -1; /* no tables yet--level -1 */ w = -l; /* bits decoded == (l * h) */ u[0] = (struct huft *) NULL; /* just to keep compilers happy */ q = (struct huft *) NULL; /* ditto */ z = 0; /* ditto */ /* go through the bit lengths (k already is bits in shortest code) */ for (; k <= g; k++) { a = c[k]; while (a--) { /* here i is the Huffman code of length k bits for value *p */ /* make tables up to required level */ while (k > w + l) { h++; w += l; /* previous table always l bits */ /* compute minimum size table less than or equal to l bits */ z = (z = (unsigned) (g - w)) > (unsigned) l ? (unsigned) l : z; /* upper limit on table size */ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ { /* too few codes for k-w bit table */ f -= a + 1; /* deduct codes from patterns left */ xp = c + k; while (++j < z) /* try smaller tables up to z bits */ { if ((f <<= 1) <= *++xp) break; /* enough codes to use up j bits */ f -= *xp; /* else deduct codes from patterns */ } } z = 1 << j; /* table entries for j-bit table */ /* allocate and link in new table */ q = (struct huft *) grub_malloc ((z + 1) * sizeof (struct huft)); if (! q) { if (h) huft_free (u[0]); return 3; } *t = q + 1; /* link to list for huft_free() */ *(t = &(q->v.t)) = (struct huft *) NULL; u[h] = ++q; /* table starts after link */ /* connect to last table, if there is one */ if (h) { x[h] = i; /* save pattern for backing up */ r.b = (uch) l; /* bits to dump before this table */ r.e = (uch) (16 + j); /* bits in this table */ r.v.t = q; /* pointer to this table */ j = i >> (w - l); /* (get around Turbo C bug) */ u[h - 1][j] = r; /* connect to last table */ } } /* set up table entry in r */ r.b = (uch) (k - w); if (p >= v + n) r.e = 99; /* out of values--invalid code */ else if (*p < s) { r.e = (uch) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ r.v.n = (ush) (*p); /* simple code is just the value */ p++; /* one compiler does not like *p++ */ } else { r.e = (uch) e[*p - s]; /* non-simple--look up in lists */ r.v.n = d[*p++ - s]; } /* fill code-like entries with r */ f = 1 << (k - w); for (j = i >> w; j < z; j += f) q[j] = r; /* backwards increment the k-bit code i */ for (j = 1 << (k - 1); i & j; j >>= 1) i ^= j; i ^= j; /* backup over finished tables */ while ((i & ((1 << w) - 1)) != x[h]) { h--; /* don't need to update q */ w -= l; } } } /* Return true (1) if we were given an incomplete table */ return y != 0 && g != 1; }
static grub_err_t grub_cpio_find_file (struct grub_cpio_data *data, char **name, grub_uint32_t * ofs) { #ifndef MODE_USTAR struct head hd; if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd)) return grub_errno; if (hd.magic != MAGIC_BCPIO) return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive"); data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2; if (hd.namesize & 1) hd.namesize++; if ((*name = grub_malloc (hd.namesize)) == NULL) return grub_errno; if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd), hd.namesize, *name)) { grub_free (*name); return grub_errno; } if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1 && ! grub_memcmp(*name, "TRAILER!!!", 11)) { *ofs = 0; return GRUB_ERR_NONE; } data->dofs = data->hofs + sizeof (hd) + hd.namesize; *ofs = data->dofs + data->size; if (data->size & 1) (*ofs)++; #else struct head hd; if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd)) return grub_errno; if (!hd.name[0]) { *ofs = 0; return GRUB_ERR_NONE; } if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1)) return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive"); if ((*name = grub_strdup (hd.name)) == NULL) return grub_errno; data->size = grub_strtoul (hd.size, NULL, 8); data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE; *ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) & ~(GRUB_DISK_SECTOR_SIZE - 1)); #endif return GRUB_ERR_NONE; }
/* Read a line from the file FILE. */ char * grub_file_getline (grub_file_t file) { char c; int pos = 0; int literal = 0; char *cmdline; int max_len = 64; /* Initially locate some space. */ cmdline = grub_malloc (max_len); if (! cmdline) return 0; while (1) { if (grub_file_read (file, &c, 1) != 1) break; /* Skip all carriage returns. */ if (c == '\r') continue; /* Replace tabs with spaces. */ if (c == '\t') c = ' '; /* The previous is a backslash, then... */ if (literal) { /* If it is a newline, replace it with a space and continue. */ if (c == '\n') { c = ' '; /* Go back to overwrite the backslash. */ if (pos > 0) pos--; } literal = 0; } if (c == '\\') literal = 1; if (pos == 0) { if (! grub_isspace (c)) cmdline[pos++] = c; } else { if (pos >= max_len) { char *old_cmdline = cmdline; max_len = max_len * 2; cmdline = grub_realloc (cmdline, max_len); if (! cmdline) { grub_free (old_cmdline); return 0; } } if (c == '\n') break; cmdline[pos++] = c; } } cmdline[pos] = '\0'; /* If the buffer is empty, don't return anything at all. */ if (pos == 0) { grub_free (cmdline); cmdline = 0; } return cmdline; }
static grub_err_t grub_cbfs_find_file (struct grub_archelp_data *data, char **name, grub_int32_t *mtime, grub_uint32_t *mode) { grub_size_t offset; for (;; data->dofs = data->hofs + offset, data->next_hofs = ALIGN_UP (data->dofs + data->size, data->cbfs_align)) { struct cbfs_file hd; grub_size_t namesize; data->hofs = data->next_hofs; if (data->hofs >= data->cbfs_end) { *mode = GRUB_ARCHELP_ATTR_END; return GRUB_ERR_NONE; } if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd)) return grub_errno; if (grub_memcmp (hd.magic, CBFS_FILE_MAGIC, sizeof (hd.magic)) != 0) { *mode = GRUB_ARCHELP_ATTR_END; return GRUB_ERR_NONE; } data->size = grub_be_to_cpu32 (hd.len); (void) mtime; offset = grub_be_to_cpu32 (hd.offset); *mode = GRUB_ARCHELP_ATTR_FILE | GRUB_ARCHELP_ATTR_NOTIME; namesize = offset; if (namesize >= sizeof (hd)) namesize -= sizeof (hd); if (namesize == 0) continue; *name = grub_malloc (namesize + 1); if (*name == NULL) return grub_errno; if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd), namesize, *name)) { grub_free (*name); return grub_errno; } if ((*name)[0] == '\0') { grub_free (*name); *name = NULL; continue; } (*name)[namesize] = 0; data->dofs = data->hofs + offset; data->next_hofs = ALIGN_UP (data->dofs + data->size, data->cbfs_align); return GRUB_ERR_NONE; } }