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>
64 #if defined(__apollo) && !defined(ONLCR)
65 # define ONLCR 0 /* This guy (XPG3), not on apollo yet */
76 #include <sys/ttycom.h>
81 #include "DtSvcLock.h"
83 /* External declarations */
86 * Pseudo-Terminal device file definitions:
87 * Switch _1 and _2 around if BSD or SYSV conventions are more likely
90 #if defined (SVR4) || defined(AIX)
91 #define MPREFIX_1 "/dev/pty" /* BSD convention ?? */
92 #define SPREFIX_1 "/dev/tty"
94 #define MPREFIX_2 "/dev/ptym/pty" /* AT&T convention ?? */
95 #define SPREFIX_2 "/dev/pty/tty"
98 #define MPREFIX_1 "/dev/ptym/pty" /* AT&T convention ?? */
99 #define SPREFIX_1 "/dev/pty/tty"
101 #define MPREFIX_2 "/dev/pty" /* BSD convention ?? */
102 #define SPREFIX_2 "/dev/tty"
106 #include <sys/ptms.h>
107 static char *MASTER_PATH = "/dev/ptmx";
110 static char *MASTER_NAMES = "pqrstuvwabcefghijklmnoxyz";
112 #define SCANBITS(sfds,step) \
114 for(__i=0; __i<FD_SETSIZE; __i++) \
115 if(FD_ISSET(__i, sfds)) \
119 #define IS_FD_SET(fdarr, res) \
122 for(__i=0; __i<FD_SETSIZE; __i++) \
123 if(FD_ISSET(__i, fdarr)) { \
128 static int send_eof_pty_channel_object(SPC_Channel_Ptr channel);
130 void pty_channel_class_init(object_clasp t)
133 pty_channel_clasp c = (pty_channel_clasp) t;
135 c->new_obj = alloc_channel_object;
137 c->open = open_pty_channel_object;
138 c->close = close_local_channel_object;
139 c->read = read_pty_channel_object;
140 c->write = write_local_channel_object;
141 c->reset = reset_pty_channel_object;
142 c->pre_fork = pre_fork_pty_channel_object;
143 c->post_fork = post_fork_pty_channel_object;
144 c->exec_proc = exec_proc_local_channel_object;
145 c->signal = signal_local_channel_object;
146 c->wait_for_termination=local_channel_object_wait_for_termination;
147 c->attach = attach_pty_channel_object;
148 c->add_input = add_input_pty_channel_object;
149 c->input = local_channel_object_input_handler;
150 c->remove_logfile = remove_logfile_local_channel_object;
152 /* New B.00 methods */
154 c->send_eof = send_eof_pty_channel_object;
155 c->set_termio = set_termio_pty_channel_object;
159 static struct pty_channel_class pty_channel_class_struct = {
160 (channel_clasp) &channel_class, /* base class pointer */
161 "pty_channel", /* class name */
162 pty_channel_class_init, /* class initialize function */
163 sizeof(SPC_Channel), /* size */
167 pty_channel_clasp pty_channel_class = &pty_channel_class_struct;
170 static XeChar *hexdigits = "0123456789abcdef";
173 /*----------------------------------------------------------------------+*/
174 static SPC_Disable_Trapping(int fd)
175 /*----------------------------------------------------------------------+*/
179 struct request_info req_info;
181 /* Disable trapping */
182 ioctl(fd, TIOCTRAP, &disable);
184 /* Just in case, flush any queued requests */
186 while((ioctl(fd, TIOCTRAPSTATUS, &flag) != ERROR) && flag) {
187 ioctl(fd, TIOCREQGET, &req_info);
188 ioctl(fd, TIOCREQSET, &req_info);
192 #endif /* __hpux_pty */
195 * Routines for opening pty master/slave devices
200 /*----------------------------------------------------------------------+*/
201 static int getspec1170ptypair(Wire *wire)
202 /*----------------------------------------------------------------------+*/
205 struct sigaction newAction, oldAction;
207 strcpy(wire->master_name, MASTER_PATH);
209 if ((wire->fd[MASTER_SIDE] = open(wire->master_name, O_RDWR)) < OK)
211 /* open(master) failed. */
215 /* SIGCHLD handler, if any, must be disabled during grantpt! */
216 sigaction(SIGCHLD, (struct sigaction *)NULL, &oldAction);
217 if (oldAction.sa_handler != SIG_DFL)
219 newAction = oldAction;
220 newAction.sa_handler = SIG_DFL;
221 sigaction(SIGCHLD, &newAction, (struct sigaction *)NULL);
224 if (grantpt(wire->fd[MASTER_SIDE]) != OK)
226 /* cannot access the slave pty. */
227 close(wire->fd[MASTER_SIDE]);
231 /* Restore SIGCHLD handler. */
232 if (oldAction.sa_handler != SIG_DFL)
233 sigaction(SIGCHLD, &oldAction, (struct sigaction *)NULL);
235 if ((unlockpt(wire->fd[MASTER_SIDE]) != OK) ||
236 ((slaveName = ptsname(wire->fd[MASTER_SIDE])) == (char *)NULL) ||
237 (access(slaveName, R_OK | W_OK) == ERROR))
239 /* cannot access the slave pty. */
240 close(wire->fd[MASTER_SIDE]);
244 /* we have opened a master with a slave we can access */
245 strcpy(wire->slave_name, slaveName);
251 /* This is not exactly what should be done. We really should open the
252 directory which contains "suspected" ptys. Then read the directory
253 to get filenames, then check each file name to tell whether it is a
254 master pty. However, for the time being, we will use the old way.
258 /*----------------------------------------------------------------------+*/
259 static int getptypair(Wire *wire)
260 /*----------------------------------------------------------------------+*/
262 /* Attempt to open the master/slave pair of preset pty */
264 XeString master=wire->master_name;
265 XeString slave =wire->slave_name;
270 XeString sptr; /* Point to end of preset prefixes */
271 int c_len = strlen (MASTER_NAMES);
273 /* Set things up to quickly alter last 2 chars of path strings */
274 mptr = master + strlen(master);
275 *(mptr+2) = (XeChar)'\0';
277 sptr = slave + strlen(slave);
278 *(sptr+2) = (XeChar)'\0';
280 for (c = 0; c < c_len; c++) { /* 1st char */
282 /* Get the next character in order */
283 *(mptr) = *(sptr) = MASTER_NAMES[c];
285 for (d = 0; d < 15; d++) { /* 2nd char: 0..9,a..f */
287 /* Get the next hex number in order */
288 *(mptr+1) = hexdigits[d];
290 /* Attempt to open this master side of pty */
292 if ((wire->fd[MASTER_SIDE] = open(master, O_RDWR)) < OK) {
293 /* open(master) failed, try next master... */
297 *(sptr+1) = hexdigits[d];
299 /* check that we can eventually open the slave side, using
300 the access system call */
301 if(access(slave, R_OK | W_OK) == ERROR) {
302 /* cannot access the slave pty. Close master and try next one */
303 close(wire->fd[MASTER_SIDE]);
307 /* we have opened a master with a slave we can access */
310 } /* End for 2nd char */
311 } /* End for 1st char */
316 /*----------------------------------------------------------------------+*/
317 static int initpty(Wire *wire)
318 /*----------------------------------------------------------------------+*/
320 /* Find first available master/slave pair */
322 /* set both sides of wire to -1 (unitialized convention) */
323 wire->fd[MASTER_SIDE] = wire->fd[SLAVE_SIDE] = -1;
326 if (!getspec1170ptypair(wire))
329 /* Start with convention 1 */
330 strcpy(wire->master_name, MPREFIX_1);
331 strcpy(wire->slave_name, SPREFIX_1);
333 if (!getptypair(wire)) {
334 /* Cannot get that pair, so try convention 2 */
335 strcpy(wire->master_name, MPREFIX_2);
336 strcpy(wire->slave_name, SPREFIX_2);
337 if (!getptypair(wire)) {
338 /* No available pty's ?? */
339 wire->master_name[0] = wire->slave_name[0] = (XeChar)'\0';
340 wire->fd[MASTER_SIDE] = wire->fd[SLAVE_SIDE] = -1;
341 SPC_Error(SPC_No_Pty);
350 /*----------------------------------------------------------------------+*/
351 static int set_pty_state(int fd, struct termios *term_state)
352 /*----------------------------------------------------------------------+*/
355 if (fd < 0 || !isatty(fd))
358 /* Go to cooked mode (modify terminal state) */
359 if(tcsetattr(fd, TCSANOW, term_state)==ERROR) {
360 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcsetattr");
371 if(ioctl(fd, TIOCSWINSZ, &size) == ERROR) {
372 SPC_Error(SPC_Bad_tc_Call,(XeString)"tc_setwinsize");
381 /*----------------------------------------------------------------------+*/
382 int master_pty(int fd, struct termios *state)
383 /*----------------------------------------------------------------------+*/
385 /* Make any special circumstances required on master side of pty */
392 /* Enable trapping of ioctl/open/close (we care about close()) */
393 if(ioctl(fd, TIOCTRAP, &enable)==ERROR) {
394 SPC_Error(SPC_Bad_Ioctl);
397 #endif /* __hpux_pty */
399 set_pty_state(fd, state);
406 /*----------------------------------------------------------------------+*/
407 static Wire *getpty(Wire *prevwire)
408 /*----------------------------------------------------------------------+*/
410 Wire *wire_ptr=get_new_wire();
415 if(initpty(wire_ptr)==SPC_ERROR) {
420 wire_ptr->next=prevwire;
424 static void init_termio(struct termios *term_state)
427 /* Basically, we want the pty channel to act like like a pipe
428 (perhaps later we should get more fancy). This means that we
429 do not do any input processing for KILL / ERASE characters, we don't
430 echo the data, and reads will return when there is at least one character
431 in the buffer to be read. */
433 term_state->c_iflag = 0;
434 term_state->c_oflag = 0;
435 term_state->c_cflag = CS8 | CREAD | HUPCL;
436 term_state->c_lflag = 0;
438 cfsetispeed(term_state, B9600);
439 cfsetospeed(term_state, B9600);
441 term_state->c_cc[VMIN]=1;
442 term_state->c_cc[VTIME]=0;
447 *** Method definitions
451 /*----------------------------------------------------------------------+*/
452 SPC_Channel_Ptr open_pty_channel_object(SPC_Channel_Ptr channel,
455 /*----------------------------------------------------------------------+*/
458 Wire *tmpwire, *newwire;
459 SPC_Channel_Ptr result;
461 call_parent_method(channel, open, (channel, iomode, hostname), result);
463 if(result==SPC_ERROR)
466 /* We know that we are going to use one of STDIN, STDOUT, or STDERR
467 (or else we would be a NOIO channel), so allocate at least one
470 if(!(tmpwire=getpty(NULL)))
473 if (IS_SPCIO_STDIN(iomode)) {
474 channel->wires[STDIN]=tmpwire;
477 if (IS_SPCIO_STDOUT(iomode)) {
478 channel->wires[STDOUT]=tmpwire;
481 if (IS_SPCIO_SEPARATE(iomode)) {
482 if(!(newwire=getpty(tmpwire))) {
483 spc_close(tmpwire->fd[MASTER_SIDE]);
490 if (IS_SPCIO_STDERR(iomode)) {
491 channel->wires[STDERR]=tmpwire;
494 channel->wire_list=tmpwire;
496 /* set up the channel file descriptors */
498 channel->file_descs[STDIN] = (channel->wires[STDIN]) ->fd[MASTER_SIDE];
499 channel->file_descs[STDOUT] = (channel->wires[STDOUT])->fd[MASTER_SIDE];
500 channel->file_descs[STDERR] = (channel->wires[STDERR])->fd[MASTER_SIDE];
502 for(tmpwire=channel->wire_list; tmpwire; tmpwire=tmpwire->next) {
503 init_termio(&tmpwire->master_termio);
504 init_termio(&tmpwire->slave_termio);
511 /*----------------------------------------------------------------------+*/
512 int read_pty_channel_object(SPC_Channel_Ptr channel,
513 int connector, /* STDOUT or STDERR */
516 /*----------------------------------------------------------------------+*/
520 int result, select_value;
521 struct fd_set read_mask, except_mask;
522 int fd=channel->file_descs[connector];
523 struct request_info req_info;
524 struct timeval timeout, *timeptr;
527 call_parent_method(channel,
529 (channel, connector, buffer, nbytes),
532 if(result==SPC_ERROR)
535 if(!IS_SPCIO_DATA(channel->wires[connector]->flags))
539 FD_ZERO(&except_mask);
541 FD_SET(fd, &read_mask);
542 FD_SET(fd, &except_mask);
544 if(channel->close_timeout) {
545 timeout.tv_sec=channel->close_timeout;
547 timeptr = (&timeout);
552 select_value=select(fd+1, &read_mask, NULL, &except_mask, timeptr);
553 while(select_value==ERROR && errno==EINTR);
555 if(select_value==ERROR) {
556 SPC_Error(SPC_Bad_Select);
560 /* If there is anything to read, read it & return */
561 IS_FD_SET(&read_mask, result);
564 result = read(fd, buffer, nbytes);
565 } while (result<0 && errno == EINTR);
567 SPC_Error(SPC_Reading);
573 /* Nothing to read. We either timed out or got an exception. */
575 if(select_value != 0) {
577 /* We got an exception */
578 ioctl(fd, TIOCREQGET, &req_info);
580 /* Clear the request (Not really necessary in the case of a close,
583 ioctl(fd, TIOCREQSET, &req_info);
586 if((select_value == 0) || (req_info.request == TIOCCLOSE)) {
588 /* Close, disable trapping on this fd & return EOF. We regard
589 a timeout as being the same as a close. */
591 SPC_Disable_Trapping(fd);
592 SPC_Change_State(channel, connector, 0, -1);
597 /* Otherwise (open or IOCTL), return -1 */
601 #else /* not __hpux_pty */
604 int fd=channel->file_descs[connector];
607 struct timeval tv={0, 50000};
609 result=ioctl(fd, FIONREAD, &numbytes);
612 result = kill(channel->pid, 0);
613 if((result == -1) && errno == ESRCH) {
614 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
615 SPC_Change_State(channel, connector, 0, -1);
619 FD_SET(fd, &read_mask);
622 ** This call to select doesn't have the cast to (int*), because
623 ** this clause of the ifdef is not compiled on HPUX.
626 result=select(fd+1, &read_mask, NULL, NULL, &tv);
627 if((result == -1) && (errno != EINTR)) {
628 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
629 SPC_Change_State(channel, connector, 0, -1);
632 } while((result <= 0));
635 result = read(fd, buffer, nbytes);
636 } while (result<0 && errno == EINTR);
638 if(result == ERROR) {
640 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
641 SPC_Change_State(channel, connector, 0, -1);
644 XeString connection_hostname = (channel->connection ?
645 CONNECTION_HOSTNAME(channel->connection) :
646 Xestrdup(XeString_Empty));
647 SPC_Error(SPC_Reading, connection_hostname);
648 XeFree(connection_hostname);
655 #endif /* __hpux_pty */
657 /*----------------------------------------------------------------------+*/
658 int pre_fork_pty_channel_object(SPC_Channel_Ptr channel)
659 /*----------------------------------------------------------------------+*/
665 call_parent_method(channel, pre_fork, (channel), result);
667 if(result==SPC_ERROR)
672 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
673 if(master_pty(wirelist->fd[MASTER_SIDE], &wirelist->master_termio)
679 if(pipe(channel->sync_pipe) < 0) {
680 SPC_Error(SPC_No_Pipe);
683 #endif /* __hpux_pty */
689 /*----------------------------------------------------------------------+*/
691 /*----------------------------------------------------------------------+*/
693 /* I am not particularly enamored of this macro. However, the style of
694 the SCANBITS macro kinda forces me to write it this way. In particular,
695 I am a bit worried about the reference to except_mask, which is a
696 "nonlocal reference" */
698 #define clear_trap(fd) {struct request_info req_info; \
700 ioctl(my_fd, TIOCREQGET, &req_info); \
701 if(req_info.request != TIOCOPEN) { \
702 SPC_Error(SPC_Bad_Ioctl); \
705 ioctl(my_fd, TIOCREQSET, &req_info); \
706 FD_CLR(my_fd, &except_mask); \
708 #endif /* __hpux_pty */
710 /*----------------------------------------------------------------------+*/
711 int post_fork_pty_channel_object(SPC_Channel_Ptr channel,
713 /*----------------------------------------------------------------------+*/
718 int iomode=channel->IOMode;
719 int fd=channel->file_descs[STDIN];
720 int stdinfd, stdoutfd, stderrfd;
722 struct fd_set except_mask, temp_mask;
727 call_parent_method(channel, post_fork, (channel, parentp), result);
729 if(result==SPC_ERROR)
732 if (parentp) { /* Master process */
737 stdinfd = channel->wires[STDIN]->fd[MASTER_SIDE];
738 stdoutfd = channel->wires[STDOUT]->fd[MASTER_SIDE];
739 stderrfd = channel->wires[STDERR]->fd[MASTER_SIDE];
741 FD_ZERO(&except_mask);
744 FD_SET(stdinfd, &except_mask);
746 FD_SET(stdoutfd, &except_mask);
748 FD_SET(stderrfd, &except_mask);
750 IS_FD_SET(&except_mask, result);
752 temp_mask = except_mask;
753 select_value=select(max_fds, NULL, NULL, &temp_mask, NULL);
754 SCANBITS(&temp_mask, clear_trap);
755 IS_FD_SET(&except_mask, result);
758 #else /* not __hpux_pty */
759 close(channel->sync_pipe[WRITE_SIDE]);
760 read(channel->sync_pipe[READ_SIDE], &c, 1);
761 close(channel->sync_pipe[READ_SIDE]);
762 channel->sync_pipe[READ_SIDE] = -1;
763 channel->sync_pipe[WRITE_SIDE] = -1;
764 XeSPCAddInput(channel, NULL, NULL);
765 #endif /* __hpux_pty */
767 } else { /* Slave process */
769 /* Open the slave pty. Do it up to three times to set up
770 stdin, stdout, stderr */
780 if(IS_SPCIO_STDIN(iomode)) {
781 if((stdinfd=open(channel->wires[STDIN]->slave_name, O_RDWR))<0) {
782 SPC_Error(SPC_Cannot_Open_Slave,
783 channel->wires[STDIN]->slave_name);
789 if(IS_SPCIO_STDOUT(iomode)) {
790 /* We will always share the file descriptor with STDIN,
795 if((stdoutfd=open(channel->wires[STDOUT]->slave_name, O_RDWR))<0) {
796 SPC_Error(SPC_Cannot_Open_Slave,
797 channel->wires[STDOUT]->slave_name);
804 if(IS_SPCIO_STDERR(iomode)) {
805 /* If we want separate STDOUT/STDERR, open a new FD */
806 if(IS_SPCIO_SEPARATE(iomode)) {
807 if((stderrfd=open(channel->wires[STDERR]->slave_name, O_RDWR))<0) {
808 SPC_Error(SPC_Cannot_Open_Slave,
809 channel->wires[STDIN]->slave_name);
819 /* The pty trapping stuff handles EOF for us. Use the "sync" pipe */
820 /* to inform the other side when we don't have that code. */
822 write(channel->sync_pipe[WRITE_SIDE], &c, 1);
823 close(channel->sync_pipe[READ_SIDE]);
824 close(channel->sync_pipe[WRITE_SIDE]);
825 #endif /* __hpux_pty */
827 /* Duplicate these file descriptors to 3, 4, 5 so we don't have to
828 worry about any of std[in|out|err]fd being 0, 1, or 2. */
830 spc_dup2(stdinfd, 3);
831 spc_dup2(stdoutfd, 4);
832 spc_dup2(stderrfd, 5);
838 if(IS_SPCIO_STDIN(iomode))
839 set_pty_state(STDIN, &(channel->wires[STDIN]->slave_termio));
840 if(IS_SPCIO_STDOUT(iomode))
841 set_pty_state(STDOUT, &(channel->wires[STDOUT]->slave_termio));
842 if(IS_SPCIO_STDERR(iomode))
843 set_pty_state(STDERR, &(channel->wires[STDERR]->slave_termio));
845 /* Close any other open file descriptors in the child */
852 /*----------------------------------------------------------------------+*/
853 int reset_pty_channel_object(SPC_Channel_Ptr channel)
854 /*----------------------------------------------------------------------+*/
859 call_parent_method(channel, reset, (channel), result);
861 if(result==SPC_ERROR)
866 /* Make any special circumstances required on master side of pty */
868 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
872 int fd=wirelist->fd[MASTER_SIDE];
873 /* Disable trapping of ioctl/open/close */
874 if(SPC_Disable_Trapping(fd) == SPC_ERROR)
877 #endif /* __hpux_pty */
879 wirelist->flags &= ~SPCIO_DATA;
885 /*----------------------------------------------------------------------+*/
886 int attach_pty_channel_object(SPC_Channel_Ptr channel, int pid)
887 /*----------------------------------------------------------------------+*/
889 set_pty_state(channel->file_descs[STDIN],
890 &(channel->wires[STDIN]->master_termio));
891 set_pty_state(channel->file_descs[STDOUT],
892 &(channel->wires[STDOUT]->master_termio));
893 set_pty_state(channel->file_descs[STDERR],
894 &(channel->wires[STDERR]->master_termio));
898 if(!mempf0(channel, pre_fork))
904 /*----------------------------------------------------------------------+*/
905 int add_input_pty_channel_object(SPC_Channel_Ptr channel,
906 SbInputHandlerProc handler,
908 /*----------------------------------------------------------------------+*/
911 Wire *wirelist, *stdinwire;
913 call_parent_method(channel, add_input, (channel, handler, data), result);
915 if(result==SPC_ERROR)
918 stdinwire=channel->wires[STDIN];
920 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
922 if((wirelist->read_toolkit_id != -1) ||
923 (wirelist->except_toolkit_id != -1))
926 fd=wirelist->fd[READ_SIDE];
927 SPC_XtAddInput(channel,
928 &wirelist->read_toolkit_id,
930 channel->class_ptr->input,
933 SPC_XtAddInput(channel,
934 &wirelist->except_toolkit_id,
936 channel->class_ptr->input,
938 #endif /* __hpux_pty */
945 Wire *setpgrp_wire = NULL;
947 struct termios *XeTermioStruct = NULL;
948 struct termios XeDefaultTermioStruct;
950 /*----------------------------------------------------------------------+*/
951 void InitDefaultTermioStruct(void)
952 /*----------------------------------------------------------------------+*/
956 XeDefaultTermioStruct.c_iflag = BRKINT | IGNPAR | ICRNL | IXON;
957 XeDefaultTermioStruct.c_oflag = OPOST | ONLCR;
958 XeDefaultTermioStruct.c_cflag = CS8 | CREAD | CLOCAL;
959 XeDefaultTermioStruct.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
961 cfsetispeed(&XeDefaultTermioStruct, B9600);
962 cfsetospeed(&XeDefaultTermioStruct, B9600);
964 for(i=0; i<NCCS; i++)
965 XeDefaultTermioStruct.c_cc[i] = 0;
967 XeDefaultTermioStruct.c_cc[VEOF] = 04; /* ^d */
968 XeDefaultTermioStruct.c_cc[VEOL] = 0; /* no extra eol char */
969 XeDefaultTermioStruct.c_cc[VERASE] = 010; /* ^h */
970 XeDefaultTermioStruct.c_cc[VINTR] = 03; /* ^c */
971 XeDefaultTermioStruct.c_cc[VKILL] = 025; /* ^u */
972 XeDefaultTermioStruct.c_cc[VQUIT] = 034; /* ^\ */
973 XeDefaultTermioStruct.c_cc[VSTART] = 021; /* ^q */
974 XeDefaultTermioStruct.c_cc[VSTOP] = 023; /* ^s */
975 XeDefaultTermioStruct.c_cc[VSUSP] = 032; /* ^z */
977 /* MIN and TIME are not needed in canonical ("line" or "cooked") mode */
982 /*----------------------------------------------------------------------+*/
983 struct termios *SPC_Get_Current_Termio(void)
984 /*----------------------------------------------------------------------+*/
987 struct termios *termio_struct;
989 static Boolean default_is_initialized = FALSE;
992 if (!default_is_initialized)
994 default_is_initialized = TRUE;
995 InitDefaultTermioStruct();
997 _DtSvcProcessUnlock();
999 termio_struct = (struct termios *)XeMalloc(sizeof(struct termios));
1001 /* See if we can open /dev/tty go get default settings for this system */
1005 tty_fd = open("/dev/tty", O_RDWR);
1010 /* retval=ioctl(tty_fd, TCGETA, termio_struct); */
1011 retval = tcgetattr(tty_fd, termio_struct);
1014 if(retval == ERROR) {
1015 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcgetattr");
1017 /* Fall through and use default settings */
1020 return(termio_struct);
1023 /* We get here if we can't open /dev/tty or the tcgetattr() call failed */
1025 memcpy(termio_struct, &XeDefaultTermioStruct, sizeof(struct termios));
1026 return(termio_struct);
1029 /*----------------------------------------------------------------------+*/
1030 int SPC_Setpgrp(int read_current_termio)
1031 /*----------------------------------------------------------------------+*/
1033 _DtSvcProcessLock();
1034 if(setpgrp_wire == NULL)
1035 setpgrp_wire = get_new_wire();
1037 if(read_current_termio || XeTermioStruct == NULL) {
1040 free((char *)XeTermioStruct);
1042 if((XeTermioStruct=SPC_Get_Current_Termio()) == SPC_ERROR) {
1043 _DtSvcProcessUnlock();
1048 spc_close(setpgrp_wire->fd[MASTER_SIDE]);
1049 spc_close(setpgrp_wire->fd[SLAVE_SIDE]);
1051 if((initpty(setpgrp_wire)) == SPC_ERROR) {
1052 spc_close(setpgrp_wire->fd[MASTER_SIDE]);
1053 spc_close(setpgrp_wire->fd[SLAVE_SIDE]);
1054 _DtSvcProcessUnlock();
1058 /* Point of no return */
1062 if((setpgrp_wire->fd[SLAVE_SIDE]=open(setpgrp_wire->slave_name, O_RDWR)) < 0) {
1063 _DtSvcProcessUnlock();
1067 if(tcsetattr(setpgrp_wire->fd[SLAVE_SIDE], TCSANOW, XeTermioStruct)==ERROR) {
1068 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcsetattr");
1069 _DtSvcProcessUnlock();
1073 _DtSvcProcessUnlock();
1083 int set_termio_pty_channel_object(SPC_Channel_Ptr channel,
1086 struct termios *termio)
1088 struct termios *old_termio;
1090 if(side == MASTER_SIDE)
1091 old_termio = &channel->wires[connection]->master_termio;
1093 old_termio = &channel->wires[connection]->slave_termio;
1095 memcpy(old_termio, termio, sizeof(struct termios));
1102 static int send_eof_pty_channel_object(SPC_Channel_Ptr channel)
1104 Wire *wire = channel->wires[STDIN];
1111 if((wire->slave_termio.c_lflag & ~ICANON) == 0)
1114 output_char = wire->slave_termio.c_cc[VEOF];
1115 fd = channel->file_descs[STDIN];
1117 /* Write twice -- once to flush output, and once to have 0 bytes sent. */
1119 ret = write(fd, &output_char, 1);
1120 ret = write(fd, &output_char, 1);