blob: 374e3a7b9426dddbb9305c8fb2a97c9b86fc5ca6 [file] [log] [blame]
/*
* 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);
}