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.

190 lines
4.3 KiB

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