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