xref: /csrg-svn/sys/kern/sys_generic.c (revision 7487)
1 /*	sys_generic.c	5.2	82/07/22	*/
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 
26 /*
27  * Read system call.
28  */
29 read()
30 {
31 	register struct file *fp;
32 	register struct inode *ip;
33 	register struct a {
34 		int	fdes;
35 		char	*cbuf;
36 		unsigned count;
37 	} *uap;
38 
39 	uap = (struct a *)u.u_ap;
40 	if ((int)uap->count < 0) {
41 		u.u_error = EINVAL;
42 		return;
43 	}
44 	GETF(fp, uap->fdes);
45 	if ((fp->f_flag&FREAD) == 0) {
46 		u.u_error = EBADF;
47 		return;
48 	}
49 	u.u_base = (caddr_t)uap->cbuf;
50 	u.u_count = uap->count;
51 	u.u_segflg = 0;
52 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
53 		if (u.u_count == uap->count)
54 			u.u_eosys = RESTARTSYS;
55 	} else if (fp->f_flag & FSOCKET)
56 		u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0);
57 	else {
58 		ip = fp->f_inode;
59 		u.u_offset = fp->f_offset;
60 		if ((ip->i_mode&IFMT) == IFREG) {
61 			ilock(ip);
62 			readi(ip);
63 			iunlock(ip);
64 		} else
65 			readi(ip);
66 		fp->f_offset += uap->count - u.u_count;
67 	}
68 	u.u_r.r_val1 = uap->count - u.u_count;
69 }
70 
71 /*
72  * Write system call
73  */
74 write()
75 {
76 	register struct file *fp;
77 	register struct inode *ip;
78 	register struct a {
79 		int	fdes;
80 		char	*cbuf;
81 		unsigned count;
82 	} *uap;
83 
84 	uap = (struct a *)u.u_ap;
85 	if ((int)uap->count < 0) {
86 		u.u_error = EINVAL;
87 		return;
88 	}
89 	GETF(fp, uap->fdes);
90 	if ((fp->f_flag&FWRITE) == 0) {
91 		u.u_error = EBADF;
92 		return;
93 	}
94 	u.u_base = (caddr_t)uap->cbuf;
95 	u.u_count = uap->count;
96 	u.u_segflg = 0;
97 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
98 		if (u.u_count == uap->count)
99 			u.u_eosys = RESTARTSYS;
100 	} else if (fp->f_flag & FSOCKET)
101 		u.u_error = sosend(fp->f_socket, (struct sockaddr *)0);
102 	else {
103 		ip = fp->f_inode;
104 		u.u_offset = fp->f_offset;
105 		if ((ip->i_mode&IFMT) == IFREG) {
106 			ilock(ip);
107 			writei(ip);
108 			iunlock(ip);
109 		} else
110 			writei(ip);
111 		fp->f_offset += uap->count - u.u_count;
112 	}
113 	u.u_r.r_val1 = uap->count - u.u_count;
114 }
115 
116 
117 /*
118  * Ioctl system call
119  * Check legality, execute common code, and switch out to individual
120  * device routine.
121  */
122 ioctl()
123 {
124 	register struct file *fp;
125 	register struct inode *ip;
126 	register struct a {
127 		int	fdes;
128 		int	cmd;
129 		caddr_t	cmarg;
130 	} *uap;
131 	register dev_t dev;
132 	register fmt;
133 
134 	uap = (struct a *)u.u_ap;
135 	if ((fp = getf(uap->fdes)) == NULL)
136 		return;
137 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
138 		u.u_error = EBADF;
139 		return;
140 	}
141 	if (uap->cmd==FIOCLEX) {
142 		u.u_pofile[uap->fdes] |= EXCLOSE;
143 		return;
144 	}
145 	if (uap->cmd==FIONCLEX) {
146 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
147 		return;
148 	}
149 	if (fp->f_flag & FSOCKET) {
150 		soioctl(fp->f_socket, uap->cmd, uap->cmarg);
151 		return;
152 	}
153 	ip = fp->f_inode;
154 	fmt = ip->i_mode & IFMT;
155 	if (fmt != IFCHR) {
156 		if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
157 			off_t nread = ip->i_size - fp->f_offset;
158 
159 			if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
160 				u.u_error = EFAULT;
161 		} else if (uap->cmd == FIONBIO || uap->cmd == FIOASYNC)
162 			return;
163 		else
164 			u.u_error = ENOTTY;
165 		return;
166 	}
167 	dev = ip->i_rdev;
168 	u.u_r.r_val1 = 0;
169 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
170 		u.u_eosys = RESTARTSYS;
171 		return;
172 	}
173 	(*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, 0);
174 }
175 
176 /*
177  * Do nothing specific version of line
178  * discipline specific ioctl command.
179  */
180 /*ARGSUSED*/
181 nullioctl(tp, cmd, addr)
182 	struct tty *tp;
183 	caddr_t addr;
184 {
185 
186 	return (cmd);
187 }
188 
189 /*
190  * Read the file corresponding to
191  * the inode pointed at by the argument.
192  * The actual read arguments are found
193  * in the variables:
194  *	u_base		core address for destination
195  *	u_offset	byte offset in file
196  *	u_count		number of bytes to read
197  *	u_segflg	read to kernel/user/user I
198  */
199 readi(ip)
200 	register struct inode *ip;
201 {
202 	struct buf *bp;
203 	struct fs *fs;
204 	dev_t dev;
205 	daddr_t lbn, bn;
206 	off_t diff;
207 	register int on, type;
208 	register unsigned n;
209 	int size;
210 	long bsize;
211 	extern int mem_no;
212 
213 	if (u.u_count == 0)
214 		return;
215 	dev = (dev_t)ip->i_rdev;
216 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
217 	    mem_no != major(dev))) {
218 		u.u_error = EINVAL;
219 		return;
220 	}
221 	ip->i_flag |= IACC;
222 	type = ip->i_mode&IFMT;
223 	if (type == IFCHR) {
224 		register c = u.u_count;
225 		(*cdevsw[major(dev)].d_read)(dev);
226 		CHARGE(sc_tio * (c - u.u_count));
227 		return;
228 	}
229 	if (type != IFBLK) {
230 		dev = ip->i_dev;
231 		fs = ip->i_fs;
232 		bsize = fs->fs_bsize;
233 	} else
234 		bsize = BLKDEV_IOSIZE;
235 	do {
236 		lbn = u.u_offset / bsize;
237 		on = u.u_offset % bsize;
238 		n = MIN((unsigned)(bsize - on), u.u_count);
239 		if (type != IFBLK) {
240 			diff = ip->i_size - u.u_offset;
241 			if (diff <= 0)
242 				return;
243 			if (diff < n)
244 				n = diff;
245 			bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
246 			if (u.u_error)
247 				return;
248 			size = blksize(fs, ip, lbn);
249 		} else {
250 			size = bsize;
251 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
252 			rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
253 			rasize = bsize;
254 		}
255 		if ((long)bn<0) {
256 			bp = geteblk(size);
257 			clrbuf(bp);
258 		} else if (ip->i_lastr + 1 == lbn)
259 			bp = breada(dev, bn, size, rablock, rasize);
260 		else
261 			bp = bread(dev, bn, size);
262 		ip->i_lastr = lbn;
263 		n = MIN(n, size - bp->b_resid);
264 		if (n != 0) {
265 #ifdef UNFAST
266 			iomove(bp->b_un.b_addr + on, n, B_READ);
267 #else
268 			if (u.u_segflg != 1) {
269 				if (copyout(bp->b_un.b_addr+on, u.u_base, n)) {
270 					u.u_error = EFAULT;
271 					goto bad;
272 				}
273 			} else
274 				bcopy(bp->b_un.b_addr + on, u.u_base, n);
275 			u.u_base += n;
276 			u.u_offset += n;
277 			u.u_count -= n;
278 bad:
279 			;
280 #endif
281 		}
282 		if (n + on == bsize || u.u_offset == ip->i_size)
283 			bp->b_flags |= B_AGE;
284 		brelse(bp);
285 	} while (u.u_error == 0 && u.u_count != 0 && n != 0);
286 }
287 
288 /*
289  * Write the file corresponding to
290  * the inode pointed at by the argument.
291  * The actual write arguments are found
292  * in the variables:
293  *	u_base		core address for source
294  *	u_offset	byte offset in file
295  *	u_count		number of bytes to write
296  *	u_segflg	write to kernel/user/user I
297  */
298 writei(ip)
299 	register struct inode *ip;
300 {
301 	struct buf *bp;
302 	register struct fs *fs;
303 	dev_t dev;
304 	daddr_t lbn, bn;
305 	register int on, type;
306 	register unsigned n;
307 	long bsize;
308 	int size, i, count;
309 	extern int mem_no;
310 
311 	dev = (dev_t)ip->i_rdev;
312 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
313 	    mem_no != major(dev)) ) {
314 		u.u_error = EINVAL;
315 		return;
316 	}
317 	type = ip->i_mode & IFMT;
318 	if (type == IFCHR) {
319 		ip->i_flag |= IUPD|ICHG;
320 		CHARGE(sc_tio * u.u_count);
321 		(*cdevsw[major(dev)].d_write)(dev);
322 		return;
323 	}
324 	if (u.u_count == 0)
325 		return;
326 	if ((ip->i_mode & IFMT) == IFREG &&
327 	    u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
328 		psignal(u.u_procp, SIGXFSZ);
329 		u.u_error = EMFILE;
330 		return;
331 	}
332 	if (type!=IFBLK) {
333 		dev = ip->i_dev;
334 		fs = ip->i_fs;
335 		bsize = fs->fs_bsize;
336 	} else {
337 		bsize = BLKDEV_IOSIZE;
338 	}
339 	do {
340 		lbn = u.u_offset / bsize;
341 		on = u.u_offset % bsize;
342 		n = MIN((unsigned)(bsize - on), u.u_count);
343 		if (type != IFBLK) {
344 			bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
345 			if ((long)bn<0)
346 				return;
347 			if(u.u_offset + n > ip->i_size &&
348 			   (type == IFDIR || type == IFREG || type == IFLNK))
349 				ip->i_size = u.u_offset + n;
350 			size = blksize(fs, ip, lbn);
351 		} else {
352 			size = bsize;
353 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
354 		}
355 		if (bn) {
356 			count = howmany(size, DEV_BSIZE);
357 			for (i = 0; i < count; i += CLSIZE) {
358 				if (mfind(dev, bn + i))
359 					munhash(dev, bn + i);
360 			}
361 		}
362 		if(n == bsize)
363 			bp = getblk(dev, bn, size);
364 		else
365 			bp = bread(dev, bn, size);
366 #ifdef UNFAST
367 		iomove(bp->b_un.b_addr + on, n, B_WRITE);
368 #else
369 		if (u.u_segflg != 1) {
370 			if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
371 				u.u_error = EFAULT;
372 				goto bad;
373 			}
374 		} else
375 			bcopy(u.u_base, bp->b_un.b_addr + on, n);
376 		u.u_base += n;
377 		u.u_offset += n;
378 		u.u_count -= n;
379 bad:
380 		;
381 #endif
382 		if (u.u_error != 0)
383 			brelse(bp);
384 		else {
385 			if ((ip->i_mode&IFMT) == IFDIR)
386 				/*
387 				 * Writing to clear a directory entry.
388 				 * Must insure the write occurs before
389 				 * the inode is freed, or may end up
390 				 * pointing at a new (different) file
391 				 * if inode is quickly allocated again
392 				 * and system crashes.
393 				 */
394 				bwrite(bp);
395 			else if (n + on == bsize) {
396 				bp->b_flags |= B_AGE;
397 				bawrite(bp);
398 			} else
399 				bdwrite(bp);
400 		}
401 		ip->i_flag |= IUPD|ICHG;
402 		if (u.u_ruid != 0)
403 			ip->i_mode &= ~(ISUID|ISGID);
404 	} while (u.u_error == 0 && u.u_count != 0);
405 }
406 
407 /*
408  * Move n bytes at byte location
409  * &bp->b_un.b_addr[o] to/from (flag) the
410  * user/kernel (u.segflg) area starting at u.base.
411  * Update all the arguments by the number
412  * of bytes moved.
413  */
414 iomove(cp, n, flag)
415 	register caddr_t cp;
416 	register unsigned n;
417 {
418 	register int t;
419 
420 	if (n==0)
421 		return;
422 	if (u.u_segflg != 1) {
423 		if (flag==B_WRITE)
424 			t = copyin(u.u_base, (caddr_t)cp, n);
425 		else
426 			t = copyout((caddr_t)cp, u.u_base, n);
427 		if (t) {
428 			u.u_error = EFAULT;
429 			return;
430 		}
431 	} else
432 		if (flag == B_WRITE)
433 			bcopy(u.u_base, (caddr_t)cp, n);
434 		else
435 			bcopy((caddr_t)cp, u.u_base, n);
436 	u.u_base += n;
437 	u.u_offset += n;
438 	u.u_count -= n;
439 }
440