* 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.
*/
/*
* Old version would die on largish filesystems. Change to mmap the
- * files one by one instaed of all simultaneously. - aeb, 2002-11-01
+ * files one by one instead of all simultaneously. - aeb, 2002-11-01
*/
#include <sys/types.h>
#include <string.h>
#include <getopt.h>
#include <zconf.h>
+
+/* We don't use our include/crc32.h, but crc32 from zlib!
+ *
+ * The zlib implementation performs pre/post-conditioning. The util-linux
+ * imlemenation requires post-conditioning (xor) in the applications.
+ */
#include <zlib.h>
#include "c.h"
#include "nls.h"
#include "exitcodes.h"
#include "strutils.h"
-#define XALLOC_EXIT_CODE MKFS_ERROR
+
+#define CLOSE_EXIT_CODE MKFS_EX_ERROR
+#include "closestream.h"
+
+#define XALLOC_EXIT_CODE MKFS_EX_ERROR
#include "xalloc.h"
/* The kernel only supports PAD_SIZE of 0 and 512. */
static int verbose = 0;
-static unsigned int blksize; /* settable via -b option */
+static unsigned int blksize = 0; /* settable via -b option, default page size */
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 */
* Note that kernels up to at least 2.3.39 don't support cramfs holes,
* which is why this is turned off by default.
*/
-static int opt_edition = 0;
+static unsigned int opt_edition = 0;
static int opt_errors = 0;
static int opt_holes = 0;
static int opt_pad = 0;
static int warn_size = 0;
static int warn_uid = 0;
-#ifndef MIN
-# define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
-#endif
-
/* entry.flags */
#define CRAMFS_EFLAG_MD5 1
#define CRAMFS_EFLAG_INVALID 2
/* stats */
unsigned char *name;
unsigned int mode, size, uid, gid;
- unsigned char md5sum[MD5LENGTH];
+ unsigned char md5sum[UL_MD5LENGTH];
unsigned char flags; /* CRAMFS_EFLAG_* */
/* FS data */
#define CRAMFS_GID_WIDTH 8
#define CRAMFS_OFFSET_WIDTH 26
-/* Input status of 0 to print help and exit without an error. */
-static void
-usage(int status) {
- FILE *stream = status ? stderr : stdout;
-
- fprintf(stream,
- _("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 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"
- " -p pad by %d bytes for boot code\n"
- " -s sort directory entries (old option, ignored)\n"
- " -z make explicit holes (requires >= 2.3.39)\n"
- " dirname root of the filesystem to be compressed\n"
- " outfile output file\n"),
- program_invocation_short_name, PAD_SIZE);
-
- exit(status);
+static void __attribute__((__noreturn__)) usage(void)
+{
+ fputs(USAGE_HEADER, stdout);
+ printf(_(" %s [-h] [-v] [-b blksize] [-e edition] [-N endian] [-i file] [-n name] dirname outfile\n"),
+ program_invocation_short_name);
+ fputs(USAGE_SEPARATOR, stdout);
+ puts(_("Make compressed ROM file system."));
+ fputs(USAGE_OPTIONS, stdout);
+ puts(_( " -v be verbose"));
+ puts(_( " -E make all warnings errors (non-zero exit status)"));
+ puts(_( " -b blksize use this blocksize, must equal page size"));
+ puts(_( " -e edition set edition number (part of fsid)"));
+ printf(_(" -N endian set cramfs endianness (%s|%s|%s), default %s\n"), "big", "little", "host", "host");
+ puts(_( " -i file insert a file image into the filesystem"));
+ puts(_( " -n name set name of cramfs filesystem"));
+ printf(_(" -p pad by %d bytes for boot code\n"), PAD_SIZE);
+ puts(_( " -s sort directory entries (old option, ignored)"));
+ puts(_( " -z make explicit holes"));
+ puts(_( " dirname root of the filesystem to be compressed"));
+ puts(_( " outfile output file"));
+ fputs(USAGE_SEPARATOR, stdout);
+ printf(USAGE_HELP_OPTIONS(16));
+ printf(USAGE_MAN_TAIL("mkfs.cramfs(8)"));
+ exit(MKFS_EX_OK);
}
static char *
do_mmap(char *path, unsigned int size, unsigned int mode){
int fd;
- char *start;
+ char *start = NULL;
if (!size)
return NULL;
if (S_ISLNK(mode)) {
start = xmalloc(size);
if (readlink(path, start, size) < 0) {
- perror(path);
+ warn(_("readlink failed: %s"), path);
warn_skip = 1;
- start = NULL;
+ goto err;
}
return start;
}
fd = open(path, O_RDONLY);
if (fd < 0) {
- perror(path);
+ warn(_("cannot open %s"), path);
warn_skip = 1;
- return NULL;
+ goto err;
}
start = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (-1 == (int) (long) start)
- err(MKFS_ERROR, "mmap");
close(fd);
-
+ if (start == MAP_FAILED)
+ err(MKFS_EX_ERROR, "mmap");
return start;
+err:
+ free(start);
+ return NULL;
}
static void
/* compute md5sums, so that we do not have to compare every pair of files */
static void
mdfile(struct entry *e) {
- MD5_CTX ctx;
char *start;
start = do_mmap(e->path, e->size, e->mode);
if (start == NULL) {
e->flags |= CRAMFS_EFLAG_INVALID;
} else {
- MD5Init(&ctx);
- MD5Update(&ctx, (unsigned char *) start, e->size);
- MD5Final(e->md5sum, &ctx);
+ UL_MD5_CTX ctx;
+
+ ul_MD5Init(&ctx);
+ ul_MD5Update(&ctx, (unsigned char *) start, e->size);
+ ul_MD5Final(e->md5sum, &ctx);
do_munmap(start, e->size, e->mode);
if (!start1)
return 0;
start2 = do_mmap(e2->path, e2->size, e2->mode);
- if (!start2)
+ if (!start2) {
+ do_munmap(start1, e1->size, e1->mode);
return 0;
+ }
equal = !memcmp(start1, start2, e1->size);
do_munmap(start1, e1->size, e1->mode);
do_munmap(start2, e2->size, e2->mode);
if ((orig->flags & CRAMFS_EFLAG_MD5) &&
(new->flags & CRAMFS_EFLAG_MD5) &&
- !memcmp(orig->md5sum, new->md5sum, MD5LENGTH) &&
+ !memcmp(orig->md5sum, new->md5sum, UL_MD5LENGTH) &&
identical_file(orig, new)) {
new->same = orig;
*fslen_ub -= new->size;
endpath++;
/* read in the directory and sort */
- dircount = scandir(name, &dirlist, 0, cramsort);
+ dircount = scandir(name, &dirlist, NULL, cramsort);
if (dircount < 0)
- err(MKFS_ERROR, _("could not read directory %s"), name);
+ err(MKFS_EX_ERROR, _("could not read directory %s"), name);
/* process directory */
for (dirindex = 0; dirindex < dircount; dirindex++) {
if (dirent->d_name[0] == '.') {
if (dirent->d_name[1] == '\0')
continue;
- if (dirent->d_name[1] == '.') {
- if (dirent->d_name[2] == '\0')
- continue;
- }
+ if (dirent->d_name[1] == '.' &&
+ dirent->d_name[2] == '\0')
+ continue;
}
namelen = strlen(dirent->d_name);
- 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."),
- namelen, dirent->d_name);
+ if (namelen > MAX_INPUT_NAMELEN) {
+ namelen = MAX_INPUT_NAMELEN;
+ warn_namelen = 1;
+ }
+
memcpy(endpath, dirent->d_name, namelen + 1);
if (lstat(path, &st) < 0) {
- perror(endpath);
+ warn(_("stat of %s failed"), endpath);
warn_skip = 1;
continue;
}
entry = xcalloc(1, sizeof(struct entry));
- entry->name = (unsigned char *)xstrdup(dirent->d_name);
- if (namelen > 255) {
- /* Can't happen when reading from ext2fs. */
-
- /* TODO: we ought to avoid chopping in half
- multi-byte UTF8 characters. */
- entry->name[namelen = 255] = '\0';
- warn_namelen = 1;
- }
+ entry->name = (unsigned char *)xstrndup(dirent->d_name, namelen);
entry->mode = st.st_mode;
entry->size = st.st_size;
entry->uid = st.st_uid;
entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub);
} else if (S_ISREG(st.st_mode)) {
entry->path = xstrdup(path);
- if (entry->size) {
- if (entry->size >= (1 << CRAMFS_SIZE_WIDTH)) {
- warn_size = 1;
- entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
- }
+ if (entry->size >= (1 << CRAMFS_SIZE_WIDTH)) {
+ warn_size = 1;
+ entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
}
} else if (S_ISLNK(st.st_mode)) {
entry->path = xstrdup(path);
super->size = size;
memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));
- super->fsid.crc = crc32(0L, Z_NULL, 0);
+ super->fsid.crc = crc32(0L, NULL, 0);
super->fsid.edition = opt_edition;
super->fsid.blocks = total_blocks;
super->fsid.files = total_nodes;
memset(super->name, 0x00, sizeof(super->name));
if (opt_name)
- strncpy((char *)super->name, opt_name, sizeof(super->name));
+ str2memcpy((char *)super->name, opt_name, sizeof(super->name));
else
- strncpy((char *)super->name, "Compressed", sizeof(super->name));
+ str2memcpy((char *)super->name, "Compressed", sizeof(super->name));
super->root.mode = root->mode;
super->root.uid = root->uid;
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)))
- errx(MKFS_ERROR, _("filesystem too big. Exiting."));
+ errx(MKFS_EX_ERROR, _("filesystem too big. Exiting."));
inode->offset = (offset >> 2);
inode_from_host(cramfs_is_big_endian, inode, inode);
}
(len-- == 0 ||
(begin[3] == '\0' &&
memcmp(begin, begin + 4, len) == 0))))))));
- else
- /* Never create holes. */
- return 0;
+
+ /* Never create holes. */
+ return 0;
}
/*
printf(_("AIEEE: block \"compressed\" to > "
"2*blocklength (%ld)\n"),
len);
- exit(MKFS_ERROR);
+ exit(MKFS_EX_ERROR);
}
*(uint32_t *) (base + offset) = u32_toggle_endianness(cramfs_is_big_endian, curr);
fd = open(file, O_RDONLY);
if (fd < 0)
- err(MKFS_ERROR, _("cannot open file %s"), file);
+ err(MKFS_EX_ERROR, _("cannot open %s"), file);
buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
memcpy(base + offset, buf, image_length);
munmap(buf, image_length);
if (close (fd) < 0)
- err(MKFS_ERROR, _("cannot close file %s"), file);
+ err(MKFS_EX_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;
- uint32_t crc = crc32(0L, Z_NULL, 0);
+ uint32_t crc = crc32(0L, NULL, 0);
int c;
cramfs_is_big_endian = HOST_IS_BIG_ENDIAN; /* default is to use host order */
- blksize = getpagesize();
total_blocks = 0;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
+ close_stdout_atexit();
+
+ if (argc > 1) {
+ /* first arg may be one of our standard longopts */
+ if (!strcmp(argv[1], "--help"))
+ usage();
+ if (!strcmp(argv[1], "--version")) {
+ print_version(EXIT_SUCCESS);
+ exit(MKFS_EX_OK);
+ }
+ }
+ strutils_set_exitcode(MKFS_EX_USAGE);
/* command line options */
while ((c = getopt(argc, argv, "hb:Ee:i:n:N:psVvz")) != EOF) {
switch (c) {
case 'h':
- usage(MKFS_OK);
+ usage();
case 'b':
- blksize = strtoll_or_err(optarg, _("failed to parse blocksize argument"));
- if (blksize <= 0)
- usage(MKFS_USAGE);
+ blksize = strtou32_or_err(optarg, _("invalid blocksize argument"));
break;
case 'E':
opt_errors = 1;
break;
case 'e':
- opt_edition = strtoll_or_err(optarg, _("edition number argument failed"));
+ opt_edition = strtou32_or_err(optarg, _("invalid edition number argument"));
break;
case 'N':
if (strcmp(optarg, "big") == 0)
else if (strcmp(optarg, "host") == 0)
/* default */ ;
else
- errx(MKFS_USAGE, _("invalid endianness given."
- " Must be 'big', 'little', or 'host'"));
+ errx(MKFS_EX_USAGE, _("invalid endianness given;"
+ " must be 'big', 'little', or 'host'"));
break;
case 'i':
opt_image = optarg;
if (lstat(opt_image, &st) < 0)
- err(MKFS_USAGE, _("cannot stat %s"), opt_image);
+ err(MKFS_EX_USAGE, _("stat of %s failed"), 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 from %s\n"),
- program_invocation_short_name, PACKAGE_STRING);
- exit(MKFS_OK);
+ print_version(MKFS_EX_OK);
case 'v':
verbose = 1;
break;
case 'z':
opt_holes = 1;
break;
+ default:
+ errtryhelp(MKFS_EX_USAGE);
}
}
- if ((argc - optind) != 2)
- usage(MKFS_USAGE);
+ if ((argc - optind) != 2) {
+ warnx(_("bad usage"));
+ errtryhelp(MKFS_EX_USAGE);
+ }
dirname = argv[optind];
outfile = argv[optind + 1];
+ if (blksize == 0)
+ blksize = getpagesize();
+
if (stat(dirname, &st) < 0)
- err(MKFS_USAGE, _("cannot stat %s"), dirname);
+ err(MKFS_EX_USAGE, _("stat of %s failed"), dirname);
fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
- err(MKFS_USAGE, _("cannot open %s"), outfile);
+ err(MKFS_EX_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 */
fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
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
-1, 0);
if (-1 == (int) (long) rom_image)
- err(MKFS_ERROR, _("ROM image map"));
+ err(MKFS_EX_ERROR, _("ROM image map"));
/* Skip the first opt_pad bytes for boot loader code */
offset = opt_pad;
/* Check to make sure we allocated enough space. */
if (fslen_ub < offset)
- errx(MKFS_ERROR,
+ errx(MKFS_EX_ERROR,
_("not enough space allocated for ROM image "
"(%lld allocated, %zu used)"),
(long long) fslen_ub, offset);
written = write(fd, rom_image, offset);
- if (written < 0)
- err(MKFS_ERROR, _("ROM image"));
if (offset != written)
- errx(MKFS_ERROR, _("ROM image write failed (%zd %zd)"),
+ errx(MKFS_EX_ERROR, _("ROM image write failed (%zd %zd)"),
written, offset);
+ if (close_fd(fd) != 0)
+ err(MKFS_EX_ERROR, _("ROM image"));
/*
* (These warnings used to come at the start, but they scroll off
if (warn_namelen)
/* Can't happen when reading from ext2fs. */
/* Bytes, not chars: think UTF8. */
- warnx(_("warning: filenames truncated to 255 bytes."));
+ warnx(_("warning: filenames truncated to %u bytes."), MAX_INPUT_NAMELEN);
if (warn_skip)
warnx(_("warning: files were skipped due to errors."));
if (warn_size)
CRAMFS_OFFSET_WIDTH);
if (opt_errors &&
(warn_namelen|warn_skip|warn_size|warn_uid|warn_gid|warn_dev))
- exit(MKFS_ERROR);
+ exit(MKFS_EX_ERROR);
- return EXIT_SUCCESS;
+ return MKFS_EX_OK;
}