@@ -11,7 +11,7 @@ HFILES =
CFILES = proto.c xfs_mkfs.c
LLDLIBS += $(LIBXFS) $(LIBXCMD) $(LIBFROG) $(LIBRT) $(LIBPTHREAD) $(LIBBLKID) \
- $(LIBUUID)
+ $(LIBUUID) $(LIBINIH)
LTDEPENDENCIES += $(LIBXFS) $(LIBXCMD) $(LIBFROG)
LLDFLAGS = -static-libtool-libs
@@ -11,6 +11,7 @@
#include "libfrog/fsgeom.h"
#include "libfrog/topology.h"
#include "libfrog/convert.h"
+#include <ini.h>
#define TERABYTES(count, blog) ((uint64_t)(count) << (40 - (blog)))
#define GIGABYTES(count, blog) ((uint64_t)(count) << (30 - (blog)))
@@ -44,6 +45,11 @@ enum {
B_MAX_OPTS,
};
+enum {
+ C_FILE = 0,
+ C_MAX_OPTS,
+};
+
enum {
D_AGCOUNT = 0,
D_FILE,
@@ -236,6 +242,28 @@ static struct opt_params bopts = {
},
};
+/*
+ * Config file specification. Usage is:
+ *
+ * mkfs.xfs -c file=<name>
+ *
+ * A subopt is used for the filename so in future we can extend the behaviour
+ * of the config file (e.g. specified defaults rather than options) if we ever
+ * have a need to do that sort of thing.
+ */
+static struct opt_params copts = {
+ .name = 'c',
+ .subopts = {
+ [C_FILE] = "file",
+ },
+ .subopt_params = {
+ { .index = C_FILE,
+ .conflicts = { { NULL, LAST_CONFLICT } },
+ .defaultval = SUBOPT_NEEDS_VAL,
+ },
+ },
+};
+
static struct opt_params dopts = {
.name = 'd',
.subopts = {
@@ -740,6 +768,8 @@ struct cli_params {
int sectorsize;
int blocksize;
+ char *cfgfile;
+
/* parameters that depend on sector/block size being validated. */
char *dsize;
char *agsize;
@@ -854,6 +884,7 @@ usage( void )
{
fprintf(stderr, _("Usage: %s\n\
/* blocksize */ [-b size=num]\n\
+/* config file */ [-c file=xxx]\n\
/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
/* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
(sunit=value,swidth=value|su=num,sw=num|noalign),\n\
@@ -1377,6 +1408,23 @@ block_opts_parser(
return 0;
}
+static int
+cfgfile_opts_parser(
+ struct opt_params *opts,
+ int subopt,
+ char *value,
+ struct cli_params *cli)
+{
+ switch (subopt) {
+ case C_FILE:
+ cli->cfgfile = getstr(value, opts, subopt);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int
data_opts_parser(
struct opt_params *opts,
@@ -1642,6 +1690,7 @@ static struct subopts {
struct cli_params *cli);
} subopt_tab[] = {
{ 'b', &bopts, block_opts_parser },
+ { 'c', &copts, cfgfile_opts_parser },
{ 'd', &dopts, data_opts_parser },
{ 'i', &iopts, inode_opts_parser },
{ 'l', &lopts, log_opts_parser },
@@ -3552,6 +3601,47 @@ check_root_ino(
}
}
+/*
+ * INI file format option parser.
+ *
+ * This is called by the file parser library for every valid option it finds in
+ * the config file. The option is already broken down into a
+ * {section,name,value} tuple, so all we need to do is feed it to the correct
+ * suboption parser function and translate the return value.
+ *
+ * Returns 0 on failure, 1 for success.
+ */
+static int
+cfgfile_parse_ini(
+ void *user,
+ const char *section,
+ const char *name,
+ const char *value)
+{
+ struct cli_params *cli = user;
+
+ fprintf(stderr, "Ini debug: file %s, section %s, name %s, value %s\n",
+ cli->cfgfile, section, name, value);
+
+ return 1;
+}
+
+void
+cfgfile_parse(
+ struct cli_params *cli)
+{
+ if (!cli->cfgfile)
+ return;
+
+ if (ini_parse(cli->cfgfile, cfgfile_parse_ini, cli) < 0) {
+ fprintf(stderr, _("Error parsing config file %s. Aborting\n"),
+ cli->cfgfile);
+ exit(1);
+ }
+ printf(_("Parameters parsed from config file %s successfully\n"),
+ cli->cfgfile);
+}
+
int
main(
int argc,
@@ -3638,13 +3728,14 @@ main(
memcpy(&cli.sb_feat, &dft.sb_feat, sizeof(cli.sb_feat));
memcpy(&cli.fsx, &dft.fsx, sizeof(cli.fsx));
- while ((c = getopt(argc, argv, "b:d:i:l:L:m:n:KNp:qr:s:CfV")) != EOF) {
+ while ((c = getopt(argc, argv, "b:c:d:i:l:L:m:n:KNp:qr:s:CfV")) != EOF) {
switch (c) {
case 'C':
case 'f':
force_overwrite = 1;
break;
case 'b':
+ case 'c':
case 'd':
case 'i':
case 'l':
@@ -3688,6 +3779,14 @@ main(
} else
dfile = xi.dname;
+ /*
+ * Now we have all the options parsed, we can read in the option file
+ * specified on the command line via "-c file=xxx". Once we have all the
+ * options from this file parsed, we can then proceed with parameter
+ * and bounds checking and making the filesystem.
+ */
+ cfgfile_parse(&cli);
+
protostring = setup_proto(protofile);
/*