summaryrefslogtreecommitdiffstats
path: root/lib/dpkg/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dpkg/command.c')
-rw-r--r--lib/dpkg/command.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/lib/dpkg/command.c b/lib/dpkg/command.c
new file mode 100644
index 0000000..ab89d4b
--- /dev/null
+++ b/lib/dpkg/command.c
@@ -0,0 +1,211 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * command.c - command execution support
+ *
+ * Copyright © 2010-2012 Guillem Jover <guillem@debian.org>
+ *
+ * This 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 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dpkg/dpkg.h>
+#include <dpkg/i18n.h>
+#include <dpkg/string.h>
+#include <dpkg/path.h>
+#include <dpkg/command.h>
+
+/**
+ * Initialize a command structure.
+ *
+ * If name is NULL, then the last component of the filename path will be
+ * used to initialize the name member.
+ *
+ * @param cmd The command structure to initialize.
+ * @param filename The filename of the command to execute.
+ * @param name The description of the command to execute.
+ */
+void
+command_init(struct command *cmd, const char *filename, const char *name)
+{
+ cmd->filename = filename;
+ if (name == NULL)
+ cmd->name = path_basename(filename);
+ else
+ cmd->name = name;
+ cmd->argc = 0;
+ cmd->argv_size = 10;
+ cmd->argv = m_malloc(cmd->argv_size * sizeof(cmd->argv[0]));
+ cmd->argv[0] = NULL;
+}
+
+/**
+ * Destroy a command structure.
+ *
+ * Free the members managed by the command functions (i.e. the argv pointer
+ * array), and zero all members of a command structure.
+ *
+ * @param cmd The command structure to free.
+ */
+void
+command_destroy(struct command *cmd)
+{
+ cmd->filename = NULL;
+ cmd->name = NULL;
+ cmd->argc = 0;
+ cmd->argv_size = 0;
+ free(cmd->argv);
+ cmd->argv = NULL;
+}
+
+static void
+command_grow_argv(struct command *cmd, int need)
+{
+ /* We need a ghost byte for the NUL character. */
+ need++;
+
+ /* Check if we already have enough room. */
+ if ((cmd->argv_size - cmd->argc) >= need)
+ return;
+
+ cmd->argv_size = (cmd->argv_size + need) * 2;
+ cmd->argv = m_realloc(cmd->argv, cmd->argv_size * sizeof(cmd->argv[0]));
+}
+
+/**
+ * Append an argument to the command's argv.
+ *
+ * @param cmd The command structure to act on.
+ * @param arg The argument to append to argv.
+ */
+void
+command_add_arg(struct command *cmd, const char *arg)
+{
+ command_grow_argv(cmd, 1);
+
+ cmd->argv[cmd->argc++] = arg;
+ cmd->argv[cmd->argc] = NULL;
+}
+
+/**
+ * Append an argument array to the command's argv.
+ *
+ * @param cmd The command structure to act on.
+ * @param argv The NULL terminated argument array to append to argv.
+ */
+void
+command_add_argl(struct command *cmd, const char **argv)
+{
+ int i, add_argc = 0;
+
+ while (argv[add_argc] != NULL)
+ add_argc++;
+
+ command_grow_argv(cmd, add_argc);
+
+ for (i = 0; i < add_argc; i++)
+ cmd->argv[cmd->argc++] = argv[i];
+
+ cmd->argv[cmd->argc] = NULL;
+}
+
+/**
+ * Append a va_list of argument to the command's argv.
+ *
+ * @param cmd The command structure to act on.
+ * @param args The NULL terminated va_list of argument array to append to argv.
+ */
+void
+command_add_argv(struct command *cmd, va_list args)
+{
+ va_list args_copy;
+ int i, add_argc = 0;
+
+ va_copy(args_copy, args);
+ while (va_arg(args_copy, const char *) != NULL)
+ add_argc++;
+ va_end(args_copy);
+
+ command_grow_argv(cmd, add_argc);
+
+ for (i = 0; i < add_argc; i++)
+ cmd->argv[cmd->argc++] = va_arg(args, const char *);
+
+ cmd->argv[cmd->argc] = NULL;
+}
+
+/**
+ * Append a variable list of argument to the command's argv.
+ *
+ * @param cmd The command structure to act on.
+ * @param ... The NULL terminated variable list of argument to append to argv.
+ */
+void
+command_add_args(struct command *cmd, ...)
+{
+ va_list args;
+
+ va_start(args, cmd);
+ command_add_argv(cmd, args);
+ va_end(args);
+}
+
+/**
+ * Execute the command specified.
+ *
+ * The command is executed searching the PATH if the filename does not
+ * contain any slashes, or using the full path if it's either a relative or
+ * absolute pathname. This functions does not return.
+ *
+ * @param cmd The command structure to act on.
+ */
+void
+command_exec(struct command *cmd)
+{
+ execvp(cmd->filename, (char * const *)cmd->argv);
+ ohshite(_("unable to execute %s (%s)"), cmd->name, cmd->filename);
+}
+
+/**
+ * Execute a shell with a possible command.
+ *
+ * @param cmd The command string to execute, if it's NULL an interactive
+ * shell will be executed instead.
+ * @param name The description of the command to execute.
+ */
+void
+command_shell(const char *cmd, const char *name)
+{
+ const char *shell;
+ const char *mode;
+
+ if (cmd == NULL) {
+ mode = "-i";
+ shell = getenv("SHELL");
+ } else {
+ mode = "-c";
+ shell = NULL;
+ }
+
+ if (str_is_unset(shell))
+ shell = DEFAULTSHELL;
+
+ execlp(shell, shell, mode, cmd, NULL);
+ ohshite(_("unable to execute %s (%s)"), name, cmd);
+}