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(__cplusplus)
68 #if defined(__apollo) && !defined(ONLCR)
69 # define ONLCR 0 /* This guy (XPG3), not on apollo yet */
80 #include <sys/ttycom.h>
85 #include "DtSvcLock.h"
87 /* External declarations */
90 * Pseudo-Terminal device file definitions:
91 * Switch _1 and _2 around if BSD or SYSV conventions are more likely
94 #if defined (SVR4) || defined(AIX)
95 #define MPREFIX_1 "/dev/pty" /* BSD convention ?? */
96 #define SPREFIX_1 "/dev/tty"
98 #define MPREFIX_2 "/dev/ptym/pty" /* AT&T convention ?? */
99 #define SPREFIX_2 "/dev/pty/tty"
102 #define MPREFIX_1 "/dev/ptym/pty" /* AT&T convention ?? */
103 #define SPREFIX_1 "/dev/pty/tty"
105 #define MPREFIX_2 "/dev/pty" /* BSD convention ?? */
106 #define SPREFIX_2 "/dev/tty"
110 #include <sys/ptms.h>
111 static char *MASTER_PATH = "/dev/ptmx";
114 static char *MASTER_NAMES = "pqrstuvwabcefghijklmnoxyz";
116 #define SCANBITS(sfds,step) \
118 for(__i=0; __i<FD_SETSIZE; __i++) \
119 if(FD_ISSET(__i, sfds)) \
123 #define IS_FD_SET(fdarr, res) \
126 for(__i=0; __i<FD_SETSIZE; __i++) \
127 if(FD_ISSET(__i, fdarr)) { \
132 static int send_eof_pty_channel_object(SPC_Channel_Ptr channel);
134 void pty_channel_class_init(object_clasp t)
137 pty_channel_clasp c = (pty_channel_clasp) t;
139 c->new_obj = alloc_channel_object;
141 c->open = open_pty_channel_object;
142 c->close = close_local_channel_object;
143 c->read = read_pty_channel_object;
144 c->write = write_local_channel_object;
145 c->reset = reset_pty_channel_object;
146 c->pre_fork = pre_fork_pty_channel_object;
147 c->post_fork = post_fork_pty_channel_object;
148 c->exec_proc = exec_proc_local_channel_object;
149 c->signal = signal_local_channel_object;
150 c->wait_for_termination=local_channel_object_wait_for_termination;
151 c->attach = attach_pty_channel_object;
152 c->add_input = add_input_pty_channel_object;
153 c->input = local_channel_object_input_handler;
154 c->remove_logfile = remove_logfile_local_channel_object;
156 /* New B.00 methods */
158 c->send_eof = send_eof_pty_channel_object;
159 c->set_termio = set_termio_pty_channel_object;
163 static struct pty_channel_class pty_channel_class_struct = {
164 (channel_clasp) &channel_class, /* base class pointer */
165 "pty_channel", /* class name */
166 pty_channel_class_init, /* class initialize function */
167 sizeof(SPC_Channel), /* size */
171 pty_channel_clasp pty_channel_class = &pty_channel_class_struct;
174 static XeChar *hexdigits = "0123456789abcdef";
177 /*----------------------------------------------------------------------+*/
178 static SPC_Disable_Trapping(int fd)
179 /*----------------------------------------------------------------------+*/
183 struct request_info req_info;
185 /* Disable trapping */
186 ioctl(fd, TIOCTRAP, &disable);
188 /* Just in case, flush any queued requests */
190 while((ioctl(fd, TIOCTRAPSTATUS, &flag) != ERROR) && flag) {
191 ioctl(fd, TIOCREQGET, &req_info);
192 ioctl(fd, TIOCREQSET, &req_info);
196 #endif /* __hpux_pty */
199 * Routines for opening pty master/slave devices
204 /*----------------------------------------------------------------------+*/
205 static int getspec1170ptypair(Wire *wire)
206 /*----------------------------------------------------------------------+*/
209 struct sigaction newAction, oldAction;
211 strcpy(wire->master_name, MASTER_PATH);
213 if ((wire->fd[MASTER_SIDE] = open(wire->master_name, O_RDWR)) < OK)
215 /* open(master) failed. */
219 /* SIGCHLD handler, if any, must be disabled during grantpt! */
220 sigaction(SIGCHLD, (struct sigaction *)NULL, &oldAction);
221 if (oldAction.sa_handler != SIG_DFL)
223 newAction = oldAction;
224 newAction.sa_handler = SIG_DFL;
225 sigaction(SIGCHLD, &newAction, (struct sigaction *)NULL);
228 if (grantpt(wire->fd[MASTER_SIDE]) != OK)
230 /* cannot access the slave pty. */
231 close(wire->fd[MASTER_SIDE]);
235 /* Restore SIGCHLD handler. */
236 if (oldAction.sa_handler != SIG_DFL)
237 sigaction(SIGCHLD, &oldAction, (struct sigaction *)NULL);
239 if ((unlockpt(wire->fd[MASTER_SIDE]) != OK) ||
240 ((slaveName = ptsname(wire->fd[MASTER_SIDE])) == (char *)NULL) ||
241 (access(slaveName, R_OK | W_OK) == ERROR))
243 /* cannot access the slave pty. */
244 close(wire->fd[MASTER_SIDE]);
248 /* we have opened a master with a slave we can access */
249 strcpy(wire->slave_name, slaveName);
255 /* This is not exactly what should be done. We really should open the
256 directory which contains "suspected" ptys. Then read the directory
257 to get filenames, then check each file name to tell whether it is a
258 master pty. However, for the time being, we will use the old way.
262 /*----------------------------------------------------------------------+*/
263 static int getptypair(Wire *wire)
264 /*----------------------------------------------------------------------+*/
266 /* Attempt to open the master/slave pair of preset pty */
268 XeString master=wire->master_name;
269 XeString slave =wire->slave_name;
274 XeString sptr; /* Point to end of preset prefixes */
275 int c_len = strlen (MASTER_NAMES);
277 /* Set things up to quickly alter last 2 chars of path strings */
278 mptr = master + strlen(master);
279 *(mptr+2) = (XeChar)'\0';
281 sptr = slave + strlen(slave);
282 *(sptr+2) = (XeChar)'\0';
284 for (c = 0; c < c_len; c++) { /* 1st char */
286 /* Get the next character in order */
287 *(mptr) = *(sptr) = MASTER_NAMES[c];
289 for (d = 0; d < 15; d++) { /* 2nd char: 0..9,a..f */
291 /* Get the next hex number in order */
292 *(mptr+1) = hexdigits[d];
294 /* Attempt to open this master side of pty */
296 if ((wire->fd[MASTER_SIDE] = open(master, O_RDWR)) < OK) {
297 /* open(master) failed, try next master... */
301 *(sptr+1) = hexdigits[d];
303 /* check that we can eventually open the slave side, using
304 the access system call */
305 if(access(slave, R_OK | W_OK) == ERROR) {
306 /* cannot access the slave pty. Close master and try next one */
307 close(wire->fd[MASTER_SIDE]);
311 /* we have opened a master with a slave we can access */
314 } /* End for 2nd char */
315 } /* End for 1st char */
320 /*----------------------------------------------------------------------+*/
321 static int initpty(Wire *wire)
322 /*----------------------------------------------------------------------+*/
324 /* Find first available master/slave pair */
326 /* set both sides of wire to -1 (unitialized convention) */
327 wire->fd[MASTER_SIDE] = wire->fd[SLAVE_SIDE] = -1;
330 if (!getspec1170ptypair(wire))
333 /* Start with convention 1 */
334 strcpy(wire->master_name, MPREFIX_1);
335 strcpy(wire->slave_name, SPREFIX_1);
337 if (!getptypair(wire)) {
338 /* Cannot get that pair, so try convention 2 */
339 strcpy(wire->master_name, MPREFIX_2);
340 strcpy(wire->slave_name, SPREFIX_2);
341 if (!getptypair(wire)) {
342 /* No available pty's ?? */
343 wire->master_name[0] = wire->slave_name[0] = (XeChar)'\0';
344 wire->fd[MASTER_SIDE] = wire->fd[SLAVE_SIDE] = -1;
345 SPC_Error(SPC_No_Pty);
354 /*----------------------------------------------------------------------+*/
355 static int set_pty_state(int fd, struct termios *term_state)
356 /*----------------------------------------------------------------------+*/
359 if (fd < 0 || !isatty(fd))
362 /* Go to cooked mode (modify terminal state) */
363 if(tcsetattr(fd, TCSANOW, term_state)==ERROR) {
364 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcsetattr");
375 if(ioctl(fd, TIOCSWINSZ, &size) == ERROR) {
376 SPC_Error(SPC_Bad_tc_Call,(XeString)"tc_setwinsize");
385 /*----------------------------------------------------------------------+*/
386 int master_pty(int fd, struct termios *state)
387 /*----------------------------------------------------------------------+*/
389 /* Make any special circumstances required on master side of pty */
396 /* Enable trapping of ioctl/open/close (we care about close()) */
397 if(ioctl(fd, TIOCTRAP, &enable)==ERROR) {
398 SPC_Error(SPC_Bad_Ioctl);
401 #endif /* __hpux_pty */
403 set_pty_state(fd, state);
410 /*----------------------------------------------------------------------+*/
411 static Wire *getpty(Wire *prevwire)
412 /*----------------------------------------------------------------------+*/
414 Wire *wire_ptr=get_new_wire();
419 if(initpty(wire_ptr)==SPC_ERROR) {
424 wire_ptr->next=prevwire;
428 static void init_termio(struct termios *term_state)
431 /* Basically, we want the pty channel to act like like a pipe
432 (perhaps later we should get more fancy). This means that we
433 do not do any input processing for KILL / ERASE characters, we don't
434 echo the data, and reads will return when there is at least one character
435 in the buffer to be read. */
437 term_state->c_iflag = 0;
438 term_state->c_oflag = 0;
439 term_state->c_cflag = CS8 | CREAD | HUPCL;
440 term_state->c_lflag = 0;
442 cfsetispeed(term_state, B9600);
443 cfsetospeed(term_state, B9600);
445 term_state->c_cc[VMIN]=1;
446 term_state->c_cc[VTIME]=0;
451 *** Method definitions
455 /*----------------------------------------------------------------------+*/
456 SPC_Channel_Ptr open_pty_channel_object(SPC_Channel_Ptr channel,
459 /*----------------------------------------------------------------------+*/
462 Wire *tmpwire, *newwire;
463 SPC_Channel_Ptr result;
465 call_parent_method(channel, open, (channel, iomode, hostname), result);
467 if(result==SPC_ERROR)
470 /* We know that we are going to use one of STDIN, STDOUT, or STDERR
471 (or else we would be a NOIO channel), so allocate at least one
474 if(!(tmpwire=getpty(NULL)))
477 if (IS_SPCIO_STDIN(iomode)) {
478 channel->wires[STDIN]=tmpwire;
481 if (IS_SPCIO_STDOUT(iomode)) {
482 channel->wires[STDOUT]=tmpwire;
485 if (IS_SPCIO_SEPARATE(iomode)) {
486 if(!(newwire=getpty(tmpwire))) {
487 spc_close(tmpwire->fd[MASTER_SIDE]);
494 if (IS_SPCIO_STDERR(iomode)) {
495 channel->wires[STDERR]=tmpwire;
498 channel->wire_list=tmpwire;
500 /* set up the channel file descriptors */
502 channel->file_descs[STDIN] = (channel->wires[STDIN]) ->fd[MASTER_SIDE];
503 channel->file_descs[STDOUT] = (channel->wires[STDOUT])->fd[MASTER_SIDE];
504 channel->file_descs[STDERR] = (channel->wires[STDERR])->fd[MASTER_SIDE];
506 for(tmpwire=channel->wire_list; tmpwire; tmpwire=tmpwire->next) {
507 init_termio(&tmpwire->master_termio);
508 init_termio(&tmpwire->slave_termio);
515 /*----------------------------------------------------------------------+*/
516 int read_pty_channel_object(SPC_Channel_Ptr channel,
517 int connector, /* STDOUT or STDERR */
520 /*----------------------------------------------------------------------+*/
524 int result, select_value;
525 struct fd_set read_mask, except_mask;
526 int fd=channel->file_descs[connector];
527 struct request_info req_info;
528 struct timeval timeout, *timeptr;
531 call_parent_method(channel,
533 (channel, connector, buffer, nbytes),
536 if(result==SPC_ERROR)
539 if(!IS_SPCIO_DATA(channel->wires[connector]->flags))
543 FD_ZERO(&except_mask);
545 FD_SET(fd, &read_mask);
546 FD_SET(fd, &except_mask);
548 if(channel->close_timeout) {
549 timeout.tv_sec=channel->close_timeout;
551 timeptr = (&timeout);
556 select_value=select(fd+1, &read_mask, NULL, &except_mask, timeptr);
557 while(select_value==ERROR && errno==EINTR);
559 if(select_value==ERROR) {
560 SPC_Error(SPC_Bad_Select);
564 /* If there is anything to read, read it & return */
565 IS_FD_SET(&read_mask, result);
568 result = read(fd, buffer, nbytes);
569 } while (result<0 && errno == EINTR);
571 SPC_Error(SPC_Reading);
577 /* Nothing to read. We either timed out or got an exception. */
579 if(select_value != 0) {
581 /* We got an exception */
582 ioctl(fd, TIOCREQGET, &req_info);
584 /* Clear the request (Not really necessary in the case of a close,
587 ioctl(fd, TIOCREQSET, &req_info);
590 if((select_value == 0) || (req_info.request == TIOCCLOSE)) {
592 /* Close, disable trapping on this fd & return EOF. We regard
593 a timeout as being the same as a close. */
595 SPC_Disable_Trapping(fd);
596 SPC_Change_State(channel, connector, 0, -1);
601 /* Otherwise (open or IOCTL), return -1 */
605 #else /* not __hpux_pty */
608 int fd=channel->file_descs[connector];
611 struct timeval tv={0, 50000};
613 result=ioctl(fd, FIONREAD, &numbytes);
616 result = kill(channel->pid, 0);
617 if((result == -1) && errno == ESRCH) {
618 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
619 SPC_Change_State(channel, connector, 0, -1);
623 FD_SET(fd, &read_mask);
626 ** This call to select doesn't have the cast to (int*), because
627 ** this clause of the ifdef is not compiled on HPUX.
630 result=select(fd+1, &read_mask, NULL, NULL, &tv);
631 if((result == -1) && (errno != EINTR)) {
632 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
633 SPC_Change_State(channel, connector, 0, -1);
636 } while((result <= 0));
639 result = read(fd, buffer, nbytes);
640 } while (result<0 && errno == EINTR);
642 if(result == ERROR) {
644 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
645 SPC_Change_State(channel, connector, 0, -1);
648 XeString connection_hostname = (channel->connection ?
649 CONNECTION_HOSTNAME(channel->connection) :
650 Xestrdup(XeString_Empty));
651 SPC_Error(SPC_Reading, connection_hostname);
652 XeFree(connection_hostname);
659 #endif /* __hpux_pty */
661 /*----------------------------------------------------------------------+*/
662 int pre_fork_pty_channel_object(SPC_Channel_Ptr channel)
663 /*----------------------------------------------------------------------+*/
669 call_parent_method(channel, pre_fork, (channel), result);
671 if(result==SPC_ERROR)
676 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
677 if(master_pty(wirelist->fd[MASTER_SIDE], &wirelist->master_termio)
683 if(pipe(channel->sync_pipe) < 0) {
684 SPC_Error(SPC_No_Pipe);
687 #endif /* __hpux_pty */
693 /*----------------------------------------------------------------------+*/
695 /*----------------------------------------------------------------------+*/
697 /* I am not particularly enamored of this macro. However, the style of
698 the SCANBITS macro kinda forces me to write it this way. In particular,
699 I am a bit worried about the reference to except_mask, which is a
700 "nonlocal reference" */
702 #define clear_trap(fd) {struct request_info req_info; \
704 ioctl(my_fd, TIOCREQGET, &req_info); \
705 if(req_info.request != TIOCOPEN) { \
706 SPC_Error(SPC_Bad_Ioctl); \
709 ioctl(my_fd, TIOCREQSET, &req_info); \
710 FD_CLR(my_fd, &except_mask); \
712 #endif /* __hpux_pty */
714 /*----------------------------------------------------------------------+*/
715 int post_fork_pty_channel_object(SPC_Channel_Ptr channel,
717 /*----------------------------------------------------------------------+*/
722 int iomode=channel->IOMode;
723 int fd=channel->file_descs[STDIN];
724 int stdinfd, stdoutfd, stderrfd;
726 struct fd_set except_mask, temp_mask;
731 call_parent_method(channel, post_fork, (channel, parentp), result);
733 if(result==SPC_ERROR)
736 if (parentp) { /* Master process */
741 stdinfd = channel->wires[STDIN]->fd[MASTER_SIDE];
742 stdoutfd = channel->wires[STDOUT]->fd[MASTER_SIDE];
743 stderrfd = channel->wires[STDERR]->fd[MASTER_SIDE];
745 FD_ZERO(&except_mask);
748 FD_SET(stdinfd, &except_mask);
750 FD_SET(stdoutfd, &except_mask);
752 FD_SET(stderrfd, &except_mask);
754 IS_FD_SET(&except_mask, result);
756 temp_mask = except_mask;
757 select_value=select(max_fds, NULL, NULL, &temp_mask, NULL);
758 SCANBITS(&temp_mask, clear_trap);
759 IS_FD_SET(&except_mask, result);
762 #else /* not __hpux_pty */
763 close(channel->sync_pipe[WRITE_SIDE]);
764 read(channel->sync_pipe[READ_SIDE], &c, 1);
765 close(channel->sync_pipe[READ_SIDE]);
766 channel->sync_pipe[READ_SIDE] = -1;
767 channel->sync_pipe[WRITE_SIDE] = -1;
768 XeSPCAddInput(channel, NULL, NULL);
769 #endif /* __hpux_pty */
771 } else { /* Slave process */
773 /* Open the slave pty. Do it up to three times to set up
774 stdin, stdout, stderr */
784 if(IS_SPCIO_STDIN(iomode)) {
785 if((stdinfd=open(channel->wires[STDIN]->slave_name, O_RDWR))<0) {
786 SPC_Error(SPC_Cannot_Open_Slave,
787 channel->wires[STDIN]->slave_name);
793 if(IS_SPCIO_STDOUT(iomode)) {
794 /* We will always share the file descriptor with STDIN,
799 if((stdoutfd=open(channel->wires[STDOUT]->slave_name, O_RDWR))<0) {
800 SPC_Error(SPC_Cannot_Open_Slave,
801 channel->wires[STDOUT]->slave_name);
808 if(IS_SPCIO_STDERR(iomode)) {
809 /* If we want separate STDOUT/STDERR, open a new FD */
810 if(IS_SPCIO_SEPARATE(iomode)) {
811 if((stderrfd=open(channel->wires[STDERR]->slave_name, O_RDWR))<0) {
812 SPC_Error(SPC_Cannot_Open_Slave,
813 channel->wires[STDIN]->slave_name);
823 /* The pty trapping stuff handles EOF for us. Use the "sync" pipe */
824 /* to inform the other side when we don't have that code. */
826 write(channel->sync_pipe[WRITE_SIDE], &c, 1);
827 close(channel->sync_pipe[READ_SIDE]);
828 close(channel->sync_pipe[WRITE_SIDE]);
829 #endif /* __hpux_pty */
831 /* Duplicate these file descriptors to 3, 4, 5 so we don't have to
832 worry about any of std[in|out|err]fd being 0, 1, or 2. */
834 spc_dup2(stdinfd, 3);
835 spc_dup2(stdoutfd, 4);
836 spc_dup2(stderrfd, 5);
842 if(IS_SPCIO_STDIN(iomode))
843 set_pty_state(STDIN, &(channel->wires[STDIN]->slave_termio));
844 if(IS_SPCIO_STDOUT(iomode))
845 set_pty_state(STDOUT, &(channel->wires[STDOUT]->slave_termio));
846 if(IS_SPCIO_STDERR(iomode))
847 set_pty_state(STDERR, &(channel->wires[STDERR]->slave_termio));
849 /* Close any other open file descriptors in the child */
856 /*----------------------------------------------------------------------+*/
857 int reset_pty_channel_object(SPC_Channel_Ptr channel)
858 /*----------------------------------------------------------------------+*/
863 call_parent_method(channel, reset, (channel), result);
865 if(result==SPC_ERROR)
870 /* Make any special circumstances required on master side of pty */
872 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
876 int fd=wirelist->fd[MASTER_SIDE];
877 /* Disable trapping of ioctl/open/close */
878 if(SPC_Disable_Trapping(fd) == SPC_ERROR)
881 #endif /* __hpux_pty */
883 wirelist->flags &= ~SPCIO_DATA;
889 /*----------------------------------------------------------------------+*/
890 int attach_pty_channel_object(SPC_Channel_Ptr channel, int pid)
891 /*----------------------------------------------------------------------+*/
893 set_pty_state(channel->file_descs[STDIN],
894 &(channel->wires[STDIN]->master_termio));
895 set_pty_state(channel->file_descs[STDOUT],
896 &(channel->wires[STDOUT]->master_termio));
897 set_pty_state(channel->file_descs[STDERR],
898 &(channel->wires[STDERR]->master_termio));
902 if(!mempf0(channel, pre_fork))
908 /*----------------------------------------------------------------------+*/
909 int add_input_pty_channel_object(SPC_Channel_Ptr channel,
910 SbInputHandlerProc handler,
912 /*----------------------------------------------------------------------+*/
915 Wire *wirelist, *stdinwire;
917 call_parent_method(channel, add_input, (channel, handler, data), result);
919 if(result==SPC_ERROR)
922 stdinwire=channel->wires[STDIN];
924 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
926 if((wirelist->read_toolkit_id != -1) ||
927 (wirelist->except_toolkit_id != -1))
930 fd=wirelist->fd[READ_SIDE];
931 SPC_XtAddInput(channel,
932 &wirelist->read_toolkit_id,
934 channel->class_ptr->input,
937 SPC_XtAddInput(channel,
938 &wirelist->except_toolkit_id,
940 channel->class_ptr->input,
942 #endif /* __hpux_pty */
949 Wire *setpgrp_wire = NULL;
951 struct termios *XeTermioStruct = NULL;
952 struct termios XeDefaultTermioStruct;
954 /*----------------------------------------------------------------------+*/
955 void InitDefaultTermioStruct(void)
956 /*----------------------------------------------------------------------+*/
960 XeDefaultTermioStruct.c_iflag = BRKINT | IGNPAR | ICRNL | IXON;
961 XeDefaultTermioStruct.c_oflag = OPOST | ONLCR;
962 XeDefaultTermioStruct.c_cflag = CS8 | CREAD | CLOCAL;
963 XeDefaultTermioStruct.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
965 cfsetispeed(&XeDefaultTermioStruct, B9600);
966 cfsetospeed(&XeDefaultTermioStruct, B9600);
968 for(i=0; i<NCCS; i++)
969 XeDefaultTermioStruct.c_cc[i] = 0;
971 XeDefaultTermioStruct.c_cc[VEOF] = 04; /* ^d */
972 XeDefaultTermioStruct.c_cc[VEOL] = 0; /* no extra eol char */
973 XeDefaultTermioStruct.c_cc[VERASE] = 010; /* ^h */
974 XeDefaultTermioStruct.c_cc[VINTR] = 03; /* ^c */
975 XeDefaultTermioStruct.c_cc[VKILL] = 025; /* ^u */
976 XeDefaultTermioStruct.c_cc[VQUIT] = 034; /* ^\ */
977 XeDefaultTermioStruct.c_cc[VSTART] = 021; /* ^q */
978 XeDefaultTermioStruct.c_cc[VSTOP] = 023; /* ^s */
979 XeDefaultTermioStruct.c_cc[VSUSP] = 032; /* ^z */
981 /* MIN and TIME are not needed in canonical ("line" or "cooked") mode */
986 /*----------------------------------------------------------------------+*/
987 struct termios *SPC_Get_Current_Termio(void)
988 /*----------------------------------------------------------------------+*/
991 struct termios *termio_struct;
993 static Boolean default_is_initialized = FALSE;
996 if (!default_is_initialized)
998 default_is_initialized = TRUE;
999 InitDefaultTermioStruct();
1001 _DtSvcProcessUnlock();
1003 termio_struct = (struct termios *)XeMalloc(sizeof(struct termios));
1005 /* See if we can open /dev/tty go get default settings for this system */
1009 tty_fd = open("/dev/tty", O_RDWR);
1014 /* retval=ioctl(tty_fd, TCGETA, termio_struct); */
1015 retval = tcgetattr(tty_fd, termio_struct);
1018 if(retval == ERROR) {
1019 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcgetattr");
1021 /* Fall through and use default settings */
1024 return(termio_struct);
1027 /* We get here if we can't open /dev/tty or the tcgetattr() call failed */
1029 memcpy(termio_struct, &XeDefaultTermioStruct, sizeof(struct termios));
1030 return(termio_struct);
1033 /*----------------------------------------------------------------------+*/
1034 int SPC_Setpgrp(int read_current_termio)
1035 /*----------------------------------------------------------------------+*/
1037 _DtSvcProcessLock();
1038 if(setpgrp_wire == NULL)
1039 setpgrp_wire = get_new_wire();
1041 if(read_current_termio || XeTermioStruct == NULL) {
1044 free((char *)XeTermioStruct);
1046 if((XeTermioStruct=SPC_Get_Current_Termio()) == SPC_ERROR) {
1047 _DtSvcProcessUnlock();
1052 spc_close(setpgrp_wire->fd[MASTER_SIDE]);
1053 spc_close(setpgrp_wire->fd[SLAVE_SIDE]);
1055 if((initpty(setpgrp_wire)) == SPC_ERROR) {
1056 spc_close(setpgrp_wire->fd[MASTER_SIDE]);
1057 spc_close(setpgrp_wire->fd[SLAVE_SIDE]);
1058 _DtSvcProcessUnlock();
1062 /* Point of no return */
1066 if((setpgrp_wire->fd[SLAVE_SIDE]=open(setpgrp_wire->slave_name, O_RDWR)) < 0) {
1067 _DtSvcProcessUnlock();
1071 if(tcsetattr(setpgrp_wire->fd[SLAVE_SIDE], TCSANOW, XeTermioStruct)==ERROR) {
1072 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcsetattr");
1073 _DtSvcProcessUnlock();
1077 _DtSvcProcessUnlock();
1087 int set_termio_pty_channel_object(SPC_Channel_Ptr channel,
1090 struct termios *termio)
1092 struct termios *old_termio;
1094 if(side == MASTER_SIDE)
1095 old_termio = &channel->wires[connection]->master_termio;
1097 old_termio = &channel->wires[connection]->slave_termio;
1099 memcpy(old_termio, termio, sizeof(struct termios));
1106 static int send_eof_pty_channel_object(SPC_Channel_Ptr channel)
1108 Wire *wire = channel->wires[STDIN];
1115 if((wire->slave_termio.c_lflag & ~ICANON) == 0)
1118 output_char = wire->slave_termio.c_cc[VEOF];
1119 fd = channel->file_descs[STDIN];
1121 /* Write twice -- once to flush output, and once to have 0 bytes sent. */
1123 ret = write(fd, &output_char, 1);
1124 ret = write(fd, &output_char, 1);