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