| #include <string.h> |
| #include <errno.h> |
| #include <linux/sched.h> |
| #include <linux/kernel.h> |
| #include <asm/segment.h> |
| |
| #include <fcntl.h> |
| #include <sys/stat.h> |
| |
| extern int sys_close(int fd); |
| |
| static int dupfd(unsigned int fd, unsigned int arg) |
| { |
| if (fd >= NR_OPEN || !current->filp[fd]) |
| return -EBADF; |
| if (arg >= NR_OPEN) |
| return -EINVAL; |
| while (arg < NR_OPEN) |
| if (current->filp[arg]) |
| arg++; |
| else |
| break; |
| if (arg >= NR_OPEN) |
| return -EMFILE; |
| current->close_on_exec &= ~(1<<arg); |
| (current->filp[arg] = current->filp[fd])->f_count++; |
| return arg; |
| } |
| |
| int sys_dup2(unsigned int oldfd, unsigned int newfd) |
| { |
| sys_close(newfd); |
| return dupfd(oldfd,newfd); |
| } |
| |
| int sys_dup(unsigned int fildes) |
| { |
| return dupfd(fildes,0); |
| } |
| |
| int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) |
| { |
| struct file * filp; |
| |
| if (fd >= NR_OPEN || !(filp = current->filp[fd])) |
| return -EBADF; |
| switch (cmd) { |
| case F_DUPFD: |
| return dupfd(fd,arg); |
| case F_GETFD: |
| return (current->close_on_exec>>fd)&1; |
| case F_SETFD: |
| if (arg&1) |
| current->close_on_exec |= (1<<fd); |
| else |
| current->close_on_exec &= ~(1<<fd); |
| 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: case F_SETLK: case F_SETLKW: |
| return -1; |
| default: |
| return -1; |
| } |
| } |