* 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/mman.h>
#include <fcntl.h>
#include <dirent.h>
+#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
-#include <stdarg.h>
+#include <zconf.h>
#include <zlib.h>
#include "c.h"
#include "cramfs.h"
#include "md5.h"
#include "nls.h"
-#include "mkfs.h"
+#include "exitcodes.h"
+#include "strutils.h"
#define XALLOC_EXIT_CODE MKFS_ERROR
#include "xalloc.h"
/* FS data */
char *path;
int fd; /* temporarily open files while mmapped */
- struct entry *same; /* points to other identical file */
- unsigned int offset; /* pointer to compressed data in archive */
+ 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 */
}
start = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (-1 == (int) (long) start) {
- perror("mmap");
- exit(MKFS_ERROR);
- }
+ if (-1 == (int) (long) start)
+ err(MKFS_ERROR, "mmap");
close(fd);
return start;
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)
*fslen_ub -= new->size;
return 1;
}
- }
- return find_identical_file(orig->child, new, fslen_ub) ||
- find_identical_file(orig->next, new, fslen_ub);
+ }
+ 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, loff_t *fslen_ub) {
- if (orig) {
- if (orig->size && orig->path)
+ 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);
- }
+ eliminate_doubles(root,orig->child, fslen_ub);
+ eliminate_doubles(root,orig->next, 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(MKFS_ERROR);
- }
+ 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,
+ 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(MKFS_ERROR);
- }
memcpy(endpath, dirent->d_name, namelen + 1);
if (lstat(path, &st) < 0) {
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;
/* block pointers & data expansion allowance + data */
if (entry->size)
*fslen_ub += (4+26)*blocks + entry->size + 3;
- }
+ }
/* Link it into the list */
*prev = entry;
{
struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
inode_to_host(cramfs_is_big_endian, inode, inode);
- if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
- fprintf(stderr, _("filesystem too big. Exiting.\n"));
- exit(MKFS_ERROR);
- }
+ 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);
}
/*
* 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;
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 if (e->size) {
- 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(MKFS_ERROR);
- }
+ 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';
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) {
+ if (strcmp(optarg, "big") == 0)
cramfs_is_big_endian = 1;
- }
- else if (strcmp(optarg, "little") == 0) {
+ else if (strcmp(optarg, "little") == 0)
cramfs_is_big_endian = 0;
- }
- else if (strcmp(optarg, "host") == 0); /* default */
- else {
- perror("invalid endianness given. Must be 'big', 'little', or 'host'");
- exit(MKFS_USAGE);
- }
-
+ 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(MKFS_USAGE);
- }
+ 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;
/* old option, ignored */
break;
case 'V':
- printf(_("%s (%s)\n"),
+ printf(_("%s from %s\n"),
program_invocation_short_name, PACKAGE_STRING);
exit(MKFS_OK);
case 'v':
}
if ((argc - optind) != 2)
- usage(16);
+ usage(MKFS_USAGE);
dirname = argv[optind];
outfile = argv[optind + 1];
- if (stat(dirname, &st) < 0) {
- perror(dirname);
- exit(MKFS_USAGE);
- }
+ 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 = xcalloc(1, sizeof(struct entry));
root_entry->mode = st.st_mode;
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) "
+ warnx( _("warning: guestimate of required size (upper bound) "
"is %lldMB, but maximum image size is %uMB. "
- "We might die prematurely.\n"),
+ "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, &fslen_ub);
-
/* 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(MKFS_ERROR);
- }
+ 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_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: %zd kilobytes\n"), offset >> 10);
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 "
- "(%lld allocated, %zu used)\n"),
+ "(%lld allocated, %zu used)"),
(long long) fslen_ub, offset);
- exit(MKFS_ERROR);
- }
written = write(fd, rom_image, offset);
- if (written < 0) {
- perror(_("ROM image"));
- exit(MKFS_ERROR);
- }
- if (offset != written) {
- fprintf(stderr, _("ROM image write failed (%zd %zd)\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(MKFS_ERROR);
- }
- /* (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(MKFS_ERROR);
- return 0;
+
+ return EXIT_SUCCESS;
}