new ioctl's
[unix-history] / usr / src / sys / kern / sys_generic.c
CommitLineData
4b72e2f9 1/* sys_generic.c 5.5 82/08/01 */
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
4b72e2f9
SL
132 * Check legality, execute common code,
133 * and switch out to individual device routine.
ffe28cfe
BJ
134 */
135ioctl()
136{
137 register struct file *fp;
4b72e2f9 138 struct a {
ffe28cfe
BJ
139 int fdes;
140 int cmd;
141 caddr_t cmarg;
142 } *uap;
4b72e2f9
SL
143 register int com, size;
144 char data[IOCPARM_MASK+1];
ffe28cfe
BJ
145
146 uap = (struct a *)u.u_ap;
147 if ((fp = getf(uap->fdes)) == NULL)
148 return;
149 if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
150 u.u_error = EBADF;
151 return;
152 }
4b72e2f9
SL
153 com = uap->cmd;
154
155#ifndef ONLYNEWIOCTLS
156 /*
157 * Map old style ioctl's into new for the
158 * sake of backwards compatibility (sigh).
159 */
160 if ((com&~0xffff) == 0) {
161 com = mapioctl(com);
162 if (com == 0) {
163 u.u_error = EINVAL;
164 return;
165 }
166 }
167#endif
168 if (com == FIOCLEX) {
ffe28cfe
BJ
169 u.u_pofile[uap->fdes] |= EXCLOSE;
170 return;
171 }
4b72e2f9 172 if (com == FIONCLEX) {
ffe28cfe
BJ
173 u.u_pofile[uap->fdes] &= ~EXCLOSE;
174 return;
175 }
4b72e2f9
SL
176
177 /*
178 * Interpret high order word to find
179 * amount of data to be copied to/from the
180 * user's address space.
181 * (this'll have to change if we have in+out ioctls)
182 */
183 size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
184 if (size > sizeof (data)) {
185 u.u_error = EFAULT;
ffe28cfe
BJ
186 return;
187 }
4b72e2f9
SL
188 if ((com&IOC_IN) && size) {
189 if (copyin(uap->cmarg, (caddr_t)data, size)) {
190 u.u_error = EFAULT;
ffe28cfe 191 return;
4b72e2f9
SL
192 }
193 } else
194 *(caddr_t *)data = uap->cmarg;
195 /*
196 * Zero the buffer on the stack so the user
197 * always gets back something deterministic.
198 */
199 if ((com&IOC_OUT) && size)
200 bzero((caddr_t)data, size);
201
202 if (fp->f_type == DTYPE_SOCKET)
203 soioctl(fp->f_socket, com, data);
204 else {
205 register struct inode *ip = fp->f_inode;
206 int fmt = ip->i_mode & IFMT;
207 dev_t dev;
208
209 if (fmt != IFCHR) {
210 if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
211 *(off_t *)data = ip->i_size - fp->f_offset;
212 goto returndata;
213 }
214 if (com != FIONBIO && com != FIOASYNC)
215 u.u_error = ENOTTY;
216 return;
217 }
218 dev = ip->i_rdev;
219 u.u_r.r_val1 = 0;
220 if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
221 u.u_eosys = RESTARTSYS;
222 return;
223 }
224 (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0);
ffe28cfe 225 }
4b72e2f9
SL
226
227returndata:
228 /*
229 * Copy any data to user, size was
230 * already set and checked above.
231 */
232 if ((com&IOC_OUT) && 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) {
329#ifdef UNFAST
330 iomove(bp->b_un.b_addr + on, n, B_READ);
331#else
332 if (u.u_segflg != 1) {
333 if (copyout(bp->b_un.b_addr+on, u.u_base, n)) {
334 u.u_error = EFAULT;
335 goto bad;
336 }
337 } else
338 bcopy(bp->b_un.b_addr + on, u.u_base, n);
339 u.u_base += n;
340 u.u_offset += n;
341 u.u_count -= n;
342bad:
343 ;
344#endif
345 }
346 if (n + on == bsize || u.u_offset == ip->i_size)
347 bp->b_flags |= B_AGE;
348 brelse(bp);
349 } while (u.u_error == 0 && u.u_count != 0 && n != 0);
350}
351
352/*
353 * Write the file corresponding to
354 * the inode pointed at by the argument.
355 * The actual write arguments are found
356 * in the variables:
357 * u_base core address for source
358 * u_offset byte offset in file
359 * u_count number of bytes to write
360 * u_segflg write to kernel/user/user I
361 */
362writei(ip)
363 register struct inode *ip;
364{
365 struct buf *bp;
366 register struct fs *fs;
367 dev_t dev;
368 daddr_t lbn, bn;
369 register int on, type;
370 register unsigned n;
371 long bsize;
372 int size, i, count;
373 extern int mem_no;
374
375 dev = (dev_t)ip->i_rdev;
376 if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
377 mem_no != major(dev)) ) {
378 u.u_error = EINVAL;
379 return;
380 }
381 type = ip->i_mode & IFMT;
382 if (type == IFCHR) {
383 ip->i_flag |= IUPD|ICHG;
cabdaec4 384 CHARGE(sc_tio * u.u_count);
ffe28cfe
BJ
385 (*cdevsw[major(dev)].d_write)(dev);
386 return;
387 }
388 if (u.u_count == 0)
389 return;
390 if ((ip->i_mode & IFMT) == IFREG &&
391 u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
392 psignal(u.u_procp, SIGXFSZ);
393 u.u_error = EMFILE;
394 return;
395 }
396 if (type!=IFBLK) {
397 dev = ip->i_dev;
398 fs = ip->i_fs;
399 bsize = fs->fs_bsize;
323f251c 400 } else
ffe28cfe 401 bsize = BLKDEV_IOSIZE;
ffe28cfe
BJ
402 do {
403 lbn = u.u_offset / bsize;
404 on = u.u_offset % bsize;
405 n = MIN((unsigned)(bsize - on), u.u_count);
406 if (type != IFBLK) {
407 bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
323f251c 408 if (u.u_error || (long)bn<0)
ffe28cfe
BJ
409 return;
410 if(u.u_offset + n > ip->i_size &&
411 (type == IFDIR || type == IFREG || type == IFLNK))
412 ip->i_size = u.u_offset + n;
413 size = blksize(fs, ip, lbn);
414 } else {
415 size = bsize;
416 bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
417 }
323f251c
BJ
418 count = howmany(size, DEV_BSIZE);
419 for (i = 0; i < count; i += CLSIZE)
420 if (mfind(dev, bn + i))
421 munhash(dev, bn + i);
422 if (n == bsize)
ffe28cfe
BJ
423 bp = getblk(dev, bn, size);
424 else
425 bp = bread(dev, bn, size);
426#ifdef UNFAST
427 iomove(bp->b_un.b_addr + on, n, B_WRITE);
428#else
429 if (u.u_segflg != 1) {
430 if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
431 u.u_error = EFAULT;
432 goto bad;
433 }
434 } else
435 bcopy(u.u_base, bp->b_un.b_addr + on, n);
436 u.u_base += n;
437 u.u_offset += n;
438 u.u_count -= n;
439bad:
440 ;
441#endif
442 if (u.u_error != 0)
443 brelse(bp);
444 else {
445 if ((ip->i_mode&IFMT) == IFDIR)
446 /*
447 * Writing to clear a directory entry.
448 * Must insure the write occurs before
449 * the inode is freed, or may end up
450 * pointing at a new (different) file
451 * if inode is quickly allocated again
452 * and system crashes.
453 */
454 bwrite(bp);
455 else if (n + on == bsize) {
456 bp->b_flags |= B_AGE;
457 bawrite(bp);
458 } else
459 bdwrite(bp);
460 }
461 ip->i_flag |= IUPD|ICHG;
462 if (u.u_ruid != 0)
463 ip->i_mode &= ~(ISUID|ISGID);
464 } while (u.u_error == 0 && u.u_count != 0);
465}
466
467/*
468 * Move n bytes at byte location
469 * &bp->b_un.b_addr[o] to/from (flag) the
470 * user/kernel (u.segflg) area starting at u.base.
471 * Update all the arguments by the number
472 * of bytes moved.
473 */
474iomove(cp, n, flag)
475 register caddr_t cp;
476 register unsigned n;
477{
478 register int t;
479
480 if (n==0)
481 return;
482 if (u.u_segflg != 1) {
483 if (flag==B_WRITE)
484 t = copyin(u.u_base, (caddr_t)cp, n);
485 else
486 t = copyout((caddr_t)cp, u.u_base, n);
487 if (t) {
488 u.u_error = EFAULT;
489 return;
490 }
491 } else
492 if (flag == B_WRITE)
493 bcopy(u.u_base, (caddr_t)cp, n);
494 else
495 bcopy((caddr_t)cp, u.u_base, n);
496 u.u_base += n;
497 u.u_offset += n;
498 u.u_count -= n;
499}