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

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