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

10 years ago
10 years ago
10 years ago
10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2013-2014, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license details.
  7. * ----------------------------------------------------------------------
  8. */
  9. #include <errno.h>
  10. #include <unistd.h>
  11. #include "libcork/core.h"
  12. #include "libcork/ds.h"
  13. #include "libcork/os/subprocess.h"
  14. #include "libcork/helpers/errors.h"
  15. #define ri_check_posix(call) \
  16. do { \
  17. while (true) { \
  18. if ((call) == -1) { \
  19. if (errno == EINTR) { \
  20. continue; \
  21. } else { \
  22. cork_system_error_set(); \
  23. CORK_PRINT_ERROR(); \
  24. return -1; \
  25. } \
  26. } else { \
  27. break; \
  28. } \
  29. } \
  30. } while (0)
  31. struct cork_exec {
  32. const char *program;
  33. struct cork_string_array params;
  34. struct cork_env *env;
  35. const char *cwd;
  36. struct cork_buffer description;
  37. };
  38. struct cork_exec *
  39. cork_exec_new(const char *program)
  40. {
  41. struct cork_exec *exec = cork_new(struct cork_exec);
  42. exec->program = cork_strdup(program);
  43. cork_string_array_init(&exec->params);
  44. exec->env = NULL;
  45. exec->cwd = NULL;
  46. cork_buffer_init(&exec->description);
  47. cork_buffer_set_string(&exec->description, program);
  48. return exec;
  49. }
  50. struct cork_exec *
  51. cork_exec_new_with_params(const char *program, ...)
  52. {
  53. struct cork_exec *exec;
  54. va_list args;
  55. const char *param;
  56. exec = cork_exec_new(program);
  57. cork_exec_add_param(exec, program);
  58. va_start(args, program);
  59. while ((param = va_arg(args, const char *)) != NULL) {
  60. cork_exec_add_param(exec, param);
  61. }
  62. return exec;
  63. }
  64. struct cork_exec *
  65. cork_exec_new_with_param_array(const char *program, char * const *params)
  66. {
  67. char * const *curr;
  68. struct cork_exec *exec = cork_exec_new(program);
  69. for (curr = params; *curr != NULL; curr++) {
  70. cork_exec_add_param(exec, *curr);
  71. }
  72. return exec;
  73. }
  74. void
  75. cork_exec_free(struct cork_exec *exec)
  76. {
  77. cork_strfree(exec->program);
  78. cork_array_done(&exec->params);
  79. if (exec->env != NULL) {
  80. cork_env_free(exec->env);
  81. }
  82. if (exec->cwd != NULL) {
  83. cork_strfree(exec->cwd);
  84. }
  85. cork_buffer_done(&exec->description);
  86. cork_delete(struct cork_exec, exec);
  87. }
  88. const char *
  89. cork_exec_description(struct cork_exec *exec)
  90. {
  91. return exec->description.buf;
  92. }
  93. const char *
  94. cork_exec_program(struct cork_exec *exec)
  95. {
  96. return exec->program;
  97. }
  98. size_t
  99. cork_exec_param_count(struct cork_exec *exec)
  100. {
  101. return cork_array_size(&exec->params);
  102. }
  103. const char *
  104. cork_exec_param(struct cork_exec *exec, size_t index)
  105. {
  106. return cork_array_at(&exec->params, index);
  107. }
  108. void
  109. cork_exec_add_param(struct cork_exec *exec, const char *param)
  110. {
  111. /* Don't add the first parameter to the description; that's a copy of the
  112. * program name, which we've already added. */
  113. if (!cork_array_is_empty(&exec->params)) {
  114. cork_buffer_append(&exec->description, " ", 1);
  115. cork_buffer_append_string(&exec->description, param);
  116. }
  117. cork_array_append(&exec->params, cork_strdup(param));
  118. }
  119. struct cork_env *
  120. cork_exec_env(struct cork_exec *exec)
  121. {
  122. return exec->env;
  123. }
  124. void
  125. cork_exec_set_env(struct cork_exec *exec, struct cork_env *env)
  126. {
  127. if (exec->env != NULL) {
  128. cork_env_free(exec->env);
  129. }
  130. exec->env = env;
  131. }
  132. const char *
  133. cork_exec_cwd(struct cork_exec *exec)
  134. {
  135. return exec->cwd;
  136. }
  137. void
  138. cork_exec_set_cwd(struct cork_exec *exec, const char *directory)
  139. {
  140. if (exec->cwd != NULL) {
  141. cork_strfree(exec->cwd);
  142. }
  143. exec->cwd = cork_strdup(directory);
  144. }
  145. int
  146. cork_exec_run(struct cork_exec *exec)
  147. {
  148. const char **params;
  149. /* Make sure the parameter array is NULL-terminated. */
  150. cork_array_append(&exec->params, NULL);
  151. params = cork_array_elements(&exec->params);
  152. /* Fill in the requested environment */
  153. if (exec->env != NULL) {
  154. cork_env_replace_current(exec->env);
  155. }
  156. /* Change the working directory, if requested */
  157. if (exec->cwd != NULL) {
  158. ri_check_posix(chdir(exec->cwd));
  159. }
  160. /* Execute the new program */
  161. ri_check_posix(execvp(exec->program, (char * const *) params));
  162. /* This is unreachable */
  163. return 0;
  164. }