blob: 17e4d0973aa659542b2f462475397683d343df7e [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* mkfs/main.c
*
* Copyright (C) 2018-2019 HUAWEI, Inc.
* http://www.huawei.com/
* Created by Li Guifu <bluce.liguifu@huawei.com>
*/
#define _GNU_SOURCE
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <limits.h>
#include <libgen.h>
#include "erofs/config.h"
#include "erofs/print.h"
#include "erofs/cache.h"
#include "erofs/inode.h"
#include "erofs/io.h"
#include "erofs/compress.h"
#define EROFS_SUPER_END (EROFS_SUPER_OFFSET + sizeof(struct erofs_super_block))
static void usage(void)
{
fprintf(stderr, "usage: [options] FILE DIRECTORY\n\n");
fprintf(stderr, "Generate erofs image from DIRECTORY to FILE, and [options] are:\n");
fprintf(stderr, " -zX[,Y] X=compressor (Y=compression level, optional)\n");
fprintf(stderr, " -d# set output message level to # (maximum 9)\n");
}
u64 parse_num_from_str(const char *str)
{
u64 num = 0;
char *endptr = NULL;
num = strtoull(str, &endptr, 10);
BUG_ON(num == ULLONG_MAX);
return num;
}
static int mkfs_parse_options_cfg(int argc, char *argv[])
{
int opt, i;
while ((opt = getopt(argc, argv, "d:z:")) != -1) {
switch (opt) {
case 'z':
if (!optarg) {
cfg.c_compr_alg_master = "(default)";
break;
}
/* get specified compression level */
for (i = 0; optarg[i] != '\0'; ++i) {
if (optarg[i] == ',') {
cfg.c_compr_level_master =
atoi(optarg + i + 1);
optarg[i] = '\0';
break;
}
}
cfg.c_compr_alg_master = strndup(optarg, i);
break;
case 'd':
cfg.c_dbg_lvl = parse_num_from_str(optarg);
break;
default: /* '?' */
return -EINVAL;
}
}
if (optind >= argc)
return -EINVAL;
cfg.c_img_path = strdup(argv[optind++]);
if (!cfg.c_img_path)
return -ENOMEM;
if (optind > argc) {
erofs_err("Source directory is missing");
return -EINVAL;
}
cfg.c_src_path = realpath(argv[optind++], NULL);
if (!cfg.c_src_path) {
erofs_err("Failed to parse source directory: %s",
erofs_strerror(-errno));
return -ENOENT;
}
if (optind < argc) {
erofs_err("Unexpected argument: %s\n", argv[optind]);
return -EINVAL;
}
return 0;
}
int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
erofs_nid_t root_nid)
{
struct erofs_super_block sb = {
.magic = cpu_to_le32(EROFS_SUPER_MAGIC_V1),
.blkszbits = LOG_BLOCK_SIZE,
.inos = 0,
.blocks = 0,
.meta_blkaddr = sbi.meta_blkaddr,
.xattr_blkaddr = 0,
.requirements = cpu_to_le32(sbi.requirements),
};
const unsigned int sb_blksize =
round_up(EROFS_SUPER_END, EROFS_BLKSIZ);
char *buf;
struct timeval t;
if (!gettimeofday(&t, NULL)) {
sb.build_time = cpu_to_le64(t.tv_sec);
sb.build_time_nsec = cpu_to_le32(t.tv_usec);
}
sb.blocks = cpu_to_le32(erofs_mapbh(NULL, true));
sb.root_nid = cpu_to_le16(root_nid);
buf = calloc(sb_blksize, 1);
if (!buf) {
erofs_err("Failed to allocate memory for sb: %s",
erofs_strerror(-errno));
return -ENOMEM;
}
memcpy(buf + EROFS_SUPER_OFFSET, &sb, sizeof(sb));
bh->fsprivate = buf;
bh->op = &erofs_buf_write_bhops;
return 0;
}
int main(int argc, char **argv)
{
int err = 0;
struct erofs_buffer_head *sb_bh;
struct erofs_inode *root_inode;
erofs_nid_t root_nid;
erofs_init_configure();
fprintf(stderr, "%s %s\n", basename(argv[0]), cfg.c_version);
err = mkfs_parse_options_cfg(argc, argv);
if (err) {
if (err == -EINVAL)
usage();
return 1;
}
err = dev_open(cfg.c_img_path);
if (err) {
usage();
return 1;
}
erofs_show_config();
sb_bh = erofs_buffer_init();
err = erofs_bh_balloon(sb_bh, EROFS_SUPER_END);
if (err < 0) {
erofs_err("Failed to balloon erofs_super_block: %s",
erofs_strerror(err));
goto exit;
}
err = z_erofs_compress_init();
if (err) {
erofs_err("Failed to initialize compressor: %s",
erofs_strerror(err));
goto exit;
}
erofs_inode_manager_init();
root_inode = erofs_mkfs_build_tree_from_path(NULL, cfg.c_src_path);
if (IS_ERR(root_inode)) {
err = PTR_ERR(root_inode);
goto exit;
}
root_nid = erofs_lookupnid(root_inode);
erofs_iput(root_inode);
err = erofs_mkfs_update_super_block(sb_bh, root_nid);
if (err)
goto exit;
/* flush all remaining buffers */
if (!erofs_bflush(NULL))
err = -EIO;
exit:
z_erofs_compress_exit();
dev_close();
erofs_exit_configure();
if (err) {
erofs_err("\tCould not format the device : %s\n",
erofs_strerror(err));
return 1;
}
return err;
}