diff options
Diffstat (limited to 'term')
-rw-r--r-- | term/ChangeLog | 405 | ||||
-rw-r--r-- | term/Makefile | 11 | ||||
-rw-r--r-- | term/devio.c | 458 | ||||
-rw-r--r-- | term/hurdio.c | 628 | ||||
-rw-r--r-- | term/main.c | 428 | ||||
-rw-r--r-- | term/munge.c | 44 | ||||
-rw-r--r-- | term/ptyio.c | 169 | ||||
-rw-r--r-- | term/term.h | 133 | ||||
-rw-r--r-- | term/users.c | 819 | ||||
-rw-r--r-- | term/xinl.c | 2 |
10 files changed, 1992 insertions, 1105 deletions
diff --git a/term/ChangeLog b/term/ChangeLog deleted file mode 100644 index a4831628..00000000 --- a/term/ChangeLog +++ /dev/null @@ -1,405 +0,0 @@ -Mon Jul 29 02:46:12 1996 Roland McGrath <roland@baalperazim.frob.com> - - * munge.c (input_character): In LAST_LNEXT case, jump to `alldone' - after putting the char on the queue. - -Fri Jul 19 23:46:39 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * users.c (trivfs_S_file_access): Implement locally always - returning all access. Eventually, this needs to do the right - thing when trivfs wises up wrt modes. - -Tue Jul 16 20:49:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * users.c (trivfs_S_io_read): Bother to set atime when - appropriate. - - * users.c (trivfs_modify_stat): Fill in st->st_mode, st->st_uid, - and st->st_gid ourselves. - (trivfs_S_file_chown): New routine, to override trivfs default. - (trivfs_S_file_chmod): Likewise. - * main.c (main): Initialize term_owner, term_group, and term_mode. - * term.h (term_owner, term_group, term_mode): New variables. - -Thu Jun 20 16:45:57 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * devio.c (devio_abandon_physical_output): Don't do anything if - carrier is off. - -Thu Jun 20 16:26:07 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * Makefile (OBJS): Add ../libfshelp/libfshelp.a. - -Sat May 11 01:18:41 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * iomux.c (parse_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL. - -Fri May 10 09:27:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * users.c: Include <stdio.h>. - - * users.c (init_users): Order args correctly in call to - ports_create_port. - -Thu May 9 19:32:50 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * users.c (call_asyncs): Provide sigcode arg in call to - nowait_msg_sig_post. - - * users.c (init_users): Use new ports_create_port. - * devio.c (device_open_reply): Likewise. - -Thu Apr 25 16:04:17 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ptyio.c (pty_open_hook): Don't do increment of nptyperopens - here. - (pty_po_create_hook): Increment nptyperopens here, but only if this is - for O_READ or O_WRITE. - (pty_po_destroy_hook): Only do decrement if this was for O_READ or - O_WRITE. - * users.c (open_hook): Don't circumvent pty_open_hook, not even - when FLAGS is clear. - -Wed Apr 24 09:24:29 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * users.c (call_asyncs): Add DIR argument; all callers changed. - * term.h: Include <fcntl.h>. - - * users.c (call_asyncs): Remove FORCE argument; all callers changed. - * term.h (enqueue_internal): Go back to only using call_asyncs - when inputq becomes non-empty. - (SUPPRESS_ASYNC): Flag removed. - -Tue Apr 23 17:44:25 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * term.h (enqueue_internal): Use call_asyncs on every character. - (SUPPRESS_ASYNC): New flag. - * users.c (po_create_hook, trivfs_S_io_set_some_openmodes, - trivfs_S_io_set_all_openmodes): If setting ICKY_ASYNC, then use - call_asyncs. - (call_asyncs): New argument, FORCE, which use. All callers changed. - (init_users): Give our self send rights to the async id ports, since - hurd_sig_post uses COPY_SEND. - (trivfs_S_io_get_icky_async_id): Renamed from ..._get_async_icky. - (trivfs_S_file_set_size, trivfs_S_io_seek, - trivfs_S_io_get_icky_async_id, trivfs_S_io_async): Add reply port args. - - * users.c (num_icky_async_peropens): New variable. - (po_create_hook, po_destroy_hook, trivfs_S_io_set_all_openmodes, - trivfs_S_io_set_some_openmodes, trivfs_S_io_clear_some_openmodes): Use - it to enable ICKY_ASYNC to be turned off. - -Tue Apr 23 14:26:22 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * users.c (call_asyncs): Delete local decl; no longer static. - * term.h (dequeue_quote): If this is the outputq, send SIGIO as - appropriate with call_asyncs. - (enqueue_internal): If this is the inputq, send SIGIO as appropriate - with call_asyncs. - (call_asyncs): Add decl. - -Mon Apr 22 14:55:20 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * devio.c (real_speed_to_bogus_speed): EXTB should be 38400, not - 24800. - -Tue Apr 2 16:18:09 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ptyio.c (pty_po_create_hook): Don't do anything here. - (pty_open_hook): Increment nptyperopens here. - -Wed Mar 27 11:51:43 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * users.c (trivfs_S_io_read): Call call_asyncs *before* we release - GLOBAL_LOCK. - (pi_destroy_hook): Leak the hook for now, to try and catch a bug. XXX - - * ptyio.c (pty_io_read): Block using hurd_condition_wait instead - of condition_wait. - -Sat Feb 24 13:56:46 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * ptyio.c (ptyio_init): This can't be a constructor because it - frobs INPUTQ, which is assigned in main. - * main.c (main): Call ptyio_init if appropriate. - * term.h: Declare ptyio_init. - -Wed Feb 14 14:02:54 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * users.c (trivfs_S_io_set_all_openmodes, - trivfs_S_io_set_some_openmodes): Set ICKY_ASYNC in TERMFLAGS if - O_ASYNC is set in BITS. - -Thu Jan 25 22:54:04 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (main): Use trivfs_startup & trivfs_create_port instead - of trivfs_handle_port. - * devio.c (devio_assert_dtr): Use ports_create_port instead of - ports_allocate_port. - -Thu Jan 18 11:50:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * users.c (report_carrier_off): Flush queues when carrier turns - off. - -Tue Dec 26 16:58:55 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * users.c (trivfs_S_io_select): Ask for notification if our reply - port dies. Pass REPLY to pty_io_select(). - * ptyio.c (pty_io_select): Add new reply port parameter, and ask - for notification if it dies. - * term.h (pty_io_select): Add new reply port parameter. - -Fri Dec 22 14:34:38 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (main): Set PEERCNTL to &PTYCTL if we're a slave, not 0. - -Wed Dec 20 13:56:09 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * users.c (S_term_get_nodename, S_term_set_nodename): Get the node - name from our cred->po->cntl->hook rather than NODENAME. - * main.c (main): Put the nodename on ourcntl->hook rather than - NODENAME, and also put our peer's nodname on peercntl->hook. - * term.h (nodename): Variable removed. - - * ptyio.c (ptyopen, nptyperopens, pktnostop, output_stopped): - Initialize to 0. - -Tue Dec 19 19:57:53 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * users.c (trivfs_S_io_read): After a block on the input queue, - don't go back and check the input queue if there is a signal in - progress; wait for the signal to complete first. - (send_signal): Release global_lock around signal RPC. Call - report_sig_start and report_sig_end around signal RPC. - (call_asyncs): Likewise. - (report_sig_start, report_sig_end): New functions. - (sigs_in_progress, input_sig_wait, input_sig_wakeup): New variables. - -Thu Dec 14 12:48:08 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ptyio.c (pty_io_read): When copying TIOCPKT_DATA; account for - size correctly. - - * ptyio.c (pty_io_write): Always tell the user everything was - written. - -Wed Dec 13 19:32:52 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * ptyio.c (pty_io_write): Keep track of how mount we wrote. - -Tue Dec 12 13:53:40 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * ptyio.c (ptyio_init): Make this a constructor function. - - * ptyio.c (pty_open_hook, pty_po_create_hook, - pty_po_destroy_hook): New functions. - (ptyopen, nptyperopens): New variables. - * term.h (pty_open_hook, pty_po_create_hook, pty_po_destroy_hook): - New declarations. - * users.c (open_hook): If this is the pty, then call pty specific - function. - (po_create_hook): Likewise. - (po_destroy_hook): Likewise. - (pi_create_hook): Don't do anything for pty. - (pi_destroy_hook): Likewise. - - * users.c (open_hook): Don't require carrier for opens that don't - want to read or write. - - * users.c (S_tioctl_tiocgpgrp): Omit bogus extra attempt to lock - global_lock. - - * users.c (S_term_get_bottom_type): Return TERM_ON_MASTERPTY when - appropriate. - - * main.c (main): Set BOTTOM. - -Tue Dec 5 15:30:36 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * main.c (main): Totally rework arg parsing and translator - linkage. No longer support being started s a shell program. Now - support pty's, though no attempt is made to deal nicely with the - node collision problem. - -Mon Dec 4 20:09:21 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * term.h (pty_cntl_class, ptyctl): New variables. - * main.c (main): Initialize pty_class, pty_cntl_class, - trivfs_protid_portclasses[1], and trivfs_cntl_portclasses[1]. - (trivfs_protid_portclasses): Increase size to 2. - (trivfs_cntl_portclasses): Likewise. - (trivfs_protid_nportclasses): Increase initialization to 2. - (trivfs_cntl_nportclasses): Likewise. - - * ptyio.c: Include <unistd.h>. - (ptyio_set_bits): If the stop char state has changed, dinkle the - stop bits in the control_byte accordingly. - - * term.h: Include <hurd/trivfs.h> and <sys/types.h>. - (pty_io_write, pty_io_read, pty_io_readable, pty_io_select): New - declarations. - * ptyio.c: Include <fcntl.h>. - (pty_io_read): Add CRED arg. - (pty_io_write): Likewise. - (pty_io_select): Likewise. - * users.c (trivfs_S_io_write): If this is a pty master, call pty - routine to do the work. - (trivfs_S_io_read): Likewise. - (trivfs_S_io_readable): Likewise. - (trivfs_S_io_select): Likewise. - (S_tioctl_tiocmodg): Accept both pty and tty ports. - (S_tioctl_tiocmods): Likewise. - (S_tioctl_tiocexcl): Likewise. - (S_tioctl_tiocnxcl): Likewise. - (S_tioctl_tiocflush): Likewise. - (S_tioctl_tiocgeta): Likewise. - (set_state): Likewise. - (S_tioctl_tiocgetd): Likewise. - (S_tioctl_tiocsetd): Likewise. - (S_tioctl_tiocdrain): Likewise. - (S_tioctl_tiocswinsz): Likewise. - (S_tioctl_tiocgwinsz): Likewise. - (S_tioctl_tiocmget): Likewise. - (S_tioctl_tiocmset): Likewise. - (S_tioctl_tiocmbic): Likewise. - (S_tioctl_tiocmbis): Likewise. - (S_tioctl_tiocstart): Likewise. - (S_tioctl_tiocstop): Likewise. - (S_tioctl_tiocsti): Likewise. - (S_tioctl_tiocoutq): Likewise. - (S_tioctl_tiocspgrp): Likewise. - (S_tioctl_tiocgpgrp): Likewise. - (S_tioctl_tioccdtr): Likewise. - (S_tioctl_tiocsdtr): Likewise. - (S_tioctl_tioccbrk): Likewise. - (S_tioctl_tiocsbrk): Likewise. - (set_state): If this op is being done on the pty master, then - flush output before beginning work. - -Fri Dec 1 14:08:44 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * users.c (trivfs_S_interrupt_operation): Delete function. - - * users.c (S_tioctl_tiocdrain): Free reference on CRED before - returning. - - * munge.c (input_character): Skip much processing if - external_processing is on. - (output_character): Don't do tab expansion of external_processing - is on. - (echo_p): Never echo if external_processing is on. - * users.c (set_state): Make EXTPROC bit read only. When - external_processing, call set_bits even if CIGNORE. - (S_tioctl_tiocext): Deleted function. - * term.h (external_processing): New variable. - - * users.c (trivfs_S_io_readable): If remote_input_mode, then don't - include extra final character as input. - trivfs_S_io_read): If remote_input_mode, copy characters without - interpretation; treat last character left in queue as junk. - (S_tioctl_tiocremote): Deleted function. - * term.h (remote_input_mode): New variable. - - * users.c (S_tioctl_tiocsig, S_tioctl_tiocpkt, - S_tioctl_tiocucntl): Deleted functions. - - * term.h (ptyio_bottom, pty_class): New variables. - * Makefile (SRCS): Added ptyio.c. - * ptyio.c: New file. - - * term.h (struct bottomhalf): New member `notice_input_flushed'. - * devio.c (devio_notice_input_flushed): New function. - (devio_bottom): Add devio_notice_input_flushed. - * users.c (po_destroy_hook): Call notice_input_flushed after - flushing input queues. - (S_tioctl_tiocflush): Likewise. - (set_state): Likewise. - - * munge.c (input_character) [VSTOP]: Suspend physical output after - setting flag. - * term.h (struct bottomhalf): New member `suspend_physical_output'. - * users.c (S_tioctl_tiocstart): Start output after clearing - USER_OUTPUT_SUSP. - (S_tioctl_tiocstop): Suspend physical output after setting flag. - * devio.c (devio_start_output): Honor USER_OUTPUT_SUSP flag. - Restart output if USER_OUTPUT_SUSP flag off and output_stopped true. - (output_stopped): New variable. - (devio_suspend_physical_output): New function. - (devio_bottom): Add devio_suspend_physical_output. - - * users.c (trivfs_S_io_select): Return EINTR if we are cancelled. - - * munge.c (reprint_line): C-r is CHAR_DC2, not DC3. - * term.h (CHAR_DC3): Correct value is '\023'. - (CHAR_DC1, CHAR_DC2): New macros. - -Thu Nov 30 15:50:01 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * devio.c (start_output): Add devio_ prefix; declare static. - All callers changed. - (set_break): Likewise. - (clear_break): Likewise. - (abandon_physical_output): Likewise. - (pending_output_size): Likewise. - (assert_dtr): Likewise. - (desert_dtr): Likewise. - (set_bits): Likewise. - (mdmctl): Likewise. - (mdmstate): Likewise. - (devio_bottom): New variable. - * term.h (struct bottomhalf): New type. - (bottom, devio_bottom): New variables. - (start_output, set_break, clear_break, abandon_physical_output, - pending_output_size, assert_dtr, desert_dtr, set_bits, mdmctl, - mdmstate): Deleted declarations. - - * devio.c (ports_do_mach_notify_send_once): New function. - -Sun Nov 5 02:07:56 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * main.c (main): Add flags arg to fsys_startup call. - -Sat Sep 23 00:48:17 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * term.h: Include errno.h. - -Mon Sep 18 14:51:40 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu> - - * users.c (trivfs_S_file_set_size): Renamed from - trivfs_S_file_truncate. - -Sat Sep 16 13:03:40 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * Makefile (DIST_FILES): Added ourmsg.defs. - (ourmsg_U.h ourmsgUser.c, ourmsg.defs): Targets removed. - -Thu Sep 7 13:08:55 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu> - - * users.c (trivfs_S_io_write): Start pending output before - blocking. - -Fri Sep 1 09:51:11 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu> - - * munge.c (input_character): Clear input queues correctly for - VINTR/VQUIT, VSUSP, and input queue full. - - * users.c (init_users): New function. - * main.c (main): Call init_users. - * term.h (init_users): New decl. - - * users.c (open_hook): Turn on NO_OWNER for fresh opens. - * main.c (main): Assert NO_OWNER in initial state. - - * term.h (output_psize): Delete decl. - (write_character): New decl. - * munge.c (output_character): Don't set echo_qsize or echo_pstart - here. - (write_character): New function. - (echo_char): Use write_character for closing '/' of hderase. - (output_psize): New decl. - * users.c (trivfs_S_io_write): Use write_character instead of - output_character. - * main.c (main): Don't initialize output_psize. - - diff --git a/term/Makefile b/term/Makefile index 8d224f9e..e13763a1 100644 --- a/term/Makefile +++ b/term/Makefile @@ -1,5 +1,5 @@ -# -# Copyright (C) 1995, 1996 Free Software Foundation, Inc. +# +# Copyright (C) 1995,96,97,99, 2000, 2002 Free Software Foundation, Inc. # Written by Michael I. Bushnell, p/BSG. # # This file is part of the GNU Hurd. @@ -22,10 +22,13 @@ dir := term makemode := server target = term -SRCS = devio.c munge.c users.c main.c ptyio.c +SRCS = devio.c munge.c users.c main.c ptyio.c hurdio.c xinl.c LCLHDRS = term.h DIST_FILES = ourmsg.defs -OBJS = $(subst .c,.o,$(SRCS)) termServer.o device_replyServer.o tioctlServer.o ourmsgUser.o ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a ../libthreads/libthreads.a +HURDLIBS = trivfs fshelp iohelp threads ports ihash shouldbeinlibc +OBJS = $(subst .c,.o,$(SRCS)) termServer.o device_replyServer.o tioctlServer.o ourmsgUser.o include ../Makeconf + +device_replyServer-CPPFLAGS = -DTypeCheck=0 -Wno-unused # XXX diff --git a/term/devio.c b/term/devio.c index e8f7f0b6..38eb996c 100644 --- a/term/devio.c +++ b/term/devio.c @@ -1,5 +1,5 @@ -/* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* + Copyright (C) 1995,96,98,99,2000,01,02 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -18,15 +18,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ -#include "term.h" -#include <device/device.h> -#include <device/device_request.h> -#include <hurd/ports.h> -#include <string.h> -#include <sys/types.h> -#include <hurd.h> -#include <stdio.h> +/* Avoid defenition of the baud rates from <ternios.h> at a later time. */ +#include <termios.h> +/* And undefine the baud rates to avoid warnings from + <device/tty_status.h>. */ #undef B50 #undef B75 #undef B110 @@ -40,9 +36,28 @@ #undef B2400 #undef B4800 #undef B9600 +#undef B19200 +#undef B38400 +#undef B57600 +#undef B115200 #undef EXTA #undef EXTB + +#include <assert.h> +#include <errno.h> +#include <error.h> +#include <string.h> + +#include <device/device.h> +#include <device/device_request.h> #include <device/tty_status.h> +#include <cthreads.h> + +#include <hurd.h> +#include <hurd/ports.h> + +#include "term.h" + /* This flag is set if there is an outstanding device_write. */ static int output_pending; @@ -50,8 +65,13 @@ static int output_pending; /* This flag is set if there is an outstanding device_read. */ static int input_pending; -/* This flag is set if there is an outstanding device_open. */ -static int open_pending; +/* Tell the status of any pending open */ +static enum +{ + NOTPENDING, /* no open is pending */ + INITIAL, /* initial open of device pending */ + FAKE, /* open pending to block on dtr */ +} open_pending; static char pending_output[IO_INBAND_MAX]; static int npending_output; @@ -73,24 +93,49 @@ static device_t device_master; static int output_stopped; +/* XXX Mask that omits high bits we are currently not supposed to pass + through. */ +static int char_size_mask_xxx = 0xff; + /* Forward */ -static void devio_desert_dtr (); +static error_t devio_desert_dtr (); +static error_t +devio_init (void) +{ + mach_port_t host_priv; + error_t err; + err = get_privileged_ports (&host_priv, &device_master); + if (err) + return err; + mach_port_deallocate (mach_task_self (), host_priv); + if (!phys_reply_class) + phys_reply_class = ports_create_class (0, 0); + return 0; +} -static void init_devio (void) __attribute__ ((constructor)); -static void -init_devio () +static error_t +devio_fini (void) { - mach_port_t host_priv; - errno = get_privileged_ports (&host_priv, &device_master); - if (errno) + if (phys_reply_pi) { - perror ("Getting priviliged ports"); - exit (1); + mach_port_deallocate (mach_task_self (), phys_reply); + phys_reply = MACH_PORT_NULL; + ports_port_deref (phys_reply_pi); + phys_reply_pi = 0; } - mach_port_deallocate (mach_task_self (), host_priv); - phys_reply_class = ports_create_class (0, 0); + if (phys_reply_writes_pi) + { + mach_port_deallocate (mach_task_self (), phys_reply_writes); + phys_reply_writes = MACH_PORT_NULL; + ports_port_deref (phys_reply_writes_pi); + phys_reply_writes_pi = 0; + } + mach_port_deallocate (mach_task_self (), phys_device); + mach_port_deallocate (mach_task_self (), device_master); + device_master = MACH_PORT_NULL; + return 0; } /* XXX Convert a real speed to a bogus Mach speed. Return @@ -148,6 +193,16 @@ real_speed_to_bogus_speed (int rspeed, int *bspeed) case 38400: *bspeed = EXTB; break; +#ifdef B57600 + case 57600: + *bspeed = B57600; + break; +#endif +#ifdef B115200 + case 115200: + *bspeed = B115200; + break; +#endif default: return -1; } @@ -193,22 +248,30 @@ bogus_speed_to_real_speed (int bspeed) return 19200; case EXTB: return 38400; +#ifdef B57600 + case B57600: + return 57600; +#endif +#ifdef B115200 + case B115200: + return 115200; +#endif } } /* If there are characters on the output queue and no pending output requests, then send them. */ -static void +static error_t devio_start_output () { char *cp; int size; error_t err; - + size = qsize (outputq); if (!size || output_pending || (termflags & USER_OUTPUT_SUSP)) - return; + return 0; if (output_stopped) { @@ -224,10 +287,10 @@ devio_start_output () cp = pending_output + npending_output; npending_output += size; - + while (size--) *cp++ = dequeue (outputq); - + /* Submit all the outstanding characters to the device. */ /* The D_NOWAIT flag does not, in fact, prevent blocks. Instead, it merely causes D_WOULD_BLOCK errors when carrier is down... @@ -239,6 +302,7 @@ devio_start_output () devio_desert_dtr (); else if (!err) output_pending = 1; + return 0; } error_t @@ -250,9 +314,9 @@ device_write_reply_inband (mach_port_t replypt, return EOPNOTSUPP; mutex_lock (&global_lock); - + output_pending = 0; - + if (return_code == 0) { if (amount >= npending_output) @@ -274,7 +338,7 @@ device_write_reply_inband (mach_port_t replypt, devio_desert_dtr (); else devio_start_output (); - + mutex_unlock (&global_lock); return 0; } @@ -290,15 +354,21 @@ device_read_reply_inband (mach_port_t replypt, if (replypt != phys_reply) return EOPNOTSUPP; - + mutex_lock (&global_lock); - + input_pending = 0; - + if (!error_code && (termstate.c_cflag & CREAD)) for (i = 0; i < datalen; i++) { - flush = input_character (data[i]); + int c = data[i]; + + /* XXX Mach only supports 8-bit channels; this munges things + to account for the reality. */ + c &= char_size_mask_xxx; + + flush = input_character (c); if (flush) break; } @@ -313,29 +383,31 @@ device_read_reply_inband (mach_port_t replypt, D_WOULD_BLOCK errors when carrier drops. */ err = device_read_request_inband (phys_device, phys_reply, D_NOWAIT, 0, vm_page_size); - + if (err) devio_desert_dtr (); - else + else input_pending = 1; mutex_unlock (&global_lock); return 0; } -static void +static error_t devio_set_break () { device_set_status (phys_device, TTY_SET_BREAK, 0, 0); + return 0; } -static void +static error_t devio_clear_break () { device_set_status (phys_device, TTY_CLEAR_BREAK, 0, 0); + return 0; } -static void +static error_t devio_abandon_physical_output () { int val = D_WRITE; @@ -343,20 +415,19 @@ devio_abandon_physical_output () /* If this variable is clear, then carrier is gone, so we have nothing to do. */ if (!phys_reply_writes_pi) - return; - + return 0; + mach_port_deallocate (mach_task_self (), phys_reply_writes); ports_reallocate_port (phys_reply_writes_pi); - phys_reply_writes = ports_get_right (phys_reply_writes_pi); - mach_port_insert_right (mach_task_self (), phys_reply_writes, - phys_reply_writes, MACH_MSG_TYPE_MAKE_SEND); + phys_reply_writes = ports_get_send_right (phys_reply_writes_pi); device_set_status (phys_device, TTY_FLUSH, &val, TTY_FLUSH_COUNT); npending_output = 0; output_pending = 0; + return 0; } -static void +static error_t devio_suspend_physical_output () { if (!output_stopped) @@ -364,11 +435,13 @@ devio_suspend_physical_output () device_set_status (phys_device, TTY_STOP, 0, 0); output_stopped = 1; } + return 0; } -static void +static error_t devio_notice_input_flushed () { + return 0; } static int @@ -379,33 +452,19 @@ devio_pending_output_size () return npending_output; } -static void -devio_desert_dtr () -{ - /* This will work, because we set the TF_HUPCLS bit earlier. */ - device_close (phys_device); - mach_port_deallocate (mach_task_self (), phys_device); - phys_device = MACH_PORT_NULL; - - mach_port_deallocate (mach_task_self (), phys_reply); - mach_port_deallocate (mach_task_self (), phys_reply_writes); - phys_reply = phys_reply_writes = MACH_PORT_NULL; - - ports_port_deref (phys_reply_pi); - ports_port_deref (phys_reply_writes_pi); - phys_reply_pi = phys_reply_writes_pi = 0; - - report_carrier_off (); -} - +/* Do this the first time the device is to be opened */ static error_t -devio_assert_dtr () +initial_open () { error_t err; - - if (open_pending || (phys_device != MACH_PORT_NULL)) + + assert (open_pending != FAKE); + + /* Nothing to do */ + if (open_pending == INITIAL) return 0; - + + assert (phys_device == MACH_PORT_NULL); assert (phys_reply == MACH_PORT_NULL); assert (phys_reply_pi == 0); @@ -414,12 +473,10 @@ devio_assert_dtr () if (err) return err; - phys_reply = ports_get_right (phys_reply_pi); - mach_port_insert_right (mach_task_self (), phys_reply, phys_reply, - MACH_MSG_TYPE_MAKE_SEND); + phys_reply = ports_get_send_right (phys_reply_pi); err = device_open_request (device_master, phys_reply, - D_READ|D_WRITE, pterm_name); + D_READ|D_WRITE, tty_arg); if (err) { mach_port_deallocate (mach_task_self (), phys_reply); @@ -427,120 +484,197 @@ devio_assert_dtr () ports_port_deref (phys_reply_pi); phys_reply_pi = 0; } + else + open_pending = INITIAL; + return err; } +static error_t +devio_desert_dtr () +{ + int bits; + + /* Turn off DTR. */ + bits = TM_HUP; + device_set_status (phys_device, TTY_MODEM, + (dev_status_t) &bits, TTY_MODEM_COUNT); + + report_carrier_off (); + return 0; +} + +static error_t +devio_assert_dtr () +{ + error_t err; + + /* The first time is special. */ + if (phys_device == MACH_PORT_NULL) + return initial_open (); + + /* Schedule a fake open to wait for DTR, unless one is already + happening. */ + assert (open_pending != INITIAL); + if (open_pending == FAKE) + return 0; + + err = device_open_request (device_master, phys_reply, + D_READ|D_WRITE, tty_arg); + + if (err) + return err; + + open_pending = FAKE; + return 0; +} + kern_return_t device_open_reply (mach_port_t replyport, int returncode, mach_port_t device) { struct tty_status ttystat; - int count = TTY_STATUS_COUNT; - error_t err; + size_t count = TTY_STATUS_COUNT; + error_t err = 0; if (replyport != phys_reply) return EOPNOTSUPP; mutex_lock (&global_lock); - open_pending = 0; - + assert (open_pending != NOTPENDING); + if (returncode != 0) { - /* Bogus. */ - report_carrier_on (); - report_carrier_off (); - + report_carrier_error (returncode); + mach_port_deallocate (mach_task_self (), phys_reply); phys_reply = MACH_PORT_NULL; ports_port_deref (phys_reply_pi); phys_reply_pi = 0; + + open_pending = NOTPENDING; mutex_unlock (&global_lock); return 0; } - assert (phys_device == MACH_PORT_NULL); - assert (phys_reply_writes == MACH_PORT_NULL); - assert (phys_reply_writes_pi == 0); - phys_device = device; - errno = ports_create_port (phys_reply_class, term_bucket, - sizeof (struct port_info), - &phys_reply_writes_pi); - if (errno) - return errno; - phys_reply_writes = ports_get_right (phys_reply_writes_pi); - mach_port_insert_right (mach_task_self (), phys_reply_writes, - phys_reply_writes, MACH_MSG_TYPE_MAKE_SEND); + if (open_pending == INITIAL) + { + /* Special handling for the first open */ + + assert (phys_device == MACH_PORT_NULL); + assert (phys_reply_writes == MACH_PORT_NULL); + assert (phys_reply_writes_pi == 0); + phys_device = device; + err = ports_create_port (phys_reply_class, term_bucket, + sizeof (struct port_info), + &phys_reply_writes_pi); + if (err) + { + open_pending = NOTPENDING; + mutex_unlock (&global_lock); + return err; + } + phys_reply_writes = ports_get_send_right (phys_reply_writes_pi); + + /* Schedule our first read */ + err = device_read_request_inband (phys_device, phys_reply, D_NOWAIT, + 0, vm_page_size); + + input_pending = 1; + } + else + { + /* This was a fake open, only for the sake of assert DTR. */ + device_close (device); + mach_port_deallocate (mach_task_self (), device); + } device_get_status (phys_device, TTY_STATUS, (dev_status_t)&ttystat, &count); ttystat.tt_breakc = 0; ttystat.tt_flags = TF_ANYP | TF_LITOUT | TF_NOHANG | TF_HUPCLS; - device_set_status (phys_device, TTY_STATUS, + device_set_status (phys_device, TTY_STATUS, (dev_status_t)&ttystat, TTY_STATUS_COUNT); - err = device_read_request_inband (phys_device, phys_reply, D_NOWAIT, - 0, vm_page_size); - - input_pending = 1; report_carrier_on (); if (err) devio_desert_dtr (); + open_pending = NOTPENDING; mutex_unlock (&global_lock); return 0; -} +} -/* Adjust physical state on the basis of the terminal state. +/* Adjust physical state on the basis of the terminal state. Where it isn't possible, mutate terminal state to match reality. */ -static void -devio_set_bits () +static error_t +devio_set_bits (struct termios *state) { - struct tty_status ttystat; - int cnt = TTY_STATUS_COUNT; + if (!(state->c_cflag & CIGNORE) && phys_device != MACH_PORT_NULL) + { + struct tty_status ttystat; + size_t cnt = TTY_STATUS_COUNT; + + /* Find the current state. */ + device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, &cnt); + if (state->__ispeed) + real_speed_to_bogus_speed (state->__ispeed, &ttystat.tt_ispeed); + if (state->__ospeed) + real_speed_to_bogus_speed (state->__ospeed, &ttystat.tt_ospeed); + + /* Try and set it. */ + device_set_status (phys_device, TTY_STATUS, + (dev_status_t) &ttystat, TTY_STATUS_COUNT); + + /* And now make termstate match reality. */ + cnt = TTY_STATUS_COUNT; + device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, &cnt); + state->__ispeed = bogus_speed_to_real_speed (ttystat.tt_ispeed); + state->__ospeed = bogus_speed_to_real_speed (ttystat.tt_ospeed); + + /* Mach forces us to use the normal stop bit convention: + two bits at 110 bps; 1 bit otherwise. */ + if (state->__ispeed == 110) + state->c_cflag |= CSTOPB; + else + state->c_cflag &= ~CSTOPB; - assert (!(termstate.c_cflag & CIGNORE)); + /* Figure out how to munge input, since we are unable to actually + affect what the hardware does. */ + switch (state->c_cflag & CSIZE) + { + case CS5: + char_size_mask_xxx = 0x1f; + break; - if (phys_device == MACH_PORT_NULL) - return; - - /* Find the current state. */ - device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, &cnt); - if (termstate.__ispeed) - real_speed_to_bogus_speed (termstate.__ispeed, &ttystat.tt_ispeed); - if (termstate.__ospeed) - real_speed_to_bogus_speed (termstate.__ospeed, &ttystat.tt_ospeed); - - /* Try and set it. */ - device_set_status (phys_device, TTY_STATUS, - (dev_status_t) &ttystat, TTY_STATUS_COUNT); - - /* And now make termstate match reality. */ - cnt = TTY_STATUS_COUNT; - device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, &cnt); - termstate.__ispeed = bogus_speed_to_real_speed (ttystat.tt_ispeed); - termstate.__ospeed = bogus_speed_to_real_speed (ttystat.tt_ospeed); - - /* Mach forces us to use the normal stop bit convention: - two bits at 110 bps; 1 bit otherwise. */ - if (termstate.__ispeed == 110) - termstate.c_cflag |= CSTOPB; - else - termstate.c_cflag &= ~CSTOPB; - - /* Mach only supports 8 bit channels. So wark the CSIZE to conform. */ - termstate.c_cflag = ((termstate.c_cflag & ~CSIZE) - | ((termstate.c_cflag & PARENB) ? CS7 : CS8)); + case CS6: + char_size_mask_xxx = 0x3f; + break; + + case CS7: + char_size_mask_xxx = 0x7f; + break; + + case CS8: + default: + char_size_mask_xxx = 0xff; + break; + } + if (state->c_cflag & PARENB) + char_size_mask_xxx |= 0x80; + } + return 0; } - -static void + +static error_t devio_mdmctl (int how, int bits) { int oldbits, newbits; - int cnt; + size_t cnt; if ((how == MDMCTL_BIS) || (how == MDMCTL_BIC)) { cnt = TTY_MODEM_COUNT; @@ -556,24 +690,27 @@ devio_mdmctl (int how, int bits) newbits = (oldbits &= ~bits); else newbits = bits; - - device_set_status (phys_device, TTY_MODEM, + + device_set_status (phys_device, TTY_MODEM, (dev_status_t) &newbits, TTY_MODEM_COUNT); + + return 0; } -static int -devio_mdmstate () +static error_t +devio_mdmstate (int *state) { - int bits, cnt; - - cnt = TTY_MODEM_COUNT; + int bits; + size_t cnt = TTY_MODEM_COUNT; device_get_status (phys_device, TTY_MODEM, (dev_status_t) &bits, &cnt); - if (cnt != TTY_MODEM_COUNT) - return 0; + if (cnt == TTY_MODEM_COUNT) + *state = bits; else - return bits; + *state = 0; + return 0; } + /* Unused stubs */ kern_return_t device_read_reply (mach_port_t port, @@ -596,9 +733,9 @@ error_t ports_do_mach_notify_send_once (mach_port_t notify) { error_t err; - + mutex_lock (&global_lock); - + if (notify == phys_reply_writes) { err = 0; @@ -615,7 +752,7 @@ ports_do_mach_notify_send_once (mach_port_t notify) /* end xxx */ input_pending = 0; - + err = device_read_request_inband (phys_device, phys_reply, D_NOWAIT, 0, vm_page_size); if (err) @@ -623,13 +760,13 @@ ports_do_mach_notify_send_once (mach_port_t notify) else input_pending = 1; } - else if (open_pending) + else if (open_pending != NOTPENDING) { - open_pending = 0; + open_pending = NOTPENDING; report_carrier_on (); report_carrier_off (); - + mach_port_deallocate (mach_task_self (), phys_reply); phys_reply = MACH_PORT_NULL; ports_port_deref (phys_reply_pi); @@ -639,14 +776,18 @@ ports_do_mach_notify_send_once (mach_port_t notify) } else err = EOPNOTSUPP; - + mutex_unlock (&global_lock); return err; } -struct bottomhalf devio_bottom = +const struct bottomhalf devio_bottom = { + TERM_ON_MACHDEV, + devio_init, + devio_fini, + NULL, devio_start_output, devio_set_break, devio_clear_break, @@ -660,6 +801,3 @@ struct bottomhalf devio_bottom = devio_mdmctl, devio_mdmstate, }; - - - diff --git a/term/hurdio.c b/term/hurdio.c new file mode 100644 index 00000000..ef34740b --- /dev/null +++ b/term/hurdio.c @@ -0,0 +1,628 @@ +/* + Copyright (C) 1995,96,98,99,2000,01,02 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/BSG and Marcus Brinkmann. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +/* Handle carrier dropped (at least EIO errors in read, write) correctly. */ + +#include <termios.h> + +#include <assert.h> +#include <errno.h> +#include <error.h> +#include <string.h> + +#include <cthreads.h> + +#include <hurd.h> +#include <hurd/ports.h> +#include <hurd/io.h> +#include <hurd/tioctl.h> + +#include "term.h" + + +/* The thread asserting the DTR and performing all reads. Only + different from MACH_PORT_NULL if thread is live and blocked. */ +thread_t reader_thread = MACH_PORT_NULL; + +/* The Hurd file_t representing the terminal. If this is not + MACH_PORT_NULL, it has the additional meaning that the DTR is + asserted. */ +static file_t ioport = MACH_PORT_NULL; + +/* Each bit represents a supported tioctl call in the underlying node. + If we detect that a tioctl is not supported, we clear the bit in + tioc_caps (which is initialized at every open). */ +#define TIOC_CAP_OUTQ 0x001 +#define TIOC_CAP_START 0x002 +#define TIOC_CAP_STOP 0x004 +#define TIOC_CAP_FLUSH 0x008 +#define TIOC_CAP_CBRK 0x010 +#define TIOC_CAP_SBRK 0x020 +#define TIOC_CAP_MODG 0x040 +#define TIOC_CAP_MODS 0x080 +#define TIOC_CAP_GETA 0x100 +#define TIOC_CAP_SETA 0x200 +#define TIOC_CAP_GWINSZ 0x400 +unsigned int tioc_caps; + +/* The thread performing all writes. Only different from + MACH_PORT_NULL if thread is live and blocked. */ +thread_t writer_thread = MACH_PORT_NULL; + +/* This flag is set if the output was suspended. */ +static int output_stopped; +static struct condition hurdio_writer_condition; + +/* Hold the amount of bytes that are currently in the progress of + being written. May be set to zero while you hold the global lock + to drain the pending output buffer. */ +size_t npending_output; + +/* True if we should assert the dtr. */ +int assert_dtr; +static struct condition hurdio_assert_dtr_condition; + + +/* Forward */ +static error_t hurdio_desert_dtr (); +static any_t hurdio_reader_loop (any_t arg); +static any_t hurdio_writer_loop (any_t arg); +static error_t hurdio_set_bits (struct termios *state); + + +static error_t +hurdio_init (void) +{ + condition_init (&hurdio_writer_condition); + condition_init (&hurdio_assert_dtr_condition); + + cthread_detach (cthread_fork (hurdio_reader_loop, 0)); + cthread_detach (cthread_fork (hurdio_writer_loop, 0)); + return 0; +} + +static error_t +hurdio_fini (void) +{ + hurdio_desert_dtr (); + writer_thread = MACH_PORT_NULL; + /* XXX destroy reader thread too */ + return 0; +} + +static error_t +hurdio_gwinsz (struct winsize *size) +{ + if (tioc_caps & TIOC_CAP_GWINSZ) + { + error_t err = tioctl_tiocgwinsz (ioport, size); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + { + tioc_caps &= ~TIOC_CAP_GWINSZ; + err = EOPNOTSUPP; + } + return err; + } + return EOPNOTSUPP; +} + + +/* Assert the DTR if necessary. Must be called with global lock held. */ +static void +wait_for_dtr (void) +{ + while (!assert_dtr) + hurd_condition_wait (&hurdio_assert_dtr_condition, &global_lock); + assert_dtr = 0; + + if (tty_arg == 0) + ioport = termctl->underlying; + else + { + /* Open the file in blocking mode, so that the carrier is + established as well. */ + ioport = file_name_lookup (tty_arg, O_READ|O_WRITE, 0); + if (ioport == MACH_PORT_NULL) + { + report_carrier_error (errno); + return; + } + } + + + error_t err; + struct termios state = termstate; + + /* Assume that we have a full blown terminal initially. */ + tioc_caps = ~0; + + /* Set terminal in raw mode etc. */ + err = hurdio_set_bits (&state); + if (err) + report_carrier_error (err); + else + { + termstate = state; + + /* Signal that we have a carrier. */ + report_carrier_on (); + + /* Signal that the writer thread should resume its work. */ + condition_broadcast (&hurdio_writer_condition); + } +} + + +/* Read and enqueue input characters. Is also responsible to assert + the DTR if necessary. */ +static any_t +hurdio_reader_loop (any_t arg) +{ + /* XXX The input buffer has 256 bytes. */ +#define BUFFER_SIZE 256 + char buffer[BUFFER_SIZE]; + char *data; + size_t datalen; + error_t err; + + mutex_lock (&global_lock); + reader_thread = mach_thread_self (); + + while (1) + { + /* We can only start when the DTR has been asserted. */ + while (ioport == MACH_PORT_NULL) + wait_for_dtr (); + mutex_unlock (&global_lock); + + data = buffer; + datalen = BUFFER_SIZE; + + err = io_read (ioport, &data, &datalen, -1, BUFFER_SIZE); + + mutex_lock (&global_lock); + /* Error or EOF can mean the carrier has been dropped. */ + if (err || !datalen) + hurdio_desert_dtr (); + else + { + if (termstate.c_cflag & CREAD) + { + int i; + + for (i = 0; i < datalen; i++) + if (input_character (data[i])) + break; + } + + if (data != buffer) + vm_deallocate (mach_task_self(), (vm_address_t) data, datalen); + } + } +#undef BUFFER_SIZE + + return 0; +} + + +/* Output characters. */ +static any_t +hurdio_writer_loop (any_t arg) +{ + /* XXX The output buffer has 256 bytes. */ +#define BUFFER_SIZE 256 + char *bufp; + char pending_output[BUFFER_SIZE]; + size_t amount; + error_t err; + int size; + int npending_output_copy; + mach_port_t ioport_copy; + + mutex_lock (&global_lock); + writer_thread = mach_thread_self (); + + while (1) + { + while (writer_thread != MACH_PORT_NULL + && (ioport == MACH_PORT_NULL || !qsize (outputq) + || output_stopped)) + hurd_condition_wait (&hurdio_writer_condition, &global_lock); + if (writer_thread == MACH_PORT_NULL) /* A sign to die. */ + return 0; + + /* Copy characters onto PENDING_OUTPUT, not bothering + those already there. */ + size = qsize (outputq); + + if (size + npending_output > BUFFER_SIZE) + size = BUFFER_SIZE - npending_output; + + bufp = pending_output + npending_output; + npending_output += size; + /* We need to save these values, as otherwise there are races + with hurdio_abandon_physical_output or hurdio_desert_dtr, + which might overwrite the static variables. */ + npending_output_copy = npending_output; + ioport_copy = ioport; + mach_port_mod_refs (mach_task_self (), ioport_copy, + MACH_PORT_RIGHT_SEND, 1); + + while (size--) + *bufp++ = dequeue (outputq); + + /* Submit all the outstanding characters to the I/O port. */ + mutex_unlock (&global_lock); + err = io_write (ioport_copy, pending_output, npending_output_copy, + -1, &amount); + mutex_lock (&global_lock); + + mach_port_mod_refs (mach_task_self (), ioport_copy, + MACH_PORT_RIGHT_SEND, -1); + if (err) + hurdio_desert_dtr (); + else + { + /* Note that npending_output might be set to null in the + meantime by hurdio_abandon_physical_output. */ + if (amount >= npending_output) + { + npending_output = 0; + condition_broadcast (outputq->wait); + } + else + { + /* Copy the characters that didn't get output + to the front of the array. */ + npending_output -= amount; + memmove (pending_output, pending_output + amount, + npending_output); + } + } + } +#undef BUFFER_SIZE + + return 0; +} + + +/* If there are characters on the output queue, then send them. Is + called with global lock held. */ +static error_t +hurdio_start_output () +{ + /* If the output was suspended earlier and not anymore, we have to + tell the underlying port to resume it. */ + if (output_stopped && !(termflags & USER_OUTPUT_SUSP)) + { + if (tioc_caps & TIOC_CAP_START) + { + error_t err = tioctl_tiocstart (ioport); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_START; + } + output_stopped = 0; + } + condition_broadcast (&hurdio_writer_condition); + return 0; +} + + +/* Stop carrier on the line. Is called with global lock held. */ +static error_t +hurdio_set_break () +{ + if (tioc_caps & TIOC_CAP_SBRK) + { + error_t err = tioctl_tiocsbrk (ioport); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_SBRK; + else if (err) + return err; + } + return 0; +} + + +/* Reassert carrier on the line. Is called with global lock held. */ +static error_t +hurdio_clear_break () +{ + if (tioc_caps & TIOC_CAP_CBRK) + { + error_t err = tioctl_tioccbrk (ioport); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_CBRK; + else if (err) + return err; + } + return 0; +} + + +/* This is called when output queues are being flushed. But there may + be pending output which is sitting in a device buffer or other + place lower down than the terminal's output queue; so this is + called to flush whatever other such things may be going on. Is + called with global lock held. */ +static error_t +hurdio_abandon_physical_output () +{ + if (tioc_caps & TIOC_CAP_FLUSH) + { + error_t err = tioctl_tiocflush (ioport, O_WRITE); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_FLUSH; + else if (err) + return err; + } + + /* Make sure that an incomplete write will not be finished. + hurdio_writer_loop must take care that meddling with + npending_output here does not introduce any races. */ + npending_output = 0; + return 0; +} + + +/* Tell the underlying port to suspend all pending output, and stop + output in the bottom handler as well. Is called with the global + lock held. */ +static error_t +hurdio_suspend_physical_output () +{ + if (!output_stopped) + { + if (tioc_caps & TIOC_CAP_STOP) + { + error_t err = tioctl_tiocstop (ioport); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_STOP; + else if (err) + return err; + } + output_stopped = 1; + } + return 0; +} + +/* This is called to notify the bottom half when an input flush has + occurred. It is necessary to support pty packet mode. */ +static error_t +hurdio_notice_input_flushed () +{ + if (tioc_caps & TIOC_CAP_FLUSH) + { + error_t err = tioctl_tiocflush (ioport, O_READ); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_FLUSH; + else if (err) + return err; + } + return 0; +} + + +/* Determine the number of bytes of output pending. */ +static int +hurdio_pending_output_size () +{ + int queue_size = 0; + + if (tioc_caps & TIOC_CAP_OUTQ) + { + error_t err = tioctl_tiocoutq (ioport, &queue_size); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_OUTQ; + else if (err) + queue_size = 0; + } + /* We can not get the correct number, so let's try a guess. */ + return queue_size + npending_output; +} + + +/* Desert the DTR. Is called with global lock held. */ +static error_t +hurdio_desert_dtr () +{ + if (writer_thread != MACH_PORT_NULL) + hurd_thread_cancel (writer_thread); + if (reader_thread != MACH_PORT_NULL) + hurd_thread_cancel (reader_thread); + if (ioport != MACH_PORT_NULL && tty_arg) + { + mach_port_deallocate (mach_task_self (), ioport); + ioport = MACH_PORT_NULL; + } + /* If we are called after hurdio_assert_dtr before the reader thread + had a chance to wake up and open the port, we can prevent it from + doing so by clearing this flag. */ + assert_dtr = 0; + report_carrier_off (); + return 0; +} + + +static error_t +hurdio_assert_dtr () +{ + if (ioport == MACH_PORT_NULL) + { + assert_dtr = 1; + condition_signal (&hurdio_assert_dtr_condition); + } + + return 0; +} + + +/* Adjust physical state on the basis of the terminal state. + Where it isn't possible, mutate terminal state to match + reality. */ +static error_t +hurdio_set_bits (struct termios *state) +{ + error_t err; + struct termios ttystat; + /* This structure equals how the Hurd tioctl_tiocgeta/seta split up + a termios structure into RPC arguments. */ + struct hurd_termios + { + modes_t modes; + ccs_t ccs; + speeds_t speeds; + } *hurd_ttystat = (struct hurd_termios *) &ttystat; + + if (!(state->c_cflag & CIGNORE) && ioport != MACH_PORT_NULL) + { + + /* If we can not get the terminal state, it doesn't make sense + to attempt to change it. Even if we could change it we + wouldn't know what changes took effect. */ + if (!(tioc_caps & TIOC_CAP_GETA)) + /* XXX Maybe return an error here, but then we must do the + right thing in users.c. */ + return 0; + + err = tioctl_tiocgeta (ioport, hurd_ttystat->modes, + hurd_ttystat->ccs, hurd_ttystat->speeds); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + { + tioc_caps &= ~TIOC_CAP_GETA; + /* XXX Maybe return an error here, but then we must do the + right thing in users.c. */ + return 0; + } + else if (err) + return err; + + /* If possible, change the state. Otherwise we will just make + termstate match reality below. */ + if (tioc_caps & TIOC_CAP_SETA) + { + if (state->__ispeed) + hurd_ttystat->speeds[0] = state->__ispeed; + if (state->__ospeed) + hurd_ttystat->speeds[1] = state->__ospeed; + cfmakeraw (&ttystat); + ttystat.c_cflag = state->c_cflag &~ HUPCL; + + err = tioctl_tiocseta (ioport, hurd_ttystat->modes, + hurd_ttystat->ccs, hurd_ttystat->speeds); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_SETA; + else if (err) + return err; + + /* Refetch the terminal state. */ + err = tioctl_tiocgeta (ioport, hurd_ttystat->modes, + hurd_ttystat->ccs, hurd_ttystat->speeds); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_GETA; + else if (err) + return err; + } + + /* And now make termstate match reality. */ + *state = ttystat; + } + + return 0; +} + +/* Diddle the modem control bits. If HOW is MDMCTL_BIC, the bits set + in BITS should be cleared. If HOW is MDMCTL_BIS, the bits in BITS + should be set. Otherwise, bits that are set in BITS should be set, + and the others cleared. */ +static error_t +hurdio_mdmctl (int how, int bits) +{ + error_t err; + int oldbits, newbits; + + if (tioc_caps & TIOC_CAP_MODS) + { + if ((how == MDMCTL_BIS) || (how == MDMCTL_BIC)) + { + if (tioc_caps & TIOC_CAP_MODG) + { + error_t err = tioctl_tiocmodg (ioport, &oldbits); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_MODG; + else if (err) + return err; + } + } + + if (how == MDMCTL_BIS) + newbits = (oldbits | bits); + else if (how == MDMCTL_BIC) + newbits = (oldbits &= ~bits); + else + newbits = bits; + + err = tioctl_tiocmods (ioport, oldbits); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_MODS; + else if (err) + return err; + } + return 0; +} + + +static int +hurdio_mdmstate () +{ + int oldbits; + + if (tioc_caps & TIOC_CAP_MODG) + { + error_t err = tioctl_tiocmodg (ioport, &oldbits); + if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP)) + tioc_caps &= ~TIOC_CAP_MODG; + else if (err) + return 0; /* XXX What else can we do? */ + } + return 0; +} + + + +const struct bottomhalf hurdio_bottom = +{ + TERM_ON_HURDIO, + hurdio_init, + hurdio_fini, + hurdio_gwinsz, + hurdio_start_output, + hurdio_set_break, + hurdio_clear_break, + hurdio_abandon_physical_output, + hurdio_suspend_physical_output, + hurdio_pending_output_size, + hurdio_notice_input_flushed, + hurdio_assert_dtr, + hurdio_desert_dtr, + hurdio_set_bits, + hurdio_mdmctl, + hurdio_mdmstate, +}; diff --git a/term/main.c b/term/main.c index d0702e83..405e7cd8 100644 --- a/term/main.c +++ b/term/main.c @@ -1,5 +1,5 @@ -/* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* main.c - A translator that emulates a terminal. + Copyright (C) 1995,96,97,2000,02 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -23,21 +23,40 @@ #include <fcntl.h> #include <hurd/trivfs.h> #include <stdio.h> +#include <argp.h> #include <hurd/fsys.h> #include <string.h> +#include <error.h> +#include <inttypes.h> +#include <argz.h> + +#include <version.h> + +const char *argp_program_version = STANDARD_HURD_VERSION (term); int trivfs_fstype = FSTYPE_TERM; -int trivfs_fsid = 0; /* pid?? */ +int trivfs_fsid = 0; int trivfs_support_read = 1; int trivfs_support_write = 1; int trivfs_support_exec = 0; int trivfs_allow_open = O_READ|O_WRITE; -struct port_class *trivfs_protid_portclasses[2]; -struct port_class *trivfs_cntl_portclasses[2]; -int trivfs_protid_nportclasses = 2; -int trivfs_cntl_nportclasses = 2; +enum tty_type { T_NONE = 0, T_DEVICE, T_HURDIO, T_PTYMASTER, T_PTYSLAVE }; +static const char *const tty_type_names[] = +{ + [T_DEVICE] = "device", + [T_HURDIO] = "hurdio", + [T_PTYMASTER] = "pty-master", + [T_PTYSLAVE] = "pty-slave", +}; + + +/* The argument line options. */ +char *tty_name; +enum tty_type tty_type; +char *tty_arg; +dev_t rdev; int demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) @@ -52,41 +71,248 @@ demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) || device_reply_server (inp, outp)); } +static struct argp_option options[] = +{ + {"rdev", 'n', "ID", 0, + "The stat rdev number for this node; may be either a" + " single integer, or of the form MAJOR,MINOR"}, + {"name", 'N', "NAME", 0, + "The name of this node, to be returned by term_get_nodename."}, + {"type", 'T', "TYPE", 0, + "Backend type, see below. This determines the meaning of the argument."}, + {0} +}; + +static error_t +parse_opt (int opt, char *arg, struct argp_state *state) +{ + struct + { + dev_t rdev; + int rdev_set; + enum tty_type type; + char *name; + char *arg; + } *const v = state->hook; + + switch (opt) + { + default: + return ARGP_ERR_UNKNOWN; + + case ARGP_KEY_INIT: + state->hook = calloc (1, sizeof *v); + break; + case ARGP_KEY_FINI: + free (v); + state->hook = 0; + break; + + case 'n': + { + char *start = arg; + char *end; + + v->rdev = strtoumax (start, &end, 0); + if (*end == ',') + { + /* MAJOR,MINOR form. */ + start = end; + v->rdev = (rdev << 8) + strtoul (start, &end, 0); + } + + if (end == start || *end != '\0') + { + argp_error (state, "%s: Invalid argument to --rdev", arg); + return EINVAL; + } + + v->rdev_set = 1; + } + break; + + case 'N': + v->name = arg; + break; + + case ARGP_KEY_ARG: + if (!v->name && state->input == 0) + v->name = arg; + else if (!v->type && state->input == 0) + { + case 'T': + if (!strcmp (arg, "device")) + v->type = T_DEVICE; + else if (!strcmp (arg, "hurdio")) + v->type = T_HURDIO; + else if (!strcmp (arg, "pty-master")) + v->type = T_PTYMASTER; + else if (!strcmp (arg, "pty-slave")) + v->type = T_PTYSLAVE; + else + { + argp_error (state, "Invalid terminal type"); + return EINVAL; + } + } + else if (!v->arg) + v->arg = arg; + else + { + argp_error (state, "Too many arguments"); + return EINVAL; + } + break; + + case ARGP_KEY_END: + if ((v->type && v->type != T_HURDIO && v->arg == 0) + || (state->input == 0 && v->name == 0)) + { + argp_error (state, "Too few arguments"); + return EINVAL; + } + break; + + case ARGP_KEY_SUCCESS: + /* Apply the values we've collected. */ + if (v->rdev_set) + rdev = v->rdev; + if (v->name) + { + free (tty_name); + tty_name = strdup (v->name); + } + if (state->input == 0) /* This is startup time. */ + { + tty_type = v->type ?: T_HURDIO; + tty_arg = v->arg ? strdup (v->arg) : 0; + } + else if (v->type || v->arg) + { + /* Dynamic backend switch. */ + if (!v->type) + v->type = T_HURDIO; + switch (v->type) + { + case T_PTYMASTER: + case T_PTYSLAVE: + /* Cannot dynamically switch to pty flavors. */ + return EINVAL; + default: + break; + } + switch (tty_type) + { + case T_PTYMASTER: + case T_PTYSLAVE: + /* Cannot dynamically switch from pty flavors either. */ + return EINVAL; + default: + break; + } + + mutex_lock (&global_lock); + (*bottom->fini) (); + + tty_type = v->type; + switch (tty_type) + { + case T_DEVICE: + bottom = &devio_bottom; + break; + case T_HURDIO: + bottom = &hurdio_bottom; + break; + default: + assert (! "impossible type"); + break; + } + free (tty_arg); + tty_arg = strdup (v->arg); + error_t err = (*bottom->init) (); + if (err == 0 && (termflags & TTY_OPEN)) + err = (*bottom->assert_dtr) (); + mutex_unlock (&global_lock); + return err; + } + break; + + case ARGP_KEY_ERROR: + break; + } + return 0; +} + +static struct argp term_argp = + { options, parse_opt, "NAME TYPE ARG", + "A translator that implements POSIX termios discipline.\v" + "Possible values for TYPE:\n" + " device Use Mach device ARG for underlying i/o.\n" + " hurdio Use file ARG for i/o, underlying node if no ARG.\n" + " pty-master Master for slave at ARG.\n"\ + " pty-slave Slave for master at ARG.\n"\ + "\n" + "The default type is `hurdio', so no arguments uses the underlying node.\n" + "The filename of the node that the translator is attached to should be\n" + "supplied in NAME.\n" + }; + +struct argp *trivfs_runtime_argp = &term_argp; + +error_t +trivfs_append_args (struct trivfs_control *fsys, + char **argz, size_t *argz_len) +{ + error_t err = 0; + + if (rdev) + { + char buf[64]; + snprintf (buf, sizeof buf, "--rdev=%#jx", (uintmax_t)rdev); + err = argz_add (argz, argz_len, buf); + } + + if (!err && tty_name) + err = argz_add (argz, argz_len, "--name") + ?: argz_add (argz, argz_len, tty_name); + + if (!err && tty_type != T_HURDIO) + err = argz_add (argz, argz_len, "--type") + ?: argz_add (argz, argz_len, tty_type_names[tty_type]); + + if (!err && tty_arg) + err = argz_add (argz, argz_len, tty_arg); + + return err; +} + int main (int argc, char **argv) { struct port_class *ourclass, *ourcntlclass; struct port_class *peerclass, *peercntlclass; struct trivfs_control **ourcntl, **peercntl; - mach_port_t bootstrap; - enum {T_DEVICE, T_PTYMASTER, T_PTYSLAVE} type; + mach_port_t bootstrap, right; + struct stat st; + error_t err; + int openmode; term_bucket = ports_create_bucket (); - - tty_cntl_class = ports_create_class (trivfs_clean_cntl, 0); - pty_cntl_class = ports_create_class (trivfs_clean_cntl, 0); - tty_class = ports_create_class (trivfs_clean_protid, 0); - pty_class = ports_create_class (trivfs_clean_protid, 0); + + trivfs_add_control_port_class (&tty_cntl_class); + trivfs_add_control_port_class (&pty_cntl_class); + trivfs_add_protid_port_class (&tty_class); + trivfs_add_protid_port_class (&pty_class); + cttyid_class = ports_create_class (0, 0); - - trivfs_protid_portclasses[0] = tty_class; - trivfs_protid_portclasses[1] = pty_class; - trivfs_cntl_portclasses[0] = tty_cntl_class; - trivfs_cntl_portclasses[1] = pty_cntl_class; init_users (); - task_get_bootstrap_port (mach_task_self (), &bootstrap); - - if (argc != 4) - { - fprintf (stderr, "Usage: term ttyname type arg\n"); - exit (1); - } + argp_parse (&term_argp, argc, argv, 0, 0, 0); - if (!strcmp (argv[2], "device")) + switch (tty_type) { - type = T_DEVICE; + case T_DEVICE: bottom = &devio_bottom; ourclass = tty_class; ourcntlclass = tty_cntl_class; @@ -94,11 +320,26 @@ main (int argc, char **argv) peerclass = 0; peercntlclass = 0; peercntl = 0; - pterm_name = argv[3]; - } - else if (!strcmp (argv[2], "pty-master")) - { - type = T_PTYMASTER; + openmode = 0; + break; + + case T_HURDIO: + bottom = &hurdio_bottom; + ourclass = tty_class; + ourcntlclass = tty_cntl_class; + ourcntl = &termctl; + peerclass = 0; + peercntlclass = 0; + peercntl = 0; + + /* We don't want to have a writable peropen on the underlying node + when we'll never use it. Ideally, we shouldn't open one until we + do need it, in case it has an affect on the underlying node (like + keeping DTR high and such). */ + openmode = O_RDWR; + break; + + case T_PTYMASTER: bottom = &ptyio_bottom; ourclass = pty_class; ourcntlclass = pty_cntl_class; @@ -106,10 +347,10 @@ main (int argc, char **argv) peerclass = tty_class; peercntlclass = tty_cntl_class; peercntl = &termctl; - } - else if (!strcmp (argv[2], "pty-slave")) - { - type = T_PTYSLAVE; + openmode = 0; + break; + + case T_PTYSLAVE: bottom = &ptyio_bottom; ourclass = tty_class; ourcntlclass = tty_cntl_class; @@ -117,85 +358,96 @@ main (int argc, char **argv) peerclass = pty_class; peercntlclass = pty_cntl_class; peercntl = &ptyctl; + openmode = 0; + break; + + default: + /* Should not happen. */ + error (1, 0, "Unknown terminal type"); + /*NOTREACHED*/ + return 1; } - else - { - fprintf (stderr, - "Allowable types are device, pty-master, and pty-slave.\n"); - exit (1); - } - + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + if (bootstrap == MACH_PORT_NULL) - { - fprintf (stderr, "Must be started as a translator\n"); - exit (1); - } + error (1, 0, "Must be started as a translator"); - /* Set our node */ - errno = trivfs_startup (bootstrap, 0, - ourcntlclass, term_bucket, ourclass, term_bucket, - ourcntl); - if (errno) - { - perror ("Starting translator"); - exit (1); - } + /* Set our node. */ + err = trivfs_startup (bootstrap, openmode, + ourcntlclass, term_bucket, ourclass, term_bucket, + ourcntl); + if (err) + error (1, err, "Starting translator"); /* For ptys, the nodename depends on which half is used. For now just use the hook to store the nodename. */ - (*ourcntl)->hook = argv[1]; + (*ourcntl)->hook = tty_name; - /* Set peer */ + /* Set peer. */ if (peerclass) { - char *peer_name = argv[3]; + char *peer_name = tty_arg; file_t file = file_name_lookup (peer_name, O_CREAT|O_NOTRANS, 0666); - if (file != MACH_PORT_NULL) - errno = 0; - - if (! errno) - errno = trivfs_create_control (file, peercntlclass, term_bucket, - peerclass, term_bucket, peercntl); - if (! errno) - errno = file_set_translator (file, 0, FS_TRANS_EXCL | FS_TRANS_SET, - 0, 0, 0, - ports_get_right (*peercntl), - MACH_MSG_TYPE_MAKE_SEND); + if (file == MACH_PORT_NULL) + err = errno; - if (errno) + if (! err) + err = trivfs_create_control (file, peercntlclass, term_bucket, + peerclass, term_bucket, peercntl); + if (! err) { - perror (peer_name); - exit (1); + right = ports_get_send_right (*peercntl); + err = file_set_translator (file, 0, FS_TRANS_EXCL | FS_TRANS_SET, + 0, 0, 0, right, MACH_MSG_TYPE_COPY_SEND); + mach_port_deallocate (mach_task_self (), right); } + if (err) + error (1, err, "%s", peer_name); + (*peercntl)->hook = peer_name; ports_port_deref (*peercntl); } - bzero (&termstate, sizeof (termstate)); + memset (&termstate, 0, sizeof (termstate)); termflags = NO_CARRIER | NO_OWNER; mutex_init (&global_lock); - term_owner = term_group = 0; - term_mode = (bottom == &ptyio_bottom ? 0666 : 0600) | S_IFCHR; + /* Initialize status from underlying node. */ + err = io_stat ((*ourcntl)->underlying, &st); + if (err) + { + /* We cannot stat the underlying node. Fallback to the defaults. */ + term_owner = term_group = 0; + term_mode = (bottom == &ptyio_bottom ? DEFFILEMODE : S_IRUSR | S_IWUSR); + } + else + { + term_owner = st.st_uid; + term_group = st.st_gid; + term_mode = (st.st_mode & ACCESSPERMS); + } + term_mode |= S_IFCHR | S_IROOT; - inputq = create_queue (256, 100, 300); - rawq = create_queue (256, 100, 300); - outputq = create_queue (256, 100, 300); - - if (bottom == &ptyio_bottom) - ptyio_init (); + inputq = create_queue (256, QUEUE_LOWAT, QUEUE_HIWAT); + + rawq = create_queue (256, QUEUE_LOWAT, QUEUE_HIWAT); + + outputq = create_queue (256, QUEUE_LOWAT, QUEUE_HIWAT); + + err = (*bottom->init) (); + if (err) + error (1, err, "Initializing bottom handler"); condition_init (&carrier_alert); condition_init (&select_alert); condition_implies (inputq->wait, &select_alert); condition_implies (outputq->wait, &select_alert); - /* Launch */ - ports_manage_port_operations_multithread (term_bucket, demuxer, 0, 0, - 0, MACH_PORT_NULL); + /* Launch. */ + ports_manage_port_operations_multithread (term_bucket, demuxer, 0, 0, 0); return 0; -} - +} diff --git a/term/munge.c b/term/munge.c index 03ea9106..660a99bd 100644 --- a/term/munge.c +++ b/term/munge.c @@ -1,5 +1,5 @@ /* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1999, 2002 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -49,7 +49,11 @@ poutput (int c) else if (c == '\r') output_psize = 0; else if (c == '\t') - output_psize += (output_psize + 8) % 8; + { + output_psize++; + while (output_psize % 8) + output_psize++; + } else if (c == '\b') output_psize--; @@ -131,7 +135,7 @@ output_width (int c, int loc) int n = loc + 1; while (n % 8) n++; - return n; + return n - loc; } if ((c >= ' ') && (c < '\177')) return 1; @@ -229,7 +233,7 @@ echo_char (char c, int hderase, int quoted) if (echo_double (c, quoted)) { output_character ('^'); - output_character (c + ('A' - CHAR_SOH)); + output_character (c ^ CTRL_BIT); } else output_character (c); @@ -401,8 +405,10 @@ input_character (int c) else { drop_output (); + poutput (cc[VDISCARD]); termflags |= FLUSH_OUTPUT; } + goto alldone; } } @@ -446,13 +452,13 @@ input_character (int c) { if (CCEQ (cc[VSTOP], c)) { - termflags |= USER_OUTPUT_SUSP; - (*bottom->suspend_physical_output) (); - - if (!(CCEQ(cc[VSTART], c))) /* toggle if VSTART == VSTOP */ - /* Alldone code always turns off USER_OUTPUT_SUSP. */ + if (CCEQ(cc[VSTART], c) && (termflags & USER_OUTPUT_SUSP)) + /* Toggle if VSTART == VSTOP. Alldone code always turns + off USER_OUTPUT_SUSP. */ goto alldone; + termflags |= USER_OUTPUT_SUSP; + (*bottom->suspend_physical_output) (); return flush; } if (CCEQ (cc[VSTART], c)) @@ -576,7 +582,7 @@ input_character (int c) echo_char (c, 0, 0); if (CCEQ (cc[VEOF], c) && (lflag & ECHO)) { - /* Special bizzare echo processing for VEOF character. */ + /* Special bizarre echo processing for VEOF character. */ int n; n = echo_double (c, 0) ? 2 : output_width (c, output_psize); while (n--) @@ -636,7 +642,7 @@ input_break () enqueue_quote (qp, '\0'); } -/* Called when a character is recived with a framing error. */ +/* Called when a character is received with a framing error. */ void input_framing_error (int c) { @@ -675,20 +681,24 @@ rescan_inputq () n = qsize (inputq); buf = alloca (n * sizeof (quoted_char)); - bcopy (inputq->cs, buf, n * sizeof (quoted_char)); + memcpy (buf, inputq->cs, n * sizeof (quoted_char)); clear_queue (inputq); for (i = 0; i < n; i++) input_character (unquote_char (buf[i])); } -void + +error_t drop_output () { - clear_queue (outputq); - (*bottom->abandon_physical_output) (); + error_t err = (*bottom->abandon_physical_output) (); + if (!err) + clear_queue (outputq); + return err; } + error_t drain_output () { @@ -709,12 +719,16 @@ create_queue (int size, int lowat, int hiwat) struct queue *q; q = malloc (sizeof (struct queue) + size * sizeof (quoted_char)); + assert (q); + q->susp = 0; q->lowat = lowat; q->hiwat = hiwat; q->cs = q->ce = q->array; q->arraylen = size; q->wait = malloc (sizeof (struct condition)); + assert (q->wait); + condition_init (q->wait); return q; } diff --git a/term/ptyio.c b/term/ptyio.c index 22c46407..9c1509ff 100644 --- a/term/ptyio.c +++ b/term/ptyio.c @@ -1,5 +1,5 @@ -/* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* + Copyright (C) 1995, 1996, 1999, 2002 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -19,12 +19,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include <sys/ioctl.h> -#include <hurd/hurd_types.h> #include <string.h> #include <hurd/ports.h> #include <unistd.h> #include <fcntl.h> #include "term.h" +#include "tioctl_S.h" /* Set if we need a wakeup when tty output has been done */ static int pty_read_blocked = 0; @@ -55,22 +55,22 @@ static int ptyopen = 0; static int nptyperopens = 0; -void -ptyio_init () +static error_t +ptyio_init (void) { condition_implies (inputq->wait, &pty_select_wakeup); condition_implies (&pty_read_wakeup, &pty_select_wakeup); + return 0; } - + error_t pty_open_hook (struct trivfs_control *cntl, - uid_t *uids, u_int nuids, - uid_t *gids, u_int ngids, + struct iouser *user, int flags) { if ((flags & (O_READ|O_WRITE)) == 0) return 0; - + mutex_lock (&global_lock); if (ptyopen) @@ -78,9 +78,18 @@ pty_open_hook (struct trivfs_control *cntl, mutex_unlock (&global_lock); return EBUSY; } - + ptyopen = 1; + + /* Re-initialize pty state. */ + external_processing = 0; + packet_mode = 0; + user_ioctl_mode = 0; + control_byte = 0; + pktnostop = 0; + mutex_unlock (&global_lock); + return 0; } @@ -129,7 +138,7 @@ wake_reader () /* Lower half for tty node */ -static void +static error_t ptyio_start_output () { if (packet_mode && output_stopped && (!(termflags & USER_OUTPUT_SUSP))) @@ -139,9 +148,10 @@ ptyio_start_output () output_stopped = 0; } wake_reader (); + return 0; } -static void +static error_t ptyio_abandon_physical_output () { if (packet_mode) @@ -149,9 +159,10 @@ ptyio_abandon_physical_output () control_byte |= TIOCPKT_FLUSHWRITE; wake_reader (); } + return 0; } -static void +static error_t ptyio_suspend_physical_output () { if (packet_mode) @@ -161,16 +172,17 @@ ptyio_suspend_physical_output () output_stopped = 1; wake_reader (); } + return 0; } -static int +static int ptyio_pending_output_size () { /* We don't maintain any pending output buffer separate from the outputq. */ return 0; } -static void +static error_t ptyio_notice_input_flushed () { if (packet_mode) @@ -178,76 +190,94 @@ ptyio_notice_input_flushed () control_byte |= TIOCPKT_FLUSHREAD; wake_reader (); } + return 0; } -static error_t +static error_t ptyio_assert_dtr () { dtr_on = 1; return 0; } -static void +static error_t ptyio_desert_dtr () { dtr_on = 0; wake_reader (); + return 0; } -static void -ptyio_set_bits () +static error_t +ptyio_set_bits (struct termios *state) { - int stop; - - if (packet_mode && external_processing) + if (packet_mode) { - control_byte |= TIOCPKT_IOCTL; + int wakeup = 0; + int stop = ((state->c_iflag & IXON) + && CCEQ (state->c_cc[VSTOP], CHAR_DC3) + && CCEQ (state->c_cc[VSTART], CHAR_DC1)); + + if (external_processing) + { + control_byte |= TIOCPKT_IOCTL; + wakeup = 1; + } - stop = ((termstate.c_iflag & IXON) - && CCEQ (termstate.c_cc[VSTOP], CHAR_DC3) - && CCEQ (termstate.c_cc[VSTART], CHAR_DC1)); if (pktnostop && stop) { pktnostop = 0; control_byte |= TIOCPKT_DOSTOP; control_byte &= ~TIOCPKT_NOSTOP; + wakeup = 1; } else if (!pktnostop && !stop) { pktnostop = 1; control_byte |= TIOCPKT_NOSTOP; control_byte &= ~TIOCPKT_DOSTOP; + wakeup = 1; } - wake_reader (); + if (wakeup) + wake_reader (); } + return 0; } /* These do nothing. In BSD the associated ioctls get errors, but I'd rather just ignore them. */ -static void +static error_t ptyio_set_break () { + return 0; } -static void +static error_t ptyio_clear_break () { + return 0; } -static void +static error_t ptyio_mdmctl (int a, int b) { + return 0; } -static int -ptyio_mdmstate () +static error_t +ptyio_mdmstate (int *state) { + *state = 0; return 0; } -struct bottomhalf ptyio_bottom = +const struct bottomhalf ptyio_bottom = { + TERM_ON_MASTERPTY, + ptyio_init, + NULL, /* fini */ + NULL, /* gwinsz */ ptyio_start_output, ptyio_set_break, ptyio_clear_break, @@ -275,9 +305,9 @@ pty_io_read (struct trivfs_protid *cred, mach_msg_type_number_t amount) { int size; - + mutex_lock (&global_lock); - + if ((cred->po->openmodes & O_READ) == 0) { mutex_unlock (&global_lock); @@ -285,8 +315,14 @@ pty_io_read (struct trivfs_protid *cred, } while (!control_byte + && (termflags & TTY_OPEN) && (!qsize (outputq) || (termflags & USER_OUTPUT_SUSP))) { + if (cred->po->openmodes & O_NONBLOCK) + { + mutex_unlock (&global_lock); + return EWOULDBLOCK; + } pty_read_blocked = 1; if (hurd_condition_wait (&pty_read_wakeup, &global_lock)) { @@ -294,7 +330,7 @@ pty_io_read (struct trivfs_protid *cred, return EINTR; } } - + if (control_byte) { size = 1; @@ -307,18 +343,18 @@ pty_io_read (struct trivfs_protid *cred, if (packet_mode || user_ioctl_mode) size++; } - + if (size > amount) size = amount; if (size > *datalen) - vm_allocate (mach_task_self (), (vm_address_t *) data, size, 1); + *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); *datalen = size; if (control_byte) { **data = control_byte; if (packet_mode && (control_byte & TIOCPKT_IOCTL)) - bcopy (&termstate, *data + 1, size - 1); + memcpy (*data + 1, &termstate, size - 1); control_byte = 0; } else @@ -338,7 +374,7 @@ pty_io_read (struct trivfs_protid *cred, return 0; } - + /* Validation has already been done by trivfs_S_io_write. */ error_t pty_io_write (struct trivfs_protid *cred, @@ -350,7 +386,7 @@ pty_io_write (struct trivfs_protid *cred, int cancel = 0; mutex_lock (&global_lock); - + if ((cred->po->openmodes & O_WRITE) == 0) { mutex_unlock (&global_lock); @@ -361,7 +397,14 @@ pty_io_write (struct trivfs_protid *cred, { /* Wait for the queue to be empty */ while (qsize (inputq) && !cancel) - cancel = hurd_condition_wait (inputq->wait, &global_lock); + { + if (cred->po->openmodes & O_NONBLOCK) + { + mutex_unlock (&global_lock); + return EWOULDBLOCK; + } + cancel = hurd_condition_wait (inputq->wait, &global_lock); + } if (cancel) { mutex_unlock (&global_lock); @@ -370,7 +413,7 @@ pty_io_write (struct trivfs_protid *cred, for (i = 0; i < datalen; i++) enqueue (&inputq, data[i]); - + /* Extra garbage charater */ enqueue (&inputq, 0); } @@ -398,7 +441,7 @@ pty_io_write (struct trivfs_protid *cred, /* Validation has already been done by trivfs_S_io_readable */ error_t -pty_io_readable (int *amt) +pty_io_readable (size_t *amt) { mutex_lock (&global_lock); if (control_byte) @@ -416,10 +459,10 @@ pty_io_readable (int *amt) /* Validation has already been done by trivfs_S_io_select. */ error_t pty_io_select (struct trivfs_protid *cred, mach_port_t reply, - int *type, int *idtag) + int *type) { int avail = 0; - + if (*type == 0) return 0; @@ -427,7 +470,8 @@ pty_io_select (struct trivfs_protid *cred, mach_port_t reply, while (1) { - if ((*type & SELECT_READ) && (control_byte || qsize (outputq))) + if ((*type & SELECT_READ) + && (control_byte || qsize (outputq) || !(termflags & TTY_OPEN))) avail |= SELECT_READ; if ((*type & SELECT_URG) && control_byte) @@ -435,7 +479,7 @@ pty_io_select (struct trivfs_protid *cred, mach_port_t reply, if ((*type & SELECT_WRITE) && (!remote_input_mode || !qsize (inputq))) avail |= SELECT_WRITE; - + if (avail) { *type = avail; @@ -463,13 +507,18 @@ S_tioctl_tiocsig (io_t port, port, pty_class); if (!cred) return EOPNOTSUPP; - + + mutex_lock (&global_lock); + drop_output (); clear_queue (inputq); clear_queue (rawq); ptyio_notice_input_flushed (); send_signal (sig); + + mutex_unlock (&global_lock); ports_port_deref (cred); + return 0; } @@ -478,12 +527,14 @@ S_tioctl_tiocpkt (io_t port, int mode) { error_t err; - + struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, pty_class); if (!cred) return EOPNOTSUPP; - + + mutex_lock (&global_lock); + if (!!mode == !!packet_mode) err = 0; else if (mode && user_ioctl_mode) @@ -494,7 +545,10 @@ S_tioctl_tiocpkt (io_t port, control_byte = 0; err = 0; } + + mutex_unlock (&global_lock); ports_port_deref (cred); + return err; } @@ -503,12 +557,14 @@ S_tioctl_tiocucntl (io_t port, int mode) { error_t err; - + struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, pty_class); if (!cred) return EOPNOTSUPP; - + + mutex_lock (&global_lock); + if (!!mode == !!user_ioctl_mode) err = 0; else if (mode && packet_mode) @@ -519,7 +575,10 @@ S_tioctl_tiocucntl (io_t port, control_byte = 0; err = 0; } + + mutex_unlock (&global_lock); ports_port_deref (cred); + return err; } @@ -529,7 +588,7 @@ S_tioctl_tiocremote (io_t port, { struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, pty_class); - + if (!cred) return EOPNOTSUPP; @@ -552,7 +611,7 @@ S_tioctl_tiocext (io_t port, port, pty_class); if (!cred) return EOPNOTSUPP; - + mutex_lock (&global_lock); if (mode && !external_processing) { diff --git a/term/term.h b/term/term.h index 954fb73c..81d0efee 100644 --- a/term/term.h +++ b/term/term.h @@ -1,5 +1,5 @@ -/* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* + Copyright (C) 1995,96,98,99, 2002 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -23,7 +23,16 @@ #include <errno.h> #include <hurd/trivfs.h> #include <sys/types.h> +#include <sys/mman.h> #include <fcntl.h> +#include <features.h> +#include <hurd/hurd_types.h> + +#ifdef TERM_DEFINE_EI +#define TERM_EI +#else +#define TERM_EI __extern_inline +#endif #undef MDMBUF #undef ECHO @@ -33,16 +42,26 @@ #undef NOFLSH #include <termios.h> -#define CHAR_SOH '\001' /* C-a */ #define CHAR_EOT '\004' /* C-d */ #define CHAR_DC1 '\021' /* C-q */ #define CHAR_DC2 '\022' /* C-r */ #define CHAR_DC3 '\023' /* C-s */ #define CHAR_USER_QUOTE '\377' /* break quoting, etc. */ +/* This bit specifies control */ +#define CTRL_BIT 0x40 + /* XXX These belong in <termios.h> */ +#ifdef IUCLC +#define ILCASE IUCLC +#else #define ILCASE (1 << 14) +#endif +#ifdef OLCUC +#define OLCASE OLCUC +#else #define OLCASE (1 << 9) +#endif #define OTILDE (1 << 10) /* used in mdmctl device call */ @@ -68,6 +87,13 @@ long termflags; #define NO_OWNER 0x00000200 /* there is no foreground_id */ #define ICKY_ASYNC 0x00000400 /* some user has set O_ASYNC */ +/* Use a high watermark that allows about as much input as once as + other operating systems do. Using something just a bit smaller + than a power of 2 helps to make maximum use of the buffer and avoid + reallocation for just a few bytes. */ +#define QUEUE_LOWAT 200 +#define QUEUE_HIWAT 8100 + /* Global lock */ struct mutex global_lock; @@ -101,9 +127,6 @@ struct trivfs_control *termctl; /* Trivfs control structure for the pty */ struct trivfs_control *ptyctl; -/* Mach device name for this terminal */ -char *pterm_name; - /* The queues we use */ struct queue *inputq, *rawq, *outputq; @@ -123,25 +146,33 @@ uid_t term_group; mode_t term_mode; +/* XXX Including <sys/ioctl.h> or <hurd/ioctl_types.h> leads to "ECHO + undeclared" errors in munge.c or users.c. */ +struct winsize; + /* Functions a bottom half defines */ struct bottomhalf { - void (*start_output) (void); - void (*set_break) (void); - void (*clear_break) (void); - void (*abandon_physical_output) (void); - void (*suspend_physical_output) (void); + enum term_bottom_type type; + error_t (*init) (void); + error_t (*fini) (void); + error_t (*gwinsz) (struct winsize *size); + error_t (*start_output) (void); + error_t (*set_break) (void); + error_t (*clear_break) (void); + error_t (*abandon_physical_output) (void); + error_t (*suspend_physical_output) (void); int (*pending_output_size) (void); - void (*notice_input_flushed) (void); + error_t (*notice_input_flushed) (void); error_t (*assert_dtr) (void); - void (*desert_dtr) (void); - void (*set_bits) (void); - void (*mdmctl) (int, int); - int (*mdmstate) (void); + error_t (*desert_dtr) (void); + error_t (*set_bits) (struct termios *state); + error_t (*mdmctl) (int how, int bits); + error_t (*mdmstate) (int *state); }; -struct bottomhalf *bottom; -extern struct bottomhalf devio_bottom, ptyio_bottom; +const struct bottomhalf *bottom; +extern const struct bottomhalf devio_bottom, hurdio_bottom, ptyio_bottom; /* Character queues */ @@ -160,38 +191,53 @@ struct queue struct queue *create_queue (int size, int lowat, int hiwat); +extern int qsize (struct queue *q); +extern int qavail (struct queue *q); +extern void clear_queue (struct queue *q); +extern quoted_char dequeue_quote (struct queue *q); +extern char dequeue (struct queue *q); +extern void enqueue_internal (struct queue **qp, quoted_char c); +extern void enqueue (struct queue **qp, char c); +extern void enqueue_quote (struct queue **qp, char c); +extern char unquote_char (quoted_char c); +extern int char_quoted_p (quoted_char c); +extern short queue_erase (struct queue *q); + +#if defined(__USE_EXTERN_INLINES) || defined(TERM_DEFINE_EI) /* Return the number of characters in Q. */ -extern inline int +TERM_EI int qsize (struct queue *q) { return q->ce - q->cs; } /* Return nonzero if characters can be added to Q. */ -extern inline int +TERM_EI int qavail (struct queue *q) { return !q->susp; } /* Flush all the characters from Q. */ -extern inline int +TERM_EI void clear_queue (struct queue *q) { q->susp = 0; q->cs = q->ce = q->array; condition_broadcast (q->wait); } +#endif /* Use extern inlines. */ /* Should be below, but inlines need it. */ void call_asyncs (int dir); +#if defined(__USE_EXTERN_INLINES) || defined(TERM_DEFINE_EI) /* Return the next character off Q; leave the quoting bit on. */ -extern inline quoted_char +TERM_EI quoted_char dequeue_quote (struct queue *q) { int beep = 0; - + assert (qsize (q)); if (q->susp && (qsize (q) < q->lowat)) { @@ -210,23 +256,25 @@ dequeue_quote (struct queue *q) } /* Return the next character off Q. */ -extern inline char +TERM_EI char dequeue (struct queue *q) { return dequeue_quote (q) & ~QUEUE_QUOTE_MARK; } +#endif /* Use extern inlines. */ struct queue *reallocate_queue (struct queue *); +#if defined(__USE_EXTERN_INLINES) || defined(TERM_DEFINE_EI) /* Add C to *QP. */ -extern inline void +TERM_EI void enqueue_internal (struct queue **qp, quoted_char c) { struct queue *q = *qp; if (q->ce - q->array == q->arraylen) q = *qp = reallocate_queue (q); - + *q->ce++ = c; if (qsize (q) == 1) @@ -241,28 +289,28 @@ enqueue_internal (struct queue **qp, quoted_char c) } /* Add C to *QP. */ -extern inline void +TERM_EI void enqueue (struct queue **qp, char c) { enqueue_internal (qp, c); } /* Add C to *QP, marking it with a quote. */ -extern inline void +TERM_EI void enqueue_quote (struct queue **qp, char c) { enqueue_internal (qp, c | QUEUE_QUOTE_MARK); -} +} /* Return the unquoted version of a quoted_char. */ -extern inline char +TERM_EI char unquote_char (quoted_char c) { return c & ~QUEUE_QUOTE_MARK; } /* Tell if a quoted_char is actually quoted. */ -extern inline int +TERM_EI int char_quoted_p (quoted_char c) { return c & QUEUE_QUOTE_MARK; @@ -270,12 +318,12 @@ char_quoted_p (quoted_char c) /* Remove the most recently enqueue character from Q; leaving the quote mark on. */ -extern inline short +TERM_EI short queue_erase (struct queue *q) { short answer; int beep = 0; - + assert (qsize (q)); answer = *--q->ce; if (q->susp && (qsize (q) < q->lowat)) @@ -289,16 +337,18 @@ queue_erase (struct queue *q) condition_broadcast (q->wait); return answer; } +#endif /* Use extern inlines. */ /* Functions devio is supposed to call */ int input_character (int); void report_carrier_on (void); void report_carrier_off (void); +void report_carrier_error (error_t); /* Other decls */ -void drop_output (void); +error_t drop_output (void); void send_signal (int); error_t drain_output (); void output_character (int); @@ -307,18 +357,17 @@ void rescan_inputq (void); void write_character (int); void init_users (void); -/* Call this before using ptyio_bottom. */ -void ptyio_init (void); +extern char *tty_arg; +extern dev_t rdev; /* kludge--these are pty versions of trivfs_S_io_* functions called by the real functions in users.c to do work for ptys. */ -error_t pty_io_write (struct trivfs_protid *, char *, +error_t pty_io_write (struct trivfs_protid *, char *, mach_msg_type_number_t, mach_msg_type_number_t *); -error_t pty_io_read (struct trivfs_protid *, char **, +error_t pty_io_read (struct trivfs_protid *, char **, mach_msg_type_number_t *, mach_msg_type_number_t); -error_t pty_io_readable (int *); -error_t pty_io_select (struct trivfs_protid *, mach_port_t, int *, int *); -error_t pty_open_hook (struct trivfs_control *, uid_t *, u_int, uid_t *, - u_int, int); +error_t pty_io_readable (size_t *); +error_t pty_io_select (struct trivfs_protid *, mach_port_t, int *); +error_t pty_open_hook (struct trivfs_control *, struct iouser *, int); error_t pty_po_create_hook (struct trivfs_peropen *); error_t pty_po_destroy_hook (struct trivfs_peropen *); diff --git a/term/users.c b/term/users.c index 5a72b755..4ec2b810 100644 --- a/term/users.c +++ b/term/users.c @@ -1,5 +1,5 @@ -/* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* + Copyright (C) 1995,96,97,98,99,2000,01,02 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -28,6 +28,9 @@ #include <cthreads.h> #include <hurd.h> #include <stdio.h> +#include <hurd/iohelp.h> +#include <hurd/fshelp.h> +#include <error.h> #include "ourmsg_U.h" @@ -45,10 +48,10 @@ #define TTYDEFCHARS #include <sys/ttydefaults.h> -/* Count of active opens */ +/* Count of active opens. */ int nperopens; -/* io_async requests */ +/* io_async requests. */ struct async_req { mach_port_t notify; @@ -70,25 +73,26 @@ static int sigs_in_progress; static struct condition input_sig_wait = CONDITION_INITIALIZER; static int input_sig_wakeup; -/* Attach this on the hook of any protid that is a ctty. */ +static error_t carrier_error; + +/* Attach this on the hook of any protid that is a ctty. */ struct protid_hook { int refcnt; - pid_t pid, pgrp; + pid_t pid, pgrp, sid; }; void init_users () { - errno = ports_create_port (cttyid_class, term_bucket, - sizeof (struct port_info), &cttyid); - if (errno) - { - perror ("Allocating cttyid"); - exit (1); - } + error_t err; + + err = ports_create_port (cttyid_class, term_bucket, + sizeof (struct port_info), &cttyid); + if (err) + error (1, err, "Allocating cttyid"); - mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, + mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &async_icky_id); /* Add a send right, since hurd_sig_post needs one. */ mach_port_insert_right (mach_task_self (), @@ -100,19 +104,46 @@ init_users () mach_port_insert_right (mach_task_self (), async_id, async_id, MACH_MSG_TYPE_MAKE_SEND); } - + + +static error_t +check_access_hook (struct trivfs_control *cntl, + struct iouser *user, + mach_port_t realnode, + int *allowed) +{ + struct stat st; + + mutex_lock (&global_lock); + + st.st_uid = term_owner; + st.st_gid = term_group; + st.st_mode = term_mode; + + *allowed = 0; + if (fshelp_access (&st, S_IREAD, user) == 0) + *allowed |= O_READ; + if (fshelp_access (&st, S_IWRITE, user) == 0) + *allowed |= O_WRITE; + + mutex_unlock (&global_lock); + return 0; +} +error_t (*trivfs_check_access_hook) (struct trivfs_control *, struct iouser *, + mach_port_t, int *) + = check_access_hook; static error_t open_hook (struct trivfs_control *cntl, - uid_t *uids, u_int nuids, - uid_t *gids, u_int ngids, + struct iouser *user, int flags) { + static int open_count = 0; /* XXX debugging */ int cancel = 0; error_t err; - + if (cntl == ptyctl) - return pty_open_hook (cntl, uids, nuids, gids, ngids, flags); + return pty_open_hook (cntl, user, flags); if ((flags & (O_READ|O_WRITE)) == 0) return 0; @@ -121,30 +152,40 @@ open_hook (struct trivfs_control *cntl, if (!(termflags & TTY_OPEN)) { - bzero (&termstate, sizeof termstate); + memset (&termstate, 0, sizeof termstate); /* This is different from BSD: we don't turn on ISTRIP, and we use CS8 rather than CS7|PARENB. */ termstate.c_iflag |= BRKINT | ICRNL | IMAXBEL | IXON | IXANY; termstate.c_oflag |= OPOST | ONLCR | OXTABS; - termstate.c_lflag |= (ECHO | ICANON | ISIG | IEXTEN + termstate.c_lflag |= (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL); termstate.c_cflag |= CREAD | CS8 | HUPCL; - - bcopy (ttydefchars, termstate.c_cc, NCCS); + + memcpy (termstate.c_cc, ttydefchars, NCCS); + + memset (&window_size, 0, sizeof window_size); termflags |= NO_OWNER; } - else if (termflags & EXCL_USE) + else { - mutex_unlock (&global_lock); - return EBUSY; + assert (open_count > 0); /* XXX debugging */ + + if (termflags & EXCL_USE) + { + mutex_unlock (&global_lock); + return EBUSY; + } } - /* Wait for carrier to turn on. */ - while (((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL)) - && !(flags & O_NONBLOCK) - && !cancel) + open_count++; /* XXX debugging */ + + /* XXX debugging */ + assert (! (termstate.c_oflag & OTILDE)); + + /* Assert DTR if necessary. */ + if (termflags & NO_CARRIER) { err = (*bottom->assert_dtr) (); if (err) @@ -152,30 +193,42 @@ open_hook (struct trivfs_control *cntl, mutex_unlock (&global_lock); return err; } - cancel = hurd_condition_wait (&carrier_alert, &global_lock); - } - - if ((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL)) - { - mutex_unlock (&global_lock); - return EWOULDBLOCK; } + + /* Wait for carrier to turn on. */ + while (((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL)) + && !(flags & O_NONBLOCK) + && !cancel) + cancel = hurd_condition_wait (&carrier_alert, &global_lock); + if (cancel) { mutex_unlock (&global_lock); return EINTR; } - - termflags |= TTY_OPEN; - if (!(termstate.c_cflag & CIGNORE)) - (*bottom->set_bits) (); + err = carrier_error; + carrier_error = 0; + + if (!err) + { + struct termios state = termstate; + err = (*bottom->set_bits) (&state); + if (!err) + { + termstate = state; + termflags |= TTY_OPEN; + } + + if (bottom->gwinsz) + (*bottom->gwinsz) (&window_size); + } mutex_unlock (&global_lock); - return 0; + return err; } -error_t (*trivfs_check_open_hook) (struct trivfs_control *, uid_t *, - u_int, uid_t *, u_int, int) +error_t (*trivfs_check_open_hook) (struct trivfs_control *, + struct iouser *, int) = open_hook; static error_t @@ -183,12 +236,12 @@ pi_create_hook (struct trivfs_protid *cred) { if (cred->pi.class == pty_class) return 0; - + mutex_lock (&global_lock); if (cred->hook) ((struct protid_hook *)cred->hook)->refcnt++; mutex_unlock (&global_lock); - + return 0; } error_t (*trivfs_protid_create_hook) (struct trivfs_protid *) = pi_create_hook; @@ -232,7 +285,7 @@ po_create_hook (struct trivfs_peropen *po) error_t (*trivfs_peropen_create_hook) (struct trivfs_peropen *) = po_create_hook; -static void +static void po_destroy_hook (struct trivfs_peropen *po) { if (po->cntl == ptyctl) @@ -247,7 +300,7 @@ po_destroy_hook (struct trivfs_peropen *po) termflags &= ~ICKY_ASYNC; nperopens--; - if (!nperopens) + if (!nperopens && (termflags & TTY_OPEN)) { /* Empty queues */ clear_queue (inputq); @@ -255,7 +308,7 @@ po_destroy_hook (struct trivfs_peropen *po) (*bottom->notice_input_flushed) (); drain_output (); - + /* Possibly drop carrier */ if ((termstate.c_cflag & HUPCL) || (termflags & NO_CARRIER)) (*bottom->desert_dtr) (); @@ -265,22 +318,22 @@ po_destroy_hook (struct trivfs_peropen *po) mutex_unlock (&global_lock); } -void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) +void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = po_destroy_hook; -/* Tell if CRED can do foreground terminal operations */ +/* Tell if CRED can do foreground terminal operations. */ static inline int fg_p (struct trivfs_protid *cred) { struct protid_hook *hook = cred->hook; - + if (!hook || (termflags & NO_OWNER)) return 1; - + if (hook->pid == foreground_id || hook->pgrp == -foreground_id) return 1; - + return 0; } @@ -291,13 +344,13 @@ trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) st->st_fstype = FSTYPE_TERM; st->st_fsid = getpid (); st->st_ino = 0; - st->st_mode &= ~S_IFMT; + st->st_rdev = rdev; st->st_mode = term_mode; st->st_uid = term_owner; st->st_gid = term_group; } -/* Implement term_getctty as described in <hurd/term.defs>. */ +/* Implement term_getctty as described in <hurd/term.defs>. */ kern_return_t S_term_getctty (mach_port_t arg, mach_port_t *id, @@ -306,7 +359,7 @@ S_term_getctty (mach_port_t arg, struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, tty_class); error_t err; - + if (!cred) return EOPNOTSUPP; @@ -325,7 +378,7 @@ S_term_getctty (mach_port_t arg, return err; } -/* Implement termctty_open_terminal as described in <hurd/term.defs>. */ +/* Implement termctty_open_terminal as described in <hurd/term.defs>. */ kern_return_t S_termctty_open_terminal (mach_port_t arg, int flags, @@ -334,6 +387,7 @@ S_termctty_open_terminal (mach_port_t arg, { error_t err; mach_port_t new_realnode; + struct iouser *user; struct trivfs_protid *newcred; struct port_info *pi = ports_lookup_port (term_bucket, arg, cttyid_class); @@ -346,7 +400,9 @@ S_termctty_open_terminal (mach_port_t arg, if (!err) { - err = trivfs_open (termctl, 0, 0, 0, 0, flags, new_realnode, &newcred); + err = iohelp_create_empty_iouser (&user); + if (! err) + err = trivfs_open (termctl, user, flags, new_realnode, &newcred); if (!err) { *result = ports_get_right (newcred); @@ -359,21 +415,27 @@ S_termctty_open_terminal (mach_port_t arg, return err; } -/* Implement term_become_ctty as described in <hurd/term.defs>. */ +/* Implement term_become_ctty as described in <hurd/term.defs>. */ kern_return_t S_term_open_ctty (mach_port_t arg, - pid_t pid, - pid_t pgrp, - mach_port_t *newpt, - mach_msg_type_name_t *newpttype) + pid_t pid, + pid_t pgrp, + mach_port_t *newpt, + mach_msg_type_name_t *newpttype) { error_t err; struct trivfs_protid *newcred; struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, tty_class); - + if (!cred) return EOPNOTSUPP; + if (pid <= 0 || pgrp <= 0) + { + ports_port_deref (cred); + return EINVAL; + } + mutex_lock (&global_lock); if (!cred->po->openmodes & (O_READ|O_WRITE)) @@ -392,10 +454,11 @@ S_term_open_ctty (mach_port_t arg, hook->pid = pid; hook->pgrp = pgrp; + hook->sid = getsid (pid); hook->refcnt = 1; if (newcred->hook) - /* We inherited CRED's hook, get rid of our ref to it. */ + /* We inherited CRED's hook, get rid of our ref to it. */ pi_destroy_hook (newcred); newcred->hook = hook; @@ -405,14 +468,14 @@ S_term_open_ctty (mach_port_t arg, ports_port_deref (newcred); } } - + ports_port_deref (cred); return err; } /* Implement chown locally; don't pass the value down to the - underlying node. */ + underlying node. */ error_t trivfs_S_file_chown (struct trivfs_protid *cred, mach_port_t reply, @@ -420,129 +483,101 @@ trivfs_S_file_chown (struct trivfs_protid *cred, uid_t uid, gid_t gid) { - int i; - int noticed_uid; - - /* This routine is flawed in several ways; it needs to - be rewritted once the idvec handling stuff can do - permission checks. */ + struct stat st; + error_t err; if (!cred) return EOPNOTSUPP; - noticed_uid = 0; mutex_lock (&global_lock); - for (i = 0; i < cred->nuids; i++) + + /* XXX */ + st.st_uid = term_owner; + st.st_gid = term_group; + + if (!cred->isroot) { - if (cred->uids[i] == uid) - noticed_uid = 1; - if (cred->uids[i] == 0 || cred->uids[i] == term_owner) + err = fshelp_isowner (&st, cred->user); + if (err) + goto out; + + if ((uid != (uid_t) -1 && !idvec_contains (cred->user->uids, uid)) + || (gid != (gid_t) -1 && !idvec_contains (cred->user->gids, gid))) { - /* Make sure UID is legitimate */ - if (!cred->isroot && !noticed_uid && term_owner != uid) - { - /* Continue scanning UIDS */ - for (i++; i < cred->nuids; i++) - if (cred->uids[i] == uid) - noticed_uid = 1; - if (!noticed_uid) - { - mutex_unlock (&global_lock); - return EPERM; - } - } - - /* Make sure GID is legitimate */ - for (i = 0; i < cred->ngids || cred->isroot; i++) - if (cred->isroot || cred->gids[i] == gid) - { - /* Make the change */ - term_owner = uid; - term_group = gid; - mutex_unlock (&global_lock); - return 0; - } - - /* Not legitimate */ - break; + err = EPERM; + goto out; } } + /* Make the change */ + if (uid != (uid_t) -1) + term_owner = uid; + if (gid != (gid_t) -1) + term_group = gid; + err = 0; + +out: mutex_unlock (&global_lock); - return EPERM; + return err; } -/* Implement chmod locally */ +/* Implement chmod locally. */ error_t trivfs_S_file_chmod (struct trivfs_protid *cred, mach_port_t reply, mach_msg_type_name_t reply_type, mode_t mode) { - int i; - + error_t err; + struct stat st; + if (!cred) return EOPNOTSUPP; - + mutex_lock (&global_lock); - for (i = 0; i < cred->nuids; i++) - if (cred->isroot || cred->uids[i] == term_owner) - { - if (!cred->isroot) - { - mode &= S_ISVTX; - - for (i = 0; i < cred->nuids; i++) - if (cred->uids[i] == term_owner) - break; - if (i == cred->nuids) - mode &= ~S_ISUID; - - for (i = 0; i < cred->ngids; i++) - if (cred->gids[i] == term_group) - break; - if (i == cred->nuids) - mode &= ~S_ISGID; - } - - term_mode = (mode | S_IFCHR); - mutex_unlock (&global_lock); - return 0; - } - mutex_unlock (&global_lock); - return EPERM; -} + if (!cred->isroot) + { + /* XXX */ + st.st_uid = term_owner; + st.st_gid = term_group; + err = fshelp_isowner (&st, cred->user); + if (err) + goto out; -error_t -trivfs_S_file_access (struct trivfs_protid *cred, - mach_port_t reply, - mach_msg_type_name_t reply_type, - int *allowed) -{ - if (!cred) - return EOPNOTSUPP; - - /* XXX Do the right thing eventually. */ - *allowed = O_READ | O_WRITE; - return 0; + mode &= ~S_ISVTX; + + if (!idvec_contains (cred->user->uids, term_owner)) + mode &= ~S_ISUID; + + if (!idvec_contains (cred->user->gids, term_group)) + mode &= ~S_ISUID; + } + + term_mode = ((mode & ~S_IFMT & ~S_ITRANS & ~S_ISPARE) | S_IFCHR | S_IROOT); + err = 0; + +out: + mutex_unlock (&global_lock); + return err; } -/* Called for user writes to the terminal as described - in <hurd/io.defs>. */ +/* Called for user writes to the terminal as described in + <hurd/io.defs>. */ error_t trivfs_S_io_write (struct trivfs_protid *cred, mach_port_t reply, mach_msg_type_name_t replytype, char *data, - u_int datalen, - off_t offset, - int *amt) + size_t datalen, + loff_t offset, + size_t *amt) { int i; int cancel; - + error_t err = 0; + if (!cred) return EOPNOTSUPP; @@ -558,18 +593,18 @@ trivfs_S_io_write (struct trivfs_protid *cred, mutex_unlock (&global_lock); return EBADF; } - + if ((termstate.c_lflag & TOSTOP) && !fg_p (cred)) { mutex_unlock (&global_lock); return EBACKGROUND; } - + if ((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL)) { mutex_unlock (&global_lock); return EIO; - + } cancel = 0; @@ -577,9 +612,14 @@ trivfs_S_io_write (struct trivfs_protid *cred, { while (!qavail (outputq) && !cancel) { - (*bottom->start_output) (); - if (!qavail (outputq)) - cancel = hurd_condition_wait (outputq->wait, &global_lock); + err = (*bottom->start_output) (); + if (err) + cancel = 1; + else + { + if (!qavail (outputq)) + cancel = hurd_condition_wait (outputq->wait, &global_lock); + } } if (cancel) break; @@ -589,7 +629,8 @@ trivfs_S_io_write (struct trivfs_protid *cred, *amt = i; - (*bottom->start_output) (); + if (!err && datalen) + (*bottom->start_output) (); trivfs_set_mtime (termctl); @@ -597,18 +638,18 @@ trivfs_S_io_write (struct trivfs_protid *cred, mutex_unlock (&global_lock); - return ((cancel && datalen && !*amt) ? EINTR : 0); + return ((cancel && datalen && !*amt) ? (err ?: EINTR) : 0); } -/* Called for user reads from the terminal. */ +/* Called for user reads from the terminal. */ error_t trivfs_S_io_read (struct trivfs_protid *cred, mach_port_t reply, mach_msg_type_name_t replytype, char **data, - u_int *datalen, - off_t offset, - int amount) + size_t *datalen, + loff_t offset, + size_t amount) { int cancel; int i, max; @@ -622,13 +663,13 @@ trivfs_S_io_read (struct trivfs_protid *cred, return pty_io_read (cred, data, datalen, amount); mutex_lock (&global_lock); - + if ((cred->po->openmodes & O_READ) == 0) { mutex_unlock (&global_lock); return EBADF; } - + if (!fg_p (cred)) { mutex_unlock (&global_lock); @@ -637,14 +678,14 @@ trivfs_S_io_read (struct trivfs_protid *cred, while (!qsize (inputq)) { - if ((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL)) + if ((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL) || !amount) { /* Return EOF, Posix.1 7.1.1.10. */ mutex_unlock (&global_lock); *datalen = 0; return 0; } - + if (cred->po->openmodes & O_NONBLOCK) { mutex_unlock (&global_lock); @@ -687,14 +728,14 @@ trivfs_S_io_read (struct trivfs_protid *cred, max = (amount < avail) ? amount : avail; if (max > *datalen) - vm_allocate (mach_task_self (), (vm_address_t *)data, max, 1); - + *data = mmap (0, max, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + cancel = 0; cp = *data; for (i = 0; i < max; i++) { char c = dequeue (inputq); - + if (remote_input_mode) *cp++ = c; else @@ -703,7 +744,7 @@ trivfs_S_io_read (struct trivfs_protid *cred, if (!(termstate.c_lflag & ICANON) || !CCEQ (termstate.c_cc[VEOF], c)) *cp++ = c; - + /* If this is a break character, then finish now. */ if ((termstate.c_lflag & ICANON) && (c == '\n' @@ -711,14 +752,14 @@ trivfs_S_io_read (struct trivfs_protid *cred, || CCEQ (termstate.c_cc[VEOL], c) || CCEQ (termstate.c_cc[VEOL2], c))) break; - + /* If this is the delayed suspend character, then signal now. */ if ((termstate.c_lflag & ISIG) && CCEQ (termstate.c_cc[VDSUSP], c)) { /* The CANCEL flag is being used here to tell the return below to make sure we don't signal EOF on a VDUSP that - happens at the front of a line. */ + happens at the front of a line. */ send_signal (SIGTSTP); cancel = 1; break; @@ -731,7 +772,7 @@ trivfs_S_io_read (struct trivfs_protid *cred, *datalen = cp - *data; - /* If we really read something, set atime */ + /* If we really read something, set atime. */ if (*datalen || !cancel) trivfs_set_atime (termctl); @@ -743,10 +784,50 @@ trivfs_S_io_read (struct trivfs_protid *cred, } error_t +trivfs_S_io_pathconf (struct trivfs_protid *cred, + mach_port_t reply, + mach_msg_type_name_t reply_type, + int name, + int *val) +{ + if (!cred) + return EOPNOTSUPP; + + switch (name) + { + case _PC_LINK_MAX: + case _PC_NAME_MAX: + case _PC_PATH_MAX: + case _PC_PIPE_BUF: + case _PC_NO_TRUNC: + default: + return io_pathconf (cred->realnode, name, val); + + case _PC_MAX_CANON: + *val = rawq->hiwat; + return 0; + + case _PC_MAX_INPUT: + *val = inputq->hiwat; + return 0; + + case _PC_CHOWN_RESTRICTED: + /* We implement this locally, remember... */ + *val = 1; + return 0; + + case _PC_VDISABLE: + *val = _POSIX_VDISABLE; + return 0; + } +} + + +error_t trivfs_S_io_readable (struct trivfs_protid *cred, mach_port_t reply, mach_msg_type_name_t replytype, - int *amt) + size_t *amt) { if (!cred) return EOPNOTSUPP; @@ -756,7 +837,10 @@ trivfs_S_io_readable (struct trivfs_protid *cred, mutex_lock (&global_lock); if ((cred->po->openmodes & O_READ) == 0) - return EBADF; + { + mutex_unlock (&global_lock); + return EBADF; + } *amt = qsize (inputq); if (remote_input_mode && *amt) --*amt; @@ -765,12 +849,64 @@ trivfs_S_io_readable (struct trivfs_protid *cred, return 0; } +error_t +trivfs_S_io_revoke (struct trivfs_protid *cred, + mach_port_t reply, + mach_msg_type_name_t replytype) +{ + struct stat st; + + error_t iterator_function (void *port) + { + struct trivfs_protid *user = port; + + if (user != cred) + ports_destroy_right (user); + return 0; + } + + if (!cred) + return EOPNOTSUPP; + + mutex_lock (&global_lock); + + if (!cred->isroot) + { + error_t err; + + /* XXX */ + st.st_uid = term_owner; + st.st_gid = term_group; + + err = fshelp_isowner (&st, cred->user); + if (err) + { + mutex_unlock (&global_lock); + return err; + } + } + + mutex_unlock (&global_lock); + + ports_inhibit_bucket_rpcs (term_bucket); + ports_class_iterate (cred->pi.class, iterator_function); + ports_resume_bucket_rpcs (term_bucket); + + return 0; +} + + + + + /* TIOCMODG ioctl -- Get modem state */ kern_return_t S_tioctl_tiocmodg (io_t port, int *state) { struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0); + error_t err = 0; + if (!cred) return EOPNOTSUPP; @@ -782,11 +918,11 @@ S_tioctl_tiocmodg (io_t port, } mutex_lock (&global_lock); - *state = (*bottom->mdmstate) (); + err = (*bottom->mdmstate) (state); mutex_unlock (&global_lock); - + ports_port_deref (cred); - return 0; + return err; } /* TIOCMODS ioctl -- Set modem state */ @@ -811,11 +947,8 @@ S_tioctl_tiocmods (io_t port, if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else - { - (*bottom->mdmctl) (MDMCTL_SET, state); - err = 0; - } - + err = (*bottom->mdmctl) (MDMCTL_SET, state); + mutex_unlock (&global_lock); ports_port_deref (cred); @@ -859,7 +992,7 @@ S_tioctl_tiocnxcl (io_t port) { struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0); error_t err; - + if (!cred) return EOPNOTSUPP; @@ -890,8 +1023,8 @@ S_tioctl_tiocflush (io_t port, int flags) { struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0); + error_t err = 0; - error_t err; if (!cred) return EOPNOTSUPP; @@ -903,7 +1036,7 @@ S_tioctl_tiocflush (io_t port, } mutex_lock (&global_lock); - + if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else @@ -913,21 +1046,19 @@ S_tioctl_tiocflush (io_t port, if (flags & O_READ) { - clear_queue (inputq); (*bottom->notice_input_flushed) (); + clear_queue (inputq); } - if (flags & O_WRITE) - drop_output (); - - err = 0; + if (!err && (flags & O_WRITE)) + err = drop_output (); } mutex_unlock (&global_lock); ports_port_deref (cred); return err; } - + /* TIOCGETA ioctl -- Get termios state */ kern_return_t S_tioctl_tiocgeta (io_t port, @@ -952,7 +1083,7 @@ S_tioctl_tiocgeta (io_t port, modes[1] = termstate.c_oflag; modes[2] = termstate.c_cflag; modes[3] = termstate.c_lflag; - bcopy (termstate.c_cc, ccs, NCCS); + memcpy (ccs, termstate.c_cc, NCCS); speeds[0] = termstate.__ispeed; speeds[1] = termstate.__ospeed; mutex_unlock (&global_lock); @@ -972,7 +1103,7 @@ set_state (io_t port, { struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0); error_t err; - int oldlflag; + struct termios state; if (!cred) return EOPNOTSUPP; @@ -985,73 +1116,75 @@ set_state (io_t port, } mutex_lock (&global_lock); - + if (!(cred->po->openmodes & (O_READ|O_WRITE))) - err = EBADF; + err = EBADF; else if (!fg_p (cred)) err = EBACKGROUND; - else + else { if (cred->pi.class == pty_class) { + err = (*bottom->abandon_physical_output) (); + if (err) + goto leave; clear_queue (outputq); - (*bottom->abandon_physical_output) (); } if (draino) { err = drain_output (); if (err) - { - mutex_unlock (&global_lock); - ports_port_deref (cred); - return err; - } + goto leave; } - + if (flushi) { - clear_queue (inputq); (*bottom->notice_input_flushed) (); + clear_queue (inputq); } - oldlflag = termstate.c_lflag; - termstate.c_iflag = modes[0]; - termstate.c_oflag = modes[1]; - termstate.c_cflag = modes[2]; - termstate.c_lflag = modes[3]; - bcopy (ccs, termstate.c_cc, NCCS); - termstate.__ispeed = speeds[0]; - termstate.__ospeed = speeds[1]; + state = termstate; + state.c_iflag = modes[0]; + state.c_oflag = modes[1]; + state.c_cflag = modes[2]; + state.c_lflag = modes[3]; + memcpy (state.c_cc, ccs, NCCS); + state.__ispeed = speeds[0]; + state.__ospeed = speeds[1]; if (external_processing) - termstate.c_lflag |= EXTPROC; + state.c_lflag |= EXTPROC; else - termstate.c_lflag &= ~EXTPROC; + state.c_lflag &= ~EXTPROC; - if (external_processing || !(termstate.c_cflag & CIGNORE)) - (*bottom->set_bits) (); - if (oldlflag & ICANON) - { - if (!(termstate.c_lflag & ICANON)) - copy_rawq (); - } - else + err = (*bottom->set_bits) (&state); + if (!err) { - if (termstate.c_lflag & ICANON) - rescan_inputq (); + int oldlflag = termstate.c_lflag; + + termstate = state; + if (oldlflag & ICANON) + { + if (!(termstate.c_lflag & ICANON)) + copy_rawq (); + } + else + { + if (termstate.c_lflag & ICANON) + rescan_inputq (); + } } err = 0; } - - mutex_unlock (&global_lock); + leave: + mutex_unlock (&global_lock); ports_port_deref (cred); return err; } - /* TIOCSETA -- Set termios state */ kern_return_t S_tioctl_tiocseta (io_t port, @@ -1128,7 +1261,7 @@ S_tioctl_tiocsetd (io_t port, if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; mutex_unlock (&global_lock); - + if (disc != 0) err = ENXIO; else @@ -1144,7 +1277,7 @@ S_tioctl_tiocdrain (io_t port) { struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0); error_t err; - + if (!cred) return EOPNOTSUPP; @@ -1162,7 +1295,7 @@ S_tioctl_tiocdrain (io_t port) ports_port_deref (cred); return EBADF; } - + err = drain_output (); mutex_unlock (&global_lock); ports_port_deref (cred); @@ -1187,9 +1320,8 @@ S_tioctl_tiocswinsz (io_t port, return EOPNOTSUPP; } - mutex_lock (&global_lock); - + if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else @@ -1197,10 +1329,11 @@ S_tioctl_tiocswinsz (io_t port, ports_port_deref (cred); - if (!err && (size.ws_row - window_size.ws_row + - size.ws_col - window_size.ws_col + - size.ws_xpixel - window_size.ws_xpixel + - size.ws_ypixel - window_size.ws_ypixel) != 0) + if (! err + && (size.ws_row != window_size.ws_row + || size.ws_col != window_size.ws_col + || size.ws_xpixel != window_size.ws_xpixel + || size.ws_ypixel != window_size.ws_ypixel)) { /* The size is actually changing. Record the new size and notify the process group. */ @@ -1212,7 +1345,7 @@ S_tioctl_tiocswinsz (io_t port, return err; } -/* TIOCGWINSZ -- Fetch window size */ +/* TIOCGWINSZ -- Fetch window size */ kern_return_t S_tioctl_tiocgwinsz (io_t port, struct winsize *size) @@ -1243,6 +1376,7 @@ S_tioctl_tiocmget (io_t port, int *bits) { struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0); + error_t err = 0; if (!cred) return EOPNOTSUPP; @@ -1255,13 +1389,13 @@ S_tioctl_tiocmget (io_t port, } mutex_lock (&global_lock); - *bits = (*bottom->mdmstate) (); + err = (*bottom->mdmstate) (bits); mutex_unlock (&global_lock); - + ports_port_deref (cred); - return 0; + return err; } - + /* TIOCMSET -- Set all modem bits */ kern_return_t S_tioctl_tiocmset (io_t port, @@ -1284,16 +1418,13 @@ S_tioctl_tiocmset (io_t port, if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else - { - (*bottom->mdmctl) (MDMCTL_SET, bits); - err = 0; - } - + err = (*bottom->mdmctl) (MDMCTL_SET, bits); + mutex_unlock (&global_lock); ports_port_deref (cred); return err; } - + /* TIOCMBIC -- Clear some modem bits */ kern_return_t S_tioctl_tiocmbic (io_t port, @@ -1316,10 +1447,7 @@ S_tioctl_tiocmbic (io_t port, if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else - { - (*bottom->mdmctl) (MDMCTL_BIC, bits); - err = 0; - } + err = (*bottom->mdmctl) (MDMCTL_BIC, bits); mutex_unlock (&global_lock); ports_port_deref (cred); @@ -1349,10 +1477,7 @@ S_tioctl_tiocmbis (io_t port, if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else - { - (*bottom->mdmctl) (MDMCTL_BIS, bits); - err = 0; - } + err = (*bottom->mdmctl) (MDMCTL_BIS, bits); mutex_unlock (&global_lock); ports_port_deref (cred); return err; @@ -1381,9 +1506,12 @@ S_tioctl_tiocstart (io_t port) err = EBADF; else { + int old_termflags = termflags; + termflags &= ~USER_OUTPUT_SUSP; - (*bottom->start_output) (); - err = 0; + err = (*bottom->start_output) (); + if (err) + termflags = old_termflags; } mutex_unlock (&global_lock); @@ -1408,21 +1536,23 @@ S_tioctl_tiocstop (io_t port) return EOPNOTSUPP; } mutex_lock (&global_lock); - + if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else { + int old_termflags = termflags; termflags |= USER_OUTPUT_SUSP; - (*bottom->suspend_physical_output) (); - err = 0; + err = (*bottom->suspend_physical_output) (); + if (err) + termflags = old_termflags; } mutex_unlock (&global_lock); - + ports_port_deref (cred); return err; } - + /* TIOCSTI -- Simulate terminal input */ kern_return_t S_tioctl_tiocsti (io_t port, @@ -1455,7 +1585,7 @@ S_tioctl_tiocsti (io_t port, err = 0; } mutex_unlock (&global_lock); - + ports_port_deref (cred); return err; } @@ -1488,7 +1618,7 @@ S_tioctl_tiocoutq (io_t port, err = 0; } mutex_unlock (&global_lock); - + ports_port_deref (cred); return err; } @@ -1521,11 +1651,11 @@ S_tioctl_tiocspgrp (io_t port, err = 0; } mutex_unlock (&global_lock); - + ports_port_deref (cred); return err; } - + /* TIOCGPGRP --- fetch pgrp of terminal */ kern_return_t S_tioctl_tiocgpgrp (io_t port, @@ -1579,16 +1709,13 @@ S_tioctl_tioccdtr (io_t port) if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else - { - (*bottom->mdmctl) (MDMCTL_BIC, TIOCM_DTR); - err = 0; - } + err = (*bottom->mdmctl) (MDMCTL_BIC, TIOCM_DTR); mutex_unlock (&global_lock); ports_port_deref (cred); return err; } - + /* TIOCSDTR -- set DTR */ kern_return_t S_tioctl_tiocsdtr (io_t port) @@ -1610,10 +1737,7 @@ S_tioctl_tiocsdtr (io_t port) if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else - { - (*bottom->mdmctl) (MDMCTL_BIS, TIOCM_DTR); - err = 0; - } + err = (*bottom->mdmctl) (MDMCTL_BIS, TIOCM_DTR); mutex_unlock (&global_lock); ports_port_deref (cred); @@ -1641,10 +1765,7 @@ S_tioctl_tioccbrk (io_t port) if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else - { - (*bottom->clear_break) (); - err = 0; - } + err = (*bottom->clear_break) (); mutex_unlock (&global_lock); ports_port_deref (cred); @@ -1672,10 +1793,7 @@ S_tioctl_tiocsbrk (io_t port) if (!(cred->po->openmodes & (O_READ|O_WRITE))) err = EBADF; else - { - (*bottom->set_break) (); - err = 0; - } + err = (*bottom->set_break) (); mutex_unlock (&global_lock); ports_port_deref (cred); @@ -1781,7 +1899,7 @@ trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred, mutex_unlock (&global_lock); return 0; } - + error_t trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred, mach_port_t reply, @@ -1887,57 +2005,50 @@ error_t trivfs_S_io_select (struct trivfs_protid *cred, mach_port_t reply, mach_msg_type_name_t reply_type, - int *type, - int *idtag) + int *type) { - int available; - if (!cred) return EOPNOTSUPP; if (cred->pi.class == pty_class) - return pty_io_select (cred, reply, type, idtag); + return pty_io_select (cred, reply, type); - /* We don't deal with SELECT_URG here. */ - if (*type & ~(SELECT_READ | SELECT_WRITE)) - return EINVAL; - - available = 0; - if (*type == 0) - return 0; + if ((cred->po->openmodes & O_READ) == 0) + *type &= ~SELECT_READ; + if ((cred->po->openmodes & O_WRITE) == 0) + *type &= ~SELECT_WRITE; mutex_lock (&global_lock); - + while (1) { + int available = 0; if ((*type & SELECT_READ) && qsize (inputq)) available |= SELECT_READ; if ((*type & SELECT_WRITE) && qavail (outputq)) available |= SELECT_WRITE; - if (available) + if (available == 0) { - *type = available; - mutex_unlock (&global_lock); - return 0; + ports_interrupt_self_on_port_death (cred, reply); + if (hurd_condition_wait (&select_alert, &global_lock) == 0) + continue; } - ports_interrupt_self_on_port_death (cred, reply); - if (hurd_condition_wait (&select_alert, &global_lock)) - { - *type = 0; - mutex_unlock (&global_lock); - return EINTR; - } + *type = available; + mutex_unlock (&global_lock); + return available ? 0 : EINTR; } } kern_return_t -trivfs_S_io_map (struct trivfs_protid *cred, - mach_port_t *rdobj, - mach_msg_type_name_t *rdtype, - mach_port_t *wrobj, - mach_msg_type_name_t *wrtype) +trivfs_S_io_map (struct trivfs_protid *cred, + mach_port_t reply, + mach_msg_type_name_t replyPoly, + mach_port_t *rdobj, + mach_msg_type_name_t *rdtype, + mach_port_t *wrobj, + mach_msg_type_name_t *wrtype) { return EOPNOTSUPP; } @@ -1976,7 +2087,7 @@ call_asyncs (int dir) && (!(dir & O_WRITE) && qavail (outputq) == 0)) /* Output isn't possible in the desired directions. */ return; - + if ((termflags & ICKY_ASYNC) && !(termflags & NO_OWNER)) { report_sig_start (); @@ -1985,7 +2096,7 @@ call_asyncs (int dir) mutex_lock (&global_lock); report_sig_end (); } - + for (ar = async_requests, prevp = &async_requests; ar; ar = nxt) @@ -2012,9 +2123,7 @@ send_signal (int signo) if (!(termflags & NO_OWNER)) { - right = ports_get_right (cttyid); - mach_port_insert_right (mach_task_self (), right, right, - MACH_MSG_TYPE_MAKE_SEND); + right = ports_get_send_right (cttyid); report_sig_start (); mutex_unlock (&global_lock); hurd_sig_post (foreground_id, signo, right); @@ -2042,6 +2151,13 @@ report_carrier_on () condition_broadcast (&carrier_alert); } +void +report_carrier_error (error_t err) +{ + carrier_error = err; + condition_broadcast (&carrier_alert); +} + kern_return_t S_term_get_nodename (io_t arg, char *name) @@ -2050,8 +2166,14 @@ S_term_get_nodename (io_t arg, tty_class); if (!cred) return EOPNOTSUPP; - - strcpy (name, (char *)cred->po->cntl->hook ?: ""); + + if (!cred->po->cntl->hook) + { + ports_port_deref (cred); + return ENOENT; + } + + strcpy (name, (char *)cred->po->cntl->hook); ports_port_deref (cred); return 0; @@ -2065,10 +2187,10 @@ S_term_set_nodename (io_t arg, struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, tty_class); if (!cred) return EOPNOTSUPP; - + if (strcmp (name, (char *)cred->po->cntl->hook) != 0) err = EINVAL; - + ports_port_deref (cred); return err; } @@ -2077,7 +2199,7 @@ kern_return_t S_term_set_filenode (io_t arg, file_t filenode) { - struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, + struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, tty_class); if (!cred) return EOPNOTSUPP; @@ -2087,19 +2209,44 @@ S_term_set_filenode (io_t arg, } kern_return_t +S_term_get_peername (io_t arg, + char *name) +{ + struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, 0); + struct trivfs_control *peer; + + if (!cred || (cred->pi.class != tty_class && cred->pi.class != pty_class)) + { + if (cred) + ports_port_deref (cred); + return EOPNOTSUPP; + } + + peer = (cred->pi.class == tty_class) ? ptyctl : termctl; + + if (bottom != &ptyio_bottom || !peer->hook) + { + ports_port_deref (cred); + return ENOENT; + } + + strcpy (name, (char *) peer->hook); + ports_port_deref (cred); + + return 0; +} + +kern_return_t S_term_get_bottom_type (io_t arg, int *ttype) { - struct trivfs_protid *cred = ports_lookup_port (term_bucket, + struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, tty_class); if (!cred) return EOPNOTSUPP; ports_port_deref (cred); - if (bottom == &devio_bottom) - *ttype = TERM_ON_MACHDEV; - else - *ttype = TERM_ON_MASTERPTY; + *ttype = bottom->type; return 0; } @@ -2107,7 +2254,7 @@ kern_return_t S_term_on_machdev (io_t arg, device_t machdev) { - struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, + struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, tty_class); if (!cred) return EOPNOTSUPP; diff --git a/term/xinl.c b/term/xinl.c new file mode 100644 index 00000000..3695faa5 --- /dev/null +++ b/term/xinl.c @@ -0,0 +1,2 @@ +#define TERM_DEFINE_EI +#include "term.h" |