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