Merge commit '7e3488dc6cdcb0c04e1ce167a1a3bfef83b5f2e0'
[unleashed.git] / kernel / syscall / strcalls.c
blobbdde97a39d22ab4e207fd67bed265c53f38e500d
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include <sys/types.h>
34 #include <sys/sysmacros.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/errno.h>
38 #include <sys/vnode.h>
39 #include <sys/file.h>
40 #include <sys/proc.h>
41 #include <sys/stropts.h>
42 #include <sys/stream.h>
43 #include <sys/strsubr.h>
44 #include <sys/fs/fifonode.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/debug.h>
50 * STREAMS system calls.
53 int getmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *flagsp);
54 int putmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int flags);
55 int getpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *prip,
56 int *flagsp);
57 int putpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int pri,
58 int flags);
60 static int msgio(int fdes, struct strbuf *ctl, struct strbuf *data, int *rval,
61 int mode, unsigned char *prip, int *flagsp);
63 int
64 getmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *flagsp)
66 int error;
67 int localflags;
68 int realflags = 0;
69 unsigned char pri = 0;
70 int rv = 0;
73 * Convert between old flags (localflags) and new flags (realflags).
75 if (copyin(flagsp, &localflags, sizeof (*flagsp)))
76 return (set_errno(EFAULT));
77 switch (localflags) {
78 case 0:
79 realflags = MSG_ANY;
80 break;
82 case RS_HIPRI:
83 realflags = MSG_HIPRI;
84 break;
86 default:
87 return (set_errno(EINVAL));
90 if ((error = msgio(fdes, ctl, data, &rv, FREAD, &pri,
91 &realflags)) == 0) {
93 * massage realflags based on localflags.
95 if (realflags == MSG_HIPRI)
96 localflags = RS_HIPRI;
97 else
98 localflags = 0;
99 if (copyout(&localflags, flagsp, sizeof (*flagsp)))
100 error = EFAULT;
102 if (error != 0)
103 return (set_errno(error));
104 return (rv);
108 putmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int flags)
110 unsigned char pri = 0;
111 int realflags;
112 int error;
113 int rv = 0;
115 switch (flags) {
116 case RS_HIPRI:
117 realflags = MSG_HIPRI;
118 break;
119 case (RS_HIPRI|MSG_XPG4):
120 realflags = MSG_HIPRI|MSG_XPG4;
121 break;
122 case MSG_XPG4:
123 realflags = MSG_BAND|MSG_XPG4;
124 break;
125 case 0:
126 realflags = MSG_BAND;
127 break;
129 default:
130 return (set_errno(EINVAL));
132 error = msgio(fdes, ctl, data, &rv, FWRITE, &pri, &realflags);
133 if (error != 0)
134 return (set_errno(error));
135 return (rv);
140 getpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int *prip,
141 int *flagsp)
143 int error;
144 int flags;
145 int intpri;
146 unsigned char pri;
147 int rv = 0;
149 if (copyin(flagsp, &flags, sizeof (flags)))
150 return (set_errno(EFAULT));
151 if (copyin(prip, &intpri, sizeof (intpri)))
152 return (set_errno(EFAULT));
153 if ((intpri > 255) || (intpri < 0))
154 return (set_errno(EINVAL));
155 pri = (unsigned char)intpri;
156 error = msgio(fdes, ctl, data, &rv, FREAD, &pri, &flags);
157 if (error != 0)
158 return (set_errno(error));
159 if (copyout(&flags, flagsp, sizeof (flags)))
160 return (set_errno(EFAULT));
161 intpri = (int)pri;
162 if (copyout(&intpri, prip, sizeof (intpri)))
163 return (set_errno(EFAULT));
164 return (rv);
168 putpmsg(int fdes, struct strbuf *ctl, struct strbuf *data, int intpri,
169 int flags)
171 unsigned char pri;
172 int rv = 0;
173 int error;
175 if ((intpri > 255) || (intpri < 0))
176 return (set_errno(EINVAL));
177 pri = (unsigned char)intpri;
178 error = msgio(fdes, ctl, data, &rv, FWRITE, &pri, &flags);
179 if (error != 0)
180 return (set_errno(error));
181 return (rv);
185 * Common code for getmsg and putmsg calls: check permissions,
186 * copy in args, do preliminary setup, and switch to
187 * appropriate stream routine.
189 static int
190 msgio(int fdes, struct strbuf *ctl, struct strbuf *data, int *rval,
191 int mode, unsigned char *prip, int *flagsp)
193 file_t *fp;
194 vnode_t *vp;
195 struct strbuf msgctl, msgdata;
196 int error;
197 int flag;
198 klwp_t *lwp = ttolwp(curthread);
199 rval_t rv;
201 if ((fp = getf(fdes)) == NULL)
202 return (EBADF);
203 if ((fp->f_flag & mode) == 0) {
204 releasef(fdes);
205 return (EBADF);
207 vp = fp->f_vnode;
208 if (vp->v_type == VFIFO) {
209 if (vp->v_stream) {
211 * must use sd_vnode, could be named pipe
213 (void) fifo_vfastoff(vp->v_stream->sd_vnode);
214 } else {
215 releasef(fdes);
216 return (ENOSTR);
218 } else if ((vp->v_type != VCHR && vp->v_type != VSOCK) ||
219 vp->v_stream == NULL) {
220 releasef(fdes);
221 return (ENOSTR);
223 if ((ctl != NULL) &&
224 copyin(ctl, &msgctl, sizeof (struct strbuf))) {
225 releasef(fdes);
226 return (EFAULT);
228 if ((data != NULL) &&
229 copyin(data, &msgdata, sizeof (struct strbuf))) {
230 releasef(fdes);
231 return (EFAULT);
234 if (mode == FREAD) {
235 if (ctl == NULL)
236 msgctl.maxlen = -1;
237 if (data == NULL)
238 msgdata.maxlen = -1;
239 flag = fp->f_flag;
240 rv.r_val1 = 0;
241 if (vp->v_type == VSOCK) {
242 error = sock_getmsg(vp, &msgctl, &msgdata, prip,
243 flagsp, flag, &rv);
244 } else {
245 error = strgetmsg(vp, &msgctl, &msgdata, prip,
246 flagsp, flag, &rv);
248 *rval = rv.r_val1;
249 if (error != 0) {
250 releasef(fdes);
251 return (error);
253 if (lwp != NULL)
254 lwp->lwp_ru.msgrcv++;
255 if (((ctl != NULL) &&
256 copyout(&msgctl, ctl, sizeof (struct strbuf))) ||
257 ((data != NULL) &&
258 copyout(&msgdata, data, sizeof (struct strbuf)))) {
259 releasef(fdes);
260 return (EFAULT);
262 releasef(fdes);
263 return (0);
267 * FWRITE case
269 if (ctl == NULL)
270 msgctl.len = -1;
271 if (data == NULL)
272 msgdata.len = -1;
273 flag = fp->f_flag;
274 if (vp->v_type == VSOCK) {
275 error = sock_putmsg(vp, &msgctl, &msgdata, *prip, *flagsp,
276 flag);
277 } else {
278 error = strputmsg(vp, &msgctl, &msgdata, *prip, *flagsp, flag);
280 releasef(fdes);
281 if (error == 0 && lwp != NULL)
282 lwp->lwp_ru.msgsnd++;
283 return (error);
287 #if defined(_LP64) && defined(_SYSCALL32)
289 static int msgio32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data,
290 int *rval, int mode, unsigned char *prip, int *flagsp);
293 getmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t *flagsp)
295 int error;
296 int32_t localflags;
297 int realflags = 0;
298 unsigned char pri = 0;
299 int rv = 0;
302 * Convert between old flags (localflags) and new flags (realflags).
304 if (copyin(flagsp, &localflags, sizeof (*flagsp)))
305 return (set_errno(EFAULT));
306 switch (localflags) {
307 case 0:
308 realflags = MSG_ANY;
309 break;
311 case RS_HIPRI:
312 realflags = MSG_HIPRI;
313 break;
315 default:
316 return (set_errno(EINVAL));
319 if ((error = msgio32(fdes, ctl, data, &rv, FREAD, &pri,
320 &realflags)) == 0) {
322 * massage realflags based on localflags.
324 if (realflags == MSG_HIPRI)
325 localflags = RS_HIPRI;
326 else
327 localflags = 0;
328 if (copyout(&localflags, flagsp, sizeof (*flagsp)))
329 error = EFAULT;
331 if (error != 0)
332 return (set_errno(error));
333 return (rv);
337 putmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t flags)
339 unsigned char pri = 0;
340 int realflags;
341 int error;
342 int rv = 0;
344 switch (flags) {
345 case RS_HIPRI:
346 realflags = MSG_HIPRI;
347 break;
348 case (RS_HIPRI|MSG_XPG4):
349 realflags = MSG_HIPRI|MSG_XPG4;
350 break;
351 case MSG_XPG4:
352 realflags = MSG_BAND|MSG_XPG4;
353 break;
354 case 0:
355 realflags = MSG_BAND;
356 break;
358 default:
359 return (set_errno(EINVAL));
361 error = msgio32(fdes, ctl, data, &rv, FWRITE, &pri, &realflags);
362 if (error != 0)
363 return (set_errno(error));
364 return (rv);
369 getpmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t *prip,
370 int32_t *flagsp)
372 int error;
373 int32_t flags;
374 int32_t intpri;
375 unsigned char pri;
376 int rv = 0;
378 if (copyin(flagsp, &flags, sizeof (*flagsp)))
379 return (set_errno(EFAULT));
380 if (copyin(prip, &intpri, sizeof (intpri)))
381 return (set_errno(EFAULT));
382 if ((intpri > 255) || (intpri < 0))
383 return (set_errno(EINVAL));
384 pri = (unsigned char)intpri;
385 error = msgio32(fdes, ctl, data, &rv, FREAD, &pri, &flags);
386 if (error != 0)
387 return (set_errno(error));
388 if (copyout(&flags, flagsp, sizeof (flags)))
389 return (set_errno(EFAULT));
390 intpri = (int)pri;
391 if (copyout(&intpri, prip, sizeof (intpri)))
392 return (set_errno(EFAULT));
393 return (rv);
397 putpmsg32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int32_t intpri,
398 int32_t flags)
400 unsigned char pri;
401 int rv = 0;
402 int error;
404 if ((intpri > 255) || (intpri < 0))
405 return (set_errno(EINVAL));
406 pri = (unsigned char)intpri;
407 error = msgio32(fdes, ctl, data, &rv, FWRITE, &pri, &flags);
408 if (error != 0)
409 return (set_errno(error));
410 return (rv);
414 * Common code for getmsg and putmsg calls: check permissions,
415 * copy in args, do preliminary setup, and switch to
416 * appropriate stream routine.
418 static int
419 msgio32(int fdes, struct strbuf32 *ctl, struct strbuf32 *data, int *rval,
420 int mode, unsigned char *prip, int *flagsp)
422 file_t *fp;
423 vnode_t *vp;
424 struct strbuf32 msgctl32, msgdata32;
425 struct strbuf msgctl, msgdata;
426 int error;
427 int flag;
428 klwp_t *lwp = ttolwp(curthread);
429 rval_t rv;
431 if ((fp = getf(fdes)) == NULL)
432 return (EBADF);
433 if ((fp->f_flag & mode) == 0) {
434 releasef(fdes);
435 return (EBADF);
437 vp = fp->f_vnode;
438 if (vp->v_type == VFIFO) {
439 if (vp->v_stream) {
441 * must use sd_vnode, could be named pipe
443 (void) fifo_vfastoff(vp->v_stream->sd_vnode);
444 } else {
445 releasef(fdes);
446 return (ENOSTR);
448 } else if ((vp->v_type != VCHR && vp->v_type != VSOCK) ||
449 vp->v_stream == NULL) {
450 releasef(fdes);
451 return (ENOSTR);
453 if (ctl != NULL) {
454 if (copyin(ctl, &msgctl32, sizeof (msgctl32))) {
455 releasef(fdes);
456 return (EFAULT);
458 msgctl.len = msgctl32.len;
459 msgctl.maxlen = msgctl32.maxlen;
460 msgctl.buf = (caddr_t)(uintptr_t)msgctl32.buf;
462 if (data != NULL) {
463 if (copyin(data, &msgdata32, sizeof (msgdata32))) {
464 releasef(fdes);
465 return (EFAULT);
467 msgdata.len = msgdata32.len;
468 msgdata.maxlen = msgdata32.maxlen;
469 msgdata.buf = (caddr_t)(uintptr_t)msgdata32.buf;
472 if (mode == FREAD) {
473 if (ctl == NULL)
474 msgctl.maxlen = -1;
475 if (data == NULL)
476 msgdata.maxlen = -1;
477 flag = fp->f_flag;
478 rv.r_val1 = 0;
479 if (vp->v_type == VSOCK) {
480 error = sock_getmsg(vp, &msgctl, &msgdata, prip,
481 flagsp, flag, &rv);
482 } else {
483 error = strgetmsg(vp, &msgctl, &msgdata, prip,
484 flagsp, flag, &rv);
486 *rval = rv.r_val1;
487 if (error != 0) {
488 releasef(fdes);
489 return (error);
491 if (lwp != NULL)
492 lwp->lwp_ru.msgrcv++;
493 if (ctl != NULL) {
494 /* XX64 - range check */
495 msgctl32.len = msgctl.len;
496 msgctl32.maxlen = msgctl.maxlen;
497 msgctl32.buf = (caddr32_t)(uintptr_t)msgctl.buf;
498 if (copyout(&msgctl32, ctl, sizeof (msgctl32))) {
499 releasef(fdes);
500 return (EFAULT);
503 if (data != NULL) {
504 /* XX64 - range check */
505 msgdata32.len = msgdata.len;
506 msgdata32.maxlen = msgdata.maxlen;
507 msgdata32.buf = (caddr32_t)(uintptr_t)msgdata.buf;
508 if (copyout(&msgdata32, data, sizeof (msgdata32))) {
509 releasef(fdes);
510 return (EFAULT);
513 releasef(fdes);
514 return (0);
518 * FWRITE case
520 if (ctl == NULL)
521 msgctl.len = -1;
522 if (data == NULL)
523 msgdata.len = -1;
524 flag = fp->f_flag;
525 if (vp->v_type == VSOCK) {
526 error = sock_putmsg(vp, &msgctl, &msgdata, *prip, *flagsp,
527 flag);
528 } else {
529 error = strputmsg(vp, &msgctl, &msgdata, *prip, *flagsp, flag);
531 releasef(fdes);
532 if (error == 0 && lwp != NULL)
533 lwp->lwp_ru.msgsnd++;
534 return (error);
537 #endif /* _LP64 && _SYSCALL32 */