| /* |
| * libdpkg - Debian packaging suite library routines |
| * command.c - command execution support |
| * |
| * Copyright © 2010-2011 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 <http://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/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(const char *)); |
| 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) |
| { |
| /* 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(const char *)); |
| } |
| |
| /** |
| * 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; |
| |
| shell = getenv("SHELL"); |
| if (shell == NULL || shell[0] == '\0') |
| shell = DEFAULTSHELL; |
| |
| if (cmd == NULL) |
| mode = "-i"; |
| else |
| mode = "-c"; |
| |
| execlp(shell, shell, mode, cmd, NULL); |
| ohshite(_("unable to execute %s (%s)"), name, cmd); |
| } |