2 * File: spc.c $XConsortium: spc.c /main/6 1996/06/21 17:33:08 ageorge $
5 * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
7 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
8 * (c) Copyright 1993, 1994 International Business Machines Corp. *
9 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
10 * (c) Copyright 1993, 1994 Novell, Inc. *
13 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
16 #include <SPC/spc-proto.h>
18 #include "DtSvcLock.h"
21 int SPC_Process_Single_Prot_Request (protocol_request_ptr req, SPC_Channel_Ptr channel);
24 /* This is the SPC error number variable */
25 /* extern int XeSPCErrorNumber; */
29 extern int SPC_Initialized;
30 extern SPC_Channel_Ptr spc_activation_list;
31 extern SPC_Connection_Ptr connection_list;
32 extern SPC_Connection_Ptr read_terminator;
33 extern XeString official_hostname;
35 int max_fds = 0; /* Set up below. */
37 /*----------------------------------------------------------------------+*/
40 /*----------------------------------------------------------------------+*/
45 max_fds = getdtablesize();
47 max_fds = (int)sysconf(_SC_OPEN_MAX);
49 _DtSvcProcessUnlock();
54 *** Sub-Process Control access routines. These are just functional
55 *** interfaces to the underlying methods.
59 /*----------------------------------------------------------------------+*/
60 SPC_Channel_Ptr XeSPCOpen(XeString hostname,
62 /*----------------------------------------------------------------------+*/
64 /* Attempt to open an SPC channel - return TRUE if we succeed */
65 SPC_Channel_Ptr channel;
67 /* Check for initialization */
70 if(SPC_Initialize() == SPC_ERROR) {
71 _DtSvcProcessUnlock();
74 _DtSvcProcessUnlock();
76 /* The user specified iomode needs to be processed before we can use it.
79 iomode=SPC_Transform_Iomode(iomode);
83 /* Get a new channel object */
85 channel=SPC_Initialize_Channel(hostname, iomode);
87 /* check that everything was okay */
89 if(channel==SPC_ERROR)
92 /* call the open method for it */
94 return((SPC_Channel_Ptr) mempf2(channel, open, iomode, hostname));
98 /*----------------------------------------------------------------------+*/
99 XeSPCClose(SPC_Channel_Ptr channel)
100 /*----------------------------------------------------------------------+*/
102 if(channel==SPC_ERROR) {
103 SPC_Error(SPC_Bad_Argument);
107 if(IS_ACTIVE(channel))
108 XeSPCKillProcess(channel, FALSE);
110 if(IS_SPCIO_DELAY_CLOSE(channel->IOMode)) {
111 channel->IOMode |= SPCIO_DO_CLOSE;
115 channel->IOMode &= ~SPCIO_DO_CLOSE;
117 return(mempf0(channel, close));
121 /*----------------------------------------------------------------------+*/
122 XeSPCReset(SPC_Channel_Ptr channel)
123 /*----------------------------------------------------------------------+*/
126 if(channel==SPC_ERROR) {
127 SPC_Error(SPC_Bad_Argument);
131 if(IS_ACTIVE(channel))
132 XeSPCKillProcess(channel, FALSE);
134 channel->IOMode &= ~SPCIO_ACTIVE;
136 if(mempf0(channel, reset)==SPC_ERROR)
143 /*----------------------------------------------------------------------+*/
144 XeSPCRead(SPC_Channel_Ptr channel,
145 int connector, /* STDOUT or STDERR */
148 /*----------------------------------------------------------------------+*/
153 /* check for legal arguments */
155 if (channel==SPC_ERROR || !buffer ||
156 !(connector==STDOUT || connector==STDERR) ||
158 SPC_Error(SPC_Bad_Argument);
162 /* check state of the channel */
163 if (!IS_DATA(channel) || !IS_SPCIO_DATA(channel->wires[connector]->flags))
166 /* call the read filter */
169 n=(*channel->read_filter)(channel, connector, buffer, length);
170 } while(n == (EXCEPT_FLAG));
172 /* Check for an error */
181 /*----------------------------------------------------------------------+*/
182 XeSPCWrite(SPC_Channel_Ptr channel,
185 /*----------------------------------------------------------------------+*/
189 /* check for legal arguments */
191 if (channel==SPC_ERROR || !buffer || (length<0)) {
192 SPC_Error(SPC_Bad_Argument);
196 /* check the state of the channel */
198 if(!IS_ACTIVE(channel)) {
199 SPC_Error(SPC_Inactive_Channel);
203 /* call the write method */
205 n=mempf2(channel, write, buffer, length);
210 /*----------------------------------------------------------------------+*/
211 XeSPCActive(SPC_Channel_Ptr channel)
212 /*----------------------------------------------------------------------+*/
215 if (channel==SPC_ERROR) {
216 SPC_Error(SPC_Bad_Argument);
220 /* Is the passed channel active? */
221 return (IS_ACTIVE(channel));
224 /*----------------------------------------------------------------------+*/
225 XeSPCData(SPC_Channel_Ptr channel)
226 /*----------------------------------------------------------------------+*/
229 if(channel==SPC_ERROR) {
230 SPC_Error(SPC_Bad_Argument);
234 return(IS_DATA(channel));
238 /*----------------------------------------------------------------------+*/
239 XeSPCExecuteProcess(SPC_Channel_Ptr channel)
240 /*----------------------------------------------------------------------+*/
244 if (channel==SPC_ERROR) {
245 SPC_Error(SPC_Bad_Argument);
249 if(IS_ACTIVE(channel) || IS_DATA(channel)) {
250 SPC_Error(SPC_Active_Channel);
254 if((retval=mempf0(channel, exec_proc))==SPC_ERROR)
257 if (IS_SPCIO_WAIT(channel->IOMode)) {
258 /* Wait for sub-process to finish */
259 SPC_Wait_For_Termination(channel);
266 /*----------------------------------------------------------------------+*/
267 XeSPCSignalProcess(SPC_Channel_Ptr channel,
269 /*----------------------------------------------------------------------+*/
272 if ((channel==SPC_ERROR) ||
273 (channel->pid <= 0) ||
275 #ifdef NOT_IN_XPG3_YET
276 || (sig>=NSIG) /* Not a good idea for interoperability anyway */
279 SPC_Error(SPC_Bad_Argument);
283 /* This routine does not check to see if the channel is active. */
285 return(mempf1(channel, signal, sig));
288 /*----------------------------------------------------------------------+*/
289 XeSPCAddInput(SPC_Channel_Ptr channel,
290 SbInputHandlerProc handler,
291 /*----------------------------------------------------------------------+*/
295 SPC_Error(SPC_Bad_Argument);
299 if(!handler && !channel->Input_Handler)
303 channel->Input_Handler = handler;
304 channel->client_data = client_data;
307 return(mempf2(channel, add_input, handler, client_data));
312 /*----------------------------------------------------------------------+*/
313 XeSPCRegisterTerminator(SPC_Channel_Ptr channel,
314 SPC_TerminateHandlerType terminator,
316 /*----------------------------------------------------------------------+*/
319 SPC_Connection_Ptr conn;
321 if(channel==SPC_ERROR) {
322 SPC_Error(SPC_Bad_Argument);
326 /* Okay. If we have a pty channel, we have to check that we
327 have an input handler. I don't like doing this here, but ther
328 are no methods for this routine, so it has to be done. */
330 if(IS_SPCIO_PTY(channel->IOMode) && !channel->Input_Handler) {
331 SPC_Error(SPC_Bad_Argument);
335 channel->IOMode |= SPCIO_SYNC_TERMINATOR;
337 channel->Terminate_Handler = terminator;
338 channel->Terminate_Data = client_data;
341 conn=SPC_Channel_Terminator_Connection(channel);
342 if(conn->termination_id == -1)
343 SPC_XtAddInput(channel, &conn->termination_id, conn->sid,
344 SPC_Conditional_Packet_Handler, SPC_Terminator);
351 /*----------------------------------------------------------------------+*/
352 XeSPCAttach(SPC_Channel_Ptr channel,
354 /*----------------------------------------------------------------------+*/
357 if(channel==SPC_ERROR || pid<=0) {
358 SPC_Error(SPC_Bad_Argument);
362 return(mempf1(channel, attach, pid));
365 /*----------------------------------------------------------------------+*/
366 XeSPCDetach(SPC_Channel_Ptr channel)
367 /*----------------------------------------------------------------------+*/
369 if(channel == SPC_ERROR) {
370 SPC_Error(SPC_Bad_Argument);
375 channel->IOMode &= ~SPCIO_ACTIVE;
377 return XeSPCReset(channel);
384 *** "Composite" functions -- Those which are defined in terms of the
385 *** above primitives. One assumption is that the above primitives check
386 *** their arguments, so the composite functions need only check any
387 *** additional arguments.
393 ** Start with subprocess creation routines
397 /*----------------------------------------------------------------------+*/
398 XeSPCSpawn(XeString pathname,
399 XeString context_dir,
402 SPC_Channel_Ptr channel)
403 /*----------------------------------------------------------------------+*/
406 if(channel==SPC_ERROR) {
407 SPC_Error(SPC_Bad_Argument);
411 /* Assign the command arguments to this channel and attempt to Execute */
414 SPC_Free_Envp(channel->envp);
417 if(channel->argv && IS_SPCIO_DEALLOC_ARGV(channel->IOMode)) {
418 SPC_Free_Envp(channel->argv);
419 channel->IOMode &= ~SPCIO_DEALLOC_ARGV;
423 channel->context_dir=context_dir;
424 channel->argv = argv;
425 channel->path = pathname;
427 channel->envp=SPC_Create_Default_Envp(channel->envp);
428 channel->envp=SPC_Merge_Envp(channel->envp, envp);
429 channel->envp=SPC_Fixup_Environment(channel->envp, channel);
431 if(IS_SPCIO_SYSTEM(channel->IOMode))
432 if(SPC_MakeSystemCommand(channel)==SPC_ERROR)
435 /* Execute the process (XeSPCExecuteProcess will check arguments */
437 return(XeSPCExecuteProcess(channel));
440 /*----------------------------------------------------------------------+*/
441 SPC_Channel_Ptr XeSPCOpenAndSpawn(XeString hostname,
444 XeString context_dir,
447 /*----------------------------------------------------------------------+*/
449 /* This simply wraps together the two steps: Open and Spawn */
450 SPC_Channel_Ptr channel;
452 channel = XeSPCOpen(hostname, iomode);
453 if(channel==SPC_ERROR)
456 if (XeSPCSpawn(pathname, context_dir, argv, envp, channel)!=SPC_ERROR)
459 /* Close the channel and return SPC_ERROR */
467 ** Signalling routines
471 /*----------------------------------------------------------------------+*/
473 XeSPCKillProcesses(int wait)
474 /*----------------------------------------------------------------------+*/
476 /* Attempt to KILL all the sub-process that we know of */
480 for (spc = spc_activation_list; spc != (SPC_Channel_Ptr) NULL; spc = spc->next)
481 XeSPCKillProcess(spc, wait);
482 _DtSvcProcessUnlock();
485 /*----------------------------------------------------------------------+*/
486 XeSPCKillProcess(SPC_Channel_Ptr channel,
488 /*----------------------------------------------------------------------+*/
490 /* Attempt to KILL the sub-process (should we nullify the pid?) */
496 if(IS_ACTIVE(channel)) {
497 result = XeSPCSignalProcess(channel, SIGKILL);
498 if(result==SPC_ERROR)
500 if (wait || IS_SPCIO_SYNC_TERM(channel->IOMode))
501 SPC_Wait_For_Termination(channel);
507 /*----------------------------------------------------------------------+*/
508 XeSPCInterruptProcess(SPC_Channel_Ptr channel)
509 /*----------------------------------------------------------------------+*/
511 /* Attempt to INTerrupt the sub-process */
513 return(XeSPCSignalProcess(channel, SIGINT));
518 ** Process information routines.
522 /*----------------------------------------------------------------------+*/
523 XeString XeSPCGetDevice(SPC_Channel_Ptr channel,
526 /*----------------------------------------------------------------------+*/
529 SPC_Error(SPC_Bad_Argument);
533 /* Return the device name which corresponds to the side of a channel */
534 if (connector>=STDIN && connector<=STDERR) {
535 if (side == MASTER_SIDE)
536 return(channel->wires[connector]->master_name);
537 if (side == SLAVE_SIDE)
538 return(channel->wires[connector]->slave_name);
541 /* For no channel or incorrect side, return SPC_ERROR */
543 SPC_Error(SPC_Bad_Argument);
547 /*----------------------------------------------------------------------+*/
548 XeSPCGetProcessStatus(SPC_Channel_Ptr channel,
551 /*----------------------------------------------------------------------+*/
553 /* Fill in the type and cause of a process termination */
556 if(!channel || !type || !cause) {
557 SPC_Error(SPC_Bad_Argument);
561 low = channel->status & WAIT_STATUS_MASK;
562 high = (channel->status >> 8) & WAIT_STATUS_MASK;
568 case IS_WAIT_STATUS_STOPPED:
569 *type = SPC_PROCESS_STOPPED;
572 case IS_WAIT_STATUS_EXITED:
573 *type = SPC_PROCESS_EXITED;
579 *type = SPC_PROCESS_SIGNALLED;
583 } /* End switch on status */
585 /* When a process is still active return FALSE */
589 /*----------------------------------------------------------------------+*/
590 XeSPCGetPID(SPC_Channel_Ptr channel)
591 /*----------------------------------------------------------------------+*/
595 SPC_Error(SPC_Bad_Argument);
598 return (channel->pid);
601 /*----------------------------------------------------------------------+*/
602 int XeSPCGetLogfile(SPC_Channel_Ptr channel,
605 /*----------------------------------------------------------------------+*/
608 if(!channel || !IS_SPCIO_USE_LOGFILE(channel->IOMode)) {
609 SPC_Error(SPC_Bad_Argument);
612 *file=channel->logfile;
614 if(IS_REMOTE(channel))
615 *host=channel->connection->hostname;
617 *host= official_hostname;
618 _DtSvcProcessUnlock();
623 /*----------------------------------------------------------------------+*/
624 int XeSPCRemoveLogfile(SPC_Channel_Ptr channel)
625 /*----------------------------------------------------------------------+*/
629 SPC_Error(SPC_Bad_Argument);
633 return(mempf0(channel, remove_logfile));
638 ** Synchronous termination
642 #define SINGLE_PROT_DATA(req, channel, connector) \
643 if(!channel->queued_remote_data) \
644 channel->queued_remote_data=Xe_make_queue(FALSE); \
645 Xe_push_queue(channel->queued_remote_data, req); \
646 if(channel->Input_Handler) { \
647 SPC_Input_Handler(channel, connector); \
652 ** SPC_Process_Single_Prot_Request will return TRUE if it is okay
653 ** for the caller to free the protocol request.
657 /*----------------------------------------------------------------------+*/
658 SPC_Process_Single_Prot_Request(protocol_request_ptr req, SPC_Channel_Ptr channel)
659 /*----------------------------------------------------------------------+*/
662 switch(req->request_type) {
664 case APPLICATION_DIED:
666 READ_APPLICATION_DIED(req->dataptr, channel->status);
667 SPC_Channel_Terminated(channel);
670 case APPLICATION_STDOUT:
671 SINGLE_PROT_DATA(req, channel, STDOUT);
674 case APPLICATION_STDERR:
675 SINGLE_PROT_DATA(req, channel, STDERR);
679 SPC_Error(SPC_Internal_Error);
684 /*----------------------------------------------------------------------+*/
685 SPC_Channel_Ptr XeSPCHandleTerminator(int fd)
686 /*----------------------------------------------------------------------+*/
688 SPC_Connection_Ptr connection;
689 SPC_Channel_Ptr channel;
690 protocol_request_ptr prot;
691 XeQueue connection_queue;
693 if(!(connection=SPC_Lookup_Connection_Fd(fd))) {
694 SPC_Error(SPC_Bad_Argument);
698 if(!(prot=SPC_Read_Protocol(connection))) {
702 connection_queue=connection->queued_remote_data;
703 Xe_push_queue(connection_queue, prot);
705 while(prot=(protocol_request_ptr)Xe_pop_queue(connection_queue)) {
707 channel=prot->channel;
710 channel->IOMode |= SPCIO_DELAY_CLOSE;
712 if(SPC_Process_Single_Prot_Request(prot, channel))
713 SPC_Free_Protocol_Ptr(prot);
715 channel->IOMode &= ~SPCIO_DELAY_CLOSE;
716 if(IS_SPCIO_DO_CLOSE(channel->IOMode)) {
730 ** Use this call to get the file descriptor for
731 ** Synchronous termination.
735 /*----------------------------------------------------------------------+*/
736 XeSPCGetChannelSyncFd(SPC_Channel_Ptr channel)
737 /*----------------------------------------------------------------------+*/
740 SPC_Connection_Ptr conn;
742 if(channel==SPC_ERROR) {
743 SPC_Error(SPC_Bad_Argument);
747 conn=SPC_Channel_Terminator_Connection(channel);
754 *** Error Handling routines.
758 /*----------------------------------------------------------------------+*/
759 SPCError *XeSPCLookupError(int errnum)
760 /*----------------------------------------------------------------------+*/
762 if(errnum<SPC_Min_Error || errnum > SPC_Max_Error) {
763 SPC_Error(SPC_Bad_Argument);
767 return(SPC_Lookup_Error(errnum));
772 *** Temporarily shutdown input handlers
776 /*----------------------------------------------------------------------+*/
777 void XeSPCShutdownCallbacks(void)
778 /*----------------------------------------------------------------------+*/
780 SPC_Channel_Ptr channel;
781 SPC_Connection_Ptr conn;
785 channel=spc_activation_list;
786 conn=connection_list;
789 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
790 if(wirelist->read_toolkit_id != -1)
791 SPC_XtRemoveInput(&wirelist->read_toolkit_id, SPC_Input);
792 if(wirelist->except_toolkit_id != -1)
793 SPC_XtRemoveInput(&wirelist->except_toolkit_id, SPC_Exception);
795 channel=channel->next;
799 if(conn->termination_id != -1)
800 SPC_XtRemoveInput(&conn->termination_id, SPC_Terminator);
803 _DtSvcProcessUnlock();
806 /*----------------------------------------------------------------------+*/
807 void XeSPCRestartCallbacks(void)
808 /*----------------------------------------------------------------------+*/
810 SPC_Channel_Ptr channel;
813 channel=spc_activation_list;
816 if(channel->Input_Handler)
817 XeSPCAddInput(channel, (SbInputHandlerProc)NULL, NULL);
818 if(channel->Terminate_Handler)
819 XeSPCRegisterTerminator(channel, NULL, NULL);
820 channel=channel->next;
822 _DtSvcProcessUnlock();
827 *** Okay, now for a non-SPC routine. This one is dealing with setpgrp,
828 *** but it is here because it uses internal SPC routines.
832 /*----------------------------------------------------------------------+*/
833 XeSetpgrp(int read_current_termio)
834 /*----------------------------------------------------------------------+*/
837 return(SPC_Setpgrp(read_current_termio));
840 int XeSPCSendEOF(SPC_Channel_Ptr channel)
842 if(channel==SPC_ERROR) {
843 SPC_Error(SPC_Bad_Argument);
847 return(mempf0(channel, send_eof));
850 int XeSPCSetTermio(SPC_Channel_Ptr channel, int connection, int side,
851 struct termios *termio)
853 if(channel==SPC_ERROR || termio == NULL) {
854 SPC_Error(SPC_Bad_Argument);
858 return(mempf3(channel, set_termio, connection, side, termio));