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