Commit | Line | Data |
---|---|---|
da7c5cc6 KM |
1 | /* |
2 | * Copyright (c) 1982 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
0aae4319 | 6 | * @(#)kern_descrip.c 6.13 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
40056b21 | 8 | |
94368568 JB |
9 | #include "param.h" |
10 | #include "systm.h" | |
11 | #include "dir.h" | |
12 | #include "user.h" | |
13 | #include "kernel.h" | |
14 | #include "inode.h" | |
15 | #include "proc.h" | |
94368568 JB |
16 | #include "file.h" |
17 | #include "socket.h" | |
18 | #include "socketvar.h" | |
19 | #include "mount.h" | |
20 | #include "stat.h" | |
4147b3f6 | 21 | |
94368568 | 22 | #include "ioctl.h" |
4147b3f6 BJ |
23 | |
24 | /* | |
25 | * Descriptor management. | |
26 | */ | |
27 | ||
28 | /* | |
29 | * TODO: | |
88a7a62a | 30 | * eliminate u.u_error side effects |
4147b3f6 | 31 | */ |
40056b21 BJ |
32 | |
33 | /* | |
4147b3f6 | 34 | * System calls on descriptors. |
40056b21 | 35 | */ |
3ebb7a40 | 36 | getdtablesize() |
4147b3f6 BJ |
37 | { |
38 | ||
39 | u.u_r.r_val1 = NOFILE; | |
40 | } | |
41 | ||
27b91f59 BJ |
42 | getdopt() |
43 | { | |
44 | ||
45 | } | |
46 | ||
47 | setdopt() | |
48 | { | |
49 | ||
50 | } | |
51 | ||
40056b21 BJ |
52 | dup() |
53 | { | |
4147b3f6 BJ |
54 | register struct a { |
55 | int i; | |
56 | } *uap = (struct a *) u.u_ap; | |
a81e9a81 SL |
57 | struct file *fp; |
58 | int j; | |
4147b3f6 BJ |
59 | |
60 | if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */ | |
61 | ||
21e0a474 | 62 | GETF(fp, uap->i); |
88a7a62a | 63 | j = ufalloc(0); |
4147b3f6 BJ |
64 | if (j < 0) |
65 | return; | |
c05c2528 | 66 | dupit(j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); |
4147b3f6 BJ |
67 | } |
68 | ||
69 | dup2() | |
70 | { | |
40056b21 | 71 | register struct a { |
4147b3f6 BJ |
72 | int i, j; |
73 | } *uap = (struct a *) u.u_ap; | |
74 | register struct file *fp; | |
40056b21 | 75 | |
21e0a474 | 76 | GETF(fp, uap->i); |
4147b3f6 BJ |
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 | } |
c05c2528 | 91 | dupit(uap->j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); |
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 | 102 | fp->f_count++; |
8694aaad MK |
103 | if (fd > u.u_lastfile) |
104 | u.u_lastfile = fd; | |
4147b3f6 BJ |
105 | } |
106 | ||
88a7a62a SL |
107 | /* |
108 | * The file control system call. | |
109 | */ | |
110 | fcntl() | |
4147b3f6 | 111 | { |
4147b3f6 | 112 | register struct file *fp; |
4147b3f6 | 113 | register struct a { |
88a7a62a SL |
114 | int fdes; |
115 | int cmd; | |
116 | int arg; | |
117 | } *uap; | |
118 | register i; | |
119 | register char *pop; | |
4147b3f6 | 120 | |
88a7a62a | 121 | uap = (struct a *)u.u_ap; |
21e0a474 | 122 | GETF(fp, uap->fdes); |
88a7a62a SL |
123 | pop = &u.u_pofile[uap->fdes]; |
124 | switch(uap->cmd) { | |
85f01bd4 | 125 | case F_DUPFD: |
88a7a62a | 126 | i = uap->arg; |
8b026909 | 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; | |
c05c2528 | 133 | dupit(i, fp, *pop &~ UF_EXCLOSE); |
88a7a62a | 134 | break; |
12438177 | 135 | |
85f01bd4 | 136 | case F_GETFD: |
88a7a62a SL |
137 | u.u_r.r_val1 = *pop & 1; |
138 | break; | |
40056b21 | 139 | |
85f01bd4 | 140 | case F_SETFD: |
88a7a62a SL |
141 | *pop = (*pop &~ 1) | (uap->arg & 1); |
142 | break; | |
12438177 | 143 | |
85f01bd4 | 144 | case F_GETFL: |
88a7a62a | 145 | u.u_r.r_val1 = fp->f_flag+FOPEN; |
12438177 BJ |
146 | break; |
147 | ||
85f01bd4 | 148 | case F_SETFL: |
88a7a62a SL |
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 | 158 | |
85f01bd4 MK |
159 | case F_GETOWN: |
160 | u.u_error = fgetown(fp, &u.u_r.r_val1); | |
88a7a62a SL |
161 | break; |
162 | ||
85f01bd4 MK |
163 | case F_SETOWN: |
164 | u.u_error = fsetown(fp, uap->arg); | |
88a7a62a SL |
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) | |
0aae4319 | 216 | return (ESRCH); |
88a7a62a SL |
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 | { |
8694aaad | 234 | struct a { |
88a7a62a SL |
235 | int i; |
236 | } *uap = (struct a *)u.u_ap; | |
8694aaad | 237 | register int i = uap->i; |
88a7a62a | 238 | register struct file *fp; |
92438dfc | 239 | register u_char *pf; |
3ebb7a40 | 240 | |
8694aaad MK |
241 | GETF(fp, i); |
242 | pf = (u_char *)&u.u_pofile[i]; | |
92438dfc | 243 | if (*pf & UF_MAPPED) |
8694aaad MK |
244 | munmapfd(i); |
245 | u.u_ofile[i] = NULL; | |
246 | while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL) | |
247 | u.u_lastfile--; | |
92438dfc | 248 | *pf = 0; |
e125c45d MK |
249 | closef(fp); |
250 | /* WHAT IF u.u_error ? */ | |
92438dfc SL |
251 | } |
252 | ||
253 | fstat() | |
254 | { | |
255 | register struct file *fp; | |
256 | register struct a { | |
257 | int fdes; | |
258 | struct stat *sb; | |
259 | } *uap; | |
260 | struct stat ub; | |
261 | ||
262 | uap = (struct a *)u.u_ap; | |
21e0a474 | 263 | GETF(fp, uap->fdes); |
92438dfc SL |
264 | switch (fp->f_type) { |
265 | ||
266 | case DTYPE_INODE: | |
267 | u.u_error = ino_stat((struct inode *)fp->f_data, &ub); | |
268 | break; | |
269 | ||
270 | case DTYPE_SOCKET: | |
271 | u.u_error = soo_stat((struct socket *)fp->f_data, &ub); | |
272 | break; | |
273 | ||
274 | default: | |
275 | panic("fstat"); | |
276 | /*NOTREACHED*/ | |
277 | } | |
278 | if (u.u_error == 0) | |
55dfda24 SL |
279 | u.u_error = copyout((caddr_t)&ub, (caddr_t)uap->sb, |
280 | sizeof (ub)); | |
3ebb7a40 BJ |
281 | } |
282 | ||
40056b21 | 283 | /* |
4147b3f6 | 284 | * Allocate a user file descriptor. |
40056b21 | 285 | */ |
88a7a62a SL |
286 | ufalloc(i) |
287 | register int i; | |
4147b3f6 | 288 | { |
4147b3f6 | 289 | |
88a7a62a | 290 | for (; i < NOFILE; i++) |
4147b3f6 BJ |
291 | if (u.u_ofile[i] == NULL) { |
292 | u.u_r.r_val1 = i; | |
293 | u.u_pofile[i] = 0; | |
8694aaad MK |
294 | if (i > u.u_lastfile) |
295 | u.u_lastfile = i; | |
4147b3f6 BJ |
296 | return (i); |
297 | } | |
298 | u.u_error = EMFILE; | |
299 | return (-1); | |
300 | } | |
301 | ||
88a7a62a SL |
302 | ufavail() |
303 | { | |
304 | register int i, avail = 0; | |
305 | ||
306 | for (i = 0; i < NOFILE; i++) | |
307 | if (u.u_ofile[i] == NULL) | |
308 | avail++; | |
309 | return (avail); | |
310 | } | |
311 | ||
4147b3f6 BJ |
312 | struct file *lastf; |
313 | /* | |
314 | * Allocate a user file descriptor | |
315 | * and a file structure. | |
316 | * Initialize the descriptor | |
317 | * to point at the file structure. | |
318 | */ | |
319 | struct file * | |
320 | falloc() | |
321 | { | |
322 | register struct file *fp; | |
323 | register i; | |
324 | ||
88a7a62a | 325 | i = ufalloc(0); |
4147b3f6 BJ |
326 | if (i < 0) |
327 | return (NULL); | |
328 | if (lastf == 0) | |
329 | lastf = file; | |
330 | for (fp = lastf; fp < fileNFILE; fp++) | |
331 | if (fp->f_count == 0) | |
332 | goto slot; | |
333 | for (fp = file; fp < lastf; fp++) | |
334 | if (fp->f_count == 0) | |
335 | goto slot; | |
336 | tablefull("file"); | |
337 | u.u_error = ENFILE; | |
338 | return (NULL); | |
339 | slot: | |
340 | u.u_ofile[i] = fp; | |
88a7a62a SL |
341 | fp->f_count = 1; |
342 | fp->f_data = 0; | |
4147b3f6 | 343 | fp->f_offset = 0; |
4147b3f6 BJ |
344 | lastf = fp + 1; |
345 | return (fp); | |
346 | } | |
88a7a62a | 347 | |
4147b3f6 BJ |
348 | /* |
349 | * Convert a user supplied file descriptor into a pointer | |
350 | * to a file structure. Only task is to check range of the descriptor. | |
88a7a62a | 351 | * Critical paths should use the GETF macro. |
4147b3f6 BJ |
352 | */ |
353 | struct file * | |
354 | getf(f) | |
355 | register int f; | |
40056b21 BJ |
356 | { |
357 | register struct file *fp; | |
40056b21 | 358 | |
4147b3f6 BJ |
359 | if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) { |
360 | u.u_error = EBADF; | |
361 | return (NULL); | |
362 | } | |
363 | return (fp); | |
364 | } | |
365 | ||
366 | /* | |
367 | * Internal form of close. | |
88a7a62a | 368 | * Decrement reference count on file structure. |
4147b3f6 | 369 | */ |
92438dfc | 370 | closef(fp) |
4147b3f6 BJ |
371 | register struct file *fp; |
372 | { | |
4147b3f6 | 373 | |
40056b21 BJ |
374 | if (fp == NULL) |
375 | return; | |
4147b3f6 BJ |
376 | if (fp->f_count > 1) { |
377 | fp->f_count--; | |
40056b21 BJ |
378 | return; |
379 | } | |
92438dfc | 380 | (*fp->f_ops->fo_close)(fp); |
4147b3f6 | 381 | fp->f_count = 0; |
8d528261 | 382 | } |
92438dfc SL |
383 | |
384 | /* | |
385 | * Apply an advisory lock on a file descriptor. | |
386 | */ | |
387 | flock() | |
388 | { | |
389 | register struct a { | |
390 | int fd; | |
391 | int how; | |
392 | } *uap = (struct a *)u.u_ap; | |
393 | register struct file *fp; | |
92438dfc | 394 | |
21e0a474 | 395 | GETF(fp, uap->fd); |
55dfda24 SL |
396 | if (fp->f_type != DTYPE_INODE) { |
397 | u.u_error = EOPNOTSUPP; | |
92438dfc SL |
398 | return; |
399 | } | |
55dfda24 SL |
400 | if (uap->how & LOCK_UN) { |
401 | ino_unlock(fp, FSHLOCK|FEXLOCK); | |
92438dfc | 402 | return; |
92438dfc | 403 | } |
8b026909 MK |
404 | if ((uap->how & (LOCK_SH | LOCK_EX)) == 0) |
405 | return; /* error? */ | |
742253b3 MK |
406 | if (uap->how & LOCK_EX) |
407 | uap->how &= ~LOCK_SH; | |
55dfda24 | 408 | /* avoid work... */ |
742253b3 MK |
409 | if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) || |
410 | (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH)) | |
92438dfc | 411 | return; |
55dfda24 | 412 | u.u_error = ino_lock(fp, uap->how); |
92438dfc | 413 | } |