1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)kern_descrip.c 7.11 (Berkeley) 05/04/90 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "syscontext.h" 23 #include "kernel.h" 24 #include "vnode.h" 25 #include "proc.h" 26 #include "file.h" 27 #include "socket.h" 28 #include "socketvar.h" 29 #include "stat.h" 30 31 #include "ioctl.h" 32 33 /* 34 * Descriptor management. 35 */ 36 37 /* 38 * System calls on descriptors. 39 */ 40 getdtablesize() 41 { 42 43 u.u_r.r_val1 = NOFILE; 44 } 45 46 dup() 47 { 48 register struct a { 49 int i; 50 } *uap = (struct a *) u.u_ap; 51 struct file *fp; 52 int j; 53 54 if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */ 55 56 if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) 57 RETURN (EBADF); 58 if (u.u_error = ufalloc(0, &j)) 59 return; 60 u.u_r.r_val1 = j; 61 dupit(j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); 62 } 63 64 dup2() 65 { 66 register struct a { 67 int i, j; 68 } *uap = (struct a *) u.u_ap; 69 register struct file *fp; 70 int error; 71 72 if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) 73 RETURN (EBADF); 74 if (uap->j < 0 || uap->j >= NOFILE) 75 RETURN (EBADF); 76 u.u_r.r_val1 = uap->j; 77 if (uap->i == uap->j) 78 RETURN (0); 79 if (u.u_ofile[uap->j]) { 80 if (u.u_pofile[uap->j] & UF_MAPPED) 81 munmapfd(uap->j); 82 error = closef(u.u_ofile[uap->j]); 83 } 84 dupit(uap->j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); 85 /* 86 * dup2() must succeed even though the close had an error. 87 */ 88 error = 0; /* XXX */ 89 RETURN (error); 90 } 91 92 dupit(fd, fp, flags) 93 int fd; 94 register struct file *fp; 95 register int flags; 96 { 97 98 u.u_ofile[fd] = fp; 99 u.u_pofile[fd] = flags; 100 fp->f_count++; 101 if (fd > u.u_lastfile) 102 u.u_lastfile = fd; 103 } 104 105 /* 106 * The file control system call. 107 */ 108 fcntl() 109 { 110 register struct file *fp; 111 register struct a { 112 int fdes; 113 int cmd; 114 int arg; 115 } *uap = (struct a *)u.u_ap; 116 register char *pop; 117 int i; 118 119 if ((unsigned)uap->fdes >= NOFILE || 120 (fp = u.u_ofile[uap->fdes]) == NULL) 121 RETURN (EBADF); 122 pop = &u.u_pofile[uap->fdes]; 123 switch(uap->cmd) { 124 case F_DUPFD: 125 if (uap->arg < 0 || uap->arg >= NOFILE) { 126 u.u_error = EINVAL; 127 return; 128 } 129 if (u.u_error = ufalloc(uap->arg, &i)) 130 return; 131 u.u_r.r_val1 = i; 132 dupit(i, fp, *pop &~ UF_EXCLOSE); 133 break; 134 135 case F_GETFD: 136 u.u_r.r_val1 = *pop & 1; 137 break; 138 139 case F_SETFD: 140 *pop = (*pop &~ 1) | (uap->arg & 1); 141 break; 142 143 case F_GETFL: 144 u.u_r.r_val1 = fp->f_flag+FOPEN; 145 break; 146 147 case F_SETFL: 148 fp->f_flag &= FCNTLCANT; 149 fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT; 150 u.u_error = fset(fp, FNDELAY, fp->f_flag & FNDELAY); 151 if (u.u_error) 152 break; 153 u.u_error = fset(fp, FASYNC, fp->f_flag & FASYNC); 154 if (u.u_error) 155 (void) fset(fp, FNDELAY, 0); 156 break; 157 158 case F_GETOWN: 159 u.u_error = fgetown(fp, &u.u_r.r_val1); 160 break; 161 162 case F_SETOWN: 163 u.u_error = fsetown(fp, uap->arg); 164 break; 165 166 default: 167 u.u_error = EINVAL; 168 } 169 } 170 171 fset(fp, bit, value) 172 struct file *fp; 173 int bit, value; 174 { 175 176 if (value) 177 fp->f_flag |= bit; 178 else 179 fp->f_flag &= ~bit; 180 return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC), 181 (caddr_t)&value)); 182 } 183 184 fgetown(fp, valuep) 185 struct file *fp; 186 int *valuep; 187 { 188 int error; 189 190 switch (fp->f_type) { 191 192 case DTYPE_SOCKET: 193 *valuep = ((struct socket *)fp->f_data)->so_pgid; 194 return (0); 195 196 default: 197 error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep); 198 *valuep = -*valuep; 199 return (error); 200 } 201 } 202 203 fsetown(fp, value) 204 struct file *fp; 205 int value; 206 { 207 208 if (fp->f_type == DTYPE_SOCKET) { 209 ((struct socket *)fp->f_data)->so_pgid = value; 210 return (0); 211 } 212 if (value > 0) { 213 struct proc *p = pfind(value); 214 if (p == 0) 215 return (ESRCH); 216 value = p->p_pgrp->pg_id; 217 } else 218 value = -value; 219 return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value)); 220 } 221 222 fioctl(fp, cmd, value) 223 struct file *fp; 224 int cmd; 225 caddr_t value; 226 { 227 228 return ((*fp->f_ops->fo_ioctl)(fp, cmd, value)); 229 } 230 231 close() 232 { 233 struct a { 234 int fdes; 235 } *uap = (struct a *)u.u_ap; 236 register struct file *fp; 237 register u_char *pf; 238 239 if ((unsigned)uap->fdes >= NOFILE || 240 (fp = u.u_ofile[uap->fdes]) == NULL) 241 RETURN (EBADF); 242 pf = (u_char *)&u.u_pofile[uap->fdes]; 243 if (*pf & UF_MAPPED) 244 munmapfd(uap->fdes); 245 u.u_ofile[uap->fdes] = NULL; 246 while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL) 247 u.u_lastfile--; 248 *pf = 0; 249 RETURN (closef(fp)); 250 } 251 252 fstat() 253 { 254 register struct file *fp; 255 register struct a { 256 int fdes; 257 struct stat *sb; 258 } *uap = (struct a *)u.u_ap; 259 struct stat ub; 260 261 if ((unsigned)uap->fdes >= NOFILE || 262 (fp = u.u_ofile[uap->fdes]) == NULL) 263 RETURN (EBADF); 264 switch (fp->f_type) { 265 266 case DTYPE_VNODE: 267 u.u_error = vn_stat((struct vnode *)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) 279 u.u_error = copyout((caddr_t)&ub, (caddr_t)uap->sb, 280 sizeof (ub)); 281 } 282 283 /* 284 * Allocate a user file descriptor. 285 */ 286 ufalloc(want, result) 287 register int want; 288 int *result; 289 { 290 291 for (; want < NOFILE; want++) { 292 if (u.u_ofile[want] == NULL) { 293 u.u_pofile[want] = 0; 294 if (want > u.u_lastfile) 295 u.u_lastfile = want; 296 *result = want; 297 return (0); 298 } 299 } 300 return (EMFILE); 301 } 302 303 ufavail() 304 { 305 register int i, avail = 0; 306 307 for (i = 0; i < NOFILE; i++) 308 if (u.u_ofile[i] == NULL) 309 avail++; 310 return (avail); 311 } 312 313 struct file *lastf; 314 /* 315 * Allocate a user file descriptor 316 * and a file structure. 317 * Initialize the descriptor 318 * to point at the file structure. 319 */ 320 falloc(resultfp, resultfd) 321 struct file **resultfp; 322 int *resultfd; 323 { 324 register struct file *fp; 325 int error, i; 326 327 if (error = ufalloc(0, &i)) 328 return (error); 329 if (lastf == 0) 330 lastf = file; 331 for (fp = lastf; fp < fileNFILE; fp++) 332 if (fp->f_count == 0) 333 goto slot; 334 for (fp = file; fp < lastf; fp++) 335 if (fp->f_count == 0) 336 goto slot; 337 tablefull("file"); 338 return (ENFILE); 339 slot: 340 u.u_ofile[i] = fp; 341 fp->f_count = 1; 342 fp->f_data = 0; 343 fp->f_offset = 0; 344 fp->f_cred = u.u_cred; 345 crhold(fp->f_cred); 346 lastf = fp + 1; 347 if (resultfp) 348 *resultfp = fp; 349 if (resultfd) 350 *resultfd = i; 351 return (0); 352 } 353 354 /* 355 * Internal form of close. 356 * Decrement reference count on file structure. 357 */ 358 closef(fp) 359 register struct file *fp; 360 { 361 int error; 362 363 if (fp == NULL) 364 return (0); 365 if (fp->f_count > 1) { 366 fp->f_count--; 367 return (0); 368 } 369 if (fp->f_count < 1) 370 panic("closef: count < 1"); 371 error = (*fp->f_ops->fo_close)(fp); 372 crfree(fp->f_cred); 373 fp->f_count = 0; 374 return (error); 375 } 376 377 /* 378 * Apply an advisory lock on a file descriptor. 379 */ 380 flock() 381 { 382 register struct a { 383 int fdes; 384 int how; 385 } *uap = (struct a *)u.u_ap; 386 register struct file *fp; 387 388 if ((unsigned)uap->fdes >= NOFILE || 389 (fp = u.u_ofile[uap->fdes]) == NULL) 390 RETURN (EBADF); 391 if (fp->f_type != DTYPE_VNODE) { 392 u.u_error = EOPNOTSUPP; 393 return; 394 } 395 if (uap->how & LOCK_UN) { 396 vn_unlock(fp, FSHLOCK|FEXLOCK); 397 return; 398 } 399 if ((uap->how & (LOCK_SH | LOCK_EX)) == 0) 400 return; /* error? */ 401 if (uap->how & LOCK_EX) 402 uap->how &= ~LOCK_SH; 403 /* avoid work... */ 404 if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) || 405 (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH)) 406 return; 407 u.u_error = vn_lock(fp, uap->how); 408 } 409 410 /* 411 * File Descriptor pseudo-device driver (/dev/fd/). 412 * 413 * Fred Blonder - U of Maryland 11-Sep-1984 414 * 415 * Opening minor device N dup()s the file (if any) connected to file 416 * descriptor N belonging to the calling process. Note that this driver 417 * consists of only the ``open()'' routine, because all subsequent 418 * references to this file will be direct to the other driver. 419 */ 420 /* ARGSUSED */ 421 fdopen(dev, mode, type) 422 dev_t dev; 423 int mode, type; 424 { 425 struct file *fp, *wfp; 426 int indx, dfd; 427 428 /* 429 * XXX 430 * Horrid kludge: u.u_r.r_val1 contains the value of the new file 431 * descriptor, which was set before the call to vn_open() by copen() 432 * in vfs_syscalls.c. 433 */ 434 indx = u.u_r.r_val1; 435 fp = u.u_ofile[indx]; 436 437 /* 438 * File system device minor number is the to-be-dup'd fd number. 439 * If it is greater than the allowed number of file descriptors, 440 * or the fd to be dup'd has already been closed, reject. Note, 441 * check for new == old is necessary as u_falloc could allocate 442 * an already closed to-be-dup'd descriptor as the new descriptor. 443 */ 444 dfd = minor(dev); 445 if ((u_int)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL || 446 fp == wfp) 447 return (EBADF); 448 449 /* 450 * Check that the mode the file is being opened for is a subset 451 * of the mode of the existing descriptor. 452 */ 453 if ((mode & (FREAD|FWRITE) | wfp->f_flag) != wfp->f_flag) 454 return (EACCES); 455 dupit(indx, wfp, u.u_pofile[dfd]); 456 457 /* 458 * Delete references to this pseudo-device by returning a special 459 * error (EJUSTRETURN) that will cause all resources to be freed, 460 * then detected and cleared by copen(). 461 */ 462 return (EJUSTRETURN); /* XXX */ 463 } 464