summaryrefslogtreecommitdiff
path: root/term/users.c
diff options
context:
space:
mode:
authorMichael I. Bushnell <mib@gnu.org>1995-08-31 20:01:44 +0000
committerMichael I. Bushnell <mib@gnu.org>1995-08-31 20:01:44 +0000
commit941c81aa67cdaf9c63f4835e61d33c182db5237b (patch)
tree05f62a9fc70a5eb5cf58d54bd98ffe11ee7cb8f7 /term/users.c
parent8832237df37b394f990e0746f2702f6400d1359e (diff)
Initial revision
Diffstat (limited to 'term/users.c')
-rw-r--r--term/users.c1659
1 files changed, 1659 insertions, 0 deletions
diff --git a/term/users.c b/term/users.c
new file mode 100644
index 00000000..4eb61be8
--- /dev/null
+++ b/term/users.c
@@ -0,0 +1,1659 @@
+/*
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ 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. */
+
+#include "term.h"
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <string.h>
+#include <fcntl.h>
+#include <hurd/trivfs.h>
+#include <cthreads.h>
+#include <hurd.h>
+#include "ourmsg_U.h"
+
+#undef ECHO
+#undef MDMBUF
+#undef TOSTOP
+#undef FLUSHO
+#undef PENDIN
+#undef NOFLSH
+
+#include "term_S.h"
+#include "tioctl_S.h"
+#include <sys/ioctl.h>
+
+#define TTYDEFCHARS
+#include <sys/ttydefaults.h>
+
+/* Count of active opens */
+int nperopens;
+
+/* io_async requests */
+struct async_req
+{
+ mach_port_t notify;
+ struct async_req *next;
+};
+struct async_req *async_requests;
+
+mach_port_t async_icky_id;
+mach_port_t async_id;
+struct port_info *cttyid;
+int foreground_id;
+
+struct winsize window_size;
+
+static void call_asyncs (void);
+
+/* Attach this on the hook of any protid that is a ctty. */
+struct protid_hook
+{
+ int refcnt;
+ pid_t pid, pgrp;
+};
+
+static error_t
+open_hook (struct trivfs_control *cntl,
+ uid_t *uids, u_int nuids,
+ uid_t *gids, u_int ngids,
+ int flags)
+{
+ int cancel = 0;
+ error_t err;
+
+ mutex_lock (&global_lock);
+
+ if (!(termflags & TTY_OPEN))
+ {
+ bzero (&termstate, 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
+ | ECHOE|ECHOKE|ECHOCTL);
+ termstate.c_cflag |= CREAD | CS8 | HUPCL;
+
+ bcopy (ttydefchars, termstate.c_cc, NCCS);
+ }
+ else 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)
+ {
+ err = assert_dtr ();
+ if (err)
+ {
+ 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;
+ }
+ if (cancel)
+ {
+ mutex_unlock (&global_lock);
+ return EINTR;
+ }
+
+ termflags |= TTY_OPEN;
+ if (!(termstate.c_cflag & CIGNORE))
+ set_bits ();
+
+ mutex_unlock (&global_lock);
+ return 0;
+}
+error_t (*trivfs_check_open_hook) (struct trivfs_control *, uid_t *,
+ u_int, uid_t *, u_int, int)
+ = open_hook;
+
+static error_t
+pi_create_hook (struct trivfs_protid *cred)
+{
+ 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;
+
+static void
+pi_destroy_hook (struct trivfs_protid *cred)
+{
+ mutex_lock (&global_lock);
+ if (cred->hook && !--((struct protid_hook *)cred->hook)->refcnt)
+ free (cred->hook);
+ mutex_unlock (&global_lock);
+}
+void (*trivfs_protid_destroy_hook) (struct trivfs_protid *) = pi_destroy_hook;
+
+static error_t
+po_create_hook (struct trivfs_peropen *po)
+{
+ mutex_lock (&global_lock);
+ nperopens++;
+ if (po->openmodes & O_ASYNC)
+ termflags |= ICKY_ASYNC;
+ mutex_unlock (&global_lock);
+ return 0;
+}
+error_t (*trivfs_peropen_create_hook) (struct trivfs_peropen *) =
+ po_create_hook;
+
+static void
+po_destroy_hook (struct trivfs_peropen *po)
+{
+ mutex_lock (&global_lock);
+ nperopens--;
+ if (!nperopens)
+ {
+ /* Empty queues */
+ clear_queue (inputq);
+ clear_queue (rawq);
+ drain_output ();
+
+ /* Possibly drop carrier */
+ if ((termstate.c_cflag & HUPCL) || (termflags & NO_CARRIER))
+ desert_dtr ();
+
+ termflags &= ~TTY_OPEN;
+ }
+ mutex_unlock (&global_lock);
+}
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *)
+ = po_destroy_hook;
+
+/* 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;
+}
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_blksize = 512;
+ st->st_fstype = FSTYPE_TERM;
+ st->st_fsid = getpid ();
+ st->st_ino = 0;
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFCHR;
+}
+
+/* Implement term_getctty as described in <hurd/term.defs>. */
+kern_return_t
+S_term_getctty (mach_port_t arg,
+ mach_port_t *id,
+ mach_msg_type_name_t *idtype)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket,
+ arg, tty_class);
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ *id = ports_get_right (cttyid);
+ *idtype = MACH_MSG_TYPE_MAKE_SEND;
+ err = 0;
+ }
+ ports_port_deref (cred);
+ mutex_unlock (&global_lock);
+ return err;
+}
+
+/* Implement termctty_open_terminal as described in <hurd/term.defs>. */
+kern_return_t
+S_termctty_open_terminal (mach_port_t arg,
+ int flags,
+ mach_port_t *result,
+ mach_msg_type_name_t *resulttype)
+{
+ error_t err;
+ mach_port_t new_realnode;
+ struct trivfs_protid *newcred;
+ struct port_info *pi = ports_lookup_port (term_bucket, arg, cttyid_class);
+
+ if (!pi)
+ return EOPNOTSUPP;
+
+ assert (pi == cttyid);
+
+ err = io_restrict_auth (termctl->underlying, &new_realnode, 0, 0, 0, 0);
+
+ if (!err)
+ {
+ err = trivfs_open (termctl, 0, 0, 0, 0, flags, new_realnode, &newcred);
+ if (!err)
+ {
+ *result = ports_get_right (newcred);
+ *resulttype = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newcred);
+ }
+ }
+
+ ports_port_deref (pi);
+ return err;
+}
+
+/* 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)
+{
+ error_t err;
+ struct trivfs_protid *newcred;
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, tty_class);
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!cred->po->openmodes & (O_READ|O_WRITE))
+ {
+ mutex_unlock (&global_lock);
+ err = EBADF;
+ }
+ else
+ {
+ mutex_unlock (&global_lock);
+ err = trivfs_protid_dup (cred, &newcred);
+
+ if (!err)
+ {
+ struct protid_hook *hook = malloc (sizeof (struct protid_hook));
+
+ hook->pid = pid;
+ hook->pgrp = pgrp;
+ hook->refcnt = 1;
+
+ if (newcred->hook)
+ /* We inherited CRED's hook, get rid of our ref to it. */
+ pi_destroy_hook (newcred);
+ newcred->hook = hook;
+
+ *newpt = ports_get_right (newcred);
+ *newpttype = MACH_MSG_TYPE_MAKE_SEND;
+
+ ports_port_deref (newcred);
+ }
+ }
+
+ ports_port_deref (cred);
+
+ return err;
+}
+
+/* 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)
+{
+ int i;
+ int cancel;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ /* Check for errors first. */
+
+ if ((cred->po->openmodes & O_WRITE) == 0)
+ {
+ 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;
+ for (i = 0; i < datalen; i++)
+ {
+ while (!qavail (outputq) && !cancel)
+ cancel = hurd_condition_wait (outputq->wait, &global_lock);
+ if (cancel)
+ break;
+
+ output_character (data[i]);
+ }
+
+ *amt = i;
+
+ start_output ();
+
+ trivfs_set_mtime (termctl);
+
+ call_asyncs ();
+
+ mutex_unlock (&global_lock);
+
+ return ((cancel && datalen && !*amt) ? EINTR : 0);
+}
+
+/* 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)
+{
+ int cancel;
+ int i, max;
+ char *cp;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ 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);
+ return EBACKGROUND;
+ }
+
+ while (!qsize (inputq))
+ {
+ if ((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL))
+ {
+ /* 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);
+ return EWOULDBLOCK;
+ }
+
+ if (hurd_condition_wait (inputq->wait, &global_lock))
+ {
+ mutex_unlock (&global_lock);
+ return EINTR;
+ }
+ }
+
+ max = (amount < qsize (inputq)) ? amount : qsize (inputq);
+
+ if (max > *datalen)
+ vm_allocate (mach_task_self (), (vm_address_t *)data, max, 1);
+
+ cancel = 0;
+ cp = *data;
+ for (i = 0; i < max; i++)
+ {
+ char c = dequeue (inputq);
+
+ /* Unless this is EOF, add it to the response. */
+ 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'
+ || CCEQ (termstate.c_cc[VEOF], c)
+ || 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. */
+ send_signal (SIGTSTP);
+ cancel = 1;
+ break;
+ }
+ }
+
+ *datalen = cp - *data;
+
+ mutex_unlock (&global_lock);
+
+ call_asyncs ();
+
+ return !*datalen && cancel ? EINTR : 0;
+}
+
+error_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int *amt)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if ((cred->po->openmodes & O_READ) == 0)
+ return EBADF;
+ *amt = qsize (inputq);
+ mutex_unlock (&global_lock);
+
+ 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, tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ *state = mdmstate ();
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return 0;
+}
+
+/* TIOCMODS ioctl -- Set modem state */
+kern_return_t
+S_tioctl_tiocmods (io_t port,
+ int state)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ mdmctl (MDMCTL_SET, state);
+ err = 0;
+ }
+
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCEXCL ioctl -- Set exclusive use */
+kern_return_t
+S_tioctl_tiocexcl (io_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ termflags |= EXCL_USE;
+ err = 0;
+ }
+
+ mutex_unlock (&global_lock);
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCNXCL ioctl -- Clear exclusive use */
+kern_return_t
+S_tioctl_tiocnxcl (io_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket,
+ port, tty_class);
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ termflags &= ~EXCL_USE;
+ err = 0;
+ }
+
+ mutex_unlock (&global_lock);
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCFLUSH ioctl -- Flush input, output, or both */
+kern_return_t
+S_tioctl_tiocflush (io_t port,
+ int flags)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ if (flags == 0)
+ flags = O_READ|O_WRITE;
+
+ if (flags & O_READ)
+ clear_queue (inputq);
+
+ if (flags & O_WRITE)
+ drop_output ();
+
+ err = 0;
+ }
+
+ mutex_unlock (&global_lock);
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCGETA ioctl -- Get termios state */
+kern_return_t
+S_tioctl_tiocgeta (io_t port,
+ tcflag_t *modes,
+ cc_t *ccs,
+ speed_t *speeds)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ modes[0] = termstate.c_iflag;
+ modes[1] = termstate.c_oflag;
+ modes[2] = termstate.c_cflag;
+ modes[3] = termstate.c_lflag;
+ bcopy (termstate.c_cc, ccs, NCCS);
+ speeds[0] = termstate.__ispeed;
+ speeds[1] = termstate.__ospeed;
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return 0;
+}
+
+/* Common code for the varios TIOCSET* commands. */
+static error_t
+set_state (io_t port,
+ tcflag_t *modes,
+ cc_t *ccs,
+ speed_t *speeds,
+ int draino,
+ int flushi)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ int oldlflag;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else if (!fg_p (cred))
+ err = EBACKGROUND;
+ else
+ {
+ if (draino)
+ {
+ err = drain_output ();
+ if (err)
+ {
+ mutex_unlock (&global_lock);
+ ports_port_deref (cred);
+ return err;
+ }
+ }
+
+ if (flushi)
+ 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];
+ if (!(termstate.c_cflag & CIGNORE))
+ set_bits ();
+ if (oldlflag & ICANON)
+ {
+ if (!(termstate.c_lflag & ICANON))
+ copy_rawq ();
+ }
+ else
+ {
+ if (termstate.c_lflag & ICANON)
+ rescan_inputq ();
+ }
+ err = 0;
+ }
+
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+
+
+/* TIOCSETA -- Set termios state */
+kern_return_t
+S_tioctl_tiocseta (io_t port,
+ tcflag_t *modes,
+ cc_t *ccs,
+ speed_t *speeds)
+{
+ return set_state (port, modes, ccs, speeds, 0, 0);
+}
+
+/* Drain output, then set term state. */
+kern_return_t
+S_tioctl_tiocsetaw (io_t port,
+ tcflag_t *modes,
+ cc_t *ccs,
+ speed_t *speeds)
+{
+ return set_state (port, modes, ccs, speeds, 1, 0);
+}
+
+/* Flush input, drain output, then set term state. */
+kern_return_t
+S_tioctl_tiocsetaf (io_t port,
+ tcflag_t *modes,
+ cc_t *ccs,
+ speed_t *speeds)
+
+{
+ return set_state (port, modes, ccs, speeds, 1, 1);
+}
+
+/* TIOCGETD -- Return line discipline */
+kern_return_t
+S_tioctl_tiocgetd (io_t port,
+ int *disc)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+
+ *disc = 0;
+
+ ports_port_deref (cred);
+ return 0;
+}
+
+/* TIOCSETD -- Set line discipline */
+kern_return_t
+S_tioctl_tiocsetd (io_t port,
+ int disc)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket,
+ port, tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ mutex_unlock (&global_lock);
+
+ if (disc != 0)
+ err = ENXIO;
+ else
+ err = 0;
+
+ ports_port_deref (cred);
+ return 0;
+}
+
+/* TIOCDRAIN -- Wait for output to drain */
+kern_return_t
+S_tioctl_tiocdrain (io_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket,
+ port, tty_class);
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & O_WRITE))
+ {
+ mutex_unlock (&global_lock);
+ return EBADF;
+ }
+
+ err = drain_output ();
+ mutex_unlock (&global_lock);
+ return err;
+}
+
+/* TIOCSIG -- PTY master generate signal */
+kern_return_t
+S_tioctl_tiocsig (io_t port)
+{
+ return EOPNOTSUPP;
+}
+
+/* TIOCEXT -- PTY master enter external mode */
+kern_return_t
+S_tioctl_tiocext (io_t port)
+{
+ return EOPNOTSUPP;
+}
+
+/* TIOCUCNTL -- PTY set/clear usr cntl mode */
+kern_return_t
+S_tioctl_tiocucntl (io_t port,
+ int how)
+{
+ return EOPNOTSUPP;
+}
+
+/* TIOCSWINSZ -- Set window size */
+kern_return_t
+S_tioctl_tiocswinsz (io_t port,
+ struct winsize size)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ err = 0;
+
+ 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)
+ {
+ /* The size is actually changing. Record the new size and notify the
+ process group. */
+ window_size = size;
+ send_signal (SIGWINCH);
+ }
+
+ mutex_unlock (&global_lock);
+
+ return err;
+}
+
+/* TIOCGWINSZ -- Fetch window size */
+kern_return_t
+S_tioctl_tiocgwinsz (io_t port,
+ struct winsize *size)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ *size = window_size;
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return 0;
+}
+
+/* TIOCREMOTE -- PTY enter remote mode */
+kern_return_t
+S_tioctl_tiocremote (io_t port,
+ int how)
+{
+ return EOPNOTSUPP;
+}
+
+/* TIOCMGET -- Fetch all modem bits */
+kern_return_t
+S_tioctl_tiocmget (io_t port,
+ int *bits)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ *bits = mdmstate ();
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return 0;
+}
+
+/* TIOCMSET -- Set all modem bits */
+kern_return_t
+S_tioctl_tiocmset (io_t port,
+ int bits)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ mdmctl (MDMCTL_SET, bits);
+ err = 0;
+ }
+
+ mutex_unlock (&global_lock);
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCMBIC -- Clear some modem bits */
+kern_return_t
+S_tioctl_tiocmbic (io_t port,
+ int bits)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ mdmctl (MDMCTL_BIC, bits);
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCMBIS -- Set some modem bits */
+kern_return_t
+S_tioctl_tiocmbis (io_t port,
+ int bits)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ mdmctl (MDMCTL_BIS, bits);
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCSTART -- start output as if VSTART were typed */
+kern_return_t
+S_tioctl_tiocstart (io_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ termflags &= ~USER_OUTPUT_SUSP;
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCSTOP -- stop output as if VSTOP were typed */
+kern_return_t
+S_tioctl_tiocstop (io_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket,
+ port, tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ termflags |= USER_OUTPUT_SUSP;
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCPKT -- PTY Master packet mode */
+kern_return_t
+S_tioctl_tiocpkt (io_t port,
+ int how)
+{
+ return EOPNOTSUPP;
+}
+
+/* TIOCSTI -- Simulate terminal input */
+kern_return_t
+S_tioctl_tiocsti (io_t port,
+ char c)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket,
+ port, tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ /* BSD returns EACCES if this is not our controlling terminal,
+ but we have no way to do that. (And I don't think it actually
+ provides any security there, either.) */
+
+ if (!(cred->po->openmodes & O_READ))
+ err = EPERM;
+ else
+ {
+ input_character (c);
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCOUTQ -- return output queue size */
+kern_return_t
+S_tioctl_tiocoutq (io_t port,
+ int *queue_size)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ *queue_size = qsize (outputq) + pending_output_size ();
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCSPGRP -- set pgrp of terminal */
+kern_return_t
+S_tioctl_tiocspgrp (io_t port,
+ int pgrp)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ termflags &= ~NO_OWNER;
+ foreground_id = -pgrp;
+ 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,
+ int *pgrp)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t ret;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (termflags & NO_OWNER)
+ ret = ENOTTY; /* that's what BSD says... */
+ else
+ {
+ *pgrp = - foreground_id;
+ ret = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return ret;
+}
+
+/* TIOCCDTR -- clear DTR */
+kern_return_t
+S_tioctl_tioccdtr (io_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ mdmctl (MDMCTL_BIC, TIOCM_DTR);
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCSDTR -- set DTR */
+kern_return_t
+S_tioctl_tiocsdtr (io_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ mdmctl (MDMCTL_BIS, TIOCM_DTR);
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCCBRK -- Clear break condition */
+kern_return_t
+S_tioctl_tioccbrk (io_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ clear_break ();
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* TIOCSBRK -- Set break condition */
+kern_return_t
+S_tioctl_tiocsbrk (io_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket,
+ port, tty_class);
+ error_t err;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ err = EBADF;
+ else
+ {
+ set_break ();
+ err = 0;
+ }
+ mutex_unlock (&global_lock);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+error_t
+trivfs_S_file_truncate (struct trivfs_protid *cred,
+ off_t size)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+ if ((cred->po->openmodes & O_WRITE) == 0)
+ {
+ mutex_unlock (&global_lock);
+ return EBADF;
+ }
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ off_t off,
+ int whence,
+ off_t *newp)
+{
+ return ESPIPE;
+}
+
+error_t
+trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int *bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+ *bits = cred->po->openmodes;
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+#define HONORED_STATE_MODES (O_APPEND|O_ASYNC|O_FSYNC|O_NONBLOCK|O_NOATIME)
+
+error_t
+trivfs_S_io_set_all_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int bits)
+{
+
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+ cred->po->openmodes &= ~HONORED_STATE_MODES;
+ cred->po->openmodes |= (bits & HONORED_STATE_MODES);
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+error_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+ cred->po->openmodes |= (bits & HONORED_STATE_MODES);
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+error_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+ cred->po->openmodes &= ~(bits & HONORED_STATE_MODES);
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+error_t
+trivfs_S_io_mod_owner (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+ termflags &= ~NO_OWNER;
+ foreground_id = owner;
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+error_t
+trivfs_S_io_get_owner (struct trivfs_protid *cred,
+ mach_port_t erply,
+ mach_msg_type_name_t reply_type,
+ pid_t *owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+ if (termflags & NO_OWNER)
+ {
+ mutex_unlock (&global_lock);
+ return ENOTTY;
+ }
+ *owner = foreground_id;
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+error_t
+trivfs_S_io_get_async_icky (struct trivfs_protid *cred,
+ mach_port_t *id,
+ mach_msg_type_name_t *idtype)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ {
+ mutex_unlock (&global_lock);
+ return EBADF;
+ }
+ *id = async_icky_id;
+ *idtype = MACH_MSG_TYPE_MAKE_SEND;
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+error_t
+trivfs_S_io_async (struct trivfs_protid *cred,
+ mach_port_t notify,
+ mach_port_t *id,
+ mach_msg_type_name_t *idtype)
+{
+ struct async_req *ar;
+ if (!cred)
+ return EOPNOTSUPP;
+ mutex_lock (&global_lock);
+ if (!(cred->po->openmodes & (O_READ|O_WRITE)))
+ {
+ mutex_unlock (&global_lock);
+ return EBADF;
+ }
+ ar = malloc (sizeof (struct async_req));
+ ar->notify = notify;
+ ar->next = async_requests;
+ async_requests = ar;
+ *id = async_id;
+ *idtype = MACH_MSG_TYPE_MAKE_SEND;
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+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 available;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ /* We don't deal with SELECT_URG here. */
+ if (*type & ~(SELECT_READ | SELECT_WRITE))
+ return EINVAL;
+
+ available = 0;
+ if (*type == 0)
+ return 0;
+
+ mutex_lock (&global_lock);
+
+ while (1)
+ {
+ if ((*type & SELECT_READ) && qsize (inputq))
+ available |= SELECT_READ;
+ if ((*type & SELECT_WRITE) && qavail (outputq))
+ available |= SELECT_WRITE;
+
+ if (available)
+ {
+ *type = available;
+ mutex_unlock (&global_lock);
+ return 0;
+ }
+
+ hurd_condition_wait (&select_alert, &global_lock);
+ }
+}
+
+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)
+{
+ return EOPNOTSUPP;
+}
+
+/* Call all the scheduled async I/O handlers */
+static void
+call_asyncs ()
+{
+ struct async_req *ar, *nxt, **prevp;
+ mach_port_t err;
+
+ /* If no I/O is possible or nobody wants async
+ messages, don't bother further. */
+ if ((!(termflags & ICKY_ASYNC) && !async_requests)
+ || (!qsize (inputq) && !qavail (outputq)))
+ return;
+
+ if ((termflags & ICKY_ASYNC) && !(termflags & NO_OWNER))
+ hurd_sig_post (foreground_id, SIGIO, async_icky_id);
+
+ for (ar = async_requests, prevp = &async_requests;
+ ar;
+ ar = nxt)
+ {
+ nxt = ar->next;
+ err = nowait_msg_sig_post (ar->notify, SIGIO, async_id);
+ if (err == MACH_SEND_INVALID_DEST)
+ {
+ /* Receiver died; remove the notification request. */
+ *prevp = ar->next;
+ mach_port_deallocate (mach_task_self (), ar->notify);
+ free (ar);
+ }
+ else
+ prevp = &ar->next;
+ }
+}
+
+/* Send a signal to the current process (group) of the terminal. */
+void
+send_signal (int signo)
+{
+ mach_port_t right;
+
+ if (!(termflags & NO_OWNER))
+ {
+ right = ports_get_right (cttyid);
+ mach_port_insert_right (mach_task_self (), right, right,
+ MACH_MSG_TYPE_MAKE_SEND);
+ hurd_sig_post (foreground_id, signo, right);
+ mach_port_deallocate (mach_task_self (), right);
+ }
+}
+
+error_t
+trivfs_S_interrupt_operation (mach_port_t port)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, port,
+ tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+
+ ports_interrupt_rpc (cred);
+
+ ports_port_deref (cred);
+ return 0;
+}
+
+void
+report_carrier_off ()
+{
+ termflags |= NO_CARRIER;
+ if (!(termstate.c_cflag & CLOCAL))
+ send_signal (SIGHUP);
+}
+
+void
+report_carrier_on ()
+{
+ termflags &= ~NO_CARRIER;
+ condition_broadcast (&carrier_alert);
+}
+
+kern_return_t
+S_term_get_nodename (io_t arg,
+ char *name)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg,
+ tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+
+ strcpy (name, nodename);
+
+ ports_port_deref (cred);
+ return 0;
+}
+
+kern_return_t
+S_term_set_nodename (io_t arg,
+ char *name)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg,
+ tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+ ports_port_deref (cred);
+
+ if (strcmp (name, nodename))
+ return EINVAL;
+
+ return 0;
+}
+
+kern_return_t
+S_term_set_filenode (io_t arg,
+ file_t filenode)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg,
+ tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+ ports_port_deref (cred);
+
+ return EINVAL;
+}
+
+kern_return_t
+S_term_get_bottom_type (io_t arg,
+ int *ttype)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket,
+ arg, tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+
+ ports_port_deref (cred);
+ *ttype = TERM_ON_MACHDEV;
+ return 0;
+}
+
+kern_return_t
+S_term_on_machdev (io_t arg,
+ device_t machdev)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg,
+ tty_class);
+ if (!cred)
+ return EOPNOTSUPP;
+ ports_port_deref (cred);
+ return EINVAL;
+}
+
+kern_return_t
+S_term_on_hurddev (io_t arg,
+ io_t hurddev)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_term_on_pty (io_t arg,
+ mach_port_t *master)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ return EBUSY;
+}