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
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;
|
|
}
|