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