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. make_inode_number
  4. proc_register_dynamic
  5. proc_self_followlink
  6. proc_self_readlink
  7. proc_root_init
  8. proc_match
  9. proc_lookup
  10. proc_root_lookup
  11. proc_readdir
  12. 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 #include <asm/bitops.h>
  17 
  18 /*
  19  * Offset of the first process in the /proc root directory..
  20  */
  21 #define FIRST_PROCESS_ENTRY 256
  22 
  23 static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
  24 static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
  25 
  26 static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
  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 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 struct proc_dir_entry proc_scsi = {
 135         PROC_SCSI, 4, "scsi",
 136         S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
 137         0, &proc_dir_inode_operations,
 138         NULL, NULL,
 139         NULL, &proc_root, NULL
 140 };
 141 
 142 struct proc_dir_entry proc_sys_root = {
 143         PROC_SYS, 3, "sys",                     /* inode, name */
 144         S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,   /* mode, nlink, uid, gid */
 145         0, &proc_dir_inode_operations,          /* size, ops */
 146         NULL, NULL,                             /* get_info, fill_inode */
 147         NULL,                                   /* next */
 148         NULL, NULL                              /* parent, subdir */
 149 };
 150 
 151 int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153         dp->next = dir->subdir;
 154         dp->parent = dir;
 155         dir->subdir = dp;
 156         if (S_ISDIR(dp->mode))
 157                 dir->nlink++;
 158         return 0;
 159 }
 160 
 161 int proc_unregister(struct proc_dir_entry * dir, int ino)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163         struct proc_dir_entry **p = &dir->subdir, *dp;
 164 
 165         while ((dp = *p) != NULL) {
 166                 if (dp->low_ino == ino) {
 167                         *p = dp->next;
 168                         dp->next = NULL;
 169                         if (S_ISDIR(dp->mode))
 170                                 dir->nlink--;
 171                         if (ino >= PROC_DYNAMIC_FIRST &&
 172                             ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
 173                                 clear_bit(ino-PROC_DYNAMIC_FIRST, 
 174                                           (void *) proc_alloc_map);
 175                         return 0;
 176                 }
 177                 p = &dp->next;
 178         }
 179         return -EINVAL;
 180 }       
 181 
 182 static int make_inode_number(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184         int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
 185         if (i<0 || i>=PROC_NDYNAMIC) 
 186                 return -1;
 187         set_bit(i, (void *) proc_alloc_map);
 188         return PROC_DYNAMIC_FIRST + i;
 189 }
 190 
 191 int proc_register_dynamic(struct proc_dir_entry * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
 192                           struct proc_dir_entry * dp)
 193 {
 194         int i = make_inode_number();
 195         if (i < 0)
 196                 return -EAGAIN;
 197         dp->low_ino = i;
 198         dp->next = dir->subdir;
 199         dp->parent = dir;
 200         dir->subdir = dp;
 201         if (S_ISDIR(dp->mode))
 202                 dir->nlink++;
 203         return 0;
 204 }
 205 
 206 /*
 207  * /proc/self:
 208  */
 209 static int proc_self_followlink(struct inode * dir, struct inode * inode,
     /* [previous][next][first][last][top][bottom][index][help] */
 210                         int flag, int mode, struct inode ** res_inode)
 211 {
 212         iput(dir);
 213         *res_inode = proc_get_inode(inode->i_sb, (current->pid << 16) + PROC_PID_INO, &proc_pid);
 214         iput(inode);
 215         if (!*res_inode)
 216                 return -ENOENT;
 217         return 0;
 218 }
 219 
 220 static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222         int len;
 223         char tmp[30];
 224 
 225         iput(inode);
 226         len = 1 + sprintf(tmp, "%d", current->pid);
 227         if (buflen < len)
 228                 len = buflen;
 229         memcpy_tofs(buffer, tmp, len);
 230         return len;
 231 }
 232 
 233 static struct inode_operations proc_self_inode_operations = {
 234         NULL,                   /* no file-ops */
 235         NULL,                   /* create */
 236         NULL,                   /* lookup */
 237         NULL,                   /* link */
 238         NULL,                   /* unlink */
 239         NULL,                   /* symlink */
 240         NULL,                   /* mkdir */
 241         NULL,                   /* rmdir */
 242         NULL,                   /* mknod */
 243         NULL,                   /* rename */
 244         proc_self_readlink,     /* readlink */
 245         proc_self_followlink,   /* follow_link */
 246         NULL,                   /* readpage */
 247         NULL,                   /* writepage */
 248         NULL,                   /* bmap */
 249         NULL,                   /* truncate */
 250         NULL                    /* permission */
 251 };
 252 
 253 void proc_root_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255         static int done = 0;
 256 
 257         if (done)
 258                 return;
 259         done = 1;
 260         proc_base_init();
 261         proc_register(&proc_root, &(struct proc_dir_entry) {
 262                 PROC_LOADAVG, 7, "loadavg",
 263                 S_IFREG | S_IRUGO, 1, 0, 0,
 264         });
 265         proc_register(&proc_root, &(struct proc_dir_entry) {
 266                 PROC_UPTIME, 6, "uptime",
 267                 S_IFREG | S_IRUGO, 1, 0, 0,
 268         });
 269         proc_register(&proc_root, &(struct proc_dir_entry) {
 270                 PROC_MEMINFO, 7, "meminfo",
 271                 S_IFREG | S_IRUGO, 1, 0, 0,
 272         });
 273         proc_register(&proc_root, &(struct proc_dir_entry) {
 274                 PROC_KMSG, 4, "kmsg",
 275                 S_IFREG | S_IRUSR, 1, 0, 0,
 276         });
 277         proc_register(&proc_root, &(struct proc_dir_entry) {
 278                 PROC_VERSION, 7, "version",
 279                 S_IFREG | S_IRUGO, 1, 0, 0,
 280         });
 281 #ifdef CONFIG_PCI
 282         proc_register(&proc_root, &(struct proc_dir_entry) {
 283                 PROC_PCI, 3, "pci",
 284                 S_IFREG | S_IRUGO, 1, 0, 0,
 285         });
 286 #endif
 287         proc_register(&proc_root, &(struct proc_dir_entry) {
 288                 PROC_CPUINFO, 7, "cpuinfo",
 289                 S_IFREG | S_IRUGO, 1, 0, 0,
 290         });
 291         proc_register(&proc_root, &(struct proc_dir_entry) {
 292                 PROC_SELF, 4, "self",
 293                 S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
 294                 64, &proc_self_inode_operations,
 295         });
 296         proc_register(&proc_root, &proc_net);
 297         proc_register(&proc_root, &proc_scsi);
 298         proc_register(&proc_root, &proc_sys_root);
 299 
 300 #ifdef CONFIG_DEBUG_MALLOC
 301         proc_register(&proc_root, &(struct proc_dir_entry) {
 302                 PROC_MALLOC, 6, "malloc",
 303                 S_IFREG | S_IRUGO, 1, 0, 0,
 304         });
 305 #endif
 306         proc_register(&proc_root, &(struct proc_dir_entry) {
 307                 PROC_KCORE, 5, "kcore",
 308                 S_IFREG | S_IRUSR, 1, 0, 0,
 309         });
 310 
 311 #ifdef CONFIG_MODULES
 312         proc_register(&proc_root, &(struct proc_dir_entry) {
 313                 PROC_MODULES, 7, "modules",
 314                 S_IFREG | S_IRUGO, 1, 0, 0,
 315         });
 316         proc_register(&proc_root, &(struct proc_dir_entry) {
 317                 PROC_KSYMS, 5, "ksyms",
 318                 S_IFREG | S_IRUGO, 1, 0, 0,
 319         });
 320 #endif
 321         proc_register(&proc_root, &(struct proc_dir_entry) {
 322                 PROC_STAT, 4, "stat",
 323                 S_IFREG | S_IRUGO, 1, 0, 0,
 324         });
 325         proc_register(&proc_root, &(struct proc_dir_entry) {
 326                 PROC_DEVICES, 7, "devices",
 327                 S_IFREG | S_IRUGO, 1, 0, 0,
 328         });
 329         proc_register(&proc_root, &(struct proc_dir_entry) {
 330                 PROC_INTERRUPTS, 10,"interrupts",
 331                 S_IFREG | S_IRUGO, 1, 0, 0,
 332         });
 333 #ifdef __SMP_PROF__
 334         proc_register(&proc_root, &(struct proc_dir_entry) {
 335                 PROC_SMP_PROF, 3,"smp",
 336                 S_IFREG | S_IRUGO, 1, 0, 0,
 337         });
 338 #endif 
 339         proc_register(&proc_root, &(struct proc_dir_entry) {
 340                 PROC_FILESYSTEMS, 11,"filesystems",
 341                 S_IFREG | S_IRUGO, 1, 0, 0,
 342         });
 343         proc_register(&proc_root, &(struct proc_dir_entry) {
 344                 PROC_DMA, 3, "dma",
 345                 S_IFREG | S_IRUGO, 1, 0, 0,
 346         });
 347         proc_register(&proc_root, &(struct proc_dir_entry) {
 348                 PROC_IOPORTS, 7, "ioports",
 349                 S_IFREG | S_IRUGO, 1, 0, 0,
 350         });
 351         proc_register(&proc_root, &(struct proc_dir_entry) {
 352                 PROC_CMDLINE, 7, "cmdline",
 353                 S_IFREG | S_IRUGO, 1, 0, 0,
 354         });
 355 #ifdef CONFIG_RTC
 356         proc_register(&proc_root, &(struct proc_dir_entry) {
 357                 PROC_RTC, 3, "rtc",
 358                 S_IFREG | S_IRUGO, 1, 0, 0,
 359         });
 360 #endif
 361         proc_register(&proc_root, &(struct proc_dir_entry) {
 362                 PROC_LOCKS, 5, "locks",
 363                 S_IFREG | S_IRUGO, 1, 0, 0,
 364         });
 365 
 366         proc_register( &proc_root, &(struct proc_dir_entry)
 367            { PROC_MTAB, 6, "mounts", S_IFREG | S_IRUGO, 1, 0, 0, } );
 368                    
 369         if (prof_shift) {
 370                 proc_register(&proc_root, &(struct proc_dir_entry) {
 371                         PROC_PROFILE, 7, "profile",
 372                         S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
 373                 });
 374         }
 375 }
 376 
 377 
 378 int proc_match(int len,const char * name,struct proc_dir_entry * de)
     /* [previous][next][first][last][top][bottom][index][help] */
 379 {
 380         if (!de || !de->low_ino)
 381                 return 0;
 382         /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
 383         if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
 384                 return 1;
 385         if (de->namelen != len)
 386                 return 0;
 387         return !memcmp(name, de->name, len);
 388 }
 389 
 390 int proc_lookup(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 391         struct inode ** result)
 392 {
 393         struct proc_dir_entry * de;
 394         int ino;
 395 
 396         *result = NULL;
 397         if (!dir || !S_ISDIR(dir->i_mode)) {
 398                 iput(dir);
 399                 return -ENOTDIR;
 400         }
 401 
 402         de = (struct proc_dir_entry *) dir->u.generic_ip;
 403         if (!de) {
 404                 iput(dir);
 405                 return -EINVAL;
 406         }
 407 
 408         /* Special case "." and "..": they aren't on the directory list */
 409         *result = dir;
 410         if (!len)
 411                 return 0;
 412         if (name[0] == '.') {
 413                 if (len == 1)
 414                         return 0;
 415                 if (name[1] == '.' && len == 2) {
 416                         struct inode * inode;
 417                         inode = proc_get_inode(dir->i_sb, de->parent->low_ino, de->parent);
 418                         iput(dir);
 419                         if (!inode)
 420                                 return -EINVAL;
 421                         *result = inode;
 422                         return 0;
 423                 }
 424         }
 425 
 426         *result = NULL;
 427         for (de = de->subdir; de ; de = de->next) {
 428                 if (proc_match(len, name, de))
 429                         break;
 430         }
 431         if (!de) {
 432                 iput(dir);
 433                 return -ENOENT;
 434         }
 435 
 436         ino = de->low_ino | (dir->i_ino & ~(0xffff));
 437 
 438         if (!(*result = proc_get_inode(dir->i_sb, ino, de))) {
 439                 iput(dir);
 440                 return -EINVAL;
 441         }
 442         iput(dir);
 443         return 0;
 444 }
 445 
 446 static int proc_root_lookup(struct inode * dir,const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 447         struct inode ** result)
 448 {
 449         unsigned int pid, c;
 450         int i, ino, retval;
 451 
 452         dir->i_count++;
 453         retval = proc_lookup(dir, name, len, result);
 454         if (retval != -ENOENT) {
 455                 iput(dir);
 456                 return retval;
 457         }
 458         
 459         pid = 0;
 460         while (len-- > 0) {
 461                 c = *name - '0';
 462                 name++;
 463                 if (c > 9) {
 464                         pid = 0;
 465                         break;
 466                 }
 467                 pid *= 10;
 468                 pid += c;
 469                 if (pid & 0xffff0000) {
 470                         pid = 0;
 471                         break;
 472                 }
 473         }
 474         for (i = 0 ; i < NR_TASKS ; i++)
 475                 if (task[i] && task[i]->pid == pid)
 476                         break;
 477         if (!pid || i >= NR_TASKS) {
 478                 iput(dir);
 479                 return -ENOENT;
 480         }
 481         ino = (pid << 16) + PROC_PID_INO;
 482         if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid))) {
 483                 iput(dir);
 484                 return -EINVAL;
 485         }
 486         iput(dir);
 487         return 0;
 488 }
 489 
 490 /*
 491  * This returns non-zero if at EOF, so that the /proc
 492  * root directory can use this and check if it should
 493  * continue with the <pid> entries..
 494  *
 495  * Note that the VFS-layer doesn't care about the return
 496  * value of the readdir() call, as long as it's non-negative
 497  * for success..
 498  */
 499 int proc_readdir(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 500         void * dirent, filldir_t filldir)
 501 {
 502         struct proc_dir_entry * de;
 503         unsigned int ino;
 504         int i;
 505 
 506         if (!inode || !S_ISDIR(inode->i_mode))
 507                 return -ENOTDIR;
 508         ino = inode->i_ino;
 509         de = (struct proc_dir_entry *) inode->u.generic_ip;
 510         if (!de)
 511                 return -EINVAL;
 512         i = filp->f_pos;
 513         switch (i) {
 514                 case 0:
 515                         if (filldir(dirent, ".", 1, i, ino) < 0)
 516                                 return 0;
 517                         i++;
 518                         filp->f_pos++;
 519                         /* fall through */
 520                 case 1:
 521                         if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0)
 522                                 return 0;
 523                         i++;
 524                         filp->f_pos++;
 525                         /* fall through */
 526                 default:
 527                         ino &= ~0xffff;
 528                         de = de->subdir;
 529                         i -= 2;
 530                         for (;;) {
 531                                 if (!de)
 532                                         return 1;
 533                                 if (!i)
 534                                         break;
 535                                 de = de->next;
 536                                 i--;
 537                         }
 538 
 539                         do {
 540                                 if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino | de->low_ino) < 0)
 541                                         return 0;
 542                                 filp->f_pos++;
 543                                 de = de->next;
 544                         } while (de);
 545         }
 546         return 1;
 547 }
 548 
 549 #define NUMBUF 10
 550 
 551 static int proc_root_readdir(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 552         void * dirent, filldir_t filldir)
 553 {
 554         char buf[NUMBUF];
 555         unsigned int nr,pid;
 556         unsigned long i,j;
 557 
 558         nr = filp->f_pos;
 559         if (nr < FIRST_PROCESS_ENTRY) {
 560                 int error = proc_readdir(inode, filp, dirent, filldir);
 561                 if (error <= 0)
 562                         return error;
 563                 filp->f_pos = nr = FIRST_PROCESS_ENTRY;
 564         }
 565 
 566         for (nr -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
 567                 struct task_struct * p = task[nr];
 568 
 569                 if (!p || !(pid = p->pid))
 570                         continue;
 571 
 572                 j = NUMBUF;
 573                 i = pid;
 574                 do {
 575                         j--;
 576                         buf[j] = '0' + (i % 10);
 577                         i /= 10;
 578                 } while (i);
 579 
 580                 if (filldir(dirent, buf+j, NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
 581                         break;
 582         }
 583         return 0;
 584 }

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