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