Lolly 1.4.27
Loading...
Searching...
No Matches
unix_sys_utils.cpp
Go to the documentation of this file.
1
2/******************************************************************************
3 * MODULE : unix_sys_utils.cpp
4 * DESCRIPTION: external command handling
5 * COPYRIGHT : (C) 2009 David MICHEL, 2015 Gregoire LECERF
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11
12#include "unix_sys_utils.hpp"
13#include "analyze.hpp"
14#include "tm_timer.hpp"
15#include <fcntl.h>
16#include <pthread.h>
17#include <pwd.h>
18#include <spawn.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/wait.h>
22#include <unistd.h>
23
24SN
26 return getpid ();
27}
28
29/******************************************************************************
30 * Evaluation via specified file descriptors
31 ******************************************************************************/
32extern char** environ;
33
34// exception safe mutex
35struct _mutex {
36 pthread_mutex_t rep;
37 inline _mutex () { pthread_mutex_init (&rep, NULL); }
39};
40
42 pthread_mutex_t* rep;
45};
46
47// thread safe malloc and free
49
50void*
51_ts_malloc (int n) {
53 return malloc (n);
54}
55
56void
57_ts_free (void* a) {
59 free (a);
60}
61
62// thread safe strings
63struct _ts_string {
64 int n, l;
65 char* a;
66
67 inline _ts_string () : n (0), l (0), a (NULL) {}
68 inline ~_ts_string () {
69 if (l != 0) _ts_free ((void*) a);
70 }
71
72 void resize (int m) {
73 if (m <= n) return;
74 int new_l= max (2 * n, m);
75 char* new_a= (char*) _ts_malloc (new_l * sizeof (char));
76 memcpy (new_a, a, n);
77 _ts_free ((void*) a);
78 a= new_a;
79 l= new_l;
80 }
81
82 void append (char* b, int m) {
83 resize (m + n);
84 memcpy (a + n, b, m);
85 n+= m;
86 }
87
88 void copy (char* b, int m) {
89 resize (m);
90 memcpy (a, b, m);
91 n= m;
92 }
93};
94
95// pipe
96struct _pipe_t {
97 int rep[2];
98 int st;
99 inline _pipe_t () {
100 st = pipe (rep);
101 int fl= fcntl (rep[0], F_GETFL);
102 fl = fl & (~(int) O_NONBLOCK);
103 fcntl (rep[0], F_SETFL, fl);
104 fl= fcntl (rep[1], F_GETFL);
105 fl= fl & (~(int) O_NONBLOCK);
106 fcntl (rep[1], F_SETFL, fl);
107 }
108 inline ~_pipe_t () {
109 close (rep[0]);
110 close (rep[1]);
111 }
112 inline int in () const { return rep[0]; }
113 inline int out () const { return rep[1]; }
114 inline int status () const { return st; }
115};
116
117// asynchronous channel between spawn process
118struct _channel {
119 int fd;
124 _channel () : status (0) {}
125 void _init_in (int fd2, string data2, int chunk_size) {
126 fd= fd2;
127 data.copy (&data2[0], N (data2));
129 }
130 void _init_out (int fd2, int buffer_size2) {
131 fd = fd2;
134 }
135};
136
137// data read from spawn process
138static void*
141 int fd= c->fd;
142 int n = c->buffer_size;
143 char* b = A (c->buffer);
144 int m;
145 do {
146 m= read (fd, b, n);
147 // cout << "read " << m << " bytes from " << fd << "\n";
148 if (m > 0) c->data.append (b, m);
149 if (m == 0) {
150 if (close (fd) != 0) c->status= -1;
151 }
152 } while (m > 0);
153 return (void*) NULL;
154}
155
156// data written to spawn process
157static void*
160 int fd= c->fd;
161 const char* d = c->data.a;
162 int n = c->buffer_size;
163 int t= (c->data).n, k= 0, o= 0;
164 if (t == 0) return (void*) NULL;
165 if (n == 0) {
166 c->status= -1;
167 return (void*) NULL;
168 }
169 do {
170 int m= min (n, t - k);
171 // cout << "writting " << m << " bytes / " << t-k << "\n";
172 o= write (fd, (void*) (d + k), m);
173 // cout << "written " << o << " bytes to " << fd << "\n";
174 if (o > 0) k+= o;
175 if (o < 0) {
176 close (fd);
177 c->status= -1;
178 }
179 if (k == t) {
180 if (close (fd) != 0) c->status= -1;
181 }
182 } while (o > 0 && k < t);
183 return (void*) NULL;
184}
185
186// exception safe file actions
188 posix_spawn_file_actions_t rep;
189 int st;
192 inline int status () const { return st; }
193};
194
195// Texmacs warning for long spawn commands
196static void
197_unix_system_warn (pid_t pid, string which, string msg) {
198 (void) which;
199}
200
201int
204 // Run command arg[0] with arguments arg[i], i >= 1.
205 // str_in[i] is sent to the file descriptor fd_in[i].
206 // str_out[i] is filled from the file descriptor fd_out[i].
207 // If str_in[i] is -1 then $$i automatically replaced by a valid
208 // file descriptor in arg.
209 if (N (arg) == 0) return 0;
210 string which= recompose (arg, " ");
211 int n_in= N (fd_in), n_out= N (fd_out);
212 ASSERT (N (str_in) == n_in, "size mismatch");
213 ASSERT (N (str_out) == n_out, "size mismatch");
216 for (int i= 0; i < n_in; i++) {
218 pp_in[i].out ()) != 0)
219 return -1;
220 if (fd_in[i] >= 0) {
222 fd_in[i]) != 0)
223 return -1;
225 pp_in[i].in ()) != 0)
226 return -1;
227 }
228 }
229 for (int i= 0; i < n_out; i++) {
231 pp_out[i].in ()) != 0)
232 return -1;
234 fd_out[i]) != 0)
235 return -1;
237 pp_out[i].out ()) != 0)
238 return -1;
239 }
241 for (int j= 0; j < N (arg); j++)
242 for (int i= 0; i < n_in; i++)
243 if (fd_in[i] < 0)
244 arg_[j]=
245 replace (arg_[j], "$$" * as_string (i), as_string (pp_in[i].in ()));
247 for (int j= 0; j < N (arg_); j++)
248 _arg << as_charp (arg_[j]);
249 _arg << (char*) NULL;
250 pid_t pid;
251 int status=
252 posix_spawnp (&pid, _arg[0], &file_actions.rep, NULL, A (_arg), environ);
253 for (int j= 0; j < N (arg_); j++)
255 if (status != 0) {
256 return -1;
257 }
258 // close useless ports
259 for (int i= 0; i < n_in; i++)
260 close (pp_in[i].in ());
261 for (int i= 0; i < n_out; i++)
262 close (pp_out[i].out ());
263
264 // write to spawn process
267 for (int i= 0; i < n_in; i++) {
268 channels_in[i]._init_in (pp_in[i].out (), str_in[i], 1 << 12);
269 if (pthread_create (&threads_write[i], NULL /* &attr */,
270 _background_write_task, (void*) &(channels_in[i])))
271 return -1;
272 }
273
274 // read from spawn process
277 for (int i= 0; i < n_out; i++) {
278 channels_out[i]._init_out (pp_out[i].in (), 1 << 12);
279 if (pthread_create (&threads_read[i], NULL /* &attr */,
280 _background_read_task, (void*) &(channels_out[i])))
281 return -1;
282 }
283
284 int wret;
286 while ((wret= waitpid (pid, &status, WNOHANG)) == 0) {
287 usleep (100);
288 if (texmacs_time () - last_wait_time > 5000) {
290 _unix_system_warn (pid, which, "waiting spawn process");
291 }
292 }
293
294 // wait for terminating threads
295 void* exit_status;
296 int thread_status= 0;
297 for (int i= 0; i < n_in; i++) {
299 if (channels_in[i].status < 0) thread_status= -1;
300 }
301 for (int i= 0; i < n_out; i++) {
303 *(str_out[i])= string (channels_out[i].data.a, channels_out[i].data.n);
304 if (channels_out[i].status < 0) thread_status= -1;
305 }
306
307 if (thread_status < 0) return thread_status;
308 if (wret < 0 || WIFEXITED (status) == 0) return -1;
309 return WEXITSTATUS (status);
310}
311
312string
314 uid_t uid= getuid ();
315 struct passwd* pwd= getpwuid (uid);
316 return string (pwd->pw_name);
317}
318
319string
321 uid_t uid= getuid ();
322 struct passwd* pwd= getpwuid (uid);
323 return tokenize (string (pwd->pw_gecos), string (","))[0];
324}
bool read(string s, int &i, const char *test)
Definition analyze.cpp:589
array< string > tokenize(string s, string sep)
Definition analyze.cpp:948
string recompose(array< string > a, string sep)
Definition analyze.cpp:963
string replace(string s, string what, string by)
Definition analyze.cpp:899
T * A(array< T > a)
Get a pointer to the first element of the array.
Definition array.hpp:174
int N(array< T > a)
Get the length of the array.
Definition array.hpp:170
#define ASSERT(cond, msg)
Macro used to assert that a condition is true, and throw an exception with an error message if the co...
Definition basic.hpp:85
blackbox b[13]
blackbox t[13]
The list class represents a linked list.
Definition list.hpp:48
list(T item)
Construct a new list object with a single item.
Definition list.hpp:137
void tm_delete_array(C *Ptr)
SI min(SI i, SI j)
Returns the minimum of two signed integers.
Definition minmax.hpp:27
SI max(SI i, SI j)
Returns the maximum of two signed integers.
Definition minmax.hpp:40
unsigned int SN
Definition minmax.hpp:11
char * as_charp(string s)
Definition string.cpp:294
string as_string(int16_t i)
Definition string.cpp:310
void _init_in(int fd2, string data2, int chunk_size)
array< char > buffer
void _init_out(int fd2, int buffer_size2)
_ts_string data
posix_spawn_file_actions_t rep
_mutex_lock(_mutex &m)
pthread_mutex_t * rep
pthread_mutex_t rep
int in() const
int out() const
int status() const
void append(char *b, int m)
void copy(char *b, int m)
void resize(int m)
base class of resources
Definition resource.hpp:23
time_t texmacs_time()
Definition tm_timer.cpp:47
static void * _background_write_task(void *channel_as_void_ptr)
static void * _background_read_task(void *channel_as_void_ptr)
SN unix_get_process_id()
int unix_system(array< string > arg, array< int > fd_in, array< string > str_in, array< int > fd_out, array< string * > str_out)
string unix_get_login()
void _ts_free(void *a)
static _mutex _ts_memory_lock
char ** environ
void * _ts_malloc(int n)
string unix_get_username()
static void _unix_system_warn(pid_t pid, string which, string msg)