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