merge with calder
[unix-history] / usr / src / sys / kern / sys_generic.c
CommitLineData
4147b3f6 1/* sys_generic.c 5.3 82/07/24 */
ffe28cfe
BJ
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"
4147b3f6 8#include "../h/fcntl.h"
ffe28cfe
BJ
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"
cabdaec4
RE
20#ifdef MUSH
21#include "../h/quota.h"
22#include "../h/share.h"
23#else
24#define CHARGE(nothing)
25#endif
4147b3f6 26#include "../h/descrip.h"
ffe28cfe
BJ
27
28/*
29 * Read system call.
30 */
31read()
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;
4147b3f6 57 } else if (fp->f_type == DTYPE_SOCKET)
ffe28cfe
BJ
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 */
76write()
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;
4147b3f6 102 } else if (fp->f_type == DTYPE_SOCKET)
ffe28cfe
BJ
103 u.u_error = sosend(fp->f_socket, (struct sockaddr *)0);
104 else {
105 ip = fp->f_inode;
4147b3f6
BJ
106 if (fp->f_flag & O_APPEND)
107 fp->f_offset = ip->i_size;
ffe28cfe
BJ
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
4147b3f6
BJ
120readv()
121{
122
123}
124
125writev()
126{
127
128}
ffe28cfe
BJ
129
130/*
131 * Ioctl system call
132 * Check legality, execute common code, and switch out to individual
133 * device routine.
134 */
135ioctl()
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 }
4147b3f6 162 if (fp->f_type == DTYPE_SOCKET) {
ffe28cfe
BJ
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*/
194nullioctl(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 */
212readi(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) {
cabdaec4 237 register c = u.u_count;
ffe28cfe 238 (*cdevsw[major(dev)].d_read)(dev);
cabdaec4 239 CHARGE(sc_tio * (c - u.u_count));
ffe28cfe
BJ
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;
291bad:
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 */
311writei(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;
cabdaec4 333 CHARGE(sc_tio * u.u_count);
ffe28cfe
BJ
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 }
352 do {
353 lbn = u.u_offset / bsize;
354 on = u.u_offset % bsize;
355 n = MIN((unsigned)(bsize - on), u.u_count);
356 if (type != IFBLK) {
357 bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
358 if ((long)bn<0)
359 return;
360 if(u.u_offset + n > ip->i_size &&
361 (type == IFDIR || type == IFREG || type == IFLNK))
362 ip->i_size = u.u_offset + n;
363 size = blksize(fs, ip, lbn);
364 } else {
365 size = bsize;
366 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
367 }
368 if (bn) {
369 count = howmany(size, DEV_BSIZE);
370 for (i = 0; i < count; i += CLSIZE) {
371 if (mfind(dev, bn + i))
372 munhash(dev, bn + i);
373 }
374 }
375 if(n == bsize)
376 bp = getblk(dev, bn, size);
377 else
378 bp = bread(dev, bn, size);
379#ifdef UNFAST
380 iomove(bp->b_un.b_addr + on, n, B_WRITE);
381#else
382 if (u.u_segflg != 1) {
383 if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
384 u.u_error = EFAULT;
385 goto bad;
386 }
387 } else
388 bcopy(u.u_base, bp->b_un.b_addr + on, n);
389 u.u_base += n;
390 u.u_offset += n;
391 u.u_count -= n;
392bad:
393 ;
394#endif
395 if (u.u_error != 0)
396 brelse(bp);
397 else {
398 if ((ip->i_mode&IFMT) == IFDIR)
399 /*
400 * Writing to clear a directory entry.
401 * Must insure the write occurs before
402 * the inode is freed, or may end up
403 * pointing at a new (different) file
404 * if inode is quickly allocated again
405 * and system crashes.
406 */
407 bwrite(bp);
408 else if (n + on == bsize) {
409 bp->b_flags |= B_AGE;
410 bawrite(bp);
411 } else
412 bdwrite(bp);
413 }
414 ip->i_flag |= IUPD|ICHG;
415 if (u.u_ruid != 0)
416 ip->i_mode &= ~(ISUID|ISGID);
417 } while (u.u_error == 0 && u.u_count != 0);
418}
419
420/*
421 * Move n bytes at byte location
422 * &bp->b_un.b_addr[o] to/from (flag) the
423 * user/kernel (u.segflg) area starting at u.base.
424 * Update all the arguments by the number
425 * of bytes moved.
426 */
427iomove(cp, n, flag)
428 register caddr_t cp;
429 register unsigned n;
430{
431 register int t;
432
433 if (n==0)
434 return;
435 if (u.u_segflg != 1) {
436 if (flag==B_WRITE)
437 t = copyin(u.u_base, (caddr_t)cp, n);
438 else
439 t = copyout((caddr_t)cp, u.u_base, n);
440 if (t) {
441 u.u_error = EFAULT;
442 return;
443 }
444 } else
445 if (flag == B_WRITE)
446 bcopy(u.u_base, (caddr_t)cp, n);
447 else
448 bcopy((caddr_t)cp, u.u_base, n);
449 u.u_base += n;
450 u.u_offset += n;
451 u.u_count -= n;
452}