Use an extensible buffer (a vector<char>) when reading /proc/self/cmdline. Tidy up some error messages. --- plugins/vddk/reexec.c | 57 ++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/plugins/vddk/reexec.c b/plugins/vddk/reexec.c index 5a5e9844..9641ee8c 100644 --- a/plugins/vddk/reexec.c +++ b/plugins/vddk/reexec.c @@ -48,6 +48,19 @@ char *reexeced; /* orig LD_LIBRARY_PATH on reexec */ +/* Extensible buffer (string). */ +DEFINE_VECTOR_TYPE(buffer, char); + +#define CLEANUP_FREE_BUFFER \ + __attribute__((cleanup (cleanup_free_buffer))) + +static void +cleanup_free_buffer (buffer *v) +{ + free (v->ptr); +} + +/* List of strings. */ DEFINE_VECTOR_TYPE(string_vector, char *); #define CLEANUP_FREE_STRING_VECTOR \ @@ -68,11 +81,13 @@ cleanup_free_string_vector (string_vector *v) static void perform_reexec (const char *env, const char *prepend) { + static const char cmdline_file[] = "/proc/self/cmdline"; + static const char exe_file[] = "/proc/self/exe"; CLEANUP_FREE char *library = NULL; + CLEANUP_FREE_BUFFER buffer buf = empty_vector; CLEANUP_FREE_STRING_VECTOR string_vector argv = empty_vector; int fd; - size_t len = 0, buflen = 512; - CLEANUP_FREE char *buf = NULL; + size_t len; /* In order to re-exec, we need our original command line. The * Linux kernel does not make it easy to know in advance how large @@ -80,42 +95,40 @@ perform_reexec (const char *env, const char *prepend) * until we get a short read. This assumes nbdkit did not alter its * original argv[]. */ - fd = open ("/proc/self/cmdline", O_RDONLY); + fd = open (cmdline_file, O_RDONLY|O_CLOEXEC); if (fd == -1) { - nbdkit_debug ("failure to parse original argv: %m"); + nbdkit_debug ("open: %s: %m", cmdline_file); return; } - do { - char *p = realloc (buf, buflen * 2); + for (;;) { ssize_t r; - if (!p) { - nbdkit_debug ("failure to parse original argv: %m"); + if (buffer_reserve (&buf, 512) == -1) { + nbdkit_debug ("realloc: %m"); return; } - buf = p; - buflen *= 2; - r = read (fd, buf + len, buflen - len); + r = read (fd, buf.ptr + buf.size, buf.alloc - buf.size); if (r == -1) { - nbdkit_debug ("failure to parse original argv: %m"); + nbdkit_debug ("read: %s: %m", cmdline_file); return; } - len += r; - } while (len == buflen); - nbdkit_debug ("original command line occupies %zu bytes", len); + if (r == 0) + break; + buf.size += r; + } + close (fd); + nbdkit_debug ("original command line occupies %zu bytes", buf.size); /* Split cmdline into argv, then append one more arg. */ - buflen = len; - len = 0; - while (len < buflen) { - if (string_vector_append (&argv, buf + len) == -1) { + for (len = 0; len < buf.size; len += strlen (buf.ptr + len) + 1) { + if (string_vector_append (&argv, buf.ptr + len) == -1) { argv_realloc_fail: nbdkit_debug ("argv: realloc: %m"); return; } - len += strlen (buf + len) + 1; } + if (!env) env = ""; nbdkit_debug ("adding reexeced_=%s", env); @@ -139,8 +152,8 @@ perform_reexec (const char *env, const char *prepend) nbdkit_debug ("re-executing with updated LD_LIBRARY_PATH=%s", library); fflush (NULL); - execvp ("/proc/self/exe", argv.ptr); - nbdkit_debug ("failure to execvp: %m"); + execvp (exe_file, argv.ptr); + nbdkit_debug ("execvp: %s: %m", exe_file); } /* See if prepend is already in LD_LIBRARY_PATH; if not, re-exec. */ -- 2.25.0