xref: /csrg-svn/sys/kern/sys_generic.c (revision 7749)
1 /*	sys_generic.c	5.10	82/08/14	*/
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"
19 #ifdef MUSH
20 #include "../h/quota.h"
21 #include "../h/share.h"
22 #else
23 #define	CHARGE(nothing)
24 #endif
25 #include "../h/descrip.h"
26 #include "../h/uio.h"
27 
28 /*
29  * Read system call.
30  */
31 read()
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;
40 	struct uio auio;
41 	struct iovec aiov;
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 	}
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;
61 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
62 		if (auio.uio_resid == uap->count)
63 			u.u_eosys = RESTARTSYS;
64 	} else if (fp->f_type == DTYPE_SOCKET)
65 		u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0, &auio);
66 	else {
67 		ip = fp->f_inode;
68 		auio.uio_offset = fp->f_offset;
69 		if ((ip->i_mode&IFMT) == IFREG) {
70 			ilock(ip);
71 			u.u_error = readip(ip, &auio);
72 			iunlock(ip);
73 		} else
74 			u.u_error = readip(ip, &auio);
75 		fp->f_offset += uap->count - auio.uio_resid;
76 	}
77 	u.u_r.r_val1 = uap->count - auio.uio_resid;
78 }
79 
80 /*
81  * Write system call
82  */
83 write()
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;
109 	} else if (fp->f_type == DTYPE_SOCKET)
110 		u.u_error = sosend(fp->f_socket, (struct sockaddr *)0);
111 	else {
112 		ip = fp->f_inode;
113 		if (fp->f_flag&FAPPEND)
114 			fp->f_offset = ip->i_size;
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 
127 readv()
128 {
129 
130 }
131 
132 writev()
133 {
134 
135 }
136 
137 /*
138  * Ioctl system call
139  * Check legality, execute common code,
140  * and switch out to individual device routine.
141  */
142 ioctl()
143 {
144 	register struct file *fp;
145 	struct a {
146 		int	fdes;
147 		int	cmd;
148 		caddr_t	cmarg;
149 	} *uap;
150 	register int com, size;
151 	char data[IOCPARM_MASK+1];
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 	}
160 	com = uap->cmd;
161 
162 #ifndef NOCOMPAT
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) {
176 		u.u_pofile[uap->fdes] |= EXCLOSE;
177 		return;
178 	}
179 	if (com == FIONCLEX) {
180 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
181 		return;
182 	}
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;
193 		return;
194 	}
195 	if (com&IOC_IN && size) {
196 		if (copyin(uap->cmarg, (caddr_t)data, size)) {
197 			u.u_error = EFAULT;
198 			return;
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);
232 	}
233 
234 returndata:
235 	/*
236 	 * Copy any data to user, size was
237 	 * already set and checked above.
238 	 */
239 	if (u.u_error == 0 && com&IOC_OUT)
240 		if (size && copyout(data, uap->cmarg, size))
241 			u.u_error = EFAULT;
242 }
243 
244 /*
245  * Do nothing specific version of line
246  * discipline specific ioctl command.
247  */
248 /*ARGSUSED*/
249 nullioctl(tp, cmd, data, flags)
250 	struct tty *tp;
251 	char *data;
252 	int flags;
253 {
254 
255 #ifdef lint
256 	tp = tp; data = data; flags = flags;
257 #endif
258 	return (cmd);
259 }
260 
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  */
271 writei(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;
293 		CHARGE(sc_tio * u.u_count);
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;
309 	} else
310 		bsize = BLKDEV_IOSIZE;
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)));
317 			if (u.u_error || (long)bn<0)
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 		}
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)
332 			bp = getblk(dev, bn, size);
333 		else
334 			bp = bread(dev, bn, size);
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;
345 bad:
346 		;
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  */
379 iomove(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 }
405 
406 readip1(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 
432 readip(ip, uio)
433 	register struct inode *ip;
434 	register struct uio *uio;
435 {
436 	register struct iovec *iov;
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 
449 	dev = (dev_t)ip->i_rdev;
450 	if (uio->uio_offset < 0 &&
451 	    ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev)))
452 		return (EINVAL);
453 	ip->i_flag |= IACC;
454 	type = ip->i_mode&IFMT;
455 	if (type == IFCHR) {
456 		register c = u.u_count;
457 		(*cdevsw[major(dev)].d_read)(dev, uio);
458 		CHARGE(sc_tio * (c - uio->uio_resid));
459 		return (u.u_error);
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;
467 nextiov:
468 	if (uio->uio_iovcnt == 0)
469 		return (0);
470 	iov = uio->uio_iov;
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)
484 				return (u.u_error);
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)) {
504 					brelse(bp);
505 					return (EFAULT);
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;
512 			uio->uio_resid -= n;
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);
518 	if (u.u_error == 0 && iov->iov_len == 0) {
519 		uio->uio_iov++;
520 		uio->uio_iovcnt--;
521 		goto nextiov;
522 	}
523 	return (error);
524 }
525 
526 uiomove(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 }
566