d8d372da4aaf94d15d67c8239bc26097f2055005
[kopensolaris-gnu/glibc.git] / sysdeps / mach / hurd / ioctl.c
1 /* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
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.
8
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.
13
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.  */
18
19 #include <ansidecl.h>
20 #include <errno.h>
21 #include <sys/ioctl.h>
22 #include <hurd.h>
23 #include <hurd/fd.h>
24 #include <hurd/signal.h>
25 #include <stdarg.h>
26 #include <mach/notify.h>
27 #include <assert.h>
28
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
32    hurdioctl.c.  */
33 extern struct 
34   {
35     size_t n;
36     struct ioctl_handler *v[0];
37   } *const _hurd_ioctl_handlers;
38
39
40 #define typesize(type)  (1 << (type))
41
42
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.  */
45 int
46 DEFUN(__ioctl, (fd, request),
47       int fd AND unsigned long int request DOTS)
48 {
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,
52       -1 };
53 #define io2mach_type(count, type) \
54   ((mach_msg_type_t) { mach_types[type], typesize (type) * 8, count, 1, 0, 0 })
55
56   /* Extract the type information encoded in the request.  */
57   unsigned int type = _IOC_TYPE (request);
58
59   /* Message buffer.  */
60   struct
61     {
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))];
67     } msg;
68   mach_msg_header_t *const m = &msg.header.Head;
69   mach_msg_type_t *t = &msg.header.RetCodeType;
70   mach_msg_id_t msgid;
71   unsigned int reply_size;
72
73   void *arg;
74
75   error_t err;
76
77   struct hurd_sigstate *ss;
78   int noctty;
79
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)
83     {
84       error_t err;
85
86       m->msgh_size = (char *) t - (char *) &msg;
87       m->msgh_remote_port = ioport;
88       m->msgh_local_port = __mig_get_reply_port ();
89       m->msgh_seqno = 0;
90       m->msgh_id = msgid;
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),
95                                                 m->msgh_local_port,
96                                                 MACH_MSG_TIMEOUT_NONE,
97                                                 MACH_PORT_NULL));
98       switch (err)
99         {
100         case MACH_MSG_SUCCESS:
101           break;
102         case MACH_SEND_INVALID_REPLY:
103         case MACH_RCV_INVALID_NAME:
104           __mig_dealloc_reply_port (m->msgh_local_port);
105         default:
106           return err;
107         }
108
109       if ((m->msgh_bits & MACH_MSGH_BITS_COMPLEX))
110         {
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;
116         }
117
118       if (m->msgh_id != msgid + 100)
119         return (m->msgh_id == MACH_NOTIFY_SEND_ONCE ?
120                 MIG_SERVER_DIED : MIG_REPLY_MISMATCH);
121
122       if (m->msgh_size != reply_size &&
123           m->msgh_size != sizeof (mig_reply_header_t))
124         return MIG_TYPE_ERROR;
125
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;
131     }
132
133   va_list ap;
134
135   va_start (ap, request);
136   arg = va_arg (ap, void *);
137   va_end (ap);
138
139   {
140     /* Check for a registered handler for REQUEST.  */
141
142     size_t i;
143     const struct ioctl_handler *h;
144
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);
150   }
151
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)
161     msgid += 100;
162   if (_IOC_COMMAND (request) >= 200)
163     msgid += 100;
164   msgid += _IOC_COMMAND (request);
165
166   if (_IOC_INOUT (request) & IOC_IN)
167     {
168       /* Pack an argument into the message buffer.  */
169       void in (unsigned int count, enum __ioctl_datum type)
170         {
171           if (count > 0)
172             {
173               void *p = &t[1];
174               const size_t len = count * typesize ((unsigned int) type);
175               *t = io2mach_type (count, type);
176               memcpy (p, arg, len);
177               arg += len;
178               p += len;
179               p = (void *) (((unsigned long int) p + sizeof (*t) - 1)
180                             & ~(sizeof (*t) - 1));
181               t = p;
182             }
183         }
184
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));
189     }
190
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);
195
196   if (_IOC_INOUT (request) & IOC_OUT)
197     {
198       inline void figure_reply (unsigned int count, enum __ioctl_datum type)
199         {
200           if (count > 0)
201             {
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);
207             }
208         }
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));
212     }
213
214   /* Note that fd-write.c implements the same SIGTTOU behavior.
215      Any changes here should be done there as well.  */
216
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);
222
223   err = HURD_DPORT_USE
224     (fd,
225      ({
226        const io_t ioport = (!noctty && ctty != MACH_PORT_NULL) ? ctty : port;
227        do
228          {
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)
233              {
234                if (_hurd_orphaned)
235                  /* Our process group is orphaned, so we never generate a
236                     signal; we just fail.  */
237                  err = EIO;
238                else
239                  {
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
246                       restart it.  */
247                    __mutex_lock (&ss->lock);
248                    if (!(ss->actions[SIGTTOU].sa_flags & SA_RESTART))
249                      err = EINTR;
250                    __mutex_unlock (&ss->lock);
251                  }
252              }
253          } while (err == EBACKGROUND);
254        err;
255      }));
256
257   t = (mach_msg_type_t *) msg.data;
258   switch (err)
259     {
260       /* Unpack the message buffer into the argument location.  */
261       int out (unsigned int count, unsigned int type,
262                void *store, void **update)
263         {
264           if (count > 0)
265             {
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)
270                 return 1;
271               ++t;
272               memcpy (store, t, len);
273               if (update != NULL)
274                 *update += len;
275               t = (void *) (((unsigned long int) t + len + sizeof (*t) - 1)
276                             & ~(sizeof (*t) - 1));
277             }
278           return 0;
279         }
280
281     case 0:
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);
288       return 0;
289
290     case MIG_BAD_ID:
291     case EOPNOTSUPP:
292       /* The server didn't understand the RPC.  */
293       err = ENOTTY;
294     default:
295       return __hurd_fail (err);
296     }
297 }