x86UNIXUtils.cpp
Engine/source/platformX86UNIX/x86UNIXUtils.cpp
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