Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
8fe87cbb | 6 | * @(#)kern_descrip.c 7.2 (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 | 193 | case DTYPE_SOCKET: |
8fe87cbb | 194 | *valuep = ((struct socket *)fp->f_data)->so_pgid; |
88a7a62a SL |
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 | 207 | { |
88a7a62a | 208 | if (fp->f_type == DTYPE_SOCKET) { |
8fe87cbb | 209 | ((struct socket *)fp->f_data)->so_pgid = value; |
88a7a62a SL |
210 | return (0); |
211 | } | |
212 | if (value > 0) { | |
213 | struct proc *p = pfind(value); | |
214 | if (p == 0) | |
0aae4319 | 215 | return (ESRCH); |
8fe87cbb | 216 | value = p->p_pgrp->pg_id; |
88a7a62a SL |
217 | } else |
218 | value = -value; | |
219 | return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value)); | |
40056b21 BJ |
220 | } |
221 | ||
88a7a62a SL |
222 | fioctl(fp, cmd, value) |
223 | struct file *fp; | |
224 | int cmd; | |
225 | caddr_t value; | |
40056b21 | 226 | { |
40056b21 | 227 | |
88a7a62a | 228 | return ((*fp->f_ops->fo_ioctl)(fp, cmd, value)); |
40056b21 BJ |
229 | } |
230 | ||
88a7a62a | 231 | close() |
3ebb7a40 | 232 | { |
8694aaad | 233 | struct a { |
88a7a62a SL |
234 | int i; |
235 | } *uap = (struct a *)u.u_ap; | |
8694aaad | 236 | register int i = uap->i; |
88a7a62a | 237 | register struct file *fp; |
92438dfc | 238 | register u_char *pf; |
3ebb7a40 | 239 | |
8694aaad MK |
240 | GETF(fp, i); |
241 | pf = (u_char *)&u.u_pofile[i]; | |
92438dfc | 242 | if (*pf & UF_MAPPED) |
8694aaad MK |
243 | munmapfd(i); |
244 | u.u_ofile[i] = NULL; | |
245 | while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL) | |
246 | u.u_lastfile--; | |
92438dfc | 247 | *pf = 0; |
e125c45d MK |
248 | closef(fp); |
249 | /* WHAT IF u.u_error ? */ | |
92438dfc SL |
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; | |
21e0a474 | 262 | GETF(fp, uap->fdes); |
92438dfc SL |
263 | switch (fp->f_type) { |
264 | ||
265 | case DTYPE_INODE: | |
266 | u.u_error = ino_stat((struct inode *)fp->f_data, &ub); | |
267 | break; | |
268 | ||
269 | case DTYPE_SOCKET: | |
270 | u.u_error = soo_stat((struct socket *)fp->f_data, &ub); | |
271 | break; | |
272 | ||
273 | default: | |
274 | panic("fstat"); | |
275 | /*NOTREACHED*/ | |
276 | } | |
277 | if (u.u_error == 0) | |
55dfda24 SL |
278 | u.u_error = copyout((caddr_t)&ub, (caddr_t)uap->sb, |
279 | sizeof (ub)); | |
3ebb7a40 BJ |
280 | } |
281 | ||
40056b21 | 282 | /* |
4147b3f6 | 283 | * Allocate a user file descriptor. |
40056b21 | 284 | */ |
88a7a62a SL |
285 | ufalloc(i) |
286 | register int i; | |
4147b3f6 | 287 | { |
4147b3f6 | 288 | |
88a7a62a | 289 | for (; i < NOFILE; i++) |
4147b3f6 BJ |
290 | if (u.u_ofile[i] == NULL) { |
291 | u.u_r.r_val1 = i; | |
292 | u.u_pofile[i] = 0; | |
8694aaad MK |
293 | if (i > u.u_lastfile) |
294 | u.u_lastfile = i; | |
4147b3f6 BJ |
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 | 367 | * Decrement reference count on file structure. |
4147b3f6 | 368 | */ |
92438dfc | 369 | closef(fp) |
4147b3f6 BJ |
370 | register struct file *fp; |
371 | { | |
4147b3f6 | 372 | |
40056b21 BJ |
373 | if (fp == NULL) |
374 | return; | |
4147b3f6 BJ |
375 | if (fp->f_count > 1) { |
376 | fp->f_count--; | |
40056b21 BJ |
377 | return; |
378 | } | |
92438dfc | 379 | (*fp->f_ops->fo_close)(fp); |
4147b3f6 | 380 | fp->f_count = 0; |
8d528261 | 381 | } |
92438dfc SL |
382 | |
383 | /* | |
384 | * Apply an advisory lock on a file descriptor. | |
385 | */ | |
386 | flock() | |
387 | { | |
388 | register struct a { | |
389 | int fd; | |
390 | int how; | |
391 | } *uap = (struct a *)u.u_ap; | |
392 | register struct file *fp; | |
92438dfc | 393 | |
21e0a474 | 394 | GETF(fp, uap->fd); |
55dfda24 SL |
395 | if (fp->f_type != DTYPE_INODE) { |
396 | u.u_error = EOPNOTSUPP; | |
92438dfc SL |
397 | return; |
398 | } | |
55dfda24 SL |
399 | if (uap->how & LOCK_UN) { |
400 | ino_unlock(fp, FSHLOCK|FEXLOCK); | |
92438dfc | 401 | return; |
92438dfc | 402 | } |
8b026909 MK |
403 | if ((uap->how & (LOCK_SH | LOCK_EX)) == 0) |
404 | return; /* error? */ | |
742253b3 MK |
405 | if (uap->how & LOCK_EX) |
406 | uap->how &= ~LOCK_SH; | |
55dfda24 | 407 | /* avoid work... */ |
742253b3 MK |
408 | if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) || |
409 | (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH)) | |
92438dfc | 410 | return; |
55dfda24 | 411 | u.u_error = ino_lock(fp, uap->how); |
92438dfc | 412 | } |