aboutsummaryrefslogtreecommitdiff
path: root/term
diff options
context:
space:
mode:
Diffstat (limited to 'term')
-rw-r--r--term/ChangeLog405
-rw-r--r--term/Makefile11
-rw-r--r--term/devio.c458
-rw-r--r--term/hurdio.c628
-rw-r--r--term/main.c428
-rw-r--r--term/munge.c44
-rw-r--r--term/ptyio.c169
-rw-r--r--term/term.h133
-rw-r--r--term/users.c819
-rw-r--r--term/xinl.c2
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"