Torque3D Documentation / _generateds / x86UNIXUtils.cpp

x86UNIXUtils.cpp

Engine/source/platformX86UNIX/x86UNIXUtils.cpp

More...

Public Variables

Detailed Description

Public Variables

UnixUtils utils 
UnixUtils * UUtils 
  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, 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
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell 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
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include <unistd.h>
 25#include <termios.h>
 26#include <stdio.h>
 27#include <sys/utsname.h>
 28
 29// for UnixCommandExecutor
 30#include <fcntl.h>
 31#include <errno.h>
 32#include <sys/wait.h>
 33#include <stdlib.h>
 34
 35#include "platformX86UNIX/platformX86UNIX.h"
 36#include "platformX86UNIX/x86UNIXUtils.h"
 37
 38UnixUtils *UUtils = NULL;
 39UnixUtils utils; 
 40
 41UnixUtils::UnixUtils()
 42{
 43   UUtils = this;
 44
 45   mUnameInfo = (struct utsname*)dRealMalloc(sizeof(struct utsname));;
 46   if (uname(mUnameInfo) == -1)
 47   {
 48      // oh well
 49      dRealFree(mUnameInfo);
 50      mUnameInfo = NULL;
 51   }
 52}
 53
 54UnixUtils::~UnixUtils()
 55{
 56   if (mUnameInfo != NULL)
 57   {
 58      dRealFree(mUnameInfo);
 59      mUnameInfo = NULL;
 60   }
 61}
 62
 63const char* UnixUtils::getOSName()
 64{
 65   if (mUnameInfo == NULL)
 66      return "";
 67
 68   return mUnameInfo->sysname;  
 69}
 70
 71bool UnixUtils::inBackground()
 72{
 73   int terminalGroupId = tcgetpgrp(fileno(stdin));
 74   int myPid = getpid();
 75   if (terminalGroupId != myPid)
 76      return true;
 77   else
 78      return false;
 79}
 80
 81//-----------------------------------------------------------------------------
 82// UnixCommandExecutor 
 83void UnixCommandExecutor::clearFields()
 84{
 85   mRet = -1;
 86   mStdoutSave = -1;
 87   mStderrSave = -1;
 88   mPipeFiledes[0] = -1;
 89   mPipeFiledes[1] = -1;
 90   mChildPID = -1;
 91   mBytesRead = 0;
 92   mStdoutClosed = false;
 93   mStderrClosed = false;
 94   mChildExited = false;
 95}
 96
 97UnixCommandExecutor::UnixCommandExecutor()
 98{
 99   clearFields();
100}
101
102UnixCommandExecutor::~UnixCommandExecutor()
103{
104   cleanup();
105}
106
107int UnixCommandExecutor::exec(char* args[], 
108                              char* stdoutCapture, int stdoutCaptureSize)
109{
110   // check for shitty parameters
111   if (args == NULL || stdoutCapture == NULL || 
112       stdoutCaptureSize <= 0)
113      return -666;
114
115   // we're going to be redirecting stdout, so save it so that we can 
116   // restore it
117   mRet = dup(1);
118   if (mRet == -1)
119   {
120      cleanup();
121      return mRet;
122   }
123   mStdoutSave = mRet;
124
125   // save stderr
126   mRet = dup(2);
127   if (mRet == -1)
128   {
129      cleanup();
130      return mRet;
131   }
132   mStderrSave = mRet;
133
134   // we'll need some pipe action for communicating with subprocess
135   mRet = pipe(mPipeFiledes);
136   if (mRet == -1)
137   {
138      cleanup();
139      return mRet;
140   }
141
142   // close stdout
143   mRet = close(1);
144   if (mRet == -1)
145   {
146      cleanup();
147      return mRet;
148   }
149   mStdoutClosed = true;
150
151   // stderr just gets closed and the output discarded
152   mRet = close(2);
153   if (mRet == -1)
154   {
155      cleanup();
156      return mRet;
157   }
158   mStderrClosed = true;
159
160   // dup the pipe output into stdout
161   mRet = dup2(mPipeFiledes[1], 1);
162   if (mRet == -1)
163   {
164      cleanup();
165      return mRet;
166   }
167
168   // fork
169   mRet = fork();
170   if (mRet == -1)
171   {
172      cleanup();
173      return mRet;
174   }
175         
176   if (mRet == 0)
177   {
178      // child process
179
180      //close(mPipeFiledes[0]);
181      mRet = execvp(args[0], args);
182      // if exec returns, some bad shit went down, so just
183      // get outta here
184      exit(mRet);
185   }
186
187   // parent process
188   mChildPID = mRet;
189
190   // need to suck in data from pipe while child is running, 
191   // otherwise child will eventually block on write and we'll
192   // wait forever
193   memset(stdoutCapture, 0, stdoutCaptureSize);
194
195   // set input to be non blocking so that we don't block on read
196   mRet = fcntl(mPipeFiledes[0], F_SETFL, O_NONBLOCK);
197   if (mRet == -1)
198   {
199      cleanup();
200      return mRet;
201   }
202
203   // check to see if child has exited
204   mRet = waitpid(mChildPID, NULL, WNOHANG);
205   while (mRet == 0)
206   {
207      // not exited, read some data
208      mRet = read(mPipeFiledes[0], stdoutCapture + mBytesRead, 
209                  stdoutCaptureSize - mBytesRead);
210      // any error that isn't EAGAIN means we should exit
211      if (mRet == -1 && errno != EAGAIN)
212      {
213         cleanup();
214         return mRet;
215      }
216
217      // if the read was ok, increment bytes read
218      if (mRet != -1)
219         mBytesRead += mRet;
220
221      // check again for child exit
222      mRet = waitpid(mChildPID, NULL, WNOHANG);    
223   }
224
225   // check for error from waitpid
226   if (mRet == -1 && errno != ECHILD)
227   {
228      cleanup();
229      return mRet;
230   }
231
232   // if we get here, the child exited
233   mChildExited = true;
234
235   // read final bit of data
236   mRet = read(mPipeFiledes[0], stdoutCapture + mBytesRead, 
237               stdoutCaptureSize - mBytesRead);
238   if (mRet == -1 && errno != EAGAIN)
239   {
240      cleanup();
241      return mRet;
242   }
243
244   if (mRet != -1)
245      mBytesRead += mRet;
246
247   // done...cleanup
248   cleanup();
249
250   return 0;
251}
252
253void UnixCommandExecutor::cleanup()
254{
255   // if child spawned and not exited, wait
256   if (mChildPID > 0 && !mChildExited)
257      waitpid(mChildPID, NULL, 0);
258   // close pipe descriptors
259   if (mPipeFiledes[0] != -1)
260      close(mPipeFiledes[0]);
261   if (mPipeFiledes[1] != -1)
262      close(mPipeFiledes[1]);
263   // if stdout is redirected, restore it
264   if (mStdoutClosed && mStdoutSave != -1)
265      dup2(mStdoutSave, 1);
266   // close stdout save descriptor
267   if (mStdoutSave != -1)
268      close(mStdoutSave);
269   // if stderr is redirected, restore it
270   if (mStderrClosed && mStderrSave != -1)
271      dup2(mStderrSave, 2);
272   // close stderr save descriptor
273   if (mStderrSave != -1)
274      close(mStderrSave);
275
276   clearFields();
277}
278
279/* Usage:
280   UnixCommandExecutor exec;
281   char* args[] = { "ps", "-aux", NULL };
282   char data[20000];
283   int ret = exec.exec(args, data, sizeof(data));
284   printf("%s", data);
285*/
286