int rarp (void) { int retry; struct arprequest rarpreq; if (! eth_probe ()) return 0; network_ready = 0; grub_memset (&rarpreq, 0, sizeof (rarpreq)); rarpreq.hwtype = htons (1); rarpreq.protocol = htons (IP); rarpreq.hwlen = ETH_ALEN; rarpreq.protolen = 4; rarpreq.opcode = htons (RARP_REQUEST); grub_memmove ((char *) &rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); grub_memmove ((char *) &rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) { long timeout; eth_transmit (broadcast, RARP, sizeof (rarpreq), &rarpreq); timeout = rfc2131_sleep_interval (TIMEOUT, retry); if (await_reply (AWAIT_RARP, 0, rarpreq.shwaddr, timeout)) break; if (ip_abort) return 0; } if (retry < MAX_ARP_RETRIES) { network_ready = 1; return 1; } return 0; }
grub_err_t grub_set_history (int newsize) { grub_uint32_t **old_hist_lines = hist_lines; hist_lines = grub_malloc (sizeof (grub_uint32_t *) * newsize); /* Copy the old lines into the new buffer. */ if (old_hist_lines) { /* Remove the lines that don't fit in the new buffer. */ if (newsize < hist_used) { grub_size_t i; grub_size_t delsize = hist_used - newsize; hist_used = newsize; for (i = 1; i < delsize + 1; i++) { grub_ssize_t pos = hist_end - i; if (pos < 0) pos += hist_size; grub_free (old_hist_lines[pos]); } hist_end -= delsize; if (hist_end < 0) hist_end += hist_size; } if (hist_pos < hist_end) grub_memmove (hist_lines, old_hist_lines + hist_pos, (hist_end - hist_pos) * sizeof (grub_uint32_t *)); else if (hist_used) { /* Copy the older part. */ grub_memmove (hist_lines, old_hist_lines + hist_pos, (hist_size - hist_pos) * sizeof (grub_uint32_t *)); /* Copy the newer part. */ grub_memmove (hist_lines + hist_size - hist_pos, old_hist_lines, hist_end * sizeof (grub_uint32_t *)); } } grub_free (old_hist_lines); hist_size = newsize; hist_pos = 0; hist_end = hist_used; return 0; }
int rarp (void) { int retry; /* arp and rarp requests share the same packet structure. */ struct arprequest rarpreq; /* Make sure that an ethernet is probed. */ if (! eth_probe ()) return 0; /* Clear the ready flag. */ network_ready = 0; grub_memset (&rarpreq, 0, sizeof (rarpreq)); rarpreq.hwtype = htons (1); rarpreq.protocol = htons (IP); rarpreq.hwlen = ETH_ALEN; rarpreq.protolen = 4; rarpreq.opcode = htons (RARP_REQUEST); grub_memmove ((char *) &rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); /* sipaddr is already zeroed out */ grub_memmove ((char *) &rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); /* tipaddr is already zeroed out */ for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) { long timeout; eth_transmit (broadcast, RARP, sizeof (rarpreq), &rarpreq); timeout = rfc2131_sleep_interval (TIMEOUT, retry); if (await_reply (AWAIT_RARP, 0, rarpreq.shwaddr, timeout)) break; if (ip_abort) return 0; } if (retry < MAX_ARP_RETRIES) { network_ready = 1; return 1; } return 0; }
/* Compact memory regions. */ static void compact_mem_regions (void) { int i, j; /* Sort them. */ for (i = 0; i < num_regions - 1; i++) for (j = i + 1; j < num_regions; j++) if (mem_regions[i].addr > mem_regions[j].addr) { struct mem_region tmp = mem_regions[i]; mem_regions[i] = mem_regions[j]; mem_regions[j] = tmp; } /* Merge overlaps. */ for (i = 0; i < num_regions - 1; i++) if (mem_regions[i].addr + mem_regions[i].size >= mem_regions[i + 1].addr) { j = i + 1; if (mem_regions[i].addr + mem_regions[i].size < mem_regions[j].addr + mem_regions[j].size) mem_regions[i].size = (mem_regions[j].addr + mem_regions[j].size - mem_regions[i].addr); grub_memmove (mem_regions + j, mem_regions + j + 1, (num_regions - j - 1) * sizeof (struct mem_region)); i--; num_regions--; } }
grub_err_t grub_relocator16_boot (struct grub_relocator *rel, struct grub_relocator16_state state) { grub_err_t err; void *relst; grub_relocator_chunk_t ch; /* Put it higher than the byte it checks for A20 check. */ err = grub_relocator_alloc_chunk_align (rel, &ch, 0x8010, 0xa0000 - RELOCATOR_SIZEOF (16) - GRUB_RELOCATOR16_STACK_SIZE, RELOCATOR_SIZEOF (16) + GRUB_RELOCATOR16_STACK_SIZE, 16, GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) return err; grub_relocator16_cs = state.cs; grub_relocator16_ip = state.ip; grub_relocator16_ds = state.ds; grub_relocator16_es = state.es; grub_relocator16_fs = state.fs; grub_relocator16_gs = state.gs; grub_relocator16_ss = state.ss; grub_relocator16_sp = state.sp; grub_relocator16_ebp = state.ebp; grub_relocator16_ebx = state.ebx; grub_relocator16_edx = state.edx; grub_relocator16_esi = state.esi; #ifdef GRUB_MACHINE_PCBIOS grub_relocator16_idt = *grub_realidt; #else grub_relocator16_idt.base = 0; grub_relocator16_idt.limit = 0; #endif grub_relocator16_keep_a20_enabled = state.a20; grub_memmove (get_virtual_current_address (ch), &grub_relocator16_start, RELOCATOR_SIZEOF (16)); err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), &relst, NULL); if (err) return err; asm volatile ("cli"); ((void (*) (void)) relst) (); /* Not reached. */ return GRUB_ERR_NONE; }
/* Delete COUNT characters in BUF. */ void cl_delete (int count) { grub_memmove (buf + lpos, buf + lpos + count, llen - count + 1); llen -= count; if (xpos + llen + count - lpos > CMDLINE_WIDTH) cl_refresh (0, CMDLINE_WIDTH - xpos); else cl_refresh (0, llen + count - lpos); }
/* Add CMDLINE to the history buffer. */ static void add_history (const char *cmdline, int no) { grub_memmove ((char *) HISTORY_BUF + MAX_CMDLINE * (no + 1), (char *) HISTORY_BUF + MAX_CMDLINE * no, MAX_CMDLINE * (num_history - no)); grub_strcpy ((char *) HISTORY_BUF + MAX_CMDLINE * no, cmdline); if (num_history < HISTORY_SIZE) num_history++; }
/* Insert STR to BUF. */ void cl_insert (const char *str) { int l = grub_strlen (str); if (llen + l < maxlen) { if (lpos == llen) grub_memmove (buf + lpos, str, l + 1); else { grub_memmove (buf + lpos + l, buf + lpos, llen - lpos + 1); grub_memmove (buf + lpos, str, l); } llen += l; lpos += l; if (xpos + l >= CMDLINE_WIDTH) cl_refresh (1, 0); else if (xpos + l + llen - lpos > CMDLINE_WIDTH) cl_refresh (0, CMDLINE_WIDTH - xpos); else cl_refresh (0, l + llen - lpos); } }
static int add_subnode (void *fdt, int parentoffset, const char *name) { grub_uint32_t *token = (void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt) + parentoffset); grub_uint32_t *end = (void *) struct_end (fdt); unsigned int entry_size = node_entry_size (name); unsigned int struct_size = grub_fdt_get_size_dt_struct(fdt); char *node_name; SKIP_NODE_NAME(node_name, token, end); /* Insert the new subnode just after the properties of the parent node (if any).*/ while (1) { if (token >= end) return -1; switch (grub_be_to_cpu32(*token)) { case FDT_PROP: /* Skip len, nameoff and property value. */ token += prop_entry_size(grub_be_to_cpu32(*(token + 1))) / sizeof(*token); break; case FDT_BEGIN_NODE: case FDT_END_NODE: goto insert; case FDT_NOP: token++; break; default: /* invalid token */ return -1; } } insert: grub_memmove (token + entry_size / sizeof(*token), token, (grub_addr_t) end - (grub_addr_t) token); *token = grub_cpu_to_be32_compile_time(FDT_BEGIN_NODE); token[entry_size / sizeof(*token) - 2] = 0; /* padding bytes */ grub_strcpy((char *) (token + 1), name); token[entry_size / sizeof(*token) - 1] = grub_cpu_to_be32_compile_time(FDT_END_NODE); grub_fdt_set_size_dt_struct (fdt, struct_size + entry_size); return ((grub_addr_t) token - (grub_addr_t) fdt - grub_fdt_get_off_dt_struct(fdt)); }
/* Rearrange FDT blocks in the canonical order: first the memory reservation block (just after the FDT header), then the structure block and finally the strings block. No free space is left between the first and the second block, while the space between the second and the third block is given by the clearance argument. */ static int rearrange_blocks (void *fdt, unsigned int clearance) { grub_uint32_t off_mem_rsvmap = ALIGN_UP(sizeof(grub_fdt_header_t), 8); grub_uint32_t off_dt_struct = off_mem_rsvmap + get_mem_rsvmap_size (fdt); grub_uint32_t off_dt_strings = off_dt_struct + grub_fdt_get_size_dt_struct (fdt) + clearance; grub_uint8_t *fdt_ptr = fdt; grub_uint8_t *tmp_fdt; if ((grub_fdt_get_off_mem_rsvmap (fdt) == off_mem_rsvmap) && (grub_fdt_get_off_dt_struct (fdt) == off_dt_struct)) { /* No need to allocate memory for a temporary FDT, just move the strings block if needed. */ if (grub_fdt_get_off_dt_strings (fdt) != off_dt_strings) { grub_memmove(fdt_ptr + off_dt_strings, fdt_ptr + grub_fdt_get_off_dt_strings (fdt), grub_fdt_get_size_dt_strings (fdt)); grub_fdt_set_off_dt_strings (fdt, off_dt_strings); } return 0; } tmp_fdt = grub_malloc (grub_fdt_get_totalsize (fdt)); if (!tmp_fdt) return -1; grub_memcpy (tmp_fdt + off_mem_rsvmap, fdt_ptr + grub_fdt_get_off_mem_rsvmap (fdt), get_mem_rsvmap_size (fdt)); grub_fdt_set_off_mem_rsvmap (fdt, off_mem_rsvmap); grub_memcpy (tmp_fdt + off_dt_struct, fdt_ptr + grub_fdt_get_off_dt_struct (fdt), grub_fdt_get_size_dt_struct (fdt)); grub_fdt_set_off_dt_struct (fdt, off_dt_struct); grub_memcpy (tmp_fdt + off_dt_strings, fdt_ptr + grub_fdt_get_off_dt_strings (fdt), grub_fdt_get_size_dt_strings (fdt)); grub_fdt_set_off_dt_strings (fdt, off_dt_strings); /* Copy reordered blocks back to fdt. */ grub_memcpy (fdt_ptr + off_mem_rsvmap, tmp_fdt + off_mem_rsvmap, grub_fdt_get_totalsize (fdt) - off_mem_rsvmap); grub_free(tmp_fdt); return 0; }
static grub_ssize_t grub_gzio_read (grub_file_t file, char *buf, grub_size_t len) { grub_ssize_t ret = 0; grub_gzio_t gzio = file->data; grub_off_t offset; /* Do we reset decompression to the beginning of the file? */ if (gzio->saved_offset > file->offset + WSIZE) initialize_tables (file); /* * This loop operates upon uncompressed data only. The only * special thing it does is to make sure the decompression * window is within the range of data it needs. */ offset = file->offset; while (len > 0 && grub_errno == GRUB_ERR_NONE) { register grub_size_t size; register char *srcaddr; while (offset >= gzio->saved_offset) inflate_window (file); srcaddr = (char *) ((offset & (WSIZE - 1)) + gzio->slide); size = gzio->saved_offset - offset; if (size > len) size = len; grub_memmove (buf, srcaddr, size); buf += size; len -= size; ret += size; offset += size; } if (grub_errno != GRUB_ERR_NONE) ret = -1; return ret; }
grub_err_t grub_relocator32_boot (struct grub_relocator *rel, struct grub_relocator32_state state, int avoid_efi_bootservices) { grub_err_t err; void *relst; grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (rel, &ch, 0, (0xffffffff - RELOCATOR_SIZEOF (32)) + 1, RELOCATOR_SIZEOF (32), 16, GRUB_RELOCATOR_PREFERENCE_NONE, avoid_efi_bootservices); if (err) return err; grub_relocator32_eax = state.eax; grub_relocator32_ebx = state.ebx; grub_relocator32_ecx = state.ecx; grub_relocator32_edx = state.edx; grub_relocator32_eip = state.eip; grub_relocator32_esp = state.esp; grub_relocator32_ebp = state.ebp; grub_relocator32_esi = state.esi; grub_relocator32_edi = state.edi; grub_memmove (get_virtual_current_address (ch), &grub_relocator32_start, RELOCATOR_SIZEOF (32)); err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), &relst, NULL); if (err) return err; asm volatile ("cli"); ((void (*) (void)) relst) (); /* Not reached. */ return GRUB_ERR_NONE; }
grub_err_t grub_relocator64_boot (struct grub_relocator *rel, struct grub_relocator64_state state, grub_addr_t min_addr, grub_addr_t max_addr) { grub_err_t err; void *relst; grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (rel, &ch, min_addr, max_addr - RELOCATOR_SIZEOF (64), RELOCATOR_SIZEOF (64), 16, GRUB_RELOCATOR_PREFERENCE_NONE, 0); if (err) return err; grub_relocator64_rax = state.rax; grub_relocator64_rbx = state.rbx; grub_relocator64_rcx = state.rcx; grub_relocator64_rdx = state.rdx; grub_relocator64_rip = state.rip; grub_relocator64_rsp = state.rsp; grub_relocator64_rsi = state.rsi; grub_relocator64_cr3 = state.cr3; grub_memmove (get_virtual_current_address (ch), &grub_relocator64_start, RELOCATOR_SIZEOF (64)); err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), &relst, NULL); if (err) return err; asm volatile ("cli"); ((void (*) (void)) relst) (); /* Not reached. */ return GRUB_ERR_NONE; }
int udp_transmit (unsigned long destip, unsigned int srcsock, unsigned int destsock, int len, const void *buf) { struct iphdr *ip; struct udphdr *udp; struct arprequest arpreq; int arpentry, i; int retry; ip = (struct iphdr *) buf; udp = (struct udphdr *) ((unsigned long) buf + sizeof (struct iphdr)); ip->verhdrlen = 0x45; ip->service = 0; ip->len = htons (len); ip->ident = 0; ip->frags = 0; ip->ttl = 60; ip->protocol = IP_UDP; ip->chksum = 0; ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr; ip->dest.s_addr = destip; ip->chksum = ipchksum ((unsigned short *) buf, sizeof (struct iphdr)); udp->src = htons (srcsock); udp->dest = htons (destsock); udp->len = htons (len - sizeof (struct iphdr)); udp->chksum = 0; udp->chksum = htons (udpchksum (ip)); if (udp->chksum == 0) udp->chksum = 0xffff; if (destip == IP_BROADCAST) { eth_transmit (broadcast, IP, len, buf); } else { if (((destip & netmask) != (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) && arptable[ARP_GATEWAY].ipaddr.s_addr) destip = arptable[ARP_GATEWAY].ipaddr.s_addr; for (arpentry = 0; arpentry < MAX_ARP; arpentry++) if (arptable[arpentry].ipaddr.s_addr == destip) break; if (arpentry == MAX_ARP) { etherboot_printf ("%@ is not in my arp table!\n", destip); return 0; } for (i = 0; i < ETH_ALEN; i++) if (arptable[arpentry].node[i]) break; if (i == ETH_ALEN) { #ifdef DEBUG grub_printf ("arp request.\n"); #endif arpreq.hwtype = htons (1); arpreq.protocol = htons (IP); arpreq.hwlen = ETH_ALEN; arpreq.protolen = 4; arpreq.opcode = htons (ARP_REQUEST); grub_memmove (arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); grub_memmove (arpreq.sipaddr, (char *) &arptable[ARP_CLIENT].ipaddr, sizeof (in_addr)); grub_memset (arpreq.thwaddr, 0, ETH_ALEN); grub_memmove (arpreq.tipaddr, (char *) &destip, sizeof (in_addr)); for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) { long timeout; eth_transmit (broadcast, ARP, sizeof (arpreq), &arpreq); timeout = rfc2131_sleep_interval (TIMEOUT, retry); if (await_reply (AWAIT_ARP, arpentry, arpreq.tipaddr, timeout)) goto xmit; if (ip_abort) return 0; } return 0; } xmit: eth_transmit (arptable[arpentry].node, IP, len, buf); } return 1; }
/* Fill the buffer by receiving the data via the TFTP protocol. */ static int buf_fill (int abort) { #ifdef TFTP_DEBUG grub_printf ("buf_fill (%d)\n", abort); #endif while (! buf_eof && (buf_read + packetsize <= FSYS_BUFLEN)) { struct tftp_t *tr; long timeout; #ifdef CONGESTED timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry); #else timeout = rfc2131_sleep_interval (TIMEOUT, retry); #endif if (! await_reply (AWAIT_TFTP, iport, NULL, timeout)) { if (ip_abort) return 0; if (! block && retry++ < MAX_TFTP_RETRIES) { /* Maybe initial request was lost. */ #ifdef TFTP_DEBUG grub_printf ("Maybe initial request was lost.\n"); #endif if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport, TFTP_PORT, len, &tp)) return 0; continue; } #ifdef CONGESTED if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT)) { /* We resend our last ack. */ # ifdef TFTP_DEBUG grub_printf ("<REXMT>\n"); # endif udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); continue; } #endif /* Timeout. */ return 0; } tr = (struct tftp_t *) &nic.packet[ETH_HLEN]; if (tr->opcode == ntohs (TFTP_ERROR)) { grub_printf ("TFTP error %d (%s)\n", ntohs (tr->u.err.errcode), tr->u.err.errmsg); return 0; } if (tr->opcode == ntohs (TFTP_OACK)) { char *p = tr->u.oack.data, *e; #ifdef TFTP_DEBUG grub_printf ("OACK "); #endif /* Shouldn't happen. */ if (prevblock) { /* Ignore it. */ grub_printf ("%s:%d: warning: PREVBLOCK != 0 (0x%x)\n", __FILE__, __LINE__, prevblock); continue; } len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2; if (len > TFTP_MAX_PACKET) goto noak; e = p + len; while (*p != '\000' && p < e) { if (! grub_strcmp ("blksize", p)) { p += 8; if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET) goto noak; #ifdef TFTP_DEBUG grub_printf ("blksize = %d\n", packetsize); #endif } else if (! grub_strcmp ("tsize", p)) { p += 6; if ((filemax = getdec (&p)) < 0) { filemax = -1; goto noak; } #ifdef TFTP_DEBUG grub_printf ("tsize = %d\n", filemax); #endif } else { noak: #ifdef TFTP_DEBUG grub_printf ("NOAK\n"); #endif tp.opcode = htons (TFTP_ERROR); tp.u.err.errcode = 8; len = (grub_sprintf ((char *) tp.u.err.errmsg, "RFC1782 error") + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + sizeof (tp.u.err.errcode) + 1); udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, ntohs (tr->udp.src), len, &tp); return 0; } while (p < e && *p) p++; if (p < e) p++; } if (p > e) goto noak; /* This ensures that the packet does not get processed as data! */ block = tp.u.ack.block = 0; } else if (tr->opcode == ntohs (TFTP_DATA)) { #ifdef TFTP_DEBUG grub_printf ("DATA "); #endif len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4; /* Shouldn't happen. */ if (len > packetsize) { /* Ignore it. */ grub_printf ("%s:%d: warning: LEN > PACKETSIZE (0x%x > 0x%x)\n", __FILE__, __LINE__, len, packetsize); continue; } block = ntohs (tp.u.ack.block = tr->u.data.block); } else /* Neither TFTP_OACK nor TFTP_DATA. */ break; if ((block || bcounter) && (block != prevblock + (unsigned short) 1)) /* Block order should be continuous */ tp.u.ack.block = htons (block = prevblock); /* Should be continuous. */ tp.opcode = abort ? htons (TFTP_ERROR) : htons (TFTP_ACK); oport = ntohs (tr->udp.src); #ifdef TFTP_DEBUG grub_printf ("ACK\n"); #endif /* Ack. */ udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); if (abort) { buf_eof = 1; break; } /* Retransmission or OACK. */ if ((unsigned short) (block - prevblock) != 1) /* Don't process. */ continue; prevblock = block; /* Is it the right place to zero the timer? */ retry = 0; /* In GRUB, this variable doesn't play any important role at all, but use it for consistency with Etherboot. */ bcounter++; /* Copy the downloaded data to the buffer. */ grub_memmove (buf + buf_read, tr->u.data.download, len); buf_read += len; /* End of data. */ if (len < packetsize) buf_eof = 1; } return 1; }
static grub_ssize_t grub_xzio_read (grub_file_t file, char *buf, grub_size_t len) { grub_ssize_t ret = 0; grub_ssize_t readret; enum xz_ret xzret; grub_xzio_t xzio = file->data; grub_off_t current_offset; /* If seek backward need to reset decoder and start from beginning of file. TODO Possible improvement by jumping blocks. */ if (file->offset < xzio->saved_offset) { xz_dec_reset (xzio->dec); xzio->saved_offset = 0; xzio->buf.out_pos = 0; xzio->buf.in_pos = 0; xzio->buf.in_size = 0; grub_file_seek (xzio->file, 0); } current_offset = xzio->saved_offset; while (len > 0) { xzio->buf.out_size = grub_min (file->offset + ret + len - current_offset, XZBUFSIZ); /* Feed input. */ if (xzio->buf.in_pos == xzio->buf.in_size) { readret = grub_file_read (xzio->file, xzio->inbuf, XZBUFSIZ); if (readret < 0) return -1; xzio->buf.in_size = readret; xzio->buf.in_pos = 0; } xzret = xz_dec_run (xzio->dec, &xzio->buf); switch (xzret) { case XZ_MEMLIMIT_ERROR: case XZ_FORMAT_ERROR: case XZ_OPTIONS_ERROR: case XZ_DATA_ERROR: case XZ_BUF_ERROR: grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "file corrupted or unsupported block options"); return -1; default: break; } { grub_off_t new_offset = current_offset + xzio->buf.out_pos; if (file->offset <= new_offset) /* Store first chunk of data in buffer. */ { grub_size_t delta = new_offset - (file->offset + ret); grub_memmove (buf, xzio->buf.out + (xzio->buf.out_pos - delta), delta); len -= delta; buf += delta; ret += delta; } current_offset = new_offset; } xzio->buf.out_pos = 0; if (xzret == XZ_STREAM_END) /* Stream end, EOF. */ break; } if (ret >= 0) xzio->saved_offset = file->offset + ret; return ret; }
/* Read up to SIZE bytes, returned in ADDR. */ int tftp_read (char *addr, int size) { /* How many bytes is read? */ int ret = 0; #ifdef TFTP_DEBUG grub_printf ("tftp_read (0x%x, %d)\n", (int) addr, size); #endif if (filepos < saved_filepos) { /* Uggh.. FILEPOS has been moved backwards. So reopen the file. */ buf_read = 0; buf_fill (1); grub_memmove ((char *) &tp, (char *) &saved_tp, saved_len); len = saved_len; #ifdef TFTP_DEBUG { int i; grub_printf ("opcode = 0x%x, rrq = ", (unsigned long) tp.opcode); for (i = 0; i < TFTP_DEFAULTSIZE_PACKET; i++) { if (tp.u.rrq[i] >= ' ' && tp.u.rrq[i] <= '~') grub_putchar (tp.u.rrq[i]); else grub_putchar ('*'); } grub_putchar ('\n'); } #endif if (! send_rrq ()) { errnum = ERR_WRITE; return 0; } } while (size > 0) { int amt = buf_read + saved_filepos - filepos; /* If the length that can be copied from the buffer is over the requested size, cut it down. */ if (amt > size) amt = size; if (amt > 0) { /* Copy the buffer to the supplied memory space. */ grub_memmove (addr, buf + filepos - saved_filepos, amt); size -= amt; addr += amt; filepos += amt; ret += amt; /* If the size of the empty space becomes small, move the unused data forwards. */ if (filepos - saved_filepos > FSYS_BUFLEN / 2) { grub_memmove (buf, buf + FSYS_BUFLEN / 2, FSYS_BUFLEN / 2); buf_read -= FSYS_BUFLEN / 2; saved_filepos += FSYS_BUFLEN / 2; } } else { /* Skip the whole buffer. */ saved_filepos += buf_read; buf_read = 0; } /* Read the data. */ if (size > 0 && ! buf_fill (0)) { errnum = ERR_READ; return 0; } /* Sanity check. */ if (size > 0 && buf_read == 0) { errnum = ERR_READ; return 0; } } return ret; }
/* Check if the file DIRNAME really exists. Get the size and save it in FILEMAX. */ int tftp_dir (char *dirname) { int ch; #ifdef TFTP_DEBUG grub_printf ("tftp_dir (%s)\n", dirname); #endif /* In TFTP, there is no way to know what files exist. */ if (print_possibilities) return 1; /* Don't know the size yet. */ filemax = -1; reopen: /* Construct the TFTP request packet. */ tp.opcode = htons (TFTP_RRQ); /* Terminate the filename. */ ch = nul_terminate (dirname); /* Make the request string (octet, blksize and tsize). */ len = (grub_sprintf ((char *) tp.u.rrq, "%s%coctet%cblksize%c%d%ctsize%c0", dirname, 0, 0, 0, TFTP_MAX_PACKET, 0, 0) + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1); /* Restore the original DIRNAME. */ dirname[grub_strlen (dirname)] = ch; /* Save the TFTP packet so that we can reopen the file later. */ grub_memmove ((char *) &saved_tp, (char *) &tp, len); saved_len = len; if (! send_rrq ()) { errnum = ERR_WRITE; return 0; } /* Read the data. */ if (! buf_fill (0)) { errnum = ERR_FILE_NOT_FOUND; return 0; } if (filemax == -1) { /* The server doesn't support the "tsize" option, so we must read the file twice... */ /* Zero the size of the file. */ filemax = 0; do { /* Add the length of the downloaded data. */ filemax += buf_read; /* Reset the offset. Just discard the contents of the buffer. */ buf_read = 0; /* Read the data. */ if (! buf_fill (0)) { errnum = ERR_READ; return 0; } } while (! buf_eof); /* Maybe a few amounts of data remains. */ filemax += buf_read; /* Retry the open instruction. */ goto reopen; } return 1; }
/* Run an entry from the script SCRIPT. HEAP is used for the command-line buffer. If an error occurs, return non-zero, otherwise return zero. */ int run_script (char *script, char *heap) { char *old_entry; char *cur_entry = script; /* Initialize the data. */ init_cmdline (); while (1) { struct builtin *builtin; char *arg; print_error (); if (errnum) { errnum = ERR_NONE; /* If a fallback entry is defined, don't prompt a user's intervention. */ if (fallback_entry < 0) { grub_printf ("\nPress any key to continue..."); (void) getkey (); } return 1; } /* Copy the first string in CUR_ENTRY to HEAP. */ old_entry = cur_entry; while (*cur_entry++) ; grub_memmove (heap, old_entry, (int) cur_entry - (int) old_entry); if (! *heap) { /* If there is no more command in SCRIPT... */ /* If any kernel is not loaded, just exit successfully. */ if (kernel_type == KERNEL_TYPE_NONE) return 0; /* Otherwise, the command boot is run implicitly. */ grub_memmove (heap, "boot", 5); } /* Find a builtin. */ builtin = find_command (heap); if (! builtin) { grub_printf ("%s\n", old_entry); continue; } if (! (builtin->flags & BUILTIN_NO_ECHO)) grub_printf ("%s\n", old_entry); /* If BUILTIN cannot be run in the command-line, skip it. */ if (! (builtin->flags & BUILTIN_CMDLINE)) { errnum = ERR_UNRECOGNIZED; continue; } /* Invalidate the cache, because the user may exchange removable disks. */ buf_drive = -1; /* Run BUILTIN->FUNC. */ arg = skip_to (1, heap); (builtin->func) (arg, BUILTIN_SCRIPT); } }
int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name, const void *val, grub_uint32_t len) { grub_uint32_t *prop; int prop_name_present = 0; grub_uint32_t nameoff = 0; if ((nodeoffset >= grub_fdt_get_size_dt_struct (fdt)) || (nodeoffset & 0x3) || (grub_be_to_cpu32(*(grub_uint32_t *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct (fdt) + nodeoffset)) != FDT_BEGIN_NODE)) return -1; prop = find_prop (fdt, nodeoffset, name); if (prop) { grub_uint32_t prop_len = ALIGN_UP(grub_be_to_cpu32 (*(prop + 1)), sizeof(grub_uint32_t)); grub_uint32_t i; prop_name_present = 1; for (i = 0; i < prop_len / sizeof(grub_uint32_t); i++) *(prop + 3 + i) = grub_cpu_to_be32_compile_time (FDT_NOP); if (len > ALIGN_UP(prop_len, sizeof(grub_uint32_t))) { /* Length of new property value is greater than the space allocated for the current value: a new entry needs to be created, so save the nameoff field of the current entry and replace the current entry with NOP tokens. */ nameoff = grub_be_to_cpu32 (*(prop + 2)); *prop = *(prop + 1) = *(prop + 2) = grub_cpu_to_be32_compile_time (FDT_NOP); prop = NULL; } } if (!prop || !prop_name_present) { unsigned int needed_space = 0; if (!prop) needed_space = prop_entry_size(len); if (!prop_name_present) needed_space += grub_strlen (name) + 1; if (needed_space > get_free_space (fdt)) return -1; if (rearrange_blocks (fdt, !prop ? prop_entry_size(len) : 0) < 0) return -1; } if (!prop_name_present) { /* Append the property name at the end of the strings block. */ nameoff = grub_fdt_get_size_dt_strings (fdt); grub_strcpy ((char *) fdt + grub_fdt_get_off_dt_strings (fdt) + nameoff, name); grub_fdt_set_size_dt_strings (fdt, grub_fdt_get_size_dt_strings (fdt) + grub_strlen (name) + 1); } if (!prop) { char *node_name = (char *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct (fdt) + nodeoffset + sizeof(grub_uint32_t)); prop = (void *) (node_name + ALIGN_UP(grub_strlen(node_name) + 1, 4)); grub_memmove (prop + prop_entry_size(len) / sizeof(*prop), prop, struct_end(fdt) - (grub_addr_t) prop); grub_fdt_set_size_dt_struct (fdt, grub_fdt_get_size_dt_struct (fdt) + prop_entry_size(len)); *prop = grub_cpu_to_be32_compile_time (FDT_PROP); *(prop + 2) = grub_cpu_to_be32 (nameoff); } *(prop + 1) = grub_cpu_to_be32 (len); /* Insert padding bytes at the end of the value; if they are not needed, they will be overwritten by the following memcpy. */ *(prop + prop_entry_size(len) / sizeof(grub_uint32_t) - 1) = 0; grub_memcpy (prop + 3, val, len); return 0; }
grub_err_t PREFIX (boot) (void *relocator, grub_uint32_t dest, struct grub_relocator32_state state) { grub_size_t size; char *playground; playground = (char *) relocator - PRE_REGION_SIZE; size = *(grub_size_t *) playground; grub_dprintf ("relocator", "Relocator: source: %p, destination: 0x%x, size: 0x%lx\n", relocator, (unsigned) dest, (unsigned long) size); /* Very unlikely condition: Relocator may risk overwrite itself. Just move it a bit up. */ if ((grub_addr_t) dest < (grub_addr_t) relocator + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) && (grub_addr_t) dest + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) > (grub_addr_t) relocator) { void *relocator_new = ((grub_uint8_t *) relocator) + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN); grub_dprintf ("relocator", "Overwrite condition detected moving " "relocator from %p to %p\n", relocator, relocator_new); grub_memmove (relocator_new, relocator, (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) + size + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN)); relocator = relocator_new; } if ((grub_addr_t) dest >= (grub_addr_t) relocator) { int overhead; overhead = dest - ALIGN_UP (dest - RELOCATOR_SIZEOF (backward) - RELOCATOR_ALIGN, RELOCATOR_ALIGN); grub_dprintf ("relocator", "Backward relocator: code %p, source: %p, " "destination: 0x%x, size: 0x%lx\n", (char *) relocator - overhead, (char *) relocator - overhead, (unsigned) dest - overhead, (unsigned long) size + overhead); write_call_relocator_bw ((char *) relocator - overhead, (char *) relocator - overhead, dest - overhead, size + overhead, state); } else { int overhead; overhead = ALIGN_UP (dest + size, RELOCATOR_ALIGN) + RELOCATOR_SIZEOF (forward) - (dest + size); grub_dprintf ("relocator", "Forward relocator: code %p, source: %p, " "destination: 0x%x, size: 0x%lx\n", (char *) relocator + size + overhead - RELOCATOR_SIZEOF (forward), relocator, (unsigned) dest, (unsigned long) size + overhead); write_call_relocator_fw ((char *) relocator + size + overhead - RELOCATOR_SIZEOF (forward), relocator, dest, size + overhead, state); } /* Not reached. */ return GRUB_ERR_NONE; }
static grub_err_t handle_symlink (struct grub_cpio_data *data, const char *fn, char **name, grub_uint32_t mode, int *restart) { grub_size_t flen; char *target; #ifndef MODE_USTAR grub_err_t err; #endif char *ptr; char *lastslash; grub_size_t prefixlen; char *rest; grub_size_t size; *restart = 0; if ((mode & ATTR_TYPE) != ATTR_LNK) return GRUB_ERR_NONE; flen = grub_strlen (fn); if (grub_memcmp (*name, fn, flen) != 0 || ((*name)[flen] != 0 && (*name)[flen] != '/')) return GRUB_ERR_NONE; rest = *name + flen; lastslash = rest; if (*rest) rest++; while (lastslash >= *name && *lastslash != '/') lastslash--; if (lastslash >= *name) prefixlen = lastslash - *name; else prefixlen = 0; if (prefixlen) prefixlen++; #ifdef MODE_USTAR size = grub_strlen (data->linkname); #else size = data->size; #endif if (size == 0) return GRUB_ERR_NONE; target = grub_malloc (size + grub_strlen (*name) + 2); if (!target) return grub_errno; #ifdef MODE_USTAR grub_memcpy (target + prefixlen, data->linkname, size); #else err = grub_disk_read (data->disk, 0, data->dofs, data->size, target + prefixlen); if (err) return err; #endif if (target[prefixlen] == '/') { grub_memmove (target, target + prefixlen, size); ptr = target + size; ptr = grub_stpcpy (ptr, rest); *ptr = 0; grub_dprintf ("cpio", "symlink redirected %s to %s\n", *name, target); grub_free (*name); canonicalize (target); *name = target; *restart = 1; return GRUB_ERR_NONE; } if (prefixlen) { grub_memcpy (target, *name, prefixlen); target[prefixlen-1] = '/'; } ptr = target + prefixlen + size; ptr = grub_stpcpy (ptr, rest); *ptr = 0; grub_dprintf ("cpio", "symlink redirected %s to %s\n", *name, target); grub_free (*name); canonicalize (target); *name = target; *restart = 1; return GRUB_ERR_NONE; }
int bootp (void) { int retry; #ifndef NO_DHCP_SUPPORT int reqretry; #endif /* ! NO_DHCP_SUPPORT */ struct bootpip_t ip; unsigned long starttime; /* Make sure that an ethernet is probed. */ if (! eth_probe ()) return 0; /* Clear the ready flag. */ network_ready = 0; #ifdef DEBUG grub_printf ("network is ready.\n"); #endif grub_memset (&ip, 0, sizeof (struct bootpip_t)); ip.bp.bp_op = BOOTP_REQUEST; ip.bp.bp_htype = 1; ip.bp.bp_hlen = ETH_ALEN; starttime = currticks (); /* Use lower 32 bits of node address, more likely to be distinct than the time since booting */ grub_memmove (&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid)); ip.bp.bp_xid = xid += htonl (starttime); grub_memmove (ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); #ifdef DEBUG etherboot_printf ("bp_op = %d\n", ip.bp.bp_op); etherboot_printf ("bp_htype = %d\n", ip.bp.bp_htype); etherboot_printf ("bp_hlen = %d\n", ip.bp.bp_hlen); etherboot_printf ("bp_xid = %d\n", ip.bp.bp_xid); etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); #endif #ifdef NO_DHCP_SUPPORT /* Request RFC-style options. */ grub_memmove (ip.bp.bp_vend, rfc1533_cookie, 5); #else /* Request RFC-style options. */ grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end); #endif /* ! NO_DHCP_SUPPORT */ for (retry = 0; retry < MAX_BOOTP_RETRIES;) { long timeout; #ifdef DEBUG grub_printf ("retry = %d\n", retry); #endif /* Clear out the Rx queue first. It contains nothing of * interest, except possibly ARP requests from the DHCP/TFTP * server. We use polling throughout Etherboot, so some time * may have passed since we last polled the receive queue, * which may now be filled with broadcast packets. This will * cause the reply to the packets we are about to send to be * lost immediately. Not very clever. */ await_reply (AWAIT_QDRAIN, 0, NULL, 0); udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof (struct bootpip_t), &ip); timeout = rfc2131_sleep_interval (TIMEOUT, retry++); #ifdef NO_DHCP_SUPPORT if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { network_ready = 1; return 1; } #else /* ! NO_DHCP_SUPPORT */ if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { if (dhcp_reply != DHCPOFFER) { network_ready = 1; return 1; } dhcp_reply = 0; #ifdef DEBUG etherboot_printf ("bp_op = %d\n", (int) ip.bp.bp_op); etherboot_printf ("bp_htype = %d\n", (int) ip.bp.bp_htype); etherboot_printf ("bp_hlen = %d\n", (int) ip.bp.bp_hlen); etherboot_printf ("bp_xid = %d\n", (int) ip.bp.bp_xid); etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); #endif grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end); grub_memmove (ip.bp.bp_vend + 9, (char *) &dhcp_server, sizeof (in_addr)); grub_memmove (ip.bp.bp_vend + 15, (char *) &dhcp_addr, sizeof (in_addr)); #ifdef DEBUG grub_printf ("errnum = %d\n", errnum); #endif for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES;) { int ret; #ifdef DEBUG grub_printf ("reqretry = %d\n", reqretry); #endif ret = udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof (struct bootpip_t), &ip); if (! ret) grub_printf ("udp_transmit failed.\n"); dhcp_reply = 0; timeout = rfc2131_sleep_interval (TIMEOUT, reqretry++); if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) if (dhcp_reply == DHCPACK) { network_ready = 1; return 1; } #ifdef DEBUG grub_printf ("dhcp_reply = %d\n", dhcp_reply); #endif if (ip_abort) return 0; } } #endif /* ! NO_DHCP_SUPPORT */ if (ip_abort) return 0; ip.bp.bp_secs = htons ((currticks () - starttime) / TICKS_PER_SEC); } /* Timeout. */ return 0; }
int bootp (void) { int retry; #ifndef NO_DHCP_SUPPORT int reqretry; #endif struct bootpip_t ip; unsigned long starttime; if (! eth_probe ()) return 0; network_ready = 0; #ifdef DEBUG grub_printf ("network is ready.\n"); #endif grub_memset (&ip, 0, sizeof (struct bootpip_t)); ip.bp.bp_op = BOOTP_REQUEST; ip.bp.bp_htype = 1; ip.bp.bp_hlen = ETH_ALEN; starttime = currticks (); grub_memmove (&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid)); ip.bp.bp_xid = xid += htonl (starttime); grub_memmove (ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN); #ifdef DEBUG etherboot_printf ("bp_op = %d\n", ip.bp.bp_op); etherboot_printf ("bp_htype = %d\n", ip.bp.bp_htype); etherboot_printf ("bp_hlen = %d\n", ip.bp.bp_hlen); etherboot_printf ("bp_xid = %d\n", ip.bp.bp_xid); etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); #endif #ifdef NO_DHCP_SUPPORT grub_memmove (ip.bp.bp_vend, rfc1533_cookie, 5); #else grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcpdiscover, rfc1533_end, sizeof rfc1533_end); #endif for (retry = 0; retry < MAX_BOOTP_RETRIES;) { long timeout; #ifdef DEBUG grub_printf ("retry = %d\n", retry); #endif await_reply (AWAIT_QDRAIN, 0, NULL, 0); udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof (struct bootpip_t), &ip); timeout = rfc2131_sleep_interval (TIMEOUT, retry++); #ifdef NO_DHCP_SUPPORT if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { network_ready = 1; return 1; } #else if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) { if (dhcp_reply != DHCPOFFER) { network_ready = 1; return 1; } dhcp_reply = 0; #ifdef DEBUG etherboot_printf ("bp_op = %d\n", (int) ip.bp.bp_op); etherboot_printf ("bp_htype = %d\n", (int) ip.bp.bp_htype); etherboot_printf ("bp_hlen = %d\n", (int) ip.bp.bp_hlen); etherboot_printf ("bp_xid = %d\n", (int) ip.bp.bp_xid); etherboot_printf ("bp_hwaddr = %!\n", ip.bp.bp_hwaddr); etherboot_printf ("bp_hops = %d\n", (int) ip.bp.bp_hops); etherboot_printf ("bp_secs = %d\n", (int) ip.bp.bp_hwaddr); #endif grub_memmove (ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest); grub_memmove (ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcprequest, rfc1533_end, sizeof rfc1533_end); grub_memmove (ip.bp.bp_vend + 9, (char *) &dhcp_server, sizeof (in_addr)); grub_memmove (ip.bp.bp_vend + 15, (char *) &dhcp_addr, sizeof (in_addr)); #ifdef DEBUG grub_printf ("errnum = %d\n", errnum); #endif for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES;) { int ret; #ifdef DEBUG grub_printf ("reqretry = %d\n", reqretry); #endif ret = udp_transmit (IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER, sizeof (struct bootpip_t), &ip); if (! ret) grub_printf ("udp_transmit failed.\n"); dhcp_reply = 0; timeout = rfc2131_sleep_interval (TIMEOUT, reqretry++); if (await_reply (AWAIT_BOOTP, 0, NULL, timeout)) if (dhcp_reply == DHCPACK) { network_ready = 1; return 1; } #ifdef DEBUG grub_printf ("dhcp_reply = %d\n", dhcp_reply); #endif if (ip_abort) return 0; } } #endif if (ip_abort) return 0; ip.bp.bp_secs = htons ((currticks () - starttime) / TICKS_PER_SEC); } return 0; }
static struct grub_diskfilter_vg * grub_lvm_detect (grub_disk_t disk, struct grub_diskfilter_pv_id *id, grub_disk_addr_t *start_sector) { grub_err_t err; grub_uint64_t mda_offset, mda_size; char buf[GRUB_LVM_LABEL_SIZE]; char vg_id[GRUB_LVM_ID_STRLEN+1]; char pv_id[GRUB_LVM_ID_STRLEN+1]; char *metadatabuf, *p, *q, *vgname; struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf; struct grub_lvm_pv_header *pvh; struct grub_lvm_disk_locn *dlocn; struct grub_lvm_mda_header *mdah; struct grub_lvm_raw_locn *rlocn; unsigned int i, j, vgname_len; struct grub_diskfilter_vg *vg; struct grub_diskfilter_pv *pv; /* Search for label. */ for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++) { err = grub_disk_read (disk, i, 0, sizeof(buf), buf); if (err) goto fail; if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID, sizeof (lh->id))) && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL, sizeof (lh->type)))) break; } /* Return if we didn't find a label. */ if (i == GRUB_LVM_LABEL_SCAN_SECTORS) { #ifdef GRUB_UTIL grub_util_info ("no LVM signature found"); #endif goto fail; } pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl)); for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++) { pv_id[j++] = pvh->pv_uuid[i]; if ((i != 1) && (i != 29) && (i % 4 == 1)) pv_id[j++] = '-'; } pv_id[j] = '\0'; dlocn = pvh->disk_areas_xl; dlocn++; /* Is it possible to have multiple data/metadata areas? I haven't seen devices that have it. */ if (dlocn->offset) { grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "we don't support multiple LVM data areas"); #ifdef GRUB_UTIL grub_util_info ("we don't support multiple LVM data areas\n"); #endif goto fail; } dlocn++; mda_offset = grub_le_to_cpu64 (dlocn->offset); mda_size = grub_le_to_cpu64 (dlocn->size); /* It's possible to have multiple copies of metadata areas, we just use the first one. */ /* Allocate buffer space for the circular worst-case scenario. */ metadatabuf = grub_malloc (2 * mda_size); if (! metadatabuf) goto fail; err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf); if (err) goto fail2; mdah = (struct grub_lvm_mda_header *) metadatabuf; if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC, sizeof (mdah->magic))) || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION)) { grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unknown LVM metadata header"); #ifdef GRUB_UTIL grub_util_info ("unknown LVM metadata header\n"); #endif goto fail2; } rlocn = mdah->raw_locns; if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) > grub_le_to_cpu64 (mdah->size)) { /* Metadata is circular. Copy the wrap in place. */ grub_memcpy (metadatabuf + mda_size, metadatabuf + GRUB_LVM_MDA_HEADER_SIZE, grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) - grub_le_to_cpu64 (mdah->size)); } p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset); while (*q != ' ' && q < metadatabuf + mda_size) q++; if (q == metadatabuf + mda_size) { #ifdef GRUB_UTIL grub_util_info ("error parsing metadata\n"); #endif goto fail2; } vgname_len = q - p; vgname = grub_malloc (vgname_len + 1); if (!vgname) goto fail2; grub_memcpy (vgname, p, vgname_len); vgname[vgname_len] = '\0'; p = grub_strstr (q, "id = \""); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("couldn't find ID\n"); #endif goto fail3; } p += sizeof ("id = \"") - 1; grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN); vg_id[GRUB_LVM_ID_STRLEN] = '\0'; vg = grub_diskfilter_get_vg_by_uuid (GRUB_LVM_ID_STRLEN, vg_id); if (! vg) { /* First time we see this volume group. We've to create the whole volume group structure. */ vg = grub_malloc (sizeof (*vg)); if (! vg) goto fail3; vg->name = vgname; vg->uuid = grub_malloc (GRUB_LVM_ID_STRLEN); if (! vg->uuid) goto fail3; grub_memcpy (vg->uuid, vg_id, GRUB_LVM_ID_STRLEN); vg->uuid_len = GRUB_LVM_ID_STRLEN; vg->extent_size = grub_lvm_getvalue (&p, "extent_size = "); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown extent size\n"); #endif goto fail4; } vg->lvs = NULL; vg->pvs = NULL; p = grub_strstr (p, "physical_volumes {"); if (p) { p += sizeof ("physical_volumes {") - 1; /* Add all the pvs to the volume group. */ while (1) { int s; while (grub_isspace (*p)) p++; if (*p == '}') break; pv = grub_zalloc (sizeof (*pv)); q = p; while (*q != ' ') q++; s = q - p; pv->name = grub_malloc (s + 1); grub_memcpy (pv->name, p, s); pv->name[s] = '\0'; p = grub_strstr (p, "id = \""); if (p == NULL) goto pvs_fail; p += sizeof("id = \"") - 1; pv->id.uuid = grub_malloc (GRUB_LVM_ID_STRLEN); if (!pv->id.uuid) goto pvs_fail; grub_memcpy (pv->id.uuid, p, GRUB_LVM_ID_STRLEN); pv->id.uuidlen = GRUB_LVM_ID_STRLEN; pv->start_sector = grub_lvm_getvalue (&p, "pe_start = "); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown pe_start\n"); #endif goto pvs_fail; } p = grub_strchr (p, '}'); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("error parsing pe_start\n"); #endif goto pvs_fail; } p++; pv->disk = NULL; pv->next = vg->pvs; vg->pvs = pv; continue; pvs_fail: grub_free (pv->name); grub_free (pv); goto fail4; } } p = grub_strstr (p, "logical_volumes"); if (p) { p += sizeof ("logical_volumes = ") - 1; /* And add all the lvs to the volume group. */ while (1) { int s; int skip_lv = 0; struct grub_diskfilter_lv *lv; struct grub_diskfilter_segment *seg; int is_pvmove; while (grub_isspace (*p)) p++; if (*p == '}') break; lv = grub_zalloc (sizeof (*lv)); q = p; while (*q != ' ') q++; s = q - p; lv->name = grub_strndup (p, s); if (!lv->name) goto lvs_fail; { const char *iptr; char *optr; lv->fullname = grub_malloc (sizeof ("lvm/") - 1 + 2 * vgname_len + 1 + 2 * s + 1); if (!lv->fullname) goto lvs_fail; grub_memcpy (lv->fullname, "lvm/", sizeof ("lvm/") - 1); optr = lv->fullname + sizeof ("lvm/") - 1; for (iptr = vgname; iptr < vgname + vgname_len; iptr++) { *optr++ = *iptr; if (*iptr == '-') *optr++ = '-'; } *optr++ = '-'; for (iptr = p; iptr < p + s; iptr++) { *optr++ = *iptr; if (*iptr == '-') *optr++ = '-'; } *optr++ = 0; lv->idname = grub_malloc (sizeof ("lvmid/") + 2 * GRUB_LVM_ID_STRLEN + 1); if (!lv->idname) goto lvs_fail; grub_memcpy (lv->idname, "lvmid/", sizeof ("lvmid/") - 1); grub_memcpy (lv->idname + sizeof ("lvmid/") - 1, vg_id, GRUB_LVM_ID_STRLEN); lv->idname[sizeof ("lvmid/") - 1 + GRUB_LVM_ID_STRLEN] = '/'; p = grub_strstr (q, "id = \""); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("couldn't find ID\n"); #endif goto lvs_fail; } p += sizeof ("id = \"") - 1; grub_memcpy (lv->idname + sizeof ("lvmid/") - 1 + GRUB_LVM_ID_STRLEN + 1, p, GRUB_LVM_ID_STRLEN); lv->idname[sizeof ("lvmid/") - 1 + 2 * GRUB_LVM_ID_STRLEN + 1] = '\0'; } lv->size = 0; lv->visible = grub_lvm_check_flag (p, "status", "VISIBLE"); is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE"); lv->segment_count = grub_lvm_getvalue (&p, "segment_count = "); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown segment_count\n"); #endif goto lvs_fail; } lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count); seg = lv->segments; for (i = 0; i < lv->segment_count; i++) { p = grub_strstr (p, "segment"); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown segment\n"); #endif goto lvs_segment_fail; } seg->start_extent = grub_lvm_getvalue (&p, "start_extent = "); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown start_extent\n"); #endif goto lvs_segment_fail; } seg->extent_count = grub_lvm_getvalue (&p, "extent_count = "); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown extent_count\n"); #endif goto lvs_segment_fail; } p = grub_strstr (p, "type = \""); if (p == NULL) goto lvs_segment_fail; p += sizeof("type = \"") - 1; lv->size += seg->extent_count * vg->extent_size; if (grub_memcmp (p, "striped\"", sizeof ("striped\"") - 1) == 0) { struct grub_diskfilter_node *stripe; seg->type = GRUB_DISKFILTER_STRIPED; seg->node_count = grub_lvm_getvalue (&p, "stripe_count = "); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown stripe_count\n"); #endif goto lvs_segment_fail; } if (seg->node_count != 1) seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); seg->nodes = grub_zalloc (sizeof (*stripe) * seg->node_count); stripe = seg->nodes; p = grub_strstr (p, "stripes = ["); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown stripes\n"); #endif goto lvs_segment_fail2; } p += sizeof("stripes = [") - 1; for (j = 0; j < seg->node_count; j++) { p = grub_strchr (p, '"'); if (p == NULL) continue; q = ++p; while (*q != '"') q++; s = q - p; stripe->name = grub_malloc (s + 1); if (stripe->name == NULL) goto lvs_segment_fail2; grub_memcpy (stripe->name, p, s); stripe->name[s] = '\0'; p = q + 1; stripe->start = grub_lvm_getvalue (&p, ",") * vg->extent_size; if (p == NULL) continue; stripe++; } } else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1) == 0) { seg->type = GRUB_DISKFILTER_MIRROR; seg->node_count = grub_lvm_getvalue (&p, "mirror_count = "); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown mirror_count\n"); #endif goto lvs_segment_fail; } seg->nodes = grub_zalloc (sizeof (seg->nodes[0]) * seg->node_count); p = grub_strstr (p, "mirrors = ["); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown mirrors\n"); #endif goto lvs_segment_fail2; } p += sizeof("mirrors = [") - 1; for (j = 0; j < seg->node_count; j++) { char *lvname; p = grub_strchr (p, '"'); if (p == NULL) continue; q = ++p; while (*q != '"') q++; s = q - p; lvname = grub_malloc (s + 1); if (lvname == NULL) goto lvs_segment_fail2; grub_memcpy (lvname, p, s); lvname[s] = '\0'; seg->nodes[j].name = lvname; p = q + 1; } /* Only first (original) is ok with in progress pvmove. */ if (is_pvmove) seg->node_count = 1; } else if (grub_memcmp (p, "raid", sizeof ("raid") - 1) == 0 && (p[sizeof ("raid") - 1] >= '4' && p[sizeof ("raid") - 1] <= '6') && p[sizeof ("raidX") - 1] == '"') { switch (p[sizeof ("raid") - 1]) { case '4': seg->type = GRUB_DISKFILTER_RAID4; seg->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC; break; case '5': seg->type = GRUB_DISKFILTER_RAID5; seg->layout = GRUB_RAID_LAYOUT_LEFT_SYMMETRIC; break; case '6': seg->type = GRUB_DISKFILTER_RAID6; seg->layout = (GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC | GRUB_RAID_LAYOUT_MUL_FROM_POS); break; } seg->node_count = grub_lvm_getvalue (&p, "device_count = "); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown device_count\n"); #endif goto lvs_segment_fail; } seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown stripe_size\n"); #endif goto lvs_segment_fail; } seg->nodes = grub_zalloc (sizeof (seg->nodes[0]) * seg->node_count); p = grub_strstr (p, "raids = ["); if (p == NULL) { #ifdef GRUB_UTIL grub_util_info ("unknown mirrors\n"); #endif goto lvs_segment_fail2; } p += sizeof("raids = [") - 1; for (j = 0; j < seg->node_count; j++) { char *lvname; p = grub_strchr (p, '"'); p = p ? grub_strchr (p + 1, '"') : 0; p = p ? grub_strchr (p + 1, '"') : 0; if (p == NULL) continue; q = ++p; while (*q != '"') q++; s = q - p; lvname = grub_malloc (s + 1); if (lvname == NULL) goto lvs_segment_fail2; grub_memcpy (lvname, p, s); lvname[s] = '\0'; seg->nodes[j].name = lvname; p = q + 1; } if (seg->type == GRUB_DISKFILTER_RAID4) { char *tmp; tmp = seg->nodes[0].name; grub_memmove (seg->nodes, seg->nodes + 1, sizeof (seg->nodes[0]) * (seg->node_count - 1)); seg->nodes[seg->node_count - 1].name = tmp; } } else { #ifdef GRUB_UTIL char *p2; p2 = grub_strchr (p, '"'); if (p2) *p2 = 0; grub_util_info ("unknown LVM type %s\n", p); if (p2) *p2 ='"'; #endif /* Found a non-supported type, give up and move on. */ skip_lv = 1; break; } seg++; continue; lvs_segment_fail2: grub_free (seg->nodes); lvs_segment_fail: goto fail4; } if (p != NULL) p = grub_strchr (p, '}'); if (p == NULL) goto lvs_fail; p += 3; if (skip_lv) { grub_free (lv->name); grub_free (lv); continue; } lv->vg = vg; lv->next = vg->lvs; vg->lvs = lv; continue; lvs_fail: grub_free (lv->name); grub_free (lv); goto fail4; } } /* Match lvs. */ { struct grub_diskfilter_lv *lv1; struct grub_diskfilter_lv *lv2; for (lv1 = vg->lvs; lv1; lv1 = lv1->next) for (i = 0; i < lv1->segment_count; i++) for (j = 0; j < lv1->segments[i].node_count; j++) { if (vg->pvs) for (pv = vg->pvs; pv; pv = pv->next) { if (! grub_strcmp (pv->name, lv1->segments[i].nodes[j].name)) { lv1->segments[i].nodes[j].pv = pv; break; } } if (lv1->segments[i].nodes[j].pv == NULL) for (lv2 = vg->lvs; lv2; lv2 = lv2->next) if (grub_strcmp (lv2->name, lv1->segments[i].nodes[j].name) == 0) lv1->segments[i].nodes[j].lv = lv2; } } if (grub_diskfilter_vg_register (vg)) goto fail4; } else { grub_free (vgname); } id->uuid = grub_malloc (GRUB_LVM_ID_STRLEN); if (!id->uuid) goto fail4; grub_memcpy (id->uuid, pv_id, GRUB_LVM_ID_STRLEN); id->uuidlen = GRUB_LVM_ID_STRLEN; grub_free (metadatabuf); *start_sector = -1; return vg; /* Failure path. */ fail4: grub_free (vg); fail3: grub_free (vgname); fail2: grub_free (metadatabuf); fail: return NULL; }
static int inflate_codes_in_window (grub_file_t file) { register unsigned e; /* table entry flag/number of extra bits */ unsigned n, d; /* length and index for copy */ unsigned w; /* current window position */ struct huft *t; /* pointer to table entry */ unsigned ml, md; /* masks for bl and bd bits */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ grub_gzio_t gzio = file->data; /* make local copies of globals */ d = gzio->inflate_d; n = gzio->inflate_n; b = gzio->bb; /* initialize bit buffer */ k = gzio->bk; w = gzio->wp; /* initialize window position */ /* inflate the coded data */ ml = mask_bits[gzio->bl]; /* precompute masks for speed */ md = mask_bits[gzio->bd]; for (;;) /* do until end of block */ { if (! gzio->code_state) { NEEDBITS ((unsigned) gzio->bl); if ((e = (t = gzio->tl + ((unsigned) b & ml))->e) > 16) do { if (e == 99) { grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "an unused code found"); return 1; } DUMPBITS (t->b); e -= 16; NEEDBITS (e); } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); DUMPBITS (t->b); if (e == 16) /* then it's a literal */ { gzio->slide[w++] = (uch) t->v.n; if (w == WSIZE) break; } else /* it's an EOB or a length */ { /* exit if end of block */ if (e == 15) { gzio->block_len = 0; break; } /* get length of block to copy */ NEEDBITS (e); n = t->v.n + ((unsigned) b & mask_bits[e]); DUMPBITS (e); /* decode distance of block to copy */ NEEDBITS ((unsigned) gzio->bd); if ((e = (t = gzio->td + ((unsigned) b & md))->e) > 16) do { if (e == 99) { grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "an unused code found"); return 1; } DUMPBITS (t->b); e -= 16; NEEDBITS (e); } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); DUMPBITS (t->b); NEEDBITS (e); d = w - t->v.n - ((unsigned) b & mask_bits[e]); DUMPBITS (e); gzio->code_state++; } } if (gzio->code_state) { /* do the copy */ do { n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); if (w - d >= e) { grub_memmove (gzio->slide + w, gzio->slide + d, e); w += e; d += e; } else /* purposefully use the overlap for extra copies here!! */ { while (e--) gzio->slide[w++] = gzio->slide[d++]; } if (w == WSIZE) break; } while (n); if (! n) gzio->code_state--; /* did we break from the loop too soon? */ if (w == WSIZE) break; } } /* restore the globals from the locals */ gzio->inflate_d = d; gzio->inflate_n = n; gzio->wp = w; /* restore global window pointer */ gzio->bb = b; /* restore global bit buffer */ gzio->bk = k; return ! gzio->block_len; }
void *memmove (void *dest, const void *src, grub_size_t n) { return grub_memmove (dest, src, n); }