* hurd/hurd/ioctl.h (ioctl_handler_t): Move from here... * hurd/hurd/fd.h (ioctl_handler_t): ...to here. Change return type. Add `d', `crit', and `result' arguments. Change all callers and ioctl handlers. (hurd_fd): Add ioctl handler members. * hurd/fd-close.c: Update copyright years. (_hurd_fd_close): Clear ioctl handler and deallocate linker map. * hurd/fd-ioctl-call.c (_hurd_fd_call_ioctl_handler): Change return type. Add `d', `crit', and `result' arguments. Handle descriptor locking. Save ioctl handler between calls. Change all callers. * hurd/new-fd.c: Update copyright years. (_hurd_new_fd): Initialize ioctl handler. * hurd/port2fd.c: Update copyright years. (_hurd_port2fd): Initialize ioctl handler. * hurd/dtable.c: Update copyright years. (init_dtable): Initialize ioctl handler. * hurd/fd-ioctl-cleanup.c: New file. * hurd/Makefile (dtable): Add `fd-ioctl-cleanup'. * sysdeps/mach/hurd/ioctl.c (__ioctl): Lock descriptor. --- hurd/Makefile | 2 +- hurd/dtable.c | 8 ++- hurd/fd-close.c | 13 ++++- hurd/fd-ioctl-call.c | 112 +++++++++++++++++++++++++++++++----- hurd/fd-ioctl-cleanup.c | 31 ++++++++++ hurd/hurd/fd.h | 43 +++++++++++++- hurd/hurd/ioctl.h | 7 +- hurd/hurdioctl.c | 140 +++++++++++++++++++++++++++++++++------------ hurd/new-fd.c | 7 ++- hurd/port2fd.c | 11 +++- sysdeps/mach/hurd/ioctl.c | 43 ++++++++++++-- 11 files changed, 349 insertions(+), 68 deletions(-) create mode 100644 hurd/fd-ioctl-cleanup.c
diff --git a/hurd/Makefile b/hurd/Makefile index 4ad5128..768f93a 100644 --- a/hurd/Makefile +++ b/hurd/Makefile @@ -68,7 +68,7 @@ sig = hurdsig hurdfault siginfo hurd-raise preempt-sig \ dtable = dtable port2fd new-fd alloc-fd intern-fd \ getdport openport \ fd-close fd-read fd-write hurdioctl ctty-input ctty-output \ - fd-ioctl-call + fd-ioctl-call fd-ioctl-cleanup inlines = $(inline-headers:%.h=%-inlines) distribute = hurdstartup.h hurdfault.h hurdhost.h sysvshm.h \ faultexc.defs intr-rpc.defs intr-rpc.h intr-msg.h Notes diff --git a/hurd/dtable.c b/hurd/dtable.c index 125345e..bf5a9c1 100644 --- a/hurd/dtable.c +++ b/hurd/dtable.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1991,92,93,94,95,96,97,99 Free Software Foundation, Inc. +/* Copyright (C) 1991,92,93,94,95,96,97,99,2009 + Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -70,6 +71,11 @@ init_dtable (void) _hurd_port_init (&new->port, MACH_PORT_NULL); _hurd_port_init (&new->ctty, MACH_PORT_NULL); + /* Initialize the ioctl handler. */ + new->ioctl_handler = NULL; + new->ioctl_handler_map = NULL; + new->ioctl_handler_users = NULL; + /* Install the port in the descriptor. This sets up all the ctty magic. */ _hurd_port2fd (new, _hurd_init_dtable[i], 0); diff --git a/hurd/fd-close.c b/hurd/fd-close.c index f497d75..f3d0aa5 100644 --- a/hurd/fd-close.c +++ b/hurd/fd-close.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1994, 1995, 1997, 2009 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -17,6 +17,7 @@ 02111-1307 USA. */ #include <hurd/fd.h> +#include <dlfcn.h> error_t _hurd_fd_close (struct hurd_fd *fd) @@ -33,10 +34,20 @@ _hurd_fd_close (struct hurd_fd *fd) } else { + /* Clear the descriptor's ioctl handler, and close its liker map. */ + if (fd->ioctl_handler_map != NULL + && _hurd_userlink_clear (&fd->ioctl_handler_users)) + __libc_dlclose (fd->ioctl_handler_map); + + fd->ioctl_handler = NULL; + fd->ioctl_handler_map = NULL; + fd->ioctl_handler_users = NULL; + /* Clear the descriptor's port cells. This deallocates the ports if noone else is still using them. */ _hurd_port_set (&fd->ctty, MACH_PORT_NULL); _hurd_port_locked_set (&fd->port, MACH_PORT_NULL); + err = 0; } diff --git a/hurd/fd-ioctl-call.c b/hurd/fd-ioctl-call.c index c5a41e8..873a5ca 100644 --- a/hurd/fd-ioctl-call.c +++ b/hurd/fd-ioctl-call.c @@ -61,30 +61,112 @@ load_ioctl_handler (io_t port, void **map) } -/* Call D's ioctl handler, loading it from the underlying port if - necessary. Arguments are the same as ioctl handlers. */ +/* Load and install D's ioctl handler. D should be locked and CRIT should + point to a critical section lock. CRIT is unlocked whenever D is + unlocked and a new lock is returned in CRIT if D needs to be relocked. + D is unlocked while the handler is loaded. If the underlying port + of D changes while it's unlocked the operation is retried with the + new port. This is repeated until the port remains unchanged, or + if it becomes null D remains unlocked and EBADF is returned. D is + relocked and the ioctl handler is installed. If the load failed, + a dummy ioctl handler is installed with a null linker map. */ -int -_hurd_fd_call_ioctl_handler (int fd, int request, void *arg) +static error_t +install_ioctl_handler (struct hurd_fd *d, void **crit) { + struct hurd_userlink ulink; + io_t port; ioctl_handler_t ioctl_handler; void *ioctl_handler_map; - int result; error_t err; - /* Avoid spurious "may be used uninitialized" warning. */ - ioctl_handler_map = NULL; + while (!d->ioctl_handler) + { + port = _hurd_port_locked_get (&d->port, &ulink); + _hurd_critical_section_unlock (*crit); + if (port == MACH_PORT_NULL) + /* ULINK isn't linked when port is null. */ + return EBADF; + + /* Avoid spurious "may be used uninitialized" warning. */ + ioctl_handler_map = NULL; + + err = load_ioctl_handler (port, &ioctl_handler_map); + if (!err && ioctl_handler_map) + ioctl_handler = __libc_dlsym (ioctl_handler_map, + "hurd_ioctl_handler"); + if (err || !ioctl_handler_map || !ioctl_handler) + ioctl_handler = _hurd_dummy_ioctl_handler; + + *crit = _hurd_critical_section_lock (); + __spin_lock (&d->port.lock); + + if (_hurd_userlink_unlink (&ulink)) + __mach_port_deallocate (__mach_task_self (), port); + else if (port == d->port.port) + { + d->ioctl_handler = ioctl_handler; + if (ioctl_handler_map) + d->ioctl_handler_map = ioctl_handler_map; + } + } + + return 0; +} + + +/* Call D's ioctl handler, loading it from the underlying port if + necessary. Arguments are the same as ioctl handlers, except for + CRIT in which a new lock is returned. */ + +error_t +_hurd_fd_call_ioctl_handler (int fd, struct hurd_fd *d, void **crit, + int request, void *arg, int *result) +{ + struct hurd_userlink ioctl_ulink; + void *ioctl_handler_map; + error_t err; + + err = install_ioctl_handler (d, crit); + if (err) + { + *result = __hurd_fail (err); + return 0; + } - err = HURD_DPORT_USE (fd, load_ioctl_handler (port, &ioctl_handler_map)); - if (!err && ioctl_handler_map) - ioctl_handler = __libc_dlsym (ioctl_handler_map, "hurd_ioctl_handler"); - if (err || !ioctl_handler_map || !ioctl_handler) - ioctl_handler = _hurd_dummy_ioctl_handler; + ioctl_handler_map = d->ioctl_handler_map; + if (ioctl_handler_map) + { + ioctl_ulink.cleanup = &_hurd_fd_ioctl_handler_map_cleanup; + ioctl_ulink.cleanup_data = (void *) ioctl_handler_map; + _hurd_userlink_link (&d->ioctl_handler_users, &ioctl_ulink); + } - result = (*ioctl_handler) (fd, request, arg); + err = (*d->ioctl_handler) (fd, d, *crit, request, arg, result); if (ioctl_handler_map) - __libc_dlclose (ioctl_handler_map); + /* Unlink if from D's icotl user list. Relock D for the duration + if the handler unlocked it. */ + { + void dealloc (void) + { + if (_hurd_userlink_unlink (&ioctl_ulink)) + __libc_dlclose (ioctl_handler_map); + } - return result; + if (err) + dealloc (); + else + { + void *crit = _hurd_critical_section_lock (); + __spin_lock (&d->port.lock); + + dealloc (); + + __spin_unlock (&d->port.lock); + _hurd_critical_section_unlock (crit); + } + } + + return err; } diff --git a/hurd/fd-ioctl-cleanup.c b/hurd/fd-ioctl-cleanup.c new file mode 100644 index 0000000..df6e432 --- /dev/null +++ b/hurd/fd-ioctl-cleanup.c @@ -0,0 +1,31 @@ +/* Cleanup function for FD ioctl handler users who longjmp. + Copyright (C) 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#include <hurd/fd.h> +#include <dlfcn.h> + +/* The last user of the ioctl handler linker map DATA is now doing + `longjmp (ENV, VAL)', and this will unwind the frame of that last user. + Close the linker map he will never get back to using. */ + +void +_hurd_fd_ioctl_handler_map_cleanup (void *data, jmp_buf env, int val) +{ + __libc_dlclose (data); +} diff --git a/hurd/hurd/fd.h b/hurd/hurd/fd.h index 6ea9ad6..2137b6b 100644 --- a/hurd/hurd/fd.h +++ b/hurd/hurd/fd.h @@ -30,6 +30,28 @@ #include <sys/socket.h> +struct hurd_fd; /* Forward declaration. */ + +/* Type of handler function, called by ioctl to do its entire job. + D should be _hurd_dtable[FD], and it should be valid and locked, + CRIT should be a critical section lock. If the ioctl is handled 0 + is returned, D and CRIT is unlocked, and the return value of ioctl + is returned in RESULT, and any error is returned in ERRNO. If not + handled ENOTTY, or any error that prevents the ioctl from being + handled, is returned, leaving D and CRIT locked. + + D must be locked until a ioctl handler is found that can handle the + ioctl, otherwise it may get a new underlying port with a different + ioctl handler, which might affect the choice of ioctl handler. + + Two errors are returned so it's possible to distinguish between an + unhandled ioctl and a RPC that returns ENOTTY. The latter can't be + handled by simply relocking D, since D's port may change while it's + unlocked. */ +typedef error_t (*ioctl_handler_t) (int fd, struct hurd_fd *d, void *crit, + int request, void *arg, int *result); + + /* Structure representing a file descriptor. */ struct hurd_fd @@ -41,6 +63,16 @@ struct hurd_fd the same io object but which never returns EBACKGROUND; when not, this is nil. */ struct hurd_port ctty; + + /* Server provided handler for ioctls, and map for the dynamically + loaded module it resides in as returned by `dlopen'. The + module is loaded on the first call to `ioctl', before this + IOCTL_HANDLER is NULL, and if the load fails it is set + to `_hurd_dummy_ioctl_handler'. Their values are specific to PORT + and should be invalidated whenever `port' is changed. */ + ioctl_handler_t ioctl_handler; + void *ioctl_handler_map; + struct hurd_userlink *ioctl_handler_users; }; @@ -292,8 +324,15 @@ extern file_t __directory_name_split_at (int fd, const char *directory_name, /* Call D's ioctl handler, loading it from the underlying port if - necessary. Arguments are the same as ioctl handlers. */ -extern int _hurd_fd_call_ioctl_handler (int fd, int request, void *arg); + necessary. Arguments are the same as ioctl handlers, except for + CRIT in which a new lock is returned. */ +extern error_t _hurd_fd_call_ioctl_handler (int fd, struct hurd_fd *d, + void **crit, int request, + void *arg, int *result); + +/* Ioctl handler cleanup function for non-local exits. */ +extern void _hurd_fd_ioctl_handler_map_cleanup (void *data, jmp_buf env, + int val); #endif /* hurd/fd.h */ diff --git a/hurd/hurd/ioctl.h b/hurd/hurd/ioctl.h index f932fa1..6f3f9a4 100644 --- a/hurd/hurd/ioctl.h +++ b/hurd/hurd/ioctl.h @@ -23,11 +23,9 @@ #define __need___va_list #include <stdarg.h> #include <bits/ioctls.h> +#include <hurd/fd.h> -/* Type of handler function, called like ioctl to do its entire job. */ -typedef int (*ioctl_handler_t) (int fd, int request, void *arg); - /* Structure that records an ioctl handler. */ struct ioctl_handler { @@ -76,7 +74,8 @@ ioctl_handler_t _hurd_lookup_ioctl_handler (int request); /* A dummy handler that always fails. */ -int _hurd_dummy_ioctl_handler (int fd, int request, void *arg); +error_t _hurd_dummy_ioctl_handler (int fd, struct hurd_fd *, void *crit, + int request, void *arg, int *result); #endif /* hurd/ioctl.h */ diff --git a/hurd/hurdioctl.c b/hurd/hurdioctl.c index 0b91ee1..fb2db13 100644 --- a/hurd/hurdioctl.c +++ b/hurd/hurdioctl.c @@ -51,21 +51,27 @@ _hurd_lookup_ioctl_handler (int request) } /* A dummy handler that always fails. */ -int -_hurd_dummy_ioctl_handler (int fd, int request, void *arg) +error_t +_hurd_dummy_ioctl_handler (int fd, struct hurd_fd *d, void *crit, + int request, void *arg, int *result) { - return __hurd_fail (ENOTTY); + return ENOTTY; } #include <fcntl.h> /* Find out how many bytes may be read from FD without blocking. */ -static int +static error_t fioctl (int fd, + struct hurd_fd *d, + void *crit, int request, - int *arg) + int *arg, + int *result) { + mach_port_t port; + struct hurd_userlink link; error_t err; *(volatile int *) arg = *arg; @@ -73,57 +79,78 @@ fioctl (int fd, switch (request) { default: - err = ENOTTY; + return ENOTTY; + + case FIONREAD: + case FIONBIO: + case FIOASYNC: + case FIOSETOWN: + case FIOGETOWN: break; + } + + port = _hurd_port_locked_get (&d->port, &link); + _hurd_critical_section_unlock (crit); + switch (request) + { case FIONREAD: { mach_msg_type_number_t navail; - err = HURD_DPORT_USE (fd, __io_readable (port, &navail)); + err = __io_readable (port, &navail); if (!err) *arg = (int) navail; } break; case FIONBIO: - err = HURD_DPORT_USE (fd, (*arg ? - __io_set_some_openmodes : - __io_clear_some_openmodes) - (port, O_NONBLOCK)); + if (*arg) + err = __io_set_some_openmodes (port, O_NONBLOCK); + else + err = __io_clear_some_openmodes (port, O_NONBLOCK); break; case FIOASYNC: - err = HURD_DPORT_USE (fd, (*arg ? - __io_set_some_openmodes : - __io_clear_some_openmodes) - (port, O_ASYNC)); + if (*arg) + err = __io_set_some_openmodes (port, O_ASYNC); + else + err = __io_clear_some_openmodes (port, O_ASYNC); break; case FIOSETOWN: - err = HURD_DPORT_USE (fd, __io_mod_owner (port, *arg)); + err = __io_mod_owner (port, *arg); break; case FIOGETOWN: - err = HURD_DPORT_USE (fd, __io_get_owner (port, arg)); + err = __io_get_owner (port, arg); break; + + default: + assert (! "unhandled ioctl number slipped through"); } + _hurd_port_free (&d->port, &link, port); - return err ? __hurd_dfail (fd, err) : 0; + *result = err ? __hurd_dfail (fd, err) : 0; + return 0; } _HURD_HANDLE_IOCTLS (fioctl, FIOGETOWN, FIONREAD); -static int +static error_t fioclex (int fd, - int request) + struct hurd_fd *d, + void *crit, + int request, + void *arg, + int *result) { int flag; switch (request) { default: - return __hurd_fail (ENOTTY); + return ENOTTY; case FIOCLEX: flag = FD_CLOEXEC; break; @@ -132,7 +159,12 @@ fioclex (int fd, break; } - return __fcntl (fd, F_SETFD, flag); + d->flags = flag; + __spin_unlock (&d->port.lock); + _hurd_critical_section_unlock (crit); + + *result = 0; + return 0; } _HURD_HANDLE_IOCTLS (fioclex, FIOCLEX, FIONCLEX); @@ -279,28 +311,53 @@ tiocsctty_internal (io_t port, io_t ctty) return 0; } -static int +static error_t tiocsctty (int fd, - int request) /* Always TIOCSCTTY. */ + struct hurd_fd *d, + void *crit, + int request, + void *arg, + int *result) /* Always TIOCSCTTY. */ { + struct hurd_userlink link, ctty_link; + io_t port, ctty; error_t err; - err = HURD_DPORT_USE (fd, tiocsctty_internal (port, ctty)); - return __hurd_fail (err); + ctty = _hurd_port_get (&d->ctty, &ctty_link); + port = _hurd_port_locked_get (&d->port, &link); + _hurd_critical_section_unlock (crit); + + err = tiocsctty_internal (port, ctty); + + _hurd_port_free (&d->port, &link, port); + if (ctty != MACH_PORT_NULL) + _hurd_port_free (&d->ctty, &ctty_link, ctty); + + *result = __hurd_fail (err); + return 0; } _HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY); /* Dissociate from the controlling terminal. */ -static int +static error_t tiocnotty (int fd, - int request) /* Always TIOCNOTTY. */ + struct hurd_fd *d, + void *crit, + int request, + void *arg, + int *result) /* Always TIOCNOTTY. */ { + struct hurd_userlink link; + io_t dport; mach_port_t fd_cttyid; error_t err; - if (err = HURD_DPORT_USE (fd, __term_getctty (port, &fd_cttyid))) - return __hurd_fail (err); + dport = _hurd_port_locked_get (&d->port, &link); + _hurd_critical_section_unlock (crit); + + if (err = __term_getctty (dport, &fd_cttyid)) + goto out; if (__USEPORT (CTTYID, port != fd_cttyid)) err = EINVAL; @@ -308,11 +365,14 @@ tiocnotty (int fd, __mach_port_deallocate (__mach_task_self (), fd_cttyid); if (err) - return __hurd_fail (err); + goto out; /* Clear our cttyid port. */ install_ctty (MACH_PORT_NULL); +out: + _hurd_port_free (&d->port, &link, dport); + *result = __hurd_fail (err); return 0; } _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY); @@ -323,9 +383,12 @@ _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY); /* Fill in the buffer IFC->IFC_BUF of length IFC->IFC_LEN with a list of ifr structures, one for each network interface. */ -static int -siocgifconf (int fd, int request, struct ifconf *ifc) +static error_t +siocgifconf (int fd, struct hurd_fd *d, void *crit, + int request, struct ifconf *ifc, int *result) { + struct hurd_userlink link; + io_t port; error_t err; size_t data_len = ifc->ifc_len; char *data = ifc->ifc_buf; @@ -333,8 +396,10 @@ siocgifconf (int fd, int request, struct ifconf *ifc) if (data_len <= 0) return 0; - err = HURD_DPORT_USE (fd, __pfinet_siocgifconf (port, ifc->ifc_len, - &data, &data_len)); + port = _hurd_port_locked_get (&d->port, &link); + _hurd_critical_section_unlock (crit); + + err = __pfinet_siocgifconf (port, ifc->ifc_len, &data, &data_len); if (data_len < ifc->ifc_len) ifc->ifc_len = data_len; if (data != ifc->ifc_buf) @@ -342,6 +407,9 @@ siocgifconf (int fd, int request, struct ifconf *ifc) memcpy (ifc->ifc_buf, data, ifc->ifc_len); __vm_deallocate (__mach_task_self (), (vm_address_t) data, data_len); } - return err ? __hurd_dfail (fd, err) : 0; + + _hurd_port_free (&d->port, &link, port); + *result = err ? __hurd_dfail (fd, err) : 0; + return 0; } _HURD_HANDLE_IOCTL (siocgifconf, SIOCGIFCONF); diff --git a/hurd/new-fd.c b/hurd/new-fd.c index 152bb35..b2b09de 100644 --- a/hurd/new-fd.c +++ b/hurd/new-fd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1994, 1997, 1999 Free Software Foundation, Inc. +/* Copyright (C) 1994, 1997, 1999, 2009 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -36,6 +36,11 @@ _hurd_new_fd (io_t port, io_t ctty) /* And the fcntl flags. */ d->flags = 0; + + /* And the ioctl handler. */ + d->ioctl_handler = NULL; + d->ioctl_handler_map = NULL; + d->ioctl_handler_users = NULL; } return d; diff --git a/hurd/port2fd.c b/hurd/port2fd.c index 262e6d9..4d491df 100644 --- a/hurd/port2fd.c +++ b/hurd/port2fd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1994, 1997, 1999, 2007 Free Software Foundation, Inc. +/* Copyright (C) 1994, 1997, 1999, 2007, 2009 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -21,6 +21,7 @@ #include <hurd/signal.h> #include <hurd/term.h> #include <fcntl.h> +#include <dlfcn.h> /* Store PORT in file descriptor D, doing appropriate ctty magic. FLAGS are as for `open'; only O_IGNORE_CTTY is meaningful. @@ -61,4 +62,12 @@ _hurd_port2fd (struct hurd_fd *d, io_t dport, int flags) } _hurd_port_set (&d->ctty, ctty); + + /* Clear ioctl handler associated with old port. */ + if (d->ioctl_handler_map != NULL + && _hurd_userlink_clear (&d->ioctl_handler_users)) + __libc_dlclose (d->ioctl_handler_map); + d->ioctl_handler = NULL; + d->ioctl_handler_map = NULL; + d->ioctl_handler_users = NULL; } diff --git a/sysdeps/mach/hurd/ioctl.c b/sysdeps/mach/hurd/ioctl.c index 736ad8e..bdc2fc2 100644 --- a/sysdeps/mach/hurd/ioctl.c +++ b/sysdeps/mach/hurd/ioctl.c @@ -91,6 +91,9 @@ __ioctl (int fd, unsigned long int request, ...) void *arg = NULL; + struct hurd_fd *d; + void *crit; + error_t err; /* Send the RPC already packed up in MSG to IOPORT @@ -219,10 +222,25 @@ __ioctl (int fd, unsigned long int request, ...) va_end (ap); } + d = _hurd_fd_get (fd); + if (d == NULL) + return __hurd_fail (EBADF); + + crit = _hurd_critical_section_lock (); + __spin_lock (&d->port.lock); + + if (d->port.port == MACH_PORT_NULL) + { + __spin_unlock (&d->port.lock); + _hurd_critical_section_unlock (crit); + return __hurd_fail (EBADF); + } + { int save = errno; - int result = _hurd_fd_call_ioctl_handler (fd, request, arg); - if (result != -1 || errno != ENOTTY) + int result; + err = _hurd_fd_call_ioctl_handler (fd, d, &crit, request, arg, &result); + if (!err) return result; /* The handler doesn't grok this one. Try linked handlers. */ @@ -230,14 +248,14 @@ __ioctl (int fd, unsigned long int request, ...) } { - /* Check for a registered handler for REQUEST. */ ioctl_handler_t handler = _hurd_lookup_ioctl_handler (request); if (handler) { /* This handler groks REQUEST. Se lo puntamonos. */ int save = errno; - int result = (*handler) (fd, request, arg); - if (result != -1 || errno != ENOTTY) + int result; + err = (*handler) (fd, d, crit, request, arg, &result); + if (!err) return result; /* The handler doesn't really grok this one. @@ -280,7 +298,20 @@ __ioctl (int fd, unsigned long int request, ...) /* Marshal the arguments into the request message and make the RPC. This wrapper function handles EBACKGROUND returns, turning them into either SIGTTOU or EIO. */ - err = HURD_DPORT_USE (fd, _hurd_ctty_output (port, ctty, send_rpc)); + { + io_t port, ctty; + struct hurd_userlink ulink, ctty_ulink; + + ctty = _hurd_port_get (&d->ctty, &ctty_ulink); + port = _hurd_port_locked_get (&d->port, &ulink); + _hurd_critical_section_unlock (crit); + + err = _hurd_ctty_output (port, ctty, send_rpc); + + _hurd_port_free (&d->port, &ulink, port); + if (ctty != MACH_PORT_NULL) + _hurd_port_free (&d->ctty, &ctty_ulink, ctty); + } #ifdef MACH_MSG_TYPE_BIT t = (mach_msg_type_t *) msg.data; -- 1.6.3.3