home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / fcntl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-02  |  4.7 KB  |  189 lines

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