664 lines
17 KiB
C
664 lines
17 KiB
C
#include <stdarg.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <getopt.h>
|
|
#ifdef HAVE_ZLIB_H
|
|
#include <zlib.h>
|
|
#endif
|
|
#include "elf.h"
|
|
#include "elf_boot.h"
|
|
#include "mkelfImage.h"
|
|
|
|
static struct file_type file_type[] = {
|
|
{ "linux-i386", linux_i386_probe, linux_i386_mkelf, linux_i386_usage },
|
|
{ "bzImage-i386", bzImage_i386_probe, linux_i386_mkelf, linux_i386_usage },
|
|
{ "vmlinux-i386", vmlinux_i386_probe, linux_i386_mkelf, linux_i386_usage },
|
|
{ "linux-ia64", linux_ia64_probe, linux_ia64_mkelf, linux_ia64_usage },
|
|
};
|
|
static const int file_types = sizeof(file_type)/sizeof(file_type[0]);
|
|
|
|
void die(char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vfprintf(stderr, fmt, args);
|
|
va_end(args);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
IPCHKSUM - Checksum IP Header
|
|
**************************************************************************/
|
|
uint16_t ipchksum(const void *data, unsigned long length)
|
|
{
|
|
unsigned long sum;
|
|
unsigned long i;
|
|
const uint8_t *ptr;
|
|
|
|
/* In the most straight forward way possible,
|
|
* compute an ip style checksum.
|
|
*/
|
|
sum = 0;
|
|
ptr = data;
|
|
for(i = 0; i < length; i++) {
|
|
unsigned long value;
|
|
value = ptr[i];
|
|
if (i & 1) {
|
|
value <<= 8;
|
|
}
|
|
/* Add the new value */
|
|
sum += value;
|
|
/* Wrap around the carry */
|
|
if (sum > 0xFFFF) {
|
|
sum = (sum + (sum >> 16)) & 0xFFFF;
|
|
}
|
|
}
|
|
return (~cpu_to_le16(sum)) & 0xFFFF;
|
|
}
|
|
|
|
uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
|
|
{
|
|
unsigned long checksum;
|
|
sum = ~sum & 0xFFFF;
|
|
new = ~new & 0xFFFF;
|
|
if (offset & 1) {
|
|
/* byte swap the sum if it came from an odd offset
|
|
* since the computation is endian independant this
|
|
* works.
|
|
*/
|
|
new = bswap_16(new);
|
|
}
|
|
checksum = sum + new;
|
|
if (checksum > 0xFFFF) {
|
|
checksum -= 0xFFFF;
|
|
}
|
|
return (~checksum) & 0xFFFF;
|
|
}
|
|
|
|
void *xmalloc(size_t size, const char *name)
|
|
{
|
|
void *buf;
|
|
buf = malloc(size);
|
|
if (!buf) {
|
|
die("Cannot malloc %ld bytes to hold %s: %s\n",
|
|
size + 0UL, name, strerror(errno));
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
void *xrealloc(void *ptr, size_t size, const char *name)
|
|
{
|
|
void *buf;
|
|
buf = realloc(ptr, size);
|
|
if (!buf) {
|
|
die("Cannot realloc %ld bytes to hold %s: %s\n",
|
|
size + 0UL, name, strerror(errno));
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
|
|
char *slurp_file(const char *filename, off_t *r_size)
|
|
{
|
|
int fd;
|
|
char *buf;
|
|
off_t size, progress;
|
|
ssize_t result;
|
|
struct stat stats;
|
|
|
|
|
|
if (!filename) {
|
|
*r_size = 0;
|
|
return 0;
|
|
}
|
|
fd = open(filename, O_RDONLY);
|
|
if (fd < 0) {
|
|
die("Cannot open `%s': %s\n",
|
|
filename, strerror(errno));
|
|
}
|
|
result = fstat(fd, &stats);
|
|
if (result < 0) {
|
|
die("Cannot stat: %s: %s\n",
|
|
filename, strerror(errno));
|
|
}
|
|
size = stats.st_size;
|
|
*r_size = size;
|
|
buf = xmalloc(size, filename);
|
|
progress = 0;
|
|
while(progress < size) {
|
|
result = read(fd, buf + progress, size - progress);
|
|
if (result < 0) {
|
|
if ((errno == EINTR) || (errno == EAGAIN))
|
|
continue;
|
|
die("read on %s of %ld bytes failed: %s\n",
|
|
filename, (size - progress)+ 0UL, strerror(errno));
|
|
}
|
|
progress += result;
|
|
}
|
|
result = close(fd);
|
|
if (result < 0) {
|
|
die("Close of %s failed: %s\n",
|
|
filename, strerror(errno));
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
#if HAVE_ZLIB_H
|
|
char *slurp_decompress_file(const char *filename, off_t *r_size)
|
|
{
|
|
gzFile fp;
|
|
int errnum;
|
|
const char *msg;
|
|
char *buf;
|
|
off_t size, allocated;
|
|
ssize_t result;
|
|
|
|
if (!filename) {
|
|
*r_size = 0;
|
|
return 0;
|
|
}
|
|
fp = gzopen(filename, "rb");
|
|
if (fp == 0) {
|
|
msg = gzerror(fp, &errnum);
|
|
if (errnum == Z_ERRNO) {
|
|
msg = strerror(errno);
|
|
}
|
|
die("Cannot open `%s': %s\n", filename, msg);
|
|
}
|
|
size = 0;
|
|
allocated = 65536;
|
|
buf = xmalloc(allocated, filename);
|
|
do {
|
|
if (size == allocated) {
|
|
allocated <<= 1;
|
|
buf = xrealloc(buf, allocated, filename);
|
|
}
|
|
result = gzread(fp, buf + size, allocated - size);
|
|
if (result < 0) {
|
|
if ((errno == EINTR) || (errno == EAGAIN))
|
|
continue;
|
|
|
|
msg = gzerror(fp, &errnum);
|
|
if (errnum == Z_ERRNO) {
|
|
msg = strerror(errno);
|
|
}
|
|
die ("read on %s of %ld bytes failed: %s\n",
|
|
filename, (allocated - size) + 0UL, msg);
|
|
}
|
|
size += result;
|
|
} while(result > 0);
|
|
result = gzclose(fp);
|
|
if (result != Z_OK) {
|
|
msg = gzerror(fp, &errnum);
|
|
if (errnum == Z_ERRNO) {
|
|
msg = strerror(errno);
|
|
}
|
|
die ("Close of %s failed: %s\n", filename, msg);
|
|
}
|
|
*r_size = size;
|
|
return buf;
|
|
}
|
|
#else
|
|
char *slurp_decompress_file(const char *filename, off_t *r_size)
|
|
{
|
|
return slurp_file(filename, r_size);
|
|
}
|
|
#endif
|
|
|
|
struct memelfphdr *add_program_headers(struct memelfheader *ehdr, int count)
|
|
{
|
|
struct memelfphdr *phdr;
|
|
int i;
|
|
ehdr->e_phnum = count;
|
|
ehdr->e_phdr = phdr = xmalloc(count *sizeof(*phdr), "Program headers");
|
|
/* Set the default values */
|
|
for(i = 0; i < count; i++) {
|
|
phdr[i].p_type = PT_LOAD;
|
|
phdr[i].p_flags = PF_R | PF_W | PF_X;
|
|
phdr[i].p_vaddr = 0;
|
|
phdr[i].p_paddr = 0;
|
|
phdr[i].p_filesz = 0;
|
|
phdr[i].p_memsz = 0;
|
|
phdr[i].p_data = 0;
|
|
}
|
|
return phdr;
|
|
}
|
|
|
|
struct memelfnote *add_notes(struct memelfheader *ehdr, int count)
|
|
{
|
|
struct memelfnote *notes;
|
|
ehdr->e_notenum = count;
|
|
ehdr->e_notes = notes = xmalloc(count *sizeof(*notes), "Notes");
|
|
memset(notes, 0, count *sizeof(*notes));
|
|
return notes;
|
|
}
|
|
|
|
static int sizeof_notes(struct memelfnote *note, int notes)
|
|
{
|
|
int size;
|
|
int i;
|
|
|
|
size = 0;
|
|
for(i = 0; i < notes; i++) {
|
|
size += sizeof(Elf_Nhdr);
|
|
size += roundup(strlen(note[i].n_name)+1, 4);
|
|
size += roundup(note[i].n_descsz, 4);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static uint16_t cpu_to_elf16(struct memelfheader *ehdr, uint16_t val)
|
|
{
|
|
if (ehdr->ei_data == ELFDATA2LSB) {
|
|
return cpu_to_le16(val);
|
|
}
|
|
else if (ehdr->ei_data == ELFDATA2MSB) {
|
|
return cpu_to_be16(val);
|
|
}
|
|
die("Uknown elf layout in cpu_to_elf16");
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t cpu_to_elf32(struct memelfheader *ehdr, uint32_t val)
|
|
{
|
|
if (ehdr->ei_data == ELFDATA2LSB) {
|
|
return cpu_to_le32(val);
|
|
}
|
|
else if (ehdr->ei_data == ELFDATA2MSB) {
|
|
return cpu_to_be32(val);
|
|
}
|
|
die("Uknown elf layout in cpu_to_elf32");
|
|
return 0;
|
|
}
|
|
|
|
static uint64_t cpu_to_elf64(struct memelfheader *ehdr, uint64_t val)
|
|
{
|
|
if (ehdr->ei_data == ELFDATA2LSB) {
|
|
return cpu_to_le64(val);
|
|
}
|
|
else if (ehdr->ei_data == ELFDATA2MSB) {
|
|
return cpu_to_be64(val);
|
|
}
|
|
die("Uknown elf layout in cpu_to_elf64");
|
|
return 0;
|
|
}
|
|
|
|
static void serialize_notes(char *buf, struct memelfheader *ehdr)
|
|
{
|
|
struct Elf_Nhdr hdr;
|
|
struct memelfnote *note;
|
|
int notes;
|
|
size_t size, offset;
|
|
int i;
|
|
|
|
/* Clear the buffer */
|
|
note = ehdr->e_notes;
|
|
notes = ehdr->e_notenum;
|
|
size = sizeof_notes(note, notes);
|
|
memset(buf, 0, size);
|
|
|
|
/* Write the Elf Notes */
|
|
offset = 0;
|
|
for(i = 0; i < notes; i++) {
|
|
/* Compute the note header */
|
|
size_t n_namesz;
|
|
n_namesz = strlen(note[i].n_name) +1;
|
|
hdr.n_namesz = cpu_to_elf32(ehdr, n_namesz);
|
|
hdr.n_descsz = cpu_to_elf32(ehdr, note[i].n_descsz);
|
|
hdr.n_type = cpu_to_elf32(ehdr, note[i].n_type);
|
|
|
|
/* Copy the note into the buffer */
|
|
memcpy(buf + offset, &hdr, sizeof(hdr));
|
|
offset += sizeof(hdr);
|
|
memcpy(buf + offset, note[i].n_name, n_namesz);
|
|
offset += roundup(n_namesz, 4);
|
|
memcpy(buf + offset, note[i].n_desc, note[i].n_descsz);
|
|
offset += roundup(note[i].n_descsz, 4);
|
|
|
|
}
|
|
}
|
|
static void serialize_ehdr(char *buf, struct memelfheader *ehdr)
|
|
{
|
|
if (ehdr->ei_class == ELFCLASS32) {
|
|
Elf32_Ehdr *hdr = (Elf32_Ehdr *)buf;
|
|
hdr->e_ident[EI_MAG0] = ELFMAG0;
|
|
hdr->e_ident[EI_MAG1] = ELFMAG1;
|
|
hdr->e_ident[EI_MAG2] = ELFMAG2;
|
|
hdr->e_ident[EI_MAG3] = ELFMAG3;
|
|
hdr->e_ident[EI_CLASS] = ehdr->ei_class;
|
|
hdr->e_ident[EI_DATA] = ehdr->ei_data;
|
|
hdr->e_ident[EI_VERSION] = EV_CURRENT;
|
|
hdr->e_type = cpu_to_elf16(ehdr, ehdr->e_type);
|
|
hdr->e_machine = cpu_to_elf16(ehdr, ehdr->e_machine);
|
|
hdr->e_version = cpu_to_elf32(ehdr, EV_CURRENT);
|
|
hdr->e_entry = cpu_to_elf32(ehdr, ehdr->e_entry);
|
|
hdr->e_phoff = cpu_to_elf32(ehdr, sizeof(*hdr));
|
|
hdr->e_shoff = cpu_to_elf32(ehdr, 0);
|
|
hdr->e_flags = cpu_to_elf32(ehdr, ehdr->e_flags);
|
|
hdr->e_ehsize = cpu_to_elf16(ehdr, sizeof(*hdr));
|
|
hdr->e_phentsize = cpu_to_elf16(ehdr, sizeof(Elf32_Phdr));
|
|
hdr->e_phnum = cpu_to_elf16(ehdr, ehdr->e_phnum);
|
|
hdr->e_shentsize = cpu_to_elf16(ehdr, 0);
|
|
hdr->e_shnum = cpu_to_elf16(ehdr, 0);
|
|
hdr->e_shstrndx = cpu_to_elf16(ehdr, 0);
|
|
}
|
|
else if (ehdr->ei_class == ELFCLASS64) {
|
|
Elf64_Ehdr *hdr = (Elf64_Ehdr *)buf;
|
|
hdr->e_ident[EI_MAG0] = ELFMAG0;
|
|
hdr->e_ident[EI_MAG1] = ELFMAG1;
|
|
hdr->e_ident[EI_MAG2] = ELFMAG2;
|
|
hdr->e_ident[EI_MAG3] = ELFMAG3;
|
|
hdr->e_ident[EI_CLASS] = ehdr->ei_class;
|
|
hdr->e_ident[EI_DATA] = ehdr->ei_data;
|
|
hdr->e_ident[EI_VERSION] = EV_CURRENT;
|
|
hdr->e_type = cpu_to_elf16(ehdr, ehdr->e_type);
|
|
hdr->e_machine = cpu_to_elf16(ehdr, ehdr->e_machine);
|
|
hdr->e_version = cpu_to_elf32(ehdr, EV_CURRENT);
|
|
hdr->e_entry = cpu_to_elf64(ehdr, ehdr->e_entry);
|
|
hdr->e_phoff = cpu_to_elf64(ehdr, sizeof(*hdr));
|
|
hdr->e_shoff = cpu_to_elf64(ehdr, 0);
|
|
hdr->e_flags = cpu_to_elf32(ehdr, ehdr->e_flags);
|
|
hdr->e_ehsize = cpu_to_elf16(ehdr, sizeof(*hdr));
|
|
hdr->e_phentsize = cpu_to_elf16(ehdr, sizeof(Elf64_Phdr));
|
|
hdr->e_phnum = cpu_to_elf16(ehdr, ehdr->e_phnum);
|
|
hdr->e_shentsize = cpu_to_elf16(ehdr, 0);
|
|
hdr->e_shnum = cpu_to_elf16(ehdr, 0);
|
|
hdr->e_shstrndx = cpu_to_elf16(ehdr, 0);
|
|
}
|
|
else die("Uknown elf class: %x\n", ehdr->ei_class);
|
|
}
|
|
static void serialize_phdrs(char *buf, struct memelfheader *ehdr, size_t note_size)
|
|
{
|
|
int i;
|
|
size_t offset, note_offset;
|
|
if (ehdr->ei_class == ELFCLASS32) {
|
|
Elf32_Phdr *phdr = (Elf32_Phdr *)buf;
|
|
note_offset =
|
|
sizeof(Elf32_Ehdr) + (sizeof(Elf32_Phdr)*ehdr->e_phnum);
|
|
offset = note_offset + note_size;
|
|
for(i = 0; i < ehdr->e_phnum; i++) {
|
|
struct memelfphdr *hdr = ehdr->e_phdr + i;
|
|
phdr[i].p_type = cpu_to_elf32(ehdr, hdr->p_type);
|
|
phdr[i].p_offset = cpu_to_elf32(ehdr, offset);
|
|
phdr[i].p_vaddr = cpu_to_elf32(ehdr, hdr->p_vaddr);
|
|
phdr[i].p_paddr = cpu_to_elf32(ehdr, hdr->p_paddr);
|
|
phdr[i].p_filesz = cpu_to_elf32(ehdr, hdr->p_filesz);
|
|
phdr[i].p_memsz = cpu_to_elf32(ehdr, hdr->p_memsz);
|
|
phdr[i].p_flags = cpu_to_elf32(ehdr, hdr->p_flags);
|
|
phdr[i].p_align = cpu_to_elf32(ehdr, 0);
|
|
if (phdr[i].p_type == PT_NOTE) {
|
|
phdr[i].p_filesz = cpu_to_elf32(ehdr, note_size);
|
|
phdr[i].p_memsz = cpu_to_elf32(ehdr, note_size);
|
|
phdr[i].p_offset = cpu_to_elf32(ehdr, note_offset);
|
|
} else {
|
|
offset += hdr->p_filesz;
|
|
}
|
|
}
|
|
}
|
|
else if (ehdr->ei_class == ELFCLASS64) {
|
|
Elf64_Phdr *phdr = (Elf64_Phdr *)buf;
|
|
note_offset =
|
|
sizeof(Elf64_Ehdr) + (sizeof(Elf64_Phdr)*ehdr->e_phnum);
|
|
offset = note_offset + note_size;
|
|
for(i = 0; i < ehdr->e_phnum; i++) {
|
|
struct memelfphdr *hdr = ehdr->e_phdr + i;
|
|
phdr[i].p_type = cpu_to_elf32(ehdr, hdr->p_type);
|
|
phdr[i].p_flags = cpu_to_elf32(ehdr, hdr->p_flags);
|
|
phdr[i].p_offset = cpu_to_elf64(ehdr, offset);
|
|
phdr[i].p_vaddr = cpu_to_elf64(ehdr, hdr->p_vaddr);
|
|
phdr[i].p_paddr = cpu_to_elf64(ehdr, hdr->p_paddr);
|
|
phdr[i].p_filesz = cpu_to_elf64(ehdr, hdr->p_filesz);
|
|
phdr[i].p_memsz = cpu_to_elf64(ehdr, hdr->p_memsz);
|
|
phdr[i].p_align = cpu_to_elf64(ehdr, 0);
|
|
if (phdr[i].p_type == PT_NOTE) {
|
|
phdr[i].p_filesz = cpu_to_elf64(ehdr, note_size);
|
|
phdr[i].p_memsz = cpu_to_elf64(ehdr, note_size);
|
|
phdr[i].p_offset = cpu_to_elf64(ehdr, note_offset);
|
|
} else {
|
|
offset += hdr->p_filesz;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
die("Unknwon elf class: %x\n", ehdr->ei_class);
|
|
}
|
|
}
|
|
|
|
static void write_buf(int fd, char *buf, size_t size)
|
|
{
|
|
size_t progress = 0;
|
|
ssize_t result;
|
|
while(progress < size) {
|
|
result = write(fd, buf + progress, size - progress);
|
|
if (result < 0) {
|
|
if ((errno == EAGAIN) || (errno == EINTR)) {
|
|
continue;
|
|
}
|
|
die ("write of %ld bytes failed: %s\n",
|
|
size - progress, strerror(errno));
|
|
}
|
|
progress += result;
|
|
}
|
|
}
|
|
static void write_elf(struct memelfheader *ehdr, char *output)
|
|
{
|
|
size_t ehdr_size;
|
|
size_t phdr_size;
|
|
size_t note_size;
|
|
size_t size;
|
|
uint16_t checksum;
|
|
size_t bytes;
|
|
char *buf;
|
|
int result, fd;
|
|
int i;
|
|
/* Prep for adding the checksum */
|
|
for(i = 0; i < ehdr->e_notenum; i++) {
|
|
if ((memcmp(ehdr->e_notes[i].n_name, "ELFBoot", 8) == 0) &&
|
|
(ehdr->e_notes[i].n_type == EIN_PROGRAM_CHECKSUM)) {
|
|
ehdr->e_notes[i].n_desc = &checksum;
|
|
ehdr->e_notes[i].n_descsz = 2;
|
|
}
|
|
}
|
|
/* Compute the sizes */
|
|
ehdr_size = 0;
|
|
phdr_size = 0;
|
|
note_size = 0;
|
|
if (ehdr->e_notenum) {
|
|
note_size = sizeof_notes(ehdr->e_notes, ehdr->e_notenum);
|
|
}
|
|
if (ehdr->ei_class == ELFCLASS32) {
|
|
ehdr_size = sizeof(Elf32_Ehdr);
|
|
phdr_size = sizeof(Elf32_Phdr) * ehdr->e_phnum;
|
|
}
|
|
else if (ehdr->ei_class == ELFCLASS64) {
|
|
ehdr_size = sizeof(Elf64_Ehdr);
|
|
phdr_size = sizeof(Elf64_Phdr) * ehdr->e_phnum;
|
|
}
|
|
else {
|
|
die("Unknown elf class: %x\n", ehdr->ei_class);
|
|
}
|
|
|
|
/* Allocate a buffer to temporarily hold the serialized forms */
|
|
size = ehdr_size + phdr_size + note_size;
|
|
buf = xmalloc(size, "Elf Headers");
|
|
memset(buf, 0, size);
|
|
serialize_ehdr(buf, ehdr);
|
|
serialize_phdrs(buf + ehdr_size, ehdr, note_size);
|
|
|
|
/* Compute the checksum... */
|
|
checksum = ipchksum(buf, ehdr_size + phdr_size);
|
|
bytes = ehdr_size + phdr_size;
|
|
for(i = 0; i < ehdr->e_phnum; i++) {
|
|
checksum = add_ipchksums(bytes, checksum,
|
|
ipchksum(ehdr->e_phdr[i].p_data, ehdr->e_phdr[i].p_filesz));
|
|
bytes += ehdr->e_phdr[i].p_memsz;
|
|
}
|
|
|
|
/* Compute the final form of the notes */
|
|
serialize_notes(buf + ehdr_size + phdr_size, ehdr);
|
|
|
|
/* Now write the elf image */
|
|
fd = open(output, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IRGRP | S_IROTH);
|
|
if (fd < 0) {
|
|
die("Cannot open ``%s'':%s\n",
|
|
output, strerror(errno));
|
|
}
|
|
write_buf(fd, buf, size);
|
|
for(i = 0; i < ehdr->e_phnum; i++) {
|
|
write_buf(fd, ehdr->e_phdr[i].p_data, ehdr->e_phdr[i].p_filesz);
|
|
}
|
|
result = close(fd);
|
|
if (result < 0) {
|
|
die("Close on %s failed: %s\n",
|
|
output, strerror(errno));
|
|
}
|
|
}
|
|
|
|
static void version(void)
|
|
{
|
|
printf("mkelfImage " VERSION " released " RELEASE_DATE "\n");
|
|
}
|
|
void usage(void)
|
|
{
|
|
int i;
|
|
version();
|
|
printf(
|
|
"Usage: mkelfImage [OPTION]... <kernel> <elf_kernel>\n"
|
|
"Build an ELF bootable kernel image from a normal kernel image\n"
|
|
"\n"
|
|
" -h, --help Print this help.\n"
|
|
" -v, --version Print the version of kexec.\n"
|
|
" --kernel=<filename> Set the kernel to <filename>\n"
|
|
" --output=<filename> Output to <filename>\n"
|
|
" -t, --type=TYPE Specify the new kernel is of <type>.\n"
|
|
"\n"
|
|
"Supported kernel types: \n"
|
|
);
|
|
for(i = 0; i < file_types; i++) {
|
|
printf("%s\n", file_type[i].name);
|
|
file_type[i].usage();
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
void error(char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vfprintf(stderr, fmt, args);
|
|
va_end(args);
|
|
usage();
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int opt;
|
|
int fileind;
|
|
char *type, *kernel, *output;
|
|
off_t kernel_size;
|
|
char *kernel_buf;
|
|
int result;
|
|
int i;
|
|
struct memelfheader hdr;
|
|
|
|
static const struct option options[] = {
|
|
MKELF_OPTIONS
|
|
{ 0, 0, 0, 0 },
|
|
};
|
|
static const char short_options[] = MKELF_OPT_STR;
|
|
|
|
memset(&hdr, 0, sizeof(hdr));
|
|
kernel = 0;
|
|
output = 0;
|
|
|
|
/* Get the default type from the program name */
|
|
type = strrchr(argv[0], '/');
|
|
if (!type) type = argv[0];
|
|
if (memcmp(type, "mkelf-", 6) == 0) {
|
|
type = type + 6;
|
|
} else {
|
|
type = 0;
|
|
}
|
|
opterr = 0; /* Don't complain about unrecognized options here */
|
|
while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
|
|
switch(opt) {
|
|
case OPT_HELP:
|
|
usage();
|
|
return 0;
|
|
case OPT_VERSION:
|
|
version();
|
|
return 0;
|
|
case OPT_KERNEL:
|
|
kernel = optarg;
|
|
break;
|
|
case OPT_OUTPUT:
|
|
output = optarg;
|
|
break;
|
|
case OPT_TYPE:
|
|
type = optarg;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
fileind = optind;
|
|
|
|
/* Reset getopt for the next pass */
|
|
opterr = 1;
|
|
optind = 1;
|
|
|
|
if (argc - fileind > 0) {
|
|
kernel = argv[fileind++];
|
|
}
|
|
if (argc - fileind > 0) {
|
|
output = argv[fileind++];
|
|
}
|
|
if (!kernel) {
|
|
error("No kernel specified!\n");
|
|
}
|
|
if (!output) {
|
|
error("No output file specified!\n");
|
|
}
|
|
if (argc - fileind > 0) {
|
|
error("%d extra options specified!\n", argc - fileind);
|
|
}
|
|
|
|
/* slurp in the input kernel */
|
|
kernel_buf = slurp_decompress_file(kernel, &kernel_size);
|
|
|
|
/* Find/verify the kernel type */
|
|
for(i = 0; i < file_types; i++) {
|
|
char *reason;
|
|
if (type && (strcmp(type, file_type[i].name) != 0)) {
|
|
continue;
|
|
}
|
|
reason = file_type[i].probe(kernel_buf, kernel_size);
|
|
if (reason == 0) {
|
|
break;
|
|
}
|
|
if (type) {
|
|
die("Not %s: %s\n", type, reason);
|
|
}
|
|
}
|
|
if (i == file_types) {
|
|
die("Can not determine the file type of %s\n", kernel);
|
|
}
|
|
result = file_type[i].mkelf(argc, argv, &hdr, kernel_buf, kernel_size);
|
|
if (result < 0) {
|
|
die("Cannot create %s result: %d\n", output, result);
|
|
}
|
|
/* open the output file */
|
|
write_elf(&hdr, output);
|
|
return 0;
|
|
}
|