reproc.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. #pragma once
  2. #include <stdbool.h>
  3. #include <stddef.h>
  4. #include <stdint.h>
  5. #include <stdio.h>
  6. #include <reproc/export.h>
  7. #ifdef __cplusplus
  8. extern "C" {
  9. #endif
  10. /*! Used to store information about a child process. `reproc_t` is an opaque
  11. type and can be allocated and released via `reproc_new` and `reproc_destroy`
  12. respectively. */
  13. typedef struct reproc_t reproc_t;
  14. /*! reproc error naming follows POSIX errno naming prefixed with `REPROC`. */
  15. /*! An invalid argument was passed to an API function */
  16. REPROC_EXPORT extern const int REPROC_EINVAL;
  17. /*! A timeout value passed to an API function expired. */
  18. REPROC_EXPORT extern const int REPROC_ETIMEDOUT;
  19. /*! The child process closed one of its streams (and in the case of
  20. stdout/stderr all of the data remaining in that stream has been read). */
  21. REPROC_EXPORT extern const int REPROC_EPIPE;
  22. /*! A memory allocation failed. */
  23. REPROC_EXPORT extern const int REPROC_ENOMEM;
  24. /*! A call to `reproc_read` or `reproc_write` would have blocked. */
  25. REPROC_EXPORT extern const int REPROC_EWOULDBLOCK;
  26. /*! Signal exit status constants. */
  27. REPROC_EXPORT extern const int REPROC_SIGKILL;
  28. REPROC_EXPORT extern const int REPROC_SIGTERM;
  29. /*! Tells a function that takes a timeout value to wait indefinitely. */
  30. REPROC_EXPORT extern const int REPROC_INFINITE;
  31. /*! Tells `reproc_wait` to wait until the deadline passed to `reproc_start`
  32. expires. */
  33. REPROC_EXPORT extern const int REPROC_DEADLINE;
  34. /*! Stream identifiers used to indicate which stream to act on. */
  35. typedef enum {
  36. /*! stdin */
  37. REPROC_STREAM_IN,
  38. /*! stdout */
  39. REPROC_STREAM_OUT,
  40. /*! stderr */
  41. REPROC_STREAM_ERR,
  42. } REPROC_STREAM;
  43. /*! Used to tell reproc where to redirect the streams of the child process. */
  44. typedef enum {
  45. /*! Use the default redirect behavior, see the documentation for `redirect` in
  46. `reproc_options`. */
  47. REPROC_REDIRECT_DEFAULT,
  48. /*! Redirect to a pipe. */
  49. REPROC_REDIRECT_PIPE,
  50. /*! Redirect to the corresponding stream from the parent process. */
  51. REPROC_REDIRECT_PARENT,
  52. /*! Redirect to /dev/null (or NUL on Windows). */
  53. REPROC_REDIRECT_DISCARD,
  54. /*! Redirect to child process stdout. Only valid for stderr. */
  55. REPROC_REDIRECT_STDOUT,
  56. /*! Redirect to a handle (fd on Linux, HANDLE/SOCKET on Windows). */
  57. REPROC_REDIRECT_HANDLE,
  58. /*! Redirect to a `FILE *`. */
  59. REPROC_REDIRECT_FILE,
  60. /*! Redirect to a specific path. */
  61. REPROC_REDIRECT_PATH,
  62. } REPROC_REDIRECT;
  63. /*! Used to tell `reproc_stop` how to stop a child process. */
  64. typedef enum {
  65. /*! noop (no operation) */
  66. REPROC_STOP_NOOP,
  67. /*! `reproc_wait` */
  68. REPROC_STOP_WAIT,
  69. /*! `reproc_terminate` */
  70. REPROC_STOP_TERMINATE,
  71. /*! `reproc_kill` */
  72. REPROC_STOP_KILL,
  73. } REPROC_STOP;
  74. typedef struct reproc_stop_action {
  75. REPROC_STOP action;
  76. int timeout;
  77. } reproc_stop_action;
  78. typedef struct reproc_stop_actions {
  79. reproc_stop_action first;
  80. reproc_stop_action second;
  81. reproc_stop_action third;
  82. } reproc_stop_actions;
  83. // clang-format off
  84. #define REPROC_STOP_ACTIONS_NULL (reproc_stop_actions) { \
  85. { REPROC_STOP_NOOP, 0 }, \
  86. { REPROC_STOP_NOOP, 0 }, \
  87. { REPROC_STOP_NOOP, 0 }, \
  88. }
  89. // clang-format on
  90. #if defined(_WIN32)
  91. typedef void *reproc_handle; // `HANDLE`
  92. #else
  93. typedef int reproc_handle; // fd
  94. #endif
  95. typedef struct reproc_redirect {
  96. /*! Type of redirection. */
  97. REPROC_REDIRECT type;
  98. /*!
  99. Redirect a stream to an operating system handle. The given handle must be in
  100. blocking mode ( `O_NONBLOCK` and `OVERLAPPED` handles are not supported).
  101. Note that reproc does not take ownership of the handle. The user is
  102. responsible for closing the handle after passing it to `reproc_start`. Since
  103. the operating system will copy the handle to the child process, the handle
  104. can be closed immediately after calling `reproc_start` if the handle is not
  105. needed in the parent process anymore.
  106. If `handle` is set, `type` must be unset or set to `REPROC_REDIRECT_HANDLE`
  107. and `file`, `path` must be unset.
  108. */
  109. reproc_handle handle;
  110. /*!
  111. Redirect a stream to a file stream.
  112. Note that reproc does not take ownership of the file. The user is
  113. responsible for closing the file after passing it to `reproc_start`. Just
  114. like with `handles`, the operating system will copy the file handle to the
  115. child process so the file can be closed immediately after calling
  116. `reproc_start` if it isn't needed anymore by the parent process.
  117. Any file passed to `file.in` must have been opened in read mode. Likewise,
  118. any files passed to `file.out` or `file.err` must have been opened in write
  119. mode.
  120. If `file` is set, `type` must be unset or set to `REPROC_REDIRECT_FILE` and
  121. `handle`, `path` must be unset.
  122. */
  123. FILE *file;
  124. /*!
  125. Redirect a stream to a given path.
  126. reproc will create or open the file at the given path. Depending on the
  127. stream, the file is opened in read or write mode.
  128. If `path` is set, `type` must be unset or set to `REPROC_REDIRECT_PATH` and
  129. `handle`, `file` must be unset.
  130. */
  131. const char *path;
  132. } reproc_redirect;
  133. typedef enum {
  134. REPROC_ENV_EXTEND,
  135. REPROC_ENV_EMPTY,
  136. } REPROC_ENV;
  137. typedef struct reproc_options {
  138. /*!
  139. `working_directory` specifies the working directory for the child process. If
  140. `working_directory` is `NULL`, the child process runs in the working directory
  141. of the parent process.
  142. */
  143. const char *working_directory;
  144. struct {
  145. /*!
  146. `behavior` specifies whether the child process should start with a copy of
  147. the parent process environment variables or an empty environment. By
  148. default, the child process starts with a copy of the parent's environment
  149. variables (`REPROC_ENV_EXTEND`). If `behavior` is set to `REPROC_ENV_EMPTY`,
  150. the child process starts with an empty environment.
  151. */
  152. REPROC_ENV behavior;
  153. /*!
  154. `extra` is an array of UTF-8 encoded, NUL-terminated strings that specifies
  155. extra environment variables for the child process. It has the following
  156. layout:
  157. - All elements except the final element must be of the format `NAME=VALUE`.
  158. - The final element must be `NULL`.
  159. Example: ["IP=127.0.0.1", "PORT=8080", `NULL`]
  160. If `env` is `NULL`, no extra environment variables are added to the
  161. environment of the child process.
  162. */
  163. const char *const *extra;
  164. } env;
  165. /*!
  166. `redirect` specifies where to redirect the streams from the child process.
  167. By default each stream is redirected to a pipe which can be written to (stdin)
  168. or read from (stdout/stderr) using `reproc_write` and `reproc_read`
  169. respectively.
  170. */
  171. struct {
  172. /*!
  173. `in`, `out` and `err` specify where to redirect the standard I/O streams of
  174. the child process. When not set, `in` and `out` default to
  175. `REPROC_REDIRECT_PIPE` while `err` defaults to `REPROC_REDIRECT_PARENT`.
  176. */
  177. reproc_redirect in;
  178. reproc_redirect out;
  179. reproc_redirect err;
  180. /*!
  181. Use `REPROC_REDIRECT_PARENT` instead of `REPROC_REDIRECT_PIPE` when `type`
  182. is unset.
  183. When this option is set, `discard`, `file` and `path` must be unset.
  184. */
  185. bool parent;
  186. /*!
  187. Use `REPROC_REDIRECT_DISCARD` instead of `REPROC_REDIRECT_PIPE` when `type`
  188. is unset.
  189. When this option is set, `parent`, `file` and `path` must be unset.
  190. */
  191. bool discard;
  192. /*!
  193. Shorthand for redirecting stdout and stderr to the same file.
  194. If this option is set, `out`, `err`, `parent`, `discard` and `path` must be
  195. unset.
  196. */
  197. FILE *file;
  198. /*!
  199. Shorthand for redirecting stdout and stderr to the same path.
  200. If this option is set, `out`, `err`, `parent`, `discard` and `file` must be
  201. unset.
  202. */
  203. const char *path;
  204. } redirect;
  205. /*!
  206. Stop actions that are passed to `reproc_stop` in `reproc_destroy` to stop the
  207. child process. See `reproc_stop` for more information on how `stop` is
  208. interpreted.
  209. */
  210. reproc_stop_actions stop;
  211. /*!
  212. Maximum allowed duration in milliseconds the process is allowed to run in
  213. milliseconds. If the deadline is exceeded, Any ongoing and future calls to
  214. `reproc_poll` return `REPROC_ETIMEDOUT`.
  215. Note that only `reproc_poll` takes the deadline into account. More
  216. specifically, if the `nonblocking` option is not enabled, `reproc_read` and
  217. `reproc_write` can deadlock waiting on the child process to perform I/O. If
  218. this is a problem, enable the `nonblocking` option and use `reproc_poll`
  219. together with a deadline/timeout to avoid any deadlocks.
  220. If `REPROC_DEADLINE` is passed as the timeout to `reproc_wait`, it waits until
  221. the deadline expires.
  222. When `deadline` is zero, no deadline is set for the process.
  223. */
  224. int deadline;
  225. /*!
  226. `input` is written to the stdin pipe before the child process is started.
  227. Because `input` is written to the stdin pipe before the process starts,
  228. `input.size` must be smaller than the system's default pipe size (64KB).
  229. If `input` is set, the stdin pipe is closed after `input` is written to it.
  230. If `redirect.in` is set, this option may not be set.
  231. */
  232. struct {
  233. const uint8_t *data;
  234. size_t size;
  235. } input;
  236. /*!
  237. This option can only be used on POSIX systems. If enabled on Windows, an error
  238. will be returned.
  239. If `fork` is enabled, `reproc_start` forks a child process and returns 0 in
  240. the child process and > 0 in the parent process. In the child process, only
  241. `reproc_destroy` may be called on the `reproc_t` instance to free its
  242. associated memory.
  243. When `fork` is enabled. `argv` must be `NULL` when calling `reproc_start`.
  244. */
  245. bool fork;
  246. /*!
  247. Put pipes created by reproc in nonblocking mode. This makes `reproc_read` and
  248. `reproc_write` nonblocking operations. If needed, use `reproc_poll` to wait
  249. until streams becomes readable/writable.
  250. */
  251. bool nonblocking;
  252. } reproc_options;
  253. enum {
  254. /*! Data can be written to stdin. */
  255. REPROC_EVENT_IN = 1 << 0,
  256. /*! Data can be read from stdout. */
  257. REPROC_EVENT_OUT = 1 << 1,
  258. /*! Data can be read from stderr. */
  259. REPROC_EVENT_ERR = 1 << 2,
  260. /*! The process finished running. */
  261. REPROC_EVENT_EXIT = 1 << 3,
  262. /*! The deadline of the process expired. This event is added by default to the
  263. list of interested events. */
  264. REPROC_EVENT_DEADLINE = 1 << 4,
  265. };
  266. typedef struct reproc_event_source {
  267. /*! Process to poll for events. */
  268. reproc_t *process;
  269. /*! Events of the process that we're interested in. Takes a combo of
  270. `REPROC_EVENT` flags. */
  271. int interests;
  272. /*! Combo of `REPROC_EVENT` flags that indicate the events that occurred. This
  273. field is filled in by `reproc_poll`. */
  274. int events;
  275. } reproc_event_source;
  276. /*! Allocate a new `reproc_t` instance on the heap. */
  277. REPROC_EXPORT reproc_t *reproc_new(void);
  278. /*!
  279. Starts the process specified by `argv` in the given working directory and
  280. redirects its input, output and error streams.
  281. If this function does not return an error the child process will have started
  282. running and can be inspected using the operating system's tools for process
  283. inspection (e.g. ps on Linux).
  284. Every successful call to this function should be followed by a successful call
  285. to `reproc_wait` or `reproc_stop` and a call to `reproc_destroy`. If an error
  286. occurs during `reproc_start` all allocated resources are cleaned up before
  287. `reproc_start` returns and no further action is required.
  288. `argv` is an array of UTF-8 encoded, NUL-terminated strings that specifies the
  289. program to execute along with its arguments. It has the following layout:
  290. - The first element indicates the executable to run as a child process. This can
  291. be an absolute path, a path relative to the working directory of the parent
  292. process or the name of an executable located in the PATH. It cannot be `NULL`.
  293. - The following elements indicate the whitespace delimited arguments passed to
  294. the executable. None of these elements can be `NULL`.
  295. - The final element must be `NULL`.
  296. Example: ["cmake", "-G", "Ninja", "-DCMAKE_BUILD_TYPE=Release", `NULL`]
  297. */
  298. REPROC_EXPORT int reproc_start(reproc_t *process,
  299. const char *const *argv,
  300. reproc_options options);
  301. /*!
  302. Returns the process ID of the child or `REPROC_EINVAL` on error.
  303. Note that if `reproc_wait` has been called successfully on this process already,
  304. the returned pid will be that of the just ended child process. The operating
  305. system will have cleaned up the resources allocated to the process
  306. and the operating system is free to reuse the same pid for another process.
  307. Generally, only pass the result of this function to system calls that need a
  308. valid pid if `reproc_wait` hasn't been called successfully on the process yet.
  309. */
  310. REPROC_EXPORT int reproc_pid(reproc_t *process);
  311. /*!
  312. Polls each process in `sources` for its corresponding events in `interests` and
  313. stores events that occurred for each process in `events`. If an event source
  314. process member is `NULL`, the event source is ignored.
  315. Pass `REPROC_INFINITE` to `timeout` to have `reproc_poll` wait forever for an
  316. event to occur.
  317. If one or more events occur, returns the number of processes with events. If the
  318. timeout expires, returns zero. Returns `REPROC_EPIPE` if none of the sources
  319. have valid pipes remaining that can be polled.
  320. Actionable errors:
  321. - `REPROC_EPIPE`
  322. */
  323. REPROC_EXPORT int
  324. reproc_poll(reproc_event_source *sources, size_t num_sources, int timeout);
  325. /*!
  326. Reads up to `size` bytes into `buffer` from the child process output stream
  327. indicated by `stream`.
  328. Actionable errors:
  329. - `REPROC_EPIPE`
  330. - `REPROC_EWOULDBLOCK`
  331. */
  332. REPROC_EXPORT int reproc_read(reproc_t *process,
  333. REPROC_STREAM stream,
  334. uint8_t *buffer,
  335. size_t size);
  336. /*!
  337. Writes up to `size` bytes from `buffer` to the standard input (stdin) of the
  338. child process.
  339. (POSIX) By default, writing to a closed stdin pipe terminates the parent process
  340. with the `SIGPIPE` signal. `reproc_write` will only return `REPROC_EPIPE` if
  341. this signal is ignored by the parent process.
  342. Returns the amount of bytes written. If `buffer` is `NULL` and `size` is zero,
  343. this function returns 0.
  344. If the standard input of the child process wasn't opened with
  345. `REPROC_REDIRECT_PIPE`, this function returns `REPROC_EPIPE` unless `buffer` is
  346. `NULL` and `size` is zero.
  347. Actionable errors:
  348. - `REPROC_EPIPE`
  349. - `REPROC_EWOULDBLOCK`
  350. */
  351. REPROC_EXPORT int
  352. reproc_write(reproc_t *process, const uint8_t *buffer, size_t size);
  353. /*!
  354. Closes the child process standard stream indicated by `stream`.
  355. This function is necessary when a child process reads from stdin until it is
  356. closed. After writing all the input to the child process using `reproc_write`,
  357. the standard input stream can be closed using this function.
  358. */
  359. REPROC_EXPORT int reproc_close(reproc_t *process, REPROC_STREAM stream);
  360. /*!
  361. Waits `timeout` milliseconds for the child process to exit. If the child process
  362. has already exited or exits within the given timeout, its exit status is
  363. returned.
  364. If `timeout` is 0, the function will only check if the child process is still
  365. running without waiting. If `timeout` is `REPROC_INFINITE`, this function will
  366. wait indefinitely for the child process to exit. If `timeout` is
  367. `REPROC_DEADLINE`, this function waits until the deadline passed to
  368. `reproc_start` expires.
  369. Actionable errors:
  370. - `REPROC_ETIMEDOUT`
  371. */
  372. REPROC_EXPORT int reproc_wait(reproc_t *process, int timeout);
  373. /*!
  374. Sends the `SIGTERM` signal (POSIX) or the `CTRL-BREAK` signal (Windows) to the
  375. child process. Remember that successful calls to `reproc_wait` and
  376. `reproc_destroy` are required to make sure the child process is completely
  377. cleaned up.
  378. */
  379. REPROC_EXPORT int reproc_terminate(reproc_t *process);
  380. /*!
  381. Sends the `SIGKILL` signal to the child process (POSIX) or calls
  382. `TerminateProcess` (Windows) on the child process. Remember that successful
  383. calls to `reproc_wait` and `reproc_destroy` are required to make sure the child
  384. process is completely cleaned up.
  385. */
  386. REPROC_EXPORT int reproc_kill(reproc_t *process);
  387. /*!
  388. Simplifies calling combinations of `reproc_wait`, `reproc_terminate` and
  389. `reproc_kill`. The function executes each specified step and waits (using
  390. `reproc_wait`) until the corresponding timeout expires before continuing with
  391. the next step.
  392. Example:
  393. Wait 10 seconds for the child process to exit on its own before sending
  394. `SIGTERM` (POSIX) or `CTRL-BREAK` (Windows) and waiting five more seconds for
  395. the child process to exit.
  396. ```c
  397. REPROC_ERROR error = reproc_stop(process,
  398. REPROC_STOP_WAIT, 10000,
  399. REPROC_STOP_TERMINATE, 5000,
  400. REPROC_STOP_NOOP, 0);
  401. ```
  402. Call `reproc_wait`, `reproc_terminate` and `reproc_kill` directly if you need
  403. extra logic such as logging between calls.
  404. `stop` can contain up to three stop actions that instruct this function how the
  405. child process should be stopped. The first element of each stop action specifies
  406. which action should be called on the child process. The second element of each
  407. stop actions specifies how long to wait after executing the operation indicated
  408. by the first element.
  409. When `stop` is 3x `REPROC_STOP_NOOP`, `reproc_destroy` will wait until the
  410. deadline expires (or forever if there is no deadline). If the process is still
  411. running after the deadline expires, `reproc_stop` then calls `reproc_terminate`
  412. and waits forever for the process to exit.
  413. Note that when a stop action specifies `REPROC_STOP_WAIT`, the function will
  414. just wait for the specified timeout instead of performing an action to stop the
  415. child process.
  416. If the child process has already exited or exits during the execution of this
  417. function, its exit status is returned.
  418. Actionable errors:
  419. - `REPROC_ETIMEDOUT`
  420. */
  421. REPROC_EXPORT int reproc_stop(reproc_t *process, reproc_stop_actions stop);
  422. /*!
  423. Release all resources associated with `process` including the memory allocated
  424. by `reproc_new`. Calling this function before a succesfull call to `reproc_wait`
  425. can result in resource leaks.
  426. Does nothing if `process` is an invalid `reproc_t` instance and always returns
  427. an invalid `reproc_t` instance (`NULL`). By assigning the result of
  428. `reproc_destroy` to the instance being destroyed, it can be safely called
  429. multiple times on the same instance.
  430. Example: `process = reproc_destroy(process)`.
  431. */
  432. REPROC_EXPORT reproc_t *reproc_destroy(reproc_t *process);
  433. /*!
  434. Returns a string describing `error`. This string must not be modified by the
  435. caller.
  436. */
  437. REPROC_EXPORT const char *reproc_strerror(int error);
  438. #ifdef __cplusplus
  439. }
  440. #endif