diff options
Diffstat (limited to 'term/users.c')
-rw-r--r-- | term/users.c | 819 |
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; |