1 |
/**
|
2 |
* Navit, a modular navigation system.
|
3 |
* Copyright (C) 2005-2008 Navit Team
|
4 |
*
|
5 |
* This program is free software; you can redistribute it and/or
|
6 |
* modify it under the terms of the GNU General Public License
|
7 |
* version 2 as published by the Free Software Foundation.
|
8 |
*
|
9 |
* This program is distributed in the hope that it will be useful,
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12 |
* GNU General Public License for more details.
|
13 |
*
|
14 |
* You should have received a copy of the GNU General Public License
|
15 |
* along with this program; if not, write to the
|
16 |
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
17 |
* Boston, MA 02110-1301, USA.
|
18 |
*/
|
19 |
|
20 |
#include <stdlib.h>
|
21 |
#include <glib.h>
|
22 |
#include <ctype.h>
|
23 |
#include <stdarg.h>
|
24 |
#include <time.h>
|
25 |
#include <limits.h>
|
26 |
#include <string.h>
|
27 |
|
28 |
#ifdef _POSIX_C_SOURCE
|
29 |
#include <unistd.h>
|
30 |
#include <sys/types.h>
|
31 |
#include <sys/wait.h>
|
32 |
#endif
|
33 |
#include "util.h"
|
34 |
#include "debug.h"
|
35 |
|
36 |
void
|
37 |
strtoupper(char *dest, const char *src)
|
38 |
{
|
39 |
while (*src)
|
40 |
*dest++=toupper(*src++);
|
41 |
*dest='\0';
|
42 |
}
|
43 |
|
44 |
void
|
45 |
strtolower(char *dest, const char *src)
|
46 |
{
|
47 |
while (*src)
|
48 |
*dest++=tolower(*src++);
|
49 |
*dest='\0';
|
50 |
}
|
51 |
|
52 |
|
53 |
static void
|
54 |
hash_callback(gpointer key, gpointer value, gpointer user_data)
|
55 |
{
|
56 |
GList **l=user_data;
|
57 |
*l=g_list_prepend(*l, value);
|
58 |
}
|
59 |
|
60 |
GList *
|
61 |
g_hash_to_list(GHashTable *h)
|
62 |
{
|
63 |
GList *ret=NULL;
|
64 |
g_hash_table_foreach(h, hash_callback, &ret);
|
65 |
|
66 |
return ret;
|
67 |
}
|
68 |
|
69 |
static void
|
70 |
hash_callback_key(gpointer key, gpointer value, gpointer user_data)
|
71 |
{
|
72 |
GList **l=user_data;
|
73 |
*l=g_list_prepend(*l, key);
|
74 |
}
|
75 |
|
76 |
GList *
|
77 |
g_hash_to_list_keys(GHashTable *h)
|
78 |
{
|
79 |
GList *ret=NULL;
|
80 |
g_hash_table_foreach(h, hash_callback_key, &ret);
|
81 |
|
82 |
return ret;
|
83 |
}
|
84 |
|
85 |
gchar *
|
86 |
g_strconcat_printf(gchar *buffer, gchar *fmt, ...)
|
87 |
{
|
88 |
gchar *str,*ret;
|
89 |
va_list ap;
|
90 |
|
91 |
va_start(ap, fmt);
|
92 |
str=g_strdup_vprintf(fmt, ap);
|
93 |
va_end(ap);
|
94 |
if (! buffer)
|
95 |
return str;
|
96 |
ret=g_strconcat(buffer, str, NULL);
|
97 |
g_free(buffer);
|
98 |
g_free(str);
|
99 |
return ret;
|
100 |
}
|
101 |
|
102 |
#ifndef HAVE_GLIB
|
103 |
int g_utf8_strlen_force_link(gchar *buffer, int max);
|
104 |
int
|
105 |
g_utf8_strlen_force_link(gchar *buffer, int max)
|
106 |
{
|
107 |
return g_utf8_strlen(buffer, max);
|
108 |
}
|
109 |
#endif
|
110 |
|
111 |
#if defined(_WIN32) || defined(__CEGCC__)
|
112 |
#include <windows.h>
|
113 |
#include <sys/types.h>
|
114 |
#endif
|
115 |
|
116 |
#if defined(_WIN32) || defined(__CEGCC__) || defined (__APPLE__) || defined(HAVE_API_ANDROID)
|
117 |
#include <stdio.h>
|
118 |
char *stristr(const char *String, const char *Pattern)
|
119 |
{
|
120 |
char *pptr, *sptr, *start;
|
121 |
|
122 |
for (start = (char *)String; *start != (int)NULL; start++)
|
123 |
{
|
124 |
/* find start of pattern in string */
|
125 |
for ( ; ((*start!=(int)NULL) && (toupper(*start) != toupper(*Pattern))); start++)
|
126 |
;
|
127 |
if ((int)NULL == *start)
|
128 |
return NULL;
|
129 |
|
130 |
pptr = (char *)Pattern;
|
131 |
sptr = (char *)start;
|
132 |
|
133 |
while (toupper(*sptr) == toupper(*pptr))
|
134 |
{
|
135 |
sptr++;
|
136 |
pptr++;
|
137 |
|
138 |
/* if end of pattern then pattern was found */
|
139 |
|
140 |
if ((int)NULL == *pptr)
|
141 |
return (start);
|
142 |
}
|
143 |
}
|
144 |
return NULL;
|
145 |
}
|
146 |
|
147 |
#ifndef SIZE_MAX
|
148 |
# define SIZE_MAX ((size_t) -1)
|
149 |
#endif
|
150 |
#ifndef SSIZE_MAX
|
151 |
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
|
152 |
#endif
|
153 |
#if !HAVE_FLOCKFILE
|
154 |
# undef flockfile
|
155 |
# define flockfile(x) ((void) 0)
|
156 |
#endif
|
157 |
#if !HAVE_FUNLOCKFILE
|
158 |
# undef funlockfile
|
159 |
# define funlockfile(x) ((void) 0)
|
160 |
#endif
|
161 |
|
162 |
/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
|
163 |
#ifndef EOVERFLOW
|
164 |
# define EOVERFLOW E2BIG
|
165 |
#endif
|
166 |
|
167 |
|
168 |
/**
|
169 |
* Read the part of a file up to a delimiter to a string.
|
170 |
* <p>
|
171 |
* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
|
172 |
NUL-terminate it).
|
173 |
* @param lineptr Pointer to a pointer returned from malloc (or
|
174 |
NULL), pointing to a buffer. It is realloc'ed as
|
175 |
necessary and will receive the data read.
|
176 |
* @param n Size of the buffer.
|
177 |
*
|
178 |
* @return Number of characters read (not including
|
179 |
the null terminator), or -1 on error or EOF.
|
180 |
*/
|
181 |
int
|
182 |
getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
|
183 |
{
|
184 |
int result;
|
185 |
size_t cur_len = 0;
|
186 |
|
187 |
if (lineptr == NULL || n == NULL || fp == NULL)
|
188 |
{
|
189 |
return -1;
|
190 |
}
|
191 |
|
192 |
flockfile (fp);
|
193 |
|
194 |
if (*lineptr == NULL || *n == 0)
|
195 |
{
|
196 |
*n = 120;
|
197 |
*lineptr = (char *) realloc (*lineptr, *n);
|
198 |
if (*lineptr == NULL)
|
199 |
{
|
200 |
result = -1;
|
201 |
goto unlock_return;
|
202 |
}
|
203 |
}
|
204 |
|
205 |
for (;;)
|
206 |
{
|
207 |
int i;
|
208 |
|
209 |
i = getc (fp);
|
210 |
if (i == EOF)
|
211 |
{
|
212 |
result = -1;
|
213 |
break;
|
214 |
}
|
215 |
|
216 |
/* Make enough space for len+1 (for final NUL) bytes. */
|
217 |
if (cur_len + 1 >= *n)
|
218 |
{
|
219 |
size_t needed_max=SIZE_MAX;
|
220 |
size_t needed = 2 * *n + 1; /* Be generous. */
|
221 |
char *new_lineptr;
|
222 |
if (needed_max < needed)
|
223 |
needed = needed_max;
|
224 |
if (cur_len + 1 >= needed)
|
225 |
{
|
226 |
result = -1;
|
227 |
goto unlock_return;
|
228 |
}
|
229 |
|
230 |
new_lineptr = (char *) realloc (*lineptr, needed);
|
231 |
if (new_lineptr == NULL)
|
232 |
{
|
233 |
result = -1;
|
234 |
goto unlock_return;
|
235 |
}
|
236 |
|
237 |
*lineptr = new_lineptr;
|
238 |
*n = needed;
|
239 |
}
|
240 |
|
241 |
(*lineptr)[cur_len] = i;
|
242 |
cur_len++;
|
243 |
|
244 |
if (i == delimiter)
|
245 |
break;
|
246 |
}
|
247 |
(*lineptr)[cur_len] = '\0';
|
248 |
result = cur_len ? cur_len : result;
|
249 |
|
250 |
unlock_return:
|
251 |
funlockfile (fp); /* doesn't set errno */
|
252 |
|
253 |
return result;
|
254 |
}
|
255 |
|
256 |
int
|
257 |
getline (char **lineptr, size_t *n, FILE *stream)
|
258 |
{
|
259 |
return getdelim (lineptr, n, '\n', stream);
|
260 |
}
|
261 |
|
262 |
#if defined(_UNICODE)
|
263 |
wchar_t* newSysString(const char *toconvert)
|
264 |
{
|
265 |
int newstrlen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, 0, 0);
|
266 |
wchar_t *newstring = g_new(wchar_t,newstrlen);
|
267 |
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, newstring, newstrlen) ;
|
268 |
return newstring;
|
269 |
}
|
270 |
#else
|
271 |
char * newSysString(const char *toconvert)
|
272 |
{
|
273 |
return g_strdup(toconvert);
|
274 |
}
|
275 |
#endif
|
276 |
#endif
|
277 |
|
278 |
#if defined(_MSC_VER) || (!defined(HAVE_GETTIMEOFDAY) && defined(HAVE_API_WIN32_BASE))
|
279 |
/**
|
280 |
* Impements a simple incomplete version of gettimeofday. Only usefull for messuring
|
281 |
* time spans, not the real time of day.
|
282 |
*/
|
283 |
int gettimeofday(struct timeval *time, void *local)
|
284 |
{
|
285 |
int milliseconds = GetTickCount();
|
286 |
|
287 |
time->tv_sec = milliseconds/1000;
|
288 |
time->tv_usec = (milliseconds - (time->tv_sec * 1000)) * 1000;
|
289 |
|
290 |
return 0;
|
291 |
}
|
292 |
#endif
|
293 |
/**
|
294 |
* Convert an ISO 8601-style time string into epoch time.
|
295 |
*
|
296 |
* @param iso8601 Pointer to a string containing the time in ISO 8601 format.
|
297 |
*
|
298 |
* @return An unsigned integer representing the number of seconds elapsed since January 1, 1970, 00:00:00 UTC.
|
299 |
*/
|
300 |
unsigned int
|
301 |
iso8601_to_secs(char *iso8601)
|
302 |
{
|
303 |
int a,b,d,val[6],i=0;
|
304 |
char *start=iso8601,*pos=iso8601;
|
305 |
while (*pos && i < 6) {
|
306 |
if (*pos < '0' || *pos > '9') {
|
307 |
val[i++]=atoi(start);
|
308 |
pos++;
|
309 |
start=pos;
|
310 |
}
|
311 |
pos++;
|
312 |
}
|
313 |
|
314 |
a=val[0]/100;
|
315 |
b=2-a+a/4;
|
316 |
|
317 |
if (val[1] < 2) {
|
318 |
val[0]--;
|
319 |
val[1]+=12;
|
320 |
}
|
321 |
|
322 |
d=1461*(val[0]+4716)/4+306001*(val[1]+1)/10000+val[2]+b-2442112;
|
323 |
|
324 |
return ((d*24+val[3])*60+val[4])*60+val[5];
|
325 |
}
|
326 |
|
327 |
/**
|
328 |
* Output local system time in ISO 8601 format.
|
329 |
*
|
330 |
* @return Pointer to a string containing the time in ISO 8601 format
|
331 |
*/
|
332 |
char *
|
333 |
current_to_iso8601(void)
|
334 |
{
|
335 |
char *timep=NULL;
|
336 |
#ifdef HAVE_API_WIN32_BASE
|
337 |
SYSTEMTIME ST;
|
338 |
GetSystemTime(&ST);
|
339 |
timep=g_strdup_printf("%d-%02d-%02dT%02d:%02d:%02dZ",ST.wYear,ST.wMonth,ST.wDay,ST.wHour,ST.wMinute,ST.wSecond);
|
340 |
#else
|
341 |
char buffer[32];
|
342 |
time_t tnow;
|
343 |
struct tm *tm;
|
344 |
tnow = time(0);
|
345 |
tm = gmtime(&tnow);
|
346 |
if (tm) {
|
347 |
strftime(buffer, sizeof(buffer), "%Y-%m-%dT%TZ", tm);
|
348 |
timep=g_strdup(buffer);
|
349 |
}
|
350 |
#endif
|
351 |
return timep;
|
352 |
}
|
353 |
|
354 |
|
355 |
struct spawn_process_info {
|
356 |
#ifdef HAVE_API_WIN32_BASE
|
357 |
PROCESS_INFORMATION pr;
|
358 |
#else
|
359 |
pid_t pid; // = -1 if non-blocking spawn isn't supported
|
360 |
int status; // exit status if non-blocking spawn isn't supported
|
361 |
#endif
|
362 |
};
|
363 |
|
364 |
|
365 |
/**
|
366 |
* Escape and quote string for shell
|
367 |
*
|
368 |
* @param in arg string to escape
|
369 |
* @returns escaped string
|
370 |
*/
|
371 |
char *
|
372 |
shell_escape(char *arg)
|
373 |
{
|
374 |
char *r;
|
375 |
int arglen=strlen(arg);
|
376 |
int i,j,rlen;
|
377 |
#ifdef HAVE_API_WIN32_BASE
|
378 |
{
|
379 |
int bscount=0;
|
380 |
rlen=arglen+3;
|
381 |
r=g_new(char,rlen);
|
382 |
r[0]='"';
|
383 |
for(i=0,j=1;i<arglen;i++) {
|
384 |
if(arg[i]=='\\') {
|
385 |
bscount++;
|
386 |
if(i==(arglen-1)) {
|
387 |
// Most special case - last char is
|
388 |
// backslash. We can't escape it inside
|
389 |
// quoted string due to Win unescaping
|
390 |
// rules so quote should be closed
|
391 |
// before backslashes and these
|
392 |
// backslashes shouldn't be doubled
|
393 |
rlen+=bscount;
|
394 |
r=g_realloc(r,rlen);
|
395 |
r[j++]='"';
|
396 |
memset(r+j,'\\',bscount);
|
397 |
j+=bscount;
|
398 |
}
|
399 |
} else {
|
400 |
//Any preceeding backslashes will be doubled.
|
401 |
bscount*=2;
|
402 |
// Double quote needs to be preceeded by
|
403 |
// at least one backslash
|
404 |
if(arg[i]=='"')
|
405 |
bscount++;
|
406 |
if(bscount>0) {
|
407 |
rlen+=bscount;
|
408 |
r=g_realloc(r,rlen);
|
409 |
memset(r+j,'\\',bscount);
|
410 |
j+=bscount;
|
411 |
bscount=0;
|
412 |
}
|
413 |
r[j++]=arg[i];
|
414 |
if(i==(arglen-1)) {
|
415 |
r[j++]='"';
|
416 |
}
|
417 |
}
|
418 |
}
|
419 |
r[j++]=0;
|
420 |
}
|
421 |
#else
|
422 |
{
|
423 |
// Will use hard quoting for the whole string
|
424 |
// and replace each singular quote found with a '\'' sequence.
|
425 |
rlen=arglen+3;
|
426 |
r=g_new(char,rlen);
|
427 |
r[0]='\'';
|
428 |
for(i=0,j=1;i<arglen;i++) {
|
429 |
if(arg[i]=='\'') {
|
430 |
rlen+=3;
|
431 |
r=g_realloc(r,rlen);
|
432 |
g_strlcpy(r+j,"'\\''",rlen-j);
|
433 |
} else {
|
434 |
r[j++]=arg[i];
|
435 |
}
|
436 |
}
|
437 |
r[j++]='\'';
|
438 |
r[j++]=0;
|
439 |
}
|
440 |
#endif
|
441 |
return r;
|
442 |
}
|
443 |
|
444 |
#ifndef _POSIX_C_SOURCE
|
445 |
static char*
|
446 |
spawn_process_compose_cmdline(char **argv)
|
447 |
{
|
448 |
int i,j;
|
449 |
char *cmdline=shell_escape(argv[0]);
|
450 |
for(i=1,j=strlen(cmdline);argv[i];i++) {
|
451 |
char *arg=shell_escape(argv[i]);
|
452 |
int arglen=strlen(arg);
|
453 |
cmdline[j]=' ';
|
454 |
cmdline=g_realloc(cmdline,j+1+arglen+1);
|
455 |
memcpy(cmdline+j+1,arg,arglen+1);
|
456 |
g_free(arg);
|
457 |
j=j+1+arglen;
|
458 |
}
|
459 |
return cmdline;
|
460 |
}
|
461 |
#endif
|
462 |
|
463 |
#ifdef _POSIX_C_SOURCE
|
464 |
|
465 |
#if 0 /* def _POSIX_THREADS */
|
466 |
#define spawn_process_sigmask(how,set,old) pthread_sigmask(how,set,old)
|
467 |
#else
|
468 |
#define spawn_process_sigmask(how,set,old) sigprocmask(how,set,old)
|
469 |
#endif
|
470 |
|
471 |
GList *spawn_process_children=NULL;
|
472 |
|
473 |
#endif
|
474 |
|
475 |
|
476 |
/**
|
477 |
* Call external program
|
478 |
*
|
479 |
* @param in argv NULL terminated list of parameters,
|
480 |
* zeroeth argument is program name
|
481 |
* @returns 0 - success, >0 - return code, -1 - error
|
482 |
*/
|
483 |
struct spawn_process_info*
|
484 |
spawn_process(char **argv)
|
485 |
{
|
486 |
struct spawn_process_info*r=g_new(struct spawn_process_info,1);
|
487 |
#ifdef _POSIX_C_SOURCE
|
488 |
{
|
489 |
pid_t pid;
|
490 |
|
491 |
sigset_t set, old;
|
492 |
sigemptyset(&set);
|
493 |
sigaddset(&set,SIGCHLD);
|
494 |
spawn_process_sigmask(SIG_BLOCK,&set,&old);
|
495 |
pid=fork();
|
496 |
if(pid==0) {
|
497 |
execvp(argv[0], argv);
|
498 |
/*Shouldn't reach here*/
|
499 |
exit(1);
|
500 |
} else if(pid>0) {
|
501 |
r->status=-1;
|
502 |
r->pid=pid;
|
503 |
spawn_process_children=g_list_prepend(spawn_process_children,r);
|
504 |
} else {
|
505 |
dbg(0,"fork() returned error.");
|
506 |
g_free(r);
|
507 |
r=NULL;
|
508 |
}
|
509 |
spawn_process_sigmask(SIG_SETMASK,&old,NULL);
|
510 |
return r;
|
511 |
}
|
512 |
#else
|
513 |
#ifdef HAVE_API_WIN32_BASE
|
514 |
{
|
515 |
char *cmdline;
|
516 |
LPCWSTR cmd,args;
|
517 |
DWORD dwRet;
|
518 |
|
519 |
// For [desktop] Windows it's adviceable not to use
|
520 |
// first CreateProcess parameter because PATH is not used
|
521 |
// if it is defined.
|
522 |
//
|
523 |
// On WinCE 6.0 I was unable to launch anything
|
524 |
// without first CreateProcess parameter, also it seems that
|
525 |
// no WinCE program has support for quoted strings in arguments.
|
526 |
// So...
|
527 |
#ifdef HAVE_API_WIN32_CE
|
528 |
cmdline=g_strjoinv(" ",argv+1);
|
529 |
args=newSysString(cmdline);
|
530 |
cmd = newSysString(argv[0]);
|
531 |
dwRet=CreateProcess(cmd, args, NULL, NULL, 0, 0, NULL, NULL, NULL, &(r->pr));
|
532 |
dbg(0, "CreateProcess(%s,%s), PID=%i\n",argv[0],cmdline,r->pr.dwProcessId);
|
533 |
g_free(cmd);
|
534 |
#else
|
535 |
STARTUPINFO startupInfo;
|
536 |
memset(&startupInfo, 0, sizeof(startupInfo));
|
537 |
startupInfo.cb = sizeof(startupInfo);
|
538 |
cmdline=spawn_process_compose_cmdline(argv);
|
539 |
args=newSysString(cmdline);
|
540 |
dwRet=CreateProcess(NULL, args, NULL, NULL, 0, 0, NULL, NULL, &startupInfo, &(r->pr));
|
541 |
dbg(0, "CreateProcess(%s), PID=%i\n",cmdline,r->pr.dwProcessId);
|
542 |
#endif
|
543 |
g_free(cmdline);
|
544 |
g_free(args);
|
545 |
return r;
|
546 |
}
|
547 |
#else
|
548 |
{
|
549 |
char *cmdline=spawn_process_compose_cmdline(argv);
|
550 |
int status;
|
551 |
dbg(0,"Unblocked spawn_process isn't availiable on this platform.\n");
|
552 |
status=system(cmdline);
|
553 |
g_free(cmdline);
|
554 |
r->status=status;
|
555 |
r->pid=0;
|
556 |
return r;
|
557 |
}
|
558 |
#endif
|
559 |
#endif
|
560 |
}
|
561 |
|
562 |
/**
|
563 |
* Check external program status
|
564 |
*
|
565 |
* @param in *pi pointer to spawn_process_info structure
|
566 |
* @param in block =0 do not block =1 block until child terminated
|
567 |
* @returns -1 - still running, >=0 program exited,
|
568 |
* =255 trminated abnormally or wasn't run at all.
|
569 |
*
|
570 |
*/
|
571 |
int spawn_process_check_status(struct spawn_process_info *pi, int block)
|
572 |
{
|
573 |
if(pi==NULL) {
|
574 |
dbg(0,"Trying to get process status of NULL, assuming process is terminated.\n");
|
575 |
return 255;
|
576 |
}
|
577 |
#ifdef HAVE_API_WIN32_BASE
|
578 |
{int failcount=0;
|
579 |
while(1){
|
580 |
DWORD dw;
|
581 |
if(GetExitCodeProcess(pi->pr.hProcess,&dw)) {
|
582 |
if(dw!=STILL_ACTIVE) {
|
583 |
return dw;
|
584 |
break;
|
585 |
}
|
586 |
} else {
|
587 |
dbg(0,"GetExitCodeProcess failed. Assuming the process is terminated.");
|
588 |
return 255;
|
589 |
}
|
590 |
if(!block)
|
591 |
return -1;
|
592 |
|
593 |
dw=WaitForSingleObject(pi->pr.hProcess,INFINITE);
|
594 |
if(dw==WAIT_FAILED && failcount++==1) {
|
595 |
dbg(0,"WaitForSingleObject failed twice. Assuming the process is terminated.");
|
596 |
return 0;
|
597 |
break;
|
598 |
}
|
599 |
}
|
600 |
}
|
601 |
#else
|
602 |
#ifdef _POSIX_C_SOURCE
|
603 |
if(pi->status!=-1) {
|
604 |
return pi->status;
|
605 |
}
|
606 |
while(1) {
|
607 |
int status;
|
608 |
pid_t w=waitpid(pi->pid,&status,block?0:WNOHANG);
|
609 |
if(w>0) {
|
610 |
if(WIFEXITED(status))
|
611 |
pi->status=WEXITSTATUS(status);
|
612 |
return pi->status;
|
613 |
if(WIFSTOPPED(status)) {
|
614 |
dbg(0,"child is stopped by %i signal\n",WSTOPSIG(status));
|
615 |
} else if (WIFSIGNALED(status)) {
|
616 |
dbg(0,"child terminated by signal %i\n",WEXITSTATUS(status));
|
617 |
pi->status=255;
|
618 |
return 255;
|
619 |
}
|
620 |
if(!block)
|
621 |
return -1;
|
622 |
} else if(w==0) {
|
623 |
if(!block)
|
624 |
return -1;
|
625 |
} else {
|
626 |
if(pi->status!=-1) // Signal handler has changed pi->status while in this function
|
627 |
return pi->status;
|
628 |
dbg(0,"waitpid() indicated error, reporting process termination.\n");
|
629 |
return 255;
|
630 |
}
|
631 |
}
|
632 |
#else
|
633 |
dbg(0, "Non-blocking spawn_process isn't availiable for this platform, repoting process exit status.\n");
|
634 |
return pi->status;
|
635 |
#endif
|
636 |
#endif
|
637 |
}
|
638 |
|
639 |
void spawn_process_info_free(struct spawn_process_info *pi)
|
640 |
{
|
641 |
if(pi==NULL)
|
642 |
return;
|
643 |
#ifdef HAVE_API_WIN32_BASE
|
644 |
CloseHandle(pi->pr.hProcess);
|
645 |
CloseHandle(pi->pr.hThread);
|
646 |
#endif
|
647 |
#ifdef _POSIX_C_SOURCE
|
648 |
{
|
649 |
sigset_t set, old;
|
650 |
sigemptyset(&set);
|
651 |
sigaddset(&set,SIGCHLD);
|
652 |
spawn_process_sigmask(SIG_BLOCK,&set,&old);
|
653 |
spawn_process_children=g_list_remove(spawn_process_children,pi);
|
654 |
spawn_process_sigmask(SIG_SETMASK,&old,NULL);
|
655 |
}
|
656 |
#endif
|
657 |
g_free(pi);
|
658 |
}
|
659 |
|
660 |
#ifdef _POSIX_C_SOURCE
|
661 |
static void spawn_process_sigchld(int sig)
|
662 |
{
|
663 |
int status;
|
664 |
pid_t pid;
|
665 |
while ((pid=waitpid(-1, &status, WNOHANG)) > 0) {
|
666 |
GList *el=g_list_first(spawn_process_children);
|
667 |
while(el) {
|
668 |
struct spawn_process_info *p=el->data;
|
669 |
if(p->pid==pid) {
|
670 |
p->status=status;
|
671 |
}
|
672 |
el=g_list_next(el);
|
673 |
}
|
674 |
}
|
675 |
}
|
676 |
#endif
|
677 |
|
678 |
void spawn_process_init()
|
679 |
{
|
680 |
#ifdef _POSIX_C_SOURCE
|
681 |
struct sigaction act;
|
682 |
act.sa_handler=spawn_process_sigchld;
|
683 |
act.sa_flags=0;
|
684 |
sigemptyset(&act.sa_mask);
|
685 |
sigaction(SIGCHLD, &act, NULL);
|
686 |
#endif
|
687 |
return;
|
688 |
}
|
689 |
|
690 |
|