@@ -35,8 +35,9 @@ all: version $(progs) manpages
version:
bash version.sh
-btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o
+btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o helpmsg.o
$(CC) -lpthread $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o scrub.o \
+ helpmsg.o \
$(objects) $(LDFLAGS) $(LIBS)
btrfsctl: $(objects) btrfsctl.o
@@ -84,6 +85,25 @@ convert: $(objects) convert.o
ioctl-test: $(objects) ioctl-test.o
$(CC) $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS)
+helpextract: helpextract.o
+ $(CC) $(CFLAGS) -o $@ helpextract.o
+
+man/btrfs.8.2.in: helpextract
+ ./helpextract --man-page btrfs.8*.c >$@
+
+helpmsg.c: helpextract
+ echo >$@ "/*"
+ echo >>$@ " * this file contains the help messages. It is "
+ echo >>$@ " * automatically generated. do not edit ! "
+ echo >>$@ " */"
+ echo >>$@
+ echo >>$@ "#define NULL 0"
+ echo >>$@
+
+ echo -n "char * help_messages[] = " >>$@
+ ./helpextract --c-array btrfs.8*.c >>$@
+ echo >>$@ ";"
+
manpages:
cd man; make
new file mode 100644
@@ -0,0 +1,331 @@
+/**** man: btrfs subvolume delete
+ *
+ * \Bbtrfs\b \Bsubvolume delete\b\I <subvolume>\i
+ *
+ * Delete the subvolume <subvolume>.
+ *
+ * Delete the subvolume \I<subvolume>\i. If \I<subvolume>\i is not a
+ * subvolume, \Bbtrfs\b returns an error.
+ ****/
+
+/**** man: btrfs scrub start
+ *
+ * \Bbtrfs\b \Bscrub start\b [-Bdqru] {\I<path>\i|\I<device>\i}
+ *
+ * Start a new scrub.
+ *
+ * Start a scrub on all devices of the filesystem identified by \I<path>\i or on
+ * a single \I<device>\i. Without options, scrub is started as a background
+ * process. Progress can be obtained with the \Bscrub status\b command. Scrubbing
+ * involves reading all data from all disks and verifying checksums. Errors are
+ * corrected along the way if possible.
+ * \w
+ *
+ * \IOptions\i
+ * \t -B 5
+ * Do not background and print scrub statistics when finished.
+ * \t -d 5
+ * Print separate statistics for each device of the filesystem (-B only).
+ * \t -q 5
+ * Quiet. Omit error messages and statistics.
+ * \t -r 5
+ * Read only mode. Do not attempt to correct anything.
+ * \t -u 5
+ * Scrub unused space as well. (NOT IMPLEMENTED)
+ * \q
+ ****/
+
+/**** man: btrfs filesystem show
+ *
+ * \Bbtrfs\b \Bfilesystem show\b [--all-devices|<uuid>|<label>]\b
+ *
+ * Show the info of a btrfs filesystem. If no argument
+ * is passed, info of all the btrfs filesystem are shown.
+ *
+ * Show the btrfs filesystem with some additional info. If no \IUUID\i or
+ * \Ilabel\i is passed, \Bbtrfs\b show info of all the btrfs filesystem.
+ * If \B--all-devices\b is passed, all the devices under /dev are scanned;
+ * otherwise the devices list is extracted from the /proc/partitions file.
+ ****/
+
+/**** man: btrfs balance progress
+ *
+ * \Bbtrfs\b \Bbalance progress\b [\B-m\b|\B--monitor\b] \I<path>\i
+ *
+ * Show progress of the balance operation running on <path>.
+ *
+ * Report progress on the currently-running balance operation on the
+ * filesystem mounted at \I<path>\i. Use --monitor to report progress
+ * continually, including an estimate of completion time.
+ ****/
+
+/**** man: btrfs filesystem sync
+ *
+ * \Bbtrfs\b \Bfilesystem sync\b\I <path> \i
+ *
+ * Force a sync on the filesystem <path>.
+ *
+ * Force a sync for the filesystem identified by \I<path>\i.
+ ****/
+
+/**** man: btrfs subvolume set-default
+ *
+ * \Bbtrfs\b \Bsubvolume set-default\b\I <id> <path>\i
+ *
+ * Set the subvolume of the filesystem <path> which will be mounted
+ * as default.
+ *
+ * Set the subvolume of the filesystem \I<path>\i which is mounted as
+ * \Idefault\i. The subvolume is identified by \I<id>\i, which
+ * is returned by the \Bsubvolume list\b command.
+ ****/
+
+/**** man: btrfs device delete
+ *
+ * \Bbtrfs\b \Bdevice delete\b\I <dev> [<dev>..] <path>\i
+ *
+ * Remove a device from a filesystem.
+ *
+ * Remove device(s) from a filesystem identified by \I<path>\i.
+ ****/
+
+/**** man: btrfs balance cancel
+ *
+ * \Bbtrfs\b \Bbalance cancel\b \I<path>\i
+ *
+ * Cancel the balance operation running on <path>.
+ *
+ * Cancel the balance currently running on the filesystem mounted at
+ * \I<path>\i.
+ ****/
+
+/**** man: btrfs scrub resume
+ *
+ * \Bbtrfs\b \Bscrub resume\b [-Bdqru] {\I<path>\i|\I<device>\i}
+ *
+ * Resume previously canceled or interrupted scrub.
+ *
+ * Resume a canceled or interrupted scrub cycle on the filesystem identified by
+ * \I<path>\i or on a given \I<device>\i. Does not start a new scrub if the
+ * last scrub finished successfully.
+ * \w
+ *
+ * \IOptions\i
+ * \p
+ * see \Bscrub start\b.
+ * \q
+ ****/
+
+/**** man: btrfs scrub status
+ *
+ * \Bbtrfs\b \Bscrub status\b [-d] {\I<path>\i|\I<device>\i}
+ *
+ * Show status of running or finished scrub.
+ *
+ * Show status of a running scrub for the filesystem identified by \I<path>\i or
+ * for the specified \I<device>\i.
+ * If no scrub is running, show statistics of the last finished or canceled scrub
+ * for that filesystem or device.
+ * \w
+ *
+ * \IOptions\i
+ * \t -d 5
+ * Print separate statistics for each device of the filesystem.
+ * \q
+ ****/
+
+/**** man: btrfs subvolume list
+ *
+ * \Bbtrfs\b \Bsubvolume list\b\I [-p] <path>\i
+ *
+ * List the snapshot/subvolume of a filesystem.
+ *
+ * List the subvolumes present in the filesystem \I<path>\i. For every
+ * subvolume the following information is shown by default.
+ * ID <ID> top level <ID> path <path>
+ * where path is the relative path of the subvolume to the \Itop level\i
+ * subvolume.
+ * The subvolume's ID may be used by the \Bsubvolume set-default\b command, or
+ * at mount time via the \Isubvol=\i option.
+ * If \I-p\i is given, then \Iparent <ID>\i is added to the output between ID
+ * and top level. The parent's ID may be used at mount time via the
+ * \Isubvolrootid=\i option.
+ ****/
+
+**** key= btrfs help|\-\-help|\-h ; v= \fBbtrfs\fP \fBhelp|\-\-help|\-h \fP\fI\fP
+
+/**** man: btrfs filesystem balance
+ *
+ * \Bbtrfs\b \Bfilesystem balance\b [\B-wcv\b] [\B--wait\b] [\B--count\b] [\B--verbose\b] [\B-f\b|\Bfilter=\b\I<filter>\i] \I<path>\i
+ *
+ * Balance chunks across the devices. --filter=help for help on filters.
+ * --count to count chunks only (no balance performed).
+ *
+ * Balance chunks across the devices. --filter=help for help on filters.
+ * --count to count chunks only (no balance performed).
+ ****/
+
+/**** man: btrfs subvolume snapshot
+ *
+ * \Bbtrfs\b \Bsubvolume snapshot\b\I [-r] <source> [<dest>/]<name>\i
+ *
+ * Create a writable/readonly snapshot of the subvolume <source> with
+ * the name <name> in the <dest> directory.
+ *
+ * Create a writable/readonly snapshot of the subvolume \I<source>\i with the
+ * name \I<name>\i in the \I<dest>\i directory. If \I<source>\i is not a
+ * subvolume, \Bbtrfs\b returns an error. If \I-r\i is given, the snapshot
+ * will be readonly.
+ ****/
+
+/**** man: btrfs filesystem defragment
+ *
+ * \Bbtrfs\b \Bfilesystem defragment\b -c[zlib|lzo] [-l \Ilen\i] [-s \Istart\i] [-t \Isize\i] -[vf] <\Ifile\i>|<\Idir\i> [<\Ifile\i>|<\Idir\i>...]
+ *
+ * Defragment a file or a directory.
+ *
+ * Defragment file data and/or directory metadata. To defragment all files in a
+ * directory you have to specify each one on its own or use your shell wildcards.
+ *
+ * The start position and the number of bytes to deframention can be specified by \Istart\i and \Ilen\i. Any extent bigger than \Ithresh\i will be considered already defragged. Use 0 to take the kernel default, and use 1 to say eveery single extent must be rewritten. You can also turn on compression in defragment operations.
+ *
+ * \B-v\b be verbose
+ *
+ * \B-c\b compress file contents while defragmenting
+ *
+ * \B-f\b flush filesystem after defragmenting
+ *
+ * \B-s start\b defragment only from byte \Istart\i onward
+ *
+ * \B-l len\b defragment only up to \Ilen\i bytes
+ *
+ * \B-t size\b defragment only files at least \Isize\i bytes big
+ *
+ * NOTE: defragmenting with kernels up to 2.6.37 will unlink COW-ed copies of data, don't
+ * use it if you use snapshots, have de-duplicated your data or made copies with
+ * \Bcp --reflink\b.
+ ****/
+
+/**** man: btrfs subvolume find-new
+ *
+ * \Bbtrfs\b \Bsubvolume find-new\b\I <subvolume> <last_gen>\i
+ *
+ * List the recently modified files in a filesystem.
+ *
+ * List the recently modified files in a subvolume, after \I<last_gen>\i ID.
+ ****/
+
+/**** man: btrfs device add
+ *
+ * \Bbtrfs\b \Bdevice add\b\I <dev> [<dev>..] <path>\i
+ *
+ * Add a device to a filesystem.
+ *
+ * Add device(s) to the filesystem identified by \I<path>\i.
+ ****/
+
+/**** man: btrfs filesystem resize
+ *
+ * \Bbtrfs\b \Bfilesystem resize\b\I [+/\-]<size>[gkm]|max <path>\i
+ *
+ * Resize the file system. If 'max' is passed, the filesystem
+ * will occupe all available space on the device.
+ *
+ * Resize a filesystem identified by \I<path>\i.
+ * The \I<size>\i parameter specifies the new size of the filesystem.
+ * If the prefix \I+\i or \I\-\i is present the size is increased or decreased
+ * by the quantity \I<size>\i.
+ * If no units are specified, the unit of the \I<size>\i parameter defaults to
+ * bytes. Optionally, the size parameter may be suffixed by one of the following
+ * the units designators: 'K', 'M', or 'G', kilobytes, megabytes, or gigabytes,
+ * respectively.
+ *
+ * If 'max' is passed, the filesystem will occupy all available space on the
+ * volume(s).
+ *
+ * The \Bresize\b command \Bdoes not\b manipulate the size of underlying
+ * partition. If you wish to enlarge/reduce a filesystem, you must make sure you
+ * can expand the partition before enlarging the filesystem and shrink the
+ * partition after reducing the size of the filesystem.
+ ****/
+
+/**** man: btrfs filesystem label
+ *
+ * \Bbtrfs\b \Bfilesystem label\b\I <dev> [newlabel]\i
+ *
+ * With one argument, get the label of filesystem on <device>.
+ * If <newlabel> is passed, set the filesystem label to <newlabel>.
+ * The filesystem must be unmounted.
+ *
+ * Show or update the label of a filesystem. \I<dev>\i is used to identify the
+ * filesystem.
+ * If a \Inewlabel\i optional argument is passed, the label is changed. The
+ * following costraints exist for a label:
+ * \t
+ * - the maximum allowable lenght shall be less or equal than 256 chars
+ * \t
+ * - the label shall not contain the '/' or '\\' characters.
+ *
+ * NOTE: Currently there are the following limitations:
+ * \t
+ * - the filesystem has to be unmounted
+ * \t
+ * - the filesystem should not have more than one device.
+ ****/
+
+/**** man: btrfs device scan
+ *
+ * \Bbtrfs\b \Bdevice scan\b \I[--all-devices|<device> [<device>...]\i
+ *
+ * Scan all device for or the passed device for a btrfs
+ * filesystem.
+ *
+ * If one or more devices are passed, these are scanned for a btrfs filesystem.
+ * If no devices are passed, \Bbtrfs\b scans all the block devices listed
+ * in the /proc/partitions file.
+ * Finally, if \B--all-devices\b is passed, all the devices under /dev are
+ * scanned.
+ ****/
+
+**** key= btrfs <command> \-\-help ; v= \fBbtrfs\fP \fB<command> \-\-help \fP\fI\fP
+
+/**** man: btrfs balance start
+ *
+ * \Bbtrfs\b \Bbalance start\b [\B-wcv\b] [\B--wait\b] [\B--count\b] [\B--verbose\b] [\B-f\b|\Bfilter=\b\I<filter>\i] \I<path>\i
+ *
+ * Synonym for "btrfs filesystem balance".
+ *
+ * Balance the chunks of the filesystem identified by \I<path>\i across
+ * the devices. The command returns immediately, and the balance
+ * operation runs in the background. Use \B--wait\b to run
+ * synchronously instead. Use \B--count\b to scan the filesystem and
+ * report the number of chunks that would be processed. Use
+ * \B--verbose\b in synchronous mode to report the number of chunks
+ * examined and balanced. See \BBALANCE FILTERS\b, below, for details
+ * of the different filter types and syntax.
+ ****/
+
+/**** man: btrfs subvolume create
+ *
+ * \Bbtrfs\b \Bsubvolume create\b\I [<dest>/]<name>\i
+ *
+ * Create a subvolume in <dest> (or the current directory if
+ * not passed).
+ *
+ * Create a subvolume in \I<dest>\i (or in the current directory if
+ * \I<dest>\i is omitted).
+ ****/
+
+/**** man: btrfs scrub cancel
+ *
+ * \Bbtrfs\b \Bscrub cancel\b {\I<path>\i|\I<device>\i}
+ *
+ * Cancel a running scrub.
+ *
+ * If a scrub is running on the filesystem identified by \I<path>\i, cancel it.
+ * Progress is saved in the scrub progress file and scrubbing can be resumed later
+ * using the \Bscrub resume\b command.
+ * If a \I<device>\i is given, the corresponding filesystem is found and
+ * \Bscrub cancel\b behaves as if it was called on that filesystem.
+ ****/
+
new file mode 100644
@@ -0,0 +1,116 @@
+/**** text: man btrfs header
+ * .TH BTRFS 8 "" "btrfs" "btrfs"
+ * .\"
+ * .\" Man page written by Goffredo Baroncelli <kreijack@inwind.it> (Feb 2010)
+ * .\"
+ * .SH NAME
+ * btrfs \- control a btrfs filesystem
+ ****/
+
+/**** text: man btrfs synopsis
+ * .SH SYNOPSIS
+ ****/
+
+/**** text: man btrfs synopsis format
+ * \fB%s\fP
+ * .PP
+ ****/
+
+/**** text: man btrfs command format
+ *
+ * .TP
+ * %s%s
+ ****/
+
+/**** text: btrfs introduction
+ * .SH DESCRIPTION
+ * \Bbtrfs\b is used to control the filesystem and the files and directories
+ * stored. It is the tool to create or destroy a snapshot or a subvolume for
+ * the filesystem, to defrag a file or a directory, flush the data to the disk,
+ * to resize the filesystem, to scan the device.
+ *
+ * It is possible to abbreviate the commands unless the commands are ambiguous.
+ * For example: it is possible to run
+ * \Ibtrfs sub snaps\i instead of \Ibtrfs subvolume snapshot\i. But \Ibtrfs
+ * file s\i is not allowed, because \Ifile s\i may be interpreted both as
+ * \Ifilesystem show\i and as \Ifilesystem sync\i.
+ *
+ * If a command is terminated by \I--help\i, the detailed help is showed.
+ * If the passed command matches more commands, detailed help of all the
+ * matched commands is showed. For example \Ibtrfs dev --help\i shows the
+ * help of all \Idevice*\i commands.
+ ****/
+
+/**** text: man btrfs commands
+ * .SH COMMANDS
+ * .TP
+ */
+
+/**** text: btrfs notes
+ * \h BALANCE FILTERS
+ *
+ * With balance filters, it is possible to perform a balance operation on
+ * only a subset of the available chunks. Filters are specified with the
+ * \B--filter\b option of \Bbtrfs filesystem balance\b or \Bbtrfs
+ * balance start\b. Multiple filters may be given, either with multiple
+ * \B--filter\b options, or in a colon-separated list. When multiple
+ * filters are given, only the chunks meeting all of the selection
+ * critera are balanced. Help on the avaialble filters can be obtained
+ * with \B--filter=help\b.
+ *
+ *
+ * \Btype\b=[\B~\b]\I<flagname>\i[\B,\b...]
+ *
+ * Select only the chunks with the given type flag(s). Requiring a flag
+ * to be off can be specified with a \B~\b preceding the flag
+ * name. Flag names are:
+ *
+ * \Bmeta\b, \Bdata\b, \Bsys\b for metadata, file data and system
+ * chunk types.
+ *
+ * \Braid0\b, \Braid1\b, \Braid10\b, \Bdup\b for chunks of the
+ * given replication levels.
+ *
+ *
+ * \Bdevid\b=\I<n>\i
+ *
+ * Select chunks which have data on device ID \I<n>\i. This can be
+ * used, for example, to reduplicate data in a mirrored configuration
+ * where one drive has been lost due to hardware failure.
+ *
+ *
+ * \Bvrange\b=\I<start>\i,\I<end>\i
+ *
+ * Select chunks which have btrfs-internal virtual addresses within the
+ * range \I<start>\i (inclusive) to \I<end>\i (exclusive). Given the
+ * address of the last chunk moved, this filter can be used to restart a
+ * cancelled or interrupted balance operation, by supplying a range of
+ * \B0,\I<chunkaddr+1>\i.
+ *
+ * \Bdrange\b=\I<start>\i,\I<end>\i
+ *
+ * Select chunks which contain data in the address range \I<start>\i
+ * (inclusive) to \I<end>\i (exclusive) on \Iany\i block device in
+ * the filesystem. Can be mixed with the \Bdevid\b filter to select
+ * chunks in a given address range on a specific device.
+ *
+ * \h EXIT STATUS
+ * \Bbtrfs\b returns a zero exist status if it succeeds. Non zero is returned in
+ * case of failure.
+ *
+ * \h AVAILABILITY
+ * \Bbtrfs\b is part of btrfs-progs. Btrfs filesystem is currently under
+ * heavy development, and not suitable for any uses other than benchmarking and
+ * review.
+ *
+ * Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for
+ * further details.
+ *
+ * \h SEE ALSO
+ * \Bmkfs.btrfs (8)\b
+ ****/
+
+/**** text: man btrfs footer
+ ****/
+
+
@@ -181,6 +181,8 @@ static struct Command commands[] = {
{ 0, 0, 0, 0 }
};
+extern char * help_messages[];
+
static char *get_prgname(char *programname)
{
char *np;
@@ -196,21 +198,43 @@ static char *get_prgname(char *programname)
static void print_help(char *programname, struct Command *cmd, int helptype)
{
char *pc;
+ int i;
+ char *adv_help;
+ char *std_help;
+
+ /* printf("\t%s %s ", programname, cmd->verb ); */
+
+ adv_help = cmd->adv_help;
+ std_help = cmd->help;
+
+ for(i = 0; help_messages[i]; i+= 4 ){
+ if(!strncmp(help_messages[i],"btrfs ",6) &&
+ !strcmp(help_messages[i]+6,cmd->verb) ){
+ if(help_messages[i+2])
+ std_help = help_messages[i+2];
+ if(help_messages[i+3])
+ adv_help = help_messages[i+3];
+ printf("\t%s\t\t",help_messages[i+1]);
+ break;
+ }
+ }
- printf("\t%s %s ", programname, cmd->verb );
+ if( !help_messages[i])
+ printf("\t%s %s ", programname, cmd->verb );
- if (helptype == ADVANCED_HELP && cmd->adv_help)
- for(pc = cmd->adv_help; *pc; pc++){
+ if (helptype == ADVANCED_HELP && adv_help){
+ for(pc = adv_help; *pc; pc++){
putchar(*pc);
if(*pc == '\n')
printf("\t\t");
}
- else
- for(pc = cmd->help; *pc; pc++){
+ }else{
+ for(pc = std_help; *pc; pc++){
putchar(*pc);
if(*pc == '\n')
printf("\t\t");
}
+ }
putchar('\n');
}
new file mode 100644
@@ -0,0 +1,249 @@
+import os
+
+f = open("man/btrfs.8.in")
+while True:
+ line = f.readline()
+ if line.startswith(".SH SYNOPSIS"): break
+
+
+cmds = []
+while True:
+ line = f.readline()
+ pp = f.readline()
+ if not pp.startswith(".PP"):
+ break
+
+ cmds.append(line)
+
+
+while True:
+ line = f.readline()
+ if line.startswith(".SH COMMANDS"): break
+
+
+ line = f.readline()
+
+xcmds = []
+cmd = ""
+while True:
+ line = f.readline()
+
+ if line.startswith(".\\\""):
+ continue
+
+ if line.startswith(".TP") or line.startswith(".SH"):
+ xcmds.append(cmd)
+ cmd=""
+ if line.startswith(".SH"): break
+ continue
+
+ cmd += line
+
+
+#print cmds
+#print xcmds
+
+mcmds = dict()
+for c in cmds:
+ i1 = c.find("\\fP")
+ i2 = c.find("\\fP", i1+1)
+
+ key = c[:i2]
+ key = key.replace("\\fB","").replace("\\fP","")
+
+ mcmds[key] = c
+
+
+#for k,v in mcmds.iteritems():
+# print "%s: %s"%(k,v)
+
+
+for c in xcmds:
+ c = c.strip()
+ if len(c) == 0: continue
+
+ firstline = c.split("\n")[0]
+ i = firstline.find("\\fR")
+ if(i<0):
+ i = firstline.find("\\fP")
+ if(i<0):
+ print
+ print "*****Formato linea",c
+ continue
+ key = firstline[:i]
+ key = "btrfs "+key.replace("\\fB","").replace("\\fP","").replace("\\fR","")
+
+ if mcmds.has_key(key):
+ mcmds[key] = (mcmds[key], c)
+ else:
+ print
+ print "******Non riesco a trovare ",key
+
+
+
+
+f2 = open("btrfs.c")
+
+def merge_strings(s):
+ i=0
+ q=False
+ xesc=False
+ r=""
+ escape_seq={ '"': '"',
+ 'n': '\n',
+ 't': '\t' }
+
+ while(i<len(s)):
+ if xesc:
+ xesc=False
+ r += escape_seq[s[i]]
+ i+=1
+ continue
+ elif s[i] == '"':
+ q = not q
+ i+=1
+ continue
+ elif s[i] == '\\':
+ xesc = True
+ assert(q)
+ i+=1
+ continue
+
+ if q:
+ r += s[i]
+
+ i+=1
+
+ return r
+
+
+m_short_help=dict()
+r=False
+block=False
+n=0
+head = ""
+short_help=""
+for l in f2.readlines():
+ if l.startswith("static struct Command co"):
+ r=True
+ continue
+ if r and l.startswith("}"):
+ break
+ if "{" in l:
+ block=True
+ n=0
+ continue
+ if not block:
+ continue
+
+ if(n==0):
+ head=l
+ k=head.find(",")
+ if(k>=0):
+ head = head[:k]
+ head="btrfs "+merge_strings(head)
+ n+=1
+ continue
+ if(n==1):
+ short_help+=l
+ if l.strip().endswith(","):
+ m_short_help[head]=merge_strings(short_help)
+ block=False
+ short_help=""
+ head=""
+ n=0
+
+
+
+#for k,v in m_short_help.iteritems():
+# print "\n%s:\n%s"%(k,v)
+
+def cleanup(s):
+
+ r=""
+ i=0
+ bold=False
+ italic=False
+ while(i<len(s)):
+
+ if s[i:].startswith("\\fB"):
+ bold=True
+ i+=3
+ r += "\\B"
+ elif s[i:].startswith("\\fI"):
+ italic=True
+ i+=3
+ r += "\\I"
+ elif s[i:].startswith("\\fP") or s[i:].startswith("\\fR"):
+ i+=3
+ if italic:
+ r += "\\i"
+ else:
+ r += "\\b"
+ italic = False
+ bold = False
+
+ else:
+ skip = False
+
+ ll=[
+ "P .PP",
+ "p .TP",
+ "h .SH",
+ "d .BR",
+ "e .B",
+ "t .IP",
+ "w .RS",
+ "q .RE",
+ ]
+ for f in ll:
+ new=f[0]
+ old=f[2:]
+
+ if s[i:].startswith(old):
+ i+=len(old)
+ r += "\\"+new
+ skip = True
+ break
+
+ if not skip:
+
+ r += s[i]
+ i += 1
+
+ return r
+
+
+
+for k,v in mcmds.iteritems():
+ try:
+ (s,l)=v
+ except:
+ print "**** key=",k,"; v=",v
+ continue
+
+ firstline = l.split("\n")[0]
+
+ if m_short_help.has_key(k):
+ short_help=m_short_help[k]
+ r=""
+ for sh in short_help.strip().split("\n"):
+ r += " * "+sh+"\n"
+ short_help=r
+
+ else:
+ print "##############, missing key",k
+ short_help=" *\n"
+
+ print "/**** man: %s"%(k)
+ print " * "
+ print " * %s"%("\\Bbtrfs\\b "+cleanup(firstline))
+ print " * "
+ print short_help,
+ print " * "
+ for line in l.split("\n"):
+ print " * %s"%(cleanup(line))
+ print " ****/"
+ print
+
+
new file mode 100644
@@ -0,0 +1,403 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define PREFIX_MAN "/**** man: "
+#define PREFIX_TEXT "/**** text: "
+#define PREFIX_END " ****"
+#define PREFIX_SKIP " * "
+
+#define LINEBUF 1024
+
+char **msgs=0;
+int nmsg=0;
+
+static char *xstrdup(char *str){
+ char *new = strdup(str);
+ if(!new){
+ fprintf(stderr,"*** Memory allocation fail ! (xstrdup)\n");
+ exit(101);
+ }
+ return new;
+}
+
+static void *xrealloc(void *ptr, int newsize){
+ void *new = realloc(ptr, newsize);
+ if(!new){
+ fprintf(stderr,"*** Memory allocation fail ! (xrealloc)\n");
+ exit(101);
+ }
+ return new;
+
+
+}
+
+static char *xstrip(char *s){
+
+ char *last=NULL;
+ char *first;
+
+ while(*s && isspace(*s) ) s++;
+
+ first=s;
+
+ while(*s){
+ if(isspace(*s)) last=s;
+ s++;
+ }
+
+ if(last) *last=0;
+ return first;
+
+
+}
+
+static void addtuple(char *key, char *cmdline, char *short_help,
+ char *long_help){
+
+ msgs = (char**)xrealloc(msgs, sizeof(char *)*(nmsg+1)*4);
+
+ key = xstrip(key);
+
+ if( !long_help || !strcmp(long_help,"\n"))
+ long_help = short_help;
+ else if(!short_help || !strcmp(short_help, "\n"))
+ short_help = long_help;
+
+ msgs[nmsg*4] = key;
+ msgs[nmsg*4+1] = cmdline;
+ msgs[nmsg*4+2] = short_help;
+ msgs[nmsg*4+3] = long_help;
+ nmsg++;
+}
+
+
+static int search_in_file(char *nf){
+ char buf[LINEBUF+1];
+ FILE *fp;
+ int status;
+ char *key=NULL;
+ char *cmdline=NULL;
+ char *short_help=NULL;
+ char *long_help=NULL;
+
+ fp = fopen(nf,"r");
+ if(!fp){
+ int e=errno;
+ fprintf(stderr, "*** Cannot open '%s'; error = %d - '%s'\n",
+ nf, e, strerror(e));
+ return -1;
+ }
+
+ status = 0;
+ while(fgets(buf,LINEBUF,fp)){
+ // printf("status = %d, buf=%s",status, buf);
+
+ if(status == 0){
+ if(!strncmp(buf,PREFIX_MAN, strlen(PREFIX_MAN)) ){
+ key = xstrdup(buf+strlen(PREFIX_MAN));
+ status++;
+ }else if(!strncmp(buf,PREFIX_TEXT,
+ strlen(PREFIX_TEXT))){
+ key = xstrdup(buf+strlen(PREFIX_TEXT));
+ status=5;
+ }
+ continue;
+
+ }
+
+ if( !strncmp(buf,PREFIX_END, strlen(PREFIX_END)) ||
+ strncmp(buf, PREFIX_SKIP,2)){
+
+ addtuple(key, cmdline, short_help, long_help);
+ key = cmdline = short_help = long_help = 0;
+ status = 0;
+
+ continue;
+ }
+ if( status == 2){
+ if(strlen(buf)>strlen(PREFIX_SKIP))
+ cmdline = xstrdup(buf+strlen(PREFIX_SKIP));
+ status++;
+ continue;
+ }
+ if( status == 4){
+ int len;
+ int len2;
+ char *p;
+
+ if(strlen(buf)<=strlen(PREFIX_SKIP)){
+ status++;
+ continue;
+ }
+ p=buf+3;
+ while(isspace(*p) && *p ) p++;
+ if(!*p){
+ status++;
+ continue;
+ }
+
+ len2 = strlen(buf)-strlen(PREFIX_SKIP);
+
+ if(short_help)
+ len = strlen(short_help);
+ else
+ len = 0;
+ short_help = (char*)xrealloc(short_help, len+len2+1);
+ strcpy(short_help+len,buf+strlen(PREFIX_SKIP));
+ continue;
+ }
+ if( status == 5){
+ int len;
+ int len2 = strlen(buf)-strlen(PREFIX_SKIP);
+
+ if(long_help)
+ len = strlen(long_help);
+ else
+ len = 0;
+ long_help = (char*)xrealloc(long_help, len+len2+1);
+ strcpy(long_help+len,buf+strlen(PREFIX_SKIP));
+ continue;
+ }
+ if( status == 1 || status == 3 ){
+ status++;
+ continue;
+ }
+
+ fprintf(stderr,"*** Internal error: status = %d\n",status);
+ exit(100);
+
+ }
+
+ if( status != 0 ){
+ fprintf(stderr,"*** Parse error: file = '%s', "
+ "status = %d at the end of file\n",
+ nf, status);
+ exit(100);
+
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+/* remove all the escape sequence excpet \\ */
+static char * my_escape(char *src, char *filters[] ){
+
+ static char buffer[LINEBUF*5];
+
+ int i=0;
+ while(*src){
+ int j;
+ int next_char = *(src+1);
+ if(*src != '\\'){
+ buffer[i++]=*src++;
+ continue;
+ }
+ if(!next_char){
+ buffer[i++]=*src++;
+ continue;
+ }
+ if(next_char == '\\'){
+ buffer[i++]='\\';
+ src += 2;
+ continue;
+ }
+ if( !filters ){
+ src +=2;
+ continue;
+ }
+
+ j=0;
+ while(filters[j]){
+ if(filters[j][0] == next_char ){
+ strcpy(buffer+i, filters[j]+2);
+ i+=strlen(filters[j]+2);
+ break;
+ }
+ j++;
+ }
+ if(!filters[j])
+ fprintf(stderr, "Unknow escape sequence '\%c'\n",
+ next_char);
+ src += 2;
+
+ }
+
+ buffer[i]=0;
+ return buffer;
+
+}
+
+static char * escape_c_array(char *src ){
+ return my_escape(src,NULL);
+}
+static char *escape_man_page(char *src){
+ /* from Gnu troff manual */
+ static char *filters[]={
+ "B \\fB", /* bold */
+ "b \\fP", /* end bold */
+ "I \\fI", /* italic */
+ "i \\fP", /* end italic */
+ "c .\\\"", /* comment */
+ "P .PP", /* start paragraph */
+ "p .TP", /* indented paragraph */
+ "h .SH", /* header */
+ "d .BR", /* bold regular */
+ "e .B", /* bold */
+ "t .IP", /* indented paragraph */
+ "w .RS", /* move the left margin */
+ "q .RE", /* move the left margin back */
+
+
+ 0
+ };
+
+ return my_escape(src, filters);
+}
+
+
+static void dump_c_array(){
+
+ int i;
+
+ printf("{");
+ for(i=0; i < nmsg*4 ; i++){
+ char *c = msgs[i];
+ int begin;
+
+ if(i>0){
+ putchar(',');
+ if(!(i%4)) putchar('\n');
+ }
+
+ if(!c){
+ printf("\n NULL");
+ continue;
+ }
+
+ c = escape_c_array(c);
+
+ begin = 1;
+ while( *c ){
+ if(begin)
+ printf("\n \"");
+ begin = 0;
+ if( *c == '\n' ){
+ printf("\\n\"");
+ begin = 1;
+ }else if( *c == '"' ){
+ printf("\\\"");
+ }else{
+ putchar(*c);
+ }
+
+ c++;
+ }
+ if(!begin) putchar('"');
+ }
+ printf(",\n\n ");
+ for(i=0; i < 4; i++){
+ if(i>0) putchar(',');
+ printf("NULL");
+ }
+ printf("\n}\n");
+
+}
+
+static int my_sort_cmp(const void *p1, const void *p2){
+ return strcmp(*(char**)p1, *(char **)p2);
+}
+
+static void my_sort(){
+ /* FIXME: check why the sort order is wrong */
+ qsort(msgs, nmsg, sizeof(char*)*4, my_sort_cmp);
+}
+
+static int find_section(char *key){
+ int i;
+ for(i = 0 ; i < nmsg ; i++ )
+ if(!strcmp( msgs[i*4],key) ) return i;
+
+ return -1;
+}
+
+static void dump_man_page(){
+
+ int i, fmt;
+
+ i = find_section("man btrfs header");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+
+ i = find_section("man btrfs synopsis");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+
+ fmt = find_section("man btrfs synopsis format");
+ for(i = 0; i < nmsg && fmt>=0; i++ ){
+ if( strncmp("btrfs ",msgs[i*4], 6) ||
+ !strcmp("btrfs introduction", msgs[i*4] ) ||
+ !strcmp("btrfs notes", msgs[i*4] ) )
+ continue;
+
+ printf(msgs[fmt*4+3], escape_man_page(msgs[i*4+1]));
+ }
+
+ i = find_section("btrfs introduction");
+ if( i>= 0 ) printf(escape_man_page(msgs[i*4+3]));
+
+ i = find_section("man btrfs commands");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+
+ fmt = find_section("man btrfs command format");
+ for(i = 0; i < nmsg && fmt>=0; i++ ){
+
+ char big2[LINEBUF*5];
+ if( strncmp("btrfs ",msgs[i*4], 6) ||
+ !strcmp("btrfs introduction", msgs[i*4] ) ||
+ !strcmp("btrfs notes", msgs[i*4] ) )
+ continue;
+
+ strcpy(big2, escape_man_page(msgs[i*4+3]));
+ printf(msgs[fmt*4+3], escape_man_page(msgs[i*4+1]), big2);
+
+ }
+
+ i = find_section("man btrfs notes");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+
+ i = find_section("btrfs notes");
+ if( i>= 0 ) printf(escape_man_page(msgs[i*4+3]));
+
+ i = find_section("man btrfs footer");
+ if( i>= 0 ) printf(msgs[i*4+3]);
+}
+
+static void usage(char *np){
+ printf("usage: %s --man-page|--c-array <file> [<file> [...]]\n", np);
+}
+
+int main(int argc, char **argv ){
+
+ int i;
+ if( argc < 3 || ( strcmp(argv[1],"--man-page") &&
+ strcmp(argv[1],"--c-array") )){
+ usage(argv[0]);
+ return 0;
+ }
+
+ for(i=2; i < argc ; i++)
+ search_in_file(argv[i]);
+
+ my_sort();
+
+ if(!strcmp(argv[1], "--man-page"))
+ dump_man_page();
+ else if (!strcmp(argv[1], "--c-array"))
+ dump_c_array();
+
+ return 0;
+
+}
@@ -21,8 +21,6 @@ btrfs \- control a btrfs filesystem
.PP
\fBbtrfs\fP \fBfilesystem label\fP\fI <dev> [newlabel]\fP
.PP
-\fBbtrfs\fP \fBfilesystem defrag\fP\fI [options] <file>|<dir> [<file>|<dir>...]\fP
-.PP
\fBbtrfs\fP \fBsubvolume find-new\fP\fI <subvolume> <last_gen>\fP
.PP
\fBbtrfs\fP \fBfilesystem balance\fP [\fB-wcv\fP] [\fB--wait\fP] [\fB--count\fP] [\fB--verbose\fP] [\fB-f\fP|\fBfilter=\fP\fI<filter>\fP] \fI<path>\fP
@@ -37,7 +35,7 @@ btrfs \- control a btrfs filesystem
.PP
\fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices|<device> [<device>...]]\fP
.PP
-\fBbtrfs\fP \fBdevice show\fP\fI [--all-devices|<uuid>|<label>]\fP
+\fBbtrfs\fP \fBfilesystem show\fP\fI [--all-devices|<uuid>|<label>]\fP
.PP
\fBbtrfs\fP \fBdevice add\fP\fI <device> [<device>...] <path> \fP
.PP
@@ -126,7 +124,7 @@ Set the subvolume of the filesystem \fI<path>\fR which is mounted as
is returned by the \fBsubvolume list\fR command.
.TP
-\fBfilesystem defragment\fP -c[zlib|lzo] [-l \fIlen\fR] [-s \fIstart\fR] [-t \fIsize\fR] -[vf] <\fIfile\fR>|<\fIdir\fR> [<\fIfile\fR>|<\fIdir\fR>...]
+\fBfilesystem defragment\fR -c[zlib|lzo] [-l \fIlen\fR] [-s \fIstart\fR] [-t \fIsize\fR] -[vf] <\fIfile\fR>|<\fIdir\fR> [<\fIfile\fR>|<\fIdir\fR>...]
Defragment file data and/or directory metadata. To defragment all files in a
directory you have to specify each one on its own or use your shell wildcards.
@@ -148,6 +146,8 @@ The start position and the number of bytes to deframention can be specified by \
NOTE: defragmenting with kernels up to 2.6.37 will unlink COW-ed copies of data, don't
use it if you use snapshots, have de-duplicated your data or made copies with
\fBcp --reflink\fP.
+.TP
+
\fBsubvolume find-new\fR\fI <subvolume> <last_gen>\fR
List the recently modified files in a subvolume, after \fI<last_gen>\fR ID.
.TP
@@ -179,7 +179,7 @@ can expand the partition before enlarging the filesystem and shrink the
partition after reducing the size of the filesystem.
.TP
-\fBbtrfs\fP \fBfilesystem label\fP\fI <dev> [newlabel]\fP
+\fBfilesystem label\fP\fI <dev> [newlabel]\fP
Show or update the label of a filesystem. \fI<dev>\fR is used to identify the
filesystem.
If a \fInewlabel\fR optional argument is passed, the label is changed. The
@@ -203,7 +203,7 @@ If \fB--all-devices\fP is passed, all the devices under /dev are scanned;
otherwise the devices list is extracted from the /proc/partitions file.
.TP
-\fBdevice balance\fP [\fB-wcv\fP] [\fB--wait\fP] [\fB--count\fP] [\fB--verbose\fP] [\fB-f\fP|\fBfilter=\fP\fI<filter>\fP] \fI<path>\fP
+\fBfilesystem balance\fP [\fB-wcv\fP] [\fB--wait\fP] [\fB--count\fP] [\fB--verbose\fP] [\fB-f\fP|\fBfilter=\fP\fI<filter>\fP] \fI<path>\fP
.TP
\fBbalance start\fR [\fB-wcv\fP] [\fB--wait\fP] [\fB--count\fP] [\fB--verbose\fP] [\fB-f\fP|\fBfilter=\fP\fI<filter>\fP] \fI<path>\fP
@@ -270,7 +270,7 @@ last scrub finished successfully.
.RS
\fIOptions\fR
-.TP
+ .TP
see \fBscrub start\fP.
.RE
.TP
@@ -287,28 +287,30 @@ for that filesystem or device.
Print separate statistics for each device of the filesystem.
.RE
-.PP
+.TP
\fBbalance progress\fP [\fB-m\fP|\fB--monitor\fP] \fI<path>\fP
Report progress on the currently-running balance operation on the
filesystem mounted at \fI<path>\fP. Use --monitor to report progress
continually, including an estimate of completion time.
+.TP
\fBbalance cancel\fP \fI<path>\fP
Cancel the balance currently running on the filesystem mounted at
\fI<path>\fP.
.SH BALANCE FILTERS
+
With balance filters, it is possible to perform a balance operation on
only a subset of the available chunks. Filters are specified with the
-\fB--filter\fR option of \fBbtrfs device balance\fR or \fBbtrfs
+\fB--filter\fR option of \fBbtrfs filesystem balance\fR or \fBbtrfs
balance start\fR. Multiple filters may be given, either with multiple
\fB--filter\fR options, or in a colon-separated list. When multiple
filters are given, only the chunks meeting all of the selection
critera are balanced. Help on the avaialble filters can be obtained
with \fB--filter=help\fR.
-.TP
+
\fBtype\fR=[\fB~\fR]\fI<flagname>\fR[\fB,\fR...]
Select only the chunks with the given type flag(s). Requiring a flag
@@ -321,14 +323,14 @@ chunk types.
\fBraid0\fR, \fBraid1\fR, \fBraid10\fR, \fBdup\fR for chunks of the
given replication levels.
-.TP
+
\fBdevid\fR=\fI<n>\fR
Select chunks which have data on device ID \fI<n>\fR. This can be
used, for example, to reduplicate data in a mirrored configuration
where one drive has been lost due to hardware failure.
-.TP
+
\fBvrange\fR=\fI<start>\fB,\fI<end>\fR
Select chunks which have btrfs-internal virtual addresses within the
@@ -337,7 +339,6 @@ address of the last chunk moved, this filter can be used to restart a
cancelled or interrupted balance operation, by supplying a range of
\fB0,\fI<chunkaddr+1>\fR.
-.TP
\fBdrange\fR=\fI<start>\fB,\fI<end>\fR
Select chunks which contain data in the address range \fI<start>\fR