1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/genericopenlibs/cstdlib/USTLIB/POSIXIF.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1667 @@
1.4 +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// Client interface to the CPosixServer
1.18 +//
1.19 +//
1.20 +
1.21 +#include "POSIXIF.H"
1.22 +#include "LTIME.H"
1.23 +#include "LPOSIX.H"
1.24 +#include <fcntl.h>
1.25 +#include <sys/errno.h>
1.26 +#include <sys/serial.h>
1.27 +#include <sys/wait.h>
1.28 +
1.29 +
1.30 +#ifdef _DEBUG
1.31 +#define DebugPrint RDebug::Print
1.32 +#else
1.33 +inline void DebugPrint(const TDesC&, ...) {}
1.34 +#endif
1.35 +
1.36 +// RPosixSession
1.37 +//
1.38 +// The message protocol is to pass the errno pointer in p[0] and a pointer to a PosixParams
1.39 +// in p[1]. The result is written back into the PosixParams.retval field.
1.40 +
1.41 +int RPosixSession::Request(TInt aFunction, int& anErrno, PosixParams& aParams) const
1.42 + {
1.43 + return SendReceive(aFunction,TIpcArgs(&anErrno,&aParams));
1.44 + }
1.45 +
1.46 +void RPosixSession::Request(TInt aFunction, int& anErrno, PosixParams& aParams, TRequestStatus& aStatus) const
1.47 + {
1.48 + SendReceive(aFunction,TIpcArgs(&anErrno,&aParams),aStatus); // asynchronous request
1.49 + }
1.50 +
1.51 +void RPosixSession::Request(TInt aFunction, const TIpcArgs& aArg,TRequestStatus &aStatus) const
1.52 + {
1.53 + RSessionBase::SendReceive(aFunction,aArg,aStatus);
1.54 + }
1.55 +TInt RPosixSession::Request(TInt aFunction, const TIpcArgs& aArg) const
1.56 + {
1.57 + return RSessionBase::SendReceive(aFunction,aArg);
1.58 + }
1.59 +
1.60 +TVersion RPosixSession::Version()
1.61 + {
1.62 + return TVersion(KCPosixMajorVersionNumber,KCPosixMinorVersionNumber,0);
1.63 + }
1.64 +
1.65 +TInt RPosixSession::Connect (TDesC& aServerName)
1.66 + {
1.67 + TVersion version=Version();
1.68 + return CreateSession(aServerName,version,1+3); // 3 extra message slots for pipes
1.69 + }
1.70 +
1.71 +TInt RPosixSession::Connect ()
1.72 + {
1.73 + TBuf<80> serverName;
1.74 + PosixServerName(serverName);
1.75 + return CreateSession(serverName,Version(),1);
1.76 + }
1.77 +
1.78 +// CPosixServer support functions exported from ESTLIB.DLL
1.79 +
1.80 +#if defined(__WINS__)
1.81 +
1.82 +// simple scheme to provide pretend processes on WINS
1.83 +
1.84 +extern "C" void getcwd(char*,int);
1.85 +typedef void (*FUNC)();
1.86 +
1.87 +static int id=1;
1.88 +EXPORT_C void NewProcessId ()
1.89 + {
1.90 + id += 10;
1.91 + }
1.92 +
1.93 +static FUNC procFn;
1.94 +EXPORT_C void NextProcessFn (TAny* aFn)
1.95 + {
1.96 + procFn=(FUNC)aFn;
1.97 + }
1.98 +
1.99 +TInt threadhelper (TAny* aFn)
1.100 + {
1.101 + CTrapCleanup::New();
1.102 + FUNC f=(FUNC)aFn;
1.103 + (*f)();
1.104 + return 0;
1.105 + }
1.106 +TInt processhelper (TAny*)
1.107 + {
1.108 + // Do the MCRT0.OBJ things straight away
1.109 + SpawnPosixServerThread();
1.110 + char wd[80];
1.111 + getcwd(wd, sizeof(wd)); // connect to CPosixServer
1.112 + return threadhelper(procFn);
1.113 + }
1.114 +#endif // __WINS__
1.115 +_LIT(SERVER_FORMAT,"Posix-%d");
1.116 +_LIT(SERVER_MATCH, "Posix-*");
1.117 +
1.118 +EXPORT_C void PosixServerName(TDes& aBuffer)
1.119 +//
1.120 +// Construct the name of the CPosixServer for this process
1.121 +//
1.122 + {
1.123 + TProcessId id=RProcess().Id();
1.124 + aBuffer.Format(SERVER_FORMAT,*REINTERPRET_CAST(int*,&id));
1.125 + }
1.126 +
1.127 +struct rendezvous
1.128 + {
1.129 + RThread iCaller;
1.130 + TRequestStatus* iStatus;
1.131 + };
1.132 +
1.133 +EXPORT_C TInt SpawnPosixServerThread ()
1.134 +//
1.135 +// Try to start a PosixServer thread, assuming there isn't one already
1.136 +//
1.137 + {
1.138 + RPosixSession probe;
1.139 + TInt err=probe.Connect();
1.140 + probe.Close();
1.141 + if (err==KErrNone)
1.142 + return KErrNone; // server already exists
1.143 + TBuf<80> serverName;
1.144 + PosixServerName(serverName);
1.145 + TRequestStatus status(KRequestPending);
1.146 + struct rendezvous rv;
1.147 + rv.iCaller.Duplicate(RThread(),EOwnerProcess);
1.148 + rv.iStatus=&status;
1.149 + RThread server;
1.150 + err=server.Create(serverName,CPosixServer::ThreadFunction,0x2000,NULL,&rv);
1.151 + if (err==KErrNone)
1.152 + {
1.153 + server.Resume();
1.154 + User::WaitForRequest(status);
1.155 + err=status.Int();
1.156 + server.Close();
1.157 + }
1.158 + rv.iCaller.Close();
1.159 + return err;
1.160 + }
1.161 +
1.162 +EXPORT_C TInt InstallPosixServerActiveObject (TInt aPriority)
1.163 + {
1.164 + TRAPD(err, CPosixServer::InitL(aPriority));
1.165 + return err;
1.166 + }
1.167 +
1.168 +void CPosixServer::InitL(TInt aPriority)
1.169 +//
1.170 +// Construct and install a CPosixServer active object
1.171 +//
1.172 + {
1.173 + CPosixServer *pS=new(ELeave) CPosixServer(aPriority);
1.174 + CleanupStack::PushL(pS);
1.175 + TBuf<80> serverName;
1.176 + PosixServerName(serverName);
1.177 +
1.178 + User::LeaveIfError(pS->iFs.Connect());
1.179 +
1.180 + pS->iFids.InitL();
1.181 +
1.182 + // search for parent process
1.183 + pS->FindParentL();
1.184 +
1.185 + // set up default fids
1.186 + pS->DefaultConsoleL();
1.187 +
1.188 + DebugPrint(_L("Starting CPosixServer\n"));
1.189 + pS->StartL(serverName);
1.190 + CleanupStack::Pop(pS);
1.191 +// Leave pS on the clean up stack for the calling routine to clean up normally on
1.192 +// Active Scheduler shutdown or in a failure case where the scheduler does not
1.193 +// start due to an error.
1.194 +
1.195 + }
1.196 +
1.197 +// CPosixServer
1.198 +
1.199 +CPosixServer::CPosixServer(TInt aPriority)
1.200 + : CServer2(aPriority)
1.201 + {
1.202 + __DECLARE_NAME(_S("CPosixServer"));
1.203 + }
1.204 +
1.205 +TInt CPosixServer::ThreadFunction(TAny* aPtr)
1.206 +//
1.207 +// Create and run an active scheduler containing a CPosixServer
1.208 +//
1.209 + {
1.210 + CTrapCleanup* TheTrapCleanup=CTrapCleanup::New();
1.211 +
1.212 + RLibrary stdlib;
1.213 + stdlib.Load(_L("estlib")); // workaround for RAM-loaded EXE calling RAM-loaded DLL
1.214 +
1.215 + struct rendezvous* rvp = (struct rendezvous *)aPtr;
1.216 + TInt ret=KErrNone;
1.217 + // start scheduler and server
1.218 + CActiveScheduler *pA=new CActiveScheduler;
1.219 + if (pA!=NULL)
1.220 + {
1.221 + CActiveScheduler::Install(pA);
1.222 + ret=InstallPosixServerActiveObject();
1.223 + }
1.224 + // signal to the caller that we've started (or failed!)
1.225 + rvp->iCaller.RequestComplete(rvp->iStatus,ret);
1.226 + if (ret==KErrNone)
1.227 + {
1.228 + // start fielding requests from clients
1.229 + CActiveScheduler::Start();
1.230 + }
1.231 + // finished
1.232 + delete TheTrapCleanup;
1.233 + return(KErrNone);
1.234 + }
1.235 +
1.236 +CSession2* CPosixServer::NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const
1.237 + {
1.238 + TBool r=User::QueryVersionSupported(RPosixSession::Version(),aVersion);
1.239 + if (!r)
1.240 + User::Leave(KErrNotSupported);
1.241 +
1.242 + RProcess clientProcess;
1.243 + RThread clientThread;
1.244 + User::LeaveIfError(aMessage.Client(clientThread));
1.245 + CleanupClosePushL(clientThread);
1.246 + User::LeaveIfError(clientThread.Process(clientProcess));
1.247 + TProcessId clientId = clientProcess.Id();
1.248 + clientProcess.Close();
1.249 + CleanupStack::PopAndDestroy(1); //close thread
1.250 +
1.251 + if (clientId!=RProcess().Id())
1.252 + {
1.253 + // A thread in a different process
1.254 + if (iChildren==0)
1.255 + User::Leave(KErrNotReady); // quick rejection
1.256 +
1.257 + // We need an explicit CONST_CAST so that the CPosixRequest objects have a
1.258 + // mutable reference to the CPosixServer which holds the shared data structures
1.259 + return new(ELeave) CPosixIPCSession(CONST_CAST(CPosixServer&,*this));
1.260 + }
1.261 + // A thread in the same process
1.262 + return new(ELeave) CPosixSession(CONST_CAST(CPosixServer&,*this));
1.263 + }
1.264 +
1.265 +void CPosixServer::ServerPanic (TPosixServerPanic aPanic)
1.266 + {
1.267 + _LIT(KPosixServerPanic, "Posix server");
1.268 + User::Panic(KPosixServerPanic,aPanic);
1.269 + }
1.270 +
1.271 +void CPosixServer::FindParentL()
1.272 + {
1.273 + TFullName parent;
1.274 + TPosixIPCPid pid;
1.275 + TPosixIPCReply reply;
1.276 +
1.277 + TProcessId id=RProcess().Id();
1.278 + pid = *REINTERPRET_CAST(TUint*,&id); // my process id
1.279 +
1.280 + TFindServer posixservers(SERVER_MATCH);
1.281 + while (posixservers.Next(parent)==KErrNone)
1.282 + {
1.283 + DebugPrint(_L("Are you my mother, %S?"), &parent);
1.284 + if (iParent.Connect(parent)!=KErrNone)
1.285 + continue;
1.286 + if (iParent.Request(PMAreYouMyMother,TIpcArgs(&pid, &reply))!=KErrNone)
1.287 + {
1.288 + iParent.Close();
1.289 + continue;
1.290 + }
1.291 +
1.292 + // found parent
1.293 + DebugPrint(_L("Found parent process %S"), &parent);
1.294 +
1.295 + // Create any pipes that might be required
1.296 + TUint mask=reply().iPipeMask;
1.297 + CPipeChildDesc* pipes[3];
1.298 + TInt i=0;
1.299 + for (i=0; i<3; i++, mask>>=1)
1.300 + {
1.301 + pipes[i]=0;
1.302 + if (mask&1)
1.303 + {
1.304 + CPipeChildDesc* pipe=new(ELeave) CPipeChildDesc(i,iParent);
1.305 + pipes[i]=pipe;
1.306 + pipe->PushLC();
1.307 + }
1.308 + }
1.309 +
1.310 + // organise the necessary descriptors
1.311 + TPtr env=HBufC::NewLC(reply().iEnvironmentSize)->Des();
1.312 + TPtr cwd=HBufC::NewLC(reply().iWorkingDirectorySize)->Des();
1.313 +
1.314 + // get the data from parent
1.315 + TInt err=iParent.Request(PMHelloMum, TIpcArgs(&pid, &env, &cwd));
1.316 +
1.317 + DebugPrint(_L("Environment string: %S"), &env);
1.318 + DebugPrint(_L("Working directory: %S"), &cwd);
1.319 +
1.320 + if(err!=KErrNone)
1.321 + {
1.322 + DebugPrint(_L("I've become an orphan"));
1.323 + // release stuff
1.324 + iParent.Close();
1.325 + User::Leave(err);
1.326 + break;
1.327 + }
1.328 + // apply to our process
1.329 + iEnv.ConstructL(reply().iVarCount,env);
1.330 + err=iFs.SetSessionPath(cwd);
1.331 + User::LeaveIfError(err);
1.332 +
1.333 + // free up the temporary descriptors
1.334 + CleanupStack::PopAndDestroy(2);
1.335 +
1.336 + // Attach the pipes!
1.337 + for (i=0; i<3; i++)
1.338 + {
1.339 + iFids.Attach(i, pipes[i]);
1.340 + if (pipes[i]!=0)
1.341 + CleanupStack::Pop();
1.342 + }
1.343 + return;
1.344 + }
1.345 + DebugPrint(_L("Posix-%d is a top-level process"), pid());
1.346 + User::LeaveIfError(PosixFilesystem::SetDefaultDir(iFs));
1.347 + }
1.348 +
1.349 +int CPosixServer::POpen3(PosixParams* aParams, int& anErrno)
1.350 + {
1.351 + TInt err=KErrNoMemory;
1.352 + //coverity[alloc_fn]
1.353 + //coverity[assign]
1.354 + CPosixProcess* proc= new CPosixProcess(*this);
1.355 + if (proc!=0)
1.356 + {
1.357 + //coverity[leave_without_push]
1.358 + err=iFids.Reserve(aParams->pint);
1.359 + if (err==KErrNone)
1.360 + {
1.361 + TRAP(err,proc->POpen3L(aParams));
1.362 + }
1.363 + if (err==KErrNone)
1.364 + {
1.365 + DebugPrint(_L("POpen3 created process %d"), proc->iPid);
1.366 + proc->iNextProcess=iChildren;
1.367 + iChildren=proc;
1.368 + return (int)proc->iPid; // success
1.369 + }
1.370 + delete proc;
1.371 + iFids.Detach(aParams->pint);
1.372 + }
1.373 + return MapError(err, anErrno);
1.374 + }
1.375 +
1.376 +CPosixRequest* CPosixServer::Waiters()
1.377 + {
1.378 + CPosixRequest* waiters=iWaitAnyQueue;
1.379 + iWaitAnyQueue=0;
1.380 + return waiters;
1.381 + }
1.382 +
1.383 +// CPosixSession
1.384 +//
1.385 +// Each local thread gets one of these
1.386 +
1.387 +CPosixSession::CPosixSession(CPosixServer& aServer)
1.388 + : iActive(aServer)
1.389 + {
1.390 + CActiveScheduler::Add(&iActive);
1.391 + __DECLARE_NAME(_S("CPosixSession"));
1.392 + }
1.393 +
1.394 +void CPosixSession::ServiceL(const RMessage2& aMessage)
1.395 + {
1.396 + iActive.Service(aMessage);
1.397 + }
1.398 +
1.399 +// CPosixRequest
1.400 +//
1.401 +// An active object contained within the Session that handles the deferred completion
1.402 +// of asynchronous functions (e.g. read & write).
1.403 +
1.404 +CPosixRequest::CPosixRequest(CPosixServer& aServer)
1.405 + : CActive(EPriorityStandard), iServer(aServer), iPtr(0,0)
1.406 + {
1.407 +// iFile=0;
1.408 +// iNewF=0;
1.409 +// iNewFid=0;
1.410 + }
1.411 +
1.412 +void CPosixRequest::Service(const RMessage2& aMessage)
1.413 +//
1.414 +// The message protocol is to pass the errno pointer in p[0] and a pointer to a PosixParams
1.415 +// in p[1]. The result is written back into the PosixParams.retval field.
1.416 +//
1.417 + {
1.418 + if (aMessage.Function() == PMcancel)
1.419 + {
1.420 + Cancel(); // Cancel in the active scheduler
1.421 + if (iFile)
1.422 + EndAsynch(KErrCancel); // Complete the cancelled request & clean up
1.423 + aMessage.Complete(KErrNone);
1.424 + return;
1.425 + }
1.426 +
1.427 + if (iFile!=0)
1.428 + {
1.429 + aMessage.Complete(KErrInUse);
1.430 + return;
1.431 + }
1.432 + int& anErrno=*REINTERPRET_CAST(int*,CONST_CAST(TAny*,aMessage.Ptr0()));
1.433 + PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,aMessage.Ptr1()));
1.434 + switch (aMessage.Function())
1.435 + {
1.436 +
1.437 + // Asynchronous functions need queuing, active objects etc.
1.438 +
1.439 + case PMread:
1.440 + case PMwrite:
1.441 + case PMsendto:
1.442 + case PMrecvfrom:
1.443 + iPtr.Set((TText8*)params->ptr[0], params->len[0], params->len[0]);
1.444 + // and fall through...
1.445 + case PMfsync:
1.446 + case PMconnect:
1.447 + case PMshutdown:
1.448 + {
1.449 + TInt err=Fids().Asynch(params->fid,iFile);
1.450 + if (!err)
1.451 + {
1.452 + QueueAsynch(aMessage); // start operation or queue if busy
1.453 + return; // deferred completion through RunL
1.454 + }
1.455 + params->ret=MapError(err,anErrno);
1.456 + }
1.457 + break;
1.458 +
1.459 + case PMaccept:
1.460 + {
1.461 + TInt err=Fids().Asynch(params->fid,iFile);
1.462 + if (!err)
1.463 + {
1.464 + iNewF=0;
1.465 + iNewFid=Fids().Reserve(); // reserve a fid for the accepted socket
1.466 + err=iNewFid;
1.467 + if (iNewFid>=0)
1.468 + {
1.469 + QueueAsynch(aMessage); // start operation or queue if busy
1.470 + return; // deferred completion through RunL
1.471 + }
1.472 + }
1.473 + params->ret=MapError(err,anErrno);
1.474 + }
1.475 + break;
1.476 +
1.477 + case PMioctl:
1.478 + case PMioctlN:
1.479 + {
1.480 + TInt err=Fids().Asynch(params->fid,iFile);
1.481 + if (!err)
1.482 + {
1.483 + QueueAsynch(aMessage); // start operation or queue if busy
1.484 + return; // deferred completion through RunL
1.485 + }
1.486 +
1.487 + aMessage.Complete(err); // Different calling convention
1.488 + return;
1.489 + }
1.490 +
1.491 + // complicated synchronous functions which might do their own completion
1.492 +
1.493 + case PMwaitpid:
1.494 + {
1.495 + // check for invalid options or if an invalid pid is specified. currently there is no
1.496 + // support for process group id's so a pid less than -1 or equal to 0 is invalid
1.497 + if((params->pint[1] & ~(WNOHANG|WUNTRACED))|| (params->pint[0] < -1) || (params->pint[0] ==0))
1.498 + {
1.499 + anErrno=EINVAL;
1.500 + params->ret=-1;
1.501 + break;
1.502 + }
1.503 + if (params->pint[0]==-1 && params->pint[1]==0) /* wait for any child */
1.504 + {
1.505 + iMessage=aMessage;
1.506 + iServer.WaitForAnyChild(this);
1.507 + return; // wait for the next child to die
1.508 + }
1.509 + CPosixProcess* child=iServer.Child(params->pint[0]);
1.510 + if (child!=0)
1.511 + {
1.512 + if (child->IsAlive())
1.513 + {
1.514 + if (params->pint[1]&1) /* WNOHANG */
1.515 + {
1.516 + params->ret=0;
1.517 + break;
1.518 + }
1.519 + iMessage=aMessage;
1.520 + child->Queue(this);
1.521 + return; // wait for the child to die
1.522 + }
1.523 + params->pint[0]=child->iExitReason;
1.524 + params->ret=child->iPid;
1.525 + iServer.Release(child);
1.526 + }
1.527 + else
1.528 + {
1.529 + anErrno=ECHILD;
1.530 + params->ret=-1;
1.531 + }
1.532 + }
1.533 + break;
1.534 +
1.535 + // simple synchronous functions
1.536 +
1.537 + case PMdup:
1.538 + params->ret=Fids().dup(params->fid,anErrno);
1.539 + break;
1.540 + case PMdup2:
1.541 + params->ret=Fids().dup2(params->fid,params->pint[0],anErrno);
1.542 + break;
1.543 + case PMopen:
1.544 + {
1.545 + const wchar_t* name = params->cwptr[0];
1.546 + if ((L'C' == name[0]) && (L'O' == name[1]) && (L'M' == name[2]) && (L':' == name[4]) && ((name[3] >= L'1') && (name[3] <= L'9')) ||
1.547 + (L'I' == name[0]) && (L'R' == name[1]) && (L'C' == name[2]) && (L'O' == name[3]) && (L'M' == name[4]) && (L':' == name[6]) && ((name[5] >= L'1') && (name[5] <= L'9')))
1.548 + params->ret=Fids().open(params->cwptr[0],params->pint[0],params->pint[1],anErrno,Cs());
1.549 + else
1.550 + params->ret=Fids().open(params->cwptr[0],params->pint[0],params->pint[1],anErrno,Fs());
1.551 +
1.552 + }
1.553 + break;
1.554 + case PMclose:
1.555 + params->ret=Fids().userclose(params->fid,anErrno);
1.556 + break;
1.557 + case PMlseek:
1.558 + params->ret=Fids().lseek(params->fid,params->pint[0],params->pint[1],anErrno);
1.559 + break;
1.560 + case PMfstat:
1.561 + params->ret=Fids().fstat(params->fid,(struct stat*)params->ptr[0],anErrno);
1.562 + break;
1.563 + case PMgetcwd:
1.564 +// params->ret=(int)PosixFilesystem::getcwd(Fs(),params->ptr[0],params->len[0],anErrno);
1.565 + params->ret=(int)PosixFilesystem::getcwd(Fs(),params->wptr[0],params->len[0],anErrno);
1.566 + break;
1.567 + case PMchdir:
1.568 + params->ret=PosixFilesystem::chdir(Fs(),params->cwptr[0],anErrno);
1.569 + break;
1.570 + case PMmkdir:
1.571 +// params->ret=PosixFilesystem::mkdir(Fs(),params->cptr[0],params->pint[0],anErrno);
1.572 + params->ret=PosixFilesystem::mkdir(Fs(),params->cwptr[0],params->pint[0],anErrno);
1.573 + break;
1.574 + case PMrmdir:
1.575 + params->ret=PosixFilesystem::rmdir(Fs(),params->cwptr[0],anErrno);
1.576 + break;
1.577 + case PMchmod:
1.578 + params->ret=PosixFilesystem::chmod(Fs(),params->cwptr[0],params->pint[0],anErrno);
1.579 + break;
1.580 + case PMunlink:
1.581 + params->ret=PosixFilesystem::unlink(Fs(),params->cwptr[0],anErrno);
1.582 + break;
1.583 + case PMstat:
1.584 + params->ret=PosixFilesystem::stat(Fs(),params->cwptr[0],(struct stat*)params->ptr[0],anErrno);
1.585 + break;
1.586 + case PMrename:
1.587 + params->ret=PosixFilesystem::rename(Fs(), params->cwptr[0],params->cwptr[1],anErrno);
1.588 + break;
1.589 + case PMResolvePath:
1.590 +// params->ret=PosixFilesystem::ResolvePath(Fs(),
1.591 +// *(TParse*)params->ptr[0],params->cptr[0],(TDes*)params->ptr[1]);
1.592 + params->ret=PosixFilesystem::ResolvePath(Fs(),
1.593 + *(TParse*)params->ptr[0],params->cwptr[0],(TDes*)params->ptr[1]);
1.594 + break;
1.595 + case PMsocket:
1.596 + params->ret=Fids().socket(params->pint[0],params->pint[1],params->pint[2],anErrno,Ss());
1.597 + break;
1.598 + case PMbind:
1.599 + params->ret=Fids().bind(params->fid,params->addr,anErrno);
1.600 + break;
1.601 + case PMlisten:
1.602 + params->ret=Fids().listen(params->fid,params->pint[0],anErrno);
1.603 + break;
1.604 + case PMsockname:
1.605 + params->ret=Fids().sockname(params->fid,params->addr,params->pint[0],anErrno);
1.606 + break;
1.607 + case PMgetsockopt:
1.608 + params->ret=Fids().getsockopt(params->fid,params->pint[0],params->pint[1],
1.609 + params->ptr[0],params->lenp[0],anErrno);
1.610 + break;
1.611 + case PMsetsockopt:
1.612 + params->ret=Fids().setsockopt(params->fid,params->pint[0],params->pint[1],
1.613 + params->ptr[0],params->len[0],anErrno);
1.614 + break;
1.615 + case PMgetenv:
1.616 + params->ret=(int)Env().getenv(params->cwptr[0]);
1.617 + break;
1.618 + case PMunsetenv:
1.619 + Env().unsetenv(params->cwptr[0]); // no return value
1.620 + break;
1.621 + case PMsetenv:
1.622 + params->ret=Env().setenv(params->cwptr[0],params->cwptr[1],params->pint[0],anErrno);
1.623 + break;
1.624 + case PMioctlcomplete:
1.625 + params->ret=Fids().ioctlcomplete(params->fid,params->pint[0],params->ptr[0],*(REINTERPRET_CAST(TRequestStatus*, params->ptr[1])), anErrno);
1.626 + break;
1.627 + case PMTerminateProcess:
1.628 + {
1.629 + int status = params->fid;
1.630 + RProcess().Kill(status);
1.631 + }
1.632 + break;
1.633 + case PMpopen3:
1.634 + params->ret=iServer.POpen3(params,anErrno);
1.635 + break;
1.636 + default:
1.637 + aMessage.Complete(KErrNotSupported);
1.638 + return;
1.639 + }
1.640 + // deal with completion of a synchronous request
1.641 + aMessage.Complete(KErrNone);
1.642 + }
1.643 +
1.644 +// Asynchronous requests
1.645 +//
1.646 +// 1. QueueAsynch() to get into the appropriate queue in the FileDesc
1.647 +// 2. FileDesc calls StartAsynch() when it's our turn
1.648 +// 3. StartAsynch() makes the relevant IO call and does SetActive()
1.649 +// 4a. RunL() handles the completion of the IO call and calls EndAsynch()
1.650 +// 4b. DoCancel() handles cancellation of the IO call, but doesn't call EndAsynch()
1.651 +// 5. EndAsynch() removes us from the FileDesc queue and completes iMessage
1.652 +//
1.653 +
1.654 +void CPosixRequest::QueueAsynch(const RMessage2& aMessage)
1.655 +//
1.656 +// Add this to the appropriate queue in the associated file
1.657 +//
1.658 + {
1.659 + iMessage=aMessage; // Suggested by AndrewT to avoid code duplication
1.660 + iQueue=CFileDescBase::IOwriteQ;
1.661 + switch (aMessage.Function())
1.662 + {
1.663 + case PMread:
1.664 + case PMrecvfrom:
1.665 + iQueue=CFileDescBase::IOreadQ;
1.666 + break;
1.667 + case PMioctl:
1.668 + iQueue=CFileDescBase::IOioctlQ;
1.669 + break;
1.670 + case PMioctlN:
1.671 + iQueue=CFileDescBase::IOioctlNQ;
1.672 + break;
1.673 + default:
1.674 + // everything else uses the IOwriteQ, including Accept and Connect
1.675 + break;
1.676 + }
1.677 +
1.678 + __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
1.679 + iFile->AddLast(*this,iQueue);
1.680 + }
1.681 +
1.682 +void CPosixRequest::StartAsynch()
1.683 +//
1.684 +// The request has reached the front of the queue and can now be actioned
1.685 +//
1.686 + {
1.687 + PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1()));
1.688 + switch (iMessage.Function())
1.689 + {
1.690 + case PMread:
1.691 + {
1.692 +
1.693 + //if we need to have a timer for this operation to cancel it later
1.694 + if (iFile->TimedRead())
1.695 + {
1.696 + iFile->ReadIsTimed = ETrue;
1.697 + TRAPD(tRes, {iFile->TimedMessage = CSerialTimer::NewL(iFile);});
1.698 + if (tRes != KErrNone)
1.699 + {
1.700 + //we have a problem here
1.701 + //basically, fake the async request completing with the returned error
1.702 + iStatus = KRequestPending;
1.703 + SetActive();
1.704 + TRequestStatus * ps = &iStatus;
1.705 + User::RequestComplete(ps, tRes);
1.706 + return;
1.707 + }
1.708 +
1.709 + iFile->TimedMessage->IssueRequest();
1.710 + }
1.711 + else
1.712 + iFile->ReadIsTimed = EFalse;
1.713 +
1.714 + iFile->ReadWasCancelled = EFalse;
1.715 +
1.716 + iFile->Read(iPtr,iStatus);
1.717 +
1.718 + }
1.719 + break;
1.720 + case PMrecvfrom:
1.721 + iFile->RecvFrom(iPtr,params->addr,params->pint[0],iStatus);
1.722 + break;
1.723 + case PMwrite:
1.724 + iFile->Write(iPtr,iStatus);
1.725 + break;
1.726 + case PMsendto:
1.727 + iFile->SendTo(iPtr,params->addr,params->pint[0],iStatus);
1.728 + break;
1.729 + case PMfsync:
1.730 + iFile->Sync(iStatus);
1.731 + break;
1.732 + case PMconnect:
1.733 + iFile->Connect(params->addr,iStatus);
1.734 + break;
1.735 + case PMshutdown:
1.736 + iFile->Shutdown(params->pint[0],iStatus);
1.737 + break;
1.738 + case PMaccept:
1.739 + iFile->Accept(iNewF,iStatus,Ss());
1.740 + break;
1.741 + case PMioctl:
1.742 + iFile->Ioctl(params->pint[0],params->ptr[0],iStatus);
1.743 + break;
1.744 + case PMioctlN:
1.745 + iFile->Ioctl(params->pint[0],params->ptr[0],iStatus);
1.746 + break;
1.747 + default:
1.748 + EndAsynch(KErrGeneral);
1.749 + return;
1.750 + }
1.751 + SetActive(); // for asynchronous completion via RunL
1.752 + return;
1.753 + }
1.754 +
1.755 +void CPosixRequest::RunL()
1.756 +//
1.757 +// The pending IO has completed, so handle the result
1.758 +//
1.759 + {
1.760 + __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
1.761 + TInt completion=KErrNone;
1.762 + int& anErrno=*REINTERPRET_CAST(int*,CONST_CAST(TAny*,iMessage.Ptr0()));
1.763 + PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1()));
1.764 + switch (iMessage.Function())
1.765 + {
1.766 + case PMread:
1.767 + {
1.768 + if (iFile->ReadIsTimed)
1.769 + {
1.770 + //need to stop the timer
1.771 + delete iFile->TimedMessage;
1.772 + iFile->TimedMessage = NULL;
1.773 + iFile->ReadIsTimed = EFalse;
1.774 + }
1.775 +
1.776 + TInt err=iFile->ReadCompletion(iPtr, iStatus.Int());
1.777 + if (err==0)
1.778 + {
1.779 + params->ret=iPtr.Length();
1.780 + break;
1.781 + }
1.782 + //if the read was cancelled and we are to patch it due to me cancelling it
1.783 +
1.784 + if (iFile->ReadWasCancelled)
1.785 + {
1.786 + err = ETIMEDOUT;
1.787 + iFile->ReadWasCancelled = EFalse;
1.788 + }
1.789 +
1.790 + params->ret=MapError(err,anErrno);
1.791 + }
1.792 + break;
1.793 + case PMwrite:
1.794 + {
1.795 + TInt err=iFile->WriteCompletion(iPtr, iStatus.Int());
1.796 + if (err==0)
1.797 + {
1.798 + params->ret=iPtr.Length();
1.799 + break;
1.800 + }
1.801 + params->ret=MapError(err,anErrno);
1.802 + }
1.803 + break;
1.804 + case PMconnect:
1.805 + case PMshutdown:
1.806 + case PMfsync:
1.807 + params->ret=MapError(iStatus.Int(),anErrno);
1.808 + break;
1.809 + case PMsendto:
1.810 + {
1.811 + TInt err=iFile->SendToCompletion(iPtr, iStatus.Int());
1.812 + if (err==0)
1.813 + {
1.814 + params->ret=iPtr.Length();
1.815 + break;
1.816 + }
1.817 + params->ret=MapError(err,anErrno);
1.818 + }
1.819 + break;
1.820 + case PMrecvfrom:
1.821 + {
1.822 + TInt err=iFile->RecvFromCompletion(params->ret, iStatus.Int());
1.823 + if (err==0)
1.824 + {
1.825 + params->ret=iPtr.Length();
1.826 + break;
1.827 + }
1.828 + params->ret=MapError(err,anErrno);
1.829 + }
1.830 + break;
1.831 + case PMaccept:
1.832 + {
1.833 + TInt err=iStatus.Int();
1.834 + if (err)
1.835 + Fids().Attach(iNewFid,0); // cancel the reservation
1.836 + else
1.837 + {
1.838 + err=Fids().Attach(iNewFid,iNewF);
1.839 + if (!err)
1.840 + {
1.841 + params->ret=iNewFid;
1.842 + break; // so that we return the new fid
1.843 + }
1.844 + delete iNewF;
1.845 + iNewF=0;
1.846 + }
1.847 + params->ret=MapError(err,anErrno);
1.848 + }
1.849 + break;
1.850 +
1.851 + case PMioctlN:
1.852 + {
1.853 + completion=iStatus.Int(); // caller picks up completion explicitly
1.854 + }
1.855 + break;
1.856 +
1.857 + case PMioctl:
1.858 + {
1.859 + completion=iStatus.Int(); // caller picks up completion explicitly
1.860 +// TInt err=iFile->IoctlCompletion(params->pint[0], ¶ms->ret, iStatus.Int());
1.861 +// params->ret=MapError(err,anErrno);
1.862 + }
1.863 + break;
1.864 +
1.865 + default:
1.866 + completion=KErrGeneral; // arrgh - I imagine that it's going to die if we get here...
1.867 + break;
1.868 + }
1.869 + EndAsynch(completion);
1.870 + }
1.871 +
1.872 +void CPosixRequest::EndAsynch(TInt aResult)
1.873 +//
1.874 +// finish an asynchronous operation and complete iMessage
1.875 +//
1.876 + {
1.877 + __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
1.878 + iFile->Remove(*this,iQueue);
1.879 + iFile->Close(); // balances the Dup() in CFileTable::Asynch(), may delete object!
1.880 + iFile=0;
1.881 + iMessage.Complete(aResult);
1.882 + }
1.883 +
1.884 +
1.885 +void CPosixRequest::DoCancel()
1.886 +//
1.887 +// The pending IO has been cancelled, so cancel the outstanding request
1.888 +// Needs to deal with all of the cases in RunL, but doesn't call EndAsynch().
1.889 +// This is called from CActive::Cancel() only when the object is active, but
1.890 +// EndAsynch() needs to be called when the object is active or when it's just
1.891 +// waiting in a FileDesc queue.
1.892 +//
1.893 + {
1.894 + __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
1.895 + switch (iMessage.Function())
1.896 + {
1.897 + case PMread:
1.898 + iFile->ReadCancel();
1.899 + break;
1.900 + case PMrecvfrom:
1.901 + iFile->RecvFromCancel();
1.902 + break;
1.903 + case PMwrite:
1.904 + iFile->WriteCancel();
1.905 + break;
1.906 + case PMsendto:
1.907 + iFile->SendToCancel();
1.908 + break;
1.909 + case PMfsync:
1.910 + iFile->SyncCancel();
1.911 + break;
1.912 + case PMconnect:
1.913 + iFile->ConnectCancel();
1.914 + break;
1.915 + case PMshutdown:
1.916 + iFile->ShutdownCancel();
1.917 + break;
1.918 + case PMaccept:
1.919 + iFile->AcceptCancel();
1.920 + Fids().Attach(iNewFid,0); // cancel the reservation
1.921 + break;
1.922 + case PMioctl:
1.923 + iFile->IoctlCancel();
1.924 + break;
1.925 + default:
1.926 + // it would be wrong to get here, so leave well alone
1.927 + break;
1.928 + }
1.929 + }
1.930 +
1.931 +CPosixRequest::~CPosixRequest()
1.932 + {
1.933 + Cancel();
1.934 + if (iFile)
1.935 + EndAsynch(KErrCancel);
1.936 + }
1.937 +
1.938 +// Handling waiting on other processes
1.939 +//
1.940 +void CPosixRequest::EnList(CPosixRequest*& aHead)
1.941 + {
1.942 + iNext=aHead;
1.943 + aHead=this;
1.944 + }
1.945 +
1.946 +void CPosixRequest::WaitCompleted(TInt aPid, TInt aReason)
1.947 + {
1.948 + PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1()));
1.949 +
1.950 + __ASSERT_DEBUG(iMessage.Function()==PMwaitpid, CPosixServer::ServerPanic(EPosix_BadWaitCompletion));
1.951 + params->pint[0]=aReason;
1.952 + params->ret=aPid;
1.953 + iMessage.Complete(KErrNone);
1.954 +
1.955 + CPosixRequest* next=iNext;
1.956 + iNext=0;
1.957 + if (next)
1.958 + next->WaitCompleted(aPid, aReason);
1.959 + }
1.960 +
1.961 +static void ClosePipes(CPipeDesc* aPipes[3])
1.962 + {
1.963 + TInt i=0;
1.964 + for (i=0; i<3; i++)
1.965 + {
1.966 + CPipeDesc* pipe=aPipes[i];
1.967 + aPipes[i]=0;
1.968 + if (pipe)
1.969 + pipe->ClientClose();
1.970 + }
1.971 + }
1.972 +
1.973 +TInt CPosixIPCSession::AreYouMyMotherL(const RMessage2& aMessage)
1.974 + {
1.975 + TPosixIPCPid pid;
1.976 + TPosixIPCReply reply;
1.977 + aMessage.ReadL(0,pid);
1.978 + DebugPrint(_L("Process %d asks am I its mother?"), pid());
1.979 + CPosixServer* pServ = const_cast<CPosixServer*>(static_cast<const CPosixServer*>(Server()));
1.980 + CPosixProcess* child=pServ->Child(pid());
1.981 + if (!child)
1.982 + return KErrNotFound; // you are no child of mine
1.983 + DebugPrint(_L("Found child process"));
1.984 + child->Sizes(reply);
1.985 + aMessage.Write(1,reply);
1.986 + return KErrNone;
1.987 + }
1.988 +
1.989 +TInt CPosixIPCSession::HelloMumL(const RMessage2& aMessage)
1.990 + {
1.991 + TPosixIPCPid pid;
1.992 + aMessage.ReadL(0,pid);
1.993 +
1.994 + DebugPrint(_L("Process %d is requesting its inheritance"),pid());
1.995 +
1.996 + CPosixServer* pServ = const_cast<CPosixServer*>(static_cast<const CPosixServer*>(Server()));
1.997 + CPosixProcess* child=pServ->Child(pid());
1.998 + if (!child)
1.999 + return KErrNotFound; // you are no child of mine
1.1000 +
1.1001 + // CopyToChildL will pull out the second and third element out directly so as
1.1002 + // to copy data to it. This is why data is passed in this way.
1.1003 + child->CopyToChildL(aMessage);
1.1004 + return KErrNone;
1.1005 + }
1.1006 +
1.1007 +void CPosixIPCSession::PipeRead(const RMessage2& aMessage)
1.1008 + {
1.1009 + TInt index=aMessage.Int0();
1.1010 + if (iPipes[index]==0)
1.1011 + aMessage.Complete(KErrEof); // go away, incorrect thing!
1.1012 + else
1.1013 + iPipes[index]->ClientRead(aMessage);
1.1014 + }
1.1015 +
1.1016 +void CPosixIPCSession::PipeWrite(const RMessage2& aMessage)
1.1017 + {
1.1018 + TInt index=aMessage.Int0();
1.1019 + if (iPipes[index]==0)
1.1020 + aMessage.Complete(KErrEof); // go away, incorrect thing!
1.1021 + else
1.1022 + iPipes[index]->ClientWrite(aMessage);
1.1023 + }
1.1024 +
1.1025 +void CPosixIPCSession::PipeIoctl(const RMessage2& aMessage)
1.1026 + {
1.1027 + TInt index=aMessage.Int0();
1.1028 + if (iPipes[index]==0)
1.1029 + aMessage.Complete(KErrEof); // go away, incorrect thing!
1.1030 + else
1.1031 + iPipes[index]->ClientIoctl(aMessage);
1.1032 + }
1.1033 +
1.1034 +void CPosixIPCSession::PipeClose(const RMessage2& aMessage)
1.1035 + {
1.1036 + TInt index=aMessage.Int0();
1.1037 + if (iPipes[index]!=0)
1.1038 + iPipes[index]->ClientClose();
1.1039 + aMessage.Complete(KErrNone);
1.1040 + }
1.1041 +
1.1042 +void CPosixIPCSession::PipeCancel(const RMessage2& aMessage)
1.1043 + {
1.1044 + TInt index=aMessage.Int0();
1.1045 + if (iPipes[index]!=0)
1.1046 + iPipes[index]->ClientCancel(aMessage);
1.1047 + aMessage.Complete(KErrNone);
1.1048 + }
1.1049 +
1.1050 +void CPosixIPCSession::ServiceL(const RMessage2& aMessage)
1.1051 +//
1.1052 +// Handle the communication between CPosixServers
1.1053 +//
1.1054 + {
1.1055 + TInt response=KErrNone;
1.1056 + switch (aMessage.Function())
1.1057 + {
1.1058 + case PMAreYouMyMother:
1.1059 + response=AreYouMyMotherL(aMessage);
1.1060 + break;
1.1061 + case PMHelloMum:
1.1062 + response=HelloMumL(aMessage);
1.1063 + break;
1.1064 +
1.1065 + case PMPipeRead:
1.1066 + PipeRead(aMessage);
1.1067 + return; // handles completion
1.1068 + case PMPipeWrite:
1.1069 + PipeWrite(aMessage);
1.1070 + return; // handles completion
1.1071 + case PMPipeIoctl:
1.1072 + PipeIoctl(aMessage);
1.1073 + return; // handles completion
1.1074 + case PMPipeClose:
1.1075 + PipeClose(aMessage);
1.1076 + return; // handles completion
1.1077 +
1.1078 + case PMPipeCancel:
1.1079 + PipeCancel(aMessage);
1.1080 + return;
1.1081 +
1.1082 + default:
1.1083 + response=KErrNotSupported;
1.1084 + break;
1.1085 + }
1.1086 + aMessage.Complete(response);
1.1087 + }
1.1088 +
1.1089 +void CPosixIPCSession::SetPipes(CPipeDesc* aPipes[3])
1.1090 +//
1.1091 +// Accept ownership of the pipes between child and parent
1.1092 +//
1.1093 + {
1.1094 + TInt i=0;
1.1095 + for (i=0; i<3; i++)
1.1096 + {
1.1097 + CPipeDesc* pipe=aPipes[i];
1.1098 + iPipes[i]=pipe;
1.1099 + aPipes[i]=0;
1.1100 + if (pipe)
1.1101 + pipe->SetClientSide(iPipes[i]);
1.1102 + }
1.1103 + }
1.1104 +
1.1105 +CPosixIPCSession::~CPosixIPCSession()
1.1106 + {
1.1107 + ClosePipes(iPipes);
1.1108 + }
1.1109 +
1.1110 +// Active Object representing a POSIX process
1.1111 +
1.1112 +CPosixProcess::CPosixProcess(CPosixServer& aServer)
1.1113 + : CActive(EPriorityStandard), iServer(aServer)
1.1114 + {
1.1115 + // iPid=0;
1.1116 + // iWaiters=0;
1.1117 + // iNextProcess=0;
1.1118 + // iEnvironment=0;
1.1119 + // iWorkingDirectory=0;
1.1120 + }
1.1121 +
1.1122 +CPosixProcess* CPosixProcess::Find(CPosixProcess* proc, TInt pid)
1.1123 + {
1.1124 + while (proc!=0)
1.1125 + {
1.1126 + if (proc->iPid==pid)
1.1127 + return proc;
1.1128 + if (pid==-1 && !proc->IsAlive()) // for waitpid(WAIT_ANY,...)
1.1129 + return proc;
1.1130 + proc=proc->iNextProcess;
1.1131 + }
1.1132 + return 0;
1.1133 + }
1.1134 +
1.1135 +void CPosixProcess::Release(CPosixProcess** aHead, CPosixProcess* aChild)
1.1136 + {
1.1137 + while (*aHead!=0)
1.1138 + {
1.1139 + if ((*aHead)==aChild)
1.1140 + {
1.1141 + (*aHead)=aChild->iNextProcess;
1.1142 + aChild->iNextProcess=0;
1.1143 + delete aChild;
1.1144 + return;
1.1145 + }
1.1146 + aHead=&(*aHead)->iNextProcess;
1.1147 + }
1.1148 + }
1.1149 +
1.1150 +
1.1151 +
1.1152 +void CPosixProcess::POpen3L(PosixParams* aParams)
1.1153 + {
1.1154 + TInt i=0;
1.1155 + CPipeDesc* pipes[3];
1.1156 + for (i=0; i<3; i++)
1.1157 + {
1.1158 + if (aParams->pint[i]<0)
1.1159 + pipes[i]=0;
1.1160 + else
1.1161 + {
1.1162 + pipes[i]=new(ELeave) CPipeDesc(i);
1.1163 + pipes[i]->PushLC();
1.1164 + }
1.1165 + }
1.1166 + // truncate fileName to get the name of the executable
1.1167 + TPtrC16 fileName((TText16*)aParams->wptr[0]);
1.1168 + TPtrC16 commandLine((TText16*)aParams->cwptr[0]);
1.1169 +
1.1170 + HBufC16* env=Env().ExternalizeLC(iVarCount,aParams->eptr[0]);
1.1171 + TFullName workingDirectory;
1.1172 + TInt err=Fs().SessionPath(workingDirectory);
1.1173 + User::LeaveIfError(err);
1.1174 + HBufC* cwd=workingDirectory.AllocLC();
1.1175 +
1.1176 + // Use real processes
1.1177 + err=iChild.Create(fileName,commandLine,EOwnerThread);
1.1178 + User::LeaveIfError(err);
1.1179 + TProcessId id=iChild.Id();
1.1180 + iPid=*REINTERPRET_CAST(int*,&id);
1.1181 + iChild.Logon(iStatus);
1.1182 + CActiveScheduler::Add(this);
1.1183 + SetActive();
1.1184 + iChild.Resume();
1.1185 + iEnvironment=env;
1.1186 + iWorkingDirectory=cwd;
1.1187 + CleanupStack::Pop(2);
1.1188 + // Sort out the pipes
1.1189 + for (i=0; i<3; i++)
1.1190 + {
1.1191 + CPipeDesc* pipe=pipes[i];
1.1192 + iPipes[i]=pipe;
1.1193 + if (pipe!=0)
1.1194 + {
1.1195 + CleanupStack::Pop();
1.1196 + Fids().Attach(aParams->pint[i],pipe);
1.1197 + pipe->SetClientSide(iPipes[i]); // for FinalClose
1.1198 + }
1.1199 + }
1.1200 + }
1.1201 +
1.1202 +void CPosixProcess::Sizes(TPosixIPCReply& aReply) const
1.1203 + {
1.1204 + aReply().iWorkingDirectorySize=iWorkingDirectory->Length();
1.1205 + aReply().iEnvironmentSize=iEnvironment->Length();
1.1206 + aReply().iVarCount=iVarCount;
1.1207 + TUint mask=0;
1.1208 + TInt i=0;
1.1209 + for (i=0; i<3; i++)
1.1210 + {
1.1211 + if (iPipes[i]!=0)
1.1212 + mask |= 1<<i;
1.1213 + }
1.1214 + aReply().iPipeMask=mask;
1.1215 + }
1.1216 +
1.1217 +void CPosixProcess::CopyToChildL(const RMessage2& aMessage)
1.1218 + {
1.1219 + // copy iWorkingDirectory and iEnvironment to params
1.1220 + aMessage.WriteL(1, *iEnvironment);
1.1221 + aMessage.WriteL(2, *iWorkingDirectory);
1.1222 +
1.1223 + // don't need this data anymore
1.1224 + delete iWorkingDirectory;
1.1225 + iWorkingDirectory=0;
1.1226 + delete iEnvironment;
1.1227 + iEnvironment=0;
1.1228 +
1.1229 + (static_cast<CPosixIPCSession*>(aMessage.Session()))->SetPipes(iPipes);
1.1230 + }
1.1231 +
1.1232 +void CPosixProcess::RunL()
1.1233 +//
1.1234 +// Detects termination of the child process
1.1235 +//
1.1236 + {
1.1237 + iExitReason=iStatus.Int();
1.1238 + iChild.Close();
1.1239 + DebugPrint(_L("Process %d appears to have terminated with status %d"), iPid, iExitReason);
1.1240 + ClosePipes(iPipes);
1.1241 +
1.1242 + TInt reported=0;
1.1243 + CPosixRequest* waiters=iWaiters;
1.1244 + iWaiters=0;
1.1245 + if (waiters)
1.1246 + {
1.1247 + waiters->WaitCompleted(iPid,iExitReason);
1.1248 + reported=1;
1.1249 + }
1.1250 +
1.1251 + // And any of the outstanding "wait for any" requests held in the server
1.1252 + waiters=iServer.Waiters();
1.1253 + if (waiters)
1.1254 + {
1.1255 + waiters->WaitCompleted(iPid,iExitReason);
1.1256 + reported=1;
1.1257 + }
1.1258 + if (reported)
1.1259 + iServer.Release(this);
1.1260 + }
1.1261 +
1.1262 +void CPosixProcess::DoCancel()
1.1263 + {
1.1264 + // panic if iNextProcess or iWaiters is non-zero?
1.1265 + iChild.LogonCancel(iStatus);
1.1266 + iChild.Close();
1.1267 + delete iEnvironment;
1.1268 + iEnvironment=0;
1.1269 + delete iWorkingDirectory;
1.1270 + iWorkingDirectory=0;
1.1271 + ClosePipes(iPipes);
1.1272 + }
1.1273 +
1.1274 +CPosixProcess::~CPosixProcess()
1.1275 + {
1.1276 + Cancel();
1.1277 + }
1.1278 +
1.1279 +// System Interface for process form of STDLIB
1.1280 +
1.1281 +CProcessSystemInterface::CProcessSystemInterface()
1.1282 + {}
1.1283 +
1.1284 +CProcessSystemInterface::~CProcessSystemInterface()
1.1285 + {
1.1286 + iSession.Close();
1.1287 + }
1.1288 +
1.1289 +MSystemInterface& CProcessSystemInterface::Clone()
1.1290 + {
1.1291 + return *(new CProcessSystemInterface);
1.1292 + }
1.1293 +
1.1294 +void CProcessSystemInterface::Release()
1.1295 + {
1.1296 + delete this;
1.1297 + }
1.1298 +
1.1299 +TInt CProcessSystemInterface::Connect()
1.1300 + {
1.1301 + return iSession.Connect(); // is this the right thread though?
1.1302 + }
1.1303 +
1.1304 +// CProcessSystemInterface functions
1.1305 +//
1.1306 +// These functions just package up their arguments for transmission to the
1.1307 +// CPosixServer which will unpack them and call the corresponding function in
1.1308 +// its associated CLocalSystemInterface, except for the asynchronous functions
1.1309 +// (currently read/write/fsync) which the server handles separately using an active
1.1310 +// object to defer the RMessage::Complete until the asynchronous operation has completed.
1.1311 +
1.1312 +static void doPanic(TInt aFunction, TInt aErr)
1.1313 + {
1.1314 + TBuf<100> detail;
1.1315 + _LIT(KProcessSystemInterfacePanic, "POSIXIF (%d)");
1.1316 + detail.Format(KProcessSystemInterfacePanic, aFunction);
1.1317 + User::Panic(detail,aErr);
1.1318 + }
1.1319 +
1.1320 +int CProcessSystemInterface::Request (TInt aFunction, int& anErrno)
1.1321 + {
1.1322 + TInt err=iSession.Request(aFunction,anErrno,iParams);
1.1323 + // KErrServerTerminated?
1.1324 + if (err!=KErrNone)
1.1325 + doPanic(aFunction,err); // moved out of line to reduce stack requirement
1.1326 + return iParams.ret;
1.1327 + }
1.1328 +
1.1329 +void CProcessSystemInterface::Request (TInt aFunction, int& anErrno, TRequestStatus& aStatus)
1.1330 + {
1.1331 + iSession.Request(aFunction,anErrno,iParams,aStatus);
1.1332 + }
1.1333 +
1.1334 +void CProcessSystemInterface::TerminateProcess (int status)
1.1335 + {
1.1336 + int anErrno;
1.1337 + iParams.fid=status;
1.1338 + Request(PMTerminateProcess,anErrno);
1.1339 + RProcess().Terminate(status); // just in case...
1.1340 + }
1.1341 +
1.1342 +int CProcessSystemInterface::dup (int fid, int& anErrno)
1.1343 + {
1.1344 + iParams.fid=fid;
1.1345 + return Request(PMdup,anErrno);
1.1346 + }
1.1347 +
1.1348 +int CProcessSystemInterface::dup2 (int fid, int fid2, int& anErrno)
1.1349 + {
1.1350 + iParams.fid=fid;
1.1351 + iParams.pint[0]=fid2;
1.1352 + return Request(PMdup2,anErrno);
1.1353 + }
1.1354 +
1.1355 +int CProcessSystemInterface::open (const wchar_t* name, int mode, int perms, int& anErrno)
1.1356 + {
1.1357 + iParams.cwptr[0]=name;
1.1358 + iParams.pint[0]=mode;
1.1359 + iParams.pint[1]=perms;
1.1360 + return Request(PMopen,anErrno);
1.1361 + }
1.1362 +
1.1363 +int CProcessSystemInterface::read (int fid, char* buf, unsigned long len, int& anErrno)
1.1364 + {
1.1365 + iParams.fid=fid;
1.1366 + iParams.ptr[0]=buf;
1.1367 + iParams.len[0]=len;
1.1368 + return Request(PMread,anErrno);
1.1369 + }
1.1370 +
1.1371 +int CProcessSystemInterface::write (int fid, const char* buf, unsigned long len, int& anErrno)
1.1372 + {
1.1373 + iParams.fid=fid;
1.1374 + iParams.ptr[0]=CONST_CAST(char*,buf);
1.1375 + iParams.len[0]=len;
1.1376 + return Request(PMwrite,anErrno);
1.1377 + }
1.1378 +
1.1379 +int CProcessSystemInterface::fsync (int fid, int& anErrno)
1.1380 + {
1.1381 + iParams.fid=fid;
1.1382 + return Request(PMfsync,anErrno);
1.1383 + }
1.1384 +
1.1385 +int CProcessSystemInterface::close (int fid, int& anErrno)
1.1386 + {
1.1387 + iParams.fid=fid;
1.1388 + return Request(PMclose,anErrno);
1.1389 + }
1.1390 +
1.1391 +int CProcessSystemInterface::lseek (int fid, int offset, int whence, int& anErrno)
1.1392 + {
1.1393 + iParams.fid=fid;
1.1394 + iParams.pint[0]=offset;
1.1395 + iParams.pint[1]=whence;
1.1396 + return Request(PMlseek,anErrno);
1.1397 + }
1.1398 +
1.1399 +int CProcessSystemInterface::fstat (int fid, struct stat *st, int& anErrno)
1.1400 + {
1.1401 + iParams.fid=fid;
1.1402 + iParams.ptr[0]=(char*)st;
1.1403 + return Request(PMfstat,anErrno);
1.1404 + }
1.1405 +
1.1406 +
1.1407 +wchar_t * CProcessSystemInterface::getcwd (wchar_t* buf, unsigned long len, int& anErrno)
1.1408 + {
1.1409 + iParams.wptr[0]=buf;
1.1410 +
1.1411 + iParams.len[0]=len;
1.1412 + return (wchar_t *)Request(PMgetcwd,anErrno);
1.1413 + }
1.1414 +
1.1415 +
1.1416 +int CProcessSystemInterface::chdir (const wchar_t* aPath, int& anErrno)
1.1417 + {
1.1418 + iParams.cwptr[0]=aPath;
1.1419 + return Request(PMchdir,anErrno);
1.1420 + }
1.1421 +
1.1422 +int CProcessSystemInterface::mkdir (const wchar_t* aPath, int perms, int& anErrno)
1.1423 + {
1.1424 + iParams.cwptr[0]=aPath;
1.1425 + iParams.pint[0]=perms;
1.1426 + return Request(PMmkdir,anErrno);
1.1427 + }
1.1428 +
1.1429 +int CProcessSystemInterface::rmdir (const wchar_t* aPath, int& anErrno)
1.1430 + {
1.1431 + iParams.cwptr[0]=aPath;
1.1432 + return Request(PMrmdir,anErrno);
1.1433 + }
1.1434 +
1.1435 +int CProcessSystemInterface::stat (const wchar_t* name, struct stat *st, int& anErrno)
1.1436 + {
1.1437 + iParams.cwptr[0]=name;
1.1438 + iParams.ptr[0]=(char*)st;
1.1439 + return Request(PMstat,anErrno);
1.1440 + }
1.1441 +
1.1442 +int CProcessSystemInterface::chmod (const wchar_t* name, int perms, int& anErrno)
1.1443 + {
1.1444 + iParams.cwptr[0]=name;
1.1445 + iParams.pint[0]=perms;
1.1446 + return Request(PMchmod,anErrno);
1.1447 + }
1.1448 +
1.1449 +int CProcessSystemInterface::unlink (const wchar_t* name, int& anErrno)
1.1450 + {
1.1451 + iParams.cwptr[0]=name;
1.1452 + return Request(PMunlink,anErrno);
1.1453 + }
1.1454 +
1.1455 +int CProcessSystemInterface::rename (const wchar_t* oldname, const wchar_t* newname, int& anErrno)
1.1456 + {
1.1457 + iParams.cwptr[0]=oldname;
1.1458 + iParams.cwptr[1]=newname;
1.1459 + return Request(PMrename,anErrno);
1.1460 + }
1.1461 +
1.1462 +TInt CProcessSystemInterface::ResolvePath (TParse& aResult, const wchar_t* path, TDes* aFilename)
1.1463 + {
1.1464 + TInt ignored;
1.1465 + iParams.ptr[0]=(char*)&aResult;
1.1466 + iParams.cwptr[0]=path;
1.1467 + iParams.ptr[1]=(char*)aFilename;
1.1468 + return Request(PMResolvePath,ignored);
1.1469 + }
1.1470 +
1.1471 +TInt CProcessSystemInterface::socket (int family, int style, int protocol, int& anErrno)
1.1472 + {
1.1473 + iParams.pint[0]=family;
1.1474 + iParams.pint[1]=style;
1.1475 + iParams.pint[2]=protocol;
1.1476 + return Request(PMsocket,anErrno);
1.1477 + }
1.1478 +
1.1479 +TInt CProcessSystemInterface::shutdown (int fid, int how, int& anErrno)
1.1480 + {
1.1481 + iParams.fid=fid;
1.1482 + iParams.pint[0]=how;
1.1483 + return Request(PMshutdown,anErrno);
1.1484 + }
1.1485 +
1.1486 +TInt CProcessSystemInterface::listen (int fid, int n, int& anErrno)
1.1487 + {
1.1488 + iParams.fid=fid;
1.1489 + iParams.pint[0]=n;
1.1490 + return Request(PMlisten,anErrno);
1.1491 + }
1.1492 +
1.1493 +TInt CProcessSystemInterface::accept (int fid, int& anErrno)
1.1494 + {
1.1495 + iParams.fid=fid;
1.1496 + return Request(PMaccept,anErrno);
1.1497 + }
1.1498 +
1.1499 +TInt CProcessSystemInterface::bind (int fid, struct sockaddr* addr, unsigned long size, int& anErrno)
1.1500 + {
1.1501 + iParams.fid=fid;
1.1502 + iParams.addr.Set(addr, size);
1.1503 + return Request(PMbind,anErrno);
1.1504 + }
1.1505 +
1.1506 +TInt CProcessSystemInterface::connect (int fid, struct sockaddr* addr, unsigned long size, int& anErrno)
1.1507 + {
1.1508 + iParams.fid=fid;
1.1509 + iParams.addr.Set(addr, size);
1.1510 + return Request(PMconnect,anErrno);
1.1511 + }
1.1512 +
1.1513 +TInt CProcessSystemInterface::recvfrom (int fid, char* buf, unsigned long len, int flags, struct sockaddr* from, unsigned long* fromsize, int& anErrno)
1.1514 + {
1.1515 + iParams.fid=fid;
1.1516 + iParams.ptr[0]=buf;
1.1517 + iParams.len[0]=len;
1.1518 + iParams.pint[0]=flags;
1.1519 + iParams.addr.Prepare(from);
1.1520 + TInt nbytes=Request(PMrecvfrom,anErrno);
1.1521 + if (nbytes>=0) // i.e. no error
1.1522 + iParams.addr.Get(from,fromsize);
1.1523 + return nbytes;
1.1524 + }
1.1525 +
1.1526 +TInt CProcessSystemInterface::sendto (int fid, const char* buf, unsigned long len, int flags, struct sockaddr* to, unsigned long tosize, int& anErrno)
1.1527 + {
1.1528 + iParams.fid=fid;
1.1529 + iParams.ptr[0]=CONST_CAST(char*,buf);
1.1530 + iParams.len[0]=len;
1.1531 + iParams.pint[0]=flags;
1.1532 + iParams.addr.Set(to,tosize);
1.1533 + return Request(PMsendto,anErrno);
1.1534 + }
1.1535 +
1.1536 +TInt CProcessSystemInterface::getsockopt (int fid, int level, int opt, void* buf, unsigned long* len, int& anErrno)
1.1537 + {
1.1538 + iParams.fid=fid;
1.1539 + iParams.pint[0]=level;
1.1540 + iParams.pint[1]=opt;
1.1541 + iParams.ptr[0]=(char*)buf;
1.1542 + iParams.lenp[0]=len;
1.1543 + return Request(PMgetsockopt,anErrno);
1.1544 + }
1.1545 +
1.1546 +TInt CProcessSystemInterface::setsockopt (int fid, int level, int opt, void* buf, unsigned long len, int& anErrno)
1.1547 + {
1.1548 + iParams.fid=fid;
1.1549 + iParams.pint[0]=level;
1.1550 + iParams.pint[1]=opt;
1.1551 + iParams.ptr[0]=(char*)buf;
1.1552 + iParams.len[0]=len;
1.1553 + return Request(PMsetsockopt,anErrno);
1.1554 + }
1.1555 +
1.1556 +TInt CProcessSystemInterface::sockname (int fid, struct sockaddr* addr, unsigned long* size, int anEnd, int& anErrno)
1.1557 + {
1.1558 + iParams.fid=fid;
1.1559 + iParams.addr.Prepare(addr);
1.1560 + iParams.pint[0]=anEnd;
1.1561 + TInt err=Request(PMsockname,anErrno);
1.1562 + if (err==0)
1.1563 + iParams.addr.Get(addr,size);
1.1564 + return err;
1.1565 + }
1.1566 +
1.1567 +TInt CProcessSystemInterface::ioctl (int fid, int cmd, void* param, int& anErrno)
1.1568 + {
1.1569 + TRequestStatus ioctlStatus;
1.1570 + TInt err=ioctl(fid,cmd,param,ioctlStatus,anErrno);
1.1571 + if (err==KErrNone)
1.1572 + {
1.1573 + User::WaitForRequest(ioctlStatus);
1.1574 + err=ioctl_complete(fid,cmd,param,ioctlStatus,anErrno);
1.1575 + }
1.1576 + return err;
1.1577 + }
1.1578 +
1.1579 +wchar_t* CProcessSystemInterface::getenv (const wchar_t* name)
1.1580 + {
1.1581 + int dummy;
1.1582 + iParams.cwptr[0]=name;
1.1583 + return (wchar_t*)Request(PMgetenv,dummy);
1.1584 + }
1.1585 +
1.1586 +void CProcessSystemInterface::unsetenv (const wchar_t* name)
1.1587 + {
1.1588 + int dummy;
1.1589 + iParams.cwptr[0]=name;
1.1590 + Request(PMunsetenv,dummy);
1.1591 + }
1.1592 +
1.1593 +int CProcessSystemInterface::setenv (const wchar_t* name, const wchar_t* value, int rewrite, int& anErrno)
1.1594 + {
1.1595 + iParams.cwptr[0]=name;
1.1596 + iParams.cwptr[1]=value;
1.1597 + iParams.pint[0]=rewrite;
1.1598 + return Request(PMsetenv,anErrno);
1.1599 + }
1.1600 +
1.1601 +int CProcessSystemInterface::popen3 (const wchar_t* file, const wchar_t* cmd, const wchar_t* mode, wchar_t** env, int fids[3], int& anErrno)
1.1602 + {
1.1603 + iParams.wptr[0]=(wchar_t*)file;
1.1604 + iParams.cwptr[0]=cmd;
1.1605 + iParams.cwptr[1]=mode;
1.1606 + iParams.eptr[0]=env;
1.1607 + iParams.pint[0]=fids[0];
1.1608 + iParams.pint[1]=fids[1];
1.1609 + iParams.pint[2]=fids[2];
1.1610 + TInt child=Request(PMpopen3,anErrno);
1.1611 + if (child>=0)
1.1612 + {
1.1613 + fids[0]=iParams.pint[0];
1.1614 + fids[1]=iParams.pint[1];
1.1615 + fids[2]=iParams.pint[2];
1.1616 + };
1.1617 + return child;
1.1618 + }
1.1619 +
1.1620 +int CProcessSystemInterface::waitpid (int pid, int* status, int options, int& anErrno)
1.1621 + {
1.1622 + iParams.pint[0]=pid;
1.1623 + iParams.pint[1]=options;
1.1624 + TInt ret=Request(PMwaitpid,anErrno);
1.1625 + if (iParams.ret>=0 && status!=0)
1.1626 + {
1.1627 + *status=iParams.pint[0];
1.1628 + return iParams.ret;
1.1629 + }
1.1630 +
1.1631 + return ret;
1.1632 + }
1.1633 +
1.1634 +// C++ version of asynchronous ioctl
1.1635 +//
1.1636 +// WARNING - this stuff is fairly insecure. We give no guarantees about whether the ioctl or
1.1637 +// the completion will read the parameter information (sometimes it's both).
1.1638 +//
1.1639 +
1.1640 +int CProcessSystemInterface::ioctl (int fid, int cmd, void* param, TRequestStatus& aStatus, int& anErrno)
1.1641 + {
1.1642 + iParams.fid=fid;
1.1643 + iParams.pint[0]=cmd;
1.1644 + iParams.ptr[0]=(char*)param;
1.1645 +
1.1646 + if (cmd & 0x4000)
1.1647 + Request(PMioctlN,anErrno,aStatus);
1.1648 + else
1.1649 + Request(PMioctl,anErrno,aStatus);
1.1650 +
1.1651 + return KErrNone;
1.1652 + }
1.1653 +
1.1654 +int CProcessSystemInterface::ioctl_complete (int fid, int cmd, void* param, TRequestStatus& aStatus, int& anErrno)
1.1655 + {
1.1656 + iParams.fid=fid;
1.1657 + iParams.pint[0]=cmd;
1.1658 + iParams.ptr[0]=(char*)param;
1.1659 + iParams.ptr[1]=(char*)&aStatus;
1.1660 + return Request(PMioctlcomplete,anErrno);
1.1661 + }
1.1662 +
1.1663 +int CProcessSystemInterface::ioctl_cancel (int /*fid*/, int& /*anErrno*/)
1.1664 +//
1.1665 +// Actually a generic Cancel function for any outstanding operation
1.1666 +//
1.1667 + {
1.1668 + TIpcArgs args;
1.1669 + return iSession.Request(PMcancel,args);
1.1670 + }