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 * $TOG: pty.c /main/10 1999/10/14 15:06:11 mgreess $
27 * (c) Copyright 1996 Digital Equipment Corporation.
28 * (c) Copyright 1988,1993,1994,1996 Hewlett-Packard Company.
29 * (c) Copyright 1993,1994,1996 International Business Machines Corp.
30 * (c) Copyright 1993,1994,1996 Sun Microsystems, Inc.
31 * (c) Copyright 1993,1994,1996 Novell, Inc.
32 * (c) Copyright 1996 FUJITSU LIMITED.
33 * (c) Copyright 1996 Hitachi.
38 #if defined(hpux) || defined(_hpux) || defined(__hpux) || defined(hp)
43 #define __need_timeval /* need struct timeval */
46 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
50 #include <sys/types.h>
54 #include <sys/filio.h>
56 #include <sys/ioctl.h>
61 #include <sys/ptyio.h>
72 #include <sys/ttycom.h>
77 #include "DtSvcLock.h"
79 /* External declarations */
82 * Pseudo-Terminal device file definitions:
83 * Switch _1 and _2 around if BSD or SYSV conventions are more likely
86 #if defined (SVR4) || defined(AIX)
87 #define MPREFIX_1 "/dev/pty" /* BSD convention ?? */
88 #define SPREFIX_1 "/dev/tty"
90 #define MPREFIX_2 "/dev/ptym/pty" /* AT&T convention ?? */
91 #define SPREFIX_2 "/dev/pty/tty"
94 #define MPREFIX_1 "/dev/ptym/pty" /* AT&T convention ?? */
95 #define SPREFIX_1 "/dev/pty/tty"
97 #define MPREFIX_2 "/dev/pty" /* BSD convention ?? */
98 #define SPREFIX_2 "/dev/tty"
102 #include <sys/ptms.h>
103 static char *MASTER_PATH = "/dev/ptmx";
106 static char *MASTER_NAMES = "pqrstuvwabcefghijklmnoxyz";
108 #define SCANBITS(sfds,step) \
110 for(__i=0; __i<FD_SETSIZE; __i++) \
111 if(FD_ISSET(__i, sfds)) \
115 #define IS_FD_SET(fdarr, res) \
118 for(__i=0; __i<FD_SETSIZE; __i++) \
119 if(FD_ISSET(__i, fdarr)) { \
124 static int send_eof_pty_channel_object(SPC_Channel_Ptr channel);
126 void pty_channel_class_init(object_clasp t)
129 pty_channel_clasp c = (pty_channel_clasp) t;
131 c->new_obj = alloc_channel_object;
133 c->open = open_pty_channel_object;
134 c->close = close_local_channel_object;
135 c->read = read_pty_channel_object;
136 c->write = write_local_channel_object;
137 c->reset = reset_pty_channel_object;
138 c->pre_fork = pre_fork_pty_channel_object;
139 c->post_fork = post_fork_pty_channel_object;
140 c->exec_proc = exec_proc_local_channel_object;
141 c->signal = signal_local_channel_object;
142 c->wait_for_termination=local_channel_object_wait_for_termination;
143 c->attach = attach_pty_channel_object;
144 c->add_input = add_input_pty_channel_object;
145 c->input = local_channel_object_input_handler;
146 c->remove_logfile = remove_logfile_local_channel_object;
148 /* New B.00 methods */
150 c->send_eof = send_eof_pty_channel_object;
151 c->set_termio = set_termio_pty_channel_object;
155 static struct pty_channel_class pty_channel_class_struct = {
156 (channel_clasp) &channel_class, /* base class pointer */
157 "pty_channel", /* class name */
158 pty_channel_class_init, /* class initialize function */
159 sizeof(SPC_Channel), /* size */
163 pty_channel_clasp pty_channel_class = &pty_channel_class_struct;
166 static XeChar *hexdigits = "0123456789abcdef";
169 /*----------------------------------------------------------------------+*/
170 static SPC_Disable_Trapping(int fd)
171 /*----------------------------------------------------------------------+*/
175 struct request_info req_info;
177 /* Disable trapping */
178 ioctl(fd, TIOCTRAP, &disable);
180 /* Just in case, flush any queued requests */
182 while((ioctl(fd, TIOCTRAPSTATUS, &flag) != ERROR) && flag) {
183 ioctl(fd, TIOCREQGET, &req_info);
184 ioctl(fd, TIOCREQSET, &req_info);
188 #endif /* __hpux_pty */
191 * Routines for opening pty master/slave devices
196 /*----------------------------------------------------------------------+*/
197 static int getspec1170ptypair(Wire *wire)
198 /*----------------------------------------------------------------------+*/
201 struct sigaction newAction, oldAction;
203 strcpy(wire->master_name, MASTER_PATH);
205 if ((wire->fd[MASTER_SIDE] = open(wire->master_name, O_RDWR)) < OK)
207 /* open(master) failed. */
211 /* SIGCHLD handler, if any, must be disabled during grantpt! */
212 sigaction(SIGCHLD, (struct sigaction *)NULL, &oldAction);
213 if (oldAction.sa_handler != SIG_DFL)
215 newAction = oldAction;
216 newAction.sa_handler = SIG_DFL;
217 sigaction(SIGCHLD, &newAction, (struct sigaction *)NULL);
220 if (grantpt(wire->fd[MASTER_SIDE]) != OK)
222 /* cannot access the slave pty. */
223 close(wire->fd[MASTER_SIDE]);
227 /* Restore SIGCHLD handler. */
228 if (oldAction.sa_handler != SIG_DFL)
229 sigaction(SIGCHLD, &oldAction, (struct sigaction *)NULL);
231 if ((unlockpt(wire->fd[MASTER_SIDE]) != OK) ||
232 ((slaveName = ptsname(wire->fd[MASTER_SIDE])) == (char *)NULL) ||
233 (access(slaveName, R_OK | W_OK) == ERROR))
235 /* cannot access the slave pty. */
236 close(wire->fd[MASTER_SIDE]);
240 /* we have opened a master with a slave we can access */
241 strcpy(wire->slave_name, slaveName);
247 /* This is not exactly what should be done. We really should open the
248 directory which contains "suspected" ptys. Then read the directory
249 to get filenames, then check each file name to tell whether it is a
250 master pty. However, for the time being, we will use the old way.
254 /*----------------------------------------------------------------------+*/
255 static int getptypair(Wire *wire)
256 /*----------------------------------------------------------------------+*/
258 /* Attempt to open the master/slave pair of preset pty */
260 XeString master=wire->master_name;
261 XeString slave =wire->slave_name;
266 XeString sptr; /* Point to end of preset prefixes */
267 int c_len = strlen (MASTER_NAMES);
269 /* Set things up to quickly alter last 2 chars of path strings */
270 mptr = master + strlen(master);
271 *(mptr+2) = (XeChar)'\0';
273 sptr = slave + strlen(slave);
274 *(sptr+2) = (XeChar)'\0';
276 for (c = 0; c < c_len; c++) { /* 1st char */
278 /* Get the next character in order */
279 *(mptr) = *(sptr) = MASTER_NAMES[c];
281 for (d = 0; d < 15; d++) { /* 2nd char: 0..9,a..f */
283 /* Get the next hex number in order */
284 *(mptr+1) = hexdigits[d];
286 /* Attempt to open this master side of pty */
288 if ((wire->fd[MASTER_SIDE] = open(master, O_RDWR)) < OK) {
289 /* open(master) failed, try next master... */
293 *(sptr+1) = hexdigits[d];
295 /* check that we can eventually open the slave side, using
296 the access system call */
297 if(access(slave, R_OK | W_OK) == ERROR) {
298 /* cannot access the slave pty. Close master and try next one */
299 close(wire->fd[MASTER_SIDE]);
303 /* we have opened a master with a slave we can access */
306 } /* End for 2nd char */
307 } /* End for 1st char */
312 /*----------------------------------------------------------------------+*/
313 static int initpty(Wire *wire)
314 /*----------------------------------------------------------------------+*/
316 /* Find first available master/slave pair */
318 /* set both sides of wire to -1 (unitialized convention) */
319 wire->fd[MASTER_SIDE] = wire->fd[SLAVE_SIDE] = -1;
322 if (!getspec1170ptypair(wire))
325 /* Start with convention 1 */
326 strcpy(wire->master_name, MPREFIX_1);
327 strcpy(wire->slave_name, SPREFIX_1);
329 if (!getptypair(wire)) {
330 /* Cannot get that pair, so try convention 2 */
331 strcpy(wire->master_name, MPREFIX_2);
332 strcpy(wire->slave_name, SPREFIX_2);
333 if (!getptypair(wire)) {
334 /* No available pty's ?? */
335 wire->master_name[0] = wire->slave_name[0] = (XeChar)'\0';
336 wire->fd[MASTER_SIDE] = wire->fd[SLAVE_SIDE] = -1;
337 SPC_Error(SPC_No_Pty);
346 /*----------------------------------------------------------------------+*/
347 static int set_pty_state(int fd, struct termios *term_state)
348 /*----------------------------------------------------------------------+*/
351 if (fd < 0 || !isatty(fd))
354 /* Go to cooked mode (modify terminal state) */
355 if(tcsetattr(fd, TCSANOW, term_state)==ERROR) {
356 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcsetattr");
367 if(ioctl(fd, TIOCSWINSZ, &size) == ERROR) {
368 SPC_Error(SPC_Bad_tc_Call,(XeString)"tc_setwinsize");
377 /*----------------------------------------------------------------------+*/
378 int master_pty(int fd, struct termios *state)
379 /*----------------------------------------------------------------------+*/
381 /* Make any special circumstances required on master side of pty */
388 /* Enable trapping of ioctl/open/close (we care about close()) */
389 if(ioctl(fd, TIOCTRAP, &enable)==ERROR) {
390 SPC_Error(SPC_Bad_Ioctl);
393 #endif /* __hpux_pty */
395 set_pty_state(fd, state);
402 /*----------------------------------------------------------------------+*/
403 static Wire *getpty(Wire *prevwire)
404 /*----------------------------------------------------------------------+*/
406 Wire *wire_ptr=get_new_wire();
411 if(initpty(wire_ptr)==SPC_ERROR) {
416 wire_ptr->next=prevwire;
420 static void init_termio(struct termios *term_state)
423 /* Basically, we want the pty channel to act like like a pipe
424 (perhaps later we should get more fancy). This means that we
425 do not do any input processing for KILL / ERASE characters, we don't
426 echo the data, and reads will return when there is at least one character
427 in the buffer to be read. */
429 term_state->c_iflag = 0;
430 term_state->c_oflag = 0;
431 term_state->c_cflag = CS8 | CREAD | HUPCL;
432 term_state->c_lflag = 0;
434 cfsetispeed(term_state, B9600);
435 cfsetospeed(term_state, B9600);
437 term_state->c_cc[VMIN]=1;
438 term_state->c_cc[VTIME]=0;
443 *** Method definitions
447 /*----------------------------------------------------------------------+*/
448 SPC_Channel_Ptr open_pty_channel_object(SPC_Channel_Ptr channel,
451 /*----------------------------------------------------------------------+*/
454 Wire *tmpwire, *newwire;
455 SPC_Channel_Ptr result;
457 call_parent_method(channel, open, (channel, iomode, hostname), result);
459 if(result==SPC_ERROR)
462 /* We know that we are going to use one of STDIN, STDOUT, or STDERR
463 (or else we would be a NOIO channel), so allocate at least one
466 if(!(tmpwire=getpty(NULL)))
469 if (IS_SPCIO_STDIN(iomode)) {
470 channel->wires[STDIN]=tmpwire;
473 if (IS_SPCIO_STDOUT(iomode)) {
474 channel->wires[STDOUT]=tmpwire;
477 if (IS_SPCIO_SEPARATE(iomode)) {
478 if(!(newwire=getpty(tmpwire))) {
479 spc_close(tmpwire->fd[MASTER_SIDE]);
486 if (IS_SPCIO_STDERR(iomode)) {
487 channel->wires[STDERR]=tmpwire;
490 channel->wire_list=tmpwire;
492 /* set up the channel file descriptors */
494 channel->file_descs[STDIN] = (channel->wires[STDIN]) ->fd[MASTER_SIDE];
495 channel->file_descs[STDOUT] = (channel->wires[STDOUT])->fd[MASTER_SIDE];
496 channel->file_descs[STDERR] = (channel->wires[STDERR])->fd[MASTER_SIDE];
498 for(tmpwire=channel->wire_list; tmpwire; tmpwire=tmpwire->next) {
499 init_termio(&tmpwire->master_termio);
500 init_termio(&tmpwire->slave_termio);
507 /*----------------------------------------------------------------------+*/
508 int read_pty_channel_object(SPC_Channel_Ptr channel,
509 int connector, /* STDOUT or STDERR */
512 /*----------------------------------------------------------------------+*/
516 int result, select_value;
517 struct fd_set read_mask, except_mask;
518 int fd=channel->file_descs[connector];
519 struct request_info req_info;
520 struct timeval timeout, *timeptr;
523 call_parent_method(channel,
525 (channel, connector, buffer, nbytes),
528 if(result==SPC_ERROR)
531 if(!IS_SPCIO_DATA(channel->wires[connector]->flags))
535 FD_ZERO(&except_mask);
537 FD_SET(fd, &read_mask);
538 FD_SET(fd, &except_mask);
540 if(channel->close_timeout) {
541 timeout.tv_sec=channel->close_timeout;
543 timeptr = (&timeout);
548 select_value=select(fd+1, &read_mask, NULL, &except_mask, timeptr);
549 while(select_value==ERROR && errno==EINTR);
551 if(select_value==ERROR) {
552 SPC_Error(SPC_Bad_Select);
556 /* If there is anything to read, read it & return */
557 IS_FD_SET(&read_mask, result);
560 result = read(fd, buffer, nbytes);
561 } while (result<0 && errno == EINTR);
563 SPC_Error(SPC_Reading);
569 /* Nothing to read. We either timed out or got an exception. */
571 if(select_value != 0) {
573 /* We got an exception */
574 ioctl(fd, TIOCREQGET, &req_info);
576 /* Clear the request (Not really necessary in the case of a close,
579 ioctl(fd, TIOCREQSET, &req_info);
582 if((select_value == 0) || (req_info.request == TIOCCLOSE)) {
584 /* Close, disable trapping on this fd & return EOF. We regard
585 a timeout as being the same as a close. */
587 SPC_Disable_Trapping(fd);
588 SPC_Change_State(channel, connector, 0, -1);
593 /* Otherwise (open or IOCTL), return -1 */
597 #else /* not __hpux_pty */
600 int fd=channel->file_descs[connector];
603 struct timeval tv={0, 50000};
605 result=ioctl(fd, FIONREAD, &numbytes);
608 result = kill(channel->pid, 0);
609 if((result == -1) && errno == ESRCH) {
610 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
611 SPC_Change_State(channel, connector, 0, -1);
615 FD_SET(fd, &read_mask);
618 ** This call to select doesn't have the cast to (int*), because
619 ** this clause of the ifdef is not compiled on HPUX.
622 result=select(fd+1, &read_mask, NULL, NULL, &tv);
623 if((result == -1) && (errno != EINTR)) {
624 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
625 SPC_Change_State(channel, connector, 0, -1);
628 } while((result <= 0));
631 result = read(fd, buffer, nbytes);
632 } while (result<0 && errno == EINTR);
634 if(result == ERROR) {
636 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
637 SPC_Change_State(channel, connector, 0, -1);
640 XeString connection_hostname = (channel->connection ?
641 CONNECTION_HOSTNAME(channel->connection) :
642 Xestrdup(XeString_Empty));
643 SPC_Error(SPC_Reading, connection_hostname);
644 XeFree(connection_hostname);
651 #endif /* __hpux_pty */
653 /*----------------------------------------------------------------------+*/
654 int pre_fork_pty_channel_object(SPC_Channel_Ptr channel)
655 /*----------------------------------------------------------------------+*/
661 call_parent_method(channel, pre_fork, (channel), result);
663 if(result==SPC_ERROR)
668 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
669 if(master_pty(wirelist->fd[MASTER_SIDE], &wirelist->master_termio)
675 if(pipe(channel->sync_pipe) < 0) {
676 SPC_Error(SPC_No_Pipe);
679 #endif /* __hpux_pty */
685 /*----------------------------------------------------------------------+*/
687 /*----------------------------------------------------------------------+*/
689 /* I am not particularly enamored of this macro. However, the style of
690 the SCANBITS macro kinda forces me to write it this way. In particular,
691 I am a bit worried about the reference to except_mask, which is a
692 "nonlocal reference" */
694 #define clear_trap(fd) {struct request_info req_info; \
696 ioctl(my_fd, TIOCREQGET, &req_info); \
697 if(req_info.request != TIOCOPEN) { \
698 SPC_Error(SPC_Bad_Ioctl); \
701 ioctl(my_fd, TIOCREQSET, &req_info); \
702 FD_CLR(my_fd, &except_mask); \
704 #endif /* __hpux_pty */
706 /*----------------------------------------------------------------------+*/
707 int post_fork_pty_channel_object(SPC_Channel_Ptr channel,
709 /*----------------------------------------------------------------------+*/
714 int iomode=channel->IOMode;
715 int fd=channel->file_descs[STDIN];
716 int stdinfd, stdoutfd, stderrfd;
718 struct fd_set except_mask, temp_mask;
723 call_parent_method(channel, post_fork, (channel, parentp), result);
725 if(result==SPC_ERROR)
728 if (parentp) { /* Master process */
733 stdinfd = channel->wires[STDIN]->fd[MASTER_SIDE];
734 stdoutfd = channel->wires[STDOUT]->fd[MASTER_SIDE];
735 stderrfd = channel->wires[STDERR]->fd[MASTER_SIDE];
737 FD_ZERO(&except_mask);
740 FD_SET(stdinfd, &except_mask);
742 FD_SET(stdoutfd, &except_mask);
744 FD_SET(stderrfd, &except_mask);
746 IS_FD_SET(&except_mask, result);
748 temp_mask = except_mask;
749 select_value=select(max_fds, NULL, NULL, &temp_mask, NULL);
750 SCANBITS(&temp_mask, clear_trap);
751 IS_FD_SET(&except_mask, result);
754 #else /* not __hpux_pty */
755 close(channel->sync_pipe[WRITE_SIDE]);
756 read(channel->sync_pipe[READ_SIDE], &c, 1);
757 close(channel->sync_pipe[READ_SIDE]);
758 channel->sync_pipe[READ_SIDE] = -1;
759 channel->sync_pipe[WRITE_SIDE] = -1;
760 XeSPCAddInput(channel, NULL, NULL);
761 #endif /* __hpux_pty */
763 } else { /* Slave process */
765 /* Open the slave pty. Do it up to three times to set up
766 stdin, stdout, stderr */
776 if(IS_SPCIO_STDIN(iomode)) {
777 if((stdinfd=open(channel->wires[STDIN]->slave_name, O_RDWR))<0) {
778 SPC_Error(SPC_Cannot_Open_Slave,
779 channel->wires[STDIN]->slave_name);
785 if(IS_SPCIO_STDOUT(iomode)) {
786 /* We will always share the file descriptor with STDIN,
791 if((stdoutfd=open(channel->wires[STDOUT]->slave_name, O_RDWR))<0) {
792 SPC_Error(SPC_Cannot_Open_Slave,
793 channel->wires[STDOUT]->slave_name);
800 if(IS_SPCIO_STDERR(iomode)) {
801 /* If we want separate STDOUT/STDERR, open a new FD */
802 if(IS_SPCIO_SEPARATE(iomode)) {
803 if((stderrfd=open(channel->wires[STDERR]->slave_name, O_RDWR))<0) {
804 SPC_Error(SPC_Cannot_Open_Slave,
805 channel->wires[STDIN]->slave_name);
815 /* The pty trapping stuff handles EOF for us. Use the "sync" pipe */
816 /* to inform the other side when we don't have that code. */
818 write(channel->sync_pipe[WRITE_SIDE], &c, 1);
819 close(channel->sync_pipe[READ_SIDE]);
820 close(channel->sync_pipe[WRITE_SIDE]);
821 #endif /* __hpux_pty */
823 /* Duplicate these file descriptors to 3, 4, 5 so we don't have to
824 worry about any of std[in|out|err]fd being 0, 1, or 2. */
826 spc_dup2(stdinfd, 3);
827 spc_dup2(stdoutfd, 4);
828 spc_dup2(stderrfd, 5);
834 if(IS_SPCIO_STDIN(iomode))
835 set_pty_state(STDIN, &(channel->wires[STDIN]->slave_termio));
836 if(IS_SPCIO_STDOUT(iomode))
837 set_pty_state(STDOUT, &(channel->wires[STDOUT]->slave_termio));
838 if(IS_SPCIO_STDERR(iomode))
839 set_pty_state(STDERR, &(channel->wires[STDERR]->slave_termio));
841 /* Close any other open file descriptors in the child */
848 /*----------------------------------------------------------------------+*/
849 int reset_pty_channel_object(SPC_Channel_Ptr channel)
850 /*----------------------------------------------------------------------+*/
855 call_parent_method(channel, reset, (channel), result);
857 if(result==SPC_ERROR)
862 /* Make any special circumstances required on master side of pty */
864 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
868 int fd=wirelist->fd[MASTER_SIDE];
869 /* Disable trapping of ioctl/open/close */
870 if(SPC_Disable_Trapping(fd) == SPC_ERROR)
873 #endif /* __hpux_pty */
875 wirelist->flags &= ~SPCIO_DATA;
881 /*----------------------------------------------------------------------+*/
882 int attach_pty_channel_object(SPC_Channel_Ptr channel, int pid)
883 /*----------------------------------------------------------------------+*/
885 set_pty_state(channel->file_descs[STDIN],
886 &(channel->wires[STDIN]->master_termio));
887 set_pty_state(channel->file_descs[STDOUT],
888 &(channel->wires[STDOUT]->master_termio));
889 set_pty_state(channel->file_descs[STDERR],
890 &(channel->wires[STDERR]->master_termio));
894 if(!mempf0(channel, pre_fork))
900 /*----------------------------------------------------------------------+*/
901 int add_input_pty_channel_object(SPC_Channel_Ptr channel,
902 SbInputHandlerProc handler,
904 /*----------------------------------------------------------------------+*/
907 Wire *wirelist, *stdinwire;
909 call_parent_method(channel, add_input, (channel, handler, data), result);
911 if(result==SPC_ERROR)
914 stdinwire=channel->wires[STDIN];
916 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
918 if((wirelist->read_toolkit_id != -1) ||
919 (wirelist->except_toolkit_id != -1))
922 fd=wirelist->fd[READ_SIDE];
923 SPC_XtAddInput(channel,
924 &wirelist->read_toolkit_id,
926 channel->class_ptr->input,
929 SPC_XtAddInput(channel,
930 &wirelist->except_toolkit_id,
932 channel->class_ptr->input,
934 #endif /* __hpux_pty */
941 Wire *setpgrp_wire = NULL;
943 struct termios *XeTermioStruct = NULL;
944 struct termios XeDefaultTermioStruct;
946 /*----------------------------------------------------------------------+*/
947 void InitDefaultTermioStruct(void)
948 /*----------------------------------------------------------------------+*/
952 XeDefaultTermioStruct.c_iflag = BRKINT | IGNPAR | ICRNL | IXON;
953 XeDefaultTermioStruct.c_oflag = OPOST | ONLCR;
954 XeDefaultTermioStruct.c_cflag = CS8 | CREAD | CLOCAL;
955 XeDefaultTermioStruct.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
957 cfsetispeed(&XeDefaultTermioStruct, B9600);
958 cfsetospeed(&XeDefaultTermioStruct, B9600);
960 for(i=0; i<NCCS; i++)
961 XeDefaultTermioStruct.c_cc[i] = 0;
963 XeDefaultTermioStruct.c_cc[VEOF] = 04; /* ^d */
964 XeDefaultTermioStruct.c_cc[VEOL] = 0; /* no extra eol char */
965 XeDefaultTermioStruct.c_cc[VERASE] = 010; /* ^h */
966 XeDefaultTermioStruct.c_cc[VINTR] = 03; /* ^c */
967 XeDefaultTermioStruct.c_cc[VKILL] = 025; /* ^u */
968 XeDefaultTermioStruct.c_cc[VQUIT] = 034; /* ^\ */
969 XeDefaultTermioStruct.c_cc[VSTART] = 021; /* ^q */
970 XeDefaultTermioStruct.c_cc[VSTOP] = 023; /* ^s */
971 XeDefaultTermioStruct.c_cc[VSUSP] = 032; /* ^z */
973 /* MIN and TIME are not needed in canonical ("line" or "cooked") mode */
978 /*----------------------------------------------------------------------+*/
979 struct termios *SPC_Get_Current_Termio(void)
980 /*----------------------------------------------------------------------+*/
983 struct termios *termio_struct;
985 static Boolean default_is_initialized = FALSE;
988 if (!default_is_initialized)
990 default_is_initialized = TRUE;
991 InitDefaultTermioStruct();
993 _DtSvcProcessUnlock();
995 termio_struct = (struct termios *)XeMalloc(sizeof(struct termios));
997 /* See if we can open /dev/tty go get default settings for this system */
1001 tty_fd = open("/dev/tty", O_RDWR);
1006 /* retval=ioctl(tty_fd, TCGETA, termio_struct); */
1007 retval = tcgetattr(tty_fd, termio_struct);
1010 if(retval == ERROR) {
1011 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcgetattr");
1013 /* Fall through and use default settings */
1016 return(termio_struct);
1019 /* We get here if we can't open /dev/tty or the tcgetattr() call failed */
1021 memcpy(termio_struct, &XeDefaultTermioStruct, sizeof(struct termios));
1022 return(termio_struct);
1025 /*----------------------------------------------------------------------+*/
1026 int SPC_Setpgrp(int read_current_termio)
1027 /*----------------------------------------------------------------------+*/
1029 _DtSvcProcessLock();
1030 if(setpgrp_wire == NULL)
1031 setpgrp_wire = get_new_wire();
1033 if(read_current_termio || XeTermioStruct == NULL) {
1036 free((char *)XeTermioStruct);
1038 if((XeTermioStruct=SPC_Get_Current_Termio()) == SPC_ERROR) {
1039 _DtSvcProcessUnlock();
1044 spc_close(setpgrp_wire->fd[MASTER_SIDE]);
1045 spc_close(setpgrp_wire->fd[SLAVE_SIDE]);
1047 if((initpty(setpgrp_wire)) == SPC_ERROR) {
1048 spc_close(setpgrp_wire->fd[MASTER_SIDE]);
1049 spc_close(setpgrp_wire->fd[SLAVE_SIDE]);
1050 _DtSvcProcessUnlock();
1054 /* Point of no return */
1058 if((setpgrp_wire->fd[SLAVE_SIDE]=open(setpgrp_wire->slave_name, O_RDWR)) < 0) {
1059 _DtSvcProcessUnlock();
1063 if(tcsetattr(setpgrp_wire->fd[SLAVE_SIDE], TCSANOW, XeTermioStruct)==ERROR) {
1064 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcsetattr");
1065 _DtSvcProcessUnlock();
1069 _DtSvcProcessUnlock();
1079 int set_termio_pty_channel_object(SPC_Channel_Ptr channel,
1082 struct termios *termio)
1084 struct termios *old_termio;
1086 if(side == MASTER_SIDE)
1087 old_termio = &channel->wires[connection]->master_termio;
1089 old_termio = &channel->wires[connection]->slave_termio;
1091 memcpy(old_termio, termio, sizeof(struct termios));
1098 static int send_eof_pty_channel_object(SPC_Channel_Ptr channel)
1100 Wire *wire = channel->wires[STDIN];
1107 if((wire->slave_termio.c_lflag & ~ICANON) == 0)
1110 output_char = wire->slave_termio.c_cc[VEOF];
1111 fd = channel->file_descs[STDIN];
1113 /* Write twice -- once to flush output, and once to have 0 bytes sent. */
1115 ret = write(fd, &output_char, 1);
1116 ret = write(fd, &output_char, 1);