/*
* mkcramfs - make a cramfs file system
*
- * Copyright (C) 1999-2001 Transmeta Corporation
+ * Copyright (C) 1999-2002 Transmeta Corporation
*
* 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
* 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
-#include <sys/fcntl.h>
+#include <fcntl.h>
#include <dirent.h>
+#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
-#include <assert.h>
#include <getopt.h>
+#include <zconf.h>
#include <zlib.h>
+#include "c.h"
#include "cramfs.h"
#include "md5.h"
#include "nls.h"
+#include "exitcodes.h"
+#include "strutils.h"
+#define XALLOC_EXIT_CODE MKFS_ERROR
+#include "xalloc.h"
-#define PAD_SIZE 512 /* only 0 and 512 supported by kernel */
+/* The kernel only supports PAD_SIZE of 0 and 512. */
+#define PAD_SIZE 512
-static const char *progname = "mkcramfs";
static int verbose = 0;
-#ifdef __ia64__
-#define PAGE_CACHE_SIZE (16384)
-#elif defined __alpha__
-#define PAGE_CACHE_SIZE (8192)
-#else
-#define PAGE_CACHE_SIZE (4096)
-#endif
-
-/* The kernel assumes PAGE_CACHE_SIZE as block size. */
-static unsigned int blksize = PAGE_CACHE_SIZE; /* settable via -b option */
+static unsigned int blksize; /* settable via -b option */
static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */
static int image_length = 0;
+static int cramfs_is_big_endian = 0; /* target is big endian */
/*
* If opt_holes is set, then mkcramfs can create explicit holes in the
# define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
#endif
+/* entry.flags */
+#define CRAMFS_EFLAG_MD5 1
+#define CRAMFS_EFLAG_INVALID 2
+
/* In-core version of inode / directory entry. */
struct entry {
/* stats */
- char *name;
+ unsigned char *name;
unsigned int mode, size, uid, gid;
- unsigned char md5sum[16];
- unsigned char flags;
-#define HAVE_MD5 1
-#define INVALID 2
+ unsigned char md5sum[MD5LENGTH];
+ unsigned char flags; /* CRAMFS_EFLAG_* */
/* FS data */
char *path;
- struct entry *same; /* points to other identical file */
- unsigned int offset; /* pointer to compressed data in archive */
+ int fd; /* temporarily open files while mmapped */
+ struct entry *same; /* points to other identical file */
+ unsigned int offset; /* pointer to compressed data in archive */
unsigned int dir_offset; /* offset of directory entry in archive */
/* organization */
FILE *stream = status ? stderr : stdout;
fprintf(stream,
- _("usage: %s [-v] [-b blksz] [-e edition] [-i file] [-n name] "
- "dirname outfile\n"
+ _("usage: %s [-h] [-v] [-b blksize] [-e edition] [-N endian] [-i file] "
+ "[-n name] dirname outfile\n"
" -h print this help\n"
" -v be verbose\n"
" -E make all warnings errors "
"(non-zero exit status)\n"
- " -b blksz use this blocksize, must equal page size\n"
+ " -b blksize use this blocksize, must equal page size\n"
" -e edition set edition number (part of fsid)\n"
+ " -N endian set cramfs endianness (big|little|host), default host\n"
" -i file insert a file image into the filesystem "
"(requires >= 2.4.0)\n"
" -n name set name of cramfs filesystem\n"
" -z make explicit holes (requires >= 2.3.39)\n"
" dirname root of the filesystem to be compressed\n"
" outfile output file\n"),
- progname, PAD_SIZE);
+ program_invocation_short_name, PAD_SIZE);
exit(status);
}
-/* malloc or die */
-static void *
-xmalloc (size_t size) {
- void *t = malloc(size);
- if (t == NULL) {
- perror(NULL);
- exit(8); /* out of memory */
- }
- return t;
-}
-
static char *
do_mmap(char *path, unsigned int size, unsigned int mode){
int fd;
}
start = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (-1 == (int) (long) start) {
- perror("mmap");
- exit(8);
- }
+ if (-1 == (int) (long) start)
+ err(MKFS_ERROR, "mmap");
close(fd);
return start;
start = do_mmap(e->path, e->size, e->mode);
if (start == NULL) {
- e->flags |= INVALID;
+ e->flags |= CRAMFS_EFLAG_INVALID;
} else {
MD5Init(&ctx);
- MD5Update(&ctx, start, e->size);
+ MD5Update(&ctx, (unsigned char *) start, e->size);
MD5Final(e->md5sum, &ctx);
do_munmap(start, e->size, e->mode);
- e->flags |= HAVE_MD5;
+ e->flags |= CRAMFS_EFLAG_MD5;
}
}
*/
#define MAX_INPUT_NAMELEN 255
-static int find_identical_file(struct entry *orig, struct entry *new)
+static int find_identical_file(struct entry *orig, struct entry *new, loff_t *fslen_ub)
{
- if (orig == new)
+ if (orig == new)
return 1;
- if (!orig)
+ if (!orig)
return 0;
- if (orig->size == new->size && orig->path) {
+ if (orig->size == new->size && orig->path) {
if (!orig->flags)
mdfile(orig);
if (!new->flags)
mdfile(new);
- if ((orig->flags & HAVE_MD5) && (new->flags & HAVE_MD5) &&
- !memcmp(orig->md5sum, new->md5sum, 16) &&
+ if ((orig->flags & CRAMFS_EFLAG_MD5) &&
+ (new->flags & CRAMFS_EFLAG_MD5) &&
+ !memcmp(orig->md5sum, new->md5sum, MD5LENGTH) &&
identical_file(orig, new)) {
new->same = orig;
+ *fslen_ub -= new->size;
return 1;
}
- }
- return find_identical_file(orig->child, new) ||
- find_identical_file(orig->next, new);
+ }
+ return find_identical_file(orig->child, new, fslen_ub) ||
+ find_identical_file(orig->next, new, fslen_ub);
}
-static void eliminate_doubles(struct entry *root, struct entry *orig) {
- if (orig) {
- if (orig->size && orig->path)
- find_identical_file(root,orig);
- eliminate_doubles(root,orig->child);
- eliminate_doubles(root,orig->next);
- }
+static void eliminate_doubles(struct entry *root, struct entry *orig, loff_t *fslen_ub) {
+ if (orig) {
+ if (orig->size && orig->path)
+ find_identical_file(root,orig, fslen_ub);
+ eliminate_doubles(root,orig->child, fslen_ub);
+ eliminate_doubles(root,orig->next, fslen_ub);
+ }
}
/*
* We define our own sorting function instead of using alphasort which
* uses strcoll and changes ordering based on locale information.
*/
-static int cramsort (const void *a, const void *b)
+static int cramsort (const struct dirent **a, const struct dirent **b)
{
- return strcmp ((*(const struct dirent **) a)->d_name,
- (*(const struct dirent **) b)->d_name);
+ return strcmp((*a)->d_name, (*b)->d_name);
}
static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub)
*endpath = '/';
endpath++;
- /* read in the directory and sort */
- dircount = scandir(name, &dirlist, 0, cramsort);
+ /* read in the directory and sort */
+ dircount = scandir(name, &dirlist, 0, cramsort);
- if (dircount < 0) {
- perror(name);
- exit(8);
- }
+ if (dircount < 0)
+ err(MKFS_ERROR, _("could not read directory %s"), name);
/* process directory */
for (dirindex = 0; dirindex < dircount; dirindex++) {
}
}
namelen = strlen(dirent->d_name);
- if (namelen > MAX_INPUT_NAMELEN) {
- fprintf(stderr,
- _("Very long (%u bytes) filename `%s' found.\n"
+ if (namelen > MAX_INPUT_NAMELEN)
+ errx(MKFS_ERROR,
+ _("Very long (%zu bytes) filename `%s' found.\n"
" Please increase MAX_INPUT_NAMELEN in "
- "mkcramfs.c and recompile. Exiting.\n"),
+ "mkcramfs.c and recompile. Exiting."),
namelen, dirent->d_name);
- exit(8);
- }
memcpy(endpath, dirent->d_name, namelen + 1);
if (lstat(path, &st) < 0) {
warn_skip = 1;
continue;
}
- entry = calloc(1, sizeof(struct entry));
- if (!entry) {
- perror(NULL);
- exit(8);
- }
- entry->name = strdup(dirent->d_name);
- if (!entry->name) {
- perror(NULL);
- exit(8);
- }
+ entry = xcalloc(1, sizeof(struct entry));
+ entry->name = (unsigned char *)xstrdup(dirent->d_name);
if (namelen > 255) {
/* Can't happen when reading from ext2fs. */
entry->gid = st.st_gid;
if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
/* TODO: We ought to replace with a default
- gid instead of truncating; otherwise there
- are security problems. Maybe mode should
- be &= ~070. Same goes for uid once Linux
- supports >16-bit uids. */
+ gid instead of truncating; otherwise there
+ are security problems. Maybe mode should
+ be &= ~070. Same goes for uid once Linux
+ supports >16-bit uids. */
warn_gid = 1;
size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
*fslen_ub += size;
if (S_ISDIR(st.st_mode)) {
entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub);
} else if (S_ISREG(st.st_mode)) {
- entry->path = strdup(path);
+ entry->path = xstrdup(path);
if (entry->size) {
if (entry->size >= (1 << CRAMFS_SIZE_WIDTH)) {
warn_size = 1;
}
}
} else if (S_ISLNK(st.st_mode)) {
- entry->path = strdup(path);
+ entry->path = xstrdup(path);
} else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
/* maybe we should skip sockets */
entry->size = 0;
/* block pointers & data expansion allowance + data */
if (entry->size)
*fslen_ub += (4+26)*blocks + entry->size + 3;
- }
+ }
/* Link it into the list */
*prev = entry;
memset(super->name, 0x00, sizeof(super->name));
if (opt_name)
- strncpy(super->name, opt_name, sizeof(super->name));
+ strncpy((char *)super->name, opt_name, sizeof(super->name));
else
- strncpy(super->name, "Compressed", sizeof(super->name));
+ strncpy((char *)super->name, "Compressed", sizeof(super->name));
super->root.mode = root->mode;
super->root.uid = root->uid;
super->root.size = root->size;
super->root.offset = offset >> 2;
+ super_toggle_endianness(cramfs_is_big_endian, super);
+ inode_from_host(cramfs_is_big_endian, &super->root, &super->root);
+
return offset;
}
static void set_data_offset(struct entry *entry, char *base, unsigned long offset)
{
struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
- if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
- fprintf(stderr, _("filesystem too big. Exiting.\n"));
- exit(8);
- }
+ inode_to_host(cramfs_is_big_endian, inode, inode);
+ if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH)))
+ errx(MKFS_ERROR, _("filesystem too big. Exiting."));
inode->offset = (offset >> 2);
+ inode_from_host(cramfs_is_big_endian, inode, inode);
}
* entries, using a stack to remember the directories
* we've seen.
*/
-#define MAXENTRIES (100)
static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset)
{
int stack_entries = 0;
- struct entry *entry_stack[MAXENTRIES];
+ int stack_size = 64;
+ struct entry **entry_stack;
+
+ entry_stack = xmalloc(stack_size * sizeof(struct entry *));
for (;;) {
int dir_start = stack_entries;
while (entry) {
struct cramfs_inode *inode =
(struct cramfs_inode *) (base + offset);
- size_t len = strlen(entry->name);
+ size_t len = strlen((const char *)entry->name);
entry->dir_offset = offset;
if (verbose)
printf(" %s\n", entry->name);
if (entry->child) {
- if (stack_entries >= MAXENTRIES) {
- fprintf(stderr,
- _("Exceeded MAXENTRIES. Raise"
- " this value in mkcramfs.c "
- "and recompile. Exiting.\n")
- );
- exit(8);
+ if (stack_entries >= stack_size) {
+ stack_size *= 2;
+ entry_stack = xrealloc(entry_stack, stack_size * sizeof(struct entry *));
}
entry_stack[stack_entries] = entry;
stack_entries++;
}
+ inode_from_host(cramfs_is_big_endian, inode, inode);
entry = entry->next;
}
/*
* Reverse the order the stack entries pushed during
- * this directory, for a small optimization of disk
- * access in the created fs. This change makes things
- * `ls -UR' order.
+ * this directory, for a small optimization of disk
+ * access in the created fs. This change makes things
+ * `ls -UR' order.
*/
{
struct entry **lo = entry_stack + dir_start;
printf("'%s':\n", entry->name);
entry = entry->child;
}
+ free(entry_stack);
return offset;
}
-static int is_zero(char const *begin, unsigned len)
+static int is_zero(unsigned char const *begin, unsigned len)
{
if (opt_holes)
/* Returns non-zero iff the first LEN bytes from BEGIN are
* have gotten here in the first place.
*/
static unsigned int
-do_compress(char *base, unsigned int offset, char const *name,
+do_compress(char *base, unsigned int offset, unsigned char const *name,
char *path, unsigned int size, unsigned int mode)
{
unsigned long original_size, original_offset, new_size, blocks, curr;
- int change;
- char *p, *start;
+ long change;
+ char *start;
+ Bytef *p;
/* get uncompressed data */
start = do_mmap(path, size, mode);
if (start == NULL)
return offset;
- p = start;
+ p = (Bytef *) start;
original_size = size;
original_offset = offset;
total_blocks += blocks;
do {
- unsigned long len = 2 * blksize;
- unsigned int input = size;
+ uLongf len = 2 * blksize;
+ uLongf input = size;
if (input > blksize)
input = blksize;
size -= input;
if (!is_zero (p, input)) {
- compress(base + curr, &len, p, input);
+ compress((Bytef *)(base + curr), &len, p, input);
curr += len;
}
p += input;
printf(_("AIEEE: block \"compressed\" to > "
"2*blocklength (%ld)\n"),
len);
- exit(8);
+ exit(MKFS_ERROR);
}
- *(u32 *) (base + offset) = curr;
+ *(uint32_t *) (base + offset) = u32_toggle_endianness(cramfs_is_big_endian, curr);
offset += 4;
} while (size);
administrative data should also be included in both. */
change = new_size - original_size;
if (verbose)
- printf(_("%6.2f%% (%+d bytes)\t%s\n"),
+ printf(_("%6.2f%% (%+ld bytes)\t%s\n"),
(change * 100) / (double) original_size, change, name);
return curr;
for (e = entry; e; e = e->next) {
if (e->path) {
- if (e->same) {
- set_data_offset(e, base, e->same->offset);
- e->offset = e->same->offset;
- } else {
- set_data_offset(e, base, offset);
- e->offset = offset;
- offset = do_compress(base, offset, e->name,
+ if (e->same) {
+ set_data_offset(e, base, e->same->offset);
+ e->offset = e->same->offset;
+ } else if (e->size) {
+ set_data_offset(e, base, offset);
+ e->offset = offset;
+ offset = do_compress(base, offset, e->name,
e->path, e->size,e->mode);
- }
+ }
} else if (e->child)
offset = write_data(e->child, base, offset);
}
char *buf;
fd = open(file, O_RDONLY);
- if (fd < 0) {
- perror(file);
- exit(8);
- }
+ if (fd < 0)
+ err(MKFS_ERROR, _("cannot open file %s"), file);
buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
memcpy(base + offset, buf, image_length);
munmap(buf, image_length);
- close (fd);
+ if (close (fd) < 0)
+ err(MKFS_ERROR, _("cannot close file %s"), file);
/* Pad up the image_length to a 4-byte boundary */
while (image_length & 3) {
*(base + offset + image_length) = '\0';
loff_t fslen_ub = sizeof(struct cramfs_super);
unsigned int fslen_max;
char const *dirname, *outfile;
- u32 crc = crc32(0L, Z_NULL, 0);
+ uint32_t crc = crc32(0L, Z_NULL, 0);
int c;
+ cramfs_is_big_endian = HOST_IS_BIG_ENDIAN; /* default is to use host order */
+ blksize = getpagesize();
total_blocks = 0;
- if (argc) {
- char *p;
- progname = argv[0];
- if ((p = strrchr(progname, '/')) != NULL)
- progname = p+1;
- }
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
/* command line options */
- while ((c = getopt(argc, argv, "hb:Ee:i:n:psVvz")) != EOF) {
+ while ((c = getopt(argc, argv, "hb:Ee:i:n:N:psVvz")) != EOF) {
switch (c) {
case 'h':
- usage(0);
+ usage(MKFS_OK);
case 'b':
- blksize = atoi(optarg);
- if (blksize <= 0)
- usage(1);
+ {
+ long long tmp = strtoll_or_err(optarg,
+ _("failed to parse blocksize argument"));
+
+ if (tmp <= 0 || UINT_MAX < tmp)
+ errx(MKFS_USAGE, _("invalid block size"));
+ blksize = tmp;
break;
+ }
case 'E':
opt_errors = 1;
break;
case 'e':
- opt_edition = atoi(optarg);
+ opt_edition = strtoll_or_err(optarg, _("edition number argument failed"));
+ break;
+ case 'N':
+ if (strcmp(optarg, "big") == 0)
+ cramfs_is_big_endian = 1;
+ else if (strcmp(optarg, "little") == 0)
+ cramfs_is_big_endian = 0;
+ else if (strcmp(optarg, "host") == 0)
+ /* default */ ;
+ else
+ errx(MKFS_USAGE, _("invalid endianness given."
+ " Must be 'big', 'little', or 'host'"));
break;
case 'i':
opt_image = optarg;
- if (lstat(opt_image, &st) < 0) {
- perror(opt_image);
- exit(16);
- }
+ if (lstat(opt_image, &st) < 0)
+ err(MKFS_USAGE, _("cannot stat %s"), opt_image);
image_length = st.st_size; /* may be padded later */
fslen_ub += (image_length + 3); /* 3 is for padding */
break;
break;
case 'V':
printf(_("%s from %s\n"),
- progname, util_linux_version);
- exit(0);
+ program_invocation_short_name, PACKAGE_STRING);
+ exit(MKFS_OK);
case 'v':
verbose = 1;
break;
}
if ((argc - optind) != 2)
- usage(16);
+ usage(MKFS_USAGE);
dirname = argv[optind];
outfile = argv[optind + 1];
- if (stat(dirname, &st) < 0) {
- perror(dirname);
- exit(16);
- }
+ if (stat(dirname, &st) < 0)
+ err(MKFS_USAGE, _("cannot stat %s"), dirname);
fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0)
+ err(MKFS_USAGE, _("cannot open %s"), outfile);
- root_entry = calloc(1, sizeof(struct entry));
- if (!root_entry) {
- perror(NULL);
- exit(8);
- }
+ root_entry = xcalloc(1, sizeof(struct entry));
root_entry->mode = st.st_mode;
root_entry->uid = st.st_uid;
root_entry->gid = st.st_gid;
root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
+ /* find duplicate files */
+ eliminate_doubles(root_entry,root_entry, &fslen_ub);
+
/* always allocate a multiple of blksize bytes because that's
- what we're going to write later on */
+ what we're going to write later on */
fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
fslen_max = maxfslen();
if (fslen_ub > fslen_max) {
- fprintf(stderr,
- _("warning: guestimate of required size (upper bound) "
- "is %LdMB, but maximum image size is %uMB. "
- "We might die prematurely.\n"),
- fslen_ub >> 20,
+ warnx( _("warning: guestimate of required size (upper bound) "
+ "is %lldMB, but maximum image size is %uMB. "
+ "We might die prematurely."),
+ (long long)fslen_ub >> 20,
fslen_max >> 20);
fslen_ub = fslen_max;
}
- /* find duplicate files */
- eliminate_doubles(root_entry,root_entry);
-
/* TODO: Why do we use a private/anonymous mapping here
- followed by a write below, instead of just a shared mapping
- and a couple of ftruncate calls? Is it just to save us
- having to deal with removing the file afterwards? If we
- really need this huge anonymous mapping, we ought to mmap
- in smaller chunks, so that the user doesn't need nn MB of
- RAM free. If the reason is to be able to write to
- un-mmappable block devices, then we could try shared mmap
- and revert to anonymous mmap if the shared mmap fails. */
+ followed by a write below, instead of just a shared mapping
+ and a couple of ftruncate calls? Is it just to save us
+ having to deal with removing the file afterwards? If we
+ really need this huge anonymous mapping, we ought to mmap
+ in smaller chunks, so that the user doesn't need nn MB of
+ RAM free. If the reason is to be able to write to
+ un-mmappable block devices, then we could try shared mmap
+ and revert to anonymous mmap if the shared mmap fails. */
rom_image = mmap(NULL,
fslen_ub?fslen_ub:1,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
- if (-1 == (int) (long) rom_image) {
- perror("ROM image map");
- exit(8);
- }
+ if (-1 == (int) (long) rom_image)
+ err(MKFS_ERROR, _("ROM image map"));
/* Skip the first opt_pad bytes for boot loader code */
offset = opt_pad;
offset = write_directory_structure(root_entry->child, rom_image, offset);
if (verbose)
- printf(_("Directory data: %d bytes\n"), offset);
+ printf(_("Directory data: %zd bytes\n"), offset);
offset = write_data(root_entry, rom_image, offset);
/* We always write a multiple of blksize bytes, so that
- losetup works. */
+ losetup works. */
offset = ((offset - 1) | (blksize - 1)) + 1;
if (verbose)
- printf(_("Everything: %d kilobytes\n"), offset >> 10);
+ printf(_("Everything: %zd kilobytes\n"), offset >> 10);
/* Write the superblock now that we can fill in all of the fields. */
write_superblock(root_entry, rom_image+opt_pad, offset);
if (verbose)
- printf(_("Super block: %d bytes\n"),
+ printf(_("Super block: %zd bytes\n"),
sizeof(struct cramfs_super));
/* Put the checksum in. */
- crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad));
- ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc;
+ crc = crc32(crc, (unsigned char *) (rom_image+opt_pad), (offset-opt_pad));
+ ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = u32_toggle_endianness(cramfs_is_big_endian, crc);
if (verbose)
printf(_("CRC: %x\n"), crc);
/* Check to make sure we allocated enough space. */
- if (fslen_ub < offset) {
- fprintf(stderr,
+ if (fslen_ub < offset)
+ errx(MKFS_ERROR,
_("not enough space allocated for ROM image "
- "(%Ld allocated, %d used)\n"),
- fslen_ub, offset);
- exit(8);
- }
+ "(%lld allocated, %zu used)"),
+ (long long) fslen_ub, offset);
written = write(fd, rom_image, offset);
- if (written < 0) {
- perror("ROM image");
- exit(8);
- }
- if (offset != written) {
- fprintf(stderr, _("ROM image write failed (%d %d)\n"),
+ close(fd);
+ if (written < 0)
+ err(MKFS_ERROR, _("ROM image"));
+ if (offset != written)
+ errx(MKFS_ERROR, _("ROM image write failed (%zd %zd)"),
written, offset);
- exit(8);
- }
- /* (These warnings used to come at the start, but they scroll off the
- screen too quickly.) */
- if (warn_namelen) /* (can't happen when reading from ext2fs) */
- fprintf(stderr, /* bytes, not chars: think UTF8. */
- _("warning: filenames truncated to 255 bytes.\n"));
+ /*
+ * (These warnings used to come at the start, but they scroll off
+ * the screen too quickly.)
+ */
+ if (warn_namelen)
+ /* Can't happen when reading from ext2fs. */
+ /* Bytes, not chars: think UTF8. */
+ warnx(_("warning: filenames truncated to 255 bytes."));
if (warn_skip)
- fprintf(stderr,
- _("warning: files were skipped due to errors.\n"));
+ warnx(_("warning: files were skipped due to errors."));
if (warn_size)
- fprintf(stderr,
- _("warning: file sizes truncated to %luMB "
- "(minus 1 byte).\n"),
- 1L << (CRAMFS_SIZE_WIDTH - 20));
- if (warn_uid) /* (not possible with current Linux versions) */
- fprintf(stderr,
- _("warning: uids truncated to %u bits. "
- "(This may be a security concern.)\n"),
- CRAMFS_UID_WIDTH);
+ warnx(_("warning: file sizes truncated to %luMB "
+ "(minus 1 byte)."), 1L << (CRAMFS_SIZE_WIDTH - 20));
+ if (warn_uid)
+ /* (not possible with current Linux versions) */
+ warnx(_("warning: uids truncated to %u bits. "
+ "(This may be a security concern.)"), CRAMFS_UID_WIDTH);
if (warn_gid)
- fprintf(stderr,
- _("warning: gids truncated to %u bits. "
- "(This may be a security concern.)\n"),
- CRAMFS_GID_WIDTH);
+ warnx(_("warning: gids truncated to %u bits. "
+ "(This may be a security concern.)"), CRAMFS_GID_WIDTH);
if (warn_dev)
- fprintf(stderr,
- _("WARNING: device numbers truncated to %u bits. "
- "This almost certainly means\n"
- "that some device files will be wrong.\n"),
- CRAMFS_OFFSET_WIDTH);
+ warnx(_("WARNING: device numbers truncated to %u bits. "
+ "This almost certainly means\n"
+ "that some device files will be wrong."),
+ CRAMFS_OFFSET_WIDTH);
if (opt_errors &&
(warn_namelen|warn_skip|warn_size|warn_uid|warn_gid|warn_dev))
- exit(8);
- return 0;
+ exit(MKFS_ERROR);
+
+ return EXIT_SUCCESS;
}