int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); if (fd >= NR_OPEN || !(filp = current->filp[fd])) return -EBADF; switch (cmd) { case F_DUPFD: return dupfd(fd,arg); case F_GETFD: return FD_ISSET(fd, ¤t->close_on_exec); case F_SETFD: if (arg&1) FD_SET(fd, ¤t->close_on_exec); else FD_CLR(fd, ¤t->close_on_exec); return 0; case F_GETFL: return filp->f_flags; case F_SETFL: filp->f_flags &= ~(O_APPEND | O_NONBLOCK); filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); return 0; case F_GETLK: return fcntl_getlk(fd, (struct flock *) arg); case F_SETLK: return fcntl_setlk(fd, cmd, (struct flock *) arg); case F_SETLKW: return fcntl_setlk(fd, cmd, (struct flock *) arg); default: /* sockets need a few special fcntls. */ if (S_ISSOCK (filp->f_inode->i_mode)) { return (sock_fcntl (filp, cmd, arg)); } return -EINVAL; } }
asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; long err = -EBADF; lock_kernel(); filp = fget(fd); if (!filp) goto out; err = 0; switch (cmd) { case F_DUPFD: err = dupfd(fd, arg); break; case F_GETFD: err = FD_ISSET(fd, current->files->close_on_exec); break; case F_SETFD: if (arg&1) FD_SET(fd, current->files->close_on_exec); else FD_CLR(fd, current->files->close_on_exec); break; case F_GETFL: err = filp->f_flags; break; case F_SETFL: err = setfl(fd, filp, arg); break; case F_GETLK: err = fcntl_getlk(fd, (struct flock *) arg); break; case F_SETLK: err = fcntl_setlk(fd, cmd, (struct flock *) arg); break; case F_SETLKW: err = fcntl_setlk(fd, cmd, (struct flock *) arg); break; case F_GETOWN: /* * XXX If f_owner is a process group, the * negative return value will get converted * into an error. Oops. If we keep the * current syscall conventions, the only way * to fix this will be in libc. */ err = filp->f_owner.pid; break; case F_SETOWN: filp->f_owner.pid = arg; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; if (S_ISSOCK (filp->f_dentry->d_inode->i_mode)) err = sock_fcntl (filp, F_SETOWN, arg); break; case F_GETSIG: err = filp->f_owner.signum; break; case F_SETSIG: if (arg <= 0 || arg > _NSIG) { err = -EINVAL; break; } err = 0; filp->f_owner.signum = arg; break; default: /* sockets need a few special fcntls. */ err = -EINVAL; if (S_ISSOCK (filp->f_dentry->d_inode->i_mode)) err = sock_fcntl (filp, cmd, arg); break; } fput(filp); out: unlock_kernel(); return err; }
asmlinkage int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) return -EBADF; switch (cmd) { case F_DUPFD: return dupfd(fd,arg); case F_GETFD: return FD_ISSET(fd, ¤t->files->close_on_exec); case F_SETFD: if (arg&1) FD_SET(fd, ¤t->files->close_on_exec); else FD_CLR(fd, ¤t->files->close_on_exec); return 0; case F_GETFL: return filp->f_flags; case F_SETFL: /* * In the case of an append-only file, O_APPEND * cannot be cleared */ if (IS_APPEND(filp->f_inode) && !(arg & O_APPEND)) return -EPERM; if ((arg & FASYNC) && !(filp->f_flags & FASYNC) && filp->f_op->fasync) filp->f_op->fasync(filp->f_inode, filp, 1); if (!(arg & FASYNC) && (filp->f_flags & FASYNC) && filp->f_op->fasync) filp->f_op->fasync(filp->f_inode, filp, 0); filp->f_flags &= ~(O_APPEND | O_NONBLOCK | FASYNC); filp->f_flags |= arg & (O_APPEND | O_NONBLOCK | FASYNC); return 0; case F_GETLK: return fcntl_getlk(fd, (struct flock *) arg); case F_SETLK: return fcntl_setlk(fd, cmd, (struct flock *) arg); case F_SETLKW: return fcntl_setlk(fd, cmd, (struct flock *) arg); case F_GETOWN: /* * XXX If f_owner is a process group, the * negative return value will get converted * into an error. Oops. If we keep the the * current syscall conventions, the only way * to fix this will be in libc. */ return filp->f_owner; case F_SETOWN: filp->f_owner = arg; /* XXX security implications? */ if (S_ISSOCK (filp->f_inode->i_mode)) sock_fcntl (filp, F_SETOWN, arg); return 0; default: /* sockets need a few special fcntls. */ if (S_ISSOCK (filp->f_inode->i_mode)) { return (sock_fcntl (filp, cmd, arg)); } return -EINVAL; } }