2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * File: spc.c $XConsortium: spc.c /main/6 1996/06/21 17:33:08 ageorge $
27 * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
29 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
30 * (c) Copyright 1993, 1994 International Business Machines Corp. *
31 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
32 * (c) Copyright 1993, 1994 Novell, Inc. *
35 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
38 #include <SPC/spc-proto.h>
40 #include "DtSvcLock.h"
43 int SPC_Process_Single_Prot_Request (protocol_request_ptr req, SPC_Channel_Ptr channel);
46 /* This is the SPC error number variable */
47 /* extern int XeSPCErrorNumber; */
51 extern int SPC_Initialized;
52 extern SPC_Channel_Ptr spc_activation_list;
53 extern SPC_Connection_Ptr connection_list;
54 extern SPC_Connection_Ptr read_terminator;
55 extern XeString official_hostname;
57 int max_fds = 0; /* Set up below. */
59 /*----------------------------------------------------------------------+*/
62 /*----------------------------------------------------------------------+*/
67 max_fds = getdtablesize();
69 max_fds = (int)sysconf(_SC_OPEN_MAX);
71 _DtSvcProcessUnlock();
76 *** Sub-Process Control access routines. These are just functional
77 *** interfaces to the underlying methods.
81 /*----------------------------------------------------------------------+*/
82 SPC_Channel_Ptr XeSPCOpen(XeString hostname,
84 /*----------------------------------------------------------------------+*/
86 /* Attempt to open an SPC channel - return TRUE if we succeed */
87 SPC_Channel_Ptr channel;
89 /* Check for initialization */
92 if(SPC_Initialize() == SPC_ERROR) {
93 _DtSvcProcessUnlock();
96 _DtSvcProcessUnlock();
98 /* The user specified iomode needs to be processed before we can use it.
101 iomode=SPC_Transform_Iomode(iomode);
102 if(iomode==SPC_ERROR)
105 /* Get a new channel object */
107 channel=SPC_Initialize_Channel(hostname, iomode);
109 /* check that everything was okay */
111 if(channel==SPC_ERROR)
114 /* call the open method for it */
116 return((SPC_Channel_Ptr) mempf2(channel, open, iomode, hostname));
120 /*----------------------------------------------------------------------+*/
122 XeSPCClose(SPC_Channel_Ptr channel)
123 /*----------------------------------------------------------------------+*/
125 if(channel==SPC_ERROR) {
126 SPC_Error(SPC_Bad_Argument);
130 if(IS_ACTIVE(channel))
131 XeSPCKillProcess(channel, FALSE);
133 if(IS_SPCIO_DELAY_CLOSE(channel->IOMode)) {
134 channel->IOMode |= SPCIO_DO_CLOSE;
138 channel->IOMode &= ~SPCIO_DO_CLOSE;
140 return(mempf0(channel, close));
144 /*----------------------------------------------------------------------+*/
146 XeSPCReset(SPC_Channel_Ptr channel)
147 /*----------------------------------------------------------------------+*/
150 if(channel==SPC_ERROR) {
151 SPC_Error(SPC_Bad_Argument);
155 if(IS_ACTIVE(channel))
156 XeSPCKillProcess(channel, FALSE);
158 channel->IOMode &= ~SPCIO_ACTIVE;
160 if(mempf0(channel, reset)==SPC_ERROR)
167 /*----------------------------------------------------------------------+*/
169 XeSPCRead(SPC_Channel_Ptr channel,
170 int connector, /* STDOUT or STDERR */
173 /*----------------------------------------------------------------------+*/
178 /* check for legal arguments */
180 if (channel==SPC_ERROR || !buffer ||
181 !(connector==STDOUT || connector==STDERR) ||
183 SPC_Error(SPC_Bad_Argument);
187 /* check state of the channel */
188 if (!IS_DATA(channel) || !IS_SPCIO_DATA(channel->wires[connector]->flags))
191 /* call the read filter */
194 n=(*channel->read_filter)(channel, connector, buffer, length);
195 } while(n == (EXCEPT_FLAG));
197 /* Check for an error */
206 /*----------------------------------------------------------------------+*/
208 XeSPCWrite(SPC_Channel_Ptr channel,
211 /*----------------------------------------------------------------------+*/
215 /* check for legal arguments */
217 if (channel==SPC_ERROR || !buffer || (length<0)) {
218 SPC_Error(SPC_Bad_Argument);
222 /* check the state of the channel */
224 if(!IS_ACTIVE(channel)) {
225 SPC_Error(SPC_Inactive_Channel);
229 /* call the write method */
231 n=mempf2(channel, write, buffer, length);
236 /*----------------------------------------------------------------------+*/
238 XeSPCActive(SPC_Channel_Ptr channel)
239 /*----------------------------------------------------------------------+*/
242 if (channel==SPC_ERROR) {
243 SPC_Error(SPC_Bad_Argument);
247 /* Is the passed channel active? */
248 return (IS_ACTIVE(channel));
251 /*----------------------------------------------------------------------+*/
253 XeSPCData(SPC_Channel_Ptr channel)
254 /*----------------------------------------------------------------------+*/
257 if(channel==SPC_ERROR) {
258 SPC_Error(SPC_Bad_Argument);
262 return(IS_DATA(channel));
266 /*----------------------------------------------------------------------+*/
268 XeSPCExecuteProcess(SPC_Channel_Ptr channel)
269 /*----------------------------------------------------------------------+*/
273 if (channel==SPC_ERROR) {
274 SPC_Error(SPC_Bad_Argument);
278 if(IS_ACTIVE(channel) || IS_DATA(channel)) {
279 SPC_Error(SPC_Active_Channel);
283 if((retval=mempf0(channel, exec_proc))==SPC_ERROR)
286 if (IS_SPCIO_WAIT(channel->IOMode)) {
287 /* Wait for sub-process to finish */
288 SPC_Wait_For_Termination(channel);
295 /*----------------------------------------------------------------------+*/
297 XeSPCSignalProcess(SPC_Channel_Ptr channel,
299 /*----------------------------------------------------------------------+*/
302 if ((channel==SPC_ERROR) ||
303 (channel->pid <= 0) ||
305 #ifdef NOT_IN_XPG3_YET
306 || (sig>=NSIG) /* Not a good idea for interoperability anyway */
309 SPC_Error(SPC_Bad_Argument);
313 /* This routine does not check to see if the channel is active. */
315 return(mempf1(channel, signal, sig));
318 /*----------------------------------------------------------------------+*/
320 XeSPCAddInput(SPC_Channel_Ptr channel,
321 SbInputHandlerProc handler,
322 /*----------------------------------------------------------------------+*/
326 SPC_Error(SPC_Bad_Argument);
330 if(!handler && !channel->Input_Handler)
334 channel->Input_Handler = handler;
335 channel->client_data = client_data;
338 return(mempf2(channel, add_input, handler, client_data));
343 /*----------------------------------------------------------------------+*/
345 XeSPCRegisterTerminator(SPC_Channel_Ptr channel,
346 SPC_TerminateHandlerType terminator,
348 /*----------------------------------------------------------------------+*/
351 SPC_Connection_Ptr conn;
353 if(channel==SPC_ERROR) {
354 SPC_Error(SPC_Bad_Argument);
358 /* Okay. If we have a pty channel, we have to check that we
359 have an input handler. I don't like doing this here, but ther
360 are no methods for this routine, so it has to be done. */
362 if(IS_SPCIO_PTY(channel->IOMode) && !channel->Input_Handler) {
363 SPC_Error(SPC_Bad_Argument);
367 channel->IOMode |= SPCIO_SYNC_TERMINATOR;
369 channel->Terminate_Handler = terminator;
370 channel->Terminate_Data = client_data;
373 conn=SPC_Channel_Terminator_Connection(channel);
374 if(conn->termination_id == -1)
375 SPC_XtAddInput(channel, &conn->termination_id, conn->sid,
376 SPC_Conditional_Packet_Handler, SPC_Terminator);
383 /*----------------------------------------------------------------------+*/
385 XeSPCAttach(SPC_Channel_Ptr channel,
387 /*----------------------------------------------------------------------+*/
390 if(channel==SPC_ERROR || pid<=0) {
391 SPC_Error(SPC_Bad_Argument);
395 return(mempf1(channel, attach, pid));
398 /*----------------------------------------------------------------------+*/
400 XeSPCDetach(SPC_Channel_Ptr channel)
401 /*----------------------------------------------------------------------+*/
403 if(channel == SPC_ERROR) {
404 SPC_Error(SPC_Bad_Argument);
409 channel->IOMode &= ~SPCIO_ACTIVE;
411 return XeSPCReset(channel);
418 *** "Composite" functions -- Those which are defined in terms of the
419 *** above primitives. One assumption is that the above primitives check
420 *** their arguments, so the composite functions need only check any
421 *** additional arguments.
427 ** Start with subprocess creation routines
431 /*----------------------------------------------------------------------+*/
433 XeSPCSpawn(XeString pathname,
434 XeString context_dir,
437 SPC_Channel_Ptr channel)
438 /*----------------------------------------------------------------------+*/
441 if(channel==SPC_ERROR) {
442 SPC_Error(SPC_Bad_Argument);
446 /* Assign the command arguments to this channel and attempt to Execute */
449 SPC_Free_Envp(channel->envp);
452 if(channel->argv && IS_SPCIO_DEALLOC_ARGV(channel->IOMode)) {
453 SPC_Free_Envp(channel->argv);
454 channel->IOMode &= ~SPCIO_DEALLOC_ARGV;
458 channel->context_dir=context_dir;
459 channel->argv = argv;
460 channel->path = pathname;
462 channel->envp=SPC_Create_Default_Envp(channel->envp);
463 channel->envp=SPC_Merge_Envp(channel->envp, envp);
464 channel->envp=SPC_Fixup_Environment(channel->envp, channel);
466 if(IS_SPCIO_SYSTEM(channel->IOMode))
467 if(SPC_MakeSystemCommand(channel)==SPC_ERROR)
470 /* Execute the process (XeSPCExecuteProcess will check arguments */
472 return(XeSPCExecuteProcess(channel));
475 /*----------------------------------------------------------------------+*/
476 SPC_Channel_Ptr XeSPCOpenAndSpawn(XeString hostname,
479 XeString context_dir,
482 /*----------------------------------------------------------------------+*/
484 /* This simply wraps together the two steps: Open and Spawn */
485 SPC_Channel_Ptr channel;
487 channel = XeSPCOpen(hostname, iomode);
488 if(channel==SPC_ERROR)
491 if (XeSPCSpawn(pathname, context_dir, argv, envp, channel)!=SPC_ERROR)
494 /* Close the channel and return SPC_ERROR */
502 ** Signalling routines
506 /*----------------------------------------------------------------------+*/
508 XeSPCKillProcesses(int wait)
509 /*----------------------------------------------------------------------+*/
511 /* Attempt to KILL all the sub-process that we know of */
515 for (spc = spc_activation_list; spc != (SPC_Channel_Ptr) NULL; spc = spc->next)
516 XeSPCKillProcess(spc, wait);
517 _DtSvcProcessUnlock();
520 /*----------------------------------------------------------------------+*/
522 XeSPCKillProcess(SPC_Channel_Ptr channel,
524 /*----------------------------------------------------------------------+*/
526 /* Attempt to KILL the sub-process (should we nullify the pid?) */
532 if(IS_ACTIVE(channel)) {
533 result = XeSPCSignalProcess(channel, SIGKILL);
534 if(result==SPC_ERROR)
536 if (wait || IS_SPCIO_SYNC_TERM(channel->IOMode))
537 SPC_Wait_For_Termination(channel);
543 /*----------------------------------------------------------------------+*/
545 XeSPCInterruptProcess(SPC_Channel_Ptr channel)
546 /*----------------------------------------------------------------------+*/
548 /* Attempt to INTerrupt the sub-process */
550 return(XeSPCSignalProcess(channel, SIGINT));
555 ** Process information routines.
559 /*----------------------------------------------------------------------+*/
560 XeString XeSPCGetDevice(SPC_Channel_Ptr channel,
563 /*----------------------------------------------------------------------+*/
566 SPC_Error(SPC_Bad_Argument);
570 /* Return the device name which corresponds to the side of a channel */
571 if (connector>=STDIN && connector<=STDERR) {
572 if (side == MASTER_SIDE)
573 return(channel->wires[connector]->master_name);
574 if (side == SLAVE_SIDE)
575 return(channel->wires[connector]->slave_name);
578 /* For no channel or incorrect side, return SPC_ERROR */
580 SPC_Error(SPC_Bad_Argument);
584 /*----------------------------------------------------------------------+*/
586 XeSPCGetProcessStatus(SPC_Channel_Ptr channel,
589 /*----------------------------------------------------------------------+*/
591 /* Fill in the type and cause of a process termination */
594 if(!channel || !type || !cause) {
595 SPC_Error(SPC_Bad_Argument);
599 low = channel->status & WAIT_STATUS_MASK;
600 high = (channel->status >> 8) & WAIT_STATUS_MASK;
606 case IS_WAIT_STATUS_STOPPED:
607 *type = SPC_PROCESS_STOPPED;
610 case IS_WAIT_STATUS_EXITED:
611 *type = SPC_PROCESS_EXITED;
617 *type = SPC_PROCESS_SIGNALLED;
621 } /* End switch on status */
623 /* When a process is still active return FALSE */
627 /*----------------------------------------------------------------------+*/
629 XeSPCGetPID(SPC_Channel_Ptr channel)
630 /*----------------------------------------------------------------------+*/
634 SPC_Error(SPC_Bad_Argument);
637 return (channel->pid);
640 /*----------------------------------------------------------------------+*/
641 int XeSPCGetLogfile(SPC_Channel_Ptr channel,
644 /*----------------------------------------------------------------------+*/
647 if(!channel || !IS_SPCIO_USE_LOGFILE(channel->IOMode)) {
648 SPC_Error(SPC_Bad_Argument);
651 *file=channel->logfile;
653 if(IS_REMOTE(channel))
654 *host=channel->connection->hostname;
656 *host= official_hostname;
657 _DtSvcProcessUnlock();
662 /*----------------------------------------------------------------------+*/
663 int XeSPCRemoveLogfile(SPC_Channel_Ptr channel)
664 /*----------------------------------------------------------------------+*/
668 SPC_Error(SPC_Bad_Argument);
672 return(mempf0(channel, remove_logfile));
677 ** Synchronous termination
681 #define SINGLE_PROT_DATA(req, channel, connector) \
682 if(!channel->queued_remote_data) \
683 channel->queued_remote_data=Xe_make_queue(FALSE); \
684 Xe_push_queue(channel->queued_remote_data, req); \
685 if(channel->Input_Handler) { \
686 SPC_Input_Handler(channel, connector); \
691 ** SPC_Process_Single_Prot_Request will return TRUE if it is okay
692 ** for the caller to free the protocol request.
696 /*----------------------------------------------------------------------+*/
698 SPC_Process_Single_Prot_Request(protocol_request_ptr req, SPC_Channel_Ptr channel)
699 /*----------------------------------------------------------------------+*/
702 switch(req->request_type) {
704 case APPLICATION_DIED:
706 READ_APPLICATION_DIED(req->dataptr, channel->status);
707 SPC_Channel_Terminated(channel);
710 case APPLICATION_STDOUT:
711 SINGLE_PROT_DATA(req, channel, STDOUT);
714 case APPLICATION_STDERR:
715 SINGLE_PROT_DATA(req, channel, STDERR);
719 SPC_Error(SPC_Internal_Error);
724 /*----------------------------------------------------------------------+*/
725 SPC_Channel_Ptr XeSPCHandleTerminator(int fd)
726 /*----------------------------------------------------------------------+*/
728 SPC_Connection_Ptr connection;
729 SPC_Channel_Ptr channel;
730 protocol_request_ptr prot;
731 XeQueue connection_queue;
733 if(!(connection=SPC_Lookup_Connection_Fd(fd))) {
734 SPC_Error(SPC_Bad_Argument);
738 if(!(prot=SPC_Read_Protocol(connection))) {
742 connection_queue=connection->queued_remote_data;
743 Xe_push_queue(connection_queue, prot);
745 while((prot=(protocol_request_ptr)Xe_pop_queue(connection_queue))) {
747 channel=prot->channel;
750 channel->IOMode |= SPCIO_DELAY_CLOSE;
752 if(SPC_Process_Single_Prot_Request(prot, channel))
753 SPC_Free_Protocol_Ptr(prot);
755 channel->IOMode &= ~SPCIO_DELAY_CLOSE;
756 if(IS_SPCIO_DO_CLOSE(channel->IOMode)) {
770 ** Use this call to get the file descriptor for
771 ** Synchronous termination.
775 /*----------------------------------------------------------------------+*/
777 XeSPCGetChannelSyncFd(SPC_Channel_Ptr channel)
778 /*----------------------------------------------------------------------+*/
781 SPC_Connection_Ptr conn;
783 if(channel==SPC_ERROR) {
784 SPC_Error(SPC_Bad_Argument);
788 conn=SPC_Channel_Terminator_Connection(channel);
795 *** Error Handling routines.
799 /*----------------------------------------------------------------------+*/
800 SPCError *XeSPCLookupError(int errnum)
801 /*----------------------------------------------------------------------+*/
803 if(errnum<SPC_Min_Error || errnum > SPC_Max_Error) {
804 SPC_Error(SPC_Bad_Argument);
808 return(SPC_Lookup_Error(errnum));
813 *** Temporarily shutdown input handlers
817 /*----------------------------------------------------------------------+*/
818 void XeSPCShutdownCallbacks(void)
819 /*----------------------------------------------------------------------+*/
821 SPC_Channel_Ptr channel;
822 SPC_Connection_Ptr conn;
826 channel=spc_activation_list;
827 conn=connection_list;
830 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
831 if(wirelist->read_toolkit_id != -1)
832 SPC_XtRemoveInput(&wirelist->read_toolkit_id, SPC_Input);
833 if(wirelist->except_toolkit_id != -1)
834 SPC_XtRemoveInput(&wirelist->except_toolkit_id, SPC_Exception);
836 channel=channel->next;
840 if(conn->termination_id != -1)
841 SPC_XtRemoveInput(&conn->termination_id, SPC_Terminator);
844 _DtSvcProcessUnlock();
847 /*----------------------------------------------------------------------+*/
848 void XeSPCRestartCallbacks(void)
849 /*----------------------------------------------------------------------+*/
851 SPC_Channel_Ptr channel;
854 channel=spc_activation_list;
857 if(channel->Input_Handler)
858 XeSPCAddInput(channel, (SbInputHandlerProc)NULL, NULL);
859 if(channel->Terminate_Handler)
860 XeSPCRegisterTerminator(channel, NULL, NULL);
861 channel=channel->next;
863 _DtSvcProcessUnlock();
868 *** Okay, now for a non-SPC routine. This one is dealing with setpgrp,
869 *** but it is here because it uses internal SPC routines.
873 /*----------------------------------------------------------------------+*/
875 XeSetpgrp(int read_current_termio)
876 /*----------------------------------------------------------------------+*/
879 return(SPC_Setpgrp(read_current_termio));
882 int XeSPCSendEOF(SPC_Channel_Ptr channel)
884 if(channel==SPC_ERROR) {
885 SPC_Error(SPC_Bad_Argument);
889 return(mempf0(channel, send_eof));
892 int XeSPCSetTermio(SPC_Channel_Ptr channel, int connection, int side,
893 struct termios *termio)
895 if(channel==SPC_ERROR || termio == NULL) {
896 SPC_Error(SPC_Bad_Argument);
900 return(mempf3(channel, set_termio, connection, side, termio));