You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

189 lines
4.3 KiB

/* -*- coding: utf-8 -*-
* ----------------------------------------------------------------------
* Copyright © 2013-2014, RedJack, LLC.
* All rights reserved.
*
* Please see the COPYING file in this distribution for license details.
* ----------------------------------------------------------------------
*/
#include <errno.h>
#include <unistd.h>
#include "libcork/core.h"
#include "libcork/ds.h"
#include "libcork/os/subprocess.h"
#include "libcork/helpers/errors.h"
#define ri_check_posix(call) \
do { \
while (true) { \
if ((call) == -1) { \
if (errno == EINTR) { \
continue; \
} else { \
cork_system_error_set(); \
CORK_PRINT_ERROR(); \
return -1; \
} \
} else { \
break; \
} \
} \
} while (0)
struct cork_exec {
const char *program;
struct cork_string_array params;
struct cork_env *env;
const char *cwd;
struct cork_buffer description;
};
struct cork_exec *
cork_exec_new(const char *program)
{
struct cork_exec *exec = cork_new(struct cork_exec);
exec->program = cork_strdup(program);
cork_string_array_init(&exec->params);
exec->env = NULL;
exec->cwd = NULL;
cork_buffer_init(&exec->description);
cork_buffer_set_string(&exec->description, program);
return exec;
}
struct cork_exec *
cork_exec_new_with_params(const char *program, ...)
{
struct cork_exec *exec;
va_list args;
const char *param;
exec = cork_exec_new(program);
cork_exec_add_param(exec, program);
va_start(args, program);
while ((param = va_arg(args, const char *)) != NULL) {
cork_exec_add_param(exec, param);
}
return exec;
}
struct cork_exec *
cork_exec_new_with_param_array(const char *program, char * const *params)
{
char * const *curr;
struct cork_exec *exec = cork_exec_new(program);
for (curr = params; *curr != NULL; curr++) {
cork_exec_add_param(exec, *curr);
}
return exec;
}
void
cork_exec_free(struct cork_exec *exec)
{
cork_strfree(exec->program);
cork_array_done(&exec->params);
if (exec->env != NULL) {
cork_env_free(exec->env);
}
if (exec->cwd != NULL) {
cork_strfree(exec->cwd);
}
cork_buffer_done(&exec->description);
cork_delete(struct cork_exec, exec);
}
const char *
cork_exec_description(struct cork_exec *exec)
{
return exec->description.buf;
}
const char *
cork_exec_program(struct cork_exec *exec)
{
return exec->program;
}
size_t
cork_exec_param_count(struct cork_exec *exec)
{
return cork_array_size(&exec->params);
}
const char *
cork_exec_param(struct cork_exec *exec, size_t index)
{
return cork_array_at(&exec->params, index);
}
void
cork_exec_add_param(struct cork_exec *exec, const char *param)
{
/* Don't add the first parameter to the description; that's a copy of the
* program name, which we've already added. */
if (!cork_array_is_empty(&exec->params)) {
cork_buffer_append(&exec->description, " ", 1);
cork_buffer_append_string(&exec->description, param);
}
cork_array_append(&exec->params, cork_strdup(param));
}
struct cork_env *
cork_exec_env(struct cork_exec *exec)
{
return exec->env;
}
void
cork_exec_set_env(struct cork_exec *exec, struct cork_env *env)
{
if (exec->env != NULL) {
cork_env_free(exec->env);
}
exec->env = env;
}
const char *
cork_exec_cwd(struct cork_exec *exec)
{
return exec->cwd;
}
void
cork_exec_set_cwd(struct cork_exec *exec, const char *directory)
{
if (exec->cwd != NULL) {
cork_strfree(exec->cwd);
}
exec->cwd = cork_strdup(directory);
}
int
cork_exec_run(struct cork_exec *exec)
{
const char **params;
/* Make sure the parameter array is NULL-terminated. */
cork_array_append(&exec->params, NULL);
params = cork_array_elements(&exec->params);
/* Fill in the requested environment */
if (exec->env != NULL) {
cork_env_replace_current(exec->env);
}
/* Change the working directory, if requested */
if (exec->cwd != NULL) {
ri_check_posix(chdir(exec->cwd));
}
/* Execute the new program */
ri_check_posix(execvp(exec->program, (char * const *) params));
/* This is unreachable */
return 0;
}