static grub_err_t grub_cpio_find_file (struct grub_archelp_data *data, char **name, grub_int32_t *mtime, grub_uint32_t *mode) { struct head hd; int reread = 0, have_longname = 0, have_longlink = 0; data->hofs = data->next_hofs; for (reread = 0; reread < 3; reread++) { if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd)) return grub_errno; if (!hd.name[0] && !hd.prefix[0]) { *mode = GRUB_ARCHELP_ATTR_END; return GRUB_ERR_NONE; } if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1)) return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive"); if (hd.typeflag == 'L') { grub_err_t err; grub_size_t namesize = read_number (hd.size, sizeof (hd.size)); *name = grub_malloc (namesize + 1); if (*name == NULL) return grub_errno; err = grub_disk_read (data->disk, 0, data->hofs + GRUB_DISK_SECTOR_SIZE, namesize, *name); (*name)[namesize] = 0; if (err) return err; data->hofs += GRUB_DISK_SECTOR_SIZE + ((namesize + GRUB_DISK_SECTOR_SIZE - 1) & ~(GRUB_DISK_SECTOR_SIZE - 1)); have_longname = 1; continue; } if (hd.typeflag == 'K') { grub_err_t err; grub_size_t linksize = read_number (hd.size, sizeof (hd.size)); if (data->linkname_alloc < linksize + 1) { char *n; n = grub_malloc (2 * (linksize + 1)); if (!n) return grub_errno; grub_free (data->linkname); data->linkname = n; data->linkname_alloc = 2 * (linksize + 1); } err = grub_disk_read (data->disk, 0, data->hofs + GRUB_DISK_SECTOR_SIZE, linksize, data->linkname); if (err) return err; data->linkname[linksize] = 0; data->hofs += GRUB_DISK_SECTOR_SIZE + ((linksize + GRUB_DISK_SECTOR_SIZE - 1) & ~(GRUB_DISK_SECTOR_SIZE - 1)); have_longlink = 1; continue; } if (!have_longname) { grub_size_t extra_size = 0; while (extra_size < sizeof (hd.prefix) && hd.prefix[extra_size]) extra_size++; *name = grub_malloc (sizeof (hd.name) + extra_size + 2); if (*name == NULL) return grub_errno; if (hd.prefix[0]) { grub_memcpy (*name, hd.prefix, extra_size); (*name)[extra_size++] = '/'; } grub_memcpy (*name + extra_size, hd.name, sizeof (hd.name)); (*name)[extra_size + sizeof (hd.name)] = 0; } data->size = read_number (hd.size, sizeof (hd.size)); data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE; data->next_hofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) & ~(GRUB_DISK_SECTOR_SIZE - 1)); if (mtime) *mtime = read_number (hd.mtime, sizeof (hd.mtime)); if (mode) { *mode = read_number (hd.mode, sizeof (hd.mode)); switch (hd.typeflag) { /* Hardlink. */ case '1': /* Symlink. */ case '2': *mode |= GRUB_ARCHELP_ATTR_LNK; break; case '0': *mode |= GRUB_ARCHELP_ATTR_FILE; break; case '5': *mode |= GRUB_ARCHELP_ATTR_DIR; break; } } if (!have_longlink) { if (data->linkname_alloc < 101) { char *n; n = grub_malloc (101); if (!n) return grub_errno; grub_free (data->linkname); data->linkname = n; data->linkname_alloc = 101; } grub_memcpy (data->linkname, hd.linkname, sizeof (hd.linkname)); data->linkname[100] = 0; } return GRUB_ERR_NONE; } 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; }
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; }
static int grub_ext2_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)) { unsigned int fpos = 0; struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir; if (! diro->inode_read) { grub_ext2_read_inode (diro->data, diro->ino, &diro->inode); if (grub_errno) return 0; } /* Search the file. */ while (fpos < grub_le_to_cpu32 (diro->inode.size)) { struct ext2_dirent dirent; grub_ext2_read_file (diro, 0, fpos, sizeof (struct ext2_dirent), (char *) &dirent); if (grub_errno) return 0; if (dirent.direntlen == 0) return 0; if (dirent.namelen != 0) { char filename[dirent.namelen + 1]; struct grub_fshelp_node *fdiro; enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN; grub_ext2_read_file (diro, 0, fpos + sizeof (struct ext2_dirent), dirent.namelen, filename); if (grub_errno) return 0; fdiro = grub_malloc (sizeof (struct grub_fshelp_node)); if (! fdiro) return 0; fdiro->data = diro->data; fdiro->ino = grub_le_to_cpu32 (dirent.inode); filename[dirent.namelen] = '\0'; if (dirent.filetype != FILETYPE_UNKNOWN) { fdiro->inode_read = 0; if (dirent.filetype == FILETYPE_DIRECTORY) type = GRUB_FSHELP_DIR; else if (dirent.filetype == FILETYPE_SYMLINK) type = GRUB_FSHELP_SYMLINK; else if (dirent.filetype == FILETYPE_REG) type = GRUB_FSHELP_REG; } else { /* The filetype can not be read from the dirent, read the inode to get more information. */ grub_ext2_read_inode (diro->data, grub_le_to_cpu32 (dirent.inode), &fdiro->inode); if (grub_errno) { grub_free (fdiro); return 0; } fdiro->inode_read = 1; if ((grub_le_to_cpu16 (fdiro->inode.mode) & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY) type = GRUB_FSHELP_DIR; else if ((grub_le_to_cpu16 (fdiro->inode.mode) & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK) type = GRUB_FSHELP_SYMLINK; else if ((grub_le_to_cpu16 (fdiro->inode.mode) & FILETYPE_INO_MASK) == FILETYPE_INO_REG) type = GRUB_FSHELP_REG; } if (hook (filename, type, fdiro)) return 1; } fpos += grub_le_to_cpu16 (dirent.direntlen); } return 0; }
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; } }
grub_err_t grub_multiboot_load (grub_file_t file) { char *buffer; grub_ssize_t len; struct multiboot_header *header; grub_err_t err; buffer = grub_malloc (MULTIBOOT_SEARCH); if (!buffer) return grub_errno; len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); if (len < 32) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_OS, "file too small"); } /* Look for the multiboot header in the buffer. The header should be at least 12 bytes and aligned on a 4-byte boundary. */ for (header = (struct multiboot_header *) buffer; ((char *) header <= buffer + len - 12) || (header = 0); header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN)) { if (header->magic == MULTIBOOT_HEADER_MAGIC && !(header->magic + header->flags + header->checksum)) break; } if (header == 0) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); } if (header->flags & UNSUPPORTED_FLAGS) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported flag: 0x%x", header->flags); } if (header->flags & MULTIBOOT_AOUT_KLUDGE) { int offset = ((char *) header - buffer - (header->header_addr - header->load_addr)); int load_size = ((header->load_end_addr == 0) ? file->size - offset : header->load_end_addr - header->load_addr); grub_size_t code_size; if (header->bss_end_addr) code_size = (header->bss_end_addr - header->load_addr); else code_size = load_size; grub_multiboot_payload_dest = header->load_addr; grub_multiboot_pure_size += code_size; /* Allocate a bit more to avoid relocations in most cases. */ grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; grub_multiboot_payload_orig = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); if (! grub_multiboot_payload_orig) { grub_free (buffer); return grub_errno; } if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { grub_free (buffer); return grub_errno; } grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); if (grub_errno) { grub_free (buffer); return grub_errno; } if (header->bss_end_addr) grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, header->bss_end_addr - header->load_addr - load_size); grub_multiboot_payload_eip = header->entry_addr; } else { err = grub_multiboot_load_elf (file, buffer); if (err) { grub_free (buffer); return err; } } if (header->flags & MULTIBOOT_VIDEO_MODE) { switch (header->mode_type) { case 1: err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, 0, 0, 0, 0); break; case 0: err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, header->width, header->height, header->depth, 0); break; default: err = grub_error (GRUB_ERR_BAD_OS, "unsupported graphical mode type %d", header->mode_type); break; } } else err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, 0, 0, 0, 0); return err; }
char * grub_legacy_parse (const char *buf, char **entryname, char **suffix) { const char *ptr; const char *cmdname; unsigned i, cmdnum; char *args[ARRAY_SIZE (legacy_commands[0].argt)]; *suffix = NULL; for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++); if (!*ptr || *ptr == '#') { char *ret; int len = grub_strlen (buf); ret = grub_malloc (len + 2); grub_memcpy (ret, buf, len); if (len && ret[len - 1] == '\n') ret[len] = 0; else { ret[len] = '\n'; ret[len + 1] = 0; } return ret; } cmdname = ptr; for (ptr = buf; *ptr && !grub_isspace (*ptr) && *ptr != '='; ptr++); for (cmdnum = 0; cmdnum < ARRAY_SIZE (legacy_commands); cmdnum++) if (grub_strncmp (legacy_commands[cmdnum].name, cmdname, ptr - cmdname) == 0 && legacy_commands[cmdnum].name[ptr - cmdname] == 0 && (!(*entryname != NULL && (legacy_commands[cmdnum].flags & FLAG_NO_MENUENTRY))) && (!(*entryname == NULL && (legacy_commands[cmdnum].flags & FLAG_MENUENTRY_ONLY)))) break; if (cmdnum == ARRAY_SIZE (legacy_commands)) return grub_xasprintf ("# Unsupported legacy command: %s\n", buf); for (; grub_isspace (*ptr) || *ptr == '='; ptr++); if (legacy_commands[cmdnum].flags & FLAG_TITLE) { const char *ptr2; ptr2 = ptr + grub_strlen (ptr); while (ptr2 > ptr && grub_isspace (*(ptr2 - 1))) ptr2--; *entryname = grub_strndup (ptr, ptr2 - ptr); return NULL; } if (legacy_commands[cmdnum].flags & FLAG_TERMINAL) { int dumb = 0, lines = 24; #ifdef TODO int no_echo = 0, no_edit = 0; #endif int hercules = 0; int console = 0, serial = 0, graphics = 0; /* Big enough for any possible resulting command. */ char outbuf[512] = ""; char *outptr; while (*ptr) { /* "[--timeout=SECS] [--silent]" " [console] [serial] [hercules]"*/ if (grub_memcmp (ptr, "--dumb", sizeof ("--dumb") - 1) == 0) dumb = 1; #ifdef TODO if (grub_memcmp (ptr, "--no-echo", sizeof ("--no-echo") - 1) == 0) no_echo = 1; if (grub_memcmp (ptr, "--no-edit", sizeof ("--no-edit") - 1) == 0) no_edit = 1; #endif if (grub_memcmp (ptr, "--lines=", sizeof ("--lines=") - 1) == 0) { lines = grub_strtoul (ptr + sizeof ("--lines=") - 1, 0, 0); if (grub_errno) { lines = 24; grub_errno = GRUB_ERR_NONE; } } if (grub_memcmp (ptr, "console", sizeof ("console") - 1) == 0) console = 1; if (grub_memcmp (ptr, "serial", sizeof ("serial") - 1) == 0) serial = 1; if (grub_memcmp (ptr, "hercules", sizeof ("hercules") - 1) == 0) hercules = 1; if (grub_memcmp (ptr, "graphics", sizeof ("graphics") - 1) == 0) graphics = 1; while (*ptr && !grub_isspace (*ptr)) ptr++; while (*ptr && grub_isspace (*ptr)) ptr++; } if (!console && !serial && !hercules && !graphics) return grub_strdup ("terminal_input; terminal_output; terminfo\n"); outptr = outbuf; if (graphics) outptr = grub_stpcpy (outptr, "insmod all_video; "); outptr = grub_stpcpy (outptr, "terminal_input "); if (serial) outptr = grub_stpcpy (outptr, "serial "); if (console || hercules || graphics) outptr = grub_stpcpy (outptr, "console "); outptr = grub_stpcpy (outptr, "; terminal_output "); if (serial) outptr = grub_stpcpy (outptr, "serial "); if (console) outptr = grub_stpcpy (outptr, "console "); if (hercules) outptr = grub_stpcpy (outptr, "mda_text "); if (graphics) outptr = grub_stpcpy (outptr, "gfxterm "); outptr = grub_stpcpy (outptr, "; "); *outptr = '\0'; if (serial) { grub_snprintf (outptr, outbuf + sizeof (outbuf) - outptr, "terminfo serial -g 80x%d %s; ", lines, dumb ? "dumb" : "vt100"); outptr += grub_strlen (outptr); } grub_strcpy (outptr, "\n"); return grub_strdup (outbuf); } grub_memset (args, 0, sizeof (args)); { int hold_arg = 0; const char *curarg = NULL; for (i = 0; i < legacy_commands[cmdnum].argc; i++) { grub_size_t curarglen; if (hold_arg) { ptr = curarg; hold_arg = 0; } for (; grub_isspace (*ptr); ptr++); curarg = ptr; if (!*curarg) break; for (; *ptr && !grub_isspace (*ptr); ptr++); if (i != legacy_commands[cmdnum].argc - 1 || (legacy_commands[cmdnum].flags & FLAG_IGNORE_REST)) curarglen = ptr - curarg; else { curarglen = grub_strlen (curarg); while (curarglen > 0 && grub_isspace (curarg[curarglen - 1])) curarglen--; } if (*ptr) ptr++; switch (legacy_commands[cmdnum].argt[i]) { case TYPE_FILE_NO_CONSUME: hold_arg = 1; case TYPE_PARTITION: case TYPE_FILE: args[i] = adjust_file (curarg, curarglen); break; case TYPE_REST_VERBATIM: { char *outptr, *outptr0; int overhead = 3; ptr = curarg; while (*ptr) { for (; *ptr && grub_isspace (*ptr); ptr++); for (; *ptr && !grub_isspace (*ptr); ptr++) if (*ptr == '\'') overhead += 3; if (*ptr) ptr++; overhead += 3; } outptr0 = args[i] = grub_malloc (overhead + (ptr - curarg)); if (!outptr0) return NULL; ptr = curarg; outptr = outptr0; while (*ptr) { for (; *ptr && grub_isspace (*ptr); ptr++); if (outptr != outptr0) *outptr++ = ' '; *outptr++ = '\''; for (; *ptr && !grub_isspace (*ptr); ptr++) { if (*ptr == '\'') { *outptr++ = '\''; *outptr++ = '\\'; *outptr++ = '\''; *outptr++ = '\''; } else *outptr++ = *ptr; } *outptr++ = '\''; if (*ptr) ptr++; } *outptr++ = 0; } break; case TYPE_VERBATIM: args[i] = grub_legacy_escape (curarg, curarglen); break; case TYPE_WITH_CONFIGFILE_OPTION: case TYPE_FORCE_OPTION: case TYPE_NOAPM_OPTION: case TYPE_TYPE_OR_NOMEM_OPTION: case TYPE_OPTION: if (is_option (legacy_commands[cmdnum].argt[i], curarg, curarglen)) { args[i] = grub_strndup (curarg, curarglen); break; } args[i] = grub_strdup (""); hold_arg = 1; break; case TYPE_INT: { const char *brk; int base = 10; brk = curarg; if (brk[0] == '0' && brk[1] == 'x') { base = 16; brk += 2; } else if (brk[0] == '0') base = 8; for (; *brk && brk < curarg + curarglen; brk++) { if (base == 8 && (*brk == '8' || *brk == '9')) break; if (grub_isdigit (*brk)) continue; if (base != 16) break; if (!(*brk >= 'a' && *brk <= 'f') && !(*brk >= 'A' && *brk <= 'F')) break; } if (brk == curarg) args[i] = grub_strdup ("0"); else args[i] = grub_strndup (curarg, brk - curarg); } break; case TYPE_VBE_MODE: { unsigned mod; struct grub_vesa_mode_table_entry *modedesc; mod = grub_strtoul (curarg, 0, 0); if (grub_errno) { mod = 0; grub_errno = GRUB_ERR_NONE; } if (mod < GRUB_VESA_MODE_TABLE_START || mod > GRUB_VESA_MODE_TABLE_END) { args[i] = grub_strdup ("auto"); break; } modedesc = &grub_vesa_mode_table[mod - GRUB_VESA_MODE_TABLE_START]; if (!modedesc->width) { args[i] = grub_strdup ("auto"); break; } args[i] = grub_xasprintf ("%ux%ux%u", modedesc->width, modedesc->height, modedesc->depth); break; } case TYPE_BOOL: if (curarglen == 2 && curarg[0] == 'o' && curarg[1] == 'n') args[i] = grub_strdup ("1"); else args[i] = grub_strdup ("0"); break; } } } while (legacy_commands[cmdnum].argc > 0 && args[legacy_commands[cmdnum].argc - 1] == NULL && (legacy_commands[cmdnum].flags & FLAG_FALLBACK_AVAILABLE) && args[legacy_commands[cmdnum + 1].argc] == NULL) cmdnum++; for (; i < legacy_commands[cmdnum].argc; i++) switch (legacy_commands[cmdnum].argt[i]) { case TYPE_FILE_NO_CONSUME: case TYPE_PARTITION: case TYPE_FILE: case TYPE_REST_VERBATIM: case TYPE_VERBATIM: case TYPE_WITH_CONFIGFILE_OPTION: case TYPE_FORCE_OPTION: case TYPE_NOAPM_OPTION: case TYPE_TYPE_OR_NOMEM_OPTION: case TYPE_OPTION: args[i] = grub_strdup (""); break; case TYPE_BOOL: case TYPE_INT: args[i] = grub_strdup ("0"); break; case TYPE_VBE_MODE: args[i] = grub_strdup ("auto"); break; } if (legacy_commands[cmdnum].flags & FLAG_COLOR_INVERT) { char *corig = args[legacy_commands[cmdnum].argc - 1]; char *slash = grub_strchr (corig, '/'); char *invert; grub_size_t len; len = grub_strlen (corig); if (!slash) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid color specification `%s'"), args[0]); return NULL; } invert = grub_malloc (len + 1); if (!invert) return NULL; grub_memcpy (invert, slash + 1, len - (slash - corig) - 1); invert[len - (slash - args[0]) - 1] = '/'; grub_memcpy (invert + len - (slash - corig), corig, slash - corig); invert[len] = 0; args[legacy_commands[cmdnum].argc] = invert; } if (legacy_commands[cmdnum].suffix) { *suffix = grub_xasprintf (legacy_commands[cmdnum].suffix, args[legacy_commands[cmdnum].suffixarg]); if (*suffix) return NULL; } { char *ret = grub_xasprintf (legacy_commands[cmdnum].map, args[0], args[1], args[2], args[3]); grub_free (args[0]); grub_free (args[1]); grub_free (args[2]); grub_free (args[3]); return ret; } }
static grub_err_t sun_partition_map_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, const grub_partition_t partition)) { grub_partition_t p; struct grub_sun_block block; int partnum; grub_err_t err; p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition)); if (! p) return grub_errno; p->partmap = &grub_sun_partition_map; err = grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block), &block); if (err) { grub_free (p); return err; } if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic)) { grub_free (p); return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table"); } if (! grub_sun_is_valid (&block)) { grub_free (p); return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); } /* Maybe another error value would be better, because partition table _is_ recognized but invalid. */ for (partnum = 0; partnum < GRUB_PARTMAP_SUN_MAX_PARTS; partnum++) { struct grub_sun_partition_descriptor *desc; if (block.infos[partnum].id == 0 || block.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID) continue; desc = &block.partitions[partnum]; p->start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder) * grub_be_to_cpu16 (block.ntrks) * grub_be_to_cpu16 (block.nsect)); p->len = grub_be_to_cpu32 (desc->num_sectors); p->number = p->index = partnum; if (p->len) { if (hook (disk, p)) partnum = GRUB_PARTMAP_SUN_MAX_PARTS; } } grub_free (p); return grub_errno; }
static void free_iterator (struct grub_btrfs_leaf_descriptor *desc) { grub_free (desc->data); }
/* Read a GUI object specification from the theme file. Any components created will be added to the GUI container PARENT. */ static grub_err_t read_object (struct parsebuf *p, grub_gui_container_t parent) { grub_video_rect_t bounds; char *name; name = read_identifier (p); if (! name) goto cleanup; grub_gui_component_t component = 0; if (grub_strcmp (name, "label") == 0) { component = grub_gui_label_new (); } else if (grub_strcmp (name, "image") == 0) { component = grub_gui_image_new (); } else if (grub_strcmp (name, "vbox") == 0) { component = (grub_gui_component_t) grub_gui_vbox_new (); } else if (grub_strcmp (name, "hbox") == 0) { component = (grub_gui_component_t) grub_gui_hbox_new (); } else if (grub_strcmp (name, "canvas") == 0) { component = (grub_gui_component_t) grub_gui_canvas_new (); } else if (grub_strcmp (name, "progress_bar") == 0) { component = grub_gui_progress_bar_new (); } else if (grub_strcmp (name, "circular_progress") == 0) { component = grub_gui_circular_progress_new (); } else if (grub_strcmp (name, "boot_menu") == 0) { component = grub_gui_list_new (); } else { /* Unknown type. */ grub_error (GRUB_ERR_IO, "%s:%d:%d unknown object type `%s'", p->filename, p->line_num, p->col_num, name); goto cleanup; } if (! component) goto cleanup; /* Inform the component about the theme so it can find its resources. */ component->ops->set_property (component, "theme_dir", p->theme_dir); component->ops->set_property (component, "theme_path", p->filename); /* Add the component as a child of PARENT. */ bounds.x = 0; bounds.y = 0; bounds.width = -1; bounds.height = -1; component->ops->set_bounds (component, &bounds); parent->ops->add (parent, component); skip_whitespace (p); if (read_char (p) != '{') { grub_error (GRUB_ERR_IO, "%s:%d:%d expected `{' after object type name `%s'", p->filename, p->line_num, p->col_num, name); goto cleanup; } while (has_more (p)) { skip_whitespace (p); /* Check whether the end has been encountered. */ if (peek_char (p) == '}') { /* Skip the closing brace. */ read_char (p); break; } if (peek_char (p) == '#') { /* Skip comments. */ advance_to_next_line (p); continue; } if (peek_char (p) == '+') { /* Skip the '+'. */ read_char (p); /* Check whether this component is a container. */ if (component->ops->is_instance (component, "container")) { /* Read the sub-object recursively and add it as a child. */ if (read_object (p, (grub_gui_container_t) component) != 0) goto cleanup; /* After reading the sub-object, resume parsing, expecting another property assignment or sub-object definition. */ continue; } else { grub_error (GRUB_ERR_IO, "%s:%d:%d attempted to add object to non-container", p->filename, p->line_num, p->col_num); goto cleanup; } } char *property; property = read_identifier (p); if (! property) { grub_error (GRUB_ERR_IO, "%s:%d:%d identifier expected in theme file", p->filename, p->line_num, p->col_num); goto cleanup; } skip_whitespace (p); if (read_char (p) != '=') { grub_error (GRUB_ERR_IO, "%s:%d:%d expected `=' after property name `%s'", p->filename, p->line_num, p->col_num, property); grub_free (property); goto cleanup; } skip_whitespace (p); char *value; value = read_expression (p); if (! value) { grub_free (property); goto cleanup; } /* Handle the property value. */ if (grub_strcmp (property, "left") == 0) parse_proportional_spec (value, &component->x, &component->xfrac); else if (grub_strcmp (property, "top") == 0) parse_proportional_spec (value, &component->y, &component->yfrac); else if (grub_strcmp (property, "width") == 0) parse_proportional_spec (value, &component->w, &component->wfrac); else if (grub_strcmp (property, "height") == 0) parse_proportional_spec (value, &component->h, &component->hfrac); else /* General property handling. */ component->ops->set_property (component, property, value); grub_free (value); grub_free (property); if (grub_errno != GRUB_ERR_NONE) goto cleanup; } cleanup: grub_free (name); return grub_errno; }
/* Set properties on the view based on settings from the specified theme file. */ grub_err_t grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) { grub_file_t file; struct parsebuf p; p.view = view; p.theme_dir = grub_get_dirname (theme_path); file = grub_file_open (theme_path, GRUB_FILE_TYPE_THEME); if (! file) { grub_free (p.theme_dir); return grub_errno; } p.len = grub_file_size (file); p.buf = grub_malloc (p.len); p.pos = 0; p.line_num = 1; p.col_num = 1; p.filename = theme_path; if (! p.buf) { grub_file_close (file); grub_free (p.theme_dir); return grub_errno; } if (grub_file_read (file, p.buf, p.len) != p.len) { grub_free (p.buf); grub_file_close (file); grub_free (p.theme_dir); return grub_errno; } if (view->canvas) view->canvas->component.ops->destroy (view->canvas); view->canvas = grub_gui_canvas_new (); if (!view->canvas) goto fail; ((grub_gui_component_t) view->canvas) ->ops->set_bounds ((grub_gui_component_t) view->canvas, &view->screen); while (has_more (&p)) { /* Skip comments (lines beginning with #). */ if (peek_char (&p) == '#') { advance_to_next_line (&p); continue; } /* Find the first non-whitespace character. */ skip_whitespace (&p); /* Handle the content. */ if (peek_char (&p) == '+') { /* Skip the '+'. */ read_char (&p); read_object (&p, view->canvas); } else { read_property (&p); } if (grub_errno != GRUB_ERR_NONE) goto fail; } /* Set the new theme path. */ grub_free (view->theme_path); view->theme_path = grub_strdup (theme_path); goto cleanup; fail: if (view->canvas) { view->canvas->component.ops->destroy (view->canvas); view->canvas = 0; } cleanup: grub_free (p.buf); grub_file_close (file); grub_free (p.theme_dir); return grub_errno; }
/* Set the specified property NAME on the view to the given string VALUE. The caller is responsible for the lifetimes of NAME and VALUE. */ static grub_err_t theme_set_string (grub_gfxmenu_view_t view, const char *name, const char *value, const char *theme_dir, const char *filename, int line_num, int col_num) { if (! grub_strcmp ("title-font", name)) view->title_font = grub_font_get (value); else if (! grub_strcmp ("message-font", name)) view->message_font = grub_font_get (value); else if (! grub_strcmp ("terminal-font", name)) { grub_free (view->terminal_font_name); view->terminal_font_name = grub_strdup (value); if (! view->terminal_font_name) return grub_errno; } else if (! grub_strcmp ("title-color", name)) grub_video_parse_color (value, &view->title_color); else if (! grub_strcmp ("message-color", name)) grub_video_parse_color (value, &view->message_color); else if (! grub_strcmp ("message-bg-color", name)) grub_video_parse_color (value, &view->message_bg_color); else if (! grub_strcmp ("desktop-image", name)) { struct grub_video_bitmap *raw_bitmap; char *path; path = grub_resolve_relative_path (theme_dir, value); if (! path) return grub_errno; if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE) { grub_free (path); return grub_errno; } grub_free(path); grub_video_bitmap_destroy (view->raw_desktop_image); view->raw_desktop_image = raw_bitmap; } else if (! grub_strcmp ("desktop-image-scale-method", name)) { if (! value || ! grub_strcmp ("stretch", value)) view->desktop_image_scale_method = GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH; else if (! grub_strcmp ("crop", value)) view->desktop_image_scale_method = GRUB_VIDEO_BITMAP_SELECTION_METHOD_CROP; else if (! grub_strcmp ("padding", value)) view->desktop_image_scale_method = GRUB_VIDEO_BITMAP_SELECTION_METHOD_PADDING; else if (! grub_strcmp ("fitwidth", value)) view->desktop_image_scale_method = GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITWIDTH; else if (! grub_strcmp ("fitheight", value)) view->desktop_image_scale_method = GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITHEIGHT; else return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported scale method: %s", value); } else if (! grub_strcmp ("desktop-image-h-align", name)) { if (! grub_strcmp ("left", value)) view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_LEFT; else if (! grub_strcmp ("center", value)) view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_CENTER; else if (! grub_strcmp ("right", value)) view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_RIGHT; else return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported horizontal align method: %s", value); } else if (! grub_strcmp ("desktop-image-v-align", name)) { if (! grub_strcmp ("top", value)) view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_TOP; else if (! grub_strcmp ("center", value)) view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_CENTER; else if (! grub_strcmp ("bottom", value)) view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_BOTTOM; else return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported vertical align method: %s", value); } else if (! grub_strcmp ("desktop-color", name)) grub_video_parse_color (value, &view->desktop_color); else if (! grub_strcmp ("terminal-box", name)) { grub_err_t err; err = grub_gui_recreate_box (&view->terminal_box, value, theme_dir); if (err != GRUB_ERR_NONE) return err; } else if (! grub_strcmp ("terminal-border", name)) { view->terminal_border = grub_strtoul (value, 0, 10); if (grub_errno) return grub_errno; } else if (! grub_strcmp ("terminal-left", name)) { unsigned int tmp; int err = theme_get_unsigned_int_from_proportional (value, view->screen.width, &tmp); if (err != GRUB_ERR_NONE) return err; view->terminal_rect.x = tmp; } else if (! grub_strcmp ("terminal-top", name)) { unsigned int tmp; int err = theme_get_unsigned_int_from_proportional (value, view->screen.height, &tmp); if (err != GRUB_ERR_NONE) return err; view->terminal_rect.y = tmp; } else if (! grub_strcmp ("terminal-width", name)) { unsigned int tmp; int err = theme_get_unsigned_int_from_proportional (value, view->screen.width, &tmp); if (err != GRUB_ERR_NONE) return err; view->terminal_rect.width = tmp; } else if (! grub_strcmp ("terminal-height", name)) { unsigned int tmp; int err = theme_get_unsigned_int_from_proportional (value, view->screen.height, &tmp); if (err != GRUB_ERR_NONE) return err; view->terminal_rect.height = tmp; } else if (! grub_strcmp ("title-text", name)) { grub_free (view->title_text); view->title_text = grub_strdup (value); if (! view->title_text) return grub_errno; } else { return grub_error (GRUB_ERR_BAD_ARGUMENT, "%s:%d:%d unknown property `%s'", filename, line_num, col_num, name); } return grub_errno; }
static grub_file_t grub_xzio_open (grub_file_t io) { grub_file_t file; grub_xzio_t xzio; file = (grub_file_t) grub_zalloc (sizeof (*file)); if (!file) return 0; xzio = grub_zalloc (sizeof (*xzio)); if (!xzio) { grub_free (file); return 0; } xzio->file = io; xzio->saved_offset = 0; file->device = io->device; file->offset = 0; file->data = xzio; file->read_hook = 0; file->fs = &grub_xzio_fs; file->size = GRUB_FILE_SIZE_UNKNOWN; file->not_easly_seekable = 1; if (grub_file_tell (xzio->file) != 0) grub_file_seek (xzio->file, 0); /* Allocated 64KiB for dictionary. * Decoder will relocate if bigger is needed. */ xzio->dec = xz_dec_init (1 << 16); if (!xzio->dec) { grub_free (file); grub_free (xzio); return 0; } xzio->buf.in = xzio->inbuf; xzio->buf.in_pos = 0; xzio->buf.in_size = 0; xzio->buf.out = xzio->outbuf; xzio->buf.out_pos = 0; xzio->buf.out_size = XZBUFSIZ; /* FIXME: don't test footer on not easily seekable files. */ if (!test_header (file) || !test_footer (file)) { grub_errno = GRUB_ERR_NONE; grub_file_seek (io, 0); xz_dec_end (xzio->dec); grub_free (xzio); grub_free (file); return io; } return file; }
grub_partition_t grub_partition_probe (struct grub_disk *disk, const char *str) { grub_partition_t part = 0; grub_partition_t curpart = 0; grub_partition_t tail; const char *ptr; part = tail = disk->partition; for (ptr = str; *ptr;) { grub_partition_map_t partmap; int num; const char *partname, *partname_end; partname = ptr; while (*ptr && grub_isalpha (*ptr)) ptr++; partname_end = ptr; num = grub_strtoul (ptr, (char **) &ptr, 0) - 1; curpart = 0; /* Use the first partition map type found. */ FOR_PARTITION_MAPS(partmap) { if (partname_end != partname && (grub_strncmp (partmap->name, partname, partname_end - partname) != 0 || partmap->name[partname_end - partname] != 0)) continue; disk->partition = part; curpart = grub_partition_map_probe (partmap, disk, num); disk->partition = tail; if (curpart) break; if (grub_errno == GRUB_ERR_BAD_PART_TABLE) { /* Continue to next partition map type. */ grub_errno = GRUB_ERR_NONE; continue; } break; } if (! curpart) { while (part) { curpart = part->parent; grub_free (part); part = curpart; } return 0; } curpart->parent = part; part = curpart; if (! ptr || *ptr != ',') break; ptr++; } return part; }
/* Search for the block FILEBLOCK inside the file NODE. Return the blocknumber of this block on disk. */ static grub_disk_addr_t grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_hfsplus_btnode *nnode = 0; grub_disk_addr_t blksleft = fileblock; struct grub_hfsplus_extent *extents = &node->extents[0]; while (1) { struct grub_hfsplus_extkey *key; struct grub_hfsplus_key_internal extoverflow; grub_disk_addr_t blk; grub_off_t ptr; /* Try to find this block in the current set of extents. */ blk = grub_hfsplus_find_block (extents, &blksleft); /* The previous iteration of this loop allocated memory. The code above used this memory, it can be freed now. */ grub_free (nnode); nnode = 0; if (blk != 0xffffffffffffffffULL) return blk; /* For the extent overflow file, extra extents can't be found in the extent overflow file. If this happens, you found a bug... */ if (node->fileid == GRUB_HFSPLUS_FILEID_OVERFLOW) { grub_error (GRUB_ERR_READ_ERROR, "extra extents found in an extend overflow file"); break; } /* Set up the key to look for in the extent overflow file. */ extoverflow.extkey.fileid = node->fileid; extoverflow.extkey.type = 0; extoverflow.extkey.start = fileblock - blksleft; if (grub_hfsplus_btree_search (&node->data->extoverflow_tree, &extoverflow, grub_hfsplus_cmp_extkey, &nnode, &ptr)) { grub_error (GRUB_ERR_READ_ERROR, "no block found for the file id 0x%x and the block offset 0x%x", node->fileid, fileblock); break; } /* The extent overflow file has 8 extents right after the key. */ key = (struct grub_hfsplus_extkey *) grub_hfsplus_btree_recptr (&node->data->extoverflow_tree, nnode, ptr); extents = (struct grub_hfsplus_extent *) (key + 1); /* The block wasn't found. Perhaps the next iteration will find it. The last block we found is stored in BLKSLEFT now. */ } grub_free (nnode); /* Too bad, you lose. */ return -1; }
static void grub_biosdisk_close (grub_disk_t disk) { grub_free (disk->data); }
/* Read the file fs.lst for auto-loading. */ void read_fs_list (const char *prefix) { if (prefix) { char *filename; filename = grub_xasprintf ("%s/fs.lst", prefix); if (filename) { grub_file_t file; grub_fs_autoload_hook_t tmp_autoload_hook; /* This rules out the possibility that read_fs_list() is invoked recursively when we call grub_file_open() below. */ tmp_autoload_hook = grub_fs_autoload_hook; grub_fs_autoload_hook = NULL; file = grub_file_open (filename); if (file) { /* Override previous fs.lst. */ while (fs_module_list) { grub_named_list_t tmp; tmp = fs_module_list->next; grub_free (fs_module_list); fs_module_list = tmp; } while (1) { char *buf; char *p; char *q; grub_named_list_t fs_mod; buf = grub_getline (file); if (! buf) break; p = buf; q = buf + grub_strlen (buf) - 1; /* Ignore space. */ while (grub_isspace (*p)) p++; while (p < q && grub_isspace (*q)) *q-- = '\0'; /* If the line is empty, skip it. */ if (p >= q) continue; fs_mod = grub_malloc (sizeof (*fs_mod)); if (! fs_mod) continue; fs_mod->name = grub_strdup (p); if (! fs_mod->name) { grub_free (fs_mod); continue; } fs_mod->next = fs_module_list; fs_module_list = fs_mod; } grub_file_close (file); grub_fs_autoload_hook = tmp_autoload_hook; } grub_free (filename); } } /* Ignore errors. */ grub_errno = GRUB_ERR_NONE; /* Set the hook. */ grub_fs_autoload_hook = autoload_fs_module; }
static grub_err_t grub_biosdisk_open (const char *name, grub_disk_t disk) { grub_uint64_t total_sectors = 0; int drive; struct grub_biosdisk_data *data; drive = grub_biosdisk_get_drive (name); if (drive < 0) return grub_errno; disk->has_partitions = ((drive & 0x80) && (drive != cd_drive)); disk->id = drive; data = (struct grub_biosdisk_data *) grub_zalloc (sizeof (*data)); if (! data) return grub_errno; data->drive = drive; if ((cd_drive) && (drive == cd_drive)) { data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM; data->sectors = 32; total_sectors = GRUB_ULONG_MAX; /* TODO: get the correct size. */ } else if (drive & 0x80) { /* HDD */ int version; version = grub_biosdisk_check_int13_extensions (drive); if (version) { struct grub_biosdisk_drp *drp = (struct grub_biosdisk_drp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; /* Clear out the DRP. */ grub_memset (drp, 0, sizeof (*drp)); drp->size = sizeof (*drp); if (! grub_biosdisk_get_diskinfo_int13_extensions (drive, drp)) { data->flags = GRUB_BIOSDISK_FLAG_LBA; if (drp->total_sectors) total_sectors = drp->total_sectors; else /* Some buggy BIOSes doesn't return the total sectors correctly but returns zero. So if it is zero, compute it by C/H/S returned by the LBA BIOS call. */ total_sectors = drp->cylinders * drp->heads * drp->sectors; } } } if (! (data->flags & GRUB_BIOSDISK_FLAG_CDROM)) { if (grub_biosdisk_get_diskinfo_standard (drive, &data->cylinders, &data->heads, &data->sectors) != 0) { if (total_sectors && (data->flags & GRUB_BIOSDISK_FLAG_LBA)) { data->sectors = 63; data->heads = 255; data->cylinders = grub_divmod64 (total_sectors + data->heads * data->sectors - 1, data->heads * data->sectors, 0); } else { grub_free (data); return grub_error (GRUB_ERR_BAD_DEVICE, "%s cannot get C/H/S values", disk->name); } } if (! total_sectors) total_sectors = data->cylinders * data->heads * data->sectors; } disk->total_sectors = total_sectors; disk->data = data; return GRUB_ERR_NONE; }
grub_err_t SUFFIX(grub_openbsd_find_ramdisk) (grub_file_t file, grub_addr_t kern_start, void *kern_chunk_src, struct grub_openbsd_ramdisk_descriptor *desc) { unsigned symoff, stroff, symsize, strsize, symentsize; { grub_err_t err; Elf_Ehdr e; Elf_Shdr *s; char *shdr = NULL; err = read_headers (file, &e, &shdr); if (err) return err; for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) if (s->sh_type == SHT_SYMTAB) break; if (s >= (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize)) { grub_free (shdr); return GRUB_ERR_NONE; } symsize = s->sh_size; symentsize = s->sh_entsize; symoff = s->sh_offset; s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link); stroff = s->sh_offset; strsize = s->sh_size; grub_free (shdr); } { Elf_Sym *syms, *sym, *imagesym = NULL, *sizesym = NULL; unsigned i; char *strs; syms = grub_malloc (symsize); if (!syms) return grub_errno; if (grub_file_seek (file, symoff) == (grub_off_t) -1) { grub_free (syms); return grub_errno; } if (grub_file_read (file, syms, symsize) != (grub_ssize_t) symsize) { grub_free (syms); if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } strs = grub_malloc (strsize); if (!strs) { grub_free (syms); return grub_errno; } if (grub_file_seek (file, stroff) == (grub_off_t) -1) return grub_errno; if (grub_file_read (file, strs, strsize) != (grub_ssize_t) strsize) { grub_free (syms); grub_free (strs); if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } for (i = 0, sym = syms; i < symsize / symentsize; i++, sym = (Elf_Sym *) ((char *) sym + symentsize)) { if (ELF_ST_TYPE (sym->st_info) != STT_OBJECT) continue; if (!sym->st_name) continue; if (grub_strcmp (strs + sym->st_name, "rd_root_image") == 0) imagesym = sym; if (grub_strcmp (strs + sym->st_name, "rd_root_size") == 0) sizesym = sym; if (imagesym && sizesym) break; } if (!imagesym || !sizesym) { grub_free (syms); grub_free (strs); return GRUB_ERR_NONE; } if (sizeof (*desc->size) != sizesym->st_size) { grub_free (syms); grub_free (strs); return grub_error (GRUB_ERR_BAD_OS, "unexpected size of rd_root_size"); } desc->max_size = imagesym->st_size; desc->target = (imagesym->st_value & 0xFFFFFF) - kern_start + (grub_uint8_t *) kern_chunk_src; desc->size = (grub_uint32_t *) ((sizesym->st_value & 0xFFFFFF) - kern_start + (grub_uint8_t *) kern_chunk_src); grub_free (syms); grub_free (strs); return GRUB_ERR_NONE; } }
grub_err_t grub_multiboot_load (grub_file_t file, const char *filename) { grub_properly_aligned_t *buffer; grub_ssize_t len; struct multiboot_header *header; grub_err_t err; struct multiboot_header_tag *tag; struct multiboot_header_tag_address *addr_tag = NULL; int entry_specified = 0; grub_addr_t entry = 0; grub_uint32_t console_required = 0; struct multiboot_header_tag_framebuffer *fbtag = NULL; int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; buffer = grub_malloc (MULTIBOOT_SEARCH); if (!buffer) return grub_errno; len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); if (len < 32) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), filename); } COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0); grub_tpm_measure ((unsigned char *)buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename); header = find_header (buffer, len); if (header == 0) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); } COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % 4 == 0); keep_bs = 0; for (tag = (struct multiboot_header_tag *) (header + 1); tag->type != MULTIBOOT_TAG_TYPE_END; tag = (struct multiboot_header_tag *) ((grub_uint32_t *) tag + ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / 4)) switch (tag->type) { case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: { unsigned i; struct multiboot_header_tag_information_request *request_tag = (struct multiboot_header_tag_information_request *) tag; if (request_tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL) break; for (i = 0; i < (request_tag->size - sizeof (*request_tag)) / sizeof (request_tag->requests[0]); i++) switch (request_tag->requests[i]) { case MULTIBOOT_TAG_TYPE_END: case MULTIBOOT_TAG_TYPE_CMDLINE: case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: case MULTIBOOT_TAG_TYPE_MODULE: case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: case MULTIBOOT_TAG_TYPE_BOOTDEV: case MULTIBOOT_TAG_TYPE_MMAP: case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: case MULTIBOOT_TAG_TYPE_VBE: case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: case MULTIBOOT_TAG_TYPE_APM: case MULTIBOOT_TAG_TYPE_EFI32: case MULTIBOOT_TAG_TYPE_EFI64: case MULTIBOOT_TAG_TYPE_ACPI_OLD: case MULTIBOOT_TAG_TYPE_ACPI_NEW: case MULTIBOOT_TAG_TYPE_NETWORK: case MULTIBOOT_TAG_TYPE_EFI_MMAP: case MULTIBOOT_TAG_TYPE_EFI_BS: break; default: grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported information tag: 0x%x", request_tag->requests[i]); } break; } case MULTIBOOT_HEADER_TAG_ADDRESS: addr_tag = (struct multiboot_header_tag_address *) tag; break; case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: entry_specified = 1; entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr; break; case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags & MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED)) accepted_consoles &= ~GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; if (((struct multiboot_header_tag_console_flags *) tag)->console_flags & MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED) console_required = 1; break; case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: fbtag = (struct multiboot_header_tag_framebuffer *) tag; accepted_consoles |= GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER; break; /* GRUB always page-aligns modules. */ case MULTIBOOT_HEADER_TAG_MODULE_ALIGN: break; case MULTIBOOT_HEADER_TAG_EFI_BS: keep_bs = 1; break; default: if (! (tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported tag: 0x%x", tag->type); } break; } if (addr_tag && !entry_specified) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "load address tag without entry address tag"); } if (addr_tag) { grub_uint64_t load_addr = (addr_tag->load_addr + 1) ? addr_tag->load_addr : (addr_tag->header_addr - ((char *) header - (char *) buffer)); int offset = ((char *) header - (char *) buffer - (addr_tag->header_addr - load_addr)); int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset : addr_tag->load_end_addr - addr_tag->load_addr); grub_size_t code_size; void *source; grub_relocator_chunk_t ch; if (addr_tag->bss_end_addr) code_size = (addr_tag->bss_end_addr - load_addr); else code_size = load_size; err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, load_addr, code_size); if (err) { grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); grub_free (buffer); return err; } source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { grub_free (buffer); return grub_errno; } grub_file_read (file, source, load_size); if (grub_errno) { grub_free (buffer); return grub_errno; } if (addr_tag->bss_end_addr) grub_memset ((grub_uint8_t *) source + load_size, 0, addr_tag->bss_end_addr - load_addr - load_size); } else { err = grub_multiboot_load_elf (file, filename, buffer); if (err) { grub_free (buffer); return err; } } if (entry_specified) grub_multiboot_payload_eip = entry; if (fbtag) err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, accepted_consoles, fbtag->width, fbtag->height, fbtag->depth, console_required); else err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, accepted_consoles, 0, 0, 0, console_required); return err; }
grub_err_t grub_multiboot_load (grub_file_t file) { char *buffer; grub_ssize_t len; struct multiboot_header *header; grub_err_t err; buffer = grub_malloc (MULTIBOOT_SEARCH); if (!buffer) return grub_errno; len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); if (len < 32) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_OS, "file too small"); } /* Look for the multiboot header in the buffer. The header should be at least 12 bytes and aligned on a 4-byte boundary. */ for (header = (struct multiboot_header *) buffer; ((char *) header <= buffer + len - 12) || (header = 0); header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN)) { if (header->magic == MULTIBOOT_HEADER_MAGIC && !(header->magic + header->flags + header->checksum)) break; } if (header == 0) { grub_free (buffer); return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); } if (header->flags & UNSUPPORTED_FLAGS) { grub_free (buffer); return grub_error (GRUB_ERR_UNKNOWN_OS, "unsupported flag: 0x%x", header->flags); } if (header->flags & MULTIBOOT_AOUT_KLUDGE) { int offset = ((char *) header - buffer - (header->header_addr - header->load_addr)); int load_size = ((header->load_end_addr == 0) ? file->size - offset : header->load_end_addr - header->load_addr); grub_size_t code_size; void *source; grub_relocator_chunk_t ch; if (header->bss_end_addr) code_size = (header->bss_end_addr - header->load_addr); else code_size = load_size; err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch, header->load_addr, code_size); if (err) { grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); grub_free (buffer); return err; } source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { grub_free (buffer); return grub_errno; } grub_file_read (file, source, load_size); if (grub_errno) { grub_free (buffer); return grub_errno; } if (header->bss_end_addr) grub_memset ((grub_uint8_t *) source + load_size, 0, header->bss_end_addr - header->load_addr - load_size); grub_multiboot_payload_eip = header->entry_addr; } else { err = grub_multiboot_load_elf (file, buffer); if (err) { grub_free (buffer); return err; } } if (header->flags & MULTIBOOT_VIDEO_MODE) { switch (header->mode_type) { case 1: err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, 0, 0, 0, 0); break; case 0: err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, header->width, header->height, header->depth, 0); break; default: err = grub_error (GRUB_ERR_BAD_OS, "unsupported graphical mode type %d", header->mode_type); break; } } else err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, 0, 0, 0, 0); return err; }
/* Parse a test expression starting from *argn. */ static int test_parse (char **args, int *argn, int argc) { int ret = 0, discard = 0, invert = 0; int file_exists; struct grub_dirhook_info file_info; auto void update_val (int val); auto void get_fileinfo (char *pathname); /* Take care of discarding and inverting. */ void update_val (int val) { if (! discard) ret = invert ? ! val : val; invert = discard = 0; } /* Check if file exists and fetch its information. */ void get_fileinfo (char *path) { char *filename, *pathname; char *device_name; grub_fs_t fs; grub_device_t dev; /* A hook for iterating directories. */ auto int find_file (const char *cur_filename, const struct grub_dirhook_info *info); int find_file (const char *cur_filename, const struct grub_dirhook_info *info) { if ((info->case_insensitive ? grub_strcasecmp (cur_filename, filename) : grub_strcmp (cur_filename, filename)) == 0) { file_info = *info; file_exists = 1; return 1; } return 0; } file_exists = 0; device_name = grub_file_get_device_name (path); dev = grub_device_open (device_name); if (! dev) { grub_free (device_name); return; } fs = grub_fs_probe (dev); if (! fs) { grub_free (device_name); grub_device_close (dev); return; } pathname = grub_strchr (path, ')'); if (! pathname) pathname = path; else pathname++; /* Remove trailing '/'. */ while (*pathname && pathname[grub_strlen (pathname) - 1] == '/') pathname[grub_strlen (pathname) - 1] = 0; /* Split into path and filename. */ filename = grub_strrchr (pathname, '/'); if (! filename) { path = grub_strdup ("/"); filename = pathname; } else { filename++; path = grub_strdup (pathname); path[filename - pathname] = 0; } /* It's the whole device. */ if (! *pathname) { file_exists = 1; grub_memset (&file_info, 0, sizeof (file_info)); /* Root is always a directory. */ file_info.dir = 1; /* Fetch writing time. */ file_info.mtimeset = 0; if (fs->mtime) { if (! fs->mtime (dev, &file_info.mtime)) file_info.mtimeset = 1; grub_errno = GRUB_ERR_NONE; } } else (fs->dir) (dev, path, find_file); grub_device_close (dev); grub_free (path); grub_free (device_name); }
static void grub_ofnet_findcards (void) { auto int search_net_devices (struct grub_ieee1275_devalias *alias); int search_net_devices (struct grub_ieee1275_devalias *alias) { if (!grub_strcmp (alias->type, "network")) { struct grub_ofnetcard_data *ofdata; struct grub_net_card *card; grub_ieee1275_phandle_t devhandle; grub_net_link_level_address_t lla; char *shortname; ofdata = grub_malloc (sizeof (struct grub_ofnetcard_data)); if (!ofdata) { grub_print_error (); return 1; } card = grub_zalloc (sizeof (struct grub_net_card)); if (!card) { grub_free (ofdata); grub_print_error (); return 1; } ofdata->path = grub_strdup (alias->path); grub_ieee1275_finddevice (ofdata->path, &devhandle); if (grub_ieee1275_get_integer_property (devhandle, "max-frame-size", &(ofdata->mtu), sizeof (ofdata->mtu), 0)) { ofdata->mtu = 1500; } if (grub_ieee1275_get_property (devhandle, "mac-address", &(lla.mac), 6, 0) && grub_ieee1275_get_property (devhandle, "local-mac-address", &(lla.mac), 6, 0)) { grub_error (GRUB_ERR_IO, "Couldn't retrieve mac address."); grub_print_error (); return 0; } lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; card->default_address = lla; card->driver = NULL; card->data = ofdata; card->flags = 0; shortname = find_alias (alias->path); card->name = grub_xasprintf ("ofnet_%s", shortname ? : alias->path); card->idle_poll_delay_ms = 1; grub_free (shortname); card->driver = &ofdriver; grub_net_card_register (card); return 0; } return 0; } /* Look at all nodes for devices of the type network. */ grub_ieee1275_devices_iterate (search_net_devices); }
static grub_err_t grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t *files = 0; int i, nfiles = 0; grub_size_t size = 0; grub_uint8_t *ptr; if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); goto fail; } if (!loaded) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); goto fail; } files = grub_zalloc (argc * sizeof (files[0])); if (!files) goto fail; for (i = 0; i < argc; i++) { grub_file_filter_disable_compression (); files[i] = grub_file_open (argv[i]); if (! files[i]) goto fail; nfiles++; size += ALIGN_UP (grub_file_size (files[i]), 4); } initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); if (!initrd_mem) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); goto fail; } params->ramdisk_size = size; params->ramdisk_image = (grub_uint32_t)(grub_uint64_t) initrd_mem; ptr = initrd_mem; for (i = 0; i < nfiles; i++) { grub_ssize_t cursize = grub_file_size (files[i]); if (grub_file_read (files[i], ptr, cursize) != cursize) { if (!grub_errno) grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), argv[i]); goto fail; } grub_tpm_measure (ptr, cursize, GRUB_INITRD_PCR); ptr += cursize; grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4)); ptr += ALIGN_UP_OVERHEAD (cursize, 4); } params->ramdisk_size = size; fail: for (i = 0; i < nfiles; i++) grub_file_close (files[i]); grub_free (files); if (initrd_mem && grub_errno) grub_efi_free_pages((grub_efi_physical_address_t)initrd_mem, BYTES_TO_PAGES(size)); return grub_errno; }
/* 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 grub_err_t grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; struct linux_kernel_header lh; grub_ssize_t len, start, filelen; void *kernel = NULL; grub_dl_ref (my_mod); if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); goto fail; } file = grub_file_open (argv[0]); if (! file) goto fail; filelen = grub_file_size (file); kernel = grub_malloc(filelen); if (!kernel) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); goto fail; } if (grub_file_read (file, kernel, filelen) != filelen) { grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]); goto fail; } grub_tpm_measure (kernel, filelen, GRUB_KERNEL_PCR); if (! grub_linuxefi_secure_validate (kernel, filelen)) { grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); grub_free (kernel); goto fail; } params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); if (! params) { grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); goto fail; } grub_memset (params, 0, 16384); grub_memcpy (&lh, kernel, sizeof (lh)); if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) { grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); goto fail; } if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) { grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); goto fail; } if (lh.version < grub_cpu_to_le16 (0x020b)) { grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); goto fail; } if (!lh.handover_offset) { grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); goto fail; } linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, BYTES_TO_PAGES(lh.cmdline_size + 1)); if (!linux_cmdline) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); goto fail; } grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); grub_create_loader_cmdline (argc, argv, linux_cmdline + sizeof (LINUX_IMAGE) - 1, lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1)); grub_pass_verity_hash(&lh, linux_cmdline); lh.cmd_line_ptr = (grub_uint32_t)(grub_uint64_t)linux_cmdline; handover_offset = lh.handover_offset; start = (lh.setup_sects + 1) * 512; len = grub_file_size(file) - start; kernel_mem = grub_efi_allocate_pages(lh.pref_address, BYTES_TO_PAGES(lh.init_size)); if (!kernel_mem) kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, BYTES_TO_PAGES(lh.init_size)); if (!kernel_mem) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); goto fail; } grub_memcpy (kernel_mem, (char *)kernel + start, len); grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); loaded=1; lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; grub_memcpy (params, &lh, 2 * 512); params->type_of_loader = 0x21; fail: if (file) grub_file_close (file); if (kernel) grub_free (kernel); if (grub_errno != GRUB_ERR_NONE) { grub_dl_unref (my_mod); loaded = 0; } if (linux_cmdline && !loaded) grub_efi_free_pages((grub_efi_physical_address_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1)); if (kernel_mem && !loaded) grub_efi_free_pages((grub_efi_physical_address_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); if (params && !loaded) grub_efi_free_pages((grub_efi_physical_address_t)params, BYTES_TO_PAGES(16384)); return grub_errno; }
/* 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; }
/* Print the information on the device NAME. */ grub_err_t grub_normal_print_device_info (const char *name) { grub_device_t dev; char *p; p = grub_strchr (name, ','); if (p) { grub_xputs ("\t"); grub_printf_ (N_("Partition %s:"), name); grub_xputs (" "); } else { grub_printf_ (N_("Device %s:"), name); grub_xputs (" "); } dev = grub_device_open (name); if (! dev) grub_printf ("%s", _("Filesystem cannot be accessed")); else if (dev->disk) { grub_fs_t fs; fs = grub_fs_probe (dev); /* Ignore all errors. */ grub_errno = 0; if (fs) { grub_printf_ (N_("Filesystem type %s"), fs->name); if (fs->label) { char *label; (fs->label) (dev, &label); if (grub_errno == GRUB_ERR_NONE) { if (label && grub_strlen (label)) { grub_xputs (" "); grub_printf_ (N_("- Label \"%s\""), label); } grub_free (label); } grub_errno = GRUB_ERR_NONE; } if (fs->mtime) { grub_int32_t tm; struct grub_datetime datetime; (fs->mtime) (dev, &tm); if (grub_errno == GRUB_ERR_NONE) { grub_unixtime2datetime (tm, &datetime); grub_xputs (" "); grub_printf_ (N_("- Last modification time %d-%02d-%02d " "%02d:%02d:%02d %s"), datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second, grub_get_weekday_name (&datetime)); } grub_errno = GRUB_ERR_NONE; } if (fs->uuid) { char *uuid; (fs->uuid) (dev, &uuid); if (grub_errno == GRUB_ERR_NONE) { if (uuid && grub_strlen (uuid)) grub_printf (", UUID %s", uuid); grub_free (uuid); } grub_errno = GRUB_ERR_NONE; } } else if (! dev->disk->has_partitions || dev->disk->partition) grub_printf ("%s", _("Unknown filesystem")); else grub_printf ("%s", _("Partition table")); grub_device_close (dev); } grub_xputs ("\n"); return grub_errno; }
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; }
static grub_err_t grub_ls_list_files (char *dirname, int longlist, int all, int human) { char *device_name; grub_fs_t fs; const char *path; grub_device_t dev; device_name = grub_file_get_device_name (dirname); dev = grub_device_open (device_name); if (! dev) goto fail; fs = grub_fs_probe (dev); path = grub_strchr (dirname, ')'); if (! path) path = dirname; else path++; if (! path && ! device_name) { grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); goto fail; } if (! *path) { if (grub_errno == GRUB_ERR_UNKNOWN_FS) grub_errno = GRUB_ERR_NONE; grub_normal_print_device_info (device_name); } else if (fs) { struct grub_ls_list_files_ctx ctx = { .dirname = dirname, .all = all, .human = human }; if (longlist) (fs->dir) (dev, path, print_files_long, &ctx); else (fs->dir) (dev, path, print_files, &ctx); if (grub_errno == GRUB_ERR_BAD_FILE_TYPE && path[grub_strlen (path) - 1] != '/') { /* PATH might be a regular file. */ char *p; grub_file_t file; struct grub_dirhook_info info; grub_errno = 0; grub_file_filter_disable_compression (); file = grub_file_open (dirname); if (! file) goto fail; grub_file_close (file); p = grub_strrchr (dirname, '/') + 1; dirname = grub_strndup (dirname, p - dirname); if (! dirname) goto fail; all = 1; grub_memset (&info, 0, sizeof (info)); if (longlist) print_files_long (p, &info, &ctx); else print_files (p, &info, &ctx); grub_free (dirname); } if (grub_errno == GRUB_ERR_NONE) grub_xputs ("\n"); grub_refresh (); } fail: if (dev) grub_device_close (dev); grub_free (device_name); return 0; }