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>
30 /* Symbol set of ioctl handler lists. If there are user-registered
31 handlers, one of these lists will contain them. The other lists are
32 handlers built into the library. The definition of the set comes from
37 struct ioctl_handler *v[0];
38 } *const _hurd_ioctl_handlers;
41 #define typesize(type) (1 << (type))
44 /* Perform the I/O control operation specified by REQUEST on FD.
45 The actual type and use of ARG and the return value depend on REQUEST. */
47 DEFUN(__ioctl, (fd, request),
48 int fd AND unsigned long int request DOTS)
50 /* Map individual type fields to Mach IPC types. */
51 static const int mach_types[] =
52 { MACH_MSG_TYPE_CHAR, MACH_MSG_TYPE_INTEGER_16, MACH_MSG_TYPE_INTEGER_32,
54 #define io2mach_type(count, type) \
55 ((mach_msg_type_t) { mach_types[type], typesize (type) * 8, count, 1, 0, 0 })
57 /* Extract the type information encoded in the request. */
58 unsigned int type = _IOC_TYPE (request);
63 mig_reply_header_t header;
64 char data[3 * sizeof (mach_msg_type_t) +
65 _IOT_COUNT0 (type) * typesize (_IOT_TYPE0 (type)) +
66 _IOT_COUNT1 (type) * typesize (_IOT_TYPE1 (type)) +
67 _IOT_COUNT2 (type) * typesize (_IOT_TYPE2 (type))];
69 mach_msg_header_t *const m = &msg.header.Head;
70 mach_msg_type_t *t = &msg.header.RetCodeType;
72 unsigned int reply_size;
78 struct hurd_sigstate *ss;
81 /* Send the RPC already packed up in MSG to IOPORT
82 and decode the return value. */
83 inline error_t send_rpc (io_t ioport)
87 m->msgh_size = (char *) t - (char *) &msg;
88 m->msgh_remote_port = ioport;
89 m->msgh_local_port = __mig_get_reply_port ();
92 m->msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
93 MACH_MSG_TYPE_MAKE_SEND_ONCE);
94 err = HURD_EINTR_RPC (ioport, __mach_msg (m, MACH_SEND_MSG|MACH_RCV_MSG,
95 m->msgh_size, sizeof (msg),
97 MACH_MSG_TIMEOUT_NONE,
101 case MACH_MSG_SUCCESS:
103 case MACH_SEND_INVALID_REPLY:
104 case MACH_RCV_INVALID_NAME:
105 __mig_dealloc_reply_port (m->msgh_local_port);
110 if ((m->msgh_bits & MACH_MSGH_BITS_COMPLEX))
112 /* Allow no ports or VM. */
113 __mach_msg_destroy (m);
114 /* Want to return a different error below for a different msgid. */
115 if (m->msgh_id == msgid + 100)
116 return MIG_TYPE_ERROR;
119 if (m->msgh_id != msgid + 100)
120 return (m->msgh_id == MACH_NOTIFY_SEND_ONCE ?
121 MIG_SERVER_DIED : MIG_REPLY_MISMATCH);
123 if (m->msgh_size != reply_size &&
124 m->msgh_size != sizeof (mig_reply_header_t))
125 return MIG_TYPE_ERROR;
127 if (*(int *) &msg.header.RetCodeType !=
128 ((union { mach_msg_type_t t; int i; })
129 { t: io2mach_type (1, _IOTS (sizeof msg.header.RetCode)) }).i)
130 return MIG_TYPE_ERROR;
131 return msg.header.RetCode;
136 va_start (ap, request);
137 arg = va_arg (ap, void *);
141 /* Check for a registered handler for REQUEST. */
144 const struct ioctl_handler *h;
146 for (i = 0; i < _hurd_ioctl_handlers->n; ++i)
147 for (h = _hurd_ioctl_handlers->v[i]; h != NULL; h = h->next)
148 if (request >= h->first_request && request <= h->last_request)
149 /* This handler groks REQUEST. Se lo puntamonos. */
150 return (*h->handler) (fd, request, arg);
153 /* Compute the Mach message ID for the RPC from the group and command
154 parts of the ioctl request. */
155 msgid = 100000 + ((_IOC_GROUP (request) - 'f') * 4000); /* Base subsystem */
156 /* Because of MiG's poorly chosen algorithm of adding 100 to a request
157 msgid to produce the reply msgid, we cannot just add the command part
158 of the ioctl request to the subsystem base msgid. For ioctl requests
159 past 99, we must skip blocks of 100 msgids to allow for the reply
160 msgids corresponding to the earlier requests. */
161 if (_IOC_COMMAND (request) >= 100)
163 if (_IOC_COMMAND (request) >= 200)
165 msgid += _IOC_COMMAND (request);
167 if (_IOC_INOUT (request) & IOC_IN)
169 /* Pack an argument into the message buffer. */
170 void in (unsigned int count, enum __ioctl_datum type)
175 const size_t len = count * typesize ((unsigned int) type);
176 *t = io2mach_type (count, type);
177 memcpy (p, arg, len);
180 p = (void *) (((unsigned long int) p + sizeof (*t) - 1)
181 & ~(sizeof (*t) - 1));
186 /* Pack the argument data. */
187 in (_IOT_COUNT0 (type), _IOT_TYPE0 (type));
188 in (_IOT_COUNT1 (type), _IOT_TYPE1 (type));
189 in (_IOT_COUNT2 (type), _IOT_TYPE2 (type));
192 /* Compute the expected size of the reply. There is a standard header
193 consisting of the message header and the reply code. Then, for out
194 and in/out ioctls, there come the data with their type headers. */
195 reply_size = sizeof (mig_reply_header_t);
197 if (_IOC_INOUT (request) & IOC_OUT)
199 inline void figure_reply (unsigned int count, enum __ioctl_datum type)
203 /* Add the size of the type and data. */
204 reply_size += sizeof (mach_msg_type_t) + typesize (type) * count;
205 /* Align it to word size. */
206 reply_size += sizeof (mach_msg_type_t) - 1;
207 reply_size &= ~(sizeof (mach_msg_type_t) - 1);
210 figure_reply (_IOT_COUNT0 (type), _IOT_TYPE0 (type));
211 figure_reply (_IOT_COUNT1 (type), _IOT_TYPE1 (type));
212 figure_reply (_IOT_COUNT2 (type), _IOT_TYPE2 (type));
215 /* Note that fd-write.c implements the same SIGTTOU behavior.
216 Any changes here should be done there as well. */
218 /* Don't use the ctty io port if we are blocking or ignoring SIGTTOU. */
219 ss = _hurd_self_sigstate ();
220 noctty = (__sigismember (&ss->blocked, SIGTTOU) ||
221 ss->actions[SIGTTOU].sa_handler == SIG_IGN);
222 __mutex_unlock (&ss->lock);
227 const io_t ioport = (!noctty && ctty != MACH_PORT_NULL) ? ctty : port;
230 /* The actual hair to send the RPC is in the inline `send_rpc'
231 function (above), to avoid horrendous indentation. */
232 err = send_rpc (ioport);
233 if (ioport == ctty && err == EBACKGROUND)
236 /* Our process group is orphaned, so we never generate a
237 signal; we just fail. */
241 /* Send a SIGTTOU signal to our process group. */
242 err = __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTOU, port));
243 /* XXX what to do if error here? */
244 /* At this point we should have just run the handler for
245 SIGTTOU or resumed after being stopped. Now this is
246 still a "system call", so check to see if we should
248 __mutex_lock (&ss->lock);
249 if (!(ss->actions[SIGTTOU].sa_flags & SA_RESTART))
251 __mutex_unlock (&ss->lock);
254 } while (err == EBACKGROUND);
258 t = (mach_msg_type_t *) msg.data;
261 /* Unpack the message buffer into the argument location. */
262 int out (unsigned int count, unsigned int type,
263 void *store, void **update)
267 const size_t len = count * typesize (type);
268 union { mach_msg_type_t t; int i; } ipctype;
269 ipctype.t = io2mach_type (count, type);
270 if (*(int *) t != ipctype.i)
273 memcpy (store, t, len);
276 t = (void *) (((unsigned long int) t + len + sizeof (*t) - 1)
277 & ~(sizeof (*t) - 1));
283 if (m->msgh_size != reply_size ||
284 ((_IOC_INOUT (request) & IOC_OUT) &&
285 (out (_IOT_COUNT0 (type), _IOT_TYPE0 (type), arg, &arg) ||
286 out (_IOT_COUNT1 (type), _IOT_TYPE1 (type), arg, &arg) ||
287 out (_IOT_COUNT2 (type), _IOT_TYPE2 (type), arg, &arg))))
288 return __hurd_fail (MIG_TYPE_ERROR);
293 /* The server didn't understand the RPC. */
296 return __hurd_fail (err);