|
|
|
@ -3,6 +3,7 @@ |
|
|
|
|
#include "eltorito.h" |
|
|
|
|
#include "volume.h" |
|
|
|
|
#include "util.h" |
|
|
|
|
#include "messages.h" |
|
|
|
|
|
|
|
|
|
#include <assert.h> |
|
|
|
|
#include <malloc.h> |
|
|
|
@ -15,46 +16,6 @@ |
|
|
|
|
#include <fcntl.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct el_torito_validation_entry { |
|
|
|
|
uint8_t header_id BP(1, 1); |
|
|
|
|
uint8_t platform_id BP(2, 2); |
|
|
|
|
uint8_t reserved BP(3, 4); |
|
|
|
|
uint8_t id_string BP(5, 28); |
|
|
|
|
uint8_t checksum BP(29, 30); |
|
|
|
|
uint8_t key_byte1 BP(31, 31); |
|
|
|
|
uint8_t key_byte2 BP(32, 32); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct el_torito_default_entry { |
|
|
|
|
uint8_t boot_indicator BP(1, 1); |
|
|
|
|
uint8_t boot_media_type BP(2, 2); |
|
|
|
|
uint8_t load_seg BP(3, 4); |
|
|
|
|
uint8_t system_type BP(5, 5); |
|
|
|
|
uint8_t unused1 BP(6, 6); |
|
|
|
|
uint8_t sec_count BP(7, 8); |
|
|
|
|
uint8_t block BP(9, 12); |
|
|
|
|
uint8_t unused2 BP(13, 32); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct el_torito_section_header_entry { |
|
|
|
|
uint8_t header_indicator BP(1, 1); |
|
|
|
|
uint8_t platform_id BP(2, 2); |
|
|
|
|
uint8_t number BP(3, 4); |
|
|
|
|
uint8_t character BP(5, 32); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct el_torito_section_entry { |
|
|
|
|
uint8_t boot_indicator BP(1, 1); |
|
|
|
|
uint8_t boot_media_type BP(2, 2); |
|
|
|
|
uint8_t load_seg BP(3, 4); |
|
|
|
|
uint8_t system_type BP(5, 5); |
|
|
|
|
uint8_t unused1 BP(6, 6); |
|
|
|
|
uint8_t sec_count BP(7, 8); |
|
|
|
|
uint8_t block BP(9, 12); |
|
|
|
|
uint8_t selec_criteria BP(13, 13); |
|
|
|
|
uint8_t vendor_sc BP(14, 32); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This table should be written with accuracy values at offset |
|
|
|
|
* 8 of boot image, when used ISOLINUX boot loader |
|
|
|
@ -85,18 +46,67 @@ struct hard_disc_mbr { |
|
|
|
|
uint8_t sign2; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
el_torito_image_free(struct el_torito_boot_image *image) |
|
|
|
|
{ |
|
|
|
|
assert(image); |
|
|
|
|
|
|
|
|
|
/* unref image node */ |
|
|
|
|
iso_tree_free((struct iso_tree_node*)image->node); |
|
|
|
|
free(image); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct iso_tree_node_boot* |
|
|
|
|
create_boot_image_node(struct iso_tree_node_file *image) |
|
|
|
|
{ |
|
|
|
|
struct iso_tree_node_boot *boot; |
|
|
|
|
struct iso_tree_node_dir *parent; |
|
|
|
|
|
|
|
|
|
assert(image); |
|
|
|
|
|
|
|
|
|
boot = calloc(1, sizeof(struct iso_tree_node_boot)); |
|
|
|
|
boot->node.attrib = image->node.attrib; |
|
|
|
|
boot->node.type = LIBISO_NODE_BOOT; |
|
|
|
|
boot->node.name = strdup(image->node.name); |
|
|
|
|
boot->node.hide_flags = image->node.hide_flags; |
|
|
|
|
boot->node.refcount = 2; /* mine and tree */ |
|
|
|
|
boot->loc.path = strdup(image->loc.path); |
|
|
|
|
boot->img = 1; /* it refers to image */ |
|
|
|
|
|
|
|
|
|
/* replace iso_tree_node_file with the image */ |
|
|
|
|
parent = image->node.parent; |
|
|
|
|
iso_tree_node_remove(parent, (struct iso_tree_node*)image); |
|
|
|
|
iso_tree_add_child(parent, (struct iso_tree_node*) boot); |
|
|
|
|
|
|
|
|
|
return boot; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct el_torito_boot_image * |
|
|
|
|
create_image(struct iso_tree_node *image,
|
|
|
|
|
create_image(const char *path,
|
|
|
|
|
enum eltorito_boot_media_type type) |
|
|
|
|
{ |
|
|
|
|
struct stat attrib; |
|
|
|
|
struct el_torito_boot_image *boot; |
|
|
|
|
int boot_media_type = 0; |
|
|
|
|
int load_sectors = 0; /* number of sector to load */ |
|
|
|
|
unsigned char partition_type = 0; |
|
|
|
|
|
|
|
|
|
if (stat(path, &attrib)) { |
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't access file."); |
|
|
|
|
libisofs_errno = NO_FILE; |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( !S_ISREG(attrib.st_mode) ) { |
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
|
|
|
|
|
"We can only create boot images from regular files"); |
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE; |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch (type) { |
|
|
|
|
case ELTORITO_FLOPPY_EMUL: |
|
|
|
|
switch (image->attrib.st_size) { |
|
|
|
|
switch (attrib.st_size) { |
|
|
|
|
case 1200 * 1024: |
|
|
|
|
boot_media_type = 1; /* 1.2 meg diskette */ |
|
|
|
|
break; |
|
|
|
@ -107,10 +117,14 @@ create_image(struct iso_tree_node *image, |
|
|
|
|
boot_media_type = 3; /* 2.88 meg diskette */ |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
fprintf(stderr, "Invalid image size %d Kb. Must be one of 1.2, 1.44" |
|
|
|
|
"or 2.88 Mb", (int) image->attrib.st_size / 1024); |
|
|
|
|
{ |
|
|
|
|
char msg[72]; |
|
|
|
|
sprintf(msg, "Invalid image size %d Kb. Must be one of 1.2, 1.44" |
|
|
|
|
"or 2.88 Mb", (int) attrib.st_size / 1024); |
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, msg); |
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE_SIZE; |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
break;
|
|
|
|
|
} |
|
|
|
|
/* it seems that for floppy emulation we need to load
|
|
|
|
@ -125,13 +139,16 @@ create_image(struct iso_tree_node *image, |
|
|
|
|
int used_partition; |
|
|
|
|
|
|
|
|
|
/* read the MBR on disc and get the type of the partition */ |
|
|
|
|
fd = open(((struct iso_tree_node_file*)image)->loc.path, O_RDONLY); |
|
|
|
|
fd = open(path, O_RDONLY); |
|
|
|
|
if ( fd == -1 ) { |
|
|
|
|
fprintf(stderr, "Can't open image file\n"); |
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't open image file."); |
|
|
|
|
libisofs_errno = NO_READ_ACCESS; |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
if ( read(fd, &mbr, sizeof(mbr)) ) { |
|
|
|
|
fprintf(stderr, "Can't read MBR from image file\n"); |
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
|
|
|
|
|
"Can't read MBR from image file."); |
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE; |
|
|
|
|
close(fd); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
@ -139,7 +156,9 @@ create_image(struct iso_tree_node *image, |
|
|
|
|
|
|
|
|
|
/* check valid MBR signature */ |
|
|
|
|
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) { |
|
|
|
|
fprintf(stderr, "Invalid MBR. Wrong signature.\n"); |
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
|
|
|
|
|
"Invalid MBR. Wrong signature."); |
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE; |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -149,8 +168,11 @@ create_image(struct iso_tree_node *image, |
|
|
|
|
if (mbr.partition[i].type != 0) { |
|
|
|
|
/* it's an used partition */ |
|
|
|
|
if (used_partition != -1) { |
|
|
|
|
fprintf(stderr, "Invalid MBR. At least 2 partitions: %d and "
|
|
|
|
|
char msg[72]; |
|
|
|
|
sprintf(msg, "Invalid MBR. At least 2 partitions: %d and "
|
|
|
|
|
"%d, are being used\n", used_partition, i); |
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, msg); |
|
|
|
|
libisofs_errno = ELTORITO_WRONG_IMAGE; |
|
|
|
|
return NULL; |
|
|
|
|
} else |
|
|
|
|
used_partition = i; |
|
|
|
@ -170,67 +192,180 @@ create_image(struct iso_tree_node *image, |
|
|
|
|
|
|
|
|
|
boot = calloc(1, sizeof(struct el_torito_boot_image)); |
|
|
|
|
boot->bootable = 1; |
|
|
|
|
boot->image = (struct iso_tree_node_file *) image; |
|
|
|
|
boot->type = boot_media_type; |
|
|
|
|
boot->load_size = load_sectors; |
|
|
|
|
boot->partition_type = partition_type; |
|
|
|
|
return boot; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct iso_tree_node_boot_catalog* |
|
|
|
|
/* parent and name can be null */ |
|
|
|
|
static struct iso_tree_node_boot* |
|
|
|
|
create_boot_catalog_node(struct iso_tree_node_dir *parent,
|
|
|
|
|
const char *name) |
|
|
|
|
{ |
|
|
|
|
struct iso_tree_node_boot_catalog *boot; |
|
|
|
|
struct iso_tree_node_boot *boot; |
|
|
|
|
|
|
|
|
|
assert( parent && name ); |
|
|
|
|
assert( (parent && name) || (!parent && !name) ); |
|
|
|
|
|
|
|
|
|
boot = calloc(1, sizeof(struct iso_tree_node_boot_catalog)); |
|
|
|
|
boot = calloc(1, sizeof(struct iso_tree_node_boot)); |
|
|
|
|
boot->node.attrib.st_mode = S_IFREG | 0444; |
|
|
|
|
boot->node.attrib.st_atime =
|
|
|
|
|
boot->node.attrib.st_mtime =
|
|
|
|
|
boot->node.attrib.st_ctime = time(NULL); |
|
|
|
|
boot->node.type = LIBISO_NODE_BOOTCATALOG; |
|
|
|
|
boot->node.name = strdup(name); |
|
|
|
|
iso_tree_add_child(parent, (struct iso_tree_node*) boot); |
|
|
|
|
boot->node.attrib.st_size = 2048; |
|
|
|
|
boot->node.type = LIBISO_NODE_BOOT; |
|
|
|
|
boot->node.name = name ? strdup(name) : NULL; |
|
|
|
|
boot->node.refcount = 1; /* mine */ |
|
|
|
|
if (parent) { |
|
|
|
|
boot->node.refcount++; /* add tree ref */ |
|
|
|
|
iso_tree_add_child(parent, (struct iso_tree_node*) boot); |
|
|
|
|
} |
|
|
|
|
return boot; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct el_torito_boot_image * |
|
|
|
|
iso_volume_create_boot_catalog(struct iso_volume *volume,
|
|
|
|
|
struct iso_tree_node *image, |
|
|
|
|
enum eltorito_boot_media_type type, |
|
|
|
|
struct iso_tree_node_dir *dir,
|
|
|
|
|
char *name) |
|
|
|
|
struct el_torito_boot_image* |
|
|
|
|
iso_volume_set_boot_image(struct iso_volume *volume,
|
|
|
|
|
struct iso_tree_node *image, |
|
|
|
|
enum eltorito_boot_media_type type, |
|
|
|
|
struct iso_tree_node_dir *dir,
|
|
|
|
|
char *name) |
|
|
|
|
{ |
|
|
|
|
struct el_torito_boot_image *boot_image; |
|
|
|
|
struct iso_tree_node_boot *cat_node; |
|
|
|
|
struct el_torito_boot_catalog *catalog; |
|
|
|
|
struct iso_tree_node_file *imgfile; |
|
|
|
|
|
|
|
|
|
assert(volume && !volume->bootcat); |
|
|
|
|
assert(image && ISO_ISREG(image)); |
|
|
|
|
assert(dir && name); |
|
|
|
|
|
|
|
|
|
imgfile = (struct iso_tree_node_file*)image; |
|
|
|
|
|
|
|
|
|
if (image->procedence == LIBISO_PREVIMG) { |
|
|
|
|
/* FIXME mmm, what to do here? */ |
|
|
|
|
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't use prev. image files " |
|
|
|
|
"as boot images"); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
boot_image = create_image(imgfile->loc.path, type); |
|
|
|
|
if ( !boot_image )
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
/* create image node */ |
|
|
|
|
boot_image->node = create_boot_image_node(imgfile); |
|
|
|
|
|
|
|
|
|
/* creates the catalog with the given default image */ |
|
|
|
|
catalog = malloc(sizeof(struct el_torito_boot_catalog)); |
|
|
|
|
if (!catalog) { |
|
|
|
|
el_torito_image_free(boot_image); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
catalog->image = boot_image; |
|
|
|
|
|
|
|
|
|
/* add catalog file */ |
|
|
|
|
cat_node = create_boot_catalog_node(dir, name); |
|
|
|
|
catalog->node = cat_node; |
|
|
|
|
|
|
|
|
|
volume->bootcat = catalog; |
|
|
|
|
|
|
|
|
|
return boot_image; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct el_torito_boot_image*
|
|
|
|
|
iso_volume_set_boot_image_hidden(struct iso_volume *volume, const char* path, |
|
|
|
|
enum eltorito_boot_media_type type) |
|
|
|
|
{ |
|
|
|
|
struct el_torito_boot_image *boot_image; |
|
|
|
|
struct iso_tree_node_boot_catalog *boot_node; |
|
|
|
|
struct iso_tree_node_boot *cat_node; |
|
|
|
|
struct el_torito_boot_catalog *catalog; |
|
|
|
|
|
|
|
|
|
assert( volume && !volume->bootcat); |
|
|
|
|
assert( image && ISO_ISREG(image) && dir && name); |
|
|
|
|
assert(volume && !volume->bootcat); |
|
|
|
|
assert(path); |
|
|
|
|
|
|
|
|
|
boot_image = create_image(image, type); |
|
|
|
|
boot_image = create_image(path, type); |
|
|
|
|
if ( !boot_image )
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
/* create image node */ |
|
|
|
|
{ |
|
|
|
|
struct iso_tree_node_boot *boot; |
|
|
|
|
boot = calloc(1, sizeof(struct iso_tree_node_boot)); |
|
|
|
|
/* we assume the stat won't fail, as we already stat the same file above */ |
|
|
|
|
stat(path, &boot->node.attrib); |
|
|
|
|
boot->node.type = LIBISO_NODE_BOOT; |
|
|
|
|
boot->node.refcount = 1; /* mine */ |
|
|
|
|
boot->loc.path = strdup(path); |
|
|
|
|
boot->img = 1; /* it refers to image */ |
|
|
|
|
boot_image->node = boot; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* creates the catalog with the given default image */ |
|
|
|
|
catalog = malloc(sizeof(struct el_torito_boot_catalog)); |
|
|
|
|
catalog->nentries = 1; |
|
|
|
|
catalog->entries = malloc(sizeof(struct el_torito_boot_image *)); |
|
|
|
|
catalog->entries[0] = boot_image; |
|
|
|
|
catalog->file = malloc(sizeof(struct iso_file)); |
|
|
|
|
catalog->file->size = 2048; |
|
|
|
|
if (!catalog) { |
|
|
|
|
el_torito_image_free(boot_image); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
catalog->image = boot_image; |
|
|
|
|
|
|
|
|
|
/* add catalog file */ |
|
|
|
|
boot_node = create_boot_catalog_node(dir, name); |
|
|
|
|
boot_node->catalog = catalog; |
|
|
|
|
cat_node = create_boot_catalog_node(NULL, NULL); |
|
|
|
|
catalog->node = cat_node; |
|
|
|
|
|
|
|
|
|
volume->bootcat = catalog; |
|
|
|
|
|
|
|
|
|
return boot_image; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct el_torito_boot_image* |
|
|
|
|
iso_volume_get_boot_image(struct iso_volume *volume, |
|
|
|
|
struct iso_tree_node **imgnode, |
|
|
|
|
struct iso_tree_node **catnode) |
|
|
|
|
{ |
|
|
|
|
struct el_torito_boot_catalog *catalog; |
|
|
|
|
|
|
|
|
|
assert(volume); |
|
|
|
|
|
|
|
|
|
catalog = volume->bootcat; |
|
|
|
|
if (!catalog) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
if (imgnode) |
|
|
|
|
*imgnode = (struct iso_tree_node*)catalog->image->node; |
|
|
|
|
|
|
|
|
|
if (catnode) |
|
|
|
|
*catnode = (struct iso_tree_node*)catalog->node; |
|
|
|
|
|
|
|
|
|
return catalog->image; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
iso_volume_remove_boot_image(struct iso_volume *volume) |
|
|
|
|
{ |
|
|
|
|
struct el_torito_boot_catalog *catalog; |
|
|
|
|
struct iso_tree_node *catnode; |
|
|
|
|
struct iso_tree_node *imgnode; |
|
|
|
|
assert(volume); |
|
|
|
|
|
|
|
|
|
catalog = volume->bootcat; |
|
|
|
|
if (!catalog) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
/* remove node from tree */ |
|
|
|
|
catnode = (struct iso_tree_node*)catalog->node; |
|
|
|
|
if (catnode->parent) |
|
|
|
|
iso_tree_node_remove(catnode->parent, catnode); |
|
|
|
|
|
|
|
|
|
/* remove image from tree */ |
|
|
|
|
imgnode = (struct iso_tree_node*)catalog->image->node; |
|
|
|
|
if (imgnode->parent) |
|
|
|
|
iso_tree_node_remove(imgnode->parent, imgnode); |
|
|
|
|
|
|
|
|
|
/* remove catalog */ |
|
|
|
|
el_torito_boot_catalog_free(catalog); |
|
|
|
|
volume->bootcat = NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment) |
|
|
|
|
{ |
|
|
|
@ -254,43 +389,20 @@ el_torito_set_no_bootable(struct el_torito_boot_image *bootimg) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg) |
|
|
|
|
el_torito_patch_isolinux_image(struct el_torito_boot_image *bootimg) |
|
|
|
|
{ |
|
|
|
|
bootimg->patch_isolinux = 1; |
|
|
|
|
bootimg->isolinux = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat) |
|
|
|
|
{ |
|
|
|
|
size_t i; |
|
|
|
|
|
|
|
|
|
assert(cat); |
|
|
|
|
|
|
|
|
|
for(i = 0; i < cat->nentries; ++i) { |
|
|
|
|
free(cat->entries[i]); |
|
|
|
|
} |
|
|
|
|
free(cat->entries); |
|
|
|
|
free(cat->file); |
|
|
|
|
el_torito_image_free(cat->image); |
|
|
|
|
iso_tree_free((struct iso_tree_node*)cat->node); |
|
|
|
|
free(cat); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void el_torito_get_image_files(struct ecma119_write_target *t) |
|
|
|
|
{ |
|
|
|
|
size_t i; |
|
|
|
|
struct el_torito_boot_catalog *cat = t->catalog; |
|
|
|
|
assert(cat); |
|
|
|
|
|
|
|
|
|
for(i = 0; i < cat->nentries; ++i) { |
|
|
|
|
|
|
|
|
|
struct iso_tree_node_file *image = cat->entries[i]->image; |
|
|
|
|
struct iso_file *file = iso_file_table_lookup(t->file_table, image); |
|
|
|
|
if ( file == NULL ) { |
|
|
|
|
file = iso_file_new(image); |
|
|
|
|
iso_file_table_add_file(t->file_table, file); |
|
|
|
|
} |
|
|
|
|
cat->entries[i]->file = file; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write the Boot Record Volume Descriptor |
|
|
|
|
*/ |
|
|
|
@ -307,7 +419,7 @@ el_torito_write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf) |
|
|
|
|
memcpy(vol->std_identifier, "CD001", 5); |
|
|
|
|
vol->vol_desc_version[0] = 1; |
|
|
|
|
memcpy(vol->boot_sys_id, "EL TORITO SPECIFICATION", 23); |
|
|
|
|
iso_lsb(vol->boot_catalog, cat->file->block, 4); |
|
|
|
|
iso_lsb(vol->boot_catalog, t->catblock, 4); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
@ -333,104 +445,139 @@ write_validation_entry(struct ecma119_write_target *t, uint8_t *buf) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
patch_boot_file(struct el_torito_boot_image *img) |
|
|
|
|
patch_boot_image(uint8_t *buf, struct ecma119_write_target *t, ssize_t imgsize) |
|
|
|
|
{ |
|
|
|
|
struct boot_info_table info; |
|
|
|
|
int fd; |
|
|
|
|
struct boot_info_table *info; |
|
|
|
|
uint32_t checksum; |
|
|
|
|
ssize_t len; |
|
|
|
|
uint8_t buf[4]; |
|
|
|
|
ssize_t offset; |
|
|
|
|
|
|
|
|
|
memset(&info, 0, sizeof(info)); |
|
|
|
|
|
|
|
|
|
/* open image */ |
|
|
|
|
fd = open(img->image->loc.path, O_RDWR); |
|
|
|
|
if ( fd == -1 ) { |
|
|
|
|
//TODO what do do? exit or just continue?
|
|
|
|
|
fprintf(stderr, "Can't patch boot image %s\n", img->image->loc.path); |
|
|
|
|
close(fd); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* compute checksum, as the the sum of all 32 bit words in boot image
|
|
|
|
|
* from offset 64 */ |
|
|
|
|
checksum = 0; |
|
|
|
|
lseek(fd, (off_t) 64, SEEK_SET); |
|
|
|
|
offset = (ssize_t) 64; |
|
|
|
|
|
|
|
|
|
//TODO this can (must) be optimizied by reading to a longer buffer
|
|
|
|
|
while ( (len = read(fd, buf, 4) ) == 4 ) { |
|
|
|
|
checksum += iso_read_lsb(buf, 4); |
|
|
|
|
while (offset < imgsize) { |
|
|
|
|
checksum += iso_read_lsb(buf + offset, 4); |
|
|
|
|
offset += 4; |
|
|
|
|
} |
|
|
|
|
if ( len != 0 ) { |
|
|
|
|
/* error reading file, or file length not multiple of 4 */ |
|
|
|
|
//TODO what do do? exit or just continue?
|
|
|
|
|
fprintf(stderr, "Can't patch boot image %s\n", img->image->loc.path); |
|
|
|
|
close(fd); |
|
|
|
|
return; |
|
|
|
|
if (offset != imgsize) { |
|
|
|
|
/* file length not multiple of 4 */ |
|
|
|
|
iso_msg_warn(LIBISO_ISOLINUX_CANT_PATCH,
|
|
|
|
|
"Unexpected isolinux image length. Patch might not work."); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* fill boot info table */ |
|
|
|
|
iso_lsb(info.bi_pvd, 16, 4); //FIXME this should be changed when we implement ms
|
|
|
|
|
iso_lsb(info.bi_file, img->file->block, 4); |
|
|
|
|
iso_lsb(info.bi_length, img->image->node.attrib.st_size, 4); |
|
|
|
|
iso_lsb(info.bi_csum, checksum, 4); |
|
|
|
|
|
|
|
|
|
/* patch file */ |
|
|
|
|
lseek(fd, (off_t) 8, SEEK_SET); |
|
|
|
|
write(fd, &info, sizeof(info)); |
|
|
|
|
|
|
|
|
|
close(fd); |
|
|
|
|
}
|
|
|
|
|
/* patch boot info table */ |
|
|
|
|
info = (struct boot_info_table*)(buf + 8); |
|
|
|
|
memset(info, 0, sizeof(struct boot_info_table)); |
|
|
|
|
iso_lsb(info->bi_pvd, t->ms_block + 16, 4); |
|
|
|
|
iso_lsb(info->bi_file, t->imgblock, 4); |
|
|
|
|
iso_lsb(info->bi_length, imgsize, 4); |
|
|
|
|
iso_lsb(info->bi_csum, checksum, 4); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
el_torito_patch_image_files(struct ecma119_write_target *t) |
|
|
|
|
static void |
|
|
|
|
write_boot_image(uint8_t *buf, struct ecma119_write_target *t) |
|
|
|
|
{ |
|
|
|
|
size_t i; |
|
|
|
|
struct el_torito_boot_catalog *cat = t->catalog; |
|
|
|
|
assert(cat); |
|
|
|
|
ssize_t imgsize; |
|
|
|
|
struct el_torito_boot_image *image; |
|
|
|
|
|
|
|
|
|
image = t->catalog->image; |
|
|
|
|
imgsize= image->node->node.attrib.st_size; |
|
|
|
|
|
|
|
|
|
/* copy image contents to memory buffer */ |
|
|
|
|
if (image->node->node.procedence == LIBISO_PREVIMG) { |
|
|
|
|
int block, nblocks; |
|
|
|
|
uint8_t *memloc; |
|
|
|
|
assert(t->src); |
|
|
|
|
|
|
|
|
|
block = 0; |
|
|
|
|
memloc = buf; |
|
|
|
|
nblocks = imgsize ? div_up(imgsize, 2048) : 1; |
|
|
|
|
while (block < nblocks) { |
|
|
|
|
if (t->src->read_block(t->src,
|
|
|
|
|
image->node->loc.block + block, memloc)) { |
|
|
|
|
iso_msg_sorry(LIBISO_CANT_READ_IMG, |
|
|
|
|
"Unable to read boot image from previous image."); |
|
|
|
|
break; /* exit loop */ |
|
|
|
|
} |
|
|
|
|
memloc += 2048; |
|
|
|
|
++block; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
int fd; |
|
|
|
|
ssize_t nread, tread; |
|
|
|
|
uint8_t *memloc; |
|
|
|
|
const char *path = image->node->loc.path; |
|
|
|
|
memloc = buf; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < cat->nentries; ++i) { |
|
|
|
|
struct el_torito_boot_image *img = cat->entries[i]; |
|
|
|
|
if ( img->patch_isolinux ) |
|
|
|
|
patch_boot_file(img); |
|
|
|
|
fd = open(path, O_RDONLY); |
|
|
|
|
if (fd == -1) { |
|
|
|
|
iso_msg_sorry(LIBISO_CANT_READ_FILE,
|
|
|
|
|
"Can't open boot image file for reading. Skipping"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tread = 0; |
|
|
|
|
while (tread < imgsize) { |
|
|
|
|
nread = read(fd, memloc, t->block_size); |
|
|
|
|
if (nread <= 0) { |
|
|
|
|
iso_msg_sorry(LIBISO_CANT_READ_FILE,
|
|
|
|
|
"Problem reading boot image file. Skipping"); |
|
|
|
|
break; /* exit loop */ |
|
|
|
|
} |
|
|
|
|
tread += nread; |
|
|
|
|
memloc += nread; |
|
|
|
|
} |
|
|
|
|
close(fd); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (image->isolinux) { |
|
|
|
|
/* we need to patch the image */ |
|
|
|
|
patch_boot_image(buf, t, imgsize); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write one section entry. |
|
|
|
|
* Currently this is used for both default and other entries since we |
|
|
|
|
* put selection criteria no 0 (no sel. criteria) |
|
|
|
|
* Currently this is used only for default image (the only supported just now) |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
write_section_entry(uint8_t *buf, struct el_torito_boot_image *img) |
|
|
|
|
write_section_entry(uint8_t *buf, struct ecma119_write_target *t) |
|
|
|
|
{ |
|
|
|
|
struct el_torito_boot_image *img; |
|
|
|
|
struct el_torito_section_entry *se =
|
|
|
|
|
(struct el_torito_section_entry*)buf; |
|
|
|
|
|
|
|
|
|
img = t->catalog->image; |
|
|
|
|
|
|
|
|
|
assert(img); |
|
|
|
|
|
|
|
|
|
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00; |
|
|
|
|
se->boot_media_type[0] = img->type; |
|
|
|
|
iso_lsb(se->load_seg, img->load_seg, 2); |
|
|
|
|
se->system_type[0] = 0; //TODO need to get the partition type
|
|
|
|
|
se->system_type[0] = img->partition_type; |
|
|
|
|
iso_lsb(se->sec_count, img->load_size, 2); |
|
|
|
|
iso_lsb(se->block, img->file->block, 4); |
|
|
|
|
iso_lsb(se->block, t->imgblock, 4); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write El-Torito Boot Catalog |
|
|
|
|
* Write El-Torito Boot Catalog plus image |
|
|
|
|
*/ |
|
|
|
|
static void |
|
|
|
|
write_catalog(struct ecma119_write_target *t, uint8_t *buf) |
|
|
|
|
{ |
|
|
|
|
struct el_torito_boot_catalog *cat = t->catalog; |
|
|
|
|
assert(cat); |
|
|
|
|
assert(cat->nentries >= 1 && cat->nentries < 63); |
|
|
|
|
assert(cat->image); |
|
|
|
|
|
|
|
|
|
write_validation_entry(t, buf); |
|
|
|
|
|
|
|
|
|
/* write default entry */ |
|
|
|
|
write_section_entry(buf + 32, cat->entries[0]); |
|
|
|
|
write_section_entry(buf + 32, t); |
|
|
|
|
|
|
|
|
|
//TODO write all images
|
|
|
|
|
write_boot_image(buf + 2048, t); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
@ -446,9 +593,27 @@ el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf) |
|
|
|
|
void |
|
|
|
|
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf) |
|
|
|
|
{ |
|
|
|
|
off_t size; |
|
|
|
|
off_t imgsize; |
|
|
|
|
assert(t->catalog); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Note that when this is called, we need to write el-torito info to |
|
|
|
|
* image. Note, however, that the image could come from a previous session |
|
|
|
|
* and maybe we don't know its size |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
imgsize = t->catalog->image->node->node.attrib.st_size; |
|
|
|
|
if (imgsize == 0) { |
|
|
|
|
iso_msg_warn(LIBISO_EL_TORITO_BLIND_COPY, |
|
|
|
|
"Can get boot image size, only one block will be copied"); |
|
|
|
|
imgsize = 2048; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
size = 2048 + div_up(imgsize, t->block_size); |
|
|
|
|
|
|
|
|
|
ecma119_start_chunking(t, |
|
|
|
|
write_catalog, |
|
|
|
|
2048, |
|
|
|
|
size, |
|
|
|
|
buf); |
|
|
|
|
} |
|
|
|
|