2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $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 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);
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);
658 #endif /* __hpux_pty */
660 /*----------------------------------------------------------------------+*/
661 int pre_fork_pty_channel_object(SPC_Channel_Ptr channel)
662 /*----------------------------------------------------------------------+*/
668 call_parent_method(channel, pre_fork, (channel), result);
670 if(result==SPC_ERROR)
675 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
676 if(master_pty(wirelist->fd[MASTER_SIDE], &wirelist->master_termio)
682 if(pipe(channel->sync_pipe) < 0) {
683 SPC_Error(SPC_No_Pipe);
686 #endif /* __hpux_pty */
692 /*----------------------------------------------------------------------+*/
694 /*----------------------------------------------------------------------+*/
696 /* I am not particularly enamored of this macro. However, the style of
697 the SCANBITS macro kinda forces me to write it this way. In particular,
698 I am a bit worried about the reference to except_mask, which is a
699 "nonlocal reference" */
701 #define clear_trap(fd) {struct request_info req_info; \
703 ioctl(my_fd, TIOCREQGET, &req_info); \
704 if(req_info.request != TIOCOPEN) { \
705 SPC_Error(SPC_Bad_Ioctl); \
708 ioctl(my_fd, TIOCREQSET, &req_info); \
709 FD_CLR(my_fd, &except_mask); \
711 #endif /* __hpux_pty */
713 /*----------------------------------------------------------------------+*/
714 int post_fork_pty_channel_object(SPC_Channel_Ptr channel,
716 /*----------------------------------------------------------------------+*/
721 int iomode=channel->IOMode;
722 int fd=channel->file_descs[STDIN];
723 int stdinfd, stdoutfd, stderrfd;
725 struct fd_set except_mask, temp_mask;
730 call_parent_method(channel, post_fork, (channel, parentp), result);
732 if(result==SPC_ERROR)
735 if (parentp) { /* Master process */
740 stdinfd = channel->wires[STDIN]->fd[MASTER_SIDE];
741 stdoutfd = channel->wires[STDOUT]->fd[MASTER_SIDE];
742 stderrfd = channel->wires[STDERR]->fd[MASTER_SIDE];
744 FD_ZERO(&except_mask);
747 FD_SET(stdinfd, &except_mask);
749 FD_SET(stdoutfd, &except_mask);
751 FD_SET(stderrfd, &except_mask);
753 IS_FD_SET(&except_mask, result);
755 temp_mask = except_mask;
756 select_value=select(max_fds, NULL, NULL, &temp_mask, NULL);
757 SCANBITS(&temp_mask, clear_trap);
758 IS_FD_SET(&except_mask, result);
761 #else /* not __hpux_pty */
762 close(channel->sync_pipe[WRITE_SIDE]);
763 read(channel->sync_pipe[READ_SIDE], &c, 1);
764 close(channel->sync_pipe[READ_SIDE]);
765 channel->sync_pipe[READ_SIDE] = -1;
766 channel->sync_pipe[WRITE_SIDE] = -1;
767 XeSPCAddInput(channel, NULL, NULL);
768 #endif /* __hpux_pty */
770 } else { /* Slave process */
772 /* Open the slave pty. Do it up to three times to set up
773 stdin, stdout, stderr */
783 if(IS_SPCIO_STDIN(iomode)) {
784 if((stdinfd=open(channel->wires[STDIN]->slave_name, O_RDWR))<0) {
785 SPC_Error(SPC_Cannot_Open_Slave,
786 channel->wires[STDIN]->slave_name);
792 if(IS_SPCIO_STDOUT(iomode)) {
793 /* We will always share the file descriptor with STDIN,
798 if((stdoutfd=open(channel->wires[STDOUT]->slave_name, O_RDWR))<0) {
799 SPC_Error(SPC_Cannot_Open_Slave,
800 channel->wires[STDOUT]->slave_name);
807 if(IS_SPCIO_STDERR(iomode)) {
808 /* If we want seperate STDOUT/STDERR, open a new FD */
809 if(IS_SPCIO_SEPARATE(iomode)) {
810 if((stderrfd=open(channel->wires[STDERR]->slave_name, O_RDWR))<0) {
811 SPC_Error(SPC_Cannot_Open_Slave,
812 channel->wires[STDIN]->slave_name);
822 /* The pty trapping stuff handles EOF for us. Use the "sync" pipe */
823 /* to inform the other side when we don't have that code. */
825 write(channel->sync_pipe[WRITE_SIDE], &c, 1);
826 close(channel->sync_pipe[READ_SIDE]);
827 close(channel->sync_pipe[WRITE_SIDE]);
828 #endif /* __hpux_pty */
830 /* Duplicate these file descriptors to 3, 4, 5 so we don't have to
831 worry about any of std[in|out|err]fd being 0, 1, or 2. */
833 spc_dup2(stdinfd, 3);
834 spc_dup2(stdoutfd, 4);
835 spc_dup2(stderrfd, 5);
841 if(IS_SPCIO_STDIN(iomode))
842 set_pty_state(STDIN, &(channel->wires[STDIN]->slave_termio));
843 if(IS_SPCIO_STDOUT(iomode))
844 set_pty_state(STDOUT, &(channel->wires[STDOUT]->slave_termio));
845 if(IS_SPCIO_STDERR(iomode))
846 set_pty_state(STDERR, &(channel->wires[STDERR]->slave_termio));
848 /* Close any other open file descriptors in the child */
855 /*----------------------------------------------------------------------+*/
856 int reset_pty_channel_object(SPC_Channel_Ptr channel)
857 /*----------------------------------------------------------------------+*/
862 call_parent_method(channel, reset, (channel), result);
864 if(result==SPC_ERROR)
869 /* Make any special circumstances required on master side of pty */
871 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
875 int fd=wirelist->fd[MASTER_SIDE];
876 /* Disable trapping of ioctl/open/close */
877 if(SPC_Disable_Trapping(fd) == SPC_ERROR)
880 #endif /* __hpux_pty */
882 wirelist->flags &= ~SPCIO_DATA;
888 /*----------------------------------------------------------------------+*/
889 int attach_pty_channel_object(SPC_Channel_Ptr channel, int pid)
890 /*----------------------------------------------------------------------+*/
892 set_pty_state(channel->file_descs[STDIN],
893 &(channel->wires[STDIN]->master_termio));
894 set_pty_state(channel->file_descs[STDOUT],
895 &(channel->wires[STDOUT]->master_termio));
896 set_pty_state(channel->file_descs[STDERR],
897 &(channel->wires[STDERR]->master_termio));
901 if(!mempf0(channel, pre_fork))
907 /*----------------------------------------------------------------------+*/
908 int add_input_pty_channel_object(SPC_Channel_Ptr channel,
909 SbInputHandlerProc handler,
911 /*----------------------------------------------------------------------+*/
914 Wire *wirelist, *stdinwire;
916 call_parent_method(channel, add_input, (channel, handler, data), result);
918 if(result==SPC_ERROR)
921 stdinwire=channel->wires[STDIN];
923 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
925 if((wirelist->read_toolkit_id != -1) ||
926 (wirelist->except_toolkit_id != -1))
929 fd=wirelist->fd[READ_SIDE];
930 SPC_XtAddInput(channel,
931 &wirelist->read_toolkit_id,
933 channel->class_ptr->input,
936 SPC_XtAddInput(channel,
937 &wirelist->except_toolkit_id,
939 channel->class_ptr->input,
941 #endif /* __hpux_pty */
948 Wire *setpgrp_wire = NULL;
950 struct termios *XeTermioStruct = NULL;
951 struct termios XeDefaultTermioStruct;
953 /*----------------------------------------------------------------------+*/
954 void InitDefaultTermioStruct(void)
955 /*----------------------------------------------------------------------+*/
959 XeDefaultTermioStruct.c_iflag = BRKINT | IGNPAR | ICRNL | IXON;
960 XeDefaultTermioStruct.c_oflag = OPOST | ONLCR;
961 XeDefaultTermioStruct.c_cflag = CS8 | CREAD | CLOCAL;
962 XeDefaultTermioStruct.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
964 cfsetispeed(&XeDefaultTermioStruct, B9600);
965 cfsetospeed(&XeDefaultTermioStruct, B9600);
967 for(i=0; i<NCCS; i++)
968 XeDefaultTermioStruct.c_cc[i] = 0;
970 XeDefaultTermioStruct.c_cc[VEOF] = 04; /* ^d */
971 XeDefaultTermioStruct.c_cc[VEOL] = 0; /* no extra eol char */
972 XeDefaultTermioStruct.c_cc[VERASE] = 010; /* ^h */
973 XeDefaultTermioStruct.c_cc[VINTR] = 03; /* ^c */
974 XeDefaultTermioStruct.c_cc[VKILL] = 025; /* ^u */
975 XeDefaultTermioStruct.c_cc[VQUIT] = 034; /* ^\ */
976 XeDefaultTermioStruct.c_cc[VSTART] = 021; /* ^q */
977 XeDefaultTermioStruct.c_cc[VSTOP] = 023; /* ^s */
978 XeDefaultTermioStruct.c_cc[VSUSP] = 032; /* ^z */
980 /* MIN and TIME are not needed in canonical ("line" or "cooked") mode */
985 /*----------------------------------------------------------------------+*/
986 struct termios *SPC_Get_Current_Termio(void)
987 /*----------------------------------------------------------------------+*/
990 struct termios *termio_struct;
992 static Boolean default_is_initialized = FALSE;
995 if (!default_is_initialized)
997 default_is_initialized = TRUE;
998 InitDefaultTermioStruct();
1000 _DtSvcProcessUnlock();
1002 termio_struct = (struct termios *)XeMalloc(sizeof(struct termios));
1004 /* See if we can open /dev/tty go get default settings for this system */
1008 tty_fd = open("/dev/tty", O_RDWR);
1013 /* retval=ioctl(tty_fd, TCGETA, termio_struct); */
1014 retval = tcgetattr(tty_fd, termio_struct);
1017 if(retval == ERROR) {
1018 XeFree((void *)termio_struct);
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 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 !defined(USL) && !defined(__uxp__)
1072 if(tcsetattr(setpgrp_wire->fd[SLAVE_SIDE], TCSANOW, XeTermioStruct)==ERROR) {
1073 SPC_Error(SPC_Bad_tc_Call,(XeString)"tcsetattr");
1074 _DtSvcProcessUnlock();
1079 _DtSvcProcessUnlock();
1089 int set_termio_pty_channel_object(SPC_Channel_Ptr channel,
1092 struct termios *termio)
1094 struct termios *old_termio;
1096 if(side == MASTER_SIDE)
1097 old_termio = &channel->wires[connection]->master_termio;
1099 old_termio = &channel->wires[connection]->slave_termio;
1101 memcpy(old_termio, termio, sizeof(struct termios));
1108 static int send_eof_pty_channel_object(SPC_Channel_Ptr channel)
1110 Wire *wire = channel->wires[STDIN];
1117 if((wire->slave_termio.c_lflag & ~ICANON) == 0)
1120 output_char = wire->slave_termio.c_cc[VEOF];
1121 fd = channel->file_descs[STDIN];
1123 /* Write twice -- once to flush output, and once to have 0 bytes sent. */
1125 ret = write(fd, &output_char, 1);
1126 ret = write(fd, &output_char, 1);