root/fs/proc/link.c

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

DEFINITIONS

This source file includes following definitions.
  1. proc_fd_dupf
  2. proc_follow_link
  3. proc_readlink

   1 /*
   2  *  linux/fs/proc/link.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  *
   6  *  /proc link-file handling code
   7  */
   8 
   9 #include <asm/segment.h>
  10 
  11 #include <linux/errno.h>
  12 #include <linux/sched.h>
  13 #include <linux/fs.h>
  14 #include <linux/proc_fs.h>
  15 #include <linux/stat.h>
  16 
  17 static int proc_readlink(struct inode *, char *, int);
  18 static int proc_follow_link(struct inode *, struct inode *, int, int,
  19                             struct inode **);
  20 static int proc_fd_dupf(struct inode * inode, struct file * f);
  21 
  22 #define PLAN9_SEMANTICS
  23 
  24 /*
  25  * links can't do much...
  26  */
  27 static struct file_operations proc_fd_link_operations = {
  28         NULL,                   /* lseek - default */
  29         NULL,                   /* read - bad */
  30         NULL,                   /* write - bad */
  31         NULL,                   /* readdir - bad */
  32         NULL,                   /* select - default */
  33         NULL,                   /* ioctl - default */
  34         NULL,                   /* mmap */
  35         proc_fd_dupf,           /* very special open code */
  36         NULL,                   /* no special release code */
  37         NULL                    /* can't fsync */
  38 };
  39 
  40 struct inode_operations proc_link_inode_operations = {
  41         &proc_fd_link_operations,/* file-operations */
  42         NULL,                   /* create */
  43         NULL,                   /* lookup */
  44         NULL,                   /* link */
  45         NULL,                   /* unlink */
  46         NULL,                   /* symlink */
  47         NULL,                   /* mkdir */
  48         NULL,                   /* rmdir */
  49         NULL,                   /* mknod */
  50         NULL,                   /* rename */
  51         proc_readlink,          /* readlink */
  52         proc_follow_link,       /* follow_link */
  53         NULL,                   /* bmap */
  54         NULL,                   /* truncate */
  55         NULL                    /* permission */
  56 };
  57 
  58 /*
  59  * This open routine is somewhat of a hack.... what we are doing is
  60  * looking up the file structure of the newly opened proc fd file, and
  61  * replacing it with the actual file structure of the process's file
  62  * descriptor.  This allows plan 9 semantics, so that the returned
  63  * file descriptor is an dup of the target file descriptor.
  64  */
  65 static int proc_fd_dupf(struct inode * inode, struct file * f)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67         unsigned int pid, ino;
  68         int     i, fd;
  69         struct task_struct * p;
  70         struct file *new_f;
  71         
  72         for(fd=0 ; fd<NR_OPEN ; fd++)
  73                 if (current->files->fd[fd] == f)
  74                         break;
  75         if (fd>=NR_OPEN)
  76                 return -ENOENT; /* should never happen */
  77 
  78         ino = inode->i_ino;
  79         pid = ino >> 16;
  80         ino &= 0x0000ffff;
  81 
  82         for (i = 0 ; i < NR_TASKS ; i++)
  83                 if ((p = task[i]) && p->pid == pid)
  84                         break;
  85 
  86         if ((i >= NR_TASKS) ||
  87             ((ino >> 8) != 1) || !(new_f = p->files->fd[ino & 0x0ff]))
  88                 return -ENOENT;
  89 
  90         if (new_f->f_mode && !f->f_mode && 3)
  91                 return -EPERM;
  92 
  93         new_f->f_count++;
  94         current->files->fd[fd] = new_f;
  95         if (!--f->f_count)
  96                 iput(f->f_inode);
  97         return 0;
  98 }
  99 
 100 static int proc_follow_link(struct inode * dir, struct inode * inode,
     /* [previous][next][first][last][top][bottom][index][help] */
 101         int flag, int mode, struct inode ** res_inode)
 102 {
 103         unsigned int pid, ino;
 104         struct task_struct * p;
 105         struct inode * new_inode;
 106         int i;
 107 
 108         *res_inode = NULL;
 109         if (dir)
 110                 iput(dir);
 111         if (!inode)
 112                 return -ENOENT;
 113         if (!permission(inode, MAY_EXEC)) {
 114                 iput(inode);
 115                 return -EACCES;
 116         }
 117         ino = inode->i_ino;
 118         pid = ino >> 16;
 119         ino &= 0x0000ffff;
 120         for (i = 0 ; i < NR_TASKS ; i++)
 121                 if ((p = task[i]) && p->pid == pid)
 122                         break;
 123         if (i >= NR_TASKS) {
 124                 iput(inode);
 125                 return -ENOENT;
 126         }
 127         new_inode = NULL;
 128         switch (ino) {
 129                 case PROC_PID_CWD:
 130                         new_inode = p->fs->pwd;
 131                         break;
 132                 case PROC_PID_ROOT:
 133                         new_inode = p->fs->root;
 134                         break;
 135                 case PROC_PID_EXE: {
 136                         struct vm_area_struct * vma = p->mm->mmap;
 137                         while (vma) {
 138                                 if (vma->vm_flags & VM_EXECUTABLE) {
 139                                         new_inode = vma->vm_inode;
 140                                         break;
 141                                 }
 142                                 vma = vma->vm_next;
 143                         }
 144                         break;
 145                 }
 146                 default:
 147                         switch (ino >> 8) {
 148                         case PROC_PID_FD_DIR:
 149                                 ino &= 0xff;
 150                                 if (ino < NR_OPEN && p->files->fd[ino]) {
 151 #ifdef PLAN9_SEMANTICS
 152                                         if (dir) {
 153                                                 *res_inode = inode;
 154                                                 return 0;
 155                                         }
 156 #endif
 157                                         new_inode = p->files->fd[ino]->f_inode;
 158                                 }
 159                                 break;
 160                         }
 161         }
 162         iput(inode);
 163         if (!new_inode)
 164                 return -ENOENT;
 165         *res_inode = new_inode;
 166         new_inode->i_count++;
 167         return 0;
 168 }
 169 
 170 static int proc_readlink(struct inode * inode, char * buffer, int buflen)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172         int i;
 173         unsigned int dev,ino;
 174         char buf[64];
 175 
 176         if (!S_ISLNK(inode->i_mode)) {
 177                 iput(inode);
 178                 return -EINVAL;
 179         }
 180         i = proc_follow_link(NULL, inode, 0, 0, &inode);
 181         if (i)
 182                 return i;
 183         if (!inode)
 184                 return -EIO;
 185         dev = inode->i_dev;
 186         ino = inode->i_ino;
 187         iput(inode);
 188         i = sprintf(buf,"[%04x]:%u", dev, ino);
 189         if (buflen > i)
 190                 buflen = i;
 191         i = 0;
 192         while (i < buflen)
 193                 put_fs_byte(buf[i++],buffer++);
 194         return i;
 195 }

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