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