[Libguestfs] [PATCH FOR DISCUSSION ONLY] Rewrite libguestfs-supermin-helper in C.

Richard W.M. Jones rjones at redhat.com
Fri Mar 12 12:42:08 UTC 2010


On Fri, Mar 12, 2010 at 12:06:24PM +0100, Jim Meyering wrote:
> This looks nice.
> Mostly nit-picky robustness and style-related suggestions below:

Thanks for the "nit-picky" review :-)

> IMHO, it's very often better to use asprintf.
> Two reasons:
>   - eliminates wasteful (and not-so-portable) [PATH_MAX] use.
>   - eliminates risk of misbehavior if/when some combination of inputs
>       leads to a truncated buffer.

Yup, much better.  I changed all these snprintfs, strdups, mallocs,
and reallocs, to use the gnulib x-* versions as you noted.

> > +static void
> > +add_string (char ***argv, size_t *size, size_t *alloc, const char *str)
> > +{
> 
> For a variable that counts items as this "size" does,
> I'd prefer to use a name like n_used, n_items or even just "n",
> since "size" tends to evoke "buffer size", which might be misleading here.
>
> Similar, s/alloc/n_alloc/ would make me slightly happier ;-)

Ok, replaced all those with n_used / n_alloc as suggested.

> For extra credit, see xalloc.h's comment with sample use of x2nrealloc.
> Using that would let you remove the += 64 code above,
> and make this function even more concise.

Yup, much improved.

> > +  struct dirent *d;
> > +  for (;;) {
> > +    errno = 0;
> > +    d = readdir (dir);
> 
> It'd be nice to move the declaration of "d" down into the loop.
> That'd save a line and ensure that there is no accidental use
> outside of the scope where it's intended to be used.
> 
>      for (;;) {
>        errno = 0;
>        struct dirent *d = readdir (dir);

Ok, done.

> > +    if (d == NULL) {
> > +      if (errno != 0) {
> > +        /* But if it fails here, after opening and potentially reading
> > +         * part of the directory, that's a proper failure - inform the
> > +         * user and exit.
> > +         */
> > +        perror (name);
> > +        exit (EXIT_FAILURE);
> 
> Personally, I have a bias for using the "error" function to report diagnostics.
> Then, they always start with "program_name: ", and that makes it easier
> to attribute a diagnostic to its source.
> 
> Another advantage is readability: it combines the common, 2-line fprintf;exit
> idiom into a single statement, so you often end up being able to avoid
> the curly braces, too.

OK, I replaced every use of perror with error.

> The string, "libguestfs-supermin-helper" appears enough that I'd
> factor it out.  But if you go with using the "error" function,
> you'll get that for free.

Also used error here.

> > +/* Copy contents of buffer to out_fd and keep out_offset correct. */
> > +static void
> > +copy_to_fd (const void *buffer, size_t len)
> 
> You might prefer write_to_fd, since "write" is usually what you
> do when sending the contents of a buffer to an output stream/device.

Agreed, done.

> > +{
> > +  if (full_write (out_fd, buffer, len) != len) {
> > +    perror ("libguestfs-supermin-helper: write");
> > +    exit (EXIT_FAILURE);
> > +  }
> > +  out_offset += len;
> > +}
> > +
> > +/* Copy contents of file to out_fd. */
> > +static void
> > +copy_file_to_fd (const char *filename)
> > +{
> > +  char buffer[BUFFER_SIZE];
> > +  int fd2;
> > +  ssize_t r;
> 
> You know my bias is to move declarations, like the above two,
> "down" to first use, whenever possible.

OK I moved these down a bit.

> > +      fprintf (stderr, "libguestfs-supermin-helper: copy_file_len_to_fd: %s: file has increased in size\n", filename);
> 
> long lines

Mostly fixed with the error() change.

> > +    else if (S_ISLNK (statbuf->st_mode)) {
> > +      char tmp[PATH_MAX];
> 
> Why bother reading the symlink dest. name?
> It might well be yet another symlink.

Not quite sure what you meant here -- I need to read the symlink
in order to write it out to the cpio file.

> > +    /* /lib/modules/<version> */
> > +    char *modpath = malloc (strlen (MODULESDIR) + strlen (version) + 2);
> > +    if (modpath == NULL) {
> > +      perror ("malloc");
> > +      exit (1);
> > +    }
> > +    sprintf (modpath, MODULESDIR "/%s", version);
> 
> This is the classic case in which using asprintf is better.
> Or actually, better still, xasprintf, since you want to exit upon failure.
> You can replace the above with this one line:
>
>     char *modpath = xasprintf (MODULESDIR "/%s", version);

Done.

> > +static void
> > +print_timestamped_message (const char *fs, ...)
> > +{
> > +  struct timeval tv;
> > +  gettimeofday (&tv, NULL);
> 
> Technically, gettimeofday *may* fail.  Solaris documents it:

Hmmm ... it's only informational anyway.

I'll post a new patch in a minute when I've tested it a bit.

Thanks,

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://et.redhat.com/~rjones/libguestfs/
See what it can do: http://et.redhat.com/~rjones/libguestfs/recipes.html




More information about the Libguestfs mailing list