/* * linux/fs/ioctl.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_VSERVER_LEGACY extern int vx_proc_ioctl(struct inode *, struct file *, unsigned int, unsigned long); #endif static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) { int error; int block; struct inode * inode = filp->f_dentry->d_inode; switch (cmd) { case FIBMAP: { struct address_space *mapping = filp->f_mapping; int res; /* do we support this mess? */ if (!mapping->a_ops->bmap) return -EINVAL; if (!capable(CAP_SYS_RAWIO)) return -EPERM; if ((error = get_user(block, (int *) arg)) != 0) return error; res = mapping->a_ops->bmap(mapping, block); return put_user(res, (int *) arg); } case FIGETBSZ: if (inode->i_sb == NULL) return -EBADF; return put_user(inode->i_sb->s_blocksize, (int *) arg); case FIONREAD: return put_user(i_size_read(inode) - filp->f_pos, (int *) arg); } if (filp->f_op && filp->f_op->ioctl) return filp->f_op->ioctl(inode, filp, cmd, arg); return -ENOTTY; } asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; unsigned int flag; int on, error = -EBADF; filp = fget(fd); if (!filp) goto out; error = security_file_ioctl(filp, cmd, arg); if (error) { fput(filp); goto out; } lock_kernel(); switch (cmd) { case FIOCLEX: set_close_on_exec(fd, 1); break; case FIONCLEX: set_close_on_exec(fd, 0); break; case FIONBIO: if ((error = get_user(on, (int __user *)arg)) != 0) break; flag = O_NONBLOCK; #ifdef __sparc__ /* SunOS compatibility item. */ if(O_NONBLOCK != O_NDELAY) flag |= O_NDELAY; #endif if (on) filp->f_flags |= flag; else filp->f_flags &= ~flag; break; case FIOASYNC: if ((error = get_user(on, (int __user *)arg)) != 0) break; flag = on ? FASYNC : 0; /* Did FASYNC state change ? */ if ((flag ^ filp->f_flags) & FASYNC) { if (filp->f_op && filp->f_op->fasync) error = filp->f_op->fasync(fd, filp, on); else error = -ENOTTY; } if (error != 0) break; if (on) filp->f_flags |= FASYNC; else filp->f_flags &= ~FASYNC; break; case FIOQSIZE: if (S_ISDIR(filp->f_dentry->d_inode->i_mode) || S_ISREG(filp->f_dentry->d_inode->i_mode) || S_ISLNK(filp->f_dentry->d_inode->i_mode)) { loff_t res = inode_get_bytes(filp->f_dentry->d_inode); error = copy_to_user((loff_t __user *)arg, &res, sizeof(res)) ? -EFAULT : 0; } else error = -ENOTTY; break; #ifdef CONFIG_VSERVER_LEGACY #ifndef CONFIG_INOXID_NONE case FIOC_GETXID: { struct inode *inode = filp->f_dentry->d_inode; /* fixme: if stealth, return -ENOTTY */ error = -EPERM; if (capable(CAP_CONTEXT)) error = put_user(inode->i_xid, (int *) arg); break; } case FIOC_SETXID: { struct inode *inode = filp->f_dentry->d_inode; int xid; /* fixme: if stealth, return -ENOTTY */ error = -EPERM; if (!capable(CAP_CONTEXT)) break; error = -EROFS; if (IS_RDONLY(inode)) break; error = -ENOSYS; if (!(inode->i_sb->s_flags & MS_TAGXID)) break; error = -EFAULT; if (get_user(xid, (int *) arg)) break; error = 0; inode->i_xid = (xid & 0xFFFF); inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); break; } #endif case FIOC_GETXFLG: case FIOC_SETXFLG: error = -ENOTTY; if (filp->f_dentry->d_inode->i_sb->s_magic == PROC_SUPER_MAGIC) error = vx_proc_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); break; #endif default: error = -ENOTTY; if (S_ISREG(filp->f_dentry->d_inode->i_mode)) error = file_ioctl(filp, cmd, arg); else if (filp->f_op && filp->f_op->ioctl) error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg); } unlock_kernel(); fput(filp); out: return error; }