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