Commit | Line | Data |
---|---|---|
55dfda24 | 1 | /* kern_descrip.c 5.26 83/06/14 */ |
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 | 14 | #include "../h/mount.h" |
92438dfc | 15 | #include "../h/stat.h" |
4147b3f6 | 16 | |
88a7a62a | 17 | #include "../h/ioctl.h" |
4147b3f6 BJ |
18 | |
19 | /* | |
20 | * Descriptor management. | |
21 | */ | |
22 | ||
23 | /* | |
24 | * TODO: | |
88a7a62a SL |
25 | * increase NOFILE |
26 | * eliminate u.u_error side effects | |
4147b3f6 | 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 | getdopt() |
39 | { | |
40 | ||
41 | } | |
42 | ||
43 | setdopt() | |
44 | { | |
45 | ||
46 | } | |
47 | ||
40056b21 BJ |
48 | dup() |
49 | { | |
4147b3f6 BJ |
50 | register struct a { |
51 | int i; | |
52 | } *uap = (struct a *) u.u_ap; | |
a81e9a81 SL |
53 | struct file *fp; |
54 | int j; | |
4147b3f6 BJ |
55 | |
56 | if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */ | |
57 | ||
58 | fp = getf(uap->i); | |
59 | if (fp == 0) | |
60 | return; | |
88a7a62a | 61 | j = ufalloc(0); |
4147b3f6 BJ |
62 | if (j < 0) |
63 | return; | |
88a7a62a | 64 | dupit(j, fp, u.u_pofile[uap->i]); |
4147b3f6 BJ |
65 | } |
66 | ||
67 | dup2() | |
68 | { | |
40056b21 | 69 | register struct a { |
4147b3f6 BJ |
70 | int i, j; |
71 | } *uap = (struct a *) u.u_ap; | |
72 | register struct file *fp; | |
40056b21 | 73 | |
4147b3f6 BJ |
74 | fp = getf(uap->i); |
75 | if (fp == 0) | |
76 | return; | |
77 | if (uap->j < 0 || uap->j >= NOFILE) { | |
78 | u.u_error = EBADF; | |
40056b21 | 79 | return; |
40056b21 | 80 | } |
4147b3f6 BJ |
81 | u.u_r.r_val1 = uap->j; |
82 | if (uap->i == uap->j) | |
83 | return; | |
84 | if (u.u_ofile[uap->j]) { | |
67fc76c5 BJ |
85 | if (u.u_pofile[uap->j] & UF_MAPPED) |
86 | munmapfd(uap->j); | |
55dfda24 | 87 | closef(u.u_ofile[uap->j]); |
40056b21 BJ |
88 | if (u.u_error) |
89 | return; | |
4147b3f6 | 90 | } |
88a7a62a | 91 | dupit(uap->j, fp, u.u_pofile[uap->i]); |
a81e9a81 SL |
92 | } |
93 | ||
55dfda24 | 94 | dupit(fd, fp, flags) |
a81e9a81 SL |
95 | int fd; |
96 | register struct file *fp; | |
55dfda24 | 97 | register int flags; |
a81e9a81 SL |
98 | { |
99 | ||
100 | u.u_ofile[fd] = fp; | |
55dfda24 | 101 | u.u_pofile[fd] = flags; |
4147b3f6 BJ |
102 | fp->f_count++; |
103 | } | |
104 | ||
88a7a62a SL |
105 | /* |
106 | * The file control system call. | |
107 | */ | |
108 | fcntl() | |
4147b3f6 | 109 | { |
4147b3f6 | 110 | register struct file *fp; |
4147b3f6 | 111 | register struct a { |
88a7a62a SL |
112 | int fdes; |
113 | int cmd; | |
114 | int arg; | |
115 | } *uap; | |
116 | register i; | |
117 | register char *pop; | |
4147b3f6 | 118 | |
88a7a62a SL |
119 | uap = (struct a *)u.u_ap; |
120 | fp = getf(uap->fdes); | |
121 | if (fp == NULL) | |
4147b3f6 | 122 | return; |
88a7a62a SL |
123 | pop = &u.u_pofile[uap->fdes]; |
124 | switch(uap->cmd) { | |
125 | case 0: | |
126 | i = uap->arg; | |
127 | if (i < 0 || i > NOFILE) { | |
12438177 | 128 | u.u_error = EINVAL; |
88a7a62a | 129 | return; |
12438177 | 130 | } |
88a7a62a SL |
131 | if ((i = ufalloc(i)) < 0) |
132 | return; | |
133 | dupit(i, fp, *pop); | |
134 | break; | |
12438177 | 135 | |
88a7a62a SL |
136 | case 1: |
137 | u.u_r.r_val1 = *pop & 1; | |
138 | break; | |
40056b21 | 139 | |
88a7a62a SL |
140 | case 2: |
141 | *pop = (*pop &~ 1) | (uap->arg & 1); | |
142 | break; | |
12438177 | 143 | |
88a7a62a SL |
144 | case 3: |
145 | u.u_r.r_val1 = fp->f_flag+FOPEN; | |
12438177 BJ |
146 | break; |
147 | ||
88a7a62a SL |
148 | case 4: |
149 | fp->f_flag &= FCNTLCANT; | |
150 | fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT; | |
151 | u.u_error = fset(fp, FNDELAY, fp->f_flag & FNDELAY); | |
152 | if (u.u_error) | |
153 | break; | |
154 | u.u_error = fset(fp, FASYNC, fp->f_flag & FASYNC); | |
155 | if (u.u_error) | |
156 | (void) fset(fp, FNDELAY, 0); | |
40056b21 | 157 | break; |
88a7a62a SL |
158 | |
159 | case 5: | |
160 | u.u_error = fsetown(fp, uap->arg); | |
161 | break; | |
162 | ||
163 | case 6: | |
164 | u.u_error = fgetown(fp, &u.u_r.r_val1); | |
165 | break; | |
166 | ||
167 | default: | |
168 | u.u_error = EINVAL; | |
40056b21 | 169 | } |
40056b21 BJ |
170 | } |
171 | ||
88a7a62a | 172 | fset(fp, bit, value) |
40056b21 | 173 | struct file *fp; |
88a7a62a SL |
174 | int bit, value; |
175 | { | |
40056b21 | 176 | |
88a7a62a SL |
177 | if (value) |
178 | fp->f_flag |= bit; | |
179 | else | |
180 | fp->f_flag &= ~bit; | |
181 | return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC), | |
182 | (caddr_t)&value)); | |
183 | } | |
12438177 | 184 | |
88a7a62a SL |
185 | fgetown(fp, valuep) |
186 | struct file *fp; | |
187 | int *valuep; | |
188 | { | |
189 | int error; | |
40056b21 | 190 | |
88a7a62a | 191 | switch (fp->f_type) { |
12438177 | 192 | |
88a7a62a SL |
193 | case DTYPE_SOCKET: |
194 | *valuep = ((struct socket *)fp->f_data)->so_pgrp; | |
195 | return (0); | |
196 | ||
197 | default: | |
198 | error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep); | |
199 | *valuep = -*valuep; | |
200 | return (error); | |
40056b21 | 201 | } |
40056b21 BJ |
202 | } |
203 | ||
88a7a62a SL |
204 | fsetown(fp, value) |
205 | struct file *fp; | |
206 | int value; | |
40056b21 BJ |
207 | { |
208 | ||
88a7a62a SL |
209 | if (fp->f_type == DTYPE_SOCKET) { |
210 | ((struct socket *)fp->f_data)->so_pgrp = value; | |
211 | return (0); | |
212 | } | |
213 | if (value > 0) { | |
214 | struct proc *p = pfind(value); | |
215 | if (p == 0) | |
216 | return (EINVAL); | |
217 | value = p->p_pgrp; | |
218 | } else | |
219 | value = -value; | |
220 | return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value)); | |
40056b21 BJ |
221 | } |
222 | ||
88a7a62a SL |
223 | fioctl(fp, cmd, value) |
224 | struct file *fp; | |
225 | int cmd; | |
226 | caddr_t value; | |
40056b21 | 227 | { |
40056b21 | 228 | |
88a7a62a | 229 | return ((*fp->f_ops->fo_ioctl)(fp, cmd, value)); |
40056b21 BJ |
230 | } |
231 | ||
88a7a62a | 232 | close() |
3ebb7a40 | 233 | { |
88a7a62a SL |
234 | register struct a { |
235 | int i; | |
236 | } *uap = (struct a *)u.u_ap; | |
237 | register struct file *fp; | |
92438dfc | 238 | register u_char *pf; |
3ebb7a40 | 239 | |
88a7a62a SL |
240 | fp = getf(uap->i); |
241 | if (fp == 0) | |
242 | return; | |
92438dfc SL |
243 | pf = (u_char *)&u.u_pofile[uap->i]; |
244 | if (*pf & UF_MAPPED) | |
88a7a62a | 245 | munmapfd(uap->i); |
92438dfc | 246 | closef(fp); |
88a7a62a SL |
247 | /* WHAT IF u.u_error ? */ |
248 | u.u_ofile[uap->i] = NULL; | |
92438dfc SL |
249 | *pf = 0; |
250 | } | |
251 | ||
252 | fstat() | |
253 | { | |
254 | register struct file *fp; | |
255 | register struct a { | |
256 | int fdes; | |
257 | struct stat *sb; | |
258 | } *uap; | |
259 | struct stat ub; | |
260 | ||
261 | uap = (struct a *)u.u_ap; | |
262 | fp = getf(uap->fdes); | |
263 | if (fp == 0) | |
264 | return; | |
265 | switch (fp->f_type) { | |
266 | ||
267 | case DTYPE_INODE: | |
268 | u.u_error = ino_stat((struct inode *)fp->f_data, &ub); | |
269 | break; | |
270 | ||
271 | case DTYPE_SOCKET: | |
272 | u.u_error = soo_stat((struct socket *)fp->f_data, &ub); | |
273 | break; | |
274 | ||
275 | default: | |
276 | panic("fstat"); | |
277 | /*NOTREACHED*/ | |
278 | } | |
279 | if (u.u_error == 0) | |
55dfda24 SL |
280 | u.u_error = copyout((caddr_t)&ub, (caddr_t)uap->sb, |
281 | sizeof (ub)); | |
3ebb7a40 BJ |
282 | } |
283 | ||
40056b21 | 284 | /* |
4147b3f6 | 285 | * Allocate a user file descriptor. |
40056b21 | 286 | */ |
88a7a62a SL |
287 | ufalloc(i) |
288 | register int i; | |
4147b3f6 | 289 | { |
4147b3f6 | 290 | |
88a7a62a | 291 | for (; i < NOFILE; i++) |
4147b3f6 BJ |
292 | if (u.u_ofile[i] == NULL) { |
293 | u.u_r.r_val1 = i; | |
294 | u.u_pofile[i] = 0; | |
295 | return (i); | |
296 | } | |
297 | u.u_error = EMFILE; | |
298 | return (-1); | |
299 | } | |
300 | ||
88a7a62a SL |
301 | ufavail() |
302 | { | |
303 | register int i, avail = 0; | |
304 | ||
305 | for (i = 0; i < NOFILE; i++) | |
306 | if (u.u_ofile[i] == NULL) | |
307 | avail++; | |
308 | return (avail); | |
309 | } | |
310 | ||
4147b3f6 BJ |
311 | struct file *lastf; |
312 | /* | |
313 | * Allocate a user file descriptor | |
314 | * and a file structure. | |
315 | * Initialize the descriptor | |
316 | * to point at the file structure. | |
317 | */ | |
318 | struct file * | |
319 | falloc() | |
320 | { | |
321 | register struct file *fp; | |
322 | register i; | |
323 | ||
88a7a62a | 324 | i = ufalloc(0); |
4147b3f6 BJ |
325 | if (i < 0) |
326 | return (NULL); | |
327 | if (lastf == 0) | |
328 | lastf = file; | |
329 | for (fp = lastf; fp < fileNFILE; fp++) | |
330 | if (fp->f_count == 0) | |
331 | goto slot; | |
332 | for (fp = file; fp < lastf; fp++) | |
333 | if (fp->f_count == 0) | |
334 | goto slot; | |
335 | tablefull("file"); | |
336 | u.u_error = ENFILE; | |
337 | return (NULL); | |
338 | slot: | |
339 | u.u_ofile[i] = fp; | |
88a7a62a SL |
340 | fp->f_count = 1; |
341 | fp->f_data = 0; | |
4147b3f6 | 342 | fp->f_offset = 0; |
4147b3f6 BJ |
343 | lastf = fp + 1; |
344 | return (fp); | |
345 | } | |
88a7a62a | 346 | |
4147b3f6 BJ |
347 | /* |
348 | * Convert a user supplied file descriptor into a pointer | |
349 | * to a file structure. Only task is to check range of the descriptor. | |
88a7a62a | 350 | * Critical paths should use the GETF macro. |
4147b3f6 BJ |
351 | */ |
352 | struct file * | |
353 | getf(f) | |
354 | register int f; | |
40056b21 BJ |
355 | { |
356 | register struct file *fp; | |
40056b21 | 357 | |
4147b3f6 BJ |
358 | if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) { |
359 | u.u_error = EBADF; | |
360 | return (NULL); | |
361 | } | |
362 | return (fp); | |
363 | } | |
364 | ||
365 | /* | |
366 | * Internal form of close. | |
88a7a62a SL |
367 | * Decrement reference count on file structure. |
368 | * If last reference not going away, but no more | |
369 | * references except in message queues, run a | |
370 | * garbage collect. This would better be done by | |
371 | * forcing a gc() to happen sometime soon, rather | |
372 | * than running one each time. | |
4147b3f6 | 373 | */ |
92438dfc | 374 | closef(fp) |
4147b3f6 BJ |
375 | register struct file *fp; |
376 | { | |
4147b3f6 | 377 | |
40056b21 BJ |
378 | if (fp == NULL) |
379 | return; | |
4147b3f6 BJ |
380 | if (fp->f_count > 1) { |
381 | fp->f_count--; | |
88a7a62a SL |
382 | if (fp->f_count == fp->f_msgcount) |
383 | unp_gc(); | |
40056b21 BJ |
384 | return; |
385 | } | |
92438dfc | 386 | (*fp->f_ops->fo_close)(fp); |
4147b3f6 | 387 | fp->f_count = 0; |
8d528261 | 388 | } |
92438dfc SL |
389 | |
390 | /* | |
391 | * Apply an advisory lock on a file descriptor. | |
392 | */ | |
393 | flock() | |
394 | { | |
395 | register struct a { | |
396 | int fd; | |
397 | int how; | |
398 | } *uap = (struct a *)u.u_ap; | |
399 | register struct file *fp; | |
92438dfc SL |
400 | |
401 | fp = getf(uap->fd); | |
402 | if (fp == NULL) | |
403 | return; | |
55dfda24 SL |
404 | if (fp->f_type != DTYPE_INODE) { |
405 | u.u_error = EOPNOTSUPP; | |
92438dfc SL |
406 | return; |
407 | } | |
55dfda24 SL |
408 | if (uap->how & LOCK_UN) { |
409 | ino_unlock(fp, FSHLOCK|FEXLOCK); | |
92438dfc | 410 | return; |
92438dfc | 411 | } |
55dfda24 SL |
412 | /* avoid work... */ |
413 | if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) || | |
414 | (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH)) | |
92438dfc | 415 | return; |
55dfda24 | 416 | u.u_error = ino_lock(fp, uap->how); |
92438dfc | 417 | } |