/* * libdpkg - Debian packaging suite library routines * command.c - command execution support * * Copyright © 2010-2012 Guillem Jover * * 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 . */ #include #include #include #include #include #include #include #include #include #include /** * 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); }