Commit | Line | Data |
---|---|---|
127f7d76 | 1 | /* kern_descrip.c 5.21 82/12/28 */ |
40056b21 BJ |
2 | |
3 | #include "../h/param.h" | |
4 | #include "../h/systm.h" | |
5 | #include "../h/dir.h" | |
6 | #include "../h/user.h" | |
3ebb7a40 | 7 | #include "../h/kernel.h" |
40056b21 BJ |
8 | #include "../h/inode.h" |
9 | #include "../h/proc.h" | |
40056b21 | 10 | #include "../h/conf.h" |
40056b21 | 11 | #include "../h/file.h" |
40056b21 BJ |
12 | #include "../h/socket.h" |
13 | #include "../h/socketvar.h" | |
4147b3f6 BJ |
14 | #include "../h/mount.h" |
15 | ||
16 | #include "../h/descrip.h" | |
17 | ||
18 | /* | |
19 | * Descriptor management. | |
20 | */ | |
21 | ||
22 | /* | |
23 | * TODO: | |
24 | * getf should be renamed | |
25 | * ufalloc side effects are gross | |
26 | */ | |
40056b21 BJ |
27 | |
28 | /* | |
4147b3f6 | 29 | * System calls on descriptors. |
40056b21 | 30 | */ |
3ebb7a40 | 31 | getdtablesize() |
4147b3f6 BJ |
32 | { |
33 | ||
34 | u.u_r.r_val1 = NOFILE; | |
35 | } | |
36 | ||
27b91f59 BJ |
37 | getdprop() |
38 | { | |
39 | register struct a { | |
40 | int d; | |
41 | struct dtype *dtypeb; | |
42 | } *uap = (struct a *)u.u_ap; | |
43 | register struct file *fp; | |
44 | struct dtype adtype; | |
45 | ||
46 | fp = getf(uap->d); | |
47 | if (fp == 0) | |
48 | return; | |
49 | adtype.dt_type = 0; /* XXX */ | |
50 | adtype.dt_protocol = 0; /* XXX */ | |
127f7d76 SL |
51 | u.u_error = copyout((caddr_t)&adtype, (caddr_t)uap->dtypeb, |
52 | sizeof (struct dtype)); | |
53 | if (u.u_error) | |
27b91f59 | 54 | return; |
27b91f59 BJ |
55 | } |
56 | ||
57 | getdopt() | |
58 | { | |
59 | ||
60 | } | |
61 | ||
62 | setdopt() | |
63 | { | |
64 | ||
65 | } | |
66 | ||
40056b21 BJ |
67 | dup() |
68 | { | |
4147b3f6 BJ |
69 | register struct a { |
70 | int i; | |
71 | } *uap = (struct a *) u.u_ap; | |
a81e9a81 SL |
72 | struct file *fp; |
73 | int j; | |
4147b3f6 BJ |
74 | |
75 | if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */ | |
76 | ||
77 | fp = getf(uap->i); | |
78 | if (fp == 0) | |
79 | return; | |
80 | j = ufalloc(); | |
81 | if (j < 0) | |
82 | return; | |
3650c37d | 83 | dupit(j, fp, u.u_pofile[uap->i] & (UF_SHLOCK|UF_EXLOCK)); |
4147b3f6 BJ |
84 | } |
85 | ||
86 | dup2() | |
87 | { | |
40056b21 | 88 | register struct a { |
4147b3f6 BJ |
89 | int i, j; |
90 | } *uap = (struct a *) u.u_ap; | |
91 | register struct file *fp; | |
40056b21 | 92 | |
4147b3f6 BJ |
93 | fp = getf(uap->i); |
94 | if (fp == 0) | |
95 | return; | |
96 | if (uap->j < 0 || uap->j >= NOFILE) { | |
97 | u.u_error = EBADF; | |
40056b21 | 98 | return; |
40056b21 | 99 | } |
4147b3f6 BJ |
100 | u.u_r.r_val1 = uap->j; |
101 | if (uap->i == uap->j) | |
102 | return; | |
103 | if (u.u_ofile[uap->j]) { | |
67fc76c5 BJ |
104 | if (u.u_pofile[uap->j] & UF_MAPPED) |
105 | munmapfd(uap->j); | |
a81e9a81 | 106 | closef(u.u_ofile[uap->j], 0, u.u_pofile[uap->j]); |
40056b21 BJ |
107 | if (u.u_error) |
108 | return; | |
4147b3f6 | 109 | /* u.u_ofile[uap->j] = 0; */ |
a81e9a81 | 110 | /* u.u_pofile[uap->j] = 0; */ |
4147b3f6 | 111 | } |
3650c37d | 112 | dupit(uap->j, fp, u.u_pofile[uap->i] & (UF_SHLOCK|UF_EXLOCK)); |
a81e9a81 SL |
113 | } |
114 | ||
115 | dupit(fd, fp, lockflags) | |
116 | int fd; | |
117 | register struct file *fp; | |
118 | register int lockflags; | |
119 | { | |
120 | ||
121 | u.u_ofile[fd] = fp; | |
122 | u.u_pofile[fd] = lockflags; | |
4147b3f6 | 123 | fp->f_count++; |
3650c37d | 124 | if (lockflags&UF_SHLOCK) |
4f083fd7 | 125 | fp->f_inode->i_shlockc++; |
3650c37d | 126 | if (lockflags&UF_EXLOCK) |
4f083fd7 | 127 | fp->f_inode->i_exlockc++; |
4147b3f6 BJ |
128 | } |
129 | ||
130 | close() | |
131 | { | |
132 | register struct a { | |
133 | int i; | |
134 | } *uap = (struct a *)u.u_ap; | |
135 | register struct file *fp; | |
136 | ||
137 | fp = getf(uap->i); | |
138 | if (fp == 0) | |
139 | return; | |
67fc76c5 BJ |
140 | #ifdef SUNMMAP |
141 | if (u.u_pofile[uap->i] & UF_MAPPED) | |
142 | munmapfd(uap->i); | |
143 | #endif | |
a81e9a81 | 144 | closef(fp, 0, u.u_pofile[uap->i]); |
4147b3f6 | 145 | /* WHAT IF u.u_error ? */ |
a81e9a81 SL |
146 | u.u_ofile[uap->i] = NULL; |
147 | u.u_pofile[uap->i] = 0; | |
4147b3f6 BJ |
148 | } |
149 | ||
3ebb7a40 | 150 | wrap() |
4147b3f6 BJ |
151 | { |
152 | register struct a { | |
153 | int d; | |
154 | struct dtype *dtypeb; | |
155 | } *uap = (struct a *)u.u_ap; | |
156 | register struct file *fp; | |
157 | struct dtype adtype; | |
158 | ||
159 | fp = getf(uap->d); | |
160 | if (fp == 0) | |
161 | return; | |
127f7d76 SL |
162 | u.u_error = copyin((caddr_t)uap->dtypeb, (caddr_t)&adtype, |
163 | sizeof (struct dtype)); | |
164 | if (u.u_error) | |
4147b3f6 | 165 | return; |
4147b3f6 BJ |
166 | /* DO WRAP */ |
167 | } | |
168 | ||
12438177 | 169 | int unselect(); |
40056b21 BJ |
170 | int nselcoll; |
171 | /* | |
172 | * Select system call. | |
173 | */ | |
27b91f59 | 174 | select() |
40056b21 BJ |
175 | { |
176 | register struct uap { | |
e42abae7 BJ |
177 | int nd; |
178 | long *in; | |
179 | long *ou; | |
180 | long *ex; | |
3ebb7a40 BJ |
181 | struct timeval *tv; |
182 | } *uap = (struct uap *)u.u_ap; | |
12438177 BJ |
183 | int ibits[3], obits[3]; |
184 | struct timeval atv; | |
a8d3bf7f | 185 | int s, ncoll; |
12438177 | 186 | label_t lqsave; |
40056b21 | 187 | |
ea795ba9 | 188 | obits[0] = obits[1] = obits[2] = 0; |
75c65d6e BJ |
189 | if (uap->nd > NOFILE) |
190 | uap->nd = NOFILE; /* forgiving, if slightly wrong */ | |
e42abae7 BJ |
191 | |
192 | #define getbits(name, x) \ | |
193 | if (uap->name) { \ | |
127f7d76 SL |
194 | u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \ |
195 | sizeof (ibits[x])); \ | |
196 | if (u.u_error) \ | |
ea795ba9 | 197 | goto done; \ |
e42abae7 BJ |
198 | } else \ |
199 | ibits[x] = 0; | |
200 | getbits(in, 0); | |
201 | getbits(ou, 1); | |
202 | getbits(ex, 2); | |
203 | #undef getbits | |
204 | ||
3ebb7a40 | 205 | if (uap->tv) { |
127f7d76 SL |
206 | u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv, |
207 | sizeof (atv)); | |
208 | if (u.u_error) | |
ea795ba9 | 209 | goto done; |
12438177 BJ |
210 | if (itimerfix(&atv)) { |
211 | u.u_error = EINVAL; | |
ea795ba9 | 212 | goto done; |
12438177 BJ |
213 | } |
214 | s = spl7(); timevaladd(&atv, &time); splx(s); | |
215 | } | |
40056b21 BJ |
216 | retry: |
217 | ncoll = nselcoll; | |
218 | u.u_procp->p_flag |= SSEL; | |
12438177 | 219 | u.u_r.r_val1 = selscan(ibits, obits); |
ea795ba9 | 220 | if (u.u_error || u.u_r.r_val1) |
40056b21 BJ |
221 | goto done; |
222 | s = spl6(); | |
e42abae7 | 223 | if (uap->tv && timercmp(&time, &atv, >=)) { |
12438177 BJ |
224 | splx(s); |
225 | goto done; | |
226 | } | |
40056b21 BJ |
227 | if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) { |
228 | u.u_procp->p_flag &= ~SSEL; | |
229 | splx(s); | |
230 | goto retry; | |
231 | } | |
232 | u.u_procp->p_flag &= ~SSEL; | |
12438177 BJ |
233 | if (uap->tv) { |
234 | lqsave = u.u_qsave; | |
235 | if (setjmp(&u.u_qsave)) { | |
b32450f4 | 236 | untimeout(unselect, (caddr_t)u.u_procp); |
12438177 BJ |
237 | u.u_error = EINTR; |
238 | splx(s); | |
ea795ba9 | 239 | goto done; |
12438177 | 240 | } |
b32450f4 | 241 | timeout(unselect, (caddr_t)u.u_procp, hzto(&atv)); |
12438177 BJ |
242 | } |
243 | sleep((caddr_t)&selwait, PZERO+1); | |
244 | if (uap->tv) { | |
245 | u.u_qsave = lqsave; | |
b32450f4 | 246 | untimeout(unselect, (caddr_t)u.u_procp); |
12438177 | 247 | } |
40056b21 | 248 | splx(s); |
12438177 BJ |
249 | goto retry; |
250 | done: | |
e42abae7 BJ |
251 | #define putbits(name, x) \ |
252 | if (uap->name) { \ | |
127f7d76 SL |
253 | int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \ |
254 | sizeof (obits[x])); \ | |
255 | if (error) \ | |
256 | u.u_error = error; \ | |
12438177 | 257 | } |
e42abae7 BJ |
258 | putbits(in, 0); |
259 | putbits(ou, 1); | |
260 | putbits(ex, 2); | |
261 | #undef putbits | |
12438177 BJ |
262 | } |
263 | ||
264 | unselect(p) | |
265 | register struct proc *p; | |
266 | { | |
267 | register int s = spl6(); | |
40056b21 | 268 | |
12438177 BJ |
269 | switch (p->p_stat) { |
270 | ||
271 | case SSLEEP: | |
272 | setrun(p); | |
273 | break; | |
274 | ||
275 | case SSTOP: | |
276 | unsleep(p); | |
40056b21 BJ |
277 | break; |
278 | } | |
12438177 | 279 | splx(s); |
40056b21 BJ |
280 | } |
281 | ||
12438177 BJ |
282 | selscan(ibits, obits) |
283 | int *ibits, *obits; | |
40056b21 | 284 | { |
12438177 BJ |
285 | register int which, bits, i; |
286 | int flag; | |
40056b21 | 287 | struct file *fp; |
12438177 | 288 | int able; |
40056b21 | 289 | struct inode *ip; |
12438177 | 290 | int n = 0; |
40056b21 | 291 | |
12438177 BJ |
292 | for (which = 0; which < 3; which++) { |
293 | bits = ibits[which]; | |
294 | obits[which] = 0; | |
295 | switch (which) { | |
296 | ||
297 | case 0: | |
298 | flag = FREAD; break; | |
40056b21 | 299 | |
12438177 BJ |
300 | case 1: |
301 | flag = FWRITE; break; | |
302 | ||
303 | case 2: | |
304 | flag = 0; break; | |
305 | } | |
306 | while (i = ffs(bits)) { | |
307 | bits &= ~(1<<(i-1)); | |
308 | fp = u.u_ofile[i-1]; | |
309 | if (fp == NULL) { | |
310 | u.u_error = EBADF; | |
40056b21 BJ |
311 | break; |
312 | } | |
12438177 BJ |
313 | if (fp->f_type == DTYPE_SOCKET) |
314 | able = soselect(fp->f_socket, flag); | |
315 | else { | |
316 | ip = fp->f_inode; | |
317 | switch (ip->i_mode & IFMT) { | |
318 | ||
319 | case IFCHR: | |
320 | able = | |
321 | (*cdevsw[major(ip->i_rdev)].d_select) | |
322 | (ip->i_rdev, flag); | |
323 | break; | |
324 | ||
325 | case IFBLK: | |
326 | case IFREG: | |
327 | case IFDIR: | |
328 | able = 1; | |
329 | break; | |
330 | } | |
4147b3f6 | 331 | |
12438177 BJ |
332 | } |
333 | if (able) { | |
334 | obits[which] |= (1<<(i-1)); | |
335 | n++; | |
336 | } | |
40056b21 BJ |
337 | } |
338 | } | |
12438177 | 339 | return (n); |
40056b21 BJ |
340 | } |
341 | ||
342 | /*ARGSUSED*/ | |
343 | seltrue(dev, flag) | |
344 | dev_t dev; | |
345 | int flag; | |
346 | { | |
347 | ||
348 | return (1); | |
349 | } | |
350 | ||
351 | selwakeup(p, coll) | |
352 | register struct proc *p; | |
353 | int coll; | |
354 | { | |
355 | int s; | |
356 | ||
357 | if (coll) { | |
358 | nselcoll++; | |
359 | wakeup((caddr_t)&selwait); | |
360 | } | |
361 | if (p) { | |
362 | if (p->p_wchan == (caddr_t)&selwait) | |
363 | setrun(p); | |
364 | else { | |
365 | s = spl6(); | |
366 | if (p->p_flag & SSEL) | |
367 | p->p_flag &= ~SSEL; | |
368 | splx(s); | |
369 | } | |
370 | } | |
371 | } | |
372 | ||
3ebb7a40 BJ |
373 | revoke() |
374 | { | |
375 | ||
376 | /* XXX */ | |
377 | } | |
378 | ||
40056b21 | 379 | /* |
4147b3f6 | 380 | * Allocate a user file descriptor. |
40056b21 | 381 | */ |
4147b3f6 BJ |
382 | ufalloc() |
383 | { | |
384 | register i; | |
385 | ||
386 | for (i=0; i<NOFILE; i++) | |
387 | if (u.u_ofile[i] == NULL) { | |
388 | u.u_r.r_val1 = i; | |
389 | u.u_pofile[i] = 0; | |
390 | return (i); | |
391 | } | |
392 | u.u_error = EMFILE; | |
393 | return (-1); | |
394 | } | |
395 | ||
396 | struct file *lastf; | |
397 | /* | |
398 | * Allocate a user file descriptor | |
399 | * and a file structure. | |
400 | * Initialize the descriptor | |
401 | * to point at the file structure. | |
402 | */ | |
403 | struct file * | |
404 | falloc() | |
405 | { | |
406 | register struct file *fp; | |
407 | register i; | |
408 | ||
409 | i = ufalloc(); | |
410 | if (i < 0) | |
411 | return (NULL); | |
412 | if (lastf == 0) | |
413 | lastf = file; | |
414 | for (fp = lastf; fp < fileNFILE; fp++) | |
415 | if (fp->f_count == 0) | |
416 | goto slot; | |
417 | for (fp = file; fp < lastf; fp++) | |
418 | if (fp->f_count == 0) | |
419 | goto slot; | |
420 | tablefull("file"); | |
421 | u.u_error = ENFILE; | |
422 | return (NULL); | |
423 | slot: | |
424 | u.u_ofile[i] = fp; | |
425 | fp->f_count++; | |
426 | fp->f_offset = 0; | |
427 | fp->f_inode = 0; | |
428 | lastf = fp + 1; | |
429 | return (fp); | |
430 | } | |
431 | /* | |
432 | * Convert a user supplied file descriptor into a pointer | |
433 | * to a file structure. Only task is to check range of the descriptor. | |
434 | * Critical paths should use the GETF macro, defined in inline.h. | |
435 | */ | |
436 | struct file * | |
437 | getf(f) | |
438 | register int f; | |
40056b21 BJ |
439 | { |
440 | register struct file *fp; | |
40056b21 | 441 | |
4147b3f6 BJ |
442 | if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) { |
443 | u.u_error = EBADF; | |
444 | return (NULL); | |
445 | } | |
446 | return (fp); | |
447 | } | |
448 | ||
449 | /* | |
450 | * Internal form of close. | |
451 | * Decrement reference count on | |
452 | * file structure. | |
453 | * Also make sure the pipe protocol | |
454 | * does not constipate. | |
455 | * | |
456 | * Decrement reference count on the inode following | |
457 | * removal to the referencing file structure. | |
458 | * Call device handler on last close. | |
459 | * Nouser indicates that the user isn't available to present | |
460 | * errors to. | |
a81e9a81 SL |
461 | * |
462 | * Handling locking at this level is RIDICULOUS. | |
4147b3f6 | 463 | */ |
a81e9a81 | 464 | closef(fp, nouser, flags) |
4147b3f6 | 465 | register struct file *fp; |
a81e9a81 | 466 | int nouser, flags; |
4147b3f6 BJ |
467 | { |
468 | register struct inode *ip; | |
469 | register struct mount *mp; | |
470 | int flag, mode; | |
471 | dev_t dev; | |
472 | register int (*cfunc)(); | |
473 | ||
40056b21 BJ |
474 | if (fp == NULL) |
475 | return; | |
4147b3f6 BJ |
476 | if (fp->f_count > 1) { |
477 | fp->f_count--; | |
40056b21 BJ |
478 | return; |
479 | } | |
4147b3f6 | 480 | if (fp->f_type == DTYPE_SOCKET) { |
6e7edb25 | 481 | u.u_error = soclose(fp->f_socket, nouser); |
4147b3f6 BJ |
482 | if (nouser == 0 && u.u_error) |
483 | return; | |
484 | fp->f_socket = 0; | |
485 | fp->f_count = 0; | |
486 | return; | |
487 | } | |
488 | flag = fp->f_flag; | |
489 | ip = fp->f_inode; | |
490 | dev = (dev_t)ip->i_rdev; | |
491 | mode = ip->i_mode & IFMT; | |
3650c37d | 492 | flags &= UF_SHLOCK|UF_EXLOCK; /* conservative */ |
a81e9a81 SL |
493 | if (flags) |
494 | funlocki(ip, flags); | |
4147b3f6 BJ |
495 | ilock(ip); |
496 | iput(ip); | |
497 | fp->f_count = 0; | |
498 | ||
499 | switch (mode) { | |
500 | ||
501 | case IFCHR: | |
502 | cfunc = cdevsw[major(dev)].d_close; | |
4147b3f6 BJ |
503 | break; |
504 | ||
505 | case IFBLK: | |
506 | /* | |
507 | * We don't want to really close the device if it is mounted | |
508 | */ | |
509 | for (mp = mount; mp < &mount[NMOUNT]; mp++) | |
510 | if (mp->m_bufp != NULL && mp->m_dev == dev) | |
511 | return; | |
512 | cfunc = bdevsw[major(dev)].d_close; | |
513 | break; | |
514 | ||
515 | default: | |
516 | return; | |
517 | } | |
518 | for (fp = file; fp < fileNFILE; fp++) { | |
519 | if (fp->f_type == DTYPE_SOCKET) /* XXX */ | |
520 | continue; | |
521 | if (fp->f_count && (ip = fp->f_inode) && | |
522 | ip->i_rdev == dev && (ip->i_mode&IFMT) == mode) | |
523 | return; | |
524 | } | |
525 | if (mode == IFBLK) { | |
526 | /* | |
527 | * On last close of a block device (that isn't mounted) | |
528 | * we must invalidate any in core blocks | |
529 | */ | |
530 | bflush(dev); | |
531 | binval(dev); | |
532 | } | |
533 | (*cfunc)(dev, flag, fp); | |
534 | } | |
8d528261 BJ |
535 | |
536 | opause() | |
537 | { | |
538 | ||
539 | for (;;) | |
540 | sleep((caddr_t)&u, PSLEP); | |
541 | } |