1 /* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
21 #include <sys/ioctl.h>
24 #include <hurd/signal.h>
26 #include <mach/notify.h>
29 /* Symbol set of ioctl handler lists. If there are user-registered
30 handlers, one of these lists will contain them. The other lists are
31 handlers built into the library. The definition of the set comes from
36 struct ioctl_handler *v[0];
37 } *const _hurd_ioctl_handlers;
40 #define typesize(type) (1 << (type))
43 /* Perform the I/O control operation specified by REQUEST on FD.
44 The actual type and use of ARG and the return value depend on REQUEST. */
46 DEFUN(__ioctl, (fd, request),
47 int fd AND unsigned long int request DOTS)
49 /* Map individual type fields to Mach IPC types. */
50 static const int mach_types[] =
51 { MACH_MSG_TYPE_CHAR, MACH_MSG_TYPE_INTEGER_16, MACH_MSG_TYPE_INTEGER_32,
53 #define io2mach_type(count, type) \
54 ((mach_msg_type_t) { mach_types[type], typesize (type) * 8, count, 1, 0, 0 })
56 /* Extract the type information encoded in the request. */
57 unsigned int type = _IOC_TYPE (request);
62 mig_reply_header_t header;
63 char data[3 * sizeof (mach_msg_type_t) +
64 _IOT_COUNT0 (type) * typesize (_IOT_TYPE0 (type)) +
65 _IOT_COUNT1 (type) * typesize (_IOT_TYPE1 (type)) +
66 _IOT_COUNT2 (type) * typesize (_IOT_TYPE2 (type))];
68 mach_msg_header_t *const m = &msg.header.Head;
69 mach_msg_type_t *t = &msg.header.RetCodeType;
71 unsigned int reply_size;
77 struct hurd_sigstate *ss;
80 /* Send the RPC already packed up in MSG to IOPORT
81 and decode the return value. */
82 inline error_t send_rpc (io_t ioport)
86 m->msgh_size = (char *) t - (char *) &msg;
87 m->msgh_remote_port = ioport;
88 m->msgh_local_port = __mig_get_reply_port ();
91 m->msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
92 MACH_MSG_TYPE_MAKE_SEND_ONCE);
93 err = HURD_EINTR_RPC (ioport, __mach_msg (m, MACH_SEND_MSG|MACH_RCV_MSG,
94 m->msgh_size, sizeof (msg),
96 MACH_MSG_TIMEOUT_NONE,
100 case MACH_MSG_SUCCESS:
102 case MACH_SEND_INVALID_REPLY:
103 case MACH_RCV_INVALID_NAME:
104 __mig_dealloc_reply_port ();
109 if ((m->msgh_bits & MACH_MSGH_BITS_COMPLEX))
111 /* Allow no ports or VM. */
112 __mach_msg_destroy (m);
113 /* Want to return a different error below for a different msgid. */
114 if (m->msgh_id == msgid + 100)
115 return MIG_TYPE_ERROR;
118 if (m->msgh_id != msgid + 100)
119 return (m->msgh_id == MACH_NOTIFY_SEND_ONCE ?
120 MIG_SERVER_DIED : MIG_REPLY_MISMATCH);
122 if (m->msgh_size != reply_size &&
123 m->msgh_size != sizeof (mig_reply_header_t))
124 return MIG_TYPE_ERROR;
126 if (*(int *) &msg.header.RetCodeType !=
127 ((union { mach_msg_type_t t; int i; })
128 { t: io2mach_type (1, _IOTS (sizeof msg.header.RetCode)) }).i)
129 return MIG_TYPE_ERROR;
130 return msg.header.RetCode;
135 va_start (ap, request);
136 arg = va_arg (ap, void *);
140 /* Check for a registered handler for REQUEST. */
143 const struct ioctl_handler *h;
145 for (i = 0; i < _hurd_ioctl_handlers->n; ++i)
146 for (h = _hurd_ioctl_handlers->v[i]; h != NULL; h = h->next)
147 if (request >= h->first_request && request <= h->last_request)
148 /* This handler groks REQUEST. Se lo puntamonos. */
149 return (*h->handler) (fd, request, arg);
152 /* Compute the Mach message ID for the RPC from the group and command
153 parts of the ioctl request. */
154 msgid = 100000 + ((_IOC_GROUP (request) - 'f') * 4000); /* Base subsystem */
155 /* Because of MiG's poorly chosen algorithm of adding 100 to a request
156 msgid to produce the reply msgid, we cannot just add the command part
157 of the ioctl request to the subsystem base msgid. For ioctl requests
158 past 99, we must skip blocks of 100 msgids to allow for the reply
159 msgids corresponding to the earlier requests. */
160 if (_IOC_COMMAND (request) >= 100)
162 if (_IOC_COMMAND (request) >= 200)
164 msgid += _IOC_COMMAND (request);
166 if (_IOC_INOUT (request) & IOC_IN)
168 /* Pack an argument into the message buffer. */
169 void in (unsigned int count, enum __ioctl_datum type)
174 const size_t len = count * typesize ((unsigned int) type);
175 *t = io2mach_type (count, type);
176 memcpy (p, arg, len);
179 p = (void *) (((unsigned long int) p + sizeof (*t) - 1)
180 & ~(sizeof (*t) - 1));
185 /* Pack the argument data. */
186 in (_IOT_COUNT0 (type), _IOT_TYPE0 (type));
187 in (_IOT_COUNT1 (type), _IOT_TYPE1 (type));
188 in (_IOT_COUNT2 (type), _IOT_TYPE2 (type));
191 /* Compute the expected size of the reply. There is a standard header
192 consisting of the message header and the reply code. Then, for out
193 and in/out ioctls, there come the data with their type headers. */
194 reply_size = sizeof (mig_reply_header_t);
196 if (_IOC_INOUT (request) & IOC_OUT)
198 inline void figure_reply (unsigned int count, enum __ioctl_datum type)
202 /* Add the size of the type and data. */
203 reply_size += sizeof (mach_msg_type_t) + typesize (type) * count;
204 /* Align it to word size. */
205 reply_size += sizeof (mach_msg_type_t) - 1;
206 reply_size &= ~(sizeof (mach_msg_type_t) - 1);
209 figure_reply (_IOT_COUNT0 (type), _IOT_TYPE0 (type));
210 figure_reply (_IOT_COUNT1 (type), _IOT_TYPE1 (type));
211 figure_reply (_IOT_COUNT2 (type), _IOT_TYPE2 (type));
214 /* Note that fd-write.c implements the same SIGTTOU behavior.
215 Any changes here should be done there as well. */
217 /* Don't use the ctty io port if we are blocking or ignoring SIGTTOU. */
218 ss = _hurd_self_sigstate ();
219 noctty = (__sigismember (&ss->blocked, SIGTTOU) ||
220 ss->actions[SIGTTOU].sa_handler == SIG_IGN);
221 __mutex_unlock (&ss->lock);
226 const io_t ioport = (noctty && ctty != MACH_PORT_NULL) ? ctty : port;
229 /* The actual hair to send the RPC is in the inline `send_rpc'
230 function (above), to avoid horrendous indentation. */
231 err = send_rpc (ioport);
232 if (ioport == ctty && err == EBACKGROUND)
235 /* Our process group is orphaned, so we never generate a
236 signal; we just fail. */
240 /* Send a SIGTTOU signal to our process group. */
241 err = __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTOU, port));
242 /* XXX what to do if error here? */
243 /* At this point we should have just run the handler for
244 SIGTTOU or resumed after being stopped. Now this is
245 still a "system call", so check to see if we should
247 __mutex_lock (&ss->lock);
248 if (!(ss->actions[SIGTTOU].sa_flags & SA_RESTART))
250 __mutex_unlock (&ss->lock);
253 } while (err == EBACKGROUND);
257 t = (mach_msg_type_t *) msg.data;
260 /* Unpack the message buffer into the argument location. */
261 int out (unsigned int count, unsigned int type,
262 void *store, void **update)
266 const size_t len = count * typesize (type);
267 union { mach_msg_type_t t; int i; } ipctype;
268 ipctype.t = io2mach_type (count, type);
269 if (*(int *) t != ipctype.i)
272 memcpy (store, t, len);
275 t = (void *) (((unsigned long int) t + len + sizeof (*t) - 1)
276 & ~(sizeof (*t) - 1));
282 if (m->msgh_size != reply_size ||
283 ((_IOC_INOUT (request) & IOC_OUT) &&
284 (out (_IOT_COUNT0 (type), _IOT_TYPE0 (type), arg, &arg) ||
285 out (_IOT_COUNT1 (type), _IOT_TYPE1 (type), arg, &arg) ||
286 out (_IOT_COUNT2 (type), _IOT_TYPE2 (type), arg, &arg))))
287 return __hurd_fail (MIG_TYPE_ERROR);
292 /* The server didn't understand the RPC. */
295 return __hurd_fail (err);