Mstdlib-1.24.0
m_popen.h
1/* The MIT License (MIT)
2 *
3 * Copyright (c) 2015 Monetra Technologies, LLC.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#ifndef __M_POPEN_H__
25#define __M_POPEN_H__
26
27/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28
29#include <mstdlib/base/m_defs.h>
30#include <mstdlib/base/m_types.h>
31#include <mstdlib/thread/m_thread.h>
32
33/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
34
35__BEGIN_DECLS
36
37/*! \addtogroup m_popen Process Open (popen)
38 * \ingroup m_thread
39 *
40 * Open and interact with a process.
41 *
42 * \note On Unix SIGCHLD _cannot_ be set to SIG_IGN.
43 * ECHILD could be generated and M_popen_check
44 * may return M_POPEN_ERR_WAIT when the process
45 * exits. See M_backtrace_set_ignore_signal for
46 * explantion.
47 *
48 * Example:
49 *
50 * \code{.c}
51 * const char *data = "<x><t>data</t></x>"
52 * M_popen_err_t mperr;
53 * M_popen_handle_t mp;
54 * M_popen_status_t status;
55 * int retval;
56 * char *stdout_buf = NULL;
57 * size_t stdout_buf_len = 0;
58 * char *stderr_buf = NULL;
59 * size_t stderr_buf_len = 0;
60 *
61 * mp = M_popen("curl <url>", &mperr);
62 * if (mp == NULL) {
63 * printf("m_popen failed: %s\n", M_popen_strerror(mperr));
64 * return M_FALSE;
65 * }
66 *
67 * M_printf("Process spawned....\n");
68 *
69 * retval = M_popen_write(mp, M_POPEN_FD_WRITE, data, M_str_len(data));
70 * if (retval <= 0) {
71 * M_printf("M_popen_write failed, retval = %d\n", retval);
72 * M_popen_close(mp, &mperr);
73 * return M_FALSE;
74 * }
75 *
76 * / * Close file descriptor to let process know we're done * /
77 * if (!M_popen_closefd(mp, M_POPEN_FD_WRITE)) {
78 * M_printf("M_popen_closefd() failed\n");
79 * M_popen_close(mp, &mperr);
80 * return M_FALSE;
81 * }
82 *
83 * M_printf("Wrote process stream....\n");
84 *
85 * while ((status=M_popen_check(mp)) == M_POPEN_STATUS_RUNNING) {
86 * M_thread_sleep(50000);
87 * }
88 *
89 * if (status == M_POPEN_STATUS_ERROR) {
90 * retval = M_popen_close(mp, &mperr);
91 * printf("Error during M_popen_check(): %d: %s\n", retval, M_popen_strerror(mperr));
92 * return M_FALSE;
93 * }
94 *
95 * M_printf("Process done...\n");
96 *
97 * retval = M_popen_close_ex(mp, &stdout_buf, &stdout_buf_len, &stderr_buf, &stderr_buf_len, &mperr, 0);
98 * if (retval < 0) {
99 * M_printf("error: %s\n", M_popen_strerror(mperr));
100 * return M_FALSE;
101 * }
102 *
103 * M_printf("stdout: %d:\n%s\n", (int)stdout_buf_len, stdout_buf);
104 * M_printf("stderr: %d:\n%s\n", (int)stderr_buf_len, stderr_buf);
105 * M_free(stdout_buf);
106 * M_free(stderr_buf);
107 * M_printf("return code: %d\n", retval);
108 * \endcode
109 *
110 * @{
111 */
112
113/*! Handle to M_popen object */
114struct M_popen_handle;
115typedef struct M_popen_handle M_popen_handle_t;
116
117
118/*! Types of file descriptors that can be retrieved and used */
119typedef enum {
124
125/*! Possible error reason codes */
126typedef enum {
128 M_POPEN_ERR_INVALIDUSE, /*!< invalid API usage */
129 M_POPEN_ERR_CMDNOTFOUND, /*!< command not found */
130 M_POPEN_ERR_PERM, /*!< permission denied */
131 M_POPEN_ERR_NOEXEC, /*!< file not executable */
132 M_POPEN_ERR_KILLSIGNAL, /*!< killed by signal */
133 M_POPEN_ERR_PIPE, /*!< pipe creation failed */
134 M_POPEN_ERR_WAIT, /*!< attempting to check process status failed */
135 M_POPEN_ERR_SPAWN /*!< fork failed */
137
138/*! Status codes for command being executed */
139typedef enum {
144
145
146/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
147
148/*! Start the specified command and open stdin (write), stdout (read), and
149 * stderr (read) file descriptors for communication.
150 *
151 * Must call M_popen_close() to clean up the returned handle.
152 *
153 * \param[in] cmd Command to execute.
154 * \param[out] errorid Pointer to store error id if an error occurs.
155 *
156 * \return NULL on failure, M_popen_handle_t on success.
157 */
158M_API M_popen_handle_t *M_popen(const char *cmd, M_popen_err_t *errorid);
159
160
161/*! Read from a file descriptor
162 *
163 * \param[in] mp Open M_popen_t object.
164 * \param[in] fd Which FD to read from.
165 * \param[out] out Buffer to hold read data.
166 * \param[in] out_len Length of out buffer.
167 * \param[in] timeout_ms Time in ms to wait for data.
168 * M_TIMEOUT_INF will cause this to block.
169 * Note: Windows only has 15 ms resolution.
170 *
171 * \return -1 on error, -2 if fd was closed, 0 if a timeout occurred and no
172 * bytes were read, otherwise number of bytes read.
173 */
174M_API ssize_t M_popen_read(M_popen_handle_t *mp, M_popen_fd_t fd, char *out, size_t out_len, M_uint64 timeout_ms);
175
176
177/*! Write to a file descriptor
178 *
179 * \param[in,out] mp Open M_popen_t object.
180 * \param[in] fd Which FD to write to.
181 * \param[in] in Buffer to holding data to be written.
182 * \param[in] in_len Length of data to be written.
183 *
184 * \return -1 on error, otherwise number of bytes written.
185 */
186M_API ssize_t M_popen_write(M_popen_handle_t *mp, M_popen_fd_t fd, const char *in, size_t in_len);
187
188
189/*! Close the provided file descriptor.
190 *
191 * This is used mainly to close the stdin stream to signal to the command being
192 * executed that there is no more data left to be read. Any open file
193 * descriptors are automatically closed by M_popen_close().
194 *
195 * \param[in,out] mp Open M_popen_t object.
196 * \param[in] fd Which FD to close.
197 *
198 * \return 1 on success, 0 on error.
199 */
201
202
203/*! Checks the current state of the command being executed and returns a code
204 * identifying the state.
205 *
206 * Even if the state returns DONE or ERROR, M_popen_close() must be called.
207 *
208 * \param[in] mp Open M_popen_t object.
209 *
210 * \return M_popen_status_t code.
211 */
213
214
215/*! Close the M_popen_t object.
216 *
217 * This will perform a blocking wait for the process to exit before returning
218 * control to the caller.
219 *
220 * \param[in] mp M_popen_t object
221 * \param[out] stdout_buf Optional parameter. Will return allocated buffer containing
222 * the contents of the process's stdout. If specified, must
223 * also specify stdout_buf_len.
224 * \param[out] stdout_buf_len Optional parameter. Will return the length of stdout_buf.
225 * \param[out] stderr_buf Optional parameter. Will return allocated buffer containing
226 * the contents of the process's stderr. If specified, must
227 * also specify stderr_buf_len.
228 * \param[out] stderr_buf_len Optional parameter. Will return the length of stderr_buf.
229 * \param[out] errorid if an error has occurred, will populate with a
230 * reason code.
231 * \param[in] timeout Time in ms to wait for the processes to exit. If the process
232 * has not finished after the timeout expires it will be killed.
233 * M_TIMEOUT_INF will cause this to block until the process exits.
234 * Note: the time out only has 15 ms resolution.
235 *
236 * \return -1 on error, -2 on timeout, otherwise the exit code from the process.
237 */
238M_API int M_popen_close_ex(M_popen_handle_t *mp, char **stdout_buf, size_t *stdout_buf_len, char **stderr_buf, size_t *stderr_buf_len, M_popen_err_t *errorid, M_uint64 timeout);
239
240
241/*! Close the M_popen_t object.
242 *
243 * This is a simplified wrapper around M_popen_close_ex(). This command blocks forever until the
244 * child process is done. If you need to force-kill the process after a given timeout, use
245 * M_popen_close_ex() instead of this function.
246 *
247 * \param[in] mp M_popen_t object
248 * \param[out] errorid if an error has occurred, will populate with a reason code.
249 *
250 * \see M_popen_close_ex
251 *
252 * \return -1 on error, otherwise the exit code from the process.
253 */
255
256
257/*! Output human-readable error string.
258 *
259 * \param[in] err Error as returned by M_popen() or M_popen_close().
260 *
261 * \return string error message.
262 */
263M_API const char *M_popen_strerror(M_popen_err_t err);
264
265/*! @} */
266
267__END_DECLS
268
269#endif /* __M_POPEN_H__ */
M_popen_fd_t
Definition: m_popen.h:119
M_popen_status_t M_popen_check(M_popen_handle_t *mp)
const char * M_popen_strerror(M_popen_err_t err)
int M_popen_close(M_popen_handle_t *mp, M_popen_err_t *errorid)
M_popen_err_t
Definition: m_popen.h:126
int M_popen_closefd(M_popen_handle_t *mp, M_popen_fd_t fd)
M_popen_handle_t * M_popen(const char *cmd, M_popen_err_t *errorid)
ssize_t M_popen_write(M_popen_handle_t *mp, M_popen_fd_t fd, const char *in, size_t in_len)
struct M_popen_handle M_popen_handle_t
Definition: m_popen.h:115
int M_popen_close_ex(M_popen_handle_t *mp, char **stdout_buf, size_t *stdout_buf_len, char **stderr_buf, size_t *stderr_buf_len, M_popen_err_t *errorid, M_uint64 timeout)
ssize_t M_popen_read(M_popen_handle_t *mp, M_popen_fd_t fd, char *out, size_t out_len, M_uint64 timeout_ms)
M_popen_status_t
Definition: m_popen.h:139
@ M_POPEN_FD_WRITE
Definition: m_popen.h:121
@ M_POPEN_FD_ERR
Definition: m_popen.h:122
@ M_POPEN_FD_READ
Definition: m_popen.h:120
@ M_POPEN_ERR_NONE
Definition: m_popen.h:127
@ M_POPEN_ERR_PIPE
Definition: m_popen.h:133
@ M_POPEN_ERR_KILLSIGNAL
Definition: m_popen.h:132
@ M_POPEN_ERR_INVALIDUSE
Definition: m_popen.h:128
@ M_POPEN_ERR_SPAWN
Definition: m_popen.h:135
@ M_POPEN_ERR_WAIT
Definition: m_popen.h:134
@ M_POPEN_ERR_CMDNOTFOUND
Definition: m_popen.h:129
@ M_POPEN_ERR_NOEXEC
Definition: m_popen.h:131
@ M_POPEN_ERR_PERM
Definition: m_popen.h:130
@ M_POPEN_STATUS_DONE
Definition: m_popen.h:142
@ M_POPEN_STATUS_RUNNING
Definition: m_popen.h:140
@ M_POPEN_STATUS_ERROR
Definition: m_popen.h:141