root/fs/fcntl.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dupfd
  2. sys_dup2
  3. sys_dup
  4. sys_fcntl
  5. kill_fasync

   1 /*
   2  *  linux/fs/fcntl.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <asm/segment.h>
   8 
   9 #include <linux/sched.h>
  10 #include <linux/kernel.h>
  11 #include <linux/errno.h>
  12 #include <linux/stat.h>
  13 #include <linux/fcntl.h>
  14 #include <linux/string.h>
  15 
  16 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
  17 
  18 static inline int dupfd(unsigned int fd, unsigned int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  19 {
  20         if (fd >= NR_OPEN || !current->files->fd[fd])
  21                 return -EBADF;
  22         if (arg >= NR_OPEN)
  23                 return -EINVAL;
  24         while (arg < NR_OPEN)
  25                 if (current->files->fd[arg])
  26                         arg++;
  27                 else
  28                         break;
  29         if (arg >= NR_OPEN)
  30                 return -EMFILE;
  31         FD_CLR(arg, &current->files->close_on_exec);
  32         (current->files->fd[arg] = current->files->fd[fd])->f_count++;
  33         return arg;
  34 }
  35 
  36 asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38         if (oldfd >= NR_OPEN || !current->files->fd[oldfd])
  39                 return -EBADF;
  40         if (newfd == oldfd)
  41                 return newfd;
  42         if (newfd >= NR_OPEN)
  43                 return -EBADF;  /* following POSIX.1 6.2.1 */
  44 
  45         sys_close(newfd);
  46         return dupfd(oldfd,newfd);
  47 }
  48 
  49 asmlinkage int sys_dup(unsigned int fildes)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51         return dupfd(fildes,0);
  52 }
  53 
  54 asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {       
  56         struct file * filp;
  57         struct task_struct *p;
  58         int task_found = 0;
  59 
  60         if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
  61                 return -EBADF;
  62         switch (cmd) {
  63                 case F_DUPFD:
  64                         return dupfd(fd,arg);
  65                 case F_GETFD:
  66                         return FD_ISSET(fd, &current->files->close_on_exec);
  67                 case F_SETFD:
  68                         if (arg&1)
  69                                 FD_SET(fd, &current->files->close_on_exec);
  70                         else
  71                                 FD_CLR(fd, &current->files->close_on_exec);
  72                         return 0;
  73                 case F_GETFL:
  74                         return filp->f_flags;
  75                 case F_SETFL:
  76                         /*
  77                          * In the case of an append-only file, O_APPEND
  78                          * cannot be cleared
  79                          */
  80                         if (IS_APPEND(filp->f_inode) && !(arg & O_APPEND))
  81                                 return -EPERM;
  82                         if ((arg & FASYNC) && !(filp->f_flags & FASYNC) &&
  83                             filp->f_op->fasync)
  84                                 filp->f_op->fasync(filp->f_inode, filp, 1);
  85                         if (!(arg & FASYNC) && (filp->f_flags & FASYNC) &&
  86                             filp->f_op->fasync)
  87                                 filp->f_op->fasync(filp->f_inode, filp, 0);
  88                         /* requiered for SunOS emulation */
  89                         if (O_NONBLOCK != O_NDELAY)
  90                                if (arg & O_NDELAY)
  91                                    arg |= O_NONBLOCK;
  92                         filp->f_flags &= ~(O_APPEND | O_NONBLOCK | FASYNC);
  93                         filp->f_flags |= arg & (O_APPEND | O_NONBLOCK |
  94                                                 FASYNC);
  95                         return 0;
  96                 case F_GETLK:
  97                         return fcntl_getlk(fd, (struct flock *) arg);
  98                 case F_SETLK:
  99                         return fcntl_setlk(fd, cmd, (struct flock *) arg);
 100                 case F_SETLKW:
 101                         return fcntl_setlk(fd, cmd, (struct flock *) arg);
 102                 case F_GETOWN:
 103                         /*
 104                          * XXX If f_owner is a process group, the
 105                          * negative return value will get converted
 106                          * into an error.  Oops.  If we keep the the
 107                          * current syscall conventions, the only way
 108                          * to fix this will be in libc.
 109                          */
 110                         return filp->f_owner;
 111                 case F_SETOWN:
 112                         /*
 113                          *      Add the security checks - AC. Without
 114                          *      this there is a massive Linux security
 115                          *      hole here - consider what happens if
 116                          *      you do something like
 117                          * 
 118                          *              fcntl(0,F_SETOWN,some_root_process);
 119                          *              getchar();
 120                          * 
 121                          *      and input a line!
 122                          * 
 123                          * BTW: Don't try this for fun. Several Unix
 124                          *      systems I tried this on fall for the
 125                          *      trick!
 126                          * 
 127                          * I had to fix this botch job as Linux
 128                          *      kill_fasync asserts priv making it a
 129                          *      free all user process killer!
 130                          *
 131                          * Changed to make the security checks more
 132                          * liberal.  -- TYT
 133                          */
 134                         if (current->pgrp == -arg || current->pid == arg)
 135                                 goto fasync_ok;
 136                         
 137                         for_each_task(p) {
 138                                 if ((p->pid == arg) || (p->pid == -arg) || 
 139                                     (p->pgrp == -arg)) {
 140                                         task_found++;
 141                                         if ((p->session != current->session) &&
 142                                             (p->uid != current->uid) &&
 143                                             (p->euid != current->euid) &&
 144                                             !suser())
 145                                                 return -EPERM;
 146                                         break;
 147                                 }
 148                         }
 149                         if ((task_found == 0) && !suser())
 150                                 return -EINVAL;
 151                 fasync_ok:
 152                         filp->f_owner = arg;
 153                         if (S_ISSOCK (filp->f_inode->i_mode))
 154                                 sock_fcntl (filp, F_SETOWN, arg);
 155                         return 0;
 156                 default:
 157                         /* sockets need a few special fcntls. */
 158                         if (S_ISSOCK (filp->f_inode->i_mode))
 159                           {
 160                              return (sock_fcntl (filp, cmd, arg));
 161                           }
 162                         return -EINVAL;
 163         }
 164 }
 165 
 166 void kill_fasync(struct fasync_struct *fa, int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168         while (fa) {
 169                 if (fa->magic != FASYNC_MAGIC) {
 170                         printk("kill_fasync: bad magic number in "
 171                                "fasync_struct!\n");
 172                         return;
 173                 }
 174                 if (fa->fa_file->f_owner > 0)
 175                         kill_proc(fa->fa_file->f_owner, sig, 1);
 176                 else
 177                         kill_pg(-fa->fa_file->f_owner, sig, 1);
 178                 fa = fa->fa_next;
 179         }
 180 }

/* [previous][next][first][last][top][bottom][index][help] */