aboutsummaryrefslogtreecommitdiff
path: root/term/users.c
diff options
context:
space:
mode:
Diffstat (limited to 'term/users.c')
-rw-r--r--term/users.c819
1 files changed, 483 insertions, 336 deletions
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;