X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=daemon%2Fguestfsd.c;h=e8fb48fc5be0caf335cdc8c66b91aa4561201c6d;hp=0a3e64f57beb393b2a234dff0e764d91f10855ad;hb=58e7e42033b1ac5044ae03f0aa5d5082c5fdb497;hpb=4513f2ec7b6aa843005ba886cdd1747b6ff00915 diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c index 0a3e64f..e8fb48f 100644 --- a/daemon/guestfsd.c +++ b/daemon/guestfsd.c @@ -1,5 +1,5 @@ /* libguestfs - the guestfsd daemon - * Copyright (C) 2009 Red Hat Inc. + * Copyright (C) 2009 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 @@ -36,6 +36,7 @@ #include #include #include +#include #include "daemon.h" @@ -47,11 +48,27 @@ static void usage (void); int verbose = 0; +static int print_shell_quote (FILE *stream, const struct printf_info *info, const void *const *args); +static int print_sysroot_shell_quote (FILE *stream, const struct printf_info *info, const void *const *args); +#ifdef HAVE_REGISTER_PRINTF_SPECIFIER +static int print_arginfo (const struct printf_info *info, size_t n, int *argtypes, int *size); +#else +#ifdef HAVE_REGISTER_PRINTF_FUNCTION +static int print_arginfo (const struct printf_info *info, size_t n, int *argtypes); +#else +#error "HAVE_REGISTER_PRINTF_{SPECIFIER|FUNCTION} not defined" +#endif +#endif + +/* Location to mount root device. */ +const char *sysroot = "/sysroot"; /* No trailing slash. */ +int sysroot_len = 8; + int main (int argc, char *argv[]) { static const char *options = "fh:p:?"; - static struct option long_options[] = { + static const struct option long_options[] = { { "foreground", 0, 0, 'f' }, { "help", 0, 0, '?' }, { "host", 1, 0, 'h' }, @@ -72,6 +89,19 @@ main (int argc, char *argv[]) uint32_t len; struct sigaction sa; +#ifdef HAVE_REGISTER_PRINTF_SPECIFIER + /* http://udrepper.livejournal.com/20948.html */ + register_printf_specifier ('Q', print_shell_quote, print_arginfo); + register_printf_specifier ('R', print_sysroot_shell_quote, print_arginfo); +#else +#ifdef HAVE_REGISTER_PRINTF_FUNCTION + register_printf_function ('Q', print_shell_quote, print_arginfo); + register_printf_function ('R', print_sysroot_shell_quote, print_arginfo); +#else +#error "HAVE_REGISTER_PRINTF_{SPECIFIER|FUNCTION} not defined" +#endif +#endif + for (;;) { c = getopt_long (argc, argv, options, long_options, NULL); if (c == -1) break; @@ -221,6 +251,27 @@ main (int argc, char *argv[]) exit (0); } +/* Turn "/path" into "/sysroot/path". + * + * Caller must check for NULL and call reply_with_perror ("malloc") + * if it is. Caller must also free the string. + * + * See also the custom %R printf formatter which does shell quoting too. + */ +char * +sysroot_path (const char *path) +{ + char *r; + int len = strlen (path) + sysroot_len + 1; + + r = malloc (len); + if (r == NULL) + return NULL; + + snprintf (r, len, "%s%s", sysroot, path); + return r; +} + int xwrite (int sock, const void *buf, size_t len) { @@ -572,19 +623,23 @@ commandrv (char **stdoutput, char **stderror, char * const* const argv) * trailing \n characters from the error buffer (not from stdout). */ if (stdoutput) { - *stdoutput = realloc (*stdoutput, so_size+1); - if (*stdoutput == NULL) { + void *q = realloc (*stdoutput, so_size+1); + if (q == NULL) { perror ("realloc"); - *stdoutput = NULL; - } else + free (*stdoutput); + } + *stdoutput = q; + if (*stdoutput) (*stdoutput)[so_size] = '\0'; } if (stderror) { - *stderror = realloc (*stderror, se_size+1); - if (*stderror == NULL) { + void *q = realloc (*stderror, se_size+1); + if (q == NULL) { perror ("realloc"); - *stderror = NULL; - } else { + free (*stderror); + } + *stderror = q; + if (*stderror) { (*stderror)[se_size] = '\0'; se_size--; while (se_size >= 0 && (*stderror)[se_size] == '\n') @@ -658,42 +713,66 @@ split_lines (char *str) return lines; } -/* Quote 'in' for the shell, and write max len-1 bytes to out. The - * result will be NUL-terminated, even if it is truncated. - * - * Returns number of bytes needed, so if result >= len then the buffer - * should have been longer. - * - * XXX This doesn't quote \n correctly (but is still safe). +/* printf helper function so we can use %Q ("quoted") and %R to print + * shell-quoted strings. See HACKING file for more details. */ -int -shell_quote (char *out, int len, const char *in) +static int +print_shell_quote (FILE *stream, + const struct printf_info *info, + const void *const *args) { #define SAFE(c) (isalnum((c)) || \ (c) == '/' || (c) == '-' || (c) == '_' || (c) == '.') - int i, j; - int outlen = strlen (in); + int i, len; + const char *str = *((const char **) (args[0])); - /* Calculate how much output space this really needs. */ - for (i = 0; in[i]; ++i) - if (!SAFE (in[i])) outlen++; + for (i = len = 0; str[i]; ++i) { + if (!SAFE(str[i])) { + putc ('\\', stream); + len ++; + } + putc (str[i], stream); + len ++; + } - /* Now copy the string, but only up to len-1 bytes. */ - for (i = 0, j = 0; in[i]; ++i) { - int is_safe = SAFE (in[i]); + return len; +} - /* Enough space left to write this character? */ - if (j >= len-1 || (!is_safe && j >= len-2)) - break; +static int +print_sysroot_shell_quote (FILE *stream, + const struct printf_info *info, + const void *const *args) +{ +#define SAFE(c) (isalnum((c)) || \ + (c) == '/' || (c) == '-' || (c) == '_' || (c) == '.') + fputs (sysroot, stream); + return sysroot_len + print_shell_quote (stream, info, args); +} - if (!is_safe) out[j++] = '\\'; - out[j++] = in[i]; +#ifdef HAVE_REGISTER_PRINTF_SPECIFIER +static int +print_arginfo (const struct printf_info *info, + size_t n, int *argtypes, int *size) +{ + if (n > 0) { + argtypes[0] = PA_STRING; + size[0] = sizeof (const char *); } - - out[j] = '\0'; - - return outlen; + return 1; } +#else +#ifdef HAVE_REGISTER_PRINTF_FUNCTION +static int +print_arginfo (const struct printf_info *info, size_t n, int *argtypes) +{ + if (n > 0) + argtypes[0] = PA_STRING; + return 1; +} +#else +#error "HAVE_REGISTER_PRINTF_{SPECIFIER|FUNCTION} not defined" +#endif +#endif /* Perform device name translation. Don't call this directly - * use the IS_DEVICE macro. @@ -741,3 +820,16 @@ device_name_translation (char *device, const char *func) device[5] = 's'; /* Restore original device name. */ goto error; } + +/* LVM and other commands aren't synchronous, especially when udev is + * involved. eg. You can create or remove some device, but the /dev + * device node won't appear until some time later. This means that + * you get an error if you run one command followed by another. + * Use 'udevadm settle' after certain commands, but don't be too + * fussed if it fails. + */ +void +udev_settle (void) +{ + command (NULL, NULL, "/sbin/udevadm", "settle", NULL); +}