124cbf5f8Smckusick /*
227a38ea8Sbostic * Copyright (c) 1982, 1986, 1989, 1993
327a38ea8Sbostic * The Regents of the University of California. All rights reserved.
4342da129Sbostic * (c) UNIX System Laboratories, Inc.
5342da129Sbostic * All or some portions of this file are derived from material licensed
6342da129Sbostic * to the University of California by American Telephone and Telegraph
7342da129Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8342da129Sbostic * the permission of UNIX System Laboratories, Inc.
924cbf5f8Smckusick *
108bdc900fSbostic * %sccs.include.redist.c%
1195d9d7e5Smckusick *
12*00487f8cScgd * @(#)sys_generic.c 8.9 (Berkeley) 02/14/95
1324cbf5f8Smckusick */
14c767fa90Sroot
156e23d7a0Sbostic #include <sys/param.h>
166e23d7a0Sbostic #include <sys/systm.h>
176e23d7a0Sbostic #include <sys/filedesc.h>
186e23d7a0Sbostic #include <sys/ioctl.h>
196e23d7a0Sbostic #include <sys/file.h>
206e23d7a0Sbostic #include <sys/proc.h>
216e23d7a0Sbostic #include <sys/socketvar.h>
226e23d7a0Sbostic #include <sys/uio.h>
236e23d7a0Sbostic #include <sys/kernel.h>
246e23d7a0Sbostic #include <sys/stat.h>
256e23d7a0Sbostic #include <sys/malloc.h>
26a2967617Skarels #ifdef KTRACE
276e23d7a0Sbostic #include <sys/ktrace.h>
28a2967617Skarels #endif
29c767fa90Sroot
30*00487f8cScgd #include <sys/mount.h>
31*00487f8cScgd #include <sys/syscallargs.h>
32*00487f8cScgd
33c767fa90Sroot /*
34c767fa90Sroot * Read system call.
35c767fa90Sroot */
3641982c2cStorek /* ARGSUSED */
37*00487f8cScgd int
read(p,uap,retval)3841982c2cStorek read(p, uap, retval)
3941982c2cStorek struct proc *p;
40*00487f8cScgd register struct read_args /* {
41*00487f8cScgd syscallarg(int) fd;
42*00487f8cScgd syscallarg(char *) buf;
43*00487f8cScgd syscallarg(u_int) nbyte;
44*00487f8cScgd } */ *uap;
45*00487f8cScgd register_t *retval;
4687836a50Smckusick {
4795d9d7e5Smckusick register struct file *fp;
48bcf289b6Smckusick register struct filedesc *fdp = p->p_fd;
495a55292bSroot struct uio auio;
505a55292bSroot struct iovec aiov;
5195d9d7e5Smckusick long cnt, error = 0;
5295d9d7e5Smckusick #ifdef KTRACE
5395d9d7e5Smckusick struct iovec ktriov;
5495d9d7e5Smckusick #endif
55c767fa90Sroot
56*00487f8cScgd if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
57*00487f8cScgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
5895d9d7e5Smckusick (fp->f_flag & FREAD) == 0)
592c51c3e4Skarels return (EBADF);
60*00487f8cScgd aiov.iov_base = (caddr_t)SCARG(uap, buf);
61*00487f8cScgd aiov.iov_len = SCARG(uap, nbyte);
625a55292bSroot auio.uio_iov = &aiov;
635a55292bSroot auio.uio_iovcnt = 1;
64*00487f8cScgd auio.uio_resid = SCARG(uap, nbyte);
6595d9d7e5Smckusick auio.uio_rw = UIO_READ;
6695d9d7e5Smckusick auio.uio_segflg = UIO_USERSPACE;
6737dd6451Smckusick auio.uio_procp = p;
6895d9d7e5Smckusick #ifdef KTRACE
6995d9d7e5Smckusick /*
7095d9d7e5Smckusick * if tracing, save a copy of iovec
7195d9d7e5Smckusick */
7287836a50Smckusick if (KTRPOINT(p, KTR_GENIO))
7395d9d7e5Smckusick ktriov = aiov;
7495d9d7e5Smckusick #endif
75*00487f8cScgd cnt = SCARG(uap, nbyte);
76458b3cedSkarels if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
77458b3cedSkarels if (auio.uio_resid != cnt && (error == ERESTART ||
78458b3cedSkarels error == EINTR || error == EWOULDBLOCK))
79458b3cedSkarels error = 0;
8095d9d7e5Smckusick cnt -= auio.uio_resid;
8195d9d7e5Smckusick #ifdef KTRACE
8287836a50Smckusick if (KTRPOINT(p, KTR_GENIO) && error == 0)
83*00487f8cScgd ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, &ktriov,
84*00487f8cScgd cnt, error);
8595d9d7e5Smckusick #endif
8687836a50Smckusick *retval = cnt;
872c51c3e4Skarels return (error);
88c767fa90Sroot }
89d5ddeb04Sroot
9087836a50Smckusick /*
9187836a50Smckusick * Scatter read system call.
9287836a50Smckusick */
93*00487f8cScgd int
readv(p,uap,retval)9441982c2cStorek readv(p, uap, retval)
9541982c2cStorek struct proc *p;
96*00487f8cScgd register struct readv_args /* {
97*00487f8cScgd syscallarg(int) fd;
98*00487f8cScgd syscallarg(struct iovec *) iovp;
99*00487f8cScgd syscallarg(u_int) iovcnt;
100*00487f8cScgd } */ *uap;
101*00487f8cScgd register_t *retval;
10287836a50Smckusick {
10395d9d7e5Smckusick register struct file *fp;
104bcf289b6Smckusick register struct filedesc *fdp = p->p_fd;
105d5ddeb04Sroot struct uio auio;
10695d9d7e5Smckusick register struct iovec *iov;
1076b756a40Storek struct iovec *needfree;
10895d9d7e5Smckusick struct iovec aiov[UIO_SMALLIOV];
10995d9d7e5Smckusick long i, cnt, error = 0;
11040bd33f9Sbostic u_int iovlen;
11195d9d7e5Smckusick #ifdef KTRACE
11295d9d7e5Smckusick struct iovec *ktriov = NULL;
11395d9d7e5Smckusick #endif
114d5ddeb04Sroot
115*00487f8cScgd if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
116*00487f8cScgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
11795d9d7e5Smckusick (fp->f_flag & FREAD) == 0)
1182c51c3e4Skarels return (EBADF);
11939481ef4Skarels /* note: can't use iovlen until iovcnt is validated */
120*00487f8cScgd iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
121*00487f8cScgd if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
122*00487f8cScgd if (SCARG(uap, iovcnt) > UIO_MAXIOV)
1232c51c3e4Skarels return (EINVAL);
12439481ef4Skarels MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
1256b756a40Storek needfree = iov;
1266b756a40Storek } else {
127a2967617Skarels iov = aiov;
1286b756a40Storek needfree = NULL;
1296b756a40Storek }
130a2967617Skarels auio.uio_iov = iov;
131*00487f8cScgd auio.uio_iovcnt = SCARG(uap, iovcnt);
13295d9d7e5Smckusick auio.uio_rw = UIO_READ;
13395d9d7e5Smckusick auio.uio_segflg = UIO_USERSPACE;
13437dd6451Smckusick auio.uio_procp = p;
135*00487f8cScgd if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
136a2967617Skarels goto done;
13795d9d7e5Smckusick auio.uio_resid = 0;
138*00487f8cScgd for (i = 0; i < SCARG(uap, iovcnt); i++) {
139b3c14c05Smckusick if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
14095d9d7e5Smckusick error = EINVAL;
14195d9d7e5Smckusick goto done;
14295d9d7e5Smckusick }
14395d9d7e5Smckusick auio.uio_resid += iov->iov_len;
14495d9d7e5Smckusick iov++;
14595d9d7e5Smckusick }
14695d9d7e5Smckusick #ifdef KTRACE
14795d9d7e5Smckusick /*
14895d9d7e5Smckusick * if tracing, save a copy of iovec
14995d9d7e5Smckusick */
15087836a50Smckusick if (KTRPOINT(p, KTR_GENIO)) {
15195d9d7e5Smckusick MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
15295d9d7e5Smckusick bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
15395d9d7e5Smckusick }
15495d9d7e5Smckusick #endif
15595d9d7e5Smckusick cnt = auio.uio_resid;
156458b3cedSkarels if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
157458b3cedSkarels if (auio.uio_resid != cnt && (error == ERESTART ||
158458b3cedSkarels error == EINTR || error == EWOULDBLOCK))
159458b3cedSkarels error = 0;
16095d9d7e5Smckusick cnt -= auio.uio_resid;
16195d9d7e5Smckusick #ifdef KTRACE
16295d9d7e5Smckusick if (ktriov != NULL) {
163817fcec3Smarc if (error == 0)
164*00487f8cScgd ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, ktriov,
165ee209021Smckusick cnt, error);
16695d9d7e5Smckusick FREE(ktriov, M_TEMP);
16795d9d7e5Smckusick }
16895d9d7e5Smckusick #endif
16987836a50Smckusick *retval = cnt;
170a2967617Skarels done:
1716b756a40Storek if (needfree)
1726b756a40Storek FREE(needfree, M_IOV);
1732c51c3e4Skarels return (error);
174c767fa90Sroot }
175c767fa90Sroot
176c767fa90Sroot /*
177c767fa90Sroot * Write system call
178c767fa90Sroot */
179*00487f8cScgd int
write(p,uap,retval)18041982c2cStorek write(p, uap, retval)
18141982c2cStorek struct proc *p;
182*00487f8cScgd register struct write_args /* {
183*00487f8cScgd syscallarg(int) fd;
184*00487f8cScgd syscallarg(char *) buf;
185*00487f8cScgd syscallarg(u_int) nbyte;
186*00487f8cScgd } */ *uap;
187*00487f8cScgd register_t *retval;
18887836a50Smckusick {
18995d9d7e5Smckusick register struct file *fp;
190bcf289b6Smckusick register struct filedesc *fdp = p->p_fd;
191d5ddeb04Sroot struct uio auio;
192d5ddeb04Sroot struct iovec aiov;
19395d9d7e5Smckusick long cnt, error = 0;
19495d9d7e5Smckusick #ifdef KTRACE
19595d9d7e5Smckusick struct iovec ktriov;
19695d9d7e5Smckusick #endif
197c767fa90Sroot
198*00487f8cScgd if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
199*00487f8cScgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
20095d9d7e5Smckusick (fp->f_flag & FWRITE) == 0)
2012c51c3e4Skarels return (EBADF);
202*00487f8cScgd aiov.iov_base = (caddr_t)SCARG(uap, buf);
203*00487f8cScgd aiov.iov_len = SCARG(uap, nbyte);
204d5ddeb04Sroot auio.uio_iov = &aiov;
205d5ddeb04Sroot auio.uio_iovcnt = 1;
206*00487f8cScgd auio.uio_resid = SCARG(uap, nbyte);
20795d9d7e5Smckusick auio.uio_rw = UIO_WRITE;
20895d9d7e5Smckusick auio.uio_segflg = UIO_USERSPACE;
20937dd6451Smckusick auio.uio_procp = p;
21095d9d7e5Smckusick #ifdef KTRACE
21195d9d7e5Smckusick /*
21295d9d7e5Smckusick * if tracing, save a copy of iovec
21395d9d7e5Smckusick */
21487836a50Smckusick if (KTRPOINT(p, KTR_GENIO))
21595d9d7e5Smckusick ktriov = aiov;
21695d9d7e5Smckusick #endif
217*00487f8cScgd cnt = SCARG(uap, nbyte);
218458b3cedSkarels if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
219458b3cedSkarels if (auio.uio_resid != cnt && (error == ERESTART ||
220458b3cedSkarels error == EINTR || error == EWOULDBLOCK))
221458b3cedSkarels error = 0;
222458b3cedSkarels if (error == EPIPE)
22387836a50Smckusick psignal(p, SIGPIPE);
22495d9d7e5Smckusick }
22595d9d7e5Smckusick cnt -= auio.uio_resid;
22695d9d7e5Smckusick #ifdef KTRACE
22787836a50Smckusick if (KTRPOINT(p, KTR_GENIO) && error == 0)
228*00487f8cScgd ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
229ee209021Smckusick &ktriov, cnt, error);
23095d9d7e5Smckusick #endif
23187836a50Smckusick *retval = cnt;
2322c51c3e4Skarels return (error);
233828d9165Sroot }
234828d9165Sroot
23587836a50Smckusick /*
23687836a50Smckusick * Gather write system call
23787836a50Smckusick */
238*00487f8cScgd int
writev(p,uap,retval)23941982c2cStorek writev(p, uap, retval)
24041982c2cStorek struct proc *p;
241*00487f8cScgd register struct writev_args /* {
242*00487f8cScgd syscallarg(int) fd;
243*00487f8cScgd syscallarg(struct iovec *) iovp;
244*00487f8cScgd syscallarg(u_int) iovcnt;
245*00487f8cScgd } */ *uap;
246*00487f8cScgd register_t *retval;
24787836a50Smckusick {
248d5ddeb04Sroot register struct file *fp;
249bcf289b6Smckusick register struct filedesc *fdp = p->p_fd;
25095d9d7e5Smckusick struct uio auio;
251d5ddeb04Sroot register struct iovec *iov;
2526b756a40Storek struct iovec *needfree;
25395d9d7e5Smckusick struct iovec aiov[UIO_SMALLIOV];
25495d9d7e5Smckusick long i, cnt, error = 0;
25540bd33f9Sbostic u_int iovlen;
256a2967617Skarels #ifdef KTRACE
257a2967617Skarels struct iovec *ktriov = NULL;
258a2967617Skarels #endif
259a2967617Skarels
260*00487f8cScgd if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
261*00487f8cScgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
26295d9d7e5Smckusick (fp->f_flag & FWRITE) == 0)
2632c51c3e4Skarels return (EBADF);
26439481ef4Skarels /* note: can't use iovlen until iovcnt is validated */
265*00487f8cScgd iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
266*00487f8cScgd if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
267*00487f8cScgd if (SCARG(uap, iovcnt) > UIO_MAXIOV)
2682c51c3e4Skarels return (EINVAL);
26939481ef4Skarels MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
2706b756a40Storek needfree = iov;
2716b756a40Storek } else {
27295d9d7e5Smckusick iov = aiov;
2736b756a40Storek needfree = NULL;
2746b756a40Storek }
27595d9d7e5Smckusick auio.uio_iov = iov;
276*00487f8cScgd auio.uio_iovcnt = SCARG(uap, iovcnt);
27795d9d7e5Smckusick auio.uio_rw = UIO_WRITE;
27895d9d7e5Smckusick auio.uio_segflg = UIO_USERSPACE;
27937dd6451Smckusick auio.uio_procp = p;
280*00487f8cScgd if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
28195d9d7e5Smckusick goto done;
28295d9d7e5Smckusick auio.uio_resid = 0;
283*00487f8cScgd for (i = 0; i < SCARG(uap, iovcnt); i++) {
284b3c14c05Smckusick if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
28595d9d7e5Smckusick error = EINVAL;
28695d9d7e5Smckusick goto done;
287d5ddeb04Sroot }
28895d9d7e5Smckusick auio.uio_resid += iov->iov_len;
28969d1c9ebSsam iov++;
290d5ddeb04Sroot }
291a2967617Skarels #ifdef KTRACE
29295d9d7e5Smckusick /*
29395d9d7e5Smckusick * if tracing, save a copy of iovec
29495d9d7e5Smckusick */
29587836a50Smckusick if (KTRPOINT(p, KTR_GENIO)) {
296a2967617Skarels MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
29795d9d7e5Smckusick bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
298a2967617Skarels }
299a2967617Skarels #endif
30095d9d7e5Smckusick cnt = auio.uio_resid;
301458b3cedSkarels if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
302458b3cedSkarels if (auio.uio_resid != cnt && (error == ERESTART ||
303458b3cedSkarels error == EINTR || error == EWOULDBLOCK))
304458b3cedSkarels error = 0;
305458b3cedSkarels if (error == EPIPE)
30687836a50Smckusick psignal(p, SIGPIPE);
307b0c95adcSmckusick }
30895d9d7e5Smckusick cnt -= auio.uio_resid;
309a2967617Skarels #ifdef KTRACE
310a2967617Skarels if (ktriov != NULL) {
311817fcec3Smarc if (error == 0)
312*00487f8cScgd ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
313ee209021Smckusick ktriov, cnt, error);
314a2967617Skarels FREE(ktriov, M_TEMP);
315a2967617Skarels }
316a2967617Skarels #endif
31787836a50Smckusick *retval = cnt;
31895d9d7e5Smckusick done:
3196b756a40Storek if (needfree)
3206b756a40Storek FREE(needfree, M_IOV);
3212c51c3e4Skarels return (error);
322d5ddeb04Sroot }
323d5ddeb04Sroot
324c767fa90Sroot /*
325c767fa90Sroot * Ioctl system call
326c767fa90Sroot */
32741982c2cStorek /* ARGSUSED */
328*00487f8cScgd int
ioctl(p,uap,retval)32941982c2cStorek ioctl(p, uap, retval)
33041982c2cStorek struct proc *p;
331*00487f8cScgd register struct ioctl_args /* {
332*00487f8cScgd syscallarg(int) fd;
333*00487f8cScgd syscallarg(u_long) com;
334*00487f8cScgd syscallarg(caddr_t) data;
335*00487f8cScgd } */ *uap;
336*00487f8cScgd register_t *retval;
33787836a50Smckusick {
33887836a50Smckusick register struct file *fp;
3397585af12Sbostic register struct filedesc *fdp;
340*00487f8cScgd register u_long com;
341*00487f8cScgd register int error;
342d5ddeb04Sroot register u_int size;
3437585af12Sbostic caddr_t data, memp;
3447585af12Sbostic int tmp;
345b8805943Skarels #define STK_PARAMS 128
3460edb0603Skarels char stkbuf[STK_PARAMS];
347c767fa90Sroot
3487585af12Sbostic fdp = p->p_fd;
349*00487f8cScgd if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
350*00487f8cScgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
3512c51c3e4Skarels return (EBADF);
3527585af12Sbostic
353458b3cedSkarels if ((fp->f_flag & (FREAD | FWRITE)) == 0)
3542c51c3e4Skarels return (EBADF);
355506962a6Ssam
356*00487f8cScgd switch (com = SCARG(uap, com)) {
3577585af12Sbostic case FIONCLEX:
358*00487f8cScgd fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE;
3592c51c3e4Skarels return (0);
3607585af12Sbostic case FIOCLEX:
361*00487f8cScgd fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
3627585af12Sbostic return (0);
363c767fa90Sroot }
364506962a6Ssam
365506962a6Ssam /*
3667585af12Sbostic * Interpret high order word to find amount of data to be
3677585af12Sbostic * copied to/from the user's address space.
368506962a6Ssam */
369b8805943Skarels size = IOCPARM_LEN(com);
370458b3cedSkarels if (size > IOCPARM_MAX)
3712c51c3e4Skarels return (ENOTTY);
3727585af12Sbostic memp = NULL;
3730edb0603Skarels if (size > sizeof (stkbuf)) {
374bd7e0dabSmckusick memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
375faf0051dSmckusick data = memp;
3767585af12Sbostic } else
3777585af12Sbostic data = stkbuf;
3785be745e3Ssam if (com&IOC_IN) {
3795be745e3Ssam if (size) {
380*00487f8cScgd error = copyin(SCARG(uap, data), data, (u_int)size);
381458b3cedSkarels if (error) {
382faf0051dSmckusick if (memp)
383faf0051dSmckusick free(memp, M_IOCTLOPS);
3842c51c3e4Skarels return (error);
385faf0051dSmckusick }
386506962a6Ssam } else
387*00487f8cScgd *(caddr_t *)data = SCARG(uap, data);
3885be745e3Ssam } else if ((com&IOC_OUT) && size)
389506962a6Ssam /*
390a2967617Skarels * Zero the buffer so the user always
391a2967617Skarels * gets back something deterministic.
392506962a6Ssam */
393b8805943Skarels bzero(data, size);
3942a73ef0fSsam else if (com&IOC_VOID)
395*00487f8cScgd *(caddr_t *)data = SCARG(uap, data);
396506962a6Ssam
397f655bc81Ssam switch (com) {
398506962a6Ssam
399f655bc81Ssam case FIONBIO:
40037dd6451Smckusick if (tmp = *(int *)data)
40117cfc8d6Smckusick fp->f_flag |= FNONBLOCK;
40237dd6451Smckusick else
40317cfc8d6Smckusick fp->f_flag &= ~FNONBLOCK;
40437dd6451Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
405b8805943Skarels break;
406f655bc81Ssam
407f655bc81Ssam case FIOASYNC:
40837dd6451Smckusick if (tmp = *(int *)data)
40937dd6451Smckusick fp->f_flag |= FASYNC;
41037dd6451Smckusick else
41137dd6451Smckusick fp->f_flag &= ~FASYNC;
41237dd6451Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
413b8805943Skarels break;
414f655bc81Ssam
415f655bc81Ssam case FIOSETOWN:
41637dd6451Smckusick tmp = *(int *)data;
41737dd6451Smckusick if (fp->f_type == DTYPE_SOCKET) {
41837dd6451Smckusick ((struct socket *)fp->f_data)->so_pgid = tmp;
41937dd6451Smckusick error = 0;
42037dd6451Smckusick break;
42137dd6451Smckusick }
42237dd6451Smckusick if (tmp <= 0) {
42337dd6451Smckusick tmp = -tmp;
42437dd6451Smckusick } else {
42537dd6451Smckusick struct proc *p1 = pfind(tmp);
42637dd6451Smckusick if (p1 == 0) {
42737dd6451Smckusick error = ESRCH;
42837dd6451Smckusick break;
42937dd6451Smckusick }
43037dd6451Smckusick tmp = p1->p_pgrp->pg_id;
43137dd6451Smckusick }
43237dd6451Smckusick error = (*fp->f_ops->fo_ioctl)
433*00487f8cScgd (fp, TIOCSPGRP, (caddr_t)&tmp, p);
434b8805943Skarels break;
435f655bc81Ssam
436f655bc81Ssam case FIOGETOWN:
43737dd6451Smckusick if (fp->f_type == DTYPE_SOCKET) {
43837dd6451Smckusick error = 0;
43937dd6451Smckusick *(int *)data = ((struct socket *)fp->f_data)->so_pgid;
440b8805943Skarels break;
44137dd6451Smckusick }
442*00487f8cScgd error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p);
44337dd6451Smckusick *(int *)data = -*(int *)data;
44437dd6451Smckusick break;
44537dd6451Smckusick
446b8805943Skarels default:
4470b0833e3Skarels error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
448506962a6Ssam /*
449506962a6Ssam * Copy any data to user, size was
450506962a6Ssam * already set and checked above.
451506962a6Ssam */
452458b3cedSkarels if (error == 0 && (com&IOC_OUT) && size)
453*00487f8cScgd error = copyout(data, SCARG(uap, data), (u_int)size);
454b8805943Skarels break;
455b8805943Skarels }
456faf0051dSmckusick if (memp)
457faf0051dSmckusick free(memp, M_IOCTLOPS);
4582c51c3e4Skarels return (error);
459c767fa90Sroot }
460c767fa90Sroot
461c4490912Skarels int selwait, nselcoll;
462be7d2a0dSkarels
463be7d2a0dSkarels /*
464f655bc81Ssam * Select system call.
465c767fa90Sroot */
466*00487f8cScgd int
select(p,uap,retval)46741982c2cStorek select(p, uap, retval)
46841982c2cStorek register struct proc *p;
469*00487f8cScgd register struct select_args /* {
470*00487f8cScgd syscallarg(u_int) nd;
471*00487f8cScgd syscallarg(fd_set *) in;
472*00487f8cScgd syscallarg(fd_set *) ou;
473*00487f8cScgd syscallarg(fd_set *) ex;
474*00487f8cScgd syscallarg(struct timeval *) tv;
475*00487f8cScgd } */ *uap;
476*00487f8cScgd register_t *retval;
47787836a50Smckusick {
478ac0f205eSkarels fd_set ibits[3], obits[3];
479f655bc81Ssam struct timeval atv;
480a30ab6f6Smckusick int s, ncoll, error, timo = 0;
4817ac4a081Smckusick u_int ni;
482f655bc81Ssam
483b87e53fbSkarels bzero((caddr_t)ibits, sizeof(ibits));
484b87e53fbSkarels bzero((caddr_t)obits, sizeof(obits));
485*00487f8cScgd if (SCARG(uap, nd) > FD_SETSIZE)
4867ac4a081Smckusick return (EINVAL);
487*00487f8cScgd if (SCARG(uap, nd) > p->p_fd->fd_nfiles) {
488*00487f8cScgd /* forgiving; slightly wrong */
489*00487f8cScgd SCARG(uap, nd) = p->p_fd->fd_nfiles;
490*00487f8cScgd }
491*00487f8cScgd ni = howmany(SCARG(uap, nd), NFDBITS) * sizeof(fd_mask);
492f655bc81Ssam
493f655bc81Ssam #define getbits(name, x) \
494*00487f8cScgd if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, name), \
495*00487f8cScgd (caddr_t)&ibits[x], ni))) \
4967ac4a081Smckusick goto done;
497f655bc81Ssam getbits(in, 0);
498f655bc81Ssam getbits(ou, 1);
499f655bc81Ssam getbits(ex, 2);
500f655bc81Ssam #undef getbits
501f655bc81Ssam
502*00487f8cScgd if (SCARG(uap, tv)) {
503*00487f8cScgd error = copyin((caddr_t)SCARG(uap, tv), (caddr_t)&atv,
504f655bc81Ssam sizeof (atv));
505458b3cedSkarels if (error)
506f655bc81Ssam goto done;
507f655bc81Ssam if (itimerfix(&atv)) {
508458b3cedSkarels error = EINVAL;
509f655bc81Ssam goto done;
510f655bc81Ssam }
51145922107Storek s = splclock();
51245922107Storek timevaladd(&atv, (struct timeval *)&time);
513692e3f19Sbostic splx(s);
514a30ab6f6Smckusick }
515f655bc81Ssam retry:
516f655bc81Ssam ncoll = nselcoll;
51799887da3Sbostic p->p_flag |= P_SELECT;
518*00487f8cScgd error = selscan(p, ibits, obits, SCARG(uap, nd), retval);
51987836a50Smckusick if (error || *retval)
520f655bc81Ssam goto done;
521e1ad4c2bSkarels s = splhigh();
522*00487f8cScgd if (SCARG(uap, tv)) {
523860e4a7aSmckusick if (timercmp(&time, &atv, >=)) {
524f655bc81Ssam splx(s);
525f655bc81Ssam goto done;
526f655bc81Ssam }
527860e4a7aSmckusick /*
528a30ab6f6Smckusick * If poll wait was tiny, this could be zero; we will
529a30ab6f6Smckusick * have to round it up to avoid sleeping forever. If
530a30ab6f6Smckusick * we retry below, the timercmp above will get us out.
531a30ab6f6Smckusick * Note that if wait was 0, the timercmp will prevent
532a30ab6f6Smckusick * us from getting here the first time.
533860e4a7aSmckusick */
534a30ab6f6Smckusick timo = hzto(&atv);
535a30ab6f6Smckusick if (timo == 0)
536860e4a7aSmckusick timo = 1;
537860e4a7aSmckusick }
53899887da3Sbostic if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
539f655bc81Ssam splx(s);
540f655bc81Ssam goto retry;
541f655bc81Ssam }
54299887da3Sbostic p->p_flag &= ~P_SELECT;
543458b3cedSkarels error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
544f655bc81Ssam splx(s);
545458b3cedSkarels if (error == 0)
546f655bc81Ssam goto retry;
547f655bc81Ssam done:
54899887da3Sbostic p->p_flag &= ~P_SELECT;
549458b3cedSkarels /* select is not restarted after signals... */
550458b3cedSkarels if (error == ERESTART)
551458b3cedSkarels error = EINTR;
552458b3cedSkarels if (error == EWOULDBLOCK)
553458b3cedSkarels error = 0;
554f655bc81Ssam #define putbits(name, x) \
555*00487f8cScgd if (SCARG(uap, name) && (error2 = copyout((caddr_t)&obits[x], \
556*00487f8cScgd (caddr_t)SCARG(uap, name), ni))) \
5577ac4a081Smckusick error = error2;
558458b3cedSkarels if (error == 0) {
5597ac4a081Smckusick int error2;
5607ac4a081Smckusick
561f655bc81Ssam putbits(in, 0);
562f655bc81Ssam putbits(ou, 1);
563f655bc81Ssam putbits(ex, 2);
564f655bc81Ssam #undef putbits
565f655bc81Ssam }
5662c51c3e4Skarels return (error);
567cee5ee1eSkarels }
568f655bc81Ssam
569*00487f8cScgd int
selscan(p,ibits,obits,nfd,retval)5700b0833e3Skarels selscan(p, ibits, obits, nfd, retval)
5710b0833e3Skarels struct proc *p;
572ac0f205eSkarels fd_set *ibits, *obits;
573*00487f8cScgd int nfd;
574*00487f8cScgd register_t *retval;
575f655bc81Ssam {
5760b0833e3Skarels register struct filedesc *fdp = p->p_fd;
5776b756a40Storek register int msk, i, j, fd;
578ac0f205eSkarels register fd_mask bits;
579f655bc81Ssam struct file *fp;
5806b756a40Storek int n = 0;
5816b756a40Storek static int flag[3] = { FREAD, FWRITE, 0 };
582f655bc81Ssam
5836b756a40Storek for (msk = 0; msk < 3; msk++) {
584ac0f205eSkarels for (i = 0; i < nfd; i += NFDBITS) {
5856b756a40Storek bits = ibits[msk].fds_bits[i/NFDBITS];
5866b756a40Storek while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
587be7d2a0dSkarels bits &= ~(1 << j);
5886b756a40Storek fp = fdp->fd_ofiles[fd];
5896b756a40Storek if (fp == NULL)
5906b756a40Storek return (EBADF);
5916b756a40Storek if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
5926b756a40Storek FD_SET(fd, &obits[msk]);
593f655bc81Ssam n++;
594f655bc81Ssam }
595f655bc81Ssam }
596f655bc81Ssam }
597be7d2a0dSkarels }
59887836a50Smckusick *retval = n;
5996b756a40Storek return (0);
600f655bc81Ssam }
601f655bc81Ssam
602c767fa90Sroot /*ARGSUSED*/
603*00487f8cScgd int
seltrue(dev,flag,p)6040b0833e3Skarels seltrue(dev, flag, p)
605f655bc81Ssam dev_t dev;
606f655bc81Ssam int flag;
6070b0833e3Skarels struct proc *p;
608c767fa90Sroot {
609c767fa90Sroot
610f655bc81Ssam return (1);
611c767fa90Sroot }
61272762883Sroot
6138731788dSmckusick /*
6148731788dSmckusick * Record a select request.
6158731788dSmckusick */
6168731788dSmckusick void
selrecord(selector,sip)6178731788dSmckusick selrecord(selector, sip)
6188731788dSmckusick struct proc *selector;
6198731788dSmckusick struct selinfo *sip;
62072762883Sroot {
6218731788dSmckusick struct proc *p;
6228731788dSmckusick pid_t mypid;
62372762883Sroot
6248731788dSmckusick mypid = selector->p_pid;
6258731788dSmckusick if (sip->si_pid == mypid)
6268731788dSmckusick return;
6278731788dSmckusick if (sip->si_pid && (p = pfind(sip->si_pid)) &&
6288731788dSmckusick p->p_wchan == (caddr_t)&selwait)
6298731788dSmckusick sip->si_flags |= SI_COLL;
6308731788dSmckusick else
6318731788dSmckusick sip->si_pid = mypid;
6328731788dSmckusick }
6338731788dSmckusick
6348731788dSmckusick /*
6358731788dSmckusick * Do a wakeup when a selectable event occurs.
6368731788dSmckusick */
6378731788dSmckusick void
selwakeup(sip)6388731788dSmckusick selwakeup(sip)
6398731788dSmckusick register struct selinfo *sip;
6408731788dSmckusick {
6418731788dSmckusick register struct proc *p;
6428731788dSmckusick int s;
6438731788dSmckusick
6448731788dSmckusick if (sip->si_pid == 0)
6458731788dSmckusick return;
6468731788dSmckusick if (sip->si_flags & SI_COLL) {
647f655bc81Ssam nselcoll++;
6488731788dSmckusick sip->si_flags &= ~SI_COLL;
649f655bc81Ssam wakeup((caddr_t)&selwait);
650f655bc81Ssam }
651774d6900Smckusick p = pfind(sip->si_pid);
6528731788dSmckusick sip->si_pid = 0;
653774d6900Smckusick if (p != NULL) {
6548731788dSmckusick s = splhigh();
655bc41b6b9Skarels if (p->p_wchan == (caddr_t)&selwait) {
656bc41b6b9Skarels if (p->p_stat == SSLEEP)
6577585af12Sbostic setrunnable(p);
658bc41b6b9Skarels else
659bc41b6b9Skarels unsleep(p);
66099887da3Sbostic } else if (p->p_flag & P_SELECT)
66199887da3Sbostic p->p_flag &= ~P_SELECT;
662f655bc81Ssam splx(s);
663f655bc81Ssam }
66472762883Sroot }
665