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 librararies 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 /*----------------------------------------------------------------------+*/
121 XeSPCClose(SPC_Channel_Ptr channel)
122 /*----------------------------------------------------------------------+*/
124 if(channel==SPC_ERROR) {
125 SPC_Error(SPC_Bad_Argument);
129 if(IS_ACTIVE(channel))
130 XeSPCKillProcess(channel, FALSE);
132 if(IS_SPCIO_DELAY_CLOSE(channel->IOMode)) {
133 channel->IOMode |= SPCIO_DO_CLOSE;
137 channel->IOMode &= ~SPCIO_DO_CLOSE;
139 return(mempf0(channel, close));
143 /*----------------------------------------------------------------------+*/
144 XeSPCReset(SPC_Channel_Ptr channel)
145 /*----------------------------------------------------------------------+*/
148 if(channel==SPC_ERROR) {
149 SPC_Error(SPC_Bad_Argument);
153 if(IS_ACTIVE(channel))
154 XeSPCKillProcess(channel, FALSE);
156 channel->IOMode &= ~SPCIO_ACTIVE;
158 if(mempf0(channel, reset)==SPC_ERROR)
165 /*----------------------------------------------------------------------+*/
166 XeSPCRead(SPC_Channel_Ptr channel,
167 int connector, /* STDOUT or STDERR */
170 /*----------------------------------------------------------------------+*/
175 /* check for legal arguments */
177 if (channel==SPC_ERROR || !buffer ||
178 !(connector==STDOUT || connector==STDERR) ||
180 SPC_Error(SPC_Bad_Argument);
184 /* check state of the channel */
185 if (!IS_DATA(channel) || !IS_SPCIO_DATA(channel->wires[connector]->flags))
188 /* call the read filter */
191 n=(*channel->read_filter)(channel, connector, buffer, length);
192 } while(n == (EXCEPT_FLAG));
194 /* Check for an error */
203 /*----------------------------------------------------------------------+*/
204 XeSPCWrite(SPC_Channel_Ptr channel,
207 /*----------------------------------------------------------------------+*/
211 /* check for legal arguments */
213 if (channel==SPC_ERROR || !buffer || (length<0)) {
214 SPC_Error(SPC_Bad_Argument);
218 /* check the state of the channel */
220 if(!IS_ACTIVE(channel)) {
221 SPC_Error(SPC_Inactive_Channel);
225 /* call the write method */
227 n=mempf2(channel, write, buffer, length);
232 /*----------------------------------------------------------------------+*/
233 XeSPCActive(SPC_Channel_Ptr channel)
234 /*----------------------------------------------------------------------+*/
237 if (channel==SPC_ERROR) {
238 SPC_Error(SPC_Bad_Argument);
242 /* Is the passed channel active? */
243 return (IS_ACTIVE(channel));
246 /*----------------------------------------------------------------------+*/
247 XeSPCData(SPC_Channel_Ptr channel)
248 /*----------------------------------------------------------------------+*/
251 if(channel==SPC_ERROR) {
252 SPC_Error(SPC_Bad_Argument);
256 return(IS_DATA(channel));
260 /*----------------------------------------------------------------------+*/
261 XeSPCExecuteProcess(SPC_Channel_Ptr channel)
262 /*----------------------------------------------------------------------+*/
266 if (channel==SPC_ERROR) {
267 SPC_Error(SPC_Bad_Argument);
271 if(IS_ACTIVE(channel) || IS_DATA(channel)) {
272 SPC_Error(SPC_Active_Channel);
276 if((retval=mempf0(channel, exec_proc))==SPC_ERROR)
279 if (IS_SPCIO_WAIT(channel->IOMode)) {
280 /* Wait for sub-process to finish */
281 SPC_Wait_For_Termination(channel);
288 /*----------------------------------------------------------------------+*/
289 XeSPCSignalProcess(SPC_Channel_Ptr channel,
291 /*----------------------------------------------------------------------+*/
294 if ((channel==SPC_ERROR) ||
295 (channel->pid <= 0) ||
297 #ifdef NOT_IN_XPG3_YET
298 || (sig>=NSIG) /* Not a good idea for interoperability anyway */
301 SPC_Error(SPC_Bad_Argument);
305 /* This routine does not check to see if the channel is active. */
307 return(mempf1(channel, signal, sig));
310 /*----------------------------------------------------------------------+*/
311 XeSPCAddInput(SPC_Channel_Ptr channel,
312 SbInputHandlerProc handler,
313 /*----------------------------------------------------------------------+*/
317 SPC_Error(SPC_Bad_Argument);
321 if(!handler && !channel->Input_Handler)
325 channel->Input_Handler = handler;
326 channel->client_data = client_data;
329 return(mempf2(channel, add_input, handler, client_data));
334 /*----------------------------------------------------------------------+*/
335 XeSPCRegisterTerminator(SPC_Channel_Ptr channel,
336 SPC_TerminateHandlerType terminator,
338 /*----------------------------------------------------------------------+*/
341 SPC_Connection_Ptr conn;
343 if(channel==SPC_ERROR) {
344 SPC_Error(SPC_Bad_Argument);
348 /* Okay. If we have a pty channel, we have to check that we
349 have an input handler. I don't like doing this here, but ther
350 are no methods for this routine, so it has to be done. */
352 if(IS_SPCIO_PTY(channel->IOMode) && !channel->Input_Handler) {
353 SPC_Error(SPC_Bad_Argument);
357 channel->IOMode |= SPCIO_SYNC_TERMINATOR;
359 channel->Terminate_Handler = terminator;
360 channel->Terminate_Data = client_data;
363 conn=SPC_Channel_Terminator_Connection(channel);
364 if(conn->termination_id == -1)
365 SPC_XtAddInput(channel, &conn->termination_id, conn->sid,
366 SPC_Conditional_Packet_Handler, SPC_Terminator);
373 /*----------------------------------------------------------------------+*/
374 XeSPCAttach(SPC_Channel_Ptr channel,
376 /*----------------------------------------------------------------------+*/
379 if(channel==SPC_ERROR || pid<=0) {
380 SPC_Error(SPC_Bad_Argument);
384 return(mempf1(channel, attach, pid));
387 /*----------------------------------------------------------------------+*/
388 XeSPCDetach(SPC_Channel_Ptr channel)
389 /*----------------------------------------------------------------------+*/
391 if(channel == SPC_ERROR) {
392 SPC_Error(SPC_Bad_Argument);
397 channel->IOMode &= ~SPCIO_ACTIVE;
399 return XeSPCReset(channel);
406 *** "Composite" functions -- Those which are defined in terms of the
407 *** above primitives. One assumption is that the above primitives check
408 *** their arguments, so the composite functions need only check any
409 *** additional arguments.
415 ** Start with subprocess creation routines
419 /*----------------------------------------------------------------------+*/
420 XeSPCSpawn(XeString pathname,
421 XeString context_dir,
424 SPC_Channel_Ptr channel)
425 /*----------------------------------------------------------------------+*/
428 if(channel==SPC_ERROR) {
429 SPC_Error(SPC_Bad_Argument);
433 /* Assign the command arguments to this channel and attempt to Execute */
436 SPC_Free_Envp(channel->envp);
439 if(channel->argv && IS_SPCIO_DEALLOC_ARGV(channel->IOMode)) {
440 SPC_Free_Envp(channel->argv);
441 channel->IOMode &= ~SPCIO_DEALLOC_ARGV;
445 channel->context_dir=context_dir;
446 channel->argv = argv;
447 channel->path = pathname;
449 channel->envp=SPC_Create_Default_Envp(channel->envp);
450 channel->envp=SPC_Merge_Envp(channel->envp, envp);
451 channel->envp=SPC_Fixup_Environment(channel->envp, channel);
453 if(IS_SPCIO_SYSTEM(channel->IOMode))
454 if(SPC_MakeSystemCommand(channel)==SPC_ERROR)
457 /* Execute the process (XeSPCExecuteProcess will check arguments */
459 return(XeSPCExecuteProcess(channel));
462 /*----------------------------------------------------------------------+*/
463 SPC_Channel_Ptr XeSPCOpenAndSpawn(XeString hostname,
466 XeString context_dir,
469 /*----------------------------------------------------------------------+*/
471 /* This simply wraps together the two steps: Open and Spawn */
472 SPC_Channel_Ptr channel;
474 channel = XeSPCOpen(hostname, iomode);
475 if(channel==SPC_ERROR)
478 if (XeSPCSpawn(pathname, context_dir, argv, envp, channel)!=SPC_ERROR)
481 /* Close the channel and return SPC_ERROR */
489 ** Signalling routines
493 /*----------------------------------------------------------------------+*/
495 XeSPCKillProcesses(int wait)
496 /*----------------------------------------------------------------------+*/
498 /* Attempt to KILL all the sub-process that we know of */
502 for (spc = spc_activation_list; spc != (SPC_Channel_Ptr) NULL; spc = spc->next)
503 XeSPCKillProcess(spc, wait);
504 _DtSvcProcessUnlock();
507 /*----------------------------------------------------------------------+*/
508 XeSPCKillProcess(SPC_Channel_Ptr channel,
510 /*----------------------------------------------------------------------+*/
512 /* Attempt to KILL the sub-process (should we nullify the pid?) */
518 if(IS_ACTIVE(channel)) {
519 result = XeSPCSignalProcess(channel, SIGKILL);
520 if(result==SPC_ERROR)
522 if (wait || IS_SPCIO_SYNC_TERM(channel->IOMode))
523 SPC_Wait_For_Termination(channel);
529 /*----------------------------------------------------------------------+*/
530 XeSPCInterruptProcess(SPC_Channel_Ptr channel)
531 /*----------------------------------------------------------------------+*/
533 /* Attempt to INTerrupt the sub-process */
535 return(XeSPCSignalProcess(channel, SIGINT));
540 ** Process information routines.
544 /*----------------------------------------------------------------------+*/
545 XeString XeSPCGetDevice(SPC_Channel_Ptr channel,
548 /*----------------------------------------------------------------------+*/
551 SPC_Error(SPC_Bad_Argument);
555 /* Return the device name which corresponds to the side of a channel */
556 if (connector>=STDIN && connector<=STDERR) {
557 if (side == MASTER_SIDE)
558 return(channel->wires[connector]->master_name);
559 if (side == SLAVE_SIDE)
560 return(channel->wires[connector]->slave_name);
563 /* For no channel or incorrect side, return SPC_ERROR */
565 SPC_Error(SPC_Bad_Argument);
569 /*----------------------------------------------------------------------+*/
570 XeSPCGetProcessStatus(SPC_Channel_Ptr channel,
573 /*----------------------------------------------------------------------+*/
575 /* Fill in the type and cause of a process termination */
578 if(!channel || !type || !cause) {
579 SPC_Error(SPC_Bad_Argument);
583 low = channel->status & WAIT_STATUS_MASK;
584 high = (channel->status >> 8) & WAIT_STATUS_MASK;
590 case IS_WAIT_STATUS_STOPPED:
591 *type = SPC_PROCESS_STOPPED;
594 case IS_WAIT_STATUS_EXITED:
595 *type = SPC_PROCESS_EXITED;
601 *type = SPC_PROCESS_SIGNALLED;
605 } /* End switch on status */
607 /* When a process is still active return FALSE */
611 /*----------------------------------------------------------------------+*/
612 XeSPCGetPID(SPC_Channel_Ptr channel)
613 /*----------------------------------------------------------------------+*/
617 SPC_Error(SPC_Bad_Argument);
620 return (channel->pid);
623 /*----------------------------------------------------------------------+*/
624 int XeSPCGetLogfile(SPC_Channel_Ptr channel,
627 /*----------------------------------------------------------------------+*/
630 if(!channel || !IS_SPCIO_USE_LOGFILE(channel->IOMode)) {
631 SPC_Error(SPC_Bad_Argument);
634 *file=channel->logfile;
636 if(IS_REMOTE(channel))
637 *host=channel->connection->hostname;
639 *host= official_hostname;
640 _DtSvcProcessUnlock();
645 /*----------------------------------------------------------------------+*/
646 int XeSPCRemoveLogfile(SPC_Channel_Ptr channel)
647 /*----------------------------------------------------------------------+*/
651 SPC_Error(SPC_Bad_Argument);
655 return(mempf0(channel, remove_logfile));
660 ** Synchronous termination
664 #define SINGLE_PROT_DATA(req, channel, connector) \
665 if(!channel->queued_remote_data) \
666 channel->queued_remote_data=Xe_make_queue(FALSE); \
667 Xe_push_queue(channel->queued_remote_data, req); \
668 if(channel->Input_Handler) { \
669 SPC_Input_Handler(channel, connector); \
674 ** SPC_Process_Single_Prot_Request will return TRUE if it is okay
675 ** for the caller to free the protocol request.
679 /*----------------------------------------------------------------------+*/
680 SPC_Process_Single_Prot_Request(protocol_request_ptr req, SPC_Channel_Ptr channel)
681 /*----------------------------------------------------------------------+*/
684 switch(req->request_type) {
686 case APPLICATION_DIED:
688 READ_APPLICATION_DIED(req->dataptr, channel->status);
689 SPC_Channel_Terminated(channel);
692 case APPLICATION_STDOUT:
693 SINGLE_PROT_DATA(req, channel, STDOUT);
696 case APPLICATION_STDERR:
697 SINGLE_PROT_DATA(req, channel, STDERR);
701 SPC_Error(SPC_Internal_Error);
706 /*----------------------------------------------------------------------+*/
707 SPC_Channel_Ptr XeSPCHandleTerminator(int fd)
708 /*----------------------------------------------------------------------+*/
710 SPC_Connection_Ptr connection;
711 SPC_Channel_Ptr channel;
712 protocol_request_ptr prot;
713 XeQueue connection_queue;
715 if(!(connection=SPC_Lookup_Connection_Fd(fd))) {
716 SPC_Error(SPC_Bad_Argument);
720 if(!(prot=SPC_Read_Protocol(connection))) {
724 connection_queue=connection->queued_remote_data;
725 Xe_push_queue(connection_queue, prot);
727 while(prot=(protocol_request_ptr)Xe_pop_queue(connection_queue)) {
729 channel=prot->channel;
732 channel->IOMode |= SPCIO_DELAY_CLOSE;
734 if(SPC_Process_Single_Prot_Request(prot, channel))
735 SPC_Free_Protocol_Ptr(prot);
737 channel->IOMode &= ~SPCIO_DELAY_CLOSE;
738 if(IS_SPCIO_DO_CLOSE(channel->IOMode)) {
752 ** Use this call to get the file descriptor for
753 ** Synchronous termination.
757 /*----------------------------------------------------------------------+*/
758 XeSPCGetChannelSyncFd(SPC_Channel_Ptr channel)
759 /*----------------------------------------------------------------------+*/
762 SPC_Connection_Ptr conn;
764 if(channel==SPC_ERROR) {
765 SPC_Error(SPC_Bad_Argument);
769 conn=SPC_Channel_Terminator_Connection(channel);
776 *** Error Handling routines.
780 /*----------------------------------------------------------------------+*/
781 SPCError *XeSPCLookupError(int errnum)
782 /*----------------------------------------------------------------------+*/
784 if(errnum<SPC_Min_Error || errnum > SPC_Max_Error) {
785 SPC_Error(SPC_Bad_Argument);
789 return(SPC_Lookup_Error(errnum));
794 *** Temporarily shutdown input handlers
798 /*----------------------------------------------------------------------+*/
799 void XeSPCShutdownCallbacks(void)
800 /*----------------------------------------------------------------------+*/
802 SPC_Channel_Ptr channel;
803 SPC_Connection_Ptr conn;
807 channel=spc_activation_list;
808 conn=connection_list;
811 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
812 if(wirelist->read_toolkit_id != -1)
813 SPC_XtRemoveInput(&wirelist->read_toolkit_id, SPC_Input);
814 if(wirelist->except_toolkit_id != -1)
815 SPC_XtRemoveInput(&wirelist->except_toolkit_id, SPC_Exception);
817 channel=channel->next;
821 if(conn->termination_id != -1)
822 SPC_XtRemoveInput(&conn->termination_id, SPC_Terminator);
825 _DtSvcProcessUnlock();
828 /*----------------------------------------------------------------------+*/
829 void XeSPCRestartCallbacks(void)
830 /*----------------------------------------------------------------------+*/
832 SPC_Channel_Ptr channel;
835 channel=spc_activation_list;
838 if(channel->Input_Handler)
839 XeSPCAddInput(channel, (SbInputHandlerProc)NULL, NULL);
840 if(channel->Terminate_Handler)
841 XeSPCRegisterTerminator(channel, NULL, NULL);
842 channel=channel->next;
844 _DtSvcProcessUnlock();
849 *** Okay, now for a non-SPC routine. This one is dealing with setpgrp,
850 *** but it is here because it uses internal SPC routines.
854 /*----------------------------------------------------------------------+*/
855 XeSetpgrp(int read_current_termio)
856 /*----------------------------------------------------------------------+*/
859 return(SPC_Setpgrp(read_current_termio));
862 int XeSPCSendEOF(SPC_Channel_Ptr channel)
864 if(channel==SPC_ERROR) {
865 SPC_Error(SPC_Bad_Argument);
869 return(mempf0(channel, send_eof));
872 int XeSPCSetTermio(SPC_Channel_Ptr channel, int connection, int side,
873 struct termios *termio)
875 if(channel==SPC_ERROR || termio == NULL) {
876 SPC_Error(SPC_Bad_Argument);
880 return(mempf3(channel, set_termio, connection, side, termio));