[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[debian-knoppix] ANNOUNCE: Tool for customizing Knoppix ISO-image before burning w/o remastering



Hi,

Due to high demand I am releasing my current development version of
the knoppix-customize tool. This version is still alpha and intended
for developers. License: GPL. Language ANSI-C.

Build:
  make knoppix-customize

Documentation:
  ./knoppix-customize --help

Examples:

List files in the boot-floppy (you can specify a 1.44MB boot floppy or
the 700 MB ISO-Image):
  knoppix-customize --image boot.img --action list

Copy the file syslinux.cfg from the floppy or iso-image to a local file:
  knoppix-customize --image boot.img --action export_file --image_file syslinux.cfg --local_file syslinux.cfg

Now you may edit syslinux.cfg. Make sure the size doesn't change!
(Some editors may add newlines)

Copy the local file you just edited into the image:
  knoppix-customize --image boot.img --action import_file --image_file syslinux.cfg --local_file syslinux.cfg

You may also exchange other files like the kbdmap or the boot message screen.


2002-10-23 Kester Habermann <kester@linuxtag.org>
-- 
Kester Habermann <kester@linuxtag.org>               LinuxTag 2002
http://www.linuxtag.org/ Tel: +49.631.3109371 Fax: +49.631.3109372
/* ----------------------------------------------------------------------- *
 *
 *   Copyright 2002 Kester Habermann - All Rights Reserved
 *   2002-08-30 Kester Habermann <kester@linuxtag.org>         
 *   Time-stamp: <2002-10-11 11:50:33 kester>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
 *   USA; either version 2 of the License, or (at your option) any later
 *   version; incorporated herein by reference.
 *
 * ----------------------------------------------------------------------- */

// TOOD:
//   - test if sizes are ok
//   - proper header for all error messages
//   - copyright, version, author info
//   - multi languages
//   - renaming of files (to remember which kbd map is used)
//   - clean up output for verbose
//   - action to replace complete boot floppy image 8read blockwise)
//   - shortcuts:
//     * edit boot options for userdef and set userdef as defaults
//     * set boot options for userdef
//     * set default boot
//     * change language (lang=xx + userdef default), keyboard-file, help-file

//   - add URL for El-Torito and FAT-Specification

// BUGs
//   - if given FAT name st longer than 8+3 chars it is truncated 
//     (should give error)


#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <libgen.h>

// Sector size for FAT12 and FAT16
#define FAT_SECTOR_SIZE                  0x200
#define FLOPPY_BOOT_SECTOR               (1* FAT_SECTOR_SIZE)

#define CD_SECTOR_SIZE                   0x800
#define CD_BOOT_RECORD_VOLUME_DESCRIPTOR (1 * CD_SECTOR_SIZE)
#define CD_BOOT_CAT_BUFFER               (1 * CD_SECTOR_SIZE)
// Boot-Disc Types
// Sides * Tracks * Sectors/Track * Bytes/Block
#define BOOT_IMG_BUFFER_1_2              (2 * 15 * 80 * 512)
#define BOOT_IMG_BUFFER_1_44             (2 * 18 * 80 * 512)
#define BOOT_IMG_BUFFER_2_88             (2 * 36 * 80 * 512)

#define FLOPPY_1_2                       "1.2 MB diskette"
#define FLOPPY_1_44                      "1.44 MB diskette"
#define FLOPPY_2_88                      "2.88 MB diskette"
#define ISO_9660_IDENTIFIER              "CD001"
#define CD_BOOT_SYSTEM_INDENTIFIER       "EL TORITO SPECIFICATION"
#define MANUFACTOR_MAXLEN                 24

#define FAT_FILENAME_LENGTH               11
#define FAT_ENTRY_SIZE                    32

#define MAX_PATH_LEN                      1024

// one directory entry
struct dir_entry_t {
    unsigned char name[FAT_FILENAME_LENGTH + 1];
    long pos;
    long size;
};

// important data from boot floppy
struct boot_floppy_t {
    long boot_img_offset;
    size_t boot_img_size;
    int FirstRootDirSecNum;
    int BytesPerCluster;
    struct dir_entry_t *fat_root_dir;
    int fat_root_dir_size;
};

// Global variables
int opt_verbose = 0;

int find_boot_image(FILE *fh, struct stat stat_buf, struct boot_floppy_t *boot_floppy) {
    unsigned char *floppy_boot_sector;    // buffer for boot record volume descriptor
    unsigned char *cd_boot_rvd;           // buffer for boot record volume descriptor
    unsigned char *cd_boot_cat;           // buffer for boot catalog
    char cd_manufactor[MANUFACTOR_MAXLEN];
    long cd_boot_cat_ptr;
    long cd_boot_img_ptr;

    // allocate read_buffer for reading boot record volume descriptor
    if ((cd_boot_rvd = malloc((size_t) (CD_BOOT_RECORD_VOLUME_DESCRIPTOR))) == NULL) {
        fprintf(stderr, "Error mallocing CD boot record volume descriptor\n");
        return 0;
    }

    // allocate read_buffer for reading boot catalog
    if ((cd_boot_cat = malloc((size_t) (CD_BOOT_CAT_BUFFER))) == NULL) {
        fprintf(stderr, "Error mallocing CD boot cat buffer\n");
        return 0;
    }

    // allocate read_buffer for reading floppy boot sector
    if ((floppy_boot_sector = malloc((size_t) (FLOPPY_BOOT_SECTOR))) == NULL) {
        fprintf(stderr, "Error mallocing floppy boot sector buffer\n");
        return 0;
    }

    // read first sectors of size FAT_SECTOR, to see if it's FAT
    if (fread(((void *) floppy_boot_sector),
              (size_t) FLOPPY_BOOT_SECTOR,
              (size_t) 1,
              fh) < 1) {
        fprintf(stderr, "Error reading first sector from image\n");
        return 0;
    }

    // Test whether image ist FAT, this is the case if someone chooses
    // to only modify a boot disk and not the whole book image
    // Search for FAT-Magic 0x55AA

    if (floppy_boot_sector[0x1fe] == 0x55 && floppy_boot_sector[0x1ff] == 0xAA) {
        if (opt_verbose) printf("Image is FAT, assuming floppy\n");
        boot_floppy->boot_img_offset = 0;
        // find out actual size of disk image
        switch (stat_buf.st_size) {
            case BOOT_IMG_BUFFER_1_2:  if (opt_verbose) printf("Image is %s\n", FLOPPY_1_2);
                                       boot_floppy->boot_img_size = BOOT_IMG_BUFFER_1_2;
                                       break;

            case BOOT_IMG_BUFFER_1_44: if (opt_verbose) printf("Image is %s\n", FLOPPY_1_44);
                                       boot_floppy->boot_img_size = BOOT_IMG_BUFFER_1_44;
                                       break;

            case BOOT_IMG_BUFFER_2_88: if (opt_verbose) printf("Image is %s\n", FLOPPY_2_88);
                                       boot_floppy->boot_img_size = BOOT_IMG_BUFFER_2_88;
                                       break;

            default:                   fprintf(stderr, "Invalid disk image size (%d)\n", stat_buf.st_size);
                                       return 0;
                                       break;
        }
        return 1;
    } 

    //
    // Read CD-Image
    //
    if (opt_verbose) printf("Image is not FAT, assuming ISO\n");
    // read boot volume descriptor
    if (fseek(fh, (long) (0x11 * CD_SECTOR_SIZE), SEEK_SET) != 0) {
        fprintf(stderr, "Error seeking into file\n");
        return 0;
    }
    
    if (fread(((void *) cd_boot_rvd),
              (size_t) CD_BOOT_RECORD_VOLUME_DESCRIPTOR,
              (size_t) 1,
              fh) < 1) {
        fprintf(stderr, "Error reading cd boot volume descriptor\n");
        return 0;
    }
    
    if (cd_boot_rvd[0x00] != 0) {
        fprintf(stderr, "Invalid CD Boot Record Indicator\n");
        return 0;
    }
    
    if (strncmp(cd_boot_rvd + 0x01, ISO_9660_IDENTIFIER, (size_t) sizeof(ISO_9660_IDENTIFIER) != 0)) {
        fprintf(stderr, "Not ISO 9660 image\n");
        return 0;
    }
    
    if (strncmp(cd_boot_rvd + 0x07, CD_BOOT_SYSTEM_INDENTIFIER, (size_t) sizeof(CD_BOOT_SYSTEM_INDENTIFIER) != 0)) {
        fprintf(stderr, "Not El Torito Bootable\n");
        return 0;
    }  
    
    cd_boot_cat_ptr =   ( cd_boot_rvd[0x47 + 3] << 24 )
                      + ( cd_boot_rvd[0x47 + 2] << 16 )
                      + ( cd_boot_rvd[0x47 + 1] <<  8 )
                      + ( cd_boot_rvd[0x47 + 0]       );
    
    if (opt_verbose) printf("boot cat ptr: 0x%.8x x 0x800 (0x%.8x)\n", cd_boot_cat_ptr, CD_SECTOR_SIZE * cd_boot_cat_ptr);
    
    // seek to boot catalog
    fseek(fh, (long) CD_SECTOR_SIZE * cd_boot_cat_ptr, SEEK_SET);
    
    if (!(fread(((void *) cd_boot_cat),
                (size_t) CD_BOOT_CAT_BUFFER,
                (size_t) 1,
                fh))) {
        fprintf(stderr, "Error reading CD boot cat\n");
        return 0;
    }
    
    if (cd_boot_cat[0] != 01) {
        fprintf(stderr, "Header ID, must be 01\n");
        return 0;
    }
    
    switch(cd_boot_cat[1]) {
        case 0:  if (opt_verbose) printf("Platform 80x86\n");
                 break;
        case 1:  if (opt_verbose) printf("Platform Power PC\n");
                 break;
        case 2:  if (opt_verbose) printf("Platform MAC\n");
                 break;
        default: fprintf(stderr, "Platform unknown\n");
                 return 0;
                 break;
    }
    
    strncpy(cd_manufactor, cd_boot_cat + 0x04, MANUFACTOR_MAXLEN);
    if (opt_verbose) printf("Manufactor: %s\n", cd_manufactor);
    
    switch (cd_boot_cat[0x20 + 0x00]) {
        case 0x00: fprintf(stderr, "CD Not Bootable!\n");
                   return 0;
                   break;
        case 0x88: if (opt_verbose) printf("CD Bootable!\n");
                   break;
        default:   fprintf(stderr, "Invalid Boot Indicator on CD\n");
                   return 0;
                   break;
    }

    if (opt_verbose) printf("Boot media type on CD: ");
    switch (cd_boot_cat[0x20 + 0x01]) {
        case 0x00: fprintf(stderr, "No emulation (can't handle this)\n");
                   return 0;
                   break;
        case 0x01: if (opt_verbose) printf("%s\n", FLOPPY_1_2);
                   boot_floppy->boot_img_size = BOOT_IMG_BUFFER_1_2;
                   break;
        case 0x02: if (opt_verbose) printf("%s\n", FLOPPY_1_44);
                   boot_floppy->boot_img_size = BOOT_IMG_BUFFER_1_44;
                   break;
        case 0x03: if (opt_verbose) printf("%s\n", FLOPPY_2_88);
                   boot_floppy->boot_img_size = BOOT_IMG_BUFFER_2_88;
                   break;
        case 0x04: fprintf(stderr, "Harddisk (can't handle this)\n");
                   return 0;
                   break;
        default:   fprintf(stderr, "Invalid Boot media type\n");
                   return 0;
                   break;
    }

    cd_boot_img_ptr =   ( cd_boot_cat[0x20 + 0x08 + 3] << 24 )
                      + ( cd_boot_cat[0x20 + 0x08 + 2] << 16 )
                      + ( cd_boot_cat[0x20 + 0x08 + 1] <<  8 )
                      + ( cd_boot_cat[0x20 + 0x08 + 0]       );

    boot_floppy->boot_img_offset = CD_SECTOR_SIZE * cd_boot_img_ptr;

    if (opt_verbose) printf("boot img ptr: 0x%.8x x 0x800 (0x%.8x)\n", cd_boot_img_ptr, boot_floppy->boot_img_offset);

    return 1;
}

int get_fat_root_dir (FILE *fh, struct boot_floppy_t *boot_floppy) {
    FILE *fh2;
    unsigned char *boot_img;              // buffer for boot image
    unsigned char *floppy_boot_sector;    // buffer for boot record volume descriptor
    unsigned int BPB_BytsPerSec;
    unsigned char BPB_SecPerClus;
    unsigned int BPB_RsvdSecCnt;
    unsigned char BPB_NumFATs;
    unsigned int BPB_FATSz16;
    unsigned char *fat_root_dir_buffer;
    int fat_root_dir_buffer_size;
    int i, j;

    //
    // Read Floppy-Image
    //

    // allocate read_buffer for reading boot image
    if ((boot_img = malloc(boot_floppy->boot_img_size)) == NULL) {
        fprintf(stderr, "Error mallocing CD boot img buffer\n");
        return 0;
    }

    if (opt_verbose) printf("\nReading boot image ...\n");
    // seek to boot image
    fseek(fh, boot_floppy->boot_img_offset, SEEK_SET);

    // allocate read_buffer for reading floppy boot sector
    if ((floppy_boot_sector = malloc((size_t) (FLOPPY_BOOT_SECTOR))) == NULL) {
        fprintf(stderr, "Error mallocing floppy boot sector buffer\n");
        return 0;
    }

    // read first floppy boot sector
    if (fread(((void *) floppy_boot_sector),
              (size_t) FLOPPY_BOOT_SECTOR,
              (size_t) 1,
              fh) < 1) {
        fprintf(stderr, "Error reading boot sector from image\n");
        return 0;
    }

    BPB_BytsPerSec =   ( floppy_boot_sector[12] << 8 )
                     + ( floppy_boot_sector[11]      );

    BPB_SecPerClus =     floppy_boot_sector[13];

    boot_floppy->BytesPerCluster = BPB_SecPerClus * BPB_BytsPerSec;

    BPB_RsvdSecCnt =   ( floppy_boot_sector[15] << 8 )
                     + ( floppy_boot_sector[14]      );

    BPB_NumFATs    =     floppy_boot_sector[16];

    BPB_FATSz16    =   ( floppy_boot_sector[23] << 8 )
                     + ( floppy_boot_sector[22]      );

    fat_root_dir_buffer_size  = BPB_NumFATs * BPB_BytsPerSec;
    boot_floppy->FirstRootDirSecNum = BPB_RsvdSecCnt + (BPB_NumFATs * BPB_FATSz16);

    if (opt_verbose) printf("BPB_BytsPerSec:     %d\n", BPB_BytsPerSec);
    if (opt_verbose) printf("BPB_SecPerClus:     %d\n", BPB_SecPerClus);
    if (opt_verbose) printf("BPB_RsvdSecCnt:     %d\n", BPB_RsvdSecCnt);
    if (opt_verbose) printf("BPB_NumFATs:        %d\n", BPB_NumFATs);
    if (opt_verbose) printf("BPB_FATSz16:        %d\n", BPB_FATSz16);

    if (opt_verbose) printf("\n");

    if (opt_verbose) printf("FAT Root Dir Buffer Size:  %d\n", fat_root_dir_buffer_size);
    if (opt_verbose) printf("FirstRootDirSecNum:        %d\n", boot_floppy->FirstRootDirSecNum);

    if (opt_verbose) printf("\n");

    // allocate buffer for FAT root dir
    if ((fat_root_dir_buffer = malloc((size_t) (fat_root_dir_buffer_size))) == NULL) {
        fprintf(stderr, "Error mallocing for FAT root-Rootdir\n");
        return 0;
    }

    // seek to FirstRootDirSecNum
    if (fseek(fh, boot_floppy->boot_img_offset + (long) (boot_floppy->FirstRootDirSecNum * BPB_BytsPerSec), SEEK_SET) != 0) {
        fprintf(stderr, "Error seeking into file\n");
        return 0;
    }
    
    // read FirstRootDirSecNum
    if (fread(((void *) fat_root_dir_buffer),
              (size_t) fat_root_dir_buffer_size,
              (size_t) 1,
              fh) < 1) {
        fprintf(stderr, "Error fat root dir\n");
        return 0;
    }

    // Count directory entries
    boot_floppy->fat_root_dir_size = 0;
    for (i = 0; i <= fat_root_dir_buffer_size - FAT_ENTRY_SIZE; i += FAT_ENTRY_SIZE) {
	// empty entry
	if (fat_root_dir_buffer[i] == 0xE5)
	    continue;

	// no more entries
	if (fat_root_dir_buffer[i] == 0x00)
	    break;

	boot_floppy->fat_root_dir_size++;
    }

    if (opt_verbose) printf("FAT root dir size:  %d\n", boot_floppy->fat_root_dir_size);

    // allocate buffer for FAT root dir
    if ((boot_floppy->fat_root_dir = malloc((size_t) (boot_floppy->fat_root_dir_size * FAT_ENTRY_SIZE))) == NULL) {
        fprintf(stderr, "Error mallocing for FAT root-Rootdir\n");
        return 0;
    }

    j = 0;
    for (i = 0; i <= fat_root_dir_buffer_size - FAT_ENTRY_SIZE; i += FAT_ENTRY_SIZE) {
	// empty entry
	if (fat_root_dir_buffer[i] == 0xE5)
	    continue;

	// no more entries
	if (fat_root_dir_buffer[i] == 0x00)
	    break;

	strncpy(boot_floppy->fat_root_dir[j].name, fat_root_dir_buffer + i, (size_t) FAT_FILENAME_LENGTH);
	boot_floppy->fat_root_dir[j].name[FAT_FILENAME_LENGTH] = '\0';

	boot_floppy->fat_root_dir[j].pos  =   ( fat_root_dir_buffer[i + 21] << 24 )
                                            + ( fat_root_dir_buffer[i + 20] << 16 )
				            + ( fat_root_dir_buffer[i + 27] <<  8 )
				            + ( fat_root_dir_buffer[i + 26]       );
	    
	boot_floppy->fat_root_dir[j].size =   ( fat_root_dir_buffer[i + 31] << 24 )
				            + ( fat_root_dir_buffer[i + 30] << 16 )
				            + ( fat_root_dir_buffer[i + 29] <<  8 )
				            + ( fat_root_dir_buffer[i + 28]       );
	j++;
    }

    free(fat_root_dir_buffer);

    return 1;
}

// convert file name to fat file name
void filename2fat(unsigned char *dst, const unsigned char *src) {
    int i, j, dot_pos;

    // convert searched filename to fat filename
    // - uppercase
    // - remove dot
    // - fill gap and end with spaces 

    j = 0;
    for (i = 0; i <= strlen(src) - 1; i++) {
	if (src[i] == '.') {
	    while(j <= FAT_FILENAME_LENGTH - 4) {
		dst[j] = ' ';
		j++;
	    }
	} else {
	    dst[j] = toupper(src[i]);
	    j++;
	}
    }
    
    while(j <= FAT_FILENAME_LENGTH - 1) {
	dst[j] = ' ';
	j++;
    }

    dst[FAT_FILENAME_LENGTH] = '\0';
}

void fat2filename(unsigned char *dst, const unsigned char *src) {
    int i, j;

    for (i = 0; i <= strlen(src); i++) {
	if (src[i] == ' ' || src[i] == '\0' || i >= FAT_FILENAME_LENGTH - 3)
	    break;
	dst[i] = tolower(src[i]);
    }
    
    j = FAT_FILENAME_LENGTH - 3;

    if (src[j] != ' ' && src[j] != '\0') {
	dst[i++] = '.';
	for (; j <= strlen(src); j++) {
	    if (src[j] == ' ' || src[j] == '\0' || j >= FAT_FILENAME_LENGTH)
		break;
	    dst[i++] = tolower(src[j]);
	}
    } 
    dst[i] = '\0';
}

int file_exists_in_image(const unsigned char *fname, struct boot_floppy_t *boot_floppy) {
    int i;
    int found = 0;
    unsigned char fatname[FAT_FILENAME_LENGTH + 2];

    filename2fat(fatname, fname);

    for (i = 0; i <= boot_floppy->fat_root_dir_size - 1; i++) {
	if (strncmp(boot_floppy->fat_root_dir[i].name, fatname, FAT_FILENAME_LENGTH) == 0) {
	    found = 1;
	    break;
	}
    }
    
    return found;
}

void show_root_dir(struct boot_floppy_t *boot_floppy) {
    int i;

    for (i = 0; i <= boot_floppy->fat_root_dir_size - 1; i++) {
	if (opt_verbose) printf("File: '%s' Pos: %8d, Size: %8d\n", boot_floppy->fat_root_dir[i].name,
	                                           boot_floppy->fat_root_dir[i].pos,
	                                           boot_floppy->fat_root_dir[i].size);
    }
}

void list_files(struct boot_floppy_t *boot_floppy) {
    int i;
    unsigned char fname[FAT_FILENAME_LENGTH + 2];

    for (i = 0; i <= boot_floppy->fat_root_dir_size - 1; i++) {
	fat2filename(fname, boot_floppy->fat_root_dir[i].name);
	printf("%s\n", fname);
    }
}

struct dir_entry_t get_dir_entry(const unsigned char *fname, struct boot_floppy_t *boot_floppy) {
    unsigned char fat_name[FAT_FILENAME_LENGTH + 2];
    int i;
    struct dir_entry_t dir_entry;

    filename2fat(fat_name, fname);

    for (i = 0; i <= boot_floppy->fat_root_dir_size - 1; i++) {
	if (strncmp(boot_floppy->fat_root_dir[i].name, fat_name, FAT_FILENAME_LENGTH) == 0) {
	    strncpy(dir_entry.name, boot_floppy->fat_root_dir[i].name, FAT_FILENAME_LENGTH);
	    dir_entry.pos  = boot_floppy->fat_root_dir[i].pos;
	    dir_entry.size = boot_floppy->fat_root_dir[i].size;
	    break;
	}
    }

    if (opt_verbose) printf("File: [%s], Pos: %d, Size: %d\n", fname, dir_entry.pos, dir_entry.size);

    return dir_entry;
}

int read_file(FILE *fh, struct boot_floppy_t *boot_floppy, struct dir_entry_t dir_entry, unsigned char *buffer) {
    int i;

    // seek to file
    if (fseek(fh,
	      (long) (boot_floppy->boot_img_offset + (dir_entry.pos + boot_floppy->FirstRootDirSecNum - 1) * boot_floppy->BytesPerCluster),
	      SEEK_SET) != 0) {
        fprintf(stderr, "Error seeking into file\n");
        return 0;
    }
    
    // read file into buffer
    if (fread(((void *) buffer),
              (size_t) dir_entry.size,
              (size_t) 1,
              fh) < 1) {
        fprintf(stderr, "Error reading file\n");
        return 0;
    }

    return 1;
}

int write_file(FILE *fh, struct boot_floppy_t *boot_floppy, struct dir_entry_t dir_entry, unsigned char *buffer) {
    int i;

    // seek to file
    if (fseek(fh,
	      (long) (boot_floppy->boot_img_offset + (dir_entry.pos + boot_floppy->FirstRootDirSecNum - 1) * boot_floppy->BytesPerCluster),
	      SEEK_SET) != 0) {
        fprintf(stderr, "Error seeking into file\n");
        return 0;
    }
    
    // read file into buffer
    if (fwrite(((void *) buffer),
              (size_t) dir_entry.size,
              (size_t) 1,
              fh) < 1) {
        fprintf(stderr, "Error writing file\n");
        return 0;
    }

    return 1;
}

void show_buffer(unsigned char *buffer, long size) {
    int i;

    if (opt_verbose) printf("File-Contents:\n");
    if (opt_verbose) printf("---------------->\n");
    for (i = 0; i <= size - 1; i++)
	if (opt_verbose) printf("%c", buffer[i]);
    if (opt_verbose) printf("<----------------\n");
}

int output_buffer(FILE *fh, unsigned char *buffer, long size) {
    if (fwrite(((void *) buffer),
	       (size_t) size,
	       (size_t) 1,
	       fh) < 1) {
        fprintf(stderr, "Error outputting file\n");
    }

    return 1;
}

int export_to_local_file (FILE *fh, struct boot_floppy_t *boot_floppy, const unsigned char *image_file, const unsigned char *local_file) {
    FILE *fh2;
    unsigned char *buffer;
    struct dir_entry_t dir_entry;

    dir_entry = get_dir_entry(image_file, boot_floppy);
    
    // allocate read_buffer for reading file
    if ((buffer = malloc((size_t) (dir_entry.size))) == NULL) {
	fprintf(stderr, "Error mallocing buffer for reading file\n");
	return 0;
    }
    
    if (read_file(fh, boot_floppy, dir_entry, buffer) == 0) {
	fprintf(stderr, "Error reading file. Aborting\n");
	return 0;
    }
    
    if ((fh2 = fopen(local_file, "w")) == NULL) {
	fprintf(stderr, "Error writing file '%s'\n", local_file);
	return 0;
    }
    
    if(output_buffer(fh2, buffer, dir_entry.size) == 0) {
	fprintf(stderr, "Error outputting buffer. Aborting\n");
	fclose(fh2);
	return 0;
    }
    
    fclose(fh2);
    free(buffer);

    return 1;
}

int import_from_local_file(FILE *fh, struct boot_floppy_t *boot_floppy, const unsigned char *image_file, const unsigned char *local_file) {
    FILE *fh2;
    unsigned char *buffer;
    struct dir_entry_t dir_entry;

    dir_entry = get_dir_entry(image_file, boot_floppy);
    
    // allocate read_buffer for reading file
    if ((buffer = malloc((size_t) (dir_entry.size))) == NULL) {
	fprintf(stderr, "Error mallocing buffer for reading file\n");
	return 0;
    }

    if ((fh2 = fopen(local_file, "r")) == NULL) {
	fprintf(stderr, "Error reading file '%s'\n", local_file);
	return 0;
    }

    // read local file into buffer
    if (fread(((void *) buffer),
              (size_t) dir_entry.size,
              (size_t) 1,
              fh2) < 1) {
        fprintf(stderr, "Error reading local file\n");
        return 0;
    }

    if (write_file(fh, boot_floppy, dir_entry, buffer) == 0) {
	fprintf(stderr, "Error writing file. Aborting\n");
	return 0;
    }

    fclose(fh2);
    free(buffer);

    return 1;
}

void show_help(char *name) {
    fprintf(stderr, "Usage: %s [OPTION]\n", name);
    fprintf(stderr, "      --action ACTION            action to perform. Mandatory!\n"); 
    fprintf(stderr, "               list              list files in boot image\n");
    fprintf(stderr, "               export_file       export file from image to localfile\n");
    fprintf(stderr, "               import_file       import local file into image\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "      --image KNOPPIX-Image-File the Knoppix image to customize. Mandatory!\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "      --local_file filename      file on local filesystem.\n");
    fprintf(stderr, "                                 Mandatory with --action export_file and import_file\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "      --image_file filename      file in the image'\n");
    fprintf(stderr, "                                 Mandatory with --action export_file and import_file\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "      --verbose                  be verbose\n"); 
    fprintf(stderr, "\n");
    fprintf(stderr, "      --help                     this help\n"); 
}

int main(int argc, char **argv) {
    char *knoppix_image_filename;
    struct stat stat_buf, stat_buf2;
    FILE *fh, *fh2;
    struct boot_floppy_t boot_floppy;
    int c;

    int opt_help        = 0;
    int opt_local_file  = 0;
    int opt_image_file  = 0;
    int opt_image       = 0;
    int opt_action      = 0;
    int cmd_list        = 0;
    int cmd_export_file = 0;
    int cmd_import_file = 0;

    char local_filename[MAX_PATH_LEN];
    char image_filename[FAT_FILENAME_LENGTH + 2];

    while (1) {
	int this_option_optind = optind ? optind : 1;
	int option_index = 0;
	static struct option long_options[] = {
	    {"help",        0, 0, 0},
	    {"verbose",     0, 0, 0},
	    {"action",      1, 0, 0},
	    {"local_file",  1, 0, 0},
	    {"image_file",  1, 0, 0},
	    {"image",       1, 0, 0},
	    {0,             0, 0, 0}
	};
	
	c = getopt_long (argc, argv, "", long_options, &option_index);
	if (c == -1) 
	    break;
	
	if (c == 0) {
	    if (strncmp(long_options[option_index].name, "help", 4) == 0) {
		opt_help = 1;
		continue;
	    }

	    if (strncmp(long_options[option_index].name, "verbose", 7) == 0) {
		opt_verbose = 1;
		continue;
	    }

	    if (strncmp(long_options[option_index].name, "local_file", 10) == 0) {
		opt_local_file = 1;
		strncpy(local_filename, optarg, MAX_PATH_LEN);
		continue;
	    }

	    if (strncmp(long_options[option_index].name, "image_file", 10) == 0) {
		opt_image_file = 1;
		strncpy(image_filename, optarg, FAT_FILENAME_LENGTH + 1);
		continue;
	    }

	    if (strncmp(long_options[option_index].name, "image", 5) == 0) {
		opt_image = 1;
		strncpy(knoppix_image_filename, optarg, FAT_FILENAME_LENGTH + 1);
		continue;
	    }

	    if (strncmp(long_options[option_index].name, "action", 6) == 0) {
		opt_action = 1;
		
		if (strncmp(optarg, "list", 4) == 0)
		    cmd_list = 1;
		else if (strncmp(optarg, "export_file", 10) == 0)
		    cmd_export_file = 1;
		else if (strncmp(optarg, "import_file", 10) == 0)
		    cmd_import_file = 1;
		
		continue;
	    }
	} 
    }

    // there should be no further arguments
    if (optind < argc) {
	fprintf(stderr, "Usage: %s [OPTION]\n", argv[0]);
	fprintf(stderr, "      Unknown arguments: ");
	while (optind < argc)
                   fprintf(stderr, "%s ", argv[optind++]);
	fprintf(stderr, "\n");
	fprintf(stderr, "      try --help for more information\n");

	exit(1);
    }

    // show help
    if (opt_help) {
	show_help(basename(argv[0]));
	exit(0);
    }

    // --image and --action are mandatory
    if (! opt_image || ! opt_action) {
	fprintf(stderr, "Usage: %s [OPTION]\n", argv[0]);
	fprintf(stderr, "      --image and --action are mandatory\n");
	fprintf(stderr, "      try --help for more information\n");
	exit(1);
    }

    // --local_file and image_file are mandatory for --export_file and --import_file
    if ((cmd_export_file || cmd_import_file) && ! (opt_local_file && opt_image_file)) {
	fprintf(stderr, "Usage: %s [OPTION]\n", argv[0]);
	fprintf(stderr, "      --local_file and --image_file are mandatory with\n");
	fprintf(stderr, "      --action export_file and --action import_file\n");
	fprintf(stderr, "      try --help for more information\n");
	exit(1);
    }

    // test if image exists
    if (stat(knoppix_image_filename, &stat_buf) != 0) {
        fprintf(stderr, "Error: Could not stat image file '%s'\n", knoppix_image_filename);
        exit(2);
    }

    // test if local_file exists
    if (cmd_import_file && (stat(local_filename, &stat_buf2) != 0)) {
        fprintf(stderr, "Error: Could not stat local file '%s'\n", local_filename);
        exit(2);
    }

    // open the image file for reading and writing
    if (cmd_import_file) {
	if ((fh = fopen(knoppix_image_filename, "r+")) == NULL) {
	    fprintf(stderr, "Error opening image '%s' for read/write\n", knoppix_image_filename);
	    exit(2);
	}
    } else {
	if ((fh = fopen(knoppix_image_filename, "r")) == NULL) {
	    fprintf(stderr, "Error opening image '%s' for read\n", knoppix_image_filename);
	    exit(2);
	}
    }

    // find out if it's ISO or Floppy-image, in ISO find the floppy image
    if (find_boot_image(fh, stat_buf, &boot_floppy) == 0) {
        fprintf(stderr, "Error reading image. Aborting\n");
        fclose(fh);
        exit(3);
    }

    // Get the boot floppy's root directory
    if (get_fat_root_dir(fh, &boot_floppy) == 0) {
        fprintf(stderr, "Error parsing boot image. Aborting\n");
        fclose(fh);
        exit(3);
    }

    if (opt_verbose)
	show_root_dir(&boot_floppy);

    // test if image_file exists
    // can only test this after reading the image
    if ((cmd_import_file || cmd_export_file) && !file_exists_in_image(image_filename, &boot_floppy)) {
        fprintf(stderr, "Error: image_file '%s' not in image\n", image_filename);
        exit(2);
    }

    // list files on boot floppy
    if (cmd_list)
	list_files(&boot_floppy);

    // export file from image to filesystem
    if (cmd_export_file)
	if(export_to_local_file(fh, &boot_floppy, image_filename, local_filename) == 0) {
	    fprintf(stderr, "Error exporting file to local file. Aborting\n");
	    fclose(fh);
	    exit(3);
	}
	
    // import file from filesystem into image
    if (cmd_import_file)
	if(import_from_local_file(fh, &boot_floppy, image_filename, local_filename) == 0) {
	    fprintf(stderr, "Error importing file from local file and writing zo image. Aborting\n"); 
	    fclose(fh);
	    exit(3);
	}
    
    fclose(fh);

    exit(0);
}


Reply to: