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