/* 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; }