ioctl/open return values
[unix-history] / usr / src / sys / kern / sys_generic.c
CommitLineData
840510a3 1/* sys_generic.c 5.16 82/10/13 */
ffe28cfe
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/dir.h"
6#include "../h/user.h"
7#include "../h/tty.h"
8#include "../h/file.h"
9#include "../h/inode.h"
10#include "../h/buf.h"
11#include "../h/proc.h"
ffe28cfe
BJ
12#include "../h/conf.h"
13#include "../h/socket.h"
14#include "../h/socketvar.h"
ffe28cfe 15#include "../h/fs.h"
cabdaec4
RE
16#ifdef MUSH
17#include "../h/quota.h"
18#include "../h/share.h"
19#else
20#define CHARGE(nothing)
21#endif
4147b3f6 22#include "../h/descrip.h"
6fd40cea 23#include "../h/uio.h"
ffe28cfe
BJ
24
25/*
26 * Read system call.
27 */
28read()
29{
ffe28cfe
BJ
30 register struct a {
31 int fdes;
32 char *cbuf;
33 unsigned count;
b9429893 34 } *uap = (struct a *)u.u_ap;
32a43ee2
BJ
35 struct uio auio;
36 struct iovec aiov;
ffe28cfe 37
32a43ee2
BJ
38 aiov.iov_base = (caddr_t)uap->cbuf;
39 aiov.iov_len = uap->count;
40 auio.uio_iov = &aiov;
41 auio.uio_iovcnt = 1;
b9429893
BJ
42 rwuio(&auio, UIO_READ);
43}
44
45readv()
46{
47 register struct a {
48 int fdes;
49 struct iovec *iovp;
50 int iovcnt;
51 } *uap = (struct a *)u.u_ap;
52 struct uio auio;
53 struct iovec aiov[16]; /* XXX */
54
55 if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
56 u.u_error = EINVAL;
57 return;
58 }
59 auio.uio_iov = aiov;
60 auio.uio_iovcnt = uap->iovcnt;
61 if (copyin((caddr_t)uap->iovp, (caddr_t)aiov,
62 (unsigned)(uap->iovcnt * sizeof (struct iovec)))) {
63 u.u_error = EFAULT;
64 return;
ffe28cfe 65 }
b9429893 66 rwuio(&auio, UIO_READ);
ffe28cfe
BJ
67}
68
69/*
70 * Write system call
71 */
72write()
73{
ffe28cfe
BJ
74 register struct a {
75 int fdes;
76 char *cbuf;
b9429893
BJ
77 int count;
78 } *uap = (struct a *)u.u_ap;
79 struct uio auio;
80 struct iovec aiov;
ffe28cfe 81
b9429893
BJ
82 auio.uio_iov = &aiov;
83 auio.uio_iovcnt = 1;
84 aiov.iov_base = uap->cbuf;
85 aiov.iov_len = uap->count;
86 rwuio(&auio, UIO_WRITE);
87}
88
89writev()
90{
91 register struct a {
92 int fdes;
93 struct iovec *iovp;
94 int iovcnt;
95 } *uap = (struct a *)u.u_ap;
96 struct uio auio;
97 struct iovec aiov[16]; /* XXX */
98
99 if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
ffe28cfe
BJ
100 u.u_error = EINVAL;
101 return;
102 }
b9429893
BJ
103 auio.uio_iov = aiov;
104 auio.uio_iovcnt = uap->iovcnt;
105 if (copyin((caddr_t)uap->iovp, (caddr_t)aiov,
106 (unsigned)(uap->iovcnt * sizeof (struct iovec)))) {
107 u.u_error = EFAULT;
108 return;
109 }
110 rwuio(&auio, UIO_WRITE);
111}
112
113rwuio(uio, rw)
114 register struct uio *uio;
115 enum uio_rw rw;
116{
117 struct a {
118 int fdes;
119 };
120 register struct file *fp;
121 register struct iovec *iov;
122 register struct inode *ip;
123 int i, count;
124
125 GETF(fp, ((struct a *)u.u_ap)->fdes);
126 if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
ffe28cfe
BJ
127 u.u_error = EBADF;
128 return;
129 }
b9429893
BJ
130 uio->uio_resid = 0;
131 uio->uio_segflg = 0;
132 iov = uio->uio_iov;
133 for (i = 0; i < uio->uio_iovcnt; i++) {
134 if (iov->iov_len < 0) {
135 u.u_error = EINVAL;
136 return;
137 }
138 uio->uio_resid += iov->iov_len;
139 if (uio->uio_resid < 0) {
140 u.u_error = EINVAL;
141 return;
142 }
143 }
144 count = uio->uio_resid;
eb5786ea 145 if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) {
b9429893 146 if (uio->uio_resid == count)
ffe28cfe 147 u.u_eosys = RESTARTSYS;
b9429893
BJ
148 } else if (fp->f_type == DTYPE_SOCKET) {
149 int sosend(), soreceive();
150 u.u_error =
151 (*(rw==UIO_READ?soreceive:sosend))
1e84a0b3 152 (fp->f_socket, (struct sockaddr *)0, uio, 0);
b9429893 153 } else {
ffe28cfe 154 ip = fp->f_inode;
b9429893 155 uio->uio_offset = fp->f_offset;
ffe28cfe 156 if ((ip->i_mode&IFMT) == IFREG) {
1e84a0b3 157 ILOCK(ip);
b9429893 158 u.u_error = rwip(ip, uio, rw);
1e84a0b3 159 IUNLOCK(ip);
ffe28cfe 160 } else
b9429893
BJ
161 u.u_error = rwip(ip, uio, rw);
162 fp->f_offset += count - uio->uio_resid;
ffe28cfe 163 }
b9429893 164 u.u_r.r_val1 = count - uio->uio_resid;
ffe28cfe
BJ
165}
166
b9429893
BJ
167rdwri(rw, ip, base, len, offset, segflg, aresid)
168 struct inode *ip;
169 caddr_t base;
170 int len, offset, segflg;
171 int *aresid;
172 enum uio_rw rw;
173{
174 struct uio auio;
175 struct iovec aiov;
176 int error;
177
178 auio.uio_iov = &aiov;
179 auio.uio_iovcnt = 1;
180 aiov.iov_base = base;
181 aiov.iov_len = len;
182 auio.uio_resid = len;
183 auio.uio_offset = offset;
184 auio.uio_segflg = segflg;
185 error = rwip(ip, &auio, rw);
186 if (aresid)
187 *aresid = auio.uio_resid;
188 else
189 if (auio.uio_resid)
190 error = EIO;
191 return (error);
192}
193
194rwip(ip, uio, rw)
195 register struct inode *ip;
196 register struct uio *uio;
197 enum uio_rw rw;
4147b3f6 198{
b9429893
BJ
199 dev_t dev = (dev_t)ip->i_rdev;
200 struct buf *bp;
201 struct fs *fs;
202 daddr_t lbn, bn;
203 register int on, type;
204 register unsigned n;
205 int size;
206 long bsize;
207 extern int mem_no;
208 int error = 0;
4147b3f6 209
b9429893
BJ
210 if (rw != UIO_READ && rw != UIO_WRITE)
211 panic("rwip");
212 if (uio->uio_offset < 0 &&
213 ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev)))
214 return (EINVAL); if (rw == UIO_READ)
215 ip->i_flag |= IACC;
216 type = ip->i_mode&IFMT;
217 if (type == IFCHR) {
218#ifdef QUOTA
219 register c = uio->uio_resid;
220#endif
221 if (rw == UIO_READ)
840510a3 222 u.u_error = (*cdevsw[major(dev)].d_read)(dev, uio);
b9429893
BJ
223 else {
224 ip->i_flag |= IUPD|ICHG;
840510a3 225 u.u_error = (*cdevsw[major(dev)].d_write)(dev, uio);
b9429893
BJ
226 }
227 CHARGE(sc_tio * (c - uio->uio_resid));
228 return (u.u_error);
229 }
230 if (rw == UIO_WRITE && type == IFREG &&
d1ccd44e
BJ
231 uio->uio_offset + uio->uio_resid >
232 u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
b9429893
BJ
233 psignal(u.u_procp, SIGXFSZ);
234 return (EMFILE);
235 }
236 if (type != IFBLK) {
237 dev = ip->i_dev;
238 fs = ip->i_fs;
239 bsize = fs->fs_bsize;
240 } else
241 bsize = BLKDEV_IOSIZE;
242 do {
243 lbn = uio->uio_offset / bsize;
244 on = uio->uio_offset % bsize;
245 n = MIN((unsigned)(bsize - on), uio->uio_resid);
246 if (type != IFBLK) {
247 if (rw == UIO_READ) {
248 int diff = ip->i_size - uio->uio_offset;
249 if (diff <= 0)
250 return (0);
251 if (diff < n)
252 n = diff;
253 }
254 bn = fsbtodb(fs,
255 bmap(ip, lbn, rw == UIO_WRITE ? B_WRITE: B_READ, (int)(on+n)));
256 if (u.u_error || rw == UIO_WRITE && (long)bn<0)
257 return (u.u_error);
258 if (rw == UIO_WRITE && uio->uio_offset + n > ip->i_size &&
259 (type == IFDIR || type == IFREG || type == IFLNK))
260 ip->i_size = uio->uio_offset + n;
261 size = blksize(fs, ip, lbn);
262 } else {
263 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
264 rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
265 rasize = size = bsize;
266 }
267 if (rw == UIO_READ) {
268 if ((long)bn<0) {
269 bp = geteblk(size);
270 clrbuf(bp);
271 } else if (ip->i_lastr + 1 == lbn)
272 bp = breada(dev, bn, size, rablock, rasize);
273 else
274 bp = bread(dev, bn, size);
275 ip->i_lastr = lbn;
276 } else {
277 int i, count;
278
279 count = howmany(size, DEV_BSIZE);
280 for (i = 0; i < count; i += CLSIZE)
281 if (mfind(dev, bn + i))
282 munhash(dev, bn + i);
283 if (n == bsize)
284 bp = getblk(dev, bn, size);
285 else
286 bp = bread(dev, bn, size);
287 }
288 n = MIN(n, size - bp->b_resid);
289 if (bp->b_flags & B_ERROR) {
290 error = EIO;
291 brelse(bp);
292 goto bad;
293 }
294 u.u_error =
295 uiomove(bp->b_un.b_addr+on, (u_int)n, rw, uio);
296 if (rw == UIO_READ) {
297 if (n + on == bsize || uio->uio_offset == ip->i_size)
298 bp->b_flags |= B_AGE;
299 brelse(bp);
300 } else {
301 if ((ip->i_mode&IFMT) == IFDIR)
302 bwrite(bp);
303 else if (n + on == bsize) {
304 bp->b_flags |= B_AGE;
305 bawrite(bp);
306 } else
307 bdwrite(bp);
308 ip->i_flag |= IUPD|ICHG;
309 if (u.u_ruid != 0)
310 ip->i_mode &= ~(ISUID|ISGID);
311 }
312 } while (u.u_error == 0 && uio->uio_resid > 0 && n != 0);
313bad:
314 return (error);
4147b3f6
BJ
315}
316
b9429893
BJ
317uiomove(cp, n, rw, uio)
318 register caddr_t cp;
319 register int n;
320 enum uio_rw rw;
321 register struct uio *uio;
4147b3f6 322{
b9429893
BJ
323 register struct iovec *iov;
324 int error;
325 u_int cnt;
326
327 while (n > 0 && uio->uio_resid) {
328 iov = uio->uio_iov;
329 cnt = iov->iov_len;
330 if (cnt == 0) {
331 uio->uio_iov++;
332 uio->uio_iovcnt--;
333 continue;
334 }
335 if (cnt > n)
336 cnt = n;
337 switch (uio->uio_segflg) {
338
339 case 0:
340 case 2:
341 if (rw == UIO_READ)
342 error = copyout(cp, iov->iov_base, cnt);
343 else
344 error = copyin(iov->iov_base, cp, cnt);
345 if (error)
346 return (error);
347 break;
4147b3f6 348
b9429893
BJ
349 case 1:
350 if (rw == UIO_READ)
351 bcopy((caddr_t)cp, iov->iov_base, cnt);
352 else
353 bcopy(iov->iov_base, (caddr_t)cp, cnt);
354 break;
355 }
356 iov->iov_base += cnt;
357 iov->iov_len -= cnt;
358 uio->uio_resid -= cnt;
359 uio->uio_offset += cnt;
360 cp += cnt;
361 n -= cnt;
362 }
363 return (error);
364}
365
366/*
367 * Give next character to user as result of read.
368 */
369ureadc(c, uio)
370 register int c;
371 register struct uio *uio;
372{
373 register struct iovec *iov;
374
375again:
376 if (uio->uio_iovcnt == 0)
377 panic("ureadc");
378 iov = uio->uio_iov;
379 if (iov->iov_len <= 0 || uio->uio_resid <= 0) {
380 uio->uio_iovcnt--;
381 uio->uio_iov++;
382 goto again;
383 }
384 switch (uio->uio_segflg) {
385
386 case 0:
387 if (subyte(iov->iov_base, c) < 0)
388 return (EFAULT);
389 break;
390
391 case 1:
392 *iov->iov_base = c;
393 break;
394
395 case 2:
396 if (suibyte(iov->iov_base, c) < 0)
397 return (EFAULT);
398 break;
399 }
400 iov->iov_base++;
401 iov->iov_len--;
402 uio->uio_resid--;
403 uio->uio_offset++;
404 return (0);
405}
406
407/*
408 * Get next character written in by user from uio.
409 */
410uwritec(uio)
411 struct uio *uio;
412{
413 register struct iovec *iov;
414 register int c;
415
416again:
417 if (uio->uio_iovcnt <= 0 || uio->uio_resid <= 0)
418 panic("uwritec");
419 iov = uio->uio_iov;
420 if (iov->iov_len == 0) {
421 uio->uio_iovcnt--;
422 uio->uio_iov++;
423 goto again;
424 }
425 switch (uio->uio_segflg) {
426
427 case 0:
428 c = fubyte(iov->iov_base);
429 break;
430
431 case 1:
432 c = *iov->iov_base & 0377;
433 break;
434
435 case 2:
436 c = fuibyte(iov->iov_base);
437 break;
438 }
439 if (c < 0)
440 return (-1);
441 iov->iov_base++;
442 iov->iov_len--;
443 uio->uio_resid--;
444 uio->uio_offset++;
445 return (c & 0377);
4147b3f6 446}
ffe28cfe
BJ
447
448/*
449 * Ioctl system call
4b72e2f9
SL
450 * Check legality, execute common code,
451 * and switch out to individual device routine.
ffe28cfe
BJ
452 */
453ioctl()
454{
455 register struct file *fp;
4b72e2f9 456 struct a {
ffe28cfe
BJ
457 int fdes;
458 int cmd;
459 caddr_t cmarg;
460 } *uap;
b9429893
BJ
461 register int com;
462 register u_int size;
4b72e2f9 463 char data[IOCPARM_MASK+1];
ffe28cfe
BJ
464
465 uap = (struct a *)u.u_ap;
466 if ((fp = getf(uap->fdes)) == NULL)
467 return;
468 if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
469 u.u_error = EBADF;
470 return;
471 }
4b72e2f9
SL
472 com = uap->cmd;
473
68c9244a 474#ifndef NOCOMPAT
4b72e2f9
SL
475 /*
476 * Map old style ioctl's into new for the
477 * sake of backwards compatibility (sigh).
478 */
479 if ((com&~0xffff) == 0) {
480 com = mapioctl(com);
481 if (com == 0) {
482 u.u_error = EINVAL;
483 return;
484 }
485 }
486#endif
487 if (com == FIOCLEX) {
ffe28cfe
BJ
488 u.u_pofile[uap->fdes] |= EXCLOSE;
489 return;
490 }
4b72e2f9 491 if (com == FIONCLEX) {
ffe28cfe
BJ
492 u.u_pofile[uap->fdes] &= ~EXCLOSE;
493 return;
494 }
4b72e2f9
SL
495
496 /*
497 * Interpret high order word to find
498 * amount of data to be copied to/from the
499 * user's address space.
4b72e2f9
SL
500 */
501 size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
502 if (size > sizeof (data)) {
503 u.u_error = EFAULT;
ffe28cfe
BJ
504 return;
505 }
68c9244a 506 if (com&IOC_IN && size) {
b9429893 507 if (copyin(uap->cmarg, (caddr_t)data, (u_int)size)) {
4b72e2f9 508 u.u_error = EFAULT;
ffe28cfe 509 return;
4b72e2f9
SL
510 }
511 } else
512 *(caddr_t *)data = uap->cmarg;
513 /*
514 * Zero the buffer on the stack so the user
515 * always gets back something deterministic.
516 */
517 if ((com&IOC_OUT) && size)
518 bzero((caddr_t)data, size);
519
520 if (fp->f_type == DTYPE_SOCKET)
521 soioctl(fp->f_socket, com, data);
522 else {
523 register struct inode *ip = fp->f_inode;
524 int fmt = ip->i_mode & IFMT;
525 dev_t dev;
526
527 if (fmt != IFCHR) {
528 if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
529 *(off_t *)data = ip->i_size - fp->f_offset;
530 goto returndata;
531 }
532 if (com != FIONBIO && com != FIOASYNC)
533 u.u_error = ENOTTY;
534 return;
535 }
536 dev = ip->i_rdev;
537 u.u_r.r_val1 = 0;
eb5786ea 538 if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) {
4b72e2f9
SL
539 u.u_eosys = RESTARTSYS;
540 return;
541 }
542 (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0);
ffe28cfe 543 }
4b72e2f9
SL
544
545returndata:
546 /*
547 * Copy any data to user, size was
548 * already set and checked above.
549 */
b9429893
BJ
550 if (u.u_error == 0 && (com&IOC_OUT))
551 if (size && copyout(data, uap->cmarg, (u_int)size))
68c9244a 552 u.u_error = EFAULT;
ffe28cfe
BJ
553}
554
555/*
556 * Do nothing specific version of line
557 * discipline specific ioctl command.
558 */
559/*ARGSUSED*/
4b72e2f9 560nullioctl(tp, cmd, data, flags)
ffe28cfe 561 struct tty *tp;
4b72e2f9
SL
562 char *data;
563 int flags;
ffe28cfe
BJ
564{
565
4b72e2f9
SL
566#ifdef lint
567 tp = tp; data = data; flags = flags;
568#endif
ffe28cfe
BJ
569 return (cmd);
570}
1edb1cf8
BJ
571
572ostty()
573{
574
575}
576
577ogtty()
578{
579
580}