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