Build with debug symbols enabled.
[oweals/cde.git] / cde / lib / DtSvc / DtEncap / spc.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /*
24  * File:         spc.c $XConsortium: spc.c /main/6 1996/06/21 17:33:08 ageorge $
25  * Language:     C
26  *
27  * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
28  *
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.                                *
33  */
34
35 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
36 #include <signal.h>
37 #include <SPC/spcP.h>
38 #include <SPC/spc-proto.h>
39 #include <bms/spc.h>
40 #include "DtSvcLock.h"
41
42 /* spc.c */
43 int SPC_Process_Single_Prot_Request (protocol_request_ptr req, SPC_Channel_Ptr channel);
44
45
46 /* This is the SPC error number variable */
47 /* extern int XeSPCErrorNumber; */
48
49 /* Externals */
50
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;
56
57 int max_fds = 0;   /* Set up below. */
58
59 /*----------------------------------------------------------------------+*/
60 void 
61 spc_init_fds(void)
62 /*----------------------------------------------------------------------+*/
63 {
64    _DtSvcProcessLock();
65    if (!max_fds)
66 #     ifdef __bsd
67          max_fds = getdtablesize();
68 #     else
69          max_fds = (int)sysconf(_SC_OPEN_MAX);
70 #     endif
71    _DtSvcProcessUnlock();
72 }
73
74 /*
75  ***
76  *** Sub-Process Control access routines.  These are just functional
77  *** interfaces to the underlying methods.
78  ***
79 */
80
81 /*----------------------------------------------------------------------+*/
82 SPC_Channel_Ptr XeSPCOpen(XeString hostname,
83                           int iomode)
84 /*----------------------------------------------------------------------+*/
85 {
86   /* Attempt to open an SPC channel - return TRUE if we succeed */
87   SPC_Channel_Ptr channel;
88
89   /* Check for initialization */
90   _DtSvcProcessLock();
91   if(!SPC_Initialized)
92       if(SPC_Initialize() == SPC_ERROR) {
93           _DtSvcProcessUnlock();
94           return(SPC_ERROR);
95       }
96   _DtSvcProcessUnlock();
97
98   /* The user specified iomode needs to be processed before we can use it.
99      Process the puppy. */
100
101   iomode=SPC_Transform_Iomode(iomode);
102   if(iomode==SPC_ERROR)
103     return(SPC_ERROR);
104        
105   /* Get a new channel object */
106   
107   channel=SPC_Initialize_Channel(hostname, iomode);
108
109   /* check that everything was okay */
110   
111   if(channel==SPC_ERROR)
112     return(SPC_ERROR);
113   
114   /* call the open method for it */
115
116   return((SPC_Channel_Ptr) mempf2(channel, open, iomode, hostname));
117
118 }
119
120 /*----------------------------------------------------------------------+*/
121 XeSPCClose(SPC_Channel_Ptr channel)
122 /*----------------------------------------------------------------------+*/
123 {
124   if(channel==SPC_ERROR) {
125     SPC_Error(SPC_Bad_Argument);
126     return(SPC_ERROR);
127   }
128
129   if(IS_ACTIVE(channel))
130     XeSPCKillProcess(channel, FALSE);
131
132   if(IS_SPCIO_DELAY_CLOSE(channel->IOMode)) {
133     channel->IOMode |= SPCIO_DO_CLOSE;
134     return(TRUE);
135   }
136   
137   channel->IOMode &= ~SPCIO_DO_CLOSE;
138   
139   return(mempf0(channel, close));
140   
141 }
142
143 /*----------------------------------------------------------------------+*/
144 XeSPCReset(SPC_Channel_Ptr channel)
145 /*----------------------------------------------------------------------+*/
146 {
147
148   if(channel==SPC_ERROR) {
149     SPC_Error(SPC_Bad_Argument);
150     return(SPC_ERROR);
151   }
152
153   if(IS_ACTIVE(channel))
154     XeSPCKillProcess(channel, FALSE);
155   
156   channel->IOMode &= ~SPCIO_ACTIVE;
157
158   if(mempf0(channel, reset)==SPC_ERROR)
159     return(SPC_ERROR);
160   
161   return(TRUE);
162   
163 }
164
165 /*----------------------------------------------------------------------+*/
166 XeSPCRead(SPC_Channel_Ptr channel,
167           int connector,           /* STDOUT or STDERR */
168           XeString buffer,
169           int length)
170 /*----------------------------------------------------------------------+*/
171 {
172
173   int n;
174   
175   /* check for legal arguments */
176   
177   if (channel==SPC_ERROR || !buffer ||
178       !(connector==STDOUT || connector==STDERR) ||
179       (length < 0)) {
180     SPC_Error(SPC_Bad_Argument);
181     return(SPC_ERROR);
182   }
183
184   /* check state of the channel */
185   if (!IS_DATA(channel) || !IS_SPCIO_DATA(channel->wires[connector]->flags))
186     return(0);
187   
188   /* call the read filter */
189
190   do {
191     n=(*channel->read_filter)(channel, connector, buffer, length);
192   } while(n == (EXCEPT_FLAG));
193   
194   /* Check for an error */
195
196   if (n == SPC_ERROR)
197     return(SPC_ERROR);
198   
199   return(n);
200 }
201
202   
203 /*----------------------------------------------------------------------+*/
204 XeSPCWrite(SPC_Channel_Ptr channel,
205            XeString buffer,
206            int length)
207 /*----------------------------------------------------------------------+*/
208 {
209   int n;
210   
211   /* check for legal arguments */
212   
213   if (channel==SPC_ERROR || !buffer || (length<0)) {
214     SPC_Error(SPC_Bad_Argument);
215     return(SPC_ERROR);
216   }
217
218   /* check the state of the channel */
219
220   if(!IS_ACTIVE(channel)) {
221     SPC_Error(SPC_Inactive_Channel);
222     return(SPC_ERROR);
223   }
224   
225   /* call the write method */
226   
227   n=mempf2(channel, write, buffer, length);
228   
229   return(n);
230 }
231
232 /*----------------------------------------------------------------------+*/
233 XeSPCActive(SPC_Channel_Ptr channel)
234 /*----------------------------------------------------------------------+*/
235 {
236
237   if (channel==SPC_ERROR) {
238     SPC_Error(SPC_Bad_Argument);
239     return(SPC_ERROR);
240   }
241   
242   /* Is the passed channel active? */
243   return (IS_ACTIVE(channel));
244 }
245
246 /*----------------------------------------------------------------------+*/
247 XeSPCData(SPC_Channel_Ptr channel)
248 /*----------------------------------------------------------------------+*/
249 {
250
251   if(channel==SPC_ERROR) {
252     SPC_Error(SPC_Bad_Argument);
253     return(SPC_ERROR);
254   }
255   
256   return(IS_DATA(channel));
257
258 }
259
260 /*----------------------------------------------------------------------+*/
261 XeSPCExecuteProcess(SPC_Channel_Ptr channel)
262 /*----------------------------------------------------------------------+*/
263 {
264   int retval;
265
266   if (channel==SPC_ERROR) {
267     SPC_Error(SPC_Bad_Argument);
268     return(SPC_ERROR);
269   }
270   
271   if(IS_ACTIVE(channel) || IS_DATA(channel)) {
272     SPC_Error(SPC_Active_Channel);
273     return(SPC_ERROR);
274   }
275
276   if((retval=mempf0(channel, exec_proc))==SPC_ERROR)
277     return(SPC_ERROR);
278
279   if (IS_SPCIO_WAIT(channel->IOMode)) {
280     /* Wait for sub-process to finish */
281     SPC_Wait_For_Termination(channel);
282   }
283   
284   return(retval);
285
286 }
287
288 /*----------------------------------------------------------------------+*/
289 XeSPCSignalProcess(SPC_Channel_Ptr channel,
290                    int sig)
291 /*----------------------------------------------------------------------+*/
292 {
293   
294   if ((channel==SPC_ERROR) ||
295       (channel->pid <= 0) ||
296       (sig < 0) 
297 #ifdef NOT_IN_XPG3_YET      
298       || (sig>=NSIG)    /* Not a good idea for interoperability anyway */
299 #endif
300       ) {
301     SPC_Error(SPC_Bad_Argument);
302     return(SPC_ERROR);
303   }
304
305   /* This routine does not check to see if the channel is active. */
306
307   return(mempf1(channel, signal, sig));
308 }
309
310 /*----------------------------------------------------------------------+*/
311 XeSPCAddInput(SPC_Channel_Ptr   channel,
312               SbInputHandlerProc handler,
313 /*----------------------------------------------------------------------+*/
314               void *            client_data)
315 {
316   if(!channel) {
317     SPC_Error(SPC_Bad_Argument);
318     return(SPC_ERROR);
319   }
320   
321   if(!handler && !channel->Input_Handler)
322     return(TRUE);
323
324   if(handler) {
325     channel->Input_Handler = handler;
326     channel->client_data   = client_data;
327   }
328
329   return(mempf2(channel, add_input, handler, client_data));
330     
331 }
332
333
334 /*----------------------------------------------------------------------+*/
335 XeSPCRegisterTerminator(SPC_Channel_Ptr                 channel,
336                         SPC_TerminateHandlerType        terminator,
337                         void *                          client_data)
338 /*----------------------------------------------------------------------+*/
339 {
340
341   SPC_Connection_Ptr conn;
342   
343   if(channel==SPC_ERROR) {
344     SPC_Error(SPC_Bad_Argument);
345     return(SPC_ERROR);
346   }
347
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. */
351
352   if(IS_SPCIO_PTY(channel->IOMode) && !channel->Input_Handler) {
353     SPC_Error(SPC_Bad_Argument);
354     return(SPC_ERROR);
355   }
356
357   channel->IOMode |= SPCIO_SYNC_TERMINATOR;
358   if(terminator) {
359     channel->Terminate_Handler = terminator;
360     channel->Terminate_Data    = client_data;
361   }
362
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);
367   
368   return(TRUE);
369   
370 }
371
372
373 /*----------------------------------------------------------------------+*/
374 XeSPCAttach(SPC_Channel_Ptr channel,
375             int pid)
376 /*----------------------------------------------------------------------+*/
377
378 {
379   if(channel==SPC_ERROR || pid<=0) {
380     SPC_Error(SPC_Bad_Argument);
381     return(SPC_ERROR);
382   }
383
384   return(mempf1(channel, attach, pid));
385 }
386
387 /*----------------------------------------------------------------------+*/
388 XeSPCDetach(SPC_Channel_Ptr channel)
389 /*----------------------------------------------------------------------+*/
390 {
391   if(channel == SPC_ERROR) {
392     SPC_Error(SPC_Bad_Argument);
393     return(SPC_ERROR);
394   }
395   
396   channel->pid = 0;
397   channel->IOMode &= ~SPCIO_ACTIVE;
398
399   return XeSPCReset(channel);
400 }
401   
402
403  
404 /*
405  ***
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.
410  ***
411 */
412
413 /*
414  **
415  ** Start with subprocess creation routines
416  **
417 */
418
419 /*----------------------------------------------------------------------+*/
420 XeSPCSpawn(XeString pathname,
421            XeString context_dir,
422            XeString *argv,
423            XeString *envp,
424            SPC_Channel_Ptr channel)
425 /*----------------------------------------------------------------------+*/
426 {
427
428   if(channel==SPC_ERROR) {
429     SPC_Error(SPC_Bad_Argument);
430     return(SPC_ERROR);
431   }
432   
433   /* Assign the command arguments to this channel and attempt to Execute */
434     
435   if(channel->envp) {
436     SPC_Free_Envp(channel->envp);
437     channel->envp=NULL;
438   }
439   if(channel->argv && IS_SPCIO_DEALLOC_ARGV(channel->IOMode)) {
440     SPC_Free_Envp(channel->argv);
441     channel->IOMode &= ~SPCIO_DEALLOC_ARGV;
442     channel->argv=NULL;
443   }
444   
445   channel->context_dir=context_dir;
446   channel->argv = argv;
447   channel->path = pathname;
448
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);
452
453   if(IS_SPCIO_SYSTEM(channel->IOMode))
454     if(SPC_MakeSystemCommand(channel)==SPC_ERROR)
455       return(SPC_ERROR);
456   
457   /* Execute the process (XeSPCExecuteProcess will check arguments */
458   
459   return(XeSPCExecuteProcess(channel));
460 }
461
462 /*----------------------------------------------------------------------+*/
463 SPC_Channel_Ptr XeSPCOpenAndSpawn(XeString hostname,
464                                   int iomode,
465                                   XeString pathname,
466                                   XeString context_dir,
467                                   XeString *argv,
468                                   XeString *envp)
469 /*----------------------------------------------------------------------+*/
470 {
471   /* This simply wraps together the two steps: Open and Spawn */
472   SPC_Channel_Ptr channel;
473
474   channel = XeSPCOpen(hostname, iomode);
475   if(channel==SPC_ERROR)
476     return(SPC_ERROR);
477   
478   if (XeSPCSpawn(pathname, context_dir, argv, envp, channel)!=SPC_ERROR)
479     return(channel);
480
481   /* Close the channel and return SPC_ERROR */
482   XeSPCClose(channel);
483   return(SPC_ERROR);
484   
485 }
486
487 /*
488  **
489  ** Signalling routines
490  **
491 */
492
493 /*----------------------------------------------------------------------+*/
494 void
495 XeSPCKillProcesses(int wait)
496 /*----------------------------------------------------------------------+*/
497 {
498   /* Attempt to KILL all the sub-process that we know of */
499   SPC_Channel_Ptr spc;
500
501   _DtSvcProcessLock();
502   for (spc = spc_activation_list; spc != (SPC_Channel_Ptr) NULL; spc = spc->next)
503     XeSPCKillProcess(spc, wait);
504   _DtSvcProcessUnlock();
505 }
506
507 /*----------------------------------------------------------------------+*/
508 XeSPCKillProcess(SPC_Channel_Ptr channel,
509                  int wait)
510 /*----------------------------------------------------------------------+*/
511 {
512   /* Attempt to KILL the sub-process (should we nullify the pid?) */
513   int result;
514
515   if(!channel)
516     return(FALSE);
517
518   if(IS_ACTIVE(channel)) {
519     result = XeSPCSignalProcess(channel, SIGKILL);
520     if(result==SPC_ERROR)
521       return(SPC_ERROR);
522     if (wait || IS_SPCIO_SYNC_TERM(channel->IOMode))
523       SPC_Wait_For_Termination(channel);
524     return result;
525   } else
526     return(TRUE);
527 }
528
529 /*----------------------------------------------------------------------+*/
530 XeSPCInterruptProcess(SPC_Channel_Ptr channel)
531 /*----------------------------------------------------------------------+*/
532 {
533   /* Attempt to INTerrupt the sub-process */
534   
535   return(XeSPCSignalProcess(channel, SIGINT));
536 }
537
538 /*
539  **
540  ** Process information routines.
541  **
542 */
543
544 /*----------------------------------------------------------------------+*/
545 XeString XeSPCGetDevice(SPC_Channel_Ptr channel,
546                               int connector, 
547                               int side)
548 /*----------------------------------------------------------------------+*/
549 {
550   if(!channel) {
551     SPC_Error(SPC_Bad_Argument);
552     return(SPC_ERROR);
553   }
554   
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);
561   }
562   
563   /* For no channel or incorrect side, return SPC_ERROR */
564   
565   SPC_Error(SPC_Bad_Argument);
566   return(SPC_ERROR);
567 }
568
569 /*----------------------------------------------------------------------+*/
570 XeSPCGetProcessStatus(SPC_Channel_Ptr channel,
571                       int *type, 
572                       int *cause)
573 /*----------------------------------------------------------------------+*/
574 {
575   /* Fill in the type and cause of a process termination */
576   int high, low;
577
578   if(!channel || !type || !cause) {
579     SPC_Error(SPC_Bad_Argument);
580     return(SPC_ERROR);
581   }
582     
583   low = channel->status & WAIT_STATUS_MASK;
584   high = (channel->status >> 8) & WAIT_STATUS_MASK;
585
586   *cause = high;
587
588   switch (low) {
589
590   case IS_WAIT_STATUS_STOPPED:
591     *type = SPC_PROCESS_STOPPED;
592     break;
593
594   case IS_WAIT_STATUS_EXITED:
595     *type = SPC_PROCESS_EXITED;
596     break;
597
598   default:
599     if (!*cause) {
600       *cause = low;
601       *type = SPC_PROCESS_SIGNALLED;
602     }
603     break;
604
605   }                             /* End switch on status */
606
607   /* When a process is still active return FALSE */
608   return(TRUE);
609 }
610
611 /*----------------------------------------------------------------------+*/
612 XeSPCGetPID(SPC_Channel_Ptr channel)
613 /*----------------------------------------------------------------------+*/
614 {
615
616   if(!channel) {
617     SPC_Error(SPC_Bad_Argument);
618     return(SPC_ERROR);
619   }
620   return (channel->pid);
621 }
622
623 /*----------------------------------------------------------------------+*/
624 int XeSPCGetLogfile(SPC_Channel_Ptr channel,
625                     XeString *host, 
626                     XeString *file)
627 /*----------------------------------------------------------------------+*/
628 {
629
630   if(!channel || !IS_SPCIO_USE_LOGFILE(channel->IOMode)) {
631     SPC_Error(SPC_Bad_Argument);
632     return(SPC_ERROR);
633   }
634   *file=channel->logfile;
635   _DtSvcProcessLock();
636   if(IS_REMOTE(channel))
637     *host=channel->connection->hostname;
638   else
639     *host= official_hostname;
640   _DtSvcProcessUnlock();
641   return(TRUE);
642   
643 }
644
645 /*----------------------------------------------------------------------+*/
646 int XeSPCRemoveLogfile(SPC_Channel_Ptr channel)
647 /*----------------------------------------------------------------------+*/
648
649
650   if(!channel) {
651     SPC_Error(SPC_Bad_Argument);
652     return(SPC_ERROR);
653   }
654   
655   return(mempf0(channel, remove_logfile));
656 }
657
658 /*
659  **
660  ** Synchronous termination
661  **
662 */
663
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);         \
670   }
671
672 /*
673  **
674  ** SPC_Process_Single_Prot_Request will return TRUE if it is okay
675  ** for the caller to free the protocol request.
676  **
677 */
678
679 /*----------------------------------------------------------------------+*/
680 SPC_Process_Single_Prot_Request(protocol_request_ptr req, SPC_Channel_Ptr channel)
681 /*----------------------------------------------------------------------+*/
682 {
683
684   switch(req->request_type) {
685     
686   case APPLICATION_DIED:
687     
688     READ_APPLICATION_DIED(req->dataptr, channel->status);
689     SPC_Channel_Terminated(channel);
690     return(TRUE);
691     
692   case APPLICATION_STDOUT:
693     SINGLE_PROT_DATA(req, channel, STDOUT);
694     return(FALSE);
695     
696   case APPLICATION_STDERR:
697     SINGLE_PROT_DATA(req, channel, STDERR);
698     return(FALSE);
699       
700   default:
701     SPC_Error(SPC_Internal_Error);
702     return(SPC_ERROR);
703   }
704 }    
705   
706 /*----------------------------------------------------------------------+*/
707 SPC_Channel_Ptr XeSPCHandleTerminator(int fd)
708 /*----------------------------------------------------------------------+*/
709 {
710   SPC_Connection_Ptr connection;
711   SPC_Channel_Ptr channel;
712   protocol_request_ptr prot;
713   XeQueue connection_queue;
714   
715   if(!(connection=SPC_Lookup_Connection_Fd(fd))) {
716     SPC_Error(SPC_Bad_Argument);
717     return(SPC_ERROR);
718   }
719   
720   if(!(prot=SPC_Read_Protocol(connection))) {
721     return(SPC_ERROR);
722   }
723
724   connection_queue=connection->queued_remote_data;
725   Xe_push_queue(connection_queue, prot);
726
727   while(prot=(protocol_request_ptr)Xe_pop_queue(connection_queue)) {
728     
729     channel=prot->channel;
730
731     if(channel) {
732       channel->IOMode |= SPCIO_DELAY_CLOSE;
733       
734       if(SPC_Process_Single_Prot_Request(prot, channel))
735         SPC_Free_Protocol_Ptr(prot);
736       
737       channel->IOMode &= ~SPCIO_DELAY_CLOSE;
738       if(IS_SPCIO_DO_CLOSE(channel->IOMode)) {
739         XeSPCClose(channel);
740         channel = NULL;
741       }
742     }
743     
744   }
745   
746   return(channel);
747   
748 }
749
750 /*
751  **
752  ** Use this call to get the file descriptor for
753  ** Synchronous termination.
754  **
755 */
756
757 /*----------------------------------------------------------------------+*/
758 XeSPCGetChannelSyncFd(SPC_Channel_Ptr channel)
759 /*----------------------------------------------------------------------+*/
760 {
761
762   SPC_Connection_Ptr conn;
763
764   if(channel==SPC_ERROR) {
765     SPC_Error(SPC_Bad_Argument);
766     return(SPC_ERROR);
767   }
768   
769   conn=SPC_Channel_Terminator_Connection(channel);
770   return(conn->sid);
771   
772 }
773
774 /*
775  ***
776  *** Error Handling routines.
777  ***
778 */
779
780 /*----------------------------------------------------------------------+*/
781 SPCError *XeSPCLookupError(int errnum)
782 /*----------------------------------------------------------------------+*/
783 {
784   if(errnum<SPC_Min_Error || errnum > SPC_Max_Error) {
785     SPC_Error(SPC_Bad_Argument);
786     return(SPC_ERROR); 
787   }
788    
789   return(SPC_Lookup_Error(errnum));
790 }
791
792 /*
793  ***
794  *** Temporarily shutdown input handlers
795  ***
796 */
797
798 /*----------------------------------------------------------------------+*/
799 void XeSPCShutdownCallbacks(void)
800 /*----------------------------------------------------------------------+*/
801 {
802   SPC_Channel_Ptr channel;
803   SPC_Connection_Ptr conn;
804   Wire *wirelist;
805
806   _DtSvcProcessLock();
807   channel=spc_activation_list;
808   conn=connection_list;
809
810   while(channel) {
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);
816     }
817     channel=channel->next;
818   }
819
820   while(conn) {
821     if(conn->termination_id != -1)
822       SPC_XtRemoveInput(&conn->termination_id, SPC_Terminator);
823     conn=conn->next;
824   }
825   _DtSvcProcessUnlock();
826 }
827
828 /*----------------------------------------------------------------------+*/
829 void XeSPCRestartCallbacks(void)
830 /*----------------------------------------------------------------------+*/
831 {
832   SPC_Channel_Ptr channel;
833
834   _DtSvcProcessLock();
835   channel=spc_activation_list;
836
837   while(channel) {
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;
843   }
844   _DtSvcProcessUnlock();
845 }
846
847 /*
848  ***
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.
851  ***
852 */
853
854 /*----------------------------------------------------------------------+*/
855 XeSetpgrp(int read_current_termio)
856 /*----------------------------------------------------------------------+*/
857 {
858
859   return(SPC_Setpgrp(read_current_termio));
860 }  
861
862 int XeSPCSendEOF(SPC_Channel_Ptr channel)
863 {
864   if(channel==SPC_ERROR) {
865     SPC_Error(SPC_Bad_Argument);
866     return(SPC_ERROR);
867   }
868   
869   return(mempf0(channel, send_eof));
870 }
871
872 int XeSPCSetTermio(SPC_Channel_Ptr channel, int connection, int side,
873                    struct termios *termio)
874 {
875   if(channel==SPC_ERROR || termio == NULL) {
876     SPC_Error(SPC_Bad_Argument);
877     return(SPC_ERROR);
878   }
879   
880   return(mempf3(channel, set_termio, connection, side, termio));
881 }
882