root/fs/proc/root.c

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

DEFINITIONS

This source file includes following definitions.
  1. proc_register
  2. proc_unregister
  3. proc_self_followlink
  4. proc_self_readlink
  5. proc_root_init
  6. proc_match
  7. proc_lookup
  8. proc_root_lookup
  9. proc_readdir
  10. proc_root_readdir

   1 /*
   2  *  linux/fs/proc/root.c
   3  *
   4  *  Copyright (C) 1991, 1992 Linus Torvalds
   5  *
   6  *  proc root directory handling functions
   7  */
   8 
   9 #include <asm/segment.h>
  10 
  11 #include <linux/errno.h>
  12 #include <linux/sched.h>
  13 #include <linux/proc_fs.h>
  14 #include <linux/stat.h>
  15 #include <linux/config.h>
  16 #ifdef CONFIG_APM
  17 #include <linux/apm_bios.h>
  18 #endif
  19 
  20 /*
  21  * Offset of the first process in the /proc root directory..
  22  */
  23 #define FIRST_PROCESS_ENTRY 256
  24 
  25 static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
  26 static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
  27 
  28 /*
  29  * These are the generic /proc directory operations. They
  30  * use the in-memory "struct proc_dir_entry" tree to parse
  31  * the /proc directory.
  32  *
  33  * NOTE! The /proc/scsi directory currently does not correctly
  34  * build up the proc_dir_entry tree, and will show up empty.
  35  */
  36 static struct file_operations proc_dir_operations = {
  37         NULL,                   /* lseek - default */
  38         NULL,                   /* read - bad */
  39         NULL,                   /* write - bad */
  40         proc_readdir,           /* readdir */
  41         NULL,                   /* select - default */
  42         NULL,                   /* ioctl - default */
  43         NULL,                   /* mmap */
  44         NULL,                   /* no special open code */
  45         NULL,                   /* no special release code */
  46         NULL                    /* can't fsync */
  47 };
  48 
  49 /*
  50  * proc directories can do almost nothing..
  51  */
  52 static struct inode_operations proc_dir_inode_operations = {
  53         &proc_dir_operations,   /* default net directory file-ops */
  54         NULL,                   /* create */
  55         proc_lookup,            /* lookup */
  56         NULL,                   /* link */
  57         NULL,                   /* unlink */
  58         NULL,                   /* symlink */
  59         NULL,                   /* mkdir */
  60         NULL,                   /* rmdir */
  61         NULL,                   /* mknod */
  62         NULL,                   /* rename */
  63         NULL,                   /* readlink */
  64         NULL,                   /* follow_link */
  65         NULL,                   /* readpage */
  66         NULL,                   /* writepage */
  67         NULL,                   /* bmap */
  68         NULL,                   /* truncate */
  69         NULL                    /* permission */
  70 };
  71 
  72 /*
  73  * The root /proc directory is special, as it has the
  74  * <pid> directories. Thus we don't use the generic
  75  * directory handling functions for that..
  76  */
  77 static struct file_operations proc_root_operations = {
  78         NULL,                   /* lseek - default */
  79         NULL,                   /* read - bad */
  80         NULL,                   /* write - bad */
  81         proc_root_readdir,      /* readdir */
  82         NULL,                   /* select - default */
  83         NULL,                   /* ioctl - default */
  84         NULL,                   /* mmap */
  85         NULL,                   /* no special open code */
  86         NULL,                   /* no special release code */
  87         NULL                    /* no fsync */
  88 };
  89 
  90 /*
  91  * proc root can do almost nothing..
  92  */
  93 static struct inode_operations proc_root_inode_operations = {
  94         &proc_root_operations,  /* default base directory file-ops */
  95         NULL,                   /* create */
  96         proc_root_lookup,       /* lookup */
  97         NULL,                   /* link */
  98         NULL,                   /* unlink */
  99         NULL,                   /* symlink */
 100         NULL,                   /* mkdir */
 101         NULL,                   /* rmdir */
 102         NULL,                   /* mknod */
 103         NULL,                   /* rename */
 104         NULL,                   /* readlink */
 105         NULL,                   /* follow_link */
 106         NULL,                   /* readpage */
 107         NULL,                   /* writepage */
 108         NULL,                   /* bmap */
 109         NULL,                   /* truncate */
 110         NULL                    /* permission */
 111 };
 112 
 113 /*
 114  * This is the root "inode" in the /proc tree..
 115  */
 116 struct proc_dir_entry proc_root = {
 117         PROC_ROOT_INO, 5, "/proc",
 118         S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
 119         0, &proc_root_inode_operations,
 120         NULL, NULL,
 121         NULL,
 122         &proc_root, NULL
 123 };
 124 
 125 struct proc_dir_entry proc_net = {
 126         PROC_NET, 3, "net",
 127         S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
 128         0, &proc_dir_inode_operations,
 129         NULL, NULL,
 130         NULL,
 131         NULL, NULL      
 132 };
 133 
 134 #ifdef CONFIG_SCSI
 135 struct proc_dir_entry proc_scsi = {
 136         PROC_SCSI, 4, "scsi",
 137         S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
 138         0, &proc_dir_inode_operations,
 139         NULL, NULL,
 140         NULL, &proc_root, NULL
 141 };
 142 #endif
 143 
 144 int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146         dp->next = dir->subdir;
 147         dp->parent = dir;
 148         dir->subdir = dp;
 149         if (S_ISDIR(dp->mode))
 150                 dir->nlink++;
 151         return 0;
 152 }
 153 
 154 int proc_unregister(struct proc_dir_entry * dir, int ino)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156         struct proc_dir_entry **p = &dir->subdir, *dp;
 157 
 158         while ((dp = *p) != NULL) {
 159                 if (dp->low_ino == ino) {
 160                         *p = dp->next;
 161                         dp->next = NULL;
 162                         if (S_ISDIR(dp->mode))
 163                                 dir->nlink--;
 164                         return 0;
 165                 }
 166                 p = &dp->next;
 167         }
 168         return -EINVAL;
 169 }       
 170 
 171 /*
 172  * /proc/self:
 173  */
 174 static int proc_self_followlink(struct inode * dir, struct inode * inode,
     /* [previous][next][first][last][top][bottom][index][help] */
 175                         int flag, int mode, struct inode ** res_inode)
 176 {
 177         iput(dir);
 178         *res_inode = proc_get_inode(inode->i_sb, (current->pid << 16) + PROC_PID_INO, &proc_pid);
 179         iput(inode);
 180         if (!*res_inode)
 181                 return -ENOENT;
 182         return 0;
 183 }
 184 
 185 static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
     /* [previous][next][first][last][top][bottom][index][help] */
 186 {
 187         int len;
 188         char tmp[30];
 189 
 190         iput(inode);
 191         len = 1 + sprintf(tmp, "%d", current->pid);
 192         if (buflen < len)
 193                 len = buflen;
 194         memcpy_tofs(buffer, tmp, len);
 195         return len;
 196 }
 197 
 198 static struct inode_operations proc_self_inode_operations = {
 199         NULL,                   /* no file-ops */
 200         NULL,                   /* create */
 201         NULL,                   /* lookup */
 202         NULL,                   /* link */
 203         NULL,                   /* unlink */
 204         NULL,                   /* symlink */
 205         NULL,                   /* mkdir */
 206         NULL,                   /* rmdir */
 207         NULL,                   /* mknod */
 208         NULL,                   /* rename */
 209         proc_self_readlink,     /* readlink */
 210         proc_self_followlink,   /* follow_link */
 211         NULL,                   /* readpage */
 212         NULL,                   /* writepage */
 213         NULL,                   /* bmap */
 214         NULL,                   /* truncate */
 215         NULL                    /* permission */
 216 };
 217 
 218 void proc_root_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220         static int done = 0;
 221 
 222         if (done)
 223                 return;
 224         done = 1;
 225         proc_base_init();
 226         proc_register(&proc_root, &(struct proc_dir_entry) {
 227                 PROC_LOADAVG, 7, "loadavg",
 228                 S_IFREG | S_IRUGO, 1, 0, 0,
 229         });
 230         proc_register(&proc_root, &(struct proc_dir_entry) {
 231                 PROC_UPTIME, 6, "uptime",
 232                 S_IFREG | S_IRUGO, 1, 0, 0,
 233         });
 234         proc_register(&proc_root, &(struct proc_dir_entry) {
 235                 PROC_MEMINFO, 7, "meminfo",
 236                 S_IFREG | S_IRUGO, 1, 0, 0,
 237         });
 238         proc_register(&proc_root, &(struct proc_dir_entry) {
 239                 PROC_KMSG, 4, "kmsg",
 240                 S_IFREG | S_IRUSR, 1, 0, 0,
 241         });
 242         proc_register(&proc_root, &(struct proc_dir_entry) {
 243                 PROC_VERSION, 7, "version",
 244                 S_IFREG | S_IRUGO, 1, 0, 0,
 245         });
 246 #ifdef CONFIG_PCI
 247         proc_register(&proc_root, &(struct proc_dir_entry) {
 248                 PROC_PCI, 3, "pci",
 249                 S_IFREG | S_IRUGO, 1, 0, 0,
 250         });
 251 #endif
 252         proc_register(&proc_root, &(struct proc_dir_entry) {
 253                 PROC_CPUINFO, 7, "cpuinfo",
 254                 S_IFREG | S_IRUGO, 1, 0, 0,
 255         });
 256         proc_register(&proc_root, &(struct proc_dir_entry) {
 257                 PROC_SELF, 4, "self",
 258                 S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
 259                 64, &proc_self_inode_operations,
 260         });
 261         proc_register(&proc_root, &proc_net);
 262 
 263 #ifdef CONFIG_SCSI
 264         proc_register(&proc_root, &proc_scsi);
 265 #endif
 266 
 267 #ifdef CONFIG_DEBUG_MALLOC
 268         proc_register(&proc_root, &(struct proc_dir_entry) {
 269                 PROC_MALLOC, 6, "malloc",
 270                 S_IFREG | S_IRUGO, 1, 0, 0,
 271         });
 272 #endif
 273         proc_register(&proc_root, &(struct proc_dir_entry) {
 274                 PROC_KCORE, 5, "kcore",
 275                 S_IFREG | S_IRUSR, 1, 0, 0,
 276         });
 277 
 278 #ifdef CONFIG_MODULES
 279         proc_register(&proc_root, &(struct proc_dir_entry) {
 280                 PROC_MODULES, 7, "modules",
 281                 S_IFREG | S_IRUGO, 1, 0, 0,
 282         });
 283         proc_register(&proc_root, &(struct proc_dir_entry) {
 284                 PROC_KSYMS, 5, "ksyms",
 285                 S_IFREG | S_IRUGO, 1, 0, 0,
 286         });
 287 #endif
 288         proc_register(&proc_root, &(struct proc_dir_entry) {
 289                 PROC_STAT, 4, "stat",
 290                 S_IFREG | S_IRUGO, 1, 0, 0,
 291         });
 292         proc_register(&proc_root, &(struct proc_dir_entry) {
 293                 PROC_DEVICES, 7, "devices",
 294                 S_IFREG | S_IRUGO, 1, 0, 0,
 295         });
 296         proc_register(&proc_root, &(struct proc_dir_entry) {
 297                 PROC_INTERRUPTS, 10,"interrupts",
 298                 S_IFREG | S_IRUGO, 1, 0, 0,
 299         });
 300         proc_register(&proc_root, &(struct proc_dir_entry) {
 301                 PROC_FILESYSTEMS, 11,"filesystems",
 302                 S_IFREG | S_IRUGO, 1, 0, 0,
 303         });
 304         proc_register(&proc_root, &(struct proc_dir_entry) {
 305                 PROC_DMA, 3, "dma",
 306                 S_IFREG | S_IRUGO, 1, 0, 0,
 307         });
 308         proc_register(&proc_root, &(struct proc_dir_entry) {
 309                 PROC_IOPORTS, 7, "ioports",
 310                 S_IFREG | S_IRUGO, 1, 0, 0,
 311         });
 312 #ifdef CONFIG_APM
 313         proc_register(&proc_root, &(struct proc_dir_entry) {
 314                 PROC_APM, 3, "apm",
 315                 S_IFREG | S_IRUGO, 1, 0, 0,
 316         });
 317 #endif
 318         proc_register(&proc_root, &(struct proc_dir_entry) {
 319                 PROC_CMDLINE, 7, "cmdline",
 320                 S_IFREG | S_IRUGO, 1, 0, 0,
 321         });
 322                    
 323         if (prof_shift) {
 324                 proc_register(&proc_root, &(struct proc_dir_entry) {
 325                         PROC_PROFILE, 7, "profile",
 326                         S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
 327                 });
 328         }
 329 }
 330 
 331 
 332 int proc_match(int len,const char * name,struct proc_dir_entry * de)
     /* [previous][next][first][last][top][bottom][index][help] */
 333 {
 334         if (!de || !de->low_ino)
 335                 return 0;
 336         /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
 337         if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
 338                 return 1;
 339         if (de->namelen != len)
 340                 return 0;
 341         return !memcmp(name, de->name, len);
 342 }
 343 
 344 int proc_lookup(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 345         struct inode ** result)
 346 {
 347         struct proc_dir_entry * de;
 348         int ino;
 349 
 350         *result = NULL;
 351         if (!dir || !S_ISDIR(dir->i_mode)) {
 352                 iput(dir);
 353                 return -ENOTDIR;
 354         }
 355 
 356         de = (struct proc_dir_entry *) dir->u.generic_ip;
 357         if (!de) {
 358                 iput(dir);
 359                 return -EINVAL;
 360         }
 361 
 362         /* Special case "." and "..": they aren't on the directory list */
 363         *result = dir;
 364         if (!len)
 365                 return 0;
 366         if (name[0] == '.') {
 367                 if (len == 1)
 368                         return 0;
 369                 if (name[1] == '.' && len == 2) {
 370                         struct inode * inode;
 371                         inode = proc_get_inode(dir->i_sb, de->parent->low_ino, de->parent);
 372                         iput(dir);
 373                         if (!inode)
 374                                 return -EINVAL;
 375                         *result = inode;
 376                         return 0;
 377                 }
 378         }
 379 
 380         *result = NULL;
 381         for (de = de->subdir; de ; de = de->next) {
 382                 if (proc_match(len, name, de))
 383                         break;
 384         }
 385         if (!de) {
 386                 iput(dir);
 387                 return -ENOENT;
 388         }
 389 
 390         ino = de->low_ino | (dir->i_ino & ~(0xffff));
 391 
 392         if (!(*result = proc_get_inode(dir->i_sb, ino, de))) {
 393                 iput(dir);
 394                 return -EINVAL;
 395         }
 396         iput(dir);
 397         return 0;
 398 }
 399 
 400 static int proc_root_lookup(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 401         struct inode ** result)
 402 {
 403         unsigned int pid, c;
 404         int i, ino, retval;
 405 
 406         dir->i_count++;
 407         retval = proc_lookup(dir, name, len, result);
 408         if (retval != -ENOENT) {
 409                 iput(dir);
 410                 return retval;
 411         }
 412         
 413         pid = 0;
 414         while (len-- > 0) {
 415                 c = *name - '0';
 416                 name++;
 417                 if (c > 9) {
 418                         pid = 0;
 419                         break;
 420                 }
 421                 pid *= 10;
 422                 pid += c;
 423                 if (pid & 0xffff0000) {
 424                         pid = 0;
 425                         break;
 426                 }
 427         }
 428         for (i = 0 ; i < NR_TASKS ; i++)
 429                 if (task[i] && task[i]->pid == pid)
 430                         break;
 431         if (!pid || i >= NR_TASKS) {
 432                 iput(dir);
 433                 return -ENOENT;
 434         }
 435         ino = (pid << 16) + PROC_PID_INO;
 436         if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid))) {
 437                 iput(dir);
 438                 return -EINVAL;
 439         }
 440         iput(dir);
 441         return 0;
 442 }
 443 
 444 /*
 445  * This returns non-zero if at EOF, so that the /proc
 446  * root directory can use this and check if it should
 447  * continue with the <pid> entries..
 448  *
 449  * Note that the VFS-layer doesn't care about the return
 450  * value of the readdir() call, as long as it's non-negative
 451  * for success..
 452  */
 453 int proc_readdir(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 454         void * dirent, filldir_t filldir)
 455 {
 456         struct proc_dir_entry * de;
 457         unsigned int ino;
 458         int i;
 459 
 460         if (!inode || !S_ISDIR(inode->i_mode))
 461                 return -ENOTDIR;
 462         ino = inode->i_ino;
 463         de = (struct proc_dir_entry *) inode->u.generic_ip;
 464         if (!de)
 465                 return -EINVAL;
 466         i = filp->f_pos;
 467         switch (i) {
 468                 case 0:
 469                         if (filldir(dirent, ".", 1, i, ino) < 0)
 470                                 return 0;
 471                         i++;
 472                         filp->f_pos++;
 473                         /* fall through */
 474                 case 1:
 475                         if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0)
 476                                 return 0;
 477                         i++;
 478                         filp->f_pos++;
 479                         /* fall through */
 480                 default:
 481                         ino &= ~0xffff;
 482                         de = de->subdir;
 483                         i -= 2;
 484                         for (;;) {
 485                                 if (!de)
 486                                         return 1;
 487                                 if (!i)
 488                                         break;
 489                                 de = de->next;
 490                                 i--;
 491                         }
 492 
 493                         do {
 494                                 if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino | de->low_ino) < 0)
 495                                         return 0;
 496                                 filp->f_pos++;
 497                                 de = de->next;
 498                         } while (de);
 499         }
 500         return 1;
 501 }
 502 
 503 #define NUMBUF 10
 504 
 505 static int proc_root_readdir(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 506         void * dirent, filldir_t filldir)
 507 {
 508         char buf[NUMBUF];
 509         unsigned int nr,pid;
 510         unsigned long i,j;
 511 
 512         nr = filp->f_pos;
 513         if (nr < FIRST_PROCESS_ENTRY) {
 514                 int error = proc_readdir(inode, filp, dirent, filldir);
 515                 if (error <= 0)
 516                         return error;
 517                 filp->f_pos = nr = FIRST_PROCESS_ENTRY;
 518         }
 519 
 520         for (nr -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
 521                 struct task_struct * p = task[nr];
 522 
 523                 if (!p || !(pid = p->pid))
 524                         continue;
 525 
 526                 j = NUMBUF;
 527                 i = pid;
 528                 do {
 529                         j--;
 530                         buf[j] = '0' + (i % 10);
 531                         i /= 10;
 532                 } while (i);
 533 
 534                 if (filldir(dirent, buf+j, NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
 535                         break;
 536         }
 537         return 0;
 538 }

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