1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 24 июл. 2019 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef CORE_IPC_PROCESS_H_
23 #define CORE_IPC_PROCESS_H_
24 
25 #include <common/types.h>
26 #include <unistd.h>
27 #include <data/cvector.h>
28 #include <core/LSPString.h>
29 #include <core/io/IInStream.h>
30 #include <core/io/IOutStream.h>
31 
32 namespace lsp
33 {
34     namespace ipc
35     {
36         /**
37          * Class for running processes
38          */
39         class Process
40         {
41             public:
42                 enum pstatus_t {
43                     PSTATUS_CREATED,
44                     PSTATUS_RUNNING,
45                     PSTATUS_EXITED,
46                     PSTATUS_ERROR
47                 };
48 
49             private:
50                 Process & operator = (const Process &);
51 
52                 typedef struct envvar_t {
53                     LSPString   name;
54                     LSPString   value;
55                 } envvar_t;
56 
57             private:
58                 LSPString               sCommand;
59                 cvector<LSPString>      vArgs;
60                 cvector<envvar_t>       vEnv;
61                 pstatus_t               nStatus;
62                 int                     nExitCode;
63 
64 #ifdef PLATFORM_WINDOWS
65                 HANDLE                  hProcess;
66                 WORD                    nPID;
67                 HANDLE                  hStdIn;
68                 HANDLE                  hStdOut;
69                 HANDLE                  hStdErr;
70 #else
71                 pid_t                   nPID;
72                 int                     hStdIn;
73                 int                     hStdOut;
74                 int                     hStdErr;
75 #endif /* PLATFORM_WINDOWS */
76 
77                 io::IOutStream         *pStdIn;
78                 io::IInStream          *pStdOut;
79                 io::IInStream          *pStdErr;
80 
81             protected:
82                 static void     destroy_args(cvector<LSPString> *args);
83                 static void     destroy_env(cvector<envvar_t> *env);
84                 void            close_handles();
85 
86 #ifdef PLATFORM_WINDOWS
87                 static status_t append_arg_escaped(LSPString *dst, const LSPString *value);
88                 status_t        build_argv(LSPString *dst);
89                 status_t        build_envp(LSPString *dst);
90 #else
91                 status_t        build_argv(cvector<char> *dst);
92                 status_t        build_envp(cvector<char> *dst);
93                 status_t        spawn_process(const char *cmd, char * const *argv, char * const *envp);
94                 status_t        vfork_process(const char *cmd, char * const *argv, char * const *envp);
95                 status_t        fork_process(const char *cmd, char * const *argv, char * const *envp);
96                 void            execve_process(const char *cmd, char * const *argv, char * const *envp, bool soft_exit);
97 #endif /* PLATFORM_WINDOWS */
98 
99             public:
100                 explicit Process();
101                 ~Process();
102 
103             public:
104                 /**
105                  * Set command for execution
106                  * @param cmd command to execute
107                  * @return status of operation
108                  */
109                 status_t    set_command(const LSPString *cmd);
110 
111                 /**
112                  * Set command for execution
113                  * @param cmd command to execute in UTF-8 encoding
114                  * @return status of operation
115                  */
116                 status_t    set_command(const char *cmd);
117 
118             public:
119                 /**
120                  * Get overall number of additional command-line arguments
121                  * @return number of additional command-line arguments
122                  */
123                 size_t      args() const;
124 
125                 /**
126                  * Add argument at the end of command line
127                  * @param value argument value
128                  * @return status of operation
129                  */
130                 status_t    add_arg(const LSPString *value);
131 
132                 /**
133                  * Add argument at the end of command line
134                  * @param value argument value in UTF-8 encoding
135                  * @return status of operation
136                  */
137                 status_t    add_arg(const char *value);
138 
139                 /**
140                  * Set value of argument at the specified place
141                  * @param value argument value
142                  * @return status of operation
143                  */
144                 status_t    set_arg(size_t index, const LSPString *value);
145 
146                 /**
147                  * Set value of argument at the specified place
148                  * @param value argument value in UTF-8 encoding
149                  * @return status of operation
150                  */
151                 status_t    set_arg(size_t index, const char *value);
152 
153                 /**
154                  * Get value of argument at the specified place
155                  * @param value pointer to store argument value
156                  * @return status of operation
157                  */
158                 status_t    get_arg(size_t index, LSPString *value);
159 
160                 /**
161                  * Get value of argument at the specified place
162                  * @param value pointer to store argument value
163                  * @return status of operation
164                  */
165                 status_t    get_arg(size_t index, char **value);
166 
167                 /**
168                  * Remove the argument at the specified place
169                  * @param value pointer to store value of removed argument
170                  * @return status of operation
171                  */
172                 status_t    remove_arg(size_t index, LSPString *value = NULL);
173 
174                 /**
175                  * Remove the argument at the specified place
176                  * @param value pointer to store value of removed argument.
177                  *        The pointer should be free()'d after use
178                  * @return status of operation
179                  */
180                 status_t    remove_arg(size_t index, char **value = NULL);
181 
182                 /**
183                  * Insert argument at the specified position
184                  * @param value argument value
185                  * @return status of operation
186                  */
187                 status_t    insert_arg(size_t index, const LSPString *value);
188 
189                 /**
190                  * Insert argument at the specified position
191                  * @param value argument value in UTF-8 encoding
192                  * @return status of operation
193                  */
194                 status_t    insert_arg(size_t index, const char *value);
195 
196                 /**
197                  * Clear arguments;
198                  * @return status of operation
199                  */
200                 status_t    clear_args();
201 
202             public:
203                 /**
204                  * Return number of environment variables
205                  * @return number of environment variables
206                  */
207                 size_t      envs() const;
208 
209                 /**
210                  * Set value of the specific environment variable
211                  * @param key the name of environment variable
212                  * @param value the value of environment variable
213                  * @return status of operation
214                  */
215                 status_t    set_env(const LSPString *key, const LSPString *value);
216 
217                 /**
218                  * Set value of the specific environment variable
219                  * @param key the name of environment variable in UTF-8 encoding
220                  * @param value the value of environment variable in UTF-8 encoding
221                  * @return status of operation
222                  */
223                 status_t    set_env(const char *key, const char *value);
224 
225                 /**
226                  * Remove the specific environment variable
227                  * @param key the name of environment variable
228                  * @param pointer to store value of the removed environment variable
229                  * @return status of operation
230                  */
231                 status_t    remove_env(const LSPString *key, LSPString *value = NULL);
232 
233                 /**
234                  * Remove the specific environment variable
235                  * @param key the name of environment variable
236                  * @param pointer to store value of the removed environment variable
237                  * @return status of operation
238                  */
239                 status_t    remove_env(const char *key, LSPString *value = NULL);
240 
241                 /**
242                  * Remove the specific environment variable
243                  * @param key the name of environment variable in UTF-8 encoding
244                  * @param pointer to store value of the removed environment variable in UTF-8 encoding.
245                  *        The obtained pointer should be free()'d after use
246                  * @return status of operation
247                  */
248                 status_t    remove_env(const char *key, char **value = NULL);
249 
250                 /**
251                  * Obtain the value of the specific environment variable
252                  * @param key the name of environment variable
253                  * @param pointer to store value of the environment variable
254                  * @return status of operation
255                  */
256                 status_t    get_env(const LSPString *key, LSPString *value = NULL);
257 
258                 /**
259                  * Obtain the value of the specific environment variable
260                  * @param key the name of environment variable
261                  * @param pointer to store value of the environment variable
262                  * @return status of operation
263                  */
264                 status_t    get_env(const char *key, LSPString *value = NULL);
265 
266                 /**
267                  * Obtain the value of the specific environment variable
268                  * @param key the name of environment variable in UTF-8 encoding
269                  * @param pointer to store value of the environment variable in UTF-8 encoding.
270                  *        The obtained pointer should be free()'d after use
271                  * @return status of operation
272                  */
273                 status_t    get_env(const char *key, char **value = NULL);
274 
275                 /**
276                  * Obtain the key and value of environment variable by index
277                  * @param idx the environment variable index
278                  * @param key environment variable key
279                  * @param value environment variable value
280                  * @return status of operation
281                  */
282                 status_t    read_env(size_t idx, LSPString *key = NULL, LSPString *value = NULL);
283 
284                 /**
285                  * Obtain the value of the specific environment variable
286                  * @param idx the environment variable index
287                  * @param key the name of environment variable in UTF-8 encoding
288                  *        The obtained pointer should be free()'d after use
289                  * @param pointer to store value of the environment variable in UTF-8 encoding.
290                  *        The obtained pointer should be free()'d after use
291                  * @return status of operation
292                  */
293                 status_t    read_env(size_t idx, char **key = NULL, char **value = NULL);
294 
295                 /**
296                  * Clear all environment variables
297                  * @return status of operation
298                  */
299                 status_t    clear_env();
300 
301             public:
302                 /**
303                  * Return redirected standard input stream of the process.
304                  * The redirection is allowed before successful launch() has been issued.
305                  *
306                  * @return pointer to standard input stream
307                  */
308                 io::IOutStream *get_stdin();
309 
310                 /**
311                  * Return redirected standard output stream of the process.
312                  * The redirection is allowed before successful launch() has been issued.
313                  *
314                  * @return pointer to standard output stream
315                  */
316                 io::IInStream *get_stdout();
317 
318                 /**
319                  * Return redirected standard error stream of the process.
320                  * The redirection is allowed before successful launch() has been issued.
321                  *
322                  * @return pointer to standard error stream
323                  */
324                 io::IInStream *get_stderr();
325 
326                 /**
327                  * Get process status
328                  * @return process status
329                  */
330                 size_t      status();
331 
332                 /**
333                  * Copy environment variables of the current process
334                  * @return status of operation
335                  */
336                 status_t    copy_env();
337 
338                 /**
339                  * Launch the process
340                  * @return status of operation
341                  */
342                 status_t    launch();
343 
344                 /**
345                  * Chech that the object is not in error state
346                  * @return true if object is in not error state
347                  */
348                 bool        valid();
349 
350                 /**
351                  * Check that process is in running state
352                  * @return true if process is in running state
353                  */
354                 bool        running();
355 
356                 /**
357                  * Check that process has exited
358                  * @return true if process has exited
359                  */
360                 bool        exited();
361 
362                 /**
363                  * Get unique process identifier
364                  * @return process identifier
365                  */
366                 ssize_t     process_id() const;
367 
368                 /**
369                  * Wait for the process termination
370                  * @param millis number of milliseconds to wait, negative value means infinite wait
371                  * @return status of operation
372                  */
373                 status_t    wait(wssize_t millis = -1);
374 
375                 /**
376                  * Get process exit status
377                  * @param code pointer to save exit status
378                  * @return status of operation
379                  */
380                 status_t    exit_code(int *code);
381         };
382 
383     } /* namespace ipc */
384 } /* namespace lsp */
385 
386 #endif /* CORE_IPC_PROCESS_H_ */
387