/* -*- coding: utf-8 -*- * ---------------------------------------------------------------------- * Copyright © 2013-2014, RedJack, LLC. * All rights reserved. * * Please see the COPYING file in this distribution for license details. * ---------------------------------------------------------------------- */ #include #include #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; }