/* Copyright (C) 2008 Emmanuel Varoquaux
This file is part of XOS.
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, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
/* Construit une archive pour XOS.
*
* Utilisation : makebin [file]...
* file un fichier a ajouter
* Options :
* -o filename ecrire l'image dans le fichier filename, au lieu de la sortie
* standard. */
#define _GNU_SOURCE
#include "bin.h"
#include
#include
#include
#include
#include
#include
#include
static void die(const char *s)
{
error(EXIT_FAILURE, errno, s);
}
static void __attribute__ ((noreturn)) die_bad_usage()
{
fprintf(stderr, "Try `%s --help' for more information.\n", program_invocation_name);
exit(EXIT_FAILURE);
}
static void print_help()
{
printf("Usage: %s [OPTION]... [FILE]...\n", program_invocation_name);
printf("Create an archive for XOS.\n");
printf("\n");
printf(" -h, --help display this help and exit\n");
printf(" -o, --output=FILE write output in FILE instead of standard output\n");
}
static inline void compute_checksum(bin_hdr_t *hdr)
{
const unsigned char *pc;
hdr->checksum = 0;
for (pc = (const unsigned char *)hdr; pc != (const unsigned char *)&hdr->checksum; pc++)
hdr->checksum += *pc;
}
static size_t write_header(const char *filename, off_t size, FILE *output)
{
bin_hdr_t hdr;
char *path;
hdr.magic = BIN_MAGIC;
hdr.size = size;
memset(hdr.name, 0, BIN_NAME_LEN);
if (!(path = strdup(filename)))
die("strdup");
strncpy(hdr.name, basename(path), BIN_NAME_LEN - 1);
free(path);
hdr.reserved = 0;
compute_checksum(&hdr);
if (fwrite(&hdr, sizeof (bin_hdr_t), 1, output) < 1)
die("fwrite");
return sizeof (bin_hdr_t);
}
static size_t write_data(FILE *fp, FILE *output)
{
char buf[4096];
size_t n;
size_t l;
n = 0;
do {
l = fread(buf, 1, sizeof buf, fp);
if (ferror(fp))
die("fread");
if (l) {
if (fwrite(buf, l, 1, output) < 1)
die("fwrite");
n += l;
}
}
while (!feof(fp));
return n;
}
static void write_trailer(FILE *output)
{
bin_hdr_t hdr;
memset(&hdr, 0, sizeof (bin_hdr_t));
if (fwrite(&hdr, sizeof (bin_hdr_t), 1, output) < 1)
die("fwrite");
}
static int add_file(const char *filename, FILE *output)
{
static const char zeros[4] = {'\0', '\0', '\0', '\0'};
struct stat statbuf;
FILE *fp;
size_t n;
if (stat(filename, &statbuf) == -1) {
error(0, errno, "cannot stat `%s'", filename);
return 0;
}
if (S_ISDIR(statbuf.st_mode)) {
error(0, 0, "omitting directory `%s'", filename);
return 0;
}
if (!(fp = fopen(filename, "r"))) {
error(0, errno, "cannot open `%s'", filename);
return 0;
}
n = 0;
n += write_header(filename, statbuf.st_size, output);
n += write_data(fp, output);
if (bin_align(n) != n)
if (fwrite(zeros, bin_align(n) - n, 1, output) < 1)
die("fwrite");
fclose(fp);
return 1;
}
static int makebin(char *const filenames[], FILE *output)
{
int status;
status = 1;
while (*filenames)
if (!add_file(*filenames++, output))
status = 0;
write_trailer(output);
return status;
}
int main(int argc, char **argv)
{
static const struct option longopts[] = {
{"help", no_argument, NULL, 'h'},
{"output", required_argument, NULL, 'o'},
{NULL, 0, NULL, 0}
};
char *output_filename;
FILE *output;
int status;
int c;
/* options par defaut */
output_filename = NULL;
/* lecture des options de la ligne de commande */
while ((c = getopt_long(argc, argv, "ho:", longopts, NULL)) != -1)
switch (c) {
case 'h':
print_help();
return EXIT_SUCCESS;
case 'o':
if (output_filename)
free(output_filename);
if (!(output_filename = strdup(optarg)))
die("strdup");
break;
case '?':
die_bad_usage();
}
if (output_filename) {
if (!(output = fopen(output_filename, "w+")))
die(output_filename);
free(output_filename);
}
else
output = stdout;
status = makebin(argv + optind, output);
if (output != stdout)
fclose(output);
return status ? EXIT_SUCCESS : EXIT_FAILURE;
}