xref: /csrg-svn/sys/kern/sys_generic.c (revision 7699)
1 /*	sys_generic.c	5.6	82/08/10	*/
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 
27 /*
28  * Read system call.
29  */
30 read()
31 {
32 	register struct file *fp;
33 	register struct inode *ip;
34 	register struct a {
35 		int	fdes;
36 		char	*cbuf;
37 		unsigned count;
38 	} *uap;
39 
40 	uap = (struct a *)u.u_ap;
41 	if ((int)uap->count < 0) {
42 		u.u_error = EINVAL;
43 		return;
44 	}
45 	GETF(fp, uap->fdes);
46 	if ((fp->f_flag&FREAD) == 0) {
47 		u.u_error = EBADF;
48 		return;
49 	}
50 	u.u_base = (caddr_t)uap->cbuf;
51 	u.u_count = uap->count;
52 	u.u_segflg = 0;
53 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
54 		if (u.u_count == uap->count)
55 			u.u_eosys = RESTARTSYS;
56 	} else if (fp->f_type == DTYPE_SOCKET)
57 		u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0);
58 	else {
59 		ip = fp->f_inode;
60 		u.u_offset = fp->f_offset;
61 		if ((ip->i_mode&IFMT) == IFREG) {
62 			ilock(ip);
63 			readi(ip);
64 			iunlock(ip);
65 		} else
66 			readi(ip);
67 		fp->f_offset += uap->count - u.u_count;
68 	}
69 	u.u_r.r_val1 = uap->count - u.u_count;
70 }
71 
72 /*
73  * Write system call
74  */
75 write()
76 {
77 	register struct file *fp;
78 	register struct inode *ip;
79 	register struct a {
80 		int	fdes;
81 		char	*cbuf;
82 		unsigned count;
83 	} *uap;
84 
85 	uap = (struct a *)u.u_ap;
86 	if ((int)uap->count < 0) {
87 		u.u_error = EINVAL;
88 		return;
89 	}
90 	GETF(fp, uap->fdes);
91 	if ((fp->f_flag&FWRITE) == 0) {
92 		u.u_error = EBADF;
93 		return;
94 	}
95 	u.u_base = (caddr_t)uap->cbuf;
96 	u.u_count = uap->count;
97 	u.u_segflg = 0;
98 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
99 		if (u.u_count == uap->count)
100 			u.u_eosys = RESTARTSYS;
101 	} else if (fp->f_type == DTYPE_SOCKET)
102 		u.u_error = sosend(fp->f_socket, (struct sockaddr *)0);
103 	else {
104 		ip = fp->f_inode;
105 		if (fp->f_flag&FAPPEND)
106 			fp->f_offset = ip->i_size;
107 		u.u_offset = fp->f_offset;
108 		if ((ip->i_mode&IFMT) == IFREG) {
109 			ilock(ip);
110 			writei(ip);
111 			iunlock(ip);
112 		} else
113 			writei(ip);
114 		fp->f_offset += uap->count - u.u_count;
115 	}
116 	u.u_r.r_val1 = uap->count - u.u_count;
117 }
118 
119 readv()
120 {
121 
122 }
123 
124 writev()
125 {
126 
127 }
128 
129 /*
130  * Ioctl system call
131  * Check legality, execute common code,
132  * and switch out to individual device routine.
133  */
134 ioctl()
135 {
136 	register struct file *fp;
137 	struct a {
138 		int	fdes;
139 		int	cmd;
140 		caddr_t	cmarg;
141 	} *uap;
142 	register int com, size;
143 	char data[IOCPARM_MASK+1];
144 
145 	uap = (struct a *)u.u_ap;
146 	if ((fp = getf(uap->fdes)) == NULL)
147 		return;
148 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
149 		u.u_error = EBADF;
150 		return;
151 	}
152 	com = uap->cmd;
153 
154 #ifndef NOCOMPAT
155 	/*
156 	 * Map old style ioctl's into new for the
157 	 * sake of backwards compatibility (sigh).
158 	 */
159 	if ((com&~0xffff) == 0) {
160 		com = mapioctl(com);
161 		if (com == 0) {
162 			u.u_error = EINVAL;
163 			return;
164 		}
165 	}
166 #endif
167 	if (com == FIOCLEX) {
168 		u.u_pofile[uap->fdes] |= EXCLOSE;
169 		return;
170 	}
171 	if (com == FIONCLEX) {
172 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
173 		return;
174 	}
175 
176 	/*
177 	 * Interpret high order word to find
178 	 * amount of data to be copied to/from the
179 	 * user's address space.
180 	 * (this'll have to change if we have in+out ioctls)
181 	 */
182 	size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
183 	if (size > sizeof (data)) {
184 		u.u_error = EFAULT;
185 		return;
186 	}
187 	if (com&IOC_IN && size) {
188 		if (copyin(uap->cmarg, (caddr_t)data, size)) {
189 			u.u_error = EFAULT;
190 			return;
191 		}
192 	} else
193 		*(caddr_t *)data = uap->cmarg;
194 	/*
195 	 * Zero the buffer on the stack so the user
196 	 * always gets back something deterministic.
197 	 */
198 	if ((com&IOC_OUT) && size)
199 		bzero((caddr_t)data, size);
200 
201 	if (fp->f_type == DTYPE_SOCKET)
202 		soioctl(fp->f_socket, com, data);
203 	else {
204 		register struct inode *ip = fp->f_inode;
205 		int fmt = ip->i_mode & IFMT;
206 		dev_t dev;
207 
208 		if (fmt != IFCHR) {
209 			if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
210 				*(off_t *)data = ip->i_size - fp->f_offset;
211 				goto returndata;
212 			}
213 			if (com != FIONBIO && com != FIOASYNC)
214 				u.u_error = ENOTTY;
215 			return;
216 		}
217 		dev = ip->i_rdev;
218 		u.u_r.r_val1 = 0;
219 		if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
220 			u.u_eosys = RESTARTSYS;
221 			return;
222 		}
223 		(*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0);
224 	}
225 
226 returndata:
227 	/*
228 	 * Copy any data to user, size was
229 	 * already set and checked above.
230 	 */
231 	if (u.u_error == 0 && com&IOC_OUT)
232 		if (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 			if (u.u_segflg != 1) {
330 				if (copyout(bp->b_un.b_addr+on, u.u_base, n)) {
331 					u.u_error = EFAULT;
332 					goto bad;
333 				}
334 			} else
335 				bcopy(bp->b_un.b_addr + on, u.u_base, n);
336 			u.u_base += n;
337 			u.u_offset += n;
338 			u.u_count -= n;
339 bad:
340 			;
341 		}
342 		if (n + on == bsize || u.u_offset == ip->i_size)
343 			bp->b_flags |= B_AGE;
344 		brelse(bp);
345 	} while (u.u_error == 0 && u.u_count != 0 && n != 0);
346 }
347 
348 /*
349  * Write the file corresponding to
350  * the inode pointed at by the argument.
351  * The actual write arguments are found
352  * in the variables:
353  *	u_base		core address for source
354  *	u_offset	byte offset in file
355  *	u_count		number of bytes to write
356  *	u_segflg	write to kernel/user/user I
357  */
358 writei(ip)
359 	register struct inode *ip;
360 {
361 	struct buf *bp;
362 	register struct fs *fs;
363 	dev_t dev;
364 	daddr_t lbn, bn;
365 	register int on, type;
366 	register unsigned n;
367 	long bsize;
368 	int size, i, count;
369 	extern int mem_no;
370 
371 	dev = (dev_t)ip->i_rdev;
372 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
373 	    mem_no != major(dev)) ) {
374 		u.u_error = EINVAL;
375 		return;
376 	}
377 	type = ip->i_mode & IFMT;
378 	if (type == IFCHR) {
379 		ip->i_flag |= IUPD|ICHG;
380 		CHARGE(sc_tio * u.u_count);
381 		(*cdevsw[major(dev)].d_write)(dev);
382 		return;
383 	}
384 	if (u.u_count == 0)
385 		return;
386 	if ((ip->i_mode & IFMT) == IFREG &&
387 	    u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
388 		psignal(u.u_procp, SIGXFSZ);
389 		u.u_error = EMFILE;
390 		return;
391 	}
392 	if (type!=IFBLK) {
393 		dev = ip->i_dev;
394 		fs = ip->i_fs;
395 		bsize = fs->fs_bsize;
396 	} else
397 		bsize = BLKDEV_IOSIZE;
398 	do {
399 		lbn = u.u_offset / bsize;
400 		on = u.u_offset % bsize;
401 		n = MIN((unsigned)(bsize - on), u.u_count);
402 		if (type != IFBLK) {
403 			bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
404 			if (u.u_error || (long)bn<0)
405 				return;
406 			if(u.u_offset + n > ip->i_size &&
407 			   (type == IFDIR || type == IFREG || type == IFLNK))
408 				ip->i_size = u.u_offset + n;
409 			size = blksize(fs, ip, lbn);
410 		} else {
411 			size = bsize;
412 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
413 		}
414 		count = howmany(size, DEV_BSIZE);
415 		for (i = 0; i < count; i += CLSIZE)
416 			if (mfind(dev, bn + i))
417 				munhash(dev, bn + i);
418 		if (n == bsize)
419 			bp = getblk(dev, bn, size);
420 		else
421 			bp = bread(dev, bn, size);
422 		if (u.u_segflg != 1) {
423 			if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
424 				u.u_error = EFAULT;
425 				goto bad;
426 			}
427 		} else
428 			bcopy(u.u_base, bp->b_un.b_addr + on, n);
429 		u.u_base += n;
430 		u.u_offset += n;
431 		u.u_count -= n;
432 bad:
433 		;
434 		if (u.u_error != 0)
435 			brelse(bp);
436 		else {
437 			if ((ip->i_mode&IFMT) == IFDIR)
438 				/*
439 				 * Writing to clear a directory entry.
440 				 * Must insure the write occurs before
441 				 * the inode is freed, or may end up
442 				 * pointing at a new (different) file
443 				 * if inode is quickly allocated again
444 				 * and system crashes.
445 				 */
446 				bwrite(bp);
447 			else if (n + on == bsize) {
448 				bp->b_flags |= B_AGE;
449 				bawrite(bp);
450 			} else
451 				bdwrite(bp);
452 		}
453 		ip->i_flag |= IUPD|ICHG;
454 		if (u.u_ruid != 0)
455 			ip->i_mode &= ~(ISUID|ISGID);
456 	} while (u.u_error == 0 && u.u_count != 0);
457 }
458 
459 /*
460  * Move n bytes at byte location
461  * &bp->b_un.b_addr[o] to/from (flag) the
462  * user/kernel (u.segflg) area starting at u.base.
463  * Update all the arguments by the number
464  * of bytes moved.
465  */
466 iomove(cp, n, flag)
467 	register caddr_t cp;
468 	register unsigned n;
469 {
470 	register int t;
471 
472 	if (n==0)
473 		return;
474 	if (u.u_segflg != 1) {
475 		if (flag==B_WRITE)
476 			t = copyin(u.u_base, (caddr_t)cp, n);
477 		else
478 			t = copyout((caddr_t)cp, u.u_base, n);
479 		if (t) {
480 			u.u_error = EFAULT;
481 			return;
482 		}
483 	} else
484 		if (flag == B_WRITE)
485 			bcopy(u.u_base, (caddr_t)cp, n);
486 		else
487 			bcopy((caddr_t)cp, u.u_base, n);
488 	u.u_base += n;
489 	u.u_offset += n;
490 	u.u_count -= n;
491 }
492