}
+bool
+is_subvol_mount(const string& fs_options)
+{
+ list<string> tmp1;
+ boost::split(tmp1, fs_options, boost::is_any_of(","), boost::token_compress_on);
+ for (const string& tmp2 : tmp1)
+ {
+ if (boost::starts_with(tmp2, "subvol=") || boost::starts_with(tmp2, "subvolid="))
+ return true;
+ }
+
+ return false;
+}
+
+
+libmnt_fs*
+find_filesystem(MntTable& mnt_table)
+{
+ string tmp = target;
+
+ for (;;)
+ {
+ libmnt_fs* fs = mnt_table.find_target_up(tmp, MNT_ITER_FORWARD);
+ if (!fs)
+ throw runtime_error("filesystem not found");
+
+ string fs_device = mnt_fs_get_source(fs);
+ string fs_fstype = mnt_fs_get_fstype(fs);
+ string fs_target = mnt_fs_get_target(fs);
+ string fs_options = mnt_fs_get_options(fs);
+
+ if (verbose)
+ {
+ cout << "fs-device:" << fs_device << endl;
+ cout << "fs-fstype:" << fs_fstype << endl;
+ cout << "fs-target:" << fs_target << endl;
+ cout << "fs-options:" << fs_options << endl;
+ }
+
+ if (fs_fstype != "btrfs")
+ throw runtime_error("filesystem is not btrfs");
+
+ if (fs_target == target)
+ throw runtime_error("target exists in fstab");
+
+ if (!is_subvol_mount(fs_options))
+ return fs;
+
+ if (verbose)
+ cout << "ignoring subvol mount" << endl;
+
+ if (tmp == "/")
+ throw runtime_error("filesystem not found");
+
+ tmp = dirname(fs_target);
+ }
+}
+
+
void
doit()
{
// Find filesystem.
- libmnt_fs* fs = mnt_table.find_target_up(target, MNT_ITER_FORWARD);
- string fs_fstype = mnt_fs_get_fstype(fs);
+ libmnt_fs* fs = find_filesystem(mnt_table);
string fs_target = mnt_fs_get_target(fs);
- if (verbose)
- {
- cout << "fs-device:" << mnt_fs_get_source(fs) << endl;
- cout << "fs-fstype:" << fs_fstype << endl;
- cout << "fs-target:" << fs_target << endl;
- cout << "fs-options:" << mnt_fs_get_options(fs) << endl;
- }
-
- if (fs_fstype != "btrfs")
- throw runtime_error("filesystem is not btrfs");
-
- if (fs_target == target)
- throw runtime_error("target exists in fstab");
-
// Get default subvolume of filesystem.
int fd = open(fs_target.c_str(), O_RDONLY);
// Determine subvol mount-option for tmp mount. The '@' is used on SLE.
- string subvol_option = boost::starts_with(default_subvolume_name, "@/") ? "@" : "";
+ string subvol_option = "";
+ if (default_subvolume_name == "@" || boost::starts_with(default_subvolume_name, "@/"))
+ subvol_option = "@";
if (verbose)
cout << "subvol-option:" << subvol_option << endl;
void
usage()
{
- cerr << "usage: --target=target [--nocow] [--verbose]" << endl;
+ cerr << "usage: [--nocow] [--verbose] target" << endl;
exit(EXIT_FAILURE);
}
setlocale(LC_ALL, "");
const struct option options[] = {
- { "target", required_argument, 0, 't' },
{ "nocow", no_argument, 0, 0 },
{ "verbose", no_argument, 0, 'v' },
{ 0, 0, 0, 0 }
GetOpts::parsed_opts::const_iterator opt;
- if ((opt = opts.find("target")) != opts.end())
- target = opt->second;
- else
- usage();
-
if ((opt = opts.find("nocow")) != opts.end())
set_nocow = true;
if ((opt = opts.find("verbose")) != opts.end())
verbose = true;
+ if (getopts.numArgs() != 1)
+ usage();
+
+ target = getopts.popArg();
+
try
{
doit();
<refsynopsisdiv id='synopsis'>
<cmdsynopsis>
<command>mksubvolume</command>
- <arg choice='req'>--target=<replaceable>path</replaceable></arg>
<arg choice='opt'>--nocow</arg>
<arg choice='opt'>--verbose</arg>
+ <arg choice='req'><replaceable>path</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1 id='description'>
<title>DESCRIPTION</title>
<para>Mksubvolume is a command-line program to create a btrfs subvolume
- including adding a fstab entry and mounting the subvolume.</para>
+ including adding a fstab entry and mounting the subvolume at
+ <replaceable>path</replaceable>.</para>
</refsect1>
<refsect1 id='global_options'>
<title>OPTIONS</title>
<variablelist>
- <varlistentry>
- <term><option>--target <replaceable>path</replaceable></option></term>
- <listitem>
- <para>Path of the subvolume to create.</para>
- </listitem>
- </varlistentry>
<varlistentry>
<term><option>--nocow</option></term>
<listitem>