rllib  1
rlspawn.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  rlspawn.cpp - description
3  -------------------
4  begin : Tue Jan 02 2001
5  copyright : (C) 2001 by R. Lehrig
6  email : lehrig@t-online.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This library is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as *
13  * published by the Free Software Foundation *
14  * *
15  ***************************************************************************/
16 #include "rldefine.h"
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #ifndef RLWIN32
22 #include <unistd.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #else
26 #include <windows.h>
27 #include <psapi.h>
28 #endif
29 #include "rlspawn.h"
30 #include "rlcutil.h"
31 #ifdef RLUNIX
32 #include <sys/wait.h>
33 #include <signal.h>
34 #endif
35 #include "rlstring.h"
36 
37 #ifdef RLWIN32_NOT_USABLE
38 WaitNamedPipe function
39 Minimum supported client Windows 2000 Professional [desktop apps only]
40 http://msdn.microsoft.com/en-us/library/windows/desktop/aa365800%28v=vs.85%29.aspx
41 static int GetFileNameFromHandle(HANDLE hFile, char *pszFilename, const int max_path)
42 {
43  int bSuccess = 0;
44  //TCHAR pszFilename[MAX_PATH+1];
45  HANDLE hFileMap;
46 
47  // Get the file size.
48  DWORD dwFileSizeHi = 0;
49  DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
50 
51  if( dwFileSizeLo == 0 && dwFileSizeHi == 0 )
52  {
53  printf(TEXT("Cannot map a file with a length of zero.\n"));
54  return FALSE;
55  }
56 
57  // Create a file mapping object.
58  hFileMap = CreateFileMapping(hFile,
59  NULL,
60  PAGE_READONLY,
61  0,
62  1,
63  NULL);
64 
65  if (hFileMap)
66  {
67  // Create a file mapping to get the file name.
68  void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
69 
70  if (pMem)
71  {
72  if (GetMappedFileName (GetCurrentProcess(),
73  pMem,
74  pszFilename,
75  max_path))
76  {
77 
78  // Translate path with device name to drive letters.
79  TCHAR szTemp[1024];
80  szTemp[0] = '\0';
81 
82  if (GetLogicalDriveStrings((int) sizeof(szTemp) -1, szTemp))
83  {
84  TCHAR szName[max_path];
85  TCHAR szDrive[3] = TEXT(" :");
86  int bFound = 0;
87  TCHAR* p = szTemp;
88 
89  do
90  {
91  // Copy the drive letter to the template string
92  *szDrive = *p;
93 
94  // Look up each device name
95  if (QueryDosDevice(szDrive, szName, max_path))
96  {
97  int uNameLen = strlen(szName);
98  rlString rlName(szName);
99  if (uNameLen < max_path)
100  {
101  //bFound = _tcsnicmp(pszFilename, szName, uNameLen) == 0
102  // && *(pszFilename + uNameLen) == _T('\\');
103  bFound = rlName.strnnocasecmp(pszFilename, uNameLen) == 0
104  && *(pszFilename + uNameLen) == _T('\\');
105 
106  if (bFound)
107  {
108  // Reconstruct pszFilename using szTempFile
109  // Replace device path with DOS path
110  TCHAR szTempFile[max_path];
111  StringCchPrintf(szTempFile,
112  max_path,
113  TEXT("%s%s"),
114  szDrive,
115  pszFilename+uNameLen);
116  StringCchCopyN(pszFilename, max_path+1, szTempFile, _tcslen(szTempFile));
117  }
118  }
119  }
120 
121  // Go to the next NULL character.
122  while (*p++);
123  } while (!bFound && *p); // end of string
124  }
125  }
126  bSuccess = 1;
127  UnmapViewOfFile(pMem);
128  }
129 
130  CloseHandle(hFileMap);
131  }
132  //_tprintf(TEXT("File name is %s\n"), pszFilename);
133  return bSuccess;
134 }
135 #endif
136 
138 {
139 #ifdef RLWIN32
140  fromChildRD = NULL;
141  fromChildRD = NULL;
142  toChildRD = NULL;
143  toChildWR = NULL;
144  hThread = NULL;
145  hProcess = NULL;
146  pid = 0;
147 #else
148  toChild = fromChild = NULL;
149  pid = 0;
150 #endif
151 }
152 
154 {
155 #ifdef RLWIN32
156  if(fromChildRD != NULL) CloseHandle(fromChildRD);
157  if(fromChildWR != NULL) CloseHandle(fromChildWR);
158  if(toChildRD != NULL) CloseHandle(toChildRD);
159  if(toChildWR != NULL) CloseHandle(toChildWR);
160  if(hThread != NULL) CloseHandle(hThread);
161  if(hProcess != NULL) CloseHandle(hProcess);
162 #else
163  if(toChild != NULL) ::fclose((FILE*) toChild);
164  if(fromChild != NULL) ::fclose((FILE*) fromChild);
165 #endif
166 }
167 
168 int rlSpawn::spawn(const char *command)
169 {
170 #ifdef RLWIN32
171  if(fromChildRD != NULL) CloseHandle(fromChildRD);
172  if(fromChildWR != NULL) CloseHandle(fromChildWR);
173  if(toChildRD != NULL) CloseHandle(toChildRD);
174  if(toChildWR != NULL) CloseHandle(toChildWR);
175  if(hThread != NULL) CloseHandle(hThread);
176  if(hProcess != NULL) CloseHandle(hProcess);
177  fromChildRD = NULL;
178  fromChildWR = NULL;
179  toChildRD = NULL;
180  toChildWR = NULL;
181  hThread = NULL;
182  hProcess = 0;
183 
184  SECURITY_ATTRIBUTES saAttr;
185  saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
186  saAttr.bInheritHandle = TRUE;
187  saAttr.lpSecurityDescriptor = NULL;
188 
189  char cmd[strlen(command)+1];
190  strcpy(cmd,command);
191 
192  if(!CreatePipe(&fromChildRD, &fromChildWR, &saAttr, 0))
193  {
194  printf("CreatePipe() - pipe for child process STDOUT failed\n");
195  return -1;
196  }
197  if(!SetHandleInformation(fromChildRD, HANDLE_FLAG_INHERIT, 0)) // Ensure the read handle to the pipe for STDOUT is not inherited
198  {
199  printf("SetHandleInformation() - pipe STDOUT read handle failed for inheritance\n");
200  CloseHandle(fromChildRD);
201  fromChildRD = NULL;
202  CloseHandle(fromChildWR);
203  fromChildWR = NULL;
204  return -2;
205  }
206  if(!CreatePipe(&toChildRD, &toChildWR, &saAttr, 0))
207  {
208  printf("CreatePipe() - pipe for child process STDIN failed\n");
209  CloseHandle(fromChildRD);
210  fromChildRD = NULL;
211  CloseHandle(fromChildWR);
212  fromChildWR = NULL;
213  return -3;
214  }
215  if(!SetHandleInformation(toChildWR, HANDLE_FLAG_INHERIT, 0)) // Ensure the write handle to the pipe for STDIN is not inherited
216  {
217  printf("SetHandleInformation() - pipe STDIN write handle failed for inheritance\n");
218  CloseHandle(fromChildRD);
219  fromChildRD = NULL;
220  CloseHandle(fromChildWR);
221  fromChildWR = NULL;
222  CloseHandle(toChildRD);
223  toChildRD = NULL;
224  CloseHandle(toChildWR);
225  toChildWR = NULL;
226  return -4;
227  }
228 
229  STARTUPINFO si; // = { sizeof(si)};
230  memset(&si,0,sizeof(si));
231  si.cb = sizeof(si);
232  si.hStdError = fromChildWR;
233  si.hStdOutput = fromChildWR;
234  si.hStdInput = toChildRD;
235  si.dwFlags |= STARTF_USESTDHANDLES;
236 
237  PROCESS_INFORMATION pi;
238  memset(&pi,0,sizeof(pi));
239 
240  DWORD dwCreationFlags = 0;
241 
242  int ret = (int) CreateProcess( NULL, cmd
243  , NULL, NULL
244  , TRUE, dwCreationFlags
245  , NULL, NULL
246  , &si, &pi);
247  if(ret)
248  { // success
249  hProcess = pi.hProcess;
250  hThread = pi.hThread;
251  return 1;
252  }
253  // fail
254  CloseHandle(fromChildRD);
255  fromChildRD = NULL;
256  CloseHandle(fromChildWR);
257  fromChildWR = NULL;
258  CloseHandle(toChildRD);
259  toChildRD = NULL;
260  CloseHandle(toChildWR);
261  toChildWR = NULL;
262  return -1;
263 #else
264  int to_child[2],from_child[2],ret;
265 
266  if(toChild != NULL) ::fclose((FILE*) toChild);
267  if(fromChild != NULL) ::fclose((FILE*) fromChild);
268  toChild = fromChild = NULL;
269 
270  ret = ::pipe(to_child);
271  if(ret == -1) return -1;
272  ret = ::pipe(from_child);
273  if(ret == -1) return -1;
274 
275  if((pid = ::fork()) == 0)
276  {
277  if(to_child[0] != 0) // stdin
278  {
279  ::dup2(to_child[0],0);
280  ::close(to_child[0]);
281  }
282  if(from_child[1] != 2) // stderr
283  {
284  ::dup2(from_child[1] ,2);
285  }
286  if(from_child[1] != 1) // stdout
287  {
288  ::dup2(from_child[1],1);
289  ::close(from_child[1]);
290  }
291  ::close(to_child[1]);
292  ::close(from_child[0]);
293  ::rlexec(command);
294  ::exit(0);
295  }
296 
297  ::close(to_child[0]);
298  ::close(from_child[1]);
299  toChild = (void*) ::fdopen(to_child[1],"w");
300  if(toChild == NULL) { return -1; }
301  fromChild = (void*) ::fdopen(from_child[0],"r");
302  if(fromChild == NULL) { ::fclose((FILE*) toChild); return -1; }
303  return pid;
304 #endif
305 }
306 
307 const char *rlSpawn::readLine()
308 {
309 #ifdef RLWIN32
310  char *cptr;
311  if(fromChildRD == NULL) return NULL;
312  int i,c;
313  for(i=0; i < (int) sizeof(line) - 1; i++)
314  {
315  if((c = getchar()) < 0)
316  {
317  if(i==0) return NULL;
318  line[i] = '\0';
319  return line;
320  }
321  line[i] = (char) c;
322  if(c == '\n')
323  {
324  cptr = strchr(line,0x0d);
325  if(cptr != NULL)
326  {
327  cptr[0] = '\n';
328  cptr[1] = '\0';
329  return line;
330  }
331  line[i+1] = '\0';
332  return line;
333  }
334  }
335  line[i] = '\0';
336  return line;
337 #else
338  if(fromChild == NULL) return NULL;
339  if(::fgets(line,sizeof(line)-1,(FILE*) fromChild) == NULL)
340  {
341 #ifdef RLUNIX
342  if(pid != 0)
343  {
344  int status;
345  waitpid(pid, &status, 0);
346  kill(pid,SIGHUP);
347  }
348 #endif
349  return NULL;
350  }
351  return line;
352 #endif
353 }
354 
356 {
357 #ifdef RLWIN32
358  if(fromChildRD == NULL) return EOF;
359  DWORD readed = 0;
360  unsigned char buf[4];
361  int ret = (int) ReadFile(fromChildRD, buf, 1, &readed, NULL);
362  if(ret)
363  { // success
364  if(readed == 1) return buf[0];
365  }
366  if(fromChildRD != NULL) CloseHandle(fromChildRD);
367  if(fromChildWR != NULL) CloseHandle(fromChildWR);
368  if(toChildRD != NULL) CloseHandle(toChildRD);
369  if(toChildWR != NULL) CloseHandle(toChildWR);
370  if(hThread != NULL) CloseHandle(hThread);
371  if(hProcess != NULL) CloseHandle(hProcess);
372  fromChildRD = NULL;
373  fromChildWR = NULL;
374  toChildRD = NULL;
375  toChildWR = NULL;
376  hThread = NULL;
377  hProcess = NULL;
378  return EOF;
379 #else
380  if(fromChild == NULL) return EOF;
381  return ::fgetc((FILE*) fromChild);
382 #endif
383 }
384 
385 int rlSpawn::write(const char *buf, int len)
386 {
387 #ifdef RLWIN32
388  if(toChildWR == NULL) return -1;
389  DWORD written = 0;
390  int ret = (int) WriteFile(toChildWR, buf, len, &written, NULL);
391  if(ret)
392  { // success
393  return written;
394  }
395  return -1;
396 #else
397  if(toChild == NULL) return -1;
398  return ::write(fileno((FILE*)toChild),buf,len);
399 #endif
400 }
401 
402 int rlSpawn::printf(const char *format, ...)
403 {
404  int ret;
405  char message[rl_PRINTF_LENGTH]; // should be big enough
406 
407  va_list ap;
408  va_start(ap,format);
409  ret = rlvsnprintf(message, rl_PRINTF_LENGTH - 1, format, ap);
410  va_end(ap);
411  if(ret < 0) return ret;
412  return write(message,strlen(message));
413 }
414 
415 int rlSpawn::writeString(const char *buf)
416 {
417  if(buf[0] == EOF && buf[1] == '\0')
418  {
419 #ifdef RLWIN32
420  if(fromChildRD != NULL) CloseHandle(fromChildRD);
421  if(fromChildWR != NULL) CloseHandle(fromChildWR);
422  if(toChildRD != NULL) CloseHandle(toChildRD);
423  if(toChildWR != NULL) CloseHandle(toChildWR);
424  if(hThread != NULL) CloseHandle(hThread);
425  if(hProcess != NULL) CloseHandle(hProcess);
426  fromChildRD = NULL;
427  fromChildWR = NULL;
428  toChildRD = NULL;
429  toChildWR = NULL;
430  hThread = NULL;
431  hProcess = NULL;
432 #else
433  if(toChild != NULL) ::fclose((FILE*) toChild);
434  if(fromChild != NULL) ::fclose((FILE*) fromChild);
435  toChild = NULL;
436  fromChild = NULL;
437 #endif
438  return 0;
439  }
440 #ifdef RLWIN32
441  if(toChildWR == NULL) return -1;
442  int len = strlen(buf);
443  return write(buf,len+1);
444 #else
445  if(toChild == NULL) return -1;
446  return fprintf((FILE*)toChild,"%s",buf);
447 #endif
448 }
449 
451 {
452  const char *cptr;
453  while((cptr=readLine()) != NULL) ::printf("%s",cptr);
454 }
455 
456 int rlSpawn::select(int timeout)
457 {
458 #ifdef RLWIN32
459  // windows does not support select on ReadFile
460  // ReadFile will return if there are no more bytes available
461  //if( _kbhit() ) return 1;
462  if(1) return 1;
463  if(timeout > 0) return 0;
464  if(fromChildRD == NULL) return 0;
465  return 0;
466 #else
467  struct timeval timout;
468  fd_set wset,rset,eset;
469  int ret,maxfdp1,s;
470 
471  if(fromChild == NULL) return -1;
472  s = fileno((FILE *) fromChild);
473  /* setup sockets to read */
474  maxfdp1 = s+1;
475  FD_ZERO(&rset);
476  FD_SET (s,&rset);
477  FD_ZERO(&wset);
478  FD_ZERO(&eset);
479  timout.tv_sec = timeout / 1000;
480  timout.tv_usec = (timeout % 1000) * 1000;
481 
482  ret = ::select(maxfdp1,&rset,&wset,&eset,&timout);
483  if(ret == 0) return 0; /* timeout */
484  return 1;
485 #endif
486 }
487 
489 {
490 #ifdef RLWIN32
491  return NULL;
492 #else
493  return (FILE *) fromChild;
494 #endif
495 }
496 
498 {
499 #ifdef RLUNIX
500  if(pid == -1) return -1;
501  if(pid == 0) return -1;
502  kill(pid,SIGKILL);
503  //printf("kill pid=%ld\n",m_pid);
504 #endif
505 
506 #ifdef __VMS
507  if(pid == -1) return -1;
508  if(pid == 0) return -1;
509  kill(pid,SIGKILL);
510 #endif
511 
512 #ifdef RLWIN32
513  if(hProcess == 0) return -1;
514  TerminateProcess((HANDLE) hProcess, 0);
515  WaitForSingleObject((HANDLE) hProcess, 60000);
516  CloseHandle((HANDLE) hProcess);
517  CloseHandle((HANDLE) hThread);
518  hThread = 0;
519  hProcess = 0;
520 #endif
521 
522  pid = 0;
523  return 0;
524 }
525 
526 int rlSpawn::readJpegBuffer(unsigned char *buffer, int maxbuffer)
527 {
528  int c1, c2;
529 
530  // search for startOfImage ff d8
531  while(1)
532  {
533  if((c1 = getchar()) < 0) return -1;
534  if(c1 == 0x0ff)
535  {
536  if((c2 = getchar()) < 0) return -2;
537  if(c2 == 0x0d8)
538  {
539  break;
540  }
541  }
542  }
543 
544  int ind = 0;
545  buffer[ind++] = (unsigned char) c1;
546  buffer[ind++] = (unsigned char) c2;
547  while(1) // read until endOfImage ff d9
548  {
549  if(ind >= maxbuffer) return -3;
550  if((c1 = getchar()) < 0) return -4;
551  buffer[ind++] = (unsigned char) c1;
552  if(c1 == 0x0ff)
553  {
554  if((c2 = getchar()) < 0) return -5;
555  buffer[ind++] = (unsigned char) c2;
556  if(c2 == 0x0d9)
557  {
558  return ind;;
559  }
560  }
561  }
562 }
563 
int select(int timeout=50)
Definition: rlspawn.cpp:456
HANDLE fromChildRD
Definition: rlspawn.h:159
FILE * getFilepointer()
Definition: rlspawn.cpp:488
HANDLE hProcess
Definition: rlspawn.h:162
int getchar()
Definition: rlspawn.cpp:355
HANDLE hThread
Definition: rlspawn.h:161
int writeString(const char *buf)
Definition: rlspawn.cpp:415
int printf(const char *format,...)
Definition: rlspawn.cpp:402
#define rl_PRINTF_LENGTH
Definition: rldefine.h:71
int readJpegBuffer(unsigned char *buffer, int maxbuffer)
Definition: rlspawn.cpp:526
int write(const char *buf, int len)
Definition: rlspawn.cpp:385
int rlexec(const char *command)
Definition: rlcutil.cpp:113
int rlvsnprintf(char *text, int len, const char *format, va_list ap)
Definition: rlcutil.cpp:197
void printAll()
Definition: rlspawn.cpp:450
int sigkill()
Definition: rlspawn.cpp:497
const char * readLine()
Definition: rlspawn.cpp:307
rlSpawn()
Definition: rlspawn.cpp:137
char line[4096]
Definition: rlspawn.h:166
int pid
Definition: rlspawn.h:153
HANDLE fromChildWR
Definition: rlspawn.h:160
HANDLE toChildWR
Definition: rlspawn.h:158
int spawn(const char *command)
Definition: rlspawn.cpp:168
virtual ~rlSpawn()
Definition: rlspawn.cpp:153
HANDLE toChildRD
Definition: rlspawn.h:157