Update contrib.
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // Client interface to the CPosixServer
22 #include <sys/errno.h>
23 #include <sys/serial.h>
28 #define DebugPrint RDebug::Print
30 inline void DebugPrint(const TDesC&, ...) {}
35 // The message protocol is to pass the errno pointer in p[0] and a pointer to a PosixParams
36 // in p[1]. The result is written back into the PosixParams.retval field.
38 int RPosixSession::Request(TInt aFunction, int& anErrno, PosixParams& aParams) const
40 return SendReceive(aFunction,TIpcArgs(&anErrno,&aParams));
43 void RPosixSession::Request(TInt aFunction, int& anErrno, PosixParams& aParams, TRequestStatus& aStatus) const
45 SendReceive(aFunction,TIpcArgs(&anErrno,&aParams),aStatus); // asynchronous request
48 void RPosixSession::Request(TInt aFunction, const TIpcArgs& aArg,TRequestStatus &aStatus) const
50 RSessionBase::SendReceive(aFunction,aArg,aStatus);
52 TInt RPosixSession::Request(TInt aFunction, const TIpcArgs& aArg) const
54 return RSessionBase::SendReceive(aFunction,aArg);
57 TVersion RPosixSession::Version()
59 return TVersion(KCPosixMajorVersionNumber,KCPosixMinorVersionNumber,0);
62 TInt RPosixSession::Connect (TDesC& aServerName)
64 TVersion version=Version();
65 return CreateSession(aServerName,version,1+3); // 3 extra message slots for pipes
68 TInt RPosixSession::Connect ()
71 PosixServerName(serverName);
72 return CreateSession(serverName,Version(),1);
75 // CPosixServer support functions exported from ESTLIB.DLL
79 // simple scheme to provide pretend processes on WINS
81 extern "C" void getcwd(char*,int);
82 typedef void (*FUNC)();
85 EXPORT_C void NewProcessId ()
91 EXPORT_C void NextProcessFn (TAny* aFn)
96 TInt threadhelper (TAny* aFn)
103 TInt processhelper (TAny*)
105 // Do the MCRT0.OBJ things straight away
106 SpawnPosixServerThread();
108 getcwd(wd, sizeof(wd)); // connect to CPosixServer
109 return threadhelper(procFn);
112 _LIT(SERVER_FORMAT,"Posix-%d");
113 _LIT(SERVER_MATCH, "Posix-*");
115 EXPORT_C void PosixServerName(TDes& aBuffer)
117 // Construct the name of the CPosixServer for this process
120 TProcessId id=RProcess().Id();
121 aBuffer.Format(SERVER_FORMAT,*REINTERPRET_CAST(int*,&id));
127 TRequestStatus* iStatus;
130 EXPORT_C TInt SpawnPosixServerThread ()
132 // Try to start a PosixServer thread, assuming there isn't one already
136 TInt err=probe.Connect();
139 return KErrNone; // server already exists
141 PosixServerName(serverName);
142 TRequestStatus status(KRequestPending);
143 struct rendezvous rv;
144 rv.iCaller.Duplicate(RThread(),EOwnerProcess);
147 err=server.Create(serverName,CPosixServer::ThreadFunction,0x2000,NULL,&rv);
151 User::WaitForRequest(status);
159 EXPORT_C TInt InstallPosixServerActiveObject (TInt aPriority)
161 TRAPD(err, CPosixServer::InitL(aPriority));
165 void CPosixServer::InitL(TInt aPriority)
167 // Construct and install a CPosixServer active object
170 CPosixServer *pS=new(ELeave) CPosixServer(aPriority);
171 CleanupStack::PushL(pS);
173 PosixServerName(serverName);
175 User::LeaveIfError(pS->iFs.Connect());
179 // search for parent process
182 // set up default fids
183 pS->DefaultConsoleL();
185 DebugPrint(_L("Starting CPosixServer\n"));
186 pS->StartL(serverName);
187 CleanupStack::Pop(pS);
188 // Leave pS on the clean up stack for the calling routine to clean up normally on
189 // Active Scheduler shutdown or in a failure case where the scheduler does not
190 // start due to an error.
196 CPosixServer::CPosixServer(TInt aPriority)
197 : CServer2(aPriority)
199 __DECLARE_NAME(_S("CPosixServer"));
202 TInt CPosixServer::ThreadFunction(TAny* aPtr)
204 // Create and run an active scheduler containing a CPosixServer
207 CTrapCleanup* TheTrapCleanup=CTrapCleanup::New();
210 stdlib.Load(_L("estlib")); // workaround for RAM-loaded EXE calling RAM-loaded DLL
212 struct rendezvous* rvp = (struct rendezvous *)aPtr;
214 // start scheduler and server
215 CActiveScheduler *pA=new CActiveScheduler;
218 CActiveScheduler::Install(pA);
219 ret=InstallPosixServerActiveObject();
221 // signal to the caller that we've started (or failed!)
222 rvp->iCaller.RequestComplete(rvp->iStatus,ret);
225 // start fielding requests from clients
226 CActiveScheduler::Start();
229 delete TheTrapCleanup;
233 CSession2* CPosixServer::NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const
235 TBool r=User::QueryVersionSupported(RPosixSession::Version(),aVersion);
237 User::Leave(KErrNotSupported);
239 RProcess clientProcess;
240 RThread clientThread;
241 User::LeaveIfError(aMessage.Client(clientThread));
242 CleanupClosePushL(clientThread);
243 User::LeaveIfError(clientThread.Process(clientProcess));
244 TProcessId clientId = clientProcess.Id();
245 clientProcess.Close();
246 CleanupStack::PopAndDestroy(1); //close thread
248 if (clientId!=RProcess().Id())
250 // A thread in a different process
252 User::Leave(KErrNotReady); // quick rejection
254 // We need an explicit CONST_CAST so that the CPosixRequest objects have a
255 // mutable reference to the CPosixServer which holds the shared data structures
256 return new(ELeave) CPosixIPCSession(CONST_CAST(CPosixServer&,*this));
258 // A thread in the same process
259 return new(ELeave) CPosixSession(CONST_CAST(CPosixServer&,*this));
262 void CPosixServer::ServerPanic (TPosixServerPanic aPanic)
264 _LIT(KPosixServerPanic, "Posix server");
265 User::Panic(KPosixServerPanic,aPanic);
268 void CPosixServer::FindParentL()
272 TPosixIPCReply reply;
274 TProcessId id=RProcess().Id();
275 pid = *REINTERPRET_CAST(TUint*,&id); // my process id
277 TFindServer posixservers(SERVER_MATCH);
278 while (posixservers.Next(parent)==KErrNone)
280 DebugPrint(_L("Are you my mother, %S?"), &parent);
281 if (iParent.Connect(parent)!=KErrNone)
283 if (iParent.Request(PMAreYouMyMother,TIpcArgs(&pid, &reply))!=KErrNone)
290 DebugPrint(_L("Found parent process %S"), &parent);
292 // Create any pipes that might be required
293 TUint mask=reply().iPipeMask;
294 CPipeChildDesc* pipes[3];
296 for (i=0; i<3; i++, mask>>=1)
301 CPipeChildDesc* pipe=new(ELeave) CPipeChildDesc(i,iParent);
307 // organise the necessary descriptors
308 TPtr env=HBufC::NewLC(reply().iEnvironmentSize)->Des();
309 TPtr cwd=HBufC::NewLC(reply().iWorkingDirectorySize)->Des();
311 // get the data from parent
312 TInt err=iParent.Request(PMHelloMum, TIpcArgs(&pid, &env, &cwd));
314 DebugPrint(_L("Environment string: %S"), &env);
315 DebugPrint(_L("Working directory: %S"), &cwd);
319 DebugPrint(_L("I've become an orphan"));
325 // apply to our process
326 iEnv.ConstructL(reply().iVarCount,env);
327 err=iFs.SetSessionPath(cwd);
328 User::LeaveIfError(err);
330 // free up the temporary descriptors
331 CleanupStack::PopAndDestroy(2);
336 iFids.Attach(i, pipes[i]);
342 DebugPrint(_L("Posix-%d is a top-level process"), pid());
343 User::LeaveIfError(PosixFilesystem::SetDefaultDir(iFs));
346 int CPosixServer::POpen3(PosixParams* aParams, int& anErrno)
348 TInt err=KErrNoMemory;
351 CPosixProcess* proc= new CPosixProcess(*this);
354 //coverity[leave_without_push]
355 err=iFids.Reserve(aParams->pint);
358 TRAP(err,proc->POpen3L(aParams));
362 DebugPrint(_L("POpen3 created process %d"), proc->iPid);
363 proc->iNextProcess=iChildren;
365 return (int)proc->iPid; // success
368 iFids.Detach(aParams->pint);
370 return MapError(err, anErrno);
373 CPosixRequest* CPosixServer::Waiters()
375 CPosixRequest* waiters=iWaitAnyQueue;
382 // Each local thread gets one of these
384 CPosixSession::CPosixSession(CPosixServer& aServer)
387 CActiveScheduler::Add(&iActive);
388 __DECLARE_NAME(_S("CPosixSession"));
391 void CPosixSession::ServiceL(const RMessage2& aMessage)
393 iActive.Service(aMessage);
398 // An active object contained within the Session that handles the deferred completion
399 // of asynchronous functions (e.g. read & write).
401 CPosixRequest::CPosixRequest(CPosixServer& aServer)
402 : CActive(EPriorityStandard), iServer(aServer), iPtr(0,0)
409 void CPosixRequest::Service(const RMessage2& aMessage)
411 // The message protocol is to pass the errno pointer in p[0] and a pointer to a PosixParams
412 // in p[1]. The result is written back into the PosixParams.retval field.
415 if (aMessage.Function() == PMcancel)
417 Cancel(); // Cancel in the active scheduler
419 EndAsynch(KErrCancel); // Complete the cancelled request & clean up
420 aMessage.Complete(KErrNone);
426 aMessage.Complete(KErrInUse);
429 int& anErrno=*REINTERPRET_CAST(int*,CONST_CAST(TAny*,aMessage.Ptr0()));
430 PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,aMessage.Ptr1()));
431 switch (aMessage.Function())
434 // Asynchronous functions need queuing, active objects etc.
440 iPtr.Set((TText8*)params->ptr[0], params->len[0], params->len[0]);
441 // and fall through...
446 TInt err=Fids().Asynch(params->fid,iFile);
449 QueueAsynch(aMessage); // start operation or queue if busy
450 return; // deferred completion through RunL
452 params->ret=MapError(err,anErrno);
458 TInt err=Fids().Asynch(params->fid,iFile);
462 iNewFid=Fids().Reserve(); // reserve a fid for the accepted socket
466 QueueAsynch(aMessage); // start operation or queue if busy
467 return; // deferred completion through RunL
470 params->ret=MapError(err,anErrno);
477 TInt err=Fids().Asynch(params->fid,iFile);
480 QueueAsynch(aMessage); // start operation or queue if busy
481 return; // deferred completion through RunL
484 aMessage.Complete(err); // Different calling convention
488 // complicated synchronous functions which might do their own completion
492 // check for invalid options or if an invalid pid is specified. currently there is no
493 // support for process group id's so a pid less than -1 or equal to 0 is invalid
494 if((params->pint[1] & ~(WNOHANG|WUNTRACED))|| (params->pint[0] < -1) || (params->pint[0] ==0))
500 if (params->pint[0]==-1 && params->pint[1]==0) /* wait for any child */
503 iServer.WaitForAnyChild(this);
504 return; // wait for the next child to die
506 CPosixProcess* child=iServer.Child(params->pint[0]);
509 if (child->IsAlive())
511 if (params->pint[1]&1) /* WNOHANG */
518 return; // wait for the child to die
520 params->pint[0]=child->iExitReason;
521 params->ret=child->iPid;
522 iServer.Release(child);
532 // simple synchronous functions
535 params->ret=Fids().dup(params->fid,anErrno);
538 params->ret=Fids().dup2(params->fid,params->pint[0],anErrno);
542 const wchar_t* name = params->cwptr[0];
543 if ((L'C' == name[0]) && (L'O' == name[1]) && (L'M' == name[2]) && (L':' == name[4]) && ((name[3] >= L'1') && (name[3] <= L'9')) ||
544 (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')))
545 params->ret=Fids().open(params->cwptr[0],params->pint[0],params->pint[1],anErrno,Cs());
547 params->ret=Fids().open(params->cwptr[0],params->pint[0],params->pint[1],anErrno,Fs());
552 params->ret=Fids().userclose(params->fid,anErrno);
555 params->ret=Fids().lseek(params->fid,params->pint[0],params->pint[1],anErrno);
558 params->ret=Fids().fstat(params->fid,(struct stat*)params->ptr[0],anErrno);
561 // params->ret=(int)PosixFilesystem::getcwd(Fs(),params->ptr[0],params->len[0],anErrno);
562 params->ret=(int)PosixFilesystem::getcwd(Fs(),params->wptr[0],params->len[0],anErrno);
565 params->ret=PosixFilesystem::chdir(Fs(),params->cwptr[0],anErrno);
568 // params->ret=PosixFilesystem::mkdir(Fs(),params->cptr[0],params->pint[0],anErrno);
569 params->ret=PosixFilesystem::mkdir(Fs(),params->cwptr[0],params->pint[0],anErrno);
572 params->ret=PosixFilesystem::rmdir(Fs(),params->cwptr[0],anErrno);
575 params->ret=PosixFilesystem::chmod(Fs(),params->cwptr[0],params->pint[0],anErrno);
578 params->ret=PosixFilesystem::unlink(Fs(),params->cwptr[0],anErrno);
581 params->ret=PosixFilesystem::stat(Fs(),params->cwptr[0],(struct stat*)params->ptr[0],anErrno);
584 params->ret=PosixFilesystem::rename(Fs(), params->cwptr[0],params->cwptr[1],anErrno);
587 // params->ret=PosixFilesystem::ResolvePath(Fs(),
588 // *(TParse*)params->ptr[0],params->cptr[0],(TDes*)params->ptr[1]);
589 params->ret=PosixFilesystem::ResolvePath(Fs(),
590 *(TParse*)params->ptr[0],params->cwptr[0],(TDes*)params->ptr[1]);
593 params->ret=Fids().socket(params->pint[0],params->pint[1],params->pint[2],anErrno,Ss());
596 params->ret=Fids().bind(params->fid,params->addr,anErrno);
599 params->ret=Fids().listen(params->fid,params->pint[0],anErrno);
602 params->ret=Fids().sockname(params->fid,params->addr,params->pint[0],anErrno);
605 params->ret=Fids().getsockopt(params->fid,params->pint[0],params->pint[1],
606 params->ptr[0],params->lenp[0],anErrno);
609 params->ret=Fids().setsockopt(params->fid,params->pint[0],params->pint[1],
610 params->ptr[0],params->len[0],anErrno);
613 params->ret=(int)Env().getenv(params->cwptr[0]);
616 Env().unsetenv(params->cwptr[0]); // no return value
619 params->ret=Env().setenv(params->cwptr[0],params->cwptr[1],params->pint[0],anErrno);
621 case PMioctlcomplete:
622 params->ret=Fids().ioctlcomplete(params->fid,params->pint[0],params->ptr[0],*(REINTERPRET_CAST(TRequestStatus*, params->ptr[1])), anErrno);
624 case PMTerminateProcess:
626 int status = params->fid;
627 RProcess().Kill(status);
631 params->ret=iServer.POpen3(params,anErrno);
634 aMessage.Complete(KErrNotSupported);
637 // deal with completion of a synchronous request
638 aMessage.Complete(KErrNone);
641 // Asynchronous requests
643 // 1. QueueAsynch() to get into the appropriate queue in the FileDesc
644 // 2. FileDesc calls StartAsynch() when it's our turn
645 // 3. StartAsynch() makes the relevant IO call and does SetActive()
646 // 4a. RunL() handles the completion of the IO call and calls EndAsynch()
647 // 4b. DoCancel() handles cancellation of the IO call, but doesn't call EndAsynch()
648 // 5. EndAsynch() removes us from the FileDesc queue and completes iMessage
651 void CPosixRequest::QueueAsynch(const RMessage2& aMessage)
653 // Add this to the appropriate queue in the associated file
656 iMessage=aMessage; // Suggested by AndrewT to avoid code duplication
657 iQueue=CFileDescBase::IOwriteQ;
658 switch (aMessage.Function())
662 iQueue=CFileDescBase::IOreadQ;
665 iQueue=CFileDescBase::IOioctlQ;
668 iQueue=CFileDescBase::IOioctlNQ;
671 // everything else uses the IOwriteQ, including Accept and Connect
675 __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
676 iFile->AddLast(*this,iQueue);
679 void CPosixRequest::StartAsynch()
681 // The request has reached the front of the queue and can now be actioned
684 PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1()));
685 switch (iMessage.Function())
690 //if we need to have a timer for this operation to cancel it later
691 if (iFile->TimedRead())
693 iFile->ReadIsTimed = ETrue;
694 TRAPD(tRes, {iFile->TimedMessage = CSerialTimer::NewL(iFile);});
695 if (tRes != KErrNone)
697 //we have a problem here
698 //basically, fake the async request completing with the returned error
699 iStatus = KRequestPending;
701 TRequestStatus * ps = &iStatus;
702 User::RequestComplete(ps, tRes);
706 iFile->TimedMessage->IssueRequest();
709 iFile->ReadIsTimed = EFalse;
711 iFile->ReadWasCancelled = EFalse;
713 iFile->Read(iPtr,iStatus);
718 iFile->RecvFrom(iPtr,params->addr,params->pint[0],iStatus);
721 iFile->Write(iPtr,iStatus);
724 iFile->SendTo(iPtr,params->addr,params->pint[0],iStatus);
727 iFile->Sync(iStatus);
730 iFile->Connect(params->addr,iStatus);
733 iFile->Shutdown(params->pint[0],iStatus);
736 iFile->Accept(iNewF,iStatus,Ss());
739 iFile->Ioctl(params->pint[0],params->ptr[0],iStatus);
742 iFile->Ioctl(params->pint[0],params->ptr[0],iStatus);
745 EndAsynch(KErrGeneral);
748 SetActive(); // for asynchronous completion via RunL
752 void CPosixRequest::RunL()
754 // The pending IO has completed, so handle the result
757 __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
758 TInt completion=KErrNone;
759 int& anErrno=*REINTERPRET_CAST(int*,CONST_CAST(TAny*,iMessage.Ptr0()));
760 PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1()));
761 switch (iMessage.Function())
765 if (iFile->ReadIsTimed)
767 //need to stop the timer
768 delete iFile->TimedMessage;
769 iFile->TimedMessage = NULL;
770 iFile->ReadIsTimed = EFalse;
773 TInt err=iFile->ReadCompletion(iPtr, iStatus.Int());
776 params->ret=iPtr.Length();
779 //if the read was cancelled and we are to patch it due to me cancelling it
781 if (iFile->ReadWasCancelled)
784 iFile->ReadWasCancelled = EFalse;
787 params->ret=MapError(err,anErrno);
792 TInt err=iFile->WriteCompletion(iPtr, iStatus.Int());
795 params->ret=iPtr.Length();
798 params->ret=MapError(err,anErrno);
804 params->ret=MapError(iStatus.Int(),anErrno);
808 TInt err=iFile->SendToCompletion(iPtr, iStatus.Int());
811 params->ret=iPtr.Length();
814 params->ret=MapError(err,anErrno);
819 TInt err=iFile->RecvFromCompletion(params->ret, iStatus.Int());
822 params->ret=iPtr.Length();
825 params->ret=MapError(err,anErrno);
830 TInt err=iStatus.Int();
832 Fids().Attach(iNewFid,0); // cancel the reservation
835 err=Fids().Attach(iNewFid,iNewF);
839 break; // so that we return the new fid
844 params->ret=MapError(err,anErrno);
850 completion=iStatus.Int(); // caller picks up completion explicitly
856 completion=iStatus.Int(); // caller picks up completion explicitly
857 // TInt err=iFile->IoctlCompletion(params->pint[0], ¶ms->ret, iStatus.Int());
858 // params->ret=MapError(err,anErrno);
863 completion=KErrGeneral; // arrgh - I imagine that it's going to die if we get here...
866 EndAsynch(completion);
869 void CPosixRequest::EndAsynch(TInt aResult)
871 // finish an asynchronous operation and complete iMessage
874 __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
875 iFile->Remove(*this,iQueue);
876 iFile->Close(); // balances the Dup() in CFileTable::Asynch(), may delete object!
878 iMessage.Complete(aResult);
882 void CPosixRequest::DoCancel()
884 // The pending IO has been cancelled, so cancel the outstanding request
885 // Needs to deal with all of the cases in RunL, but doesn't call EndAsynch().
886 // This is called from CActive::Cancel() only when the object is active, but
887 // EndAsynch() needs to be called when the object is active or when it's just
888 // waiting in a FileDesc queue.
891 __ASSERT_ALWAYS(iFile!=0,CPosixServer::ServerPanic(EPosix_NoPendingIO));
892 switch (iMessage.Function())
898 iFile->RecvFromCancel();
901 iFile->WriteCancel();
904 iFile->SendToCancel();
910 iFile->ConnectCancel();
913 iFile->ShutdownCancel();
916 iFile->AcceptCancel();
917 Fids().Attach(iNewFid,0); // cancel the reservation
920 iFile->IoctlCancel();
923 // it would be wrong to get here, so leave well alone
928 CPosixRequest::~CPosixRequest()
932 EndAsynch(KErrCancel);
935 // Handling waiting on other processes
937 void CPosixRequest::EnList(CPosixRequest*& aHead)
943 void CPosixRequest::WaitCompleted(TInt aPid, TInt aReason)
945 PosixParams* params=REINTERPRET_CAST(PosixParams*,CONST_CAST(TAny*,iMessage.Ptr1()));
947 __ASSERT_DEBUG(iMessage.Function()==PMwaitpid, CPosixServer::ServerPanic(EPosix_BadWaitCompletion));
948 params->pint[0]=aReason;
950 iMessage.Complete(KErrNone);
952 CPosixRequest* next=iNext;
955 next->WaitCompleted(aPid, aReason);
958 static void ClosePipes(CPipeDesc* aPipes[3])
963 CPipeDesc* pipe=aPipes[i];
970 TInt CPosixIPCSession::AreYouMyMotherL(const RMessage2& aMessage)
973 TPosixIPCReply reply;
974 aMessage.ReadL(0,pid);
975 DebugPrint(_L("Process %d asks am I its mother?"), pid());
976 CPosixServer* pServ = const_cast<CPosixServer*>(static_cast<const CPosixServer*>(Server()));
977 CPosixProcess* child=pServ->Child(pid());
979 return KErrNotFound; // you are no child of mine
980 DebugPrint(_L("Found child process"));
982 aMessage.Write(1,reply);
986 TInt CPosixIPCSession::HelloMumL(const RMessage2& aMessage)
989 aMessage.ReadL(0,pid);
991 DebugPrint(_L("Process %d is requesting its inheritance"),pid());
993 CPosixServer* pServ = const_cast<CPosixServer*>(static_cast<const CPosixServer*>(Server()));
994 CPosixProcess* child=pServ->Child(pid());
996 return KErrNotFound; // you are no child of mine
998 // CopyToChildL will pull out the second and third element out directly so as
999 // to copy data to it. This is why data is passed in this way.
1000 child->CopyToChildL(aMessage);
1004 void CPosixIPCSession::PipeRead(const RMessage2& aMessage)
1006 TInt index=aMessage.Int0();
1007 if (iPipes[index]==0)
1008 aMessage.Complete(KErrEof); // go away, incorrect thing!
1010 iPipes[index]->ClientRead(aMessage);
1013 void CPosixIPCSession::PipeWrite(const RMessage2& aMessage)
1015 TInt index=aMessage.Int0();
1016 if (iPipes[index]==0)
1017 aMessage.Complete(KErrEof); // go away, incorrect thing!
1019 iPipes[index]->ClientWrite(aMessage);
1022 void CPosixIPCSession::PipeIoctl(const RMessage2& aMessage)
1024 TInt index=aMessage.Int0();
1025 if (iPipes[index]==0)
1026 aMessage.Complete(KErrEof); // go away, incorrect thing!
1028 iPipes[index]->ClientIoctl(aMessage);
1031 void CPosixIPCSession::PipeClose(const RMessage2& aMessage)
1033 TInt index=aMessage.Int0();
1034 if (iPipes[index]!=0)
1035 iPipes[index]->ClientClose();
1036 aMessage.Complete(KErrNone);
1039 void CPosixIPCSession::PipeCancel(const RMessage2& aMessage)
1041 TInt index=aMessage.Int0();
1042 if (iPipes[index]!=0)
1043 iPipes[index]->ClientCancel(aMessage);
1044 aMessage.Complete(KErrNone);
1047 void CPosixIPCSession::ServiceL(const RMessage2& aMessage)
1049 // Handle the communication between CPosixServers
1052 TInt response=KErrNone;
1053 switch (aMessage.Function())
1055 case PMAreYouMyMother:
1056 response=AreYouMyMotherL(aMessage);
1059 response=HelloMumL(aMessage);
1064 return; // handles completion
1066 PipeWrite(aMessage);
1067 return; // handles completion
1069 PipeIoctl(aMessage);
1070 return; // handles completion
1072 PipeClose(aMessage);
1073 return; // handles completion
1076 PipeCancel(aMessage);
1080 response=KErrNotSupported;
1083 aMessage.Complete(response);
1086 void CPosixIPCSession::SetPipes(CPipeDesc* aPipes[3])
1088 // Accept ownership of the pipes between child and parent
1094 CPipeDesc* pipe=aPipes[i];
1098 pipe->SetClientSide(iPipes[i]);
1102 CPosixIPCSession::~CPosixIPCSession()
1107 // Active Object representing a POSIX process
1109 CPosixProcess::CPosixProcess(CPosixServer& aServer)
1110 : CActive(EPriorityStandard), iServer(aServer)
1116 // iWorkingDirectory=0;
1119 CPosixProcess* CPosixProcess::Find(CPosixProcess* proc, TInt pid)
1123 if (proc->iPid==pid)
1125 if (pid==-1 && !proc->IsAlive()) // for waitpid(WAIT_ANY,...)
1127 proc=proc->iNextProcess;
1132 void CPosixProcess::Release(CPosixProcess** aHead, CPosixProcess* aChild)
1136 if ((*aHead)==aChild)
1138 (*aHead)=aChild->iNextProcess;
1139 aChild->iNextProcess=0;
1143 aHead=&(*aHead)->iNextProcess;
1149 void CPosixProcess::POpen3L(PosixParams* aParams)
1152 CPipeDesc* pipes[3];
1155 if (aParams->pint[i]<0)
1159 pipes[i]=new(ELeave) CPipeDesc(i);
1163 // truncate fileName to get the name of the executable
1164 TPtrC16 fileName((TText16*)aParams->wptr[0]);
1165 TPtrC16 commandLine((TText16*)aParams->cwptr[0]);
1167 HBufC16* env=Env().ExternalizeLC(iVarCount,aParams->eptr[0]);
1168 TFullName workingDirectory;
1169 TInt err=Fs().SessionPath(workingDirectory);
1170 User::LeaveIfError(err);
1171 HBufC* cwd=workingDirectory.AllocLC();
1173 // Use real processes
1174 err=iChild.Create(fileName,commandLine,EOwnerThread);
1175 User::LeaveIfError(err);
1176 TProcessId id=iChild.Id();
1177 iPid=*REINTERPRET_CAST(int*,&id);
1178 iChild.Logon(iStatus);
1179 CActiveScheduler::Add(this);
1183 iWorkingDirectory=cwd;
1184 CleanupStack::Pop(2);
1185 // Sort out the pipes
1188 CPipeDesc* pipe=pipes[i];
1192 CleanupStack::Pop();
1193 Fids().Attach(aParams->pint[i],pipe);
1194 pipe->SetClientSide(iPipes[i]); // for FinalClose
1199 void CPosixProcess::Sizes(TPosixIPCReply& aReply) const
1201 aReply().iWorkingDirectorySize=iWorkingDirectory->Length();
1202 aReply().iEnvironmentSize=iEnvironment->Length();
1203 aReply().iVarCount=iVarCount;
1211 aReply().iPipeMask=mask;
1214 void CPosixProcess::CopyToChildL(const RMessage2& aMessage)
1216 // copy iWorkingDirectory and iEnvironment to params
1217 aMessage.WriteL(1, *iEnvironment);
1218 aMessage.WriteL(2, *iWorkingDirectory);
1220 // don't need this data anymore
1221 delete iWorkingDirectory;
1222 iWorkingDirectory=0;
1223 delete iEnvironment;
1226 (static_cast<CPosixIPCSession*>(aMessage.Session()))->SetPipes(iPipes);
1229 void CPosixProcess::RunL()
1231 // Detects termination of the child process
1234 iExitReason=iStatus.Int();
1236 DebugPrint(_L("Process %d appears to have terminated with status %d"), iPid, iExitReason);
1240 CPosixRequest* waiters=iWaiters;
1244 waiters->WaitCompleted(iPid,iExitReason);
1248 // And any of the outstanding "wait for any" requests held in the server
1249 waiters=iServer.Waiters();
1252 waiters->WaitCompleted(iPid,iExitReason);
1256 iServer.Release(this);
1259 void CPosixProcess::DoCancel()
1261 // panic if iNextProcess or iWaiters is non-zero?
1262 iChild.LogonCancel(iStatus);
1264 delete iEnvironment;
1266 delete iWorkingDirectory;
1267 iWorkingDirectory=0;
1271 CPosixProcess::~CPosixProcess()
1276 // System Interface for process form of STDLIB
1278 CProcessSystemInterface::CProcessSystemInterface()
1281 CProcessSystemInterface::~CProcessSystemInterface()
1286 MSystemInterface& CProcessSystemInterface::Clone()
1288 return *(new CProcessSystemInterface);
1291 void CProcessSystemInterface::Release()
1296 TInt CProcessSystemInterface::Connect()
1298 return iSession.Connect(); // is this the right thread though?
1301 // CProcessSystemInterface functions
1303 // These functions just package up their arguments for transmission to the
1304 // CPosixServer which will unpack them and call the corresponding function in
1305 // its associated CLocalSystemInterface, except for the asynchronous functions
1306 // (currently read/write/fsync) which the server handles separately using an active
1307 // object to defer the RMessage::Complete until the asynchronous operation has completed.
1309 static void doPanic(TInt aFunction, TInt aErr)
1312 _LIT(KProcessSystemInterfacePanic, "POSIXIF (%d)");
1313 detail.Format(KProcessSystemInterfacePanic, aFunction);
1314 User::Panic(detail,aErr);
1317 int CProcessSystemInterface::Request (TInt aFunction, int& anErrno)
1319 TInt err=iSession.Request(aFunction,anErrno,iParams);
1320 // KErrServerTerminated?
1322 doPanic(aFunction,err); // moved out of line to reduce stack requirement
1326 void CProcessSystemInterface::Request (TInt aFunction, int& anErrno, TRequestStatus& aStatus)
1328 iSession.Request(aFunction,anErrno,iParams,aStatus);
1331 void CProcessSystemInterface::TerminateProcess (int status)
1335 Request(PMTerminateProcess,anErrno);
1336 RProcess().Terminate(status); // just in case...
1339 int CProcessSystemInterface::dup (int fid, int& anErrno)
1342 return Request(PMdup,anErrno);
1345 int CProcessSystemInterface::dup2 (int fid, int fid2, int& anErrno)
1348 iParams.pint[0]=fid2;
1349 return Request(PMdup2,anErrno);
1352 int CProcessSystemInterface::open (const wchar_t* name, int mode, int perms, int& anErrno)
1354 iParams.cwptr[0]=name;
1355 iParams.pint[0]=mode;
1356 iParams.pint[1]=perms;
1357 return Request(PMopen,anErrno);
1360 int CProcessSystemInterface::read (int fid, char* buf, unsigned long len, int& anErrno)
1365 return Request(PMread,anErrno);
1368 int CProcessSystemInterface::write (int fid, const char* buf, unsigned long len, int& anErrno)
1371 iParams.ptr[0]=CONST_CAST(char*,buf);
1373 return Request(PMwrite,anErrno);
1376 int CProcessSystemInterface::fsync (int fid, int& anErrno)
1379 return Request(PMfsync,anErrno);
1382 int CProcessSystemInterface::close (int fid, int& anErrno)
1385 return Request(PMclose,anErrno);
1388 int CProcessSystemInterface::lseek (int fid, int offset, int whence, int& anErrno)
1391 iParams.pint[0]=offset;
1392 iParams.pint[1]=whence;
1393 return Request(PMlseek,anErrno);
1396 int CProcessSystemInterface::fstat (int fid, struct stat *st, int& anErrno)
1399 iParams.ptr[0]=(char*)st;
1400 return Request(PMfstat,anErrno);
1404 wchar_t * CProcessSystemInterface::getcwd (wchar_t* buf, unsigned long len, int& anErrno)
1406 iParams.wptr[0]=buf;
1409 return (wchar_t *)Request(PMgetcwd,anErrno);
1413 int CProcessSystemInterface::chdir (const wchar_t* aPath, int& anErrno)
1415 iParams.cwptr[0]=aPath;
1416 return Request(PMchdir,anErrno);
1419 int CProcessSystemInterface::mkdir (const wchar_t* aPath, int perms, int& anErrno)
1421 iParams.cwptr[0]=aPath;
1422 iParams.pint[0]=perms;
1423 return Request(PMmkdir,anErrno);
1426 int CProcessSystemInterface::rmdir (const wchar_t* aPath, int& anErrno)
1428 iParams.cwptr[0]=aPath;
1429 return Request(PMrmdir,anErrno);
1432 int CProcessSystemInterface::stat (const wchar_t* name, struct stat *st, int& anErrno)
1434 iParams.cwptr[0]=name;
1435 iParams.ptr[0]=(char*)st;
1436 return Request(PMstat,anErrno);
1439 int CProcessSystemInterface::chmod (const wchar_t* name, int perms, int& anErrno)
1441 iParams.cwptr[0]=name;
1442 iParams.pint[0]=perms;
1443 return Request(PMchmod,anErrno);
1446 int CProcessSystemInterface::unlink (const wchar_t* name, int& anErrno)
1448 iParams.cwptr[0]=name;
1449 return Request(PMunlink,anErrno);
1452 int CProcessSystemInterface::rename (const wchar_t* oldname, const wchar_t* newname, int& anErrno)
1454 iParams.cwptr[0]=oldname;
1455 iParams.cwptr[1]=newname;
1456 return Request(PMrename,anErrno);
1459 TInt CProcessSystemInterface::ResolvePath (TParse& aResult, const wchar_t* path, TDes* aFilename)
1462 iParams.ptr[0]=(char*)&aResult;
1463 iParams.cwptr[0]=path;
1464 iParams.ptr[1]=(char*)aFilename;
1465 return Request(PMResolvePath,ignored);
1468 TInt CProcessSystemInterface::socket (int family, int style, int protocol, int& anErrno)
1470 iParams.pint[0]=family;
1471 iParams.pint[1]=style;
1472 iParams.pint[2]=protocol;
1473 return Request(PMsocket,anErrno);
1476 TInt CProcessSystemInterface::shutdown (int fid, int how, int& anErrno)
1479 iParams.pint[0]=how;
1480 return Request(PMshutdown,anErrno);
1483 TInt CProcessSystemInterface::listen (int fid, int n, int& anErrno)
1487 return Request(PMlisten,anErrno);
1490 TInt CProcessSystemInterface::accept (int fid, int& anErrno)
1493 return Request(PMaccept,anErrno);
1496 TInt CProcessSystemInterface::bind (int fid, struct sockaddr* addr, unsigned long size, int& anErrno)
1499 iParams.addr.Set(addr, size);
1500 return Request(PMbind,anErrno);
1503 TInt CProcessSystemInterface::connect (int fid, struct sockaddr* addr, unsigned long size, int& anErrno)
1506 iParams.addr.Set(addr, size);
1507 return Request(PMconnect,anErrno);
1510 TInt CProcessSystemInterface::recvfrom (int fid, char* buf, unsigned long len, int flags, struct sockaddr* from, unsigned long* fromsize, int& anErrno)
1515 iParams.pint[0]=flags;
1516 iParams.addr.Prepare(from);
1517 TInt nbytes=Request(PMrecvfrom,anErrno);
1518 if (nbytes>=0) // i.e. no error
1519 iParams.addr.Get(from,fromsize);
1523 TInt CProcessSystemInterface::sendto (int fid, const char* buf, unsigned long len, int flags, struct sockaddr* to, unsigned long tosize, int& anErrno)
1526 iParams.ptr[0]=CONST_CAST(char*,buf);
1528 iParams.pint[0]=flags;
1529 iParams.addr.Set(to,tosize);
1530 return Request(PMsendto,anErrno);
1533 TInt CProcessSystemInterface::getsockopt (int fid, int level, int opt, void* buf, unsigned long* len, int& anErrno)
1536 iParams.pint[0]=level;
1537 iParams.pint[1]=opt;
1538 iParams.ptr[0]=(char*)buf;
1539 iParams.lenp[0]=len;
1540 return Request(PMgetsockopt,anErrno);
1543 TInt CProcessSystemInterface::setsockopt (int fid, int level, int opt, void* buf, unsigned long len, int& anErrno)
1546 iParams.pint[0]=level;
1547 iParams.pint[1]=opt;
1548 iParams.ptr[0]=(char*)buf;
1550 return Request(PMsetsockopt,anErrno);
1553 TInt CProcessSystemInterface::sockname (int fid, struct sockaddr* addr, unsigned long* size, int anEnd, int& anErrno)
1556 iParams.addr.Prepare(addr);
1557 iParams.pint[0]=anEnd;
1558 TInt err=Request(PMsockname,anErrno);
1560 iParams.addr.Get(addr,size);
1564 TInt CProcessSystemInterface::ioctl (int fid, int cmd, void* param, int& anErrno)
1566 TRequestStatus ioctlStatus;
1567 TInt err=ioctl(fid,cmd,param,ioctlStatus,anErrno);
1570 User::WaitForRequest(ioctlStatus);
1571 err=ioctl_complete(fid,cmd,param,ioctlStatus,anErrno);
1576 wchar_t* CProcessSystemInterface::getenv (const wchar_t* name)
1579 iParams.cwptr[0]=name;
1580 return (wchar_t*)Request(PMgetenv,dummy);
1583 void CProcessSystemInterface::unsetenv (const wchar_t* name)
1586 iParams.cwptr[0]=name;
1587 Request(PMunsetenv,dummy);
1590 int CProcessSystemInterface::setenv (const wchar_t* name, const wchar_t* value, int rewrite, int& anErrno)
1592 iParams.cwptr[0]=name;
1593 iParams.cwptr[1]=value;
1594 iParams.pint[0]=rewrite;
1595 return Request(PMsetenv,anErrno);
1598 int CProcessSystemInterface::popen3 (const wchar_t* file, const wchar_t* cmd, const wchar_t* mode, wchar_t** env, int fids[3], int& anErrno)
1600 iParams.wptr[0]=(wchar_t*)file;
1601 iParams.cwptr[0]=cmd;
1602 iParams.cwptr[1]=mode;
1603 iParams.eptr[0]=env;
1604 iParams.pint[0]=fids[0];
1605 iParams.pint[1]=fids[1];
1606 iParams.pint[2]=fids[2];
1607 TInt child=Request(PMpopen3,anErrno);
1610 fids[0]=iParams.pint[0];
1611 fids[1]=iParams.pint[1];
1612 fids[2]=iParams.pint[2];
1617 int CProcessSystemInterface::waitpid (int pid, int* status, int options, int& anErrno)
1619 iParams.pint[0]=pid;
1620 iParams.pint[1]=options;
1621 TInt ret=Request(PMwaitpid,anErrno);
1622 if (iParams.ret>=0 && status!=0)
1624 *status=iParams.pint[0];
1631 // C++ version of asynchronous ioctl
1633 // WARNING - this stuff is fairly insecure. We give no guarantees about whether the ioctl or
1634 // the completion will read the parameter information (sometimes it's both).
1637 int CProcessSystemInterface::ioctl (int fid, int cmd, void* param, TRequestStatus& aStatus, int& anErrno)
1640 iParams.pint[0]=cmd;
1641 iParams.ptr[0]=(char*)param;
1644 Request(PMioctlN,anErrno,aStatus);
1646 Request(PMioctl,anErrno,aStatus);
1651 int CProcessSystemInterface::ioctl_complete (int fid, int cmd, void* param, TRequestStatus& aStatus, int& anErrno)
1654 iParams.pint[0]=cmd;
1655 iParams.ptr[0]=(char*)param;
1656 iParams.ptr[1]=(char*)&aStatus;
1657 return Request(PMioctlcomplete,anErrno);
1660 int CProcessSystemInterface::ioctl_cancel (int /*fid*/, int& /*anErrno*/)
1662 // Actually a generic Cancel function for any outstanding operation
1666 return iSession.Request(PMcancel,args);