diff --git a/.gitignore b/.gitignore index ca4e89c38..ff5f2de07 100644 --- a/.gitignore +++ b/.gitignore @@ -153,6 +153,7 @@ Makefile.in /docs/guestfs-release-notes.1 /docs/guestfs-security.1 /docs/guestfs-testing.1 +/docs/internal-documentation.pod /docs/stamp-guestfs-building.pod /docs/stamp-guestfs-faq.pod /docs/stamp-guestfs-hacking.pod diff --git a/docs/Makefile.am b/docs/Makefile.am index f880e72e8..0fb369da9 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = \ guestfs-release-notes.pod \ guestfs-security.pod \ guestfs-testing.pod \ + make-internal-documentation.pl \ README CLEANFILES = \ @@ -39,6 +40,7 @@ CLEANFILES = \ guestfs-release-notes.1 \ guestfs-security.1 \ guestfs-testing.1 \ + internal-documentation.pod \ stamp-guestfs-building.pod \ stamp-guestfs-faq.pod \ stamp-guestfs-hacking.pod \ @@ -105,15 +107,26 @@ stamp-guestfs-hacking.pod: guestfs-hacking.pod guestfs-internals.1 $(top_builddir)/website/guestfs-internals.1.html: stamp-guestfs-internals.pod -stamp-guestfs-internals.pod: guestfs-internals.pod +stamp-guestfs-internals.pod: guestfs-internals.pod internal-documentation.pod $(PODWRAPPER) \ --section 1 \ --man guestfs-internals.1 \ --html $(top_builddir)/website/guestfs-internals.1.html \ + --insert internal-documentation.pod:__INTERNAL_DOCUMENTATION__ \ --license LGPLv2+ \ $< touch $@ +source_files := $(shell cd $(top_srcdir) && find -name '*.c' | grep -Ev '^(gobject/|builder/index-scan.c)') + +internal-documentation.pod: $(source_files:%=$(top_srcdir)/%) + rm -f $@ $@-t + ./make-internal-documentation.pl \ + --srcdir $(top_srcdir) \ + -o $@-t \ + $(source_files) + mv $@-t $@ + guestfs-performance.1 $(top_builddir)/website/guestfs-performance.1.html: stamp-guestfs-performance.pod stamp-guestfs-performance.pod: guestfs-performance.pod diff --git a/docs/guestfs-internals.pod b/docs/guestfs-internals.pod index a554b130d..bbb278d55 100644 --- a/docs/guestfs-internals.pod +++ b/docs/guestfs-internals.pod @@ -397,6 +397,15 @@ on a platform that does support supermin using L, copy it over, and use that to run libguestfs. +=head1 INTERNAL DOCUMENTATION + +This section documents internal functions inside libguestfs and +various utilities. It is intended for libguestfs developers only. +These functions are not publicly exported, and may change or be +removed at any time. + +__INTERNAL_DOCUMENTATION__ + =head1 SEE ALSO L, diff --git a/docs/make-internal-documentation.pl b/docs/make-internal-documentation.pl new file mode 100755 index 000000000..a275c1b4d --- /dev/null +++ b/docs/make-internal-documentation.pl @@ -0,0 +1,244 @@ +#!/usr/bin/env perl +# Copyright (C) 2016 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use warnings; +use strict; + +use Pod::Usage; +use Getopt::Long; + +=head1 NAME + +make-internal-documentation.pl - Generate internal documentation from C files + +=head1 SYNOPSIS + + make-internal-documentation.pl --output internal-documentation.pod + [C source files ...] + +=head1 DESCRIPTION + +C is a script that generates +L. + +You must specify the name of the output file using the I<-o> or +I<--output> option, and a list of the C source files in the project. + +Internal documentation is added to the C source files using special +comments which look like this: + + /** + * Returns true if C equals C. + */ + bool + is_equal (const char *foo, const char *bar) + ... + +The comment is written in POD format (see L). It may be +on several lines, and be split into paragraphs using blank lines. + +The function being documented should appear immediately after the +special comment, and is also copied into the documentation. + +In addition, each C file may have a special comment at the top of the +file (before any C<#include> lines) which outlines what the file does. + +=head1 OPTIONS + +=over 4 + +=cut + +my $help; + +=item B<--help> + +Display brief help. + +=cut + +my $man; + +=item B<--man> + +Display full documentation (man page). + +=cut + +my $output; + +=item B<-o output.pod> + +=item B<--output output.pod> + +Set the name of the output file (required). + +=cut + +my $srcdir = "."; + +=item B<--srcdir top_srcdir> + +Path to the top source directory. Input filenames are +located relative to this path. + +=back + +=cut + +# Clean up the program name. +my $progname = $0; +$progname =~ s{.*/}{}; + +# Parse options. +GetOptions ("help|?" => \$help, + "man|?" => \$man, + "output=s" => \$output, + "srcdir=s" => \$srcdir, + ) or pod2usage (2); +pod2usage (1) if $help; +pod2usage (-verbose => 2) if $man; + +die "$progname: missing -o/--output parameter\n" unless defined $output; + +die "$progname: missing argument: make-internal-documentation [C source files ...]\n" unless @ARGV >= 1; + +# Only consider input files which +# - are C source files +# - exist +# - contain /** comments. + +my @inputs = (); +my $input; +my $path; +foreach $input (@ARGV) { + if ($input =~ /\.c$/) { + $path = "$srcdir/$input"; + if (-r $path) { + my @cmd = ("grep", "-q", "^/\\*\\*", $path); + if (system (@cmd) == 0) { + push @inputs, $input + } + } + } +} +@inputs = sort @inputs; + +open OUTPUT, ">$output" or die "$progname: $output: $!"; + +foreach $input (@inputs) { + $path = "$srcdir/$input"; + + print OUTPUT ("=head2 F<$input>\n\n"); + + open INPUT, $path or die "$progname: $input: $!"; + + # A single special comment seen before any #includes can be used + # to outline the purpose of the source file. + my $seen_includes = 0; + my $lineno = 0; + + while () { + chomp; + $lineno++; + $seen_includes = 1 if /^#include/; + + if (m{^/\*\*$}) { + # Found a special comment. Read the whole comment. + my @comment = (); + my $found_end = 0; + my $start_lineno = $lineno; + while () { + chomp; + $lineno++; + + if (m{^ \*/$}) { + $found_end = 1; + last; + } + elsif (m{^ \* (.*)}) { + push @comment, $1; + } + elsif (m{^ \*$}) { + push @comment, ""; + } + else { + die "$progname: $input: $lineno: special comment with incorrect format\n"; + } + } + die "$progname: $input: $start_lineno: unterminated special comment" + unless $found_end; + + unless ($seen_includes) { + # If we've not seen the includes yet, then this is the + # top of file special comment, so we just write it out. + print OUTPUT join("\n", @comment), "\n"; + print OUTPUT "\n"; + } + else { + # Otherwise it's a function description, so now we + # need to read in the function definition. + my @function = (); + $found_end = 0; + $start_lineno = $lineno; + while () { + chomp; + $lineno++; + + if (m/^{/) { + $found_end = 1; + last; + } + else { + push @function, $_; + } + } + + die "$progname: $input: $start_lineno: unterminated function definition" + unless $found_end; + + # Print the function definition, followed by the comment. + print OUTPUT " ", join ("\n ", @function), "\n"; + print OUTPUT "\n"; + print OUTPUT join("\n", @comment), "\n"; + print OUTPUT "\n"; + } + } + elsif (m{^/\*\*}) { + die "$progname: $input: $lineno: special comment with incorrect format\n"; + } + } + + close INPUT; +} + +close OUTPUT or die "$progname: $output: close: $!"; + +exit 0; + +=head1 SEE ALSO + +L, +L. + +=head1 AUTHOR + +Richard W.M. Jones. + +=head1 COPYRIGHT + +Copyright (C) 2012-2016 Red Hat Inc. diff --git a/po/POTFILES b/po/POTFILES index 20a330efa..9e4d9ccf1 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -126,6 +126,7 @@ df/main.c df/output.c df/parallel.c diff/diff.c +docs/make-internal-documentation.pl edit/edit.c erlang/erl-guestfs-proto.c erlang/erl-guestfs.c diff --git a/src/launch.c b/src/launch.c index 7bc9cf968..fddd43ffa 100644 --- a/src/launch.c +++ b/src/launch.c @@ -16,6 +16,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/** + * This file implements L. + * + * Most of the work is done by the backends (see + * L), which are implemented in + * F, F etc, so this file + * mostly passes calls through to the current backend. + */ + #include #include @@ -119,9 +128,11 @@ guestfs_int_launch_send_progress (guestfs_h *g, int perdozen) } } -/* Compute Y - X and return the result in milliseconds. +/** + * Compute C and return the result in milliseconds. + * * Approximately the same as this code: - * http://www.mpp.mpg.de/~huber/util/timevaldiff.c + * L */ int64_t guestfs_int_timeval_diff (const struct timeval *x, const struct timeval *y) @@ -148,7 +159,10 @@ guestfs_impl_get_pid (guestfs_h *g) return g->backend_ops->get_pid (g, g->backend_data); } -/* Maximum number of disks. */ +/** + * Returns the maximum number of disks allowed to be added to the + * backend (backend dependent). + */ int guestfs_impl_max_disks (guestfs_h *g) { @@ -159,8 +173,10 @@ guestfs_impl_max_disks (guestfs_h *g) return g->backend_ops->max_disks (g, g->backend_data); } -/* You had to call this function after launch in versions <= 1.0.70, - * but it is now a no-op. +/** + * Implementation of L. You had to + * call this function after launch in versions E 1.0.70, but it is + * now an (almost) no-op. */ int guestfs_impl_wait_ready (guestfs_h *g) @@ -251,25 +267,6 @@ guestfs_impl_config (guestfs_h *g, return 0; } -/* Construct the Linux command line passed to the appliance. This is - * used by the 'direct' and 'libvirt' backends, and is simply - * located in this file because it's a convenient place for this - * common code. - * - * The 'appliance_dev' parameter must be the full device name of the - * appliance disk and must have already been adjusted to take into - * account virtio-blk or virtio-scsi; eg "/dev/sdb". - * - * The 'flags' parameter can contain the following flags logically - * or'd together (or 0): - * - * GUESTFS___APPLIANCE_COMMAND_LINE_IS_TCG: If we are launching a qemu - * TCG guest (ie. KVM is known to be disabled or unavailable). If you - * don't know, don't pass this flag. - * - * Note that this returns a newly allocated buffer which must be freed - * by the caller. - */ #if defined(__powerpc64__) #define SERIAL_CONSOLE "console=hvc0 console=ttyS0" #elif defined(__arm__) || defined(__aarch64__) @@ -284,6 +281,31 @@ guestfs_impl_config (guestfs_h *g, #define EARLYPRINTK "" #endif +/** + * Construct the Linux command line passed to the appliance. This is + * used by the C and C backends, and is simply + * located in this file because it's a convenient place for this + * common code. + * + * The C parameter must be the full device name of the + * appliance disk and must have already been adjusted to take into + * account virtio-blk or virtio-scsi; eg C. + * + * The C parameter can contain the following flags logically + * or'd together (or 0): + * + * =over 4 + * + * =item C + * + * If we are launching a qemu TCG guest (ie. KVM is known to be + * disabled or unavailable). If you don't know, don't pass this flag. + * + * =back + * + * Note that this function returns a newly allocated buffer which must + * be freed by the caller. + */ char * guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev, int flags)