/* Easy ways to run external commands. For full documentation, see * 'commandrvf' below. */ int commandf (char **stdoutput, char **stderror, int flags, const char *name, ...) { va_list args; const char **argv; char *s; size_t i; int r; /* Collect the command line arguments into an array. */ i = 2; argv = malloc (sizeof (char *) * i); if (argv == NULL) { perror ("malloc"); return -1; } argv[0] = (char *) name; argv[1] = NULL; va_start (args, name); while ((s = va_arg (args, char *)) != NULL) { const char **p = realloc (argv, sizeof (char *) * (++i)); if (p == NULL) { perror ("realloc"); free (argv); va_end (args); return -1; } argv = p; argv[i-2] = s; argv[i-1] = NULL; } va_end (args); r = commandvf (stdoutput, stderror, flags, (const char * const*) argv); /* NB: Mustn't free the strings which are on the stack. */ free (argv); return r; }
/* Takes optional arguments, consult optargs_bitmask. */ int do_ntfsresize (const char *device, int64_t size, int force) { CLEANUP_FREE char *err = NULL; int r; const char *argv[MAX_ARGS]; size_t i = 0; char size_str[32]; ADD_ARG (argv, i, str_ntfsresize); ADD_ARG (argv, i, "-P"); if (optargs_bitmask & GUESTFS_NTFSRESIZE_SIZE_BITMASK) { if (size <= 0) { reply_with_error ("size is zero or negative"); return -1; } snprintf (size_str, sizeof size_str, "%" PRIi64, size); ADD_ARG (argv, i, "--size"); ADD_ARG (argv, i, size_str); } if (optargs_bitmask & GUESTFS_NTFSRESIZE_FORCE_BITMASK && force) ADD_ARG (argv, i, "--force"); ADD_ARG (argv, i, device); ADD_ARG (argv, i, NULL); r = commandvf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, argv); if (r == -1) { reply_with_error ("%s: %s", device, err); return -1; } return 0; }
char * do_command (char *const *argv) { char *out; CLEANUP_FREE char *err = NULL; int r, flags; CLEANUP_BIND_STATE struct bind_state bind_state = { .mounted = false }; CLEANUP_RESOLVER_STATE struct resolver_state resolver_state = { .mounted = false }; /* We need a root filesystem mounted to do this. */ NEED_ROOT (, return NULL); /* Conveniently, argv is already a NULL-terminated argv-style array * of parameters, so we can pass it straight in to our internal * commandv. We just have to check the list is non-empty. */ if (argv[0] == NULL) { reply_with_error ("passed an empty list"); return NULL; } if (bind_mount (&bind_state) == -1) return NULL; if (enable_network) { if (set_up_etc_resolv_conf (&resolver_state) == -1) return NULL; } flags = COMMAND_FLAG_DO_CHROOT; r = commandvf (&out, &err, flags, (const char * const *) argv); free_bind_state (&bind_state); free_resolver_state (&resolver_state); if (r == -1) { reply_with_error ("%s", err); free (out); return NULL; } return out; /* Caller frees. */ } char ** do_command_lines (char *const *argv) { CLEANUP_FREE char *out = NULL; char **lines; out = do_command (argv); if (out == NULL) return NULL; lines = split_lines (out); if (lines == NULL) return NULL; return lines; /* Caller frees. */ } char * do_sh (const char *cmd) { const char *argv[] = { "/bin/sh", "-c", cmd, NULL }; return do_command ((char **) argv); } char ** do_sh_lines (const char *cmd) { const char *argv[] = { "/bin/sh", "-c", cmd, NULL }; return do_command_lines ((char **) argv); }