]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - disk-utils/mkfs.cramfs.c
wipefs: add --lock and LOCK_BLOCK_DEVICE
[thirdparty/util-linux.git] / disk-utils / mkfs.cramfs.c
index 519363419c4952f50310d68cbd8422dc4992ba81..1d0d17bf1deef050b091a9ae839eff4962493e99 100644 (file)
  * 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. */
@@ -52,7 +62,7 @@
 
 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 */
@@ -65,7 +75,7 @@ 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;
@@ -79,10 +89,6 @@ static int warn_skip = 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
@@ -92,7 +98,7 @@ struct entry {
        /* 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 */
@@ -116,38 +122,36 @@ struct entry {
 #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;
@@ -155,26 +159,28 @@ do_mmap(char *path, unsigned int size, unsigned int mode){
        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
@@ -188,16 +194,17 @@ do_munmap(char *start, unsigned int size, unsigned int mode){
 /* 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);
 
@@ -216,8 +223,10 @@ identical_file(struct entry *e1, struct entry *e2){
        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);
@@ -247,7 +256,7 @@ static int find_identical_file(struct entry *orig, struct entry *new, loff_t *fs
 
                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;
@@ -292,10 +301,10 @@ static unsigned int parse_directory(struct entry *root_entry, const char *name,
        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++) {
@@ -312,35 +321,25 @@ static unsigned int parse_directory(struct entry *root_entry, const char *name,
                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;
@@ -360,11 +359,9 @@ static unsigned int parse_directory(struct entry *root_entry, const char *name,
                        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);
@@ -414,16 +411,16 @@ static unsigned int write_superblock(struct entry *root, char *base, int size)
        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;
@@ -442,7 +439,7 @@ static void set_data_offset(struct entry *entry, char *base, unsigned long offse
        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);
 }
@@ -550,9 +547,9 @@ static int is_zero(unsigned char const *begin, unsigned len)
                             (len-- == 0 ||
                              (begin[3] == '\0' &&
                               memcmp(begin, begin + 4, len) == 0))))))));
-       else
-               /* Never create holes. */
-               return 0;
+
+       /* Never create holes. */
+       return 0;
 }
 
 /*
@@ -604,7 +601,7 @@ do_compress(char *base, unsigned int offset, unsigned char const *name,
                        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);
@@ -660,12 +657,12 @@ static unsigned int write_file(char *file, char *base, unsigned int offset)
 
        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';
@@ -708,32 +705,41 @@ int main(int argc, char **argv)
        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)
@@ -743,13 +749,13 @@ int main(int argc, char **argv)
                        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;
@@ -764,28 +770,33 @@ int main(int argc, char **argv)
                        /* 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;
@@ -794,6 +805,9 @@ int main(int argc, char **argv)
 
        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;
@@ -808,9 +822,6 @@ int main(int argc, char **argv)
                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
@@ -827,7 +838,7 @@ int main(int argc, char **argv)
                         -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;
@@ -869,17 +880,17 @@ int main(int argc, char **argv)
 
        /* 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
@@ -888,7 +899,7 @@ int main(int argc, char **argv)
        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)
@@ -908,7 +919,7 @@ int main(int argc, char **argv)
                      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;
 }