0405e571317f02ed483987eaf36351d5e62e1034
[kopensolaris-gnu/glibc.git] / sysdeps / mach / hurd / ioctl.c
1 /* Copyright (C) 1992, 1993, 1994, 1995 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 #include <hurd/ioctl.h>
30
31
32 #define typesize(type)  (1 << (type))
33
34
35 /* Perform the I/O control operation specified by REQUEST on FD.
36    The actual type and use of ARG and the return value depend on REQUEST.  */
37 int
38 DEFUN(__ioctl, (fd, request),
39       int fd AND unsigned long int request DOTS)
40 {
41   /* Map individual type fields to Mach IPC types.  */
42   static const int mach_types[] =
43     { MACH_MSG_TYPE_CHAR, MACH_MSG_TYPE_INTEGER_16, MACH_MSG_TYPE_INTEGER_32,
44       -1 };
45 #define io2mach_type(count, type) \
46   ((mach_msg_type_t) { mach_types[type], typesize (type) * 8, count, 1, 0, 0 })
47
48   /* Extract the type information encoded in the request.  */
49   unsigned int type = _IOC_TYPE (request);
50
51   /* Message buffer.  */
52   struct
53     {
54       mig_reply_header_t header;
55       char data[3 * sizeof (mach_msg_type_t) +
56                 _IOT_COUNT0 (type) * typesize (_IOT_TYPE0 (type)) +
57                 _IOT_COUNT1 (type) * typesize (_IOT_TYPE1 (type)) +
58                 _IOT_COUNT2 (type) * typesize (_IOT_TYPE2 (type))];
59     } msg;
60   mach_msg_header_t *const m = &msg.header.Head;
61   mach_msg_type_t *t = &msg.header.RetCodeType;
62   mach_msg_id_t msgid;
63   unsigned int reply_size;
64
65   void *arg;
66
67   error_t err;
68
69   struct hurd_sigstate *ss;
70   int noctty;
71
72   /* Send the RPC already packed up in MSG to IOPORT
73      and decode the return value.  */
74   inline error_t send_rpc (io_t ioport)
75     {
76       error_t err;
77
78       m->msgh_size = (char *) t - (char *) &msg;
79       m->msgh_remote_port = ioport;
80       m->msgh_local_port = __mig_get_reply_port ();
81       m->msgh_seqno = 0;
82       m->msgh_id = msgid;
83       m->msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
84                                      MACH_MSG_TYPE_MAKE_SEND_ONCE);
85       err = HURD_EINTR_RPC (ioport, __mach_msg (m, MACH_SEND_MSG|MACH_RCV_MSG,
86                                                 m->msgh_size, sizeof (msg),
87                                                 m->msgh_local_port,
88                                                 MACH_MSG_TIMEOUT_NONE,
89                                                 MACH_PORT_NULL));
90       switch (err)
91         {
92         case MACH_MSG_SUCCESS:
93           break;
94         case MACH_SEND_INVALID_REPLY:
95         case MACH_RCV_INVALID_NAME:
96           __mig_dealloc_reply_port (m->msgh_local_port);
97         default:
98           return err;
99         }
100
101       if ((m->msgh_bits & MACH_MSGH_BITS_COMPLEX))
102         {
103           /* Allow no ports or VM.  */
104           __mach_msg_destroy (m);
105           /* Want to return a different error below for a different msgid.  */
106           if (m->msgh_id == msgid + 100)
107             return MIG_TYPE_ERROR;
108         }
109
110       if (m->msgh_id != msgid + 100)
111         return (m->msgh_id == MACH_NOTIFY_SEND_ONCE ?
112                 MIG_SERVER_DIED : MIG_REPLY_MISMATCH);
113
114       if (m->msgh_size != reply_size &&
115           m->msgh_size != sizeof (mig_reply_header_t))
116         return MIG_TYPE_ERROR;
117
118       if (*(int *) &msg.header.RetCodeType !=
119           ((union { mach_msg_type_t t; int i; })
120            { t: io2mach_type (1, _IOTS (sizeof msg.header.RetCode)) }).i)
121         return MIG_TYPE_ERROR;
122       return msg.header.RetCode;
123     }
124
125   va_list ap;
126
127   va_start (ap, request);
128   arg = va_arg (ap, void *);
129   va_end (ap);
130
131   {
132     /* Check for a registered handler for REQUEST.  */
133     ioctl_handler_t handler = _hurd_lookup_ioctl_handler (request);
134     if (handler)
135       /* This handler groks REQUEST.  Se lo puntamonos.  */
136       return (*handler) (fd, request, arg);
137   }
138
139   /* Compute the Mach message ID for the RPC from the group and command
140      parts of the ioctl request.  */
141   msgid = 100000 + ((_IOC_GROUP (request) - 'f') * 4000); /* Base subsystem */
142   /* Because of MiG's poorly chosen algorithm of adding 100 to a request
143      msgid to produce the reply msgid, we cannot just add the command part
144      of the ioctl request to the subsystem base msgid.  For ioctl requests
145      past 99, we must skip blocks of 100 msgids to allow for the reply
146      msgids corresponding to the earlier requests.  */
147   if (_IOC_COMMAND (request) >= 100)
148     msgid += 100;
149   if (_IOC_COMMAND (request) >= 200)
150     msgid += 100;
151   msgid += _IOC_COMMAND (request);
152
153   if (_IOC_INOUT (request) & IOC_IN)
154     {
155       /* Pack an argument into the message buffer.  */
156       void in (unsigned int count, enum __ioctl_datum type)
157         {
158           if (count > 0)
159             {
160               void *p = &t[1];
161               const size_t len = count * typesize ((unsigned int) type);
162               *t = io2mach_type (count, type);
163               memcpy (p, arg, len);
164               arg += len;
165               p += len;
166               p = (void *) (((unsigned long int) p + sizeof (*t) - 1)
167                             & ~(sizeof (*t) - 1));
168               t = p;
169             }
170         }
171
172       /* Pack the argument data.  */
173       in (_IOT_COUNT0 (type), _IOT_TYPE0 (type));
174       in (_IOT_COUNT1 (type), _IOT_TYPE1 (type));
175       in (_IOT_COUNT2 (type), _IOT_TYPE2 (type));
176     }
177
178   /* Compute the expected size of the reply.  There is a standard header
179      consisting of the message header and the reply code.  Then, for out
180      and in/out ioctls, there come the data with their type headers.  */
181   reply_size = sizeof (mig_reply_header_t);
182
183   if (_IOC_INOUT (request) & IOC_OUT)
184     {
185       inline void figure_reply (unsigned int count, enum __ioctl_datum type)
186         {
187           if (count > 0)
188             {
189               /* Add the size of the type and data.  */
190               reply_size += sizeof (mach_msg_type_t) + typesize (type) * count;
191               /* Align it to word size.  */
192               reply_size += sizeof (mach_msg_type_t) - 1;
193               reply_size &= ~(sizeof (mach_msg_type_t) - 1);
194             }
195         }
196       figure_reply (_IOT_COUNT0 (type), _IOT_TYPE0 (type));
197       figure_reply (_IOT_COUNT1 (type), _IOT_TYPE1 (type));
198       figure_reply (_IOT_COUNT2 (type), _IOT_TYPE2 (type));
199     }
200
201   /* Note that fd-write.c implements the same SIGTTOU behavior.
202      Any changes here should be done there as well.  */
203
204   /* Don't use the ctty io port if we are blocking or ignoring SIGTTOU.  */
205   ss = _hurd_self_sigstate ();
206   __spin_lock (&ss->lock);
207   noctty = (__sigismember (&ss->blocked, SIGTTOU) ||
208             ss->actions[SIGTTOU].sa_handler == SIG_IGN);
209   __spin_unlock (&ss->lock);
210
211   err = HURD_DPORT_USE
212     (fd,
213      ({
214        const io_t ioport = (!noctty && ctty != MACH_PORT_NULL) ? ctty : port;
215        do
216          {
217            /* The actual hair to send the RPC is in the inline `send_rpc'
218               function (above), to avoid horrendous indentation.  */
219            err = send_rpc (ioport);
220            if (ioport == ctty && err == EBACKGROUND)
221              {
222                if (_hurd_orphaned)
223                  /* Our process group is orphaned, so we never generate a
224                     signal; we just fail.  */
225                  err = EIO;
226                else
227                  {
228                    /* Send a SIGTTOU signal to our process group.  */
229                    err = __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTOU, port));
230                    /* XXX what to do if error here? */
231                    /* At this point we should have just run the handler for
232                       SIGTTOU or resumed after being stopped.  Now this is
233                       still a "system call", so check to see if we should
234                       restart it.  */
235                    __spin_lock (&ss->lock);
236                    if (!(ss->actions[SIGTTOU].sa_flags & SA_RESTART))
237                      err = EINTR;
238                    __spin_unlock (&ss->lock);
239                  }
240              }
241          } while (err == EBACKGROUND);
242        err;
243      }));
244
245   t = (mach_msg_type_t *) msg.data;
246   switch (err)
247     {
248       /* Unpack the message buffer into the argument location.  */
249       int out (unsigned int count, unsigned int type,
250                void *store, void **update)
251         {
252           if (count > 0)
253             {
254               const size_t len = count * typesize (type);
255               union { mach_msg_type_t t; int i; } ipctype;
256               ipctype.t = io2mach_type (count, type);
257               if (*(int *) t != ipctype.i)
258                 return 1;
259               ++t;
260               memcpy (store, t, len);
261               if (update != NULL)
262                 *update += len;
263               t = (void *) (((unsigned long int) t + len + sizeof (*t) - 1)
264                             & ~(sizeof (*t) - 1));
265             }
266           return 0;
267         }
268
269     case 0:
270       if (m->msgh_size != reply_size ||
271           ((_IOC_INOUT (request) & IOC_OUT) &&
272            (out (_IOT_COUNT0 (type), _IOT_TYPE0 (type), arg, &arg) ||
273             out (_IOT_COUNT1 (type), _IOT_TYPE1 (type), arg, &arg) ||
274             out (_IOT_COUNT2 (type), _IOT_TYPE2 (type), arg, &arg))))
275         return __hurd_fail (MIG_TYPE_ERROR);
276       return 0;
277
278     case MIG_BAD_ID:
279     case EOPNOTSUPP:
280       /* The server didn't understand the RPC.  */
281       err = ENOTTY;
282     default:
283       return __hurd_fail (err);
284     }
285 }
286
287 weak_alias (__ioctl, ioctl)