OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/trunk/rc203soc/sw/uClinux/fs/proc
    from Rev 1628 to Rev 1765
    Reverse comparison

Rev 1628 → Rev 1765

/array.c
0,0 → 1,1269
/*
* linux/fs/proc/array.c
*
* Copyright (C) 1992 by Linus Torvalds
* based on ideas by Darren Senn
*
* Fixes:
* Michael. K. Johnson: stat,statm extensions.
* <johnsonm@stolaf.edu>
*
* Pauline Middelink : Made cmdline,envline only break at '\0's, to
* make sure SET_PROCTITLE works. Also removed
* bad '!' which forced address recalculation for
* EVERY character on the current page.
* <middelin@polyware.iaf.nl>
*
* Danny ter Haar : added cpuinfo
* <dth@cistron.nl>
*
* Alessandro Rubini : profile extension.
* <rubini@ipvvis.unipv.it>
*
* Jeff Tranter : added BogoMips field to cpuinfo
* <Jeff_Tranter@Mitel.COM>
*
* Bruno Haible : remove 4K limit for the maps file
* <haible@ma2s2.mathematik.uni-karlsruhe.de>
*
* Yves Arrouye : remove removal of trailing spaces in get_array.
* <Yves.Arrouye@marin.fdn.fr>
*
* Alan Cox : security fixes. <Alan.Cox@linux.org>
*/
 
/*
* uClinux revisions for NO_MM
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
* The Silver Hammer Group, Ltd.
*/
 
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/tty.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/string.h>
#include <linux/mman.h>
#include <linux/proc_fs.h>
#include <linux/ioport.h>
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
 
#include <asm/segment.h>
#include <asm/pgtable.h>
#include <asm/io.h>
 
#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
 
#ifdef CONFIG_DEBUG_MALLOC
int get_malloc(char * buffer);
#endif
 
extern unsigned long get_wchan(struct task_struct *);
 
static int read_core(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long p = file->f_pos, memsize;
int read;
int count1;
char * pnt;
struct user dump;
#ifdef __i386__
# define FIRST_MAPPED PAGE_SIZE /* we don't have page 0 mapped on x86.. */
#else
# define FIRST_MAPPED 0
#endif
 
memset(&dump, 0, sizeof(struct user));
dump.magic = CMAGIC;
dump.u_dsize = MAP_NR(high_memory);
#ifdef __alpha__
dump.start_data = PAGE_OFFSET;
#endif
 
if (count < 0)
return -EINVAL;
memsize = MAP_NR(high_memory + PAGE_SIZE) << PAGE_SHIFT;
if (p >= memsize)
return 0;
if (count > memsize - p)
count = memsize - p;
read = 0;
 
if (p < sizeof(struct user) && count > 0) {
count1 = count;
if (p + count1 > sizeof(struct user))
count1 = sizeof(struct user)-p;
pnt = (char *) &dump + p;
memcpy_tofs(buf,(void *) pnt, count1);
buf += count1;
p += count1;
count -= count1;
read += count1;
}
 
while (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
put_user(0,buf);
buf++;
p++;
count--;
read++;
}
memcpy_tofs(buf, (void *) (PAGE_OFFSET + p - PAGE_SIZE), count);
read += count;
file->f_pos += read;
return read;
}
 
static struct file_operations proc_kcore_operations = {
NULL, /* lseek */
read_core,
};
 
struct inode_operations proc_kcore_inode_operations = {
&proc_kcore_operations,
};
 
 
/*
* This function accesses profiling information. The returned data is
* binary: the sampling step and the actual contents of the profile
* buffer. Use of the program readprofile is recommended in order to
* get meaningful info out of these data.
*/
static int read_profile(struct inode *inode, struct file *file, char *buf, int count)
{
unsigned long p = file->f_pos;
int read;
char * pnt;
unsigned int sample_step = 1 << prof_shift;
 
if (count < 0)
return -EINVAL;
if (p >= (prof_len+1)*sizeof(unsigned int))
return 0;
if (count > (prof_len+1)*sizeof(unsigned int) - p)
count = (prof_len+1)*sizeof(unsigned int) - p;
read = 0;
 
while (p < sizeof(unsigned int) && count > 0) {
put_user(*((char *)(&sample_step)+p),buf);
buf++; p++; count--; read++;
}
pnt = (char *)prof_buffer + p - sizeof(unsigned int);
memcpy_tofs(buf,(void *)pnt,count);
read += count;
file->f_pos += read;
return read;
}
 
/* Writing to /proc/profile resets the counters */
static int write_profile(struct inode * inode, struct file * file, const char * buf, int count)
{
int i=prof_len;
 
while (i--)
prof_buffer[i]=0UL;
return count;
}
 
static struct file_operations proc_profile_operations = {
NULL, /* lseek */
read_profile,
write_profile,
};
 
struct inode_operations proc_profile_inode_operations = {
&proc_profile_operations,
};
 
 
static int get_loadavg(char * buffer)
{
int a, b, c;
 
a = avenrun[0] + (FIXED_1/200);
b = avenrun[1] + (FIXED_1/200);
c = avenrun[2] + (FIXED_1/200);
return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
LOAD_INT(a), LOAD_FRAC(a),
LOAD_INT(b), LOAD_FRAC(b),
LOAD_INT(c), LOAD_FRAC(c),
nr_running, nr_tasks, last_pid);
}
 
static int get_kstat(char * buffer)
{
int i, len;
unsigned sum = 0;
extern unsigned long total_forks;
 
for (i = 0 ; i < NR_IRQS ; i++)
sum += kstat.interrupts[i];
len = sprintf(buffer,
"cpu %u %u %u %lu\n"
"disk %u %u %u %u\n"
"disk_rio %u %u %u %u\n"
"disk_wio %u %u %u %u\n"
"disk_rblk %u %u %u %u\n"
"disk_wblk %u %u %u %u\n"
"page %u %u\n"
"swap %u %u\n"
"intr %u",
kstat.cpu_user,
kstat.cpu_nice,
kstat.cpu_system,
jiffies - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
kstat.dk_drive[0], kstat.dk_drive[1],
kstat.dk_drive[2], kstat.dk_drive[3],
kstat.dk_drive_rio[0], kstat.dk_drive_rio[1],
kstat.dk_drive_rio[2], kstat.dk_drive_rio[3],
kstat.dk_drive_wio[0], kstat.dk_drive_wio[1],
kstat.dk_drive_wio[2], kstat.dk_drive_wio[3],
kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1],
kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3],
kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1],
kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3],
kstat.pgpgin,
kstat.pgpgout,
kstat.pswpin,
kstat.pswpout,
sum);
for (i = 0 ; i < NR_IRQS ; i++)
len += sprintf(buffer + len, " %u", kstat.interrupts[i]);
len += sprintf(buffer + len,
"\nctxt %u\n"
"btime %lu\n"
"processes %lu\n",
kstat.context_swtch,
xtime.tv_sec - jiffies / HZ,
total_forks);
return len;
}
 
 
static int get_uptime(char * buffer)
{
unsigned long uptime;
unsigned long idle;
 
uptime = jiffies;
idle = task[0]->utime + task[0]->stime;
 
/* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
that would overflow about every five days at HZ == 100.
Therefore the identity a = (a / b) * b + a % b is used so that it is
calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
The part in front of the '+' always evaluates as 0 (mod 100). All divisions
in the above formulas are truncating. For HZ being a power of 10, the
calculations simplify to the version in the #else part (if the printf
format is adapted to the same number of digits as zeroes in HZ.
*/
#if HZ!=100
return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
uptime / HZ,
(((uptime % HZ) * 100) / HZ) % 100,
idle / HZ,
(((idle % HZ) * 100) / HZ) % 100);
#else
return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
uptime / HZ,
uptime % HZ,
idle / HZ,
idle % HZ);
#endif
}
 
static int get_meminfo(char * buffer)
{
struct sysinfo i;
int len;
 
si_meminfo(&i);
si_swapinfo(&i);
len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n"
"Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n"
"Swap: %8lu %8lu %8lu\n",
i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, page_cache_size*PAGE_SIZE,
i.totalswap, i.totalswap-i.freeswap, i.freeswap);
/*
* Tagged format, for easy grepping and expansion. The above will go away
* eventually, once the tools have been updated.
*/
return len + sprintf(buffer+len,
"MemTotal: %8lu kB\n"
"MemFree: %8lu kB\n"
"MemShared: %8lu kB\n"
"Buffers: %8lu kB\n"
"Cached: %8lu kB\n"
"SwapTotal: %8lu kB\n"
"SwapFree: %8lu kB\n",
i.totalram >> 10,
i.freeram >> 10,
i.sharedram >> 10,
i.bufferram >> 10,
page_cache_size << (PAGE_SHIFT - 10),
i.totalswap >> 10,
i.freeswap >> 10);
}
 
static int get_version(char * buffer)
{
extern const char *linux_banner;
 
strcpy(buffer, linux_banner);
return strlen(buffer);
}
 
static int get_cmdline(char * buffer)
{
extern char saved_command_line[];
 
return sprintf(buffer, "%s\n", saved_command_line);
}
 
static struct task_struct ** get_task(pid_t pid)
{
struct task_struct ** p;
 
p = task;
while (++p < task+NR_TASKS) {
if (*p && (*p)->pid == pid)
return p;
}
return NULL;
}
 
static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
{
#ifndef NO_MM
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
 
if (!p || !p->mm || ptr >= TASK_SIZE)
return 0;
page_dir = pgd_offset(p->mm,ptr);
if (pgd_none(*page_dir))
return 0;
if (pgd_bad(*page_dir)) {
printk("bad page directory entry %08lx\n", pgd_val(*page_dir));
pgd_clear(page_dir);
return 0;
}
page_middle = pmd_offset(page_dir,ptr);
if (pmd_none(*page_middle))
return 0;
if (pmd_bad(*page_middle)) {
printk("bad page middle entry %08lx\n", pmd_val(*page_middle));
pmd_clear(page_middle);
return 0;
}
pte = *pte_offset(page_middle,ptr);
if (!pte_present(pte))
return 0;
return pte_page(pte) + (ptr & ~PAGE_MASK);
#else /* NO_MM */
return ptr;
#endif /* NO_MM */
}
 
static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer)
{
unsigned long addr;
int size = 0, result = 0;
char c;
 
if (start >= end)
return result;
for (;;) {
addr = get_phys_addr(*p, start);
if (!addr)
return result;
do {
c = *(char *) addr;
if (!c)
result = size;
if (size < PAGE_SIZE)
buffer[size++] = c;
else
return result;
addr++;
start++;
if (!c && start >= end)
return result;
} while (addr & ~PAGE_MASK);
}
return result;
}
 
static int get_env(int pid, char * buffer)
{
struct task_struct ** p = get_task(pid);
 
if (!p || !*p || !(*p)->mm)
return 0;
return get_array(p, (*p)->mm->env_start, (*p)->mm->env_end, buffer);
}
 
static int get_arg(int pid, char * buffer)
{
struct task_struct ** p = get_task(pid);
 
if (!p || !*p || !(*p)->mm)
return 0;
return get_array(p, (*p)->mm->arg_start, (*p)->mm->arg_end, buffer);
}
 
#if defined(__i386__)
# define KSTK_EIP(tsk) (((unsigned long *)tsk->kernel_stack_page)[1019])
# define KSTK_ESP(tsk) (((unsigned long *)tsk->kernel_stack_page)[1022])
#elif defined(__alpha__)
/*
* See arch/alpha/kernel/ptrace.c for details.
*/
# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
+ (long)&((struct pt_regs *)0)->reg)
# define KSTK_EIP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
#elif defined(__sparc__)
# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
+ (long)&((struct pt_regs *)0)->reg)
# define KSTK_EIP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
# define KSTK_ESP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(u_regs[UREG_FP])))
#endif
 
/* Gcc optimizes away "strlen(x)" for constant x */
#define ADDBUF(buffer, string) \
do { memcpy(buffer, string, strlen(string)); \
buffer += strlen(string); } while (0)
 
static inline char * task_name(struct task_struct *p, char * buf)
{
int i;
char * name;
 
ADDBUF(buf, "Name:\t");
name = p->comm;
i = sizeof(p->comm);
do {
unsigned char c = *name;
name++;
i--;
*buf = c;
if (!c)
break;
if (c == '\\') {
buf[1] = c;
buf += 2;
continue;
}
if (c == '\n') {
buf[0] = '\\';
buf[1] = 'n';
buf += 2;
continue;
}
buf++;
} while (i);
*buf = '\n';
return buf+1;
}
 
static inline char * task_state(struct task_struct *p, char *buffer)
{
#define NR_STATES (sizeof(states)/sizeof(const char *))
unsigned int n = p->state;
static const char * states[] = {
"R (running)",
"S (sleeping)",
"D (disk sleep)",
"Z (zombie)",
"T (stopped)",
"W (paging)",
". Huh?"
};
 
if (n >= NR_STATES)
n = NR_STATES-1;
 
buffer += sprintf(buffer,
"State:\t%s\n"
"Pid:\t%d\n"
"PPid:\t%d\n"
"Uid:\t%d\t%d\t%d\t%d\n"
"Gid:\t%d\t%d\t%d\t%d\n",
states[n],
p->pid, p->p_pptr->pid,
p->uid, p->euid, p->suid, p->fsuid,
p->gid, p->egid, p->sgid, p->fsgid);
return buffer;
}
 
static inline char * task_mem(struct task_struct *p, char *buffer)
{
#ifndef NO_MM
struct mm_struct * mm = p->mm;
 
if (mm && mm != &init_mm) {
struct vm_area_struct * vma = mm->mmap;
unsigned long data = 0, stack = 0;
unsigned long exec = 0, lib = 0;
 
for (vma = mm->mmap; vma; vma = vma->vm_next) {
unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
if (!vma->vm_inode) {
data += len;
if (vma->vm_flags & VM_GROWSDOWN)
stack += len;
continue;
}
if (vma->vm_flags & VM_WRITE)
continue;
if (vma->vm_flags & VM_EXEC) {
exec += len;
if (vma->vm_flags & VM_EXECUTABLE)
continue;
lib += len;
}
}
buffer += sprintf(buffer,
"VmSize:\t%8lu kB\n"
"VmLck:\t%8lu kB\n"
"VmRSS:\t%8lu kB\n"
"VmData:\t%8lu kB\n"
"VmStk:\t%8lu kB\n"
"VmExe:\t%8lu kB\n"
"VmLib:\t%8lu kB\n",
mm->total_vm << (PAGE_SHIFT-10),
mm->locked_vm << (PAGE_SHIFT-10),
mm->rss << (PAGE_SHIFT-10),
data - stack, stack,
exec - lib, lib);
}
#else /* NO_MM */
unsigned long bytes = 0, sbytes = 0;
struct mm_tblock_struct * tblock;
/* Logic: we've got two memory sums for each process, "shared", and
* "non-shared". Shared memory may get counted more then once, for
* each process that owns it. Non-shared memory is counted
* accurately.
*
* -- Kenneth Albanowski
*/
 
for(tblock = &p->mm->tblock;tblock;tblock=tblock->next) {
if (tblock->rblock) {
bytes += ksize(tblock);
if ((p->mm->count > 1) || (tblock->rblock->refcount > 1)) {
sbytes += ksize(tblock->rblock->kblock);
sbytes += ksize(tblock->rblock) ;
} else {
bytes += ksize(tblock->rblock->kblock);
bytes += ksize(tblock->rblock) ;
}
}
}
((p->mm->count > 1) ? sbytes : bytes) += ksize(p->mm);
((p->fs->count > 1) ? sbytes : bytes) += ksize(p->fs);
((p->files->count > 1) ? sbytes : bytes) += ksize(p->files);
((p->sig->count > 1) ? sbytes : bytes) += ksize(p->sig);
bytes += ksize(p);
bytes += PAGE_SIZE; /* Kernel stack */
 
buffer += sprintf(buffer,
"Mem:\t%8lu bytes\n"
"Shared:\t%8lu bytes\n",
bytes,
sbytes);
#endif /* NO_MM */
return buffer;
}
 
static inline char * task_sig(struct task_struct *p, char *buffer)
{
buffer += sprintf(buffer,
"SigPnd:\t%08lx\n"
"SigBlk:\t%08lx\n",
p->signal, p->blocked);
if (p->sig) {
struct sigaction * action = p->sig->action;
unsigned long sig_ign = 0, sig_caught = 0;
unsigned long bit = 1;
int i;
 
for (i = 0; i < 32; i++) {
switch((unsigned long) action->sa_handler) {
case 0:
break;
case 1:
sig_ign |= bit;
break;
default:
sig_caught |= bit;
}
bit <<= 1;
action++;
}
 
buffer += sprintf(buffer,
"SigIgn:\t%08lx\n"
"SigCgt:\t%08lx\n",
sig_ign, sig_caught);
}
return buffer;
}
 
static int get_status(int pid, char * buffer)
{
char * orig = buffer;
struct task_struct ** p = get_task(pid), *tsk;
 
if (!p || (tsk = *p) == NULL)
return 0;
buffer = task_name(tsk, buffer);
buffer = task_state(tsk, buffer);
buffer = task_mem(tsk, buffer);
buffer = task_sig(tsk, buffer);
return buffer - orig;
}
 
static int get_stat(int pid, char * buffer)
{
struct task_struct ** p = get_task(pid), *tsk;
unsigned long sigignore=0, sigcatch=0, wchan;
unsigned long vsize, eip, esp;
long priority, nice;
int i,tty_pgrp;
char state;
 
if (!p || (tsk = *p) == NULL)
return 0;
if (tsk->state < 0 || tsk->state > 5)
state = '.';
else
state = "RSDZTW"[tsk->state];
vsize = eip = esp = 0;
if (tsk->mm && tsk->mm != &init_mm) {
#ifndef NO_MM
struct vm_area_struct *vma = tsk->mm->mmap;
while (vma) {
vsize += vma->vm_end - vma->vm_start;
vma = vma->vm_next;
}
if (tsk->kernel_stack_page) {
eip = KSTK_EIP(tsk);
esp = KSTK_ESP(tsk);
}
#endif /* !NO_MM */
}
wchan = get_wchan(tsk);
if (tsk->sig) {
unsigned long bit = 1;
for(i=0; i<32; ++i) {
switch((unsigned long) tsk->sig->action[i].sa_handler) {
case 0:
break;
case 1:
sigignore |= bit;
break;
default:
sigcatch |= bit;
}
bit <<= 1;
}
}
if (tsk->tty)
tty_pgrp = tsk->tty->pgrp;
else
tty_pgrp = -1;
 
/* scale priority and nice values from timeslices to -20..20 */
/* to make it look like a "normal" unix priority/nice value */
priority = tsk->counter;
priority = 20 - (priority * 10 + DEF_PRIORITY / 2) / DEF_PRIORITY;
nice = tsk->priority;
nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY;
 
return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu\n",
pid,
tsk->comm,
state,
tsk->p_pptr->pid,
tsk->pgrp,
tsk->session,
tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0,
tty_pgrp,
tsk->flags,
tsk->min_flt,
tsk->cmin_flt,
tsk->maj_flt,
tsk->cmaj_flt,
tsk->utime,
tsk->stime,
tsk->cutime,
tsk->cstime,
priority,
nice,
tsk->timeout,
tsk->it_real_value,
tsk->start_time,
vsize,
tsk->mm ? tsk->mm->rss : 0, /* you might want to shift this left 3 */
tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0,
tsk->mm ? tsk->mm->start_code : 0,
tsk->mm ? tsk->mm->end_code : 0,
tsk->mm ? tsk->mm->start_stack : 0,
esp,
eip,
tsk->signal,
tsk->blocked,
sigignore,
sigcatch,
wchan,
tsk->nswap,
tsk->cnswap);
}
#ifndef NO_MM
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
int * pages, int * shared, int * dirty, int * total)
{
pte_t * pte;
unsigned long end;
 
if (pmd_none(*pmd))
return;
if (pmd_bad(*pmd)) {
printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
pmd_clear(pmd);
return;
}
pte = pte_offset(pmd, address);
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
pte_t page = *pte;
 
address += PAGE_SIZE;
pte++;
if (pte_none(page))
continue;
++*total;
if (!pte_present(page))
continue;
++*pages;
if (pte_dirty(page))
++*dirty;
if (pte_page(page) >= high_memory)
continue;
if (mem_map[MAP_NR(pte_page(page))].count > 1)
++*shared;
} while (address < end);
}
 
static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size,
int * pages, int * shared, int * dirty, int * total)
{
pmd_t * pmd;
unsigned long end;
 
if (pgd_none(*pgd))
return;
if (pgd_bad(*pgd)) {
printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
pgd_clear(pgd);
return;
}
pmd = pmd_offset(pgd, address);
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
do {
statm_pte_range(pmd, address, end - address, pages, shared, dirty, total);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
}
 
static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end,
int * pages, int * shared, int * dirty, int * total)
{
while (address < end) {
statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
pgd++;
}
}
 
static int get_statm(int pid, char * buffer)
{
struct task_struct ** p = get_task(pid), *tsk;
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
 
if (!p || (tsk = *p) == NULL)
return 0;
if (tsk->mm && tsk->mm != &init_mm) {
struct vm_area_struct * vma = tsk->mm->mmap;
 
while (vma) {
pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
int pages = 0, shared = 0, dirty = 0, total = 0;
 
statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
resident += pages;
share += shared;
dt += dirty;
size += total;
if (vma->vm_flags & VM_EXECUTABLE)
trs += pages; /* text */
else if (vma->vm_flags & VM_GROWSDOWN)
drs += pages; /* stack */
else if (vma->vm_end > 0x60000000)
lrs += pages; /* library */
else
drs += pages;
vma = vma->vm_next;
}
}
return sprintf(buffer,"%d %d %d %d %d %d %d\n",
size, resident, share, trs, lrs, drs, dt);
}
 
/*
* The way we support synthetic files > 4K
* - without storing their contents in some buffer and
* - without walking through the entire synthetic file until we reach the
* position of the requested data
* is to cleverly encode the current position in the file's f_pos field.
* There is no requirement that a read() call which returns `count' bytes
* of data increases f_pos by exactly `count'.
*
* This idea is Linus' one. Bruno implemented it.
*/
 
/*
* For the /proc/<pid>/maps file, we use fixed length records, each containing
* a single line.
*/
#define MAPS_LINE_LENGTH 1024
#define MAPS_LINE_SHIFT 10
/*
* f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH
* + (index into the line)
*/
/* for systems with sizeof(void*) == 4: */
#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %s %lu\n"
#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */
 
/* for systems with sizeof(void*) == 8: */
#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %s %lu\n"
#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */
 
#define MAPS_LINE_MAX MAPS_LINE_MAX8
 
 
static int read_maps (int pid, struct file * file, char * buf, int count)
{
struct task_struct ** p = get_task(pid);
char * destptr;
loff_t lineno;
int column;
struct vm_area_struct * map;
int i;
 
if (!p || !*p)
return -EINVAL;
 
if (!(*p)->mm || (*p)->mm == &init_mm || count == 0)
return 0;
 
/* decode f_pos */
lineno = file->f_pos >> MAPS_LINE_SHIFT;
column = file->f_pos & (MAPS_LINE_LENGTH-1);
 
/* quickly go to line lineno */
for (map = (*p)->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
continue;
 
destptr = buf;
 
for ( ; map ; ) {
/* produce the next line */
char line[MAPS_LINE_MAX+1];
char str[5], *cp = str;
int flags;
kdev_t dev;
unsigned long ino;
int len;
 
flags = map->vm_flags;
 
*cp++ = flags & VM_READ ? 'r' : '-';
*cp++ = flags & VM_WRITE ? 'w' : '-';
*cp++ = flags & VM_EXEC ? 'x' : '-';
*cp++ = flags & VM_MAYSHARE ? 's' : 'p';
*cp++ = 0;
 
if (map->vm_inode != NULL) {
dev = map->vm_inode->i_dev;
ino = map->vm_inode->i_ino;
} else {
dev = 0;
ino = 0;
}
 
len = sprintf(line,
sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8,
map->vm_start, map->vm_end, str, map->vm_offset,
kdevname(dev), ino);
 
if (column >= len) {
column = 0; /* continue with next line at column 0 */
lineno++;
map = map->vm_next;
continue;
}
 
i = len-column;
if (i > count)
i = count;
memcpy_tofs(destptr, line+column, i);
destptr += i; count -= i;
column += i;
if (column >= len) {
column = 0; /* next time: next line at column 0 */
lineno++;
map = map->vm_next;
}
 
/* done? */
if (count == 0)
break;
 
/* By writing to user space, we might have slept.
* Stop the loop, to avoid a race condition.
*/
if (*p != current)
break;
}
 
/* encode f_pos */
file->f_pos = (lineno << MAPS_LINE_SHIFT) + column;
 
return destptr-buf;
}
#endif /* !NO_MM */
 
#ifdef CONFIG_MODULES
extern int get_module_list(char *);
extern int get_ksyms_list(char *, char **, off_t, int);
#endif
extern int get_device_list(char *);
extern int get_filesystem_list(char *);
extern int get_filesystem_info( char * );
extern int get_irq_list(char *);
extern int get_serialinfo(char *);
extern int get_dma_list(char *);
extern int get_cpuinfo(char *);
extern int get_pci_list(char*);
extern int get_md_status (char *);
extern int get_rtc_status (char *);
extern int get_locks_status (char *, char **, off_t, int);
#ifdef __SMP_PROF__
extern int get_smp_prof_list(char *);
#endif
 
static int get_root_array(char * page, int type, char **start, off_t offset, int length)
{
switch (type) {
case PROC_LOADAVG:
return get_loadavg(page);
 
case PROC_UPTIME:
return get_uptime(page);
 
case PROC_MEMINFO:
return get_meminfo(page);
 
#ifdef CONFIG_PCI
case PROC_PCI:
return get_pci_list(page);
#endif
case PROC_CPUINFO:
return get_cpuinfo(page);
 
case PROC_VERSION:
return get_version(page);
 
#ifdef CONFIG_DEBUG_MALLOC
case PROC_MALLOC:
return get_malloc(page);
#endif
 
#ifdef CONFIG_MODULES
case PROC_MODULES:
return get_module_list(page);
 
case PROC_KSYMS:
return get_ksyms_list(page, start, offset, length);
#endif
 
case PROC_STAT:
return get_kstat(page);
 
case PROC_DEVICES:
return get_device_list(page);
 
case PROC_INTERRUPTS:
return get_irq_list(page);
 
case PROC_SERIAL:
return get_serialinfo(page);
 
case PROC_FILESYSTEMS:
return get_filesystem_list(page);
 
case PROC_DMA:
return get_dma_list(page);
 
case PROC_IOPORTS:
return get_ioport_list(page);
#ifdef CONFIG_BLK_DEV_MD
case PROC_MD:
return get_md_status(page);
#endif
#ifdef __SMP_PROF__
case PROC_SMP_PROF:
return get_smp_prof_list(page);
#endif
case PROC_CMDLINE:
return get_cmdline(page);
 
case PROC_MTAB:
return get_filesystem_info( page );
#ifdef CONFIG_RTC
case PROC_RTC:
return get_rtc_status(page);
#endif
case PROC_LOCKS:
return get_locks_status(page, start, offset, length);
}
return -EBADF;
}
 
static int process_unauthorized(int type, int pid)
{
struct task_struct ** p = get_task(pid);
 
if (!p || !*p || !(*p)->mm)
return 1;
 
switch(type)
{
case PROC_PID_STATUS:
case PROC_PID_STAT:
case PROC_PID_CMDLINE:
#ifndef NO_MM
case PROC_PID_STATM:
case PROC_PID_MAPS:
#endif
return 0;
}
if(suser() || current->fsuid == (*p)->euid)
return 0;
return 1;
}
 
 
static int get_process_array(char * page, int pid, int type)
{
switch (type) {
case PROC_PID_STATUS:
return get_status(pid, page);
case PROC_PID_ENVIRON:
return get_env(pid, page);
case PROC_PID_CMDLINE:
return get_arg(pid, page);
case PROC_PID_STAT:
return get_stat(pid, page);
#ifndef NO_MM
case PROC_PID_STATM:
return get_statm(pid, page);
#endif /* !NO_MM */
}
return -EBADF;
}
 
 
static inline int fill_array(char * page, int pid, int type, char **start, off_t offset, int length)
{
if (pid)
return get_process_array(page, pid, type);
return get_root_array(page, type, start, offset, length);
}
 
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
 
static int array_read(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long page;
char *start;
int length;
int end;
unsigned int type, pid;
struct proc_dir_entry *dp;
 
if (count < 0)
return -EINVAL;
if (count > PROC_BLOCK_SIZE)
count = PROC_BLOCK_SIZE;
if (!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
type = inode->i_ino;
pid = type >> 16;
type &= 0x0000ffff;
start = NULL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
if (pid && process_unauthorized(type, pid))
{
free_page(page);
return -EIO;
}
if (dp->get_info)
length = dp->get_info((char *)page, &start, file->f_pos,
count, 0);
else
length = fill_array((char *) page, pid, type,
&start, file->f_pos, count);
if (length < 0) {
free_page(page);
return length;
}
if (start != NULL) {
/* We have had block-adjusting processing! */
memcpy_tofs(buf, start, length);
file->f_pos += length;
count = length;
} else {
/* Static 4kB (or whatever) block capacity */
if (file->f_pos >= length) {
free_page(page);
return 0;
}
if (count + file->f_pos > length)
count = length - file->f_pos;
end = count + file->f_pos;
memcpy_tofs(buf, (char *) page + file->f_pos, count);
file->f_pos = end;
}
free_page(page);
return count;
}
 
static struct file_operations proc_array_operations = {
NULL, /* array_lseek */
array_read,
NULL, /* array_write */
NULL, /* array_readdir */
NULL, /* array_select */
NULL, /* array_ioctl */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
struct inode_operations proc_array_inode_operations = {
&proc_array_operations, /* default base directory file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
static int arraylong_read (struct inode * inode, struct file * file, char * buf, int count)
{
#ifndef NO_MM
unsigned int pid = inode->i_ino >> 16;
unsigned int type = inode->i_ino & 0x0000ffff;
 
if (count < 0)
return -EINVAL;
 
switch (type) {
case PROC_PID_MAPS:
return read_maps(pid, file, buf, count);
}
#endif /* !NO_MM */
return -EINVAL;
}
 
static struct file_operations proc_arraylong_operations = {
NULL, /* array_lseek */
arraylong_read,
NULL, /* array_write */
NULL, /* array_readdir */
NULL, /* array_select */
NULL, /* array_ioctl */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
struct inode_operations proc_arraylong_inode_operations = {
&proc_arraylong_operations, /* default base directory file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
/inode.c
0,0 → 1,266
/*
* linux/fs/proc/inode.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
 
/*
* uClinux revisions for NO_MM
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
* The Silver Hammer Group, Ltd.
*/
 
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/locks.h>
#include <linux/limits.h>
 
#include <asm/system.h>
#include <asm/segment.h>
 
static void proc_put_inode(struct inode *inode)
{
if (inode->i_nlink)
return;
inode->i_size = 0;
}
 
static void proc_put_super(struct super_block *sb)
{
lock_super(sb);
sb->s_dev = 0;
unlock_super(sb);
}
 
static struct super_operations proc_sops = {
proc_read_inode,
NULL,
proc_write_inode,
proc_put_inode,
proc_put_super,
NULL,
proc_statfs,
NULL
};
 
 
static int parse_options(char *options,uid_t *uid,gid_t *gid)
{
char *this_char,*value;
 
*uid = current->uid;
*gid = current->gid;
if (!options) return 1;
for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"uid")) {
if (!value || !*value)
return 0;
*uid = simple_strtoul(value,&value,0);
if (*value)
return 0;
}
else if (!strcmp(this_char,"gid")) {
if (!value || !*value)
return 0;
*gid = simple_strtoul(value,&value,0);
if (*value)
return 0;
}
else return 1;
}
return 1;
}
 
struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de)
{
struct inode * inode = iget(s, ino);
if (inode && inode->i_sb == s) {
inode->u.generic_ip = (void *) de;
if (de) {
if (de->mode) {
inode->i_mode = de->mode;
inode->i_uid = de->uid;
inode->i_gid = de->gid;
}
if (de->size)
inode->i_size = de->size;
if (de->ops)
inode->i_op = de->ops;
if (de->nlink)
inode->i_nlink = de->nlink;
if (de->fill_inode)
de->fill_inode(inode);
}
}
return inode;
}
 
struct super_block *proc_read_super(struct super_block *s,void *data,
int silent)
{
proc_root_init();
lock_super(s);
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = PROC_SUPER_MAGIC;
s->s_op = &proc_sops;
unlock_super(s);
if (!(s->s_mounted = proc_get_inode(s, PROC_ROOT_INO, &proc_root))) {
s->s_dev = 0;
printk("get root inode failed\n");
return NULL;
}
parse_options(data, &s->s_mounted->i_uid, &s->s_mounted->i_gid);
return s;
}
 
void proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
 
tmp.f_type = PROC_SUPER_MAGIC;
tmp.f_bsize = PAGE_SIZE/sizeof(long);
tmp.f_blocks = 0;
tmp.f_bfree = 0;
tmp.f_bavail = 0;
tmp.f_files = 0;
tmp.f_ffree = 0;
tmp.f_namelen = NAME_MAX;
memcpy_tofs(buf, &tmp, bufsiz);
}
 
void proc_read_inode(struct inode * inode)
{
unsigned long ino, pid;
struct task_struct * p;
int i;
inode->i_op = NULL;
inode->i_mode = 0;
inode->i_uid = 0;
inode->i_gid = 0;
inode->i_nlink = 1;
inode->i_size = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
inode->i_blksize = 1024;
ino = inode->i_ino;
pid = ino >> 16;
p = task[0];
for (i = 0; i < NR_TASKS ; i++)
if ((p = task[i]) && (p->pid == pid))
break;
if (!p || i >= NR_TASKS)
return;
if (ino == PROC_ROOT_INO) {
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
inode->i_nlink = 2;
for (i = 1 ; i < NR_TASKS ; i++)
if (task[i])
inode->i_nlink++;
return;
}
 
if (!pid) {
switch (ino) {
case PROC_KMSG:
inode->i_mode = S_IFREG | S_IRUSR;
inode->i_op = &proc_kmsg_inode_operations;
break;
case PROC_NET:
inode->i_nlink = 2;
break;
case PROC_SCSI:
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
inode->i_nlink = 2;
inode->i_op = &proc_scsi_inode_operations;
break;
case PROC_KCORE:
inode->i_mode = S_IFREG | S_IRUSR;
inode->i_op = &proc_kcore_inode_operations;
inode->i_size = (MAP_NR(high_memory) << PAGE_SHIFT) + PAGE_SIZE;
break;
case PROC_PROFILE:
inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
inode->i_op = &proc_profile_inode_operations;
inode->i_size = (1+prof_len) * sizeof(unsigned long);
break;
default:
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_op = &proc_array_inode_operations;
break;
}
return;
}
ino &= 0x0000ffff;
if (ino == PROC_PID_INO || p->dumpable) {
inode->i_uid = p->euid;
inode->i_gid = p->egid;
}
switch (ino) {
case PROC_PID_INO:
inode->i_nlink = 4;
return;
case PROC_PID_MEM:
inode->i_op = &proc_mem_inode_operations;
inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
return;
case PROC_PID_CWD:
case PROC_PID_ROOT:
case PROC_PID_EXE:
inode->i_op = &proc_link_inode_operations;
inode->i_size = 64;
inode->i_mode = S_IFLNK | S_IRWXU;
return;
case PROC_PID_FD:
inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
inode->i_op = &proc_fd_inode_operations;
inode->i_nlink = 2;
return;
case PROC_PID_ENVIRON:
inode->i_mode = S_IFREG | S_IRUSR;
inode->i_op = &proc_array_inode_operations;
return;
case PROC_PID_CMDLINE:
case PROC_PID_STATUS:
case PROC_PID_STAT:
#ifndef NO_MM
case PROC_PID_STATM:
#endif /* !NO_MM */
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_op = &proc_array_inode_operations;
return;
#ifndef NO_MM
case PROC_PID_MAPS:
inode->i_mode = S_IFIFO | S_IRUGO;
inode->i_op = &proc_arraylong_inode_operations;
return;
#endif /* !NO_MM */
}
switch (ino >> 8) {
case PROC_PID_FD_DIR:
ino &= 0xff;
if (ino >= NR_OPEN || !p->files || !p->files->fd[ino])
return;
inode->i_op = &proc_link_inode_operations;
inode->i_size = 64;
inode->i_mode = S_IFLNK;
if (p->files->fd[ino]->f_mode & 1)
inode->i_mode |= S_IRUSR | S_IXUSR;
if (p->files->fd[ino]->f_mode & 2)
inode->i_mode |= S_IWUSR | S_IXUSR;
return;
}
return;
}
 
void proc_write_inode(struct inode * inode)
{
inode->i_dirt=0;
}
/mem.c
0,0 → 1,508
/*
* linux/fs/proc/mem.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
 
/*
* uClinux revisions for NO_MM
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
* The Silver Hammer Group, Ltd.
*/
 
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
 
#include <asm/page.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <asm/pgtable.h>
 
#ifndef NO_MM
 
/*
* mem_write isn't really a good idea right now. It needs
* to check a lot more: if the process we try to write to
* dies in the middle right now, mem_write will overwrite
* kernel memory.. This disables it altogether.
*/
#define mem_write NULL
 
static int check_range(struct mm_struct * mm, unsigned long addr, int count)
{
struct vm_area_struct *vma;
int retval;
 
vma = find_vma(mm, addr);
if (!vma)
return -EACCES;
if (vma->vm_start > addr)
return -EACCES;
if (!(vma->vm_flags & VM_READ))
return -EACCES;
while ((retval = vma->vm_end - addr) < count) {
struct vm_area_struct *next = vma->vm_next;
if (!next)
break;
if (vma->vm_end != next->vm_start)
break;
if (!(next->vm_flags & VM_READ))
break;
vma = next;
}
if (retval > count)
retval = count;
return retval;
}
 
static struct task_struct * get_task(int pid)
{
struct task_struct * tsk = current;
 
if (pid != tsk->pid) {
int i;
tsk = NULL;
for (i = 1 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid) {
tsk = task[i];
break;
}
/*
* allow accesses only under the same circumstances
* that we would allow ptrace to work
*/
if (tsk) {
if (!(tsk->flags & PF_PTRACED)
|| tsk->state != TASK_STOPPED
|| tsk->p_pptr != current)
tsk = NULL;
}
}
return tsk;
}
 
static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
{
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
char * page;
struct task_struct * tsk;
unsigned long addr;
char *tmp;
int i;
 
if (count < 0)
return -EINVAL;
tsk = get_task(inode->i_ino >> 16);
if (!tsk)
return -ESRCH;
addr = file->f_pos;
count = check_range(tsk->mm, addr, count);
if (count < 0)
return count;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
page_dir = pgd_offset(tsk->mm,addr);
if (pgd_none(*page_dir))
break;
if (pgd_bad(*page_dir)) {
printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
pgd_clear(page_dir);
break;
}
page_middle = pmd_offset(page_dir,addr);
if (pmd_none(*page_middle))
break;
if (pmd_bad(*page_middle)) {
printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
pmd_clear(page_middle);
break;
}
pte = *pte_offset(page_middle,addr);
if (!pte_present(pte))
break;
page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
i = PAGE_SIZE-(addr & ~PAGE_MASK);
if (i > count)
i = count;
memcpy_tofs(tmp, page, i);
addr += i;
tmp += i;
count -= i;
}
file->f_pos = addr;
return tmp-buf;
}
 
#ifndef mem_write
 
static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
{
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
char * page;
struct task_struct * tsk;
unsigned long addr;
char *tmp;
int i;
 
if (count < 0)
return -EINVAL;
addr = file->f_pos;
tsk = get_task(inode->i_ino >> 16);
if (!tsk)
return -ESRCH;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
page_dir = pgd_offset(tsk,addr);
if (pgd_none(*page_dir))
break;
if (pgd_bad(*page_dir)) {
printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
pgd_clear(page_dir);
break;
}
page_middle = pmd_offset(page_dir,addr);
if (pmd_none(*page_middle))
break;
if (pmd_bad(*page_middle)) {
printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
pmd_clear(page_middle);
break;
}
pte = *pte_offset(page_middle,addr);
if (!pte_present(pte))
break;
if (!pte_write(pte))
break;
page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
i = PAGE_SIZE-(addr & ~PAGE_MASK);
if (i > count)
i = count;
memcpy_fromfs(page, tmp, i);
addr += i;
tmp += i;
count -= i;
}
file->f_pos = addr;
if (tmp != buf)
return tmp-buf;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
return 0;
}
 
#endif
 
static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
{
switch (orig) {
case 0:
file->f_pos = offset;
return file->f_pos;
case 1:
file->f_pos += offset;
return file->f_pos;
default:
return -EINVAL;
}
}
 
/*
* This isn't really reliable by any means..
*/
int mem_mmap(struct inode * inode, struct file * file,
struct vm_area_struct * vma)
{
struct task_struct *tsk;
pgd_t *src_dir, *dest_dir;
pmd_t *src_middle, *dest_middle;
pte_t *src_table, *dest_table;
unsigned long stmp, dtmp, mapnr;
struct vm_area_struct *src_vma = NULL;
 
/* Get the source's task information */
 
tsk = get_task(inode->i_ino >> 16);
 
if (!tsk)
return -ESRCH;
 
/* Ensure that we have a valid source area. (Has to be mmap'ed and
have valid page information.) We can't map shared memory at the
moment because working out the vm_area_struct & nattach stuff isn't
worth it. */
 
src_vma = tsk->mm->mmap;
stmp = vma->vm_offset;
while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
while (src_vma && stmp > src_vma->vm_end)
src_vma = src_vma->vm_next;
if (!src_vma || (src_vma->vm_flags & VM_SHM))
return -EINVAL;
 
src_dir = pgd_offset(tsk->mm, stmp);
if (pgd_none(*src_dir))
return -EINVAL;
if (pgd_bad(*src_dir)) {
printk("Bad source page dir entry %08lx\n", pgd_val(*src_dir));
return -EINVAL;
}
src_middle = pmd_offset(src_dir, stmp);
if (pmd_none(*src_middle))
return -EINVAL;
if (pmd_bad(*src_middle)) {
printk("Bad source page middle entry %08lx\n", pmd_val(*src_middle));
return -EINVAL;
}
src_table = pte_offset(src_middle, stmp);
if (pte_none(*src_table))
return -EINVAL;
 
if (stmp < src_vma->vm_start) {
if (!(src_vma->vm_flags & VM_GROWSDOWN))
return -EINVAL;
if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
return -EINVAL;
}
stmp += PAGE_SIZE;
}
 
src_vma = tsk->mm->mmap;
stmp = vma->vm_offset;
dtmp = vma->vm_start;
 
flush_cache_range(vma->vm_mm, vma->vm_start, vma->vm_end);
flush_cache_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
while (dtmp < vma->vm_end) {
while (src_vma && stmp > src_vma->vm_end)
src_vma = src_vma->vm_next;
 
src_dir = pgd_offset(tsk->mm, stmp);
src_middle = pmd_offset(src_dir, stmp);
src_table = pte_offset(src_middle, stmp);
 
dest_dir = pgd_offset(current->mm, dtmp);
dest_middle = pmd_alloc(dest_dir, dtmp);
if (!dest_middle)
return -ENOMEM;
dest_table = pte_alloc(dest_middle, dtmp);
if (!dest_table)
return -ENOMEM;
 
if (!pte_present(*src_table))
do_no_page(tsk, src_vma, stmp, 1);
 
if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
do_wp_page(tsk, src_vma, stmp, 1);
 
set_pte(src_table, pte_mkdirty(*src_table));
set_pte(dest_table, *src_table);
mapnr = MAP_NR(pte_page(*src_table));
if (mapnr < MAP_NR(high_memory))
mem_map[mapnr].count++;
 
stmp += PAGE_SIZE;
dtmp += PAGE_SIZE;
}
 
flush_tlb_range(vma->vm_mm, vma->vm_start, vma->vm_end);
flush_tlb_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
return 0;
}
 
static struct file_operations proc_mem_operations = {
mem_lseek,
mem_read,
mem_write,
NULL, /* mem_readdir */
NULL, /* mem_select */
NULL, /* mem_ioctl */
mem_mmap, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
struct inode_operations proc_mem_inode_operations = {
&proc_mem_operations, /* default base directory file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
#else /* NO_MM */
 
/*
* mem_write isn't really a good idea right now. It needs
* to check a lot more: if the process we try to write to
* dies in the middle right now, mem_write will overwrite
* kernel memory.. This disables it altogether.
*/
#define mem_write NULL
 
static struct task_struct * get_task(int pid)
{
struct task_struct * tsk = current;
 
if (pid != tsk->pid) {
int i;
tsk = NULL;
for (i = 1 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid) {
tsk = task[i];
break;
}
/*
* allow accesses only under the same circumstances
* that we would allow ptrace to work
*/
if (tsk) {
if (!(tsk->flags & PF_PTRACED)
|| tsk->state != TASK_STOPPED
|| tsk->p_pptr != current)
tsk = NULL;
}
}
return tsk;
}
 
static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
{
struct task_struct * tsk;
unsigned long addr;
char *tmp;
int i;
if (count < 0)
return -EINVAL;
tsk = get_task(inode->i_ino >> 16);
if (!tsk)
return -ESRCH;
addr = file->f_pos;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
i = count;
memcpy_tofs(tmp, (void*)addr, i);
addr += i;
tmp += i;
count -= i;
}
file->f_pos = addr;
return tmp-buf;
}
 
#ifndef mem_write
 
static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
{
struct task_struct * tsk;
unsigned long addr;
char *tmp;
int i;
 
if (count < 0)
return -EINVAL;
addr = file->f_pos;
tsk = get_task(inode->i_ino >> 16);
if (!tsk)
return -ESRCH;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
i = count;
memcpy_fromfs((void*)addr, tmp, i);
addr += i;
tmp += i;
count -= i;
}
file->f_pos = addr;
if (tmp != buf)
return tmp-buf;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
return 0;
}
 
#endif
 
int mem_mmap(struct inode * inode, struct file * file,
struct vm_area_struct * vma)
{
vma->vm_start = vma->vm_offset;
return 0;
}
 
static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
{
switch (orig) {
case 0:
file->f_pos = offset;
return file->f_pos;
case 1:
file->f_pos += offset;
return file->f_pos;
default:
return -EINVAL;
}
}
 
static struct file_operations proc_mem_operations = {
mem_lseek,
mem_read,
mem_write,
NULL, /* mem_readdir */
NULL, /* mem_select */
NULL, /* mem_ioctl */
mem_mmap, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
struct inode_operations proc_mem_inode_operations = {
&proc_mem_operations, /* default base directory file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
#endif /* NO_MM */
/serial.c
0,0 → 1,45
/*
* linux/fs/proc/serial.c
*
* Copyright (C) 1999, Greg Ungerer (gerg@moreton.com.au)
*
* Copied and hacked from array.c, which was:
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
 
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/tty.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/string.h>
#include <linux/mman.h>
#include <linux/proc_fs.h>
#include <linux/ioport.h>
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
 
#include <asm/segment.h>
#include <asm/pgtable.h>
#include <asm/io.h>
 
int get_serialinfo(char * buffer)
{
int len = 0;
 
#ifdef CONFIG_COLDFIRE_SERIAL
extern int mcfrs_readproc(char *buffer);
len = mcfrs_readproc(buffer);
#else
len += sprintf(buffer, "No Serial Info\n");
#endif
 
return(len);
}
 
/kmsg.c
0,0 → 1,78
/*
* linux/fs/proc/kmsg.c
*
* Copyright (C) 1992 by Linus Torvalds
*
*/
 
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
 
#include <asm/segment.h>
#include <asm/io.h>
 
extern unsigned long log_size;
extern struct wait_queue * log_wait;
 
asmlinkage int sys_syslog(int type, char * bug, int count);
 
static int kmsg_open(struct inode * inode, struct file * file)
{
return sys_syslog(1,NULL,0);
}
 
static void kmsg_release(struct inode * inode, struct file * file)
{
(void) sys_syslog(0,NULL,0);
}
 
static int kmsg_read(struct inode * inode, struct file * file,char * buf, int count)
{
return sys_syslog(2,buf,count);
}
 
static int kmsg_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
{
if (sel_type != SEL_IN)
return 0;
if (log_size)
return 1;
select_wait(&log_wait, wait);
return 0;
}
 
 
static struct file_operations proc_kmsg_operations = {
NULL, /* kmsg_lseek */
kmsg_read,
NULL, /* kmsg_write */
NULL, /* kmsg_readdir */
kmsg_select, /* kmsg_select */
NULL, /* kmsg_ioctl */
NULL, /* mmap */
kmsg_open,
kmsg_release,
NULL /* can't fsync */
};
 
struct inode_operations proc_kmsg_inode_operations = {
&proc_kmsg_operations, /* default base directory file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
/scsi.c
0,0 → 1,223
/*
* linux/fs/proc/scsi.c
* (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
*
* The original version was derived from linux/fs/proc/net.c,
* which is Copyright (C) 1991, 1992 Linus Torvalds.
* Much has been rewritten, but some of the code still remains.
*
* /proc/scsi directory handling functions
*
* last change: 95/07/04
*
* Initial version: March '95
* 95/05/15 Added subdirectories for each driver and show every
* registered HBA as a single file.
* 95/05/30 Added rudimentary write support for parameter passing
* 95/07/04 Fixed bugs in directory handling
* 95/09/13 Update to support the new proc-dir tree
*
* TODO: Improve support to write to the driver files
* Add some more comments
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/mm.h>
 
#include <asm/segment.h>
 
/* forward references */
static int proc_readscsi(struct inode * inode, struct file * file,
char * buf, int count);
static int proc_writescsi(struct inode * inode, struct file * file,
const char * buf, int count);
static int proc_scsilseek(struct inode *, struct file *, off_t, int);
 
extern void build_proc_dir_hba_entries(uint);
 
/* the *_get_info() functions are in the respective scsi driver code */
int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
off_t offset, int length, int inout) = 0;
 
static struct file_operations proc_scsi_operations = {
proc_scsilseek, /* lseek */
proc_readscsi, /* read */
proc_writescsi, /* write */
proc_readdir, /* readdir */
NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
/*
* proc directories can do almost nothing..
*/
struct inode_operations proc_scsi_inode_operations = {
&proc_scsi_operations, /* default scsi directory file-ops */
NULL, /* create */
proc_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
int get_not_present_info(char *buffer, char **start, off_t offset, int length)
{
int len, pos, begin;
begin = 0;
pos = len = sprintf(buffer,
"No low-level scsi modules are currently present\n");
if(pos < offset) {
len = 0;
begin = pos;
}
*start = buffer + (offset - begin); /* Start of wanted data */
len -= (offset - begin);
if(len > length)
len = length;
return(len);
}
 
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size, but our output routines
* use some slack for overruns
*/
 
static int proc_readscsi(struct inode * inode, struct file * file,
char * buf, int count)
{
int length;
int bytes = count;
int copied = 0;
int thistime;
char * page;
char * start;
if (count < -1) /* Normally I wouldn't do this, */
return(-EINVAL); /* but it saves some redundant code.
* Now it is possible to seek to the
* end of the file */
if (!(page = (char *) __get_free_page(GFP_KERNEL)))
return(-ENOMEM);
while(bytes > 0 || count == -1) {
thistime = bytes;
if(bytes > PROC_BLOCK_SIZE || count == -1)
thistime = PROC_BLOCK_SIZE;
if(dispatch_scsi_info_ptr)
length = dispatch_scsi_info_ptr(inode->i_ino, page, &start,
file->f_pos, thistime, 0);
else
length = get_not_present_info(page, &start, file->f_pos, thistime);
if(length < 0) {
free_page((ulong) page);
return(length);
}
/*
* We have been given a non page aligned block of
* the data we asked for + a bit. We have been given
* the start pointer and we know the length..
*/
if (length <= 0)
break;
/*
* Copy the bytes, if we're not doing a seek to
* the end of the file
*/
if (count != -1)
memcpy_tofs(buf + copied, start, length);
file->f_pos += length; /* Move down the file */
bytes -= length;
copied += length;
if(length < thistime)
break; /* End of file */
}
free_page((ulong) page);
return(copied);
}
 
 
static int proc_writescsi(struct inode * inode, struct file * file,
const char * buf, int count)
{
int ret = 0;
char * page;
if(count > PROC_BLOCK_SIZE) {
return(-EOVERFLOW);
}
 
if(dispatch_scsi_info_ptr != NULL) {
if (!(page = (char *) __get_free_page(GFP_KERNEL)))
return(-ENOMEM);
memcpy_fromfs(page, buf, count);
ret = dispatch_scsi_info_ptr(inode->i_ino, page, 0, 0, count, 1);
} else
return(-ENOPKG); /* Nothing here */
free_page((ulong) page);
return(ret);
}
 
 
static int proc_scsilseek(struct inode * inode, struct file * file,
off_t offset, int orig)
{
switch (orig) {
case 0:
file->f_pos = offset;
return(file->f_pos);
case 1:
file->f_pos += offset;
return(file->f_pos);
case 2: /* This ugly hack allows us to */
if (offset) /* to determine the length of the */
return(-EINVAL); /* file and then later safely to */
proc_readscsi(inode, file, 0, -1); /* seek in it */
return(file->f_pos);
default:
return(-EINVAL);
}
}
 
/*
* Overrides for Emacs so that we almost follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* indent-tabs-mode: nil
* tab-width: 8
* End:
*/
/root.c
0,0 → 1,629
/*
* linux/fs/proc/root.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* proc root directory handling functions
*/
 
#include <asm/segment.h>
 
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/config.h>
#include <asm/bitops.h>
 
/*
* Offset of the first process in the /proc root directory..
*/
#define FIRST_PROCESS_ENTRY 256
 
static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
 
static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
 
/*
* These are the generic /proc directory operations. They
* use the in-memory "struct proc_dir_entry" tree to parse
* the /proc directory.
*
* NOTE! The /proc/scsi directory currently does not correctly
* build up the proc_dir_entry tree, and will show up empty.
*/
static struct file_operations proc_dir_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_readdir, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
/*
* proc directories can do almost nothing..
*/
struct inode_operations proc_dir_inode_operations = {
&proc_dir_operations, /* default net directory file-ops */
NULL, /* create */
proc_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
/*
* The root /proc directory is special, as it has the
* <pid> directories. Thus we don't use the generic
* directory handling functions for that..
*/
static struct file_operations proc_root_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_root_readdir, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* no fsync */
};
 
/*
* proc root can do almost nothing..
*/
static struct inode_operations proc_root_inode_operations = {
&proc_root_operations, /* default base directory file-ops */
NULL, /* create */
proc_root_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
/*
* This is the root "inode" in the /proc tree..
*/
struct proc_dir_entry proc_root = {
PROC_ROOT_INO, 5, "/proc",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_root_inode_operations,
NULL, NULL,
NULL,
&proc_root, NULL
};
 
struct proc_dir_entry proc_net = {
PROC_NET, 3, "net",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_dir_inode_operations,
NULL, NULL,
NULL,
NULL, NULL
};
 
struct proc_dir_entry proc_scsi = {
PROC_SCSI, 4, "scsi",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_dir_inode_operations,
NULL, NULL,
NULL, &proc_root, NULL
};
 
struct proc_dir_entry proc_sys_root = {
PROC_SYS, 3, "sys", /* inode, name */
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, /* mode, nlink, uid, gid */
0, &proc_dir_inode_operations, /* size, ops */
NULL, NULL, /* get_info, fill_inode */
NULL, /* next */
NULL, NULL /* parent, subdir */
};
 
int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{
dp->next = dir->subdir;
dp->parent = dir;
dir->subdir = dp;
if (S_ISDIR(dp->mode))
dir->nlink++;
return 0;
}
 
int proc_unregister(struct proc_dir_entry * dir, int ino)
{
struct proc_dir_entry **p = &dir->subdir, *dp;
 
while ((dp = *p) != NULL) {
if (dp->low_ino == ino) {
*p = dp->next;
dp->next = NULL;
if (S_ISDIR(dp->mode))
dir->nlink--;
if (ino >= PROC_DYNAMIC_FIRST &&
ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
clear_bit(ino-PROC_DYNAMIC_FIRST,
(void *) proc_alloc_map);
return 0;
}
p = &dp->next;
}
return -EINVAL;
}
 
static int make_inode_number(void)
{
int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
if (i<0 || i>=PROC_NDYNAMIC)
return -1;
set_bit(i, (void *) proc_alloc_map);
return PROC_DYNAMIC_FIRST + i;
}
 
int proc_register_dynamic(struct proc_dir_entry * dir,
struct proc_dir_entry * dp)
{
int i = make_inode_number();
if (i < 0)
return -EAGAIN;
dp->low_ino = i;
dp->next = dir->subdir;
dp->parent = dir;
dir->subdir = dp;
if (S_ISDIR(dp->mode))
dir->nlink++;
return 0;
}
 
/*
* /proc/self:
*/
static int proc_self_followlink(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode)
{
iput(dir);
*res_inode = proc_get_inode(inode->i_sb, (current->pid << 16) + PROC_PID_INO, &proc_pid);
iput(inode);
if (!*res_inode)
return -ENOENT;
return 0;
}
 
static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
{
int len;
char tmp[30];
 
iput(inode);
len = 1 + sprintf(tmp, "%d", current->pid);
if (buflen < len)
len = buflen;
memcpy_tofs(buffer, tmp, len);
return len;
}
 
static struct inode_operations proc_self_inode_operations = {
NULL, /* no file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
proc_self_readlink, /* readlink */
proc_self_followlink, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
struct proc_dir_entry pde_loadavg = {
PROC_LOADAVG, 7, "loadavg",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_uptime = {
PROC_UPTIME, 6, "uptime",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_meminfo = {
PROC_MEMINFO, 7, "meminfo",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_serial = {
PROC_SERIAL, 6, "serial",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_kmsg = {
PROC_KMSG, 4, "kmsg",
S_IFREG | S_IRUSR, 1, 0, 0,
};
struct proc_dir_entry pde_version = {
PROC_VERSION, 7, "version",
S_IFREG | S_IRUGO, 1, 0, 0,
};
#ifdef CONFIG_PCI
struct proc_dir_entry pde_pci = {
PROC_PCI, 3, "pci",
S_IFREG | S_IRUGO, 1, 0, 0,
};
#endif
struct proc_dir_entry pde_cpuinfo = {
PROC_CPUINFO, 7, "cpuinfo",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_self = {
PROC_SELF, 4, "self",
S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
64, &proc_self_inode_operations,
};
 
#ifdef CONFIG_DEBUG_MALLOC
struct proc_dir_entry pde_malloc = {
PROC_MALLOC, 6, "malloc",
S_IFREG | S_IRUGO, 1, 0, 0,
};
#endif
struct proc_dir_entry pde_kcore = {
PROC_KCORE, 5, "kcore",
S_IFREG | S_IRUSR, 1, 0, 0,
};
 
#ifdef CONFIG_MODULES
struct proc_dir_entry pde_modules = {
PROC_MODULES, 7, "modules",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_ksyms = {
PROC_KSYMS, 5, "ksyms",
S_IFREG | S_IRUGO, 1, 0, 0,
};
#endif
struct proc_dir_entry pde_stat = {
PROC_STAT, 4, "stat",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_devices = {
PROC_DEVICES, 7, "devices",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_interrupts = {
PROC_INTERRUPTS, 10,"interrupts",
S_IFREG | S_IRUGO, 1, 0, 0,
};
#ifdef __SMP_PROF__
struct proc_dir_entry pde_smp = {
PROC_SMP_PROF, 3,"smp",
S_IFREG | S_IRUGO, 1, 0, 0,
};
#endif
struct proc_dir_entry pde_filesystems = {
PROC_FILESYSTEMS, 11,"filesystems",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_dma = {
PROC_DMA, 3, "dma",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_ioports = {
PROC_IOPORTS, 7, "ioports",
S_IFREG | S_IRUGO, 1, 0, 0,
};
struct proc_dir_entry pde_cmdline = {
PROC_CMDLINE, 7, "cmdline",
S_IFREG | S_IRUGO, 1, 0, 0,
};
#ifdef CONFIG_RTC
struct proc_dir_entry pde_rtc = {
PROC_RTC, 3, "rtc",
S_IFREG | S_IRUGO, 1, 0, 0,
};
#endif
struct proc_dir_entry pde_locks = {
PROC_LOCKS, 5, "locks",
S_IFREG | S_IRUGO, 1, 0, 0,
};
 
struct proc_dir_entry pde_mounts =
{ PROC_MTAB, 6, "mounts", S_IFREG | S_IRUGO, 1, 0, 0, };
 
struct proc_dir_entry pde_profile = {
PROC_PROFILE, 7, "profile",
S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
};
 
void proc_root_init(void)
{
static int done = 0;
 
if (done)
return;
done = 1;
proc_base_init();
 
proc_register(&proc_root, &pde_loadavg);
proc_register(&proc_root, &pde_uptime);
proc_register(&proc_root, &pde_meminfo);
proc_register(&proc_root, &pde_kmsg);
proc_register(&proc_root, &pde_version);
#ifdef CONFIG_PCI
proc_register(&proc_root, &pde_pci);
#endif
proc_register(&proc_root, &pde_cpuinfo);
proc_register(&proc_root, &pde_self);
proc_register(&proc_root, &proc_net);
proc_register(&proc_root, &proc_scsi);
proc_register(&proc_root, &proc_sys_root);
proc_register(&proc_root, &pde_serial);
 
#ifdef CONFIG_DEBUG_MALLOC
proc_register(&proc_root, &pde_malloc);
#endif
proc_register(&proc_root, &pde_kcore);
 
#ifdef CONFIG_MODULES
proc_register(&proc_root, &pde_modules);
proc_register(&proc_root, &pde_ksyms);
#endif
proc_register(&proc_root, &pde_stat);
proc_register(&proc_root, &pde_devices);
proc_register(&proc_root, &pde_interrupts);
#ifdef __SMP_PROF__
proc_register(&proc_root, &pde_smp);
#endif
proc_register(&proc_root, &pde_filesystems);
proc_register(&proc_root, &pde_dma);
proc_register(&proc_root, &pde_ioports);
proc_register(&proc_root, &pde_cmdline);
#ifdef CONFIG_RTC
proc_register(&proc_root, &pde_rtc);
#endif
proc_register(&proc_root, &pde_locks);
 
proc_register( &proc_root, &pde_mounts);
if (prof_shift) {
proc_register(&proc_root, &pde_profile);
}
}
 
 
int proc_match(int len,const char * name,struct proc_dir_entry * de)
{
if (!de || !de->low_ino)
return 0;
/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
return 1;
if (de->namelen != len)
return 0;
return !memcmp(name, de->name, len);
}
 
int proc_lookup(struct inode * dir,const char * name, int len,
struct inode ** result)
{
struct proc_dir_entry * de;
int ino;
 
*result = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOTDIR;
}
 
de = (struct proc_dir_entry *) dir->u.generic_ip;
if (!de) {
iput(dir);
return -EINVAL;
}
 
/* Special case "." and "..": they aren't on the directory list */
*result = dir;
if (!len)
return 0;
if (name[0] == '.') {
if (len == 1)
return 0;
if (name[1] == '.' && len == 2) {
struct inode * inode;
inode = proc_get_inode(dir->i_sb, de->parent->low_ino, de->parent);
iput(dir);
if (!inode)
return -EINVAL;
*result = inode;
return 0;
}
}
 
*result = NULL;
for (de = de->subdir; de ; de = de->next) {
if (proc_match(len, name, de))
break;
}
if (!de) {
iput(dir);
return -ENOENT;
}
 
ino = de->low_ino | (dir->i_ino & ~(0xffff));
 
if (!(*result = proc_get_inode(dir->i_sb, ino, de))) {
iput(dir);
return -EINVAL;
}
iput(dir);
return 0;
}
 
static int proc_root_lookup(struct inode * dir,const char * name, int len,
struct inode ** result)
{
unsigned int pid, c;
int i, ino, retval;
 
dir->i_count++;
retval = proc_lookup(dir, name, len, result);
if (retval != -ENOENT) {
iput(dir);
return retval;
}
pid = 0;
while (len-- > 0) {
c = *name - '0';
name++;
if (c > 9) {
pid = 0;
break;
}
pid *= 10;
pid += c;
if (pid & 0xffff0000) {
pid = 0;
break;
}
}
for (i = 0 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid)
break;
if (!pid || i >= NR_TASKS) {
iput(dir);
return -ENOENT;
}
ino = (pid << 16) + PROC_PID_INO;
if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid))) {
iput(dir);
return -EINVAL;
}
iput(dir);
return 0;
}
 
/*
* This returns non-zero if at EOF, so that the /proc
* root directory can use this and check if it should
* continue with the <pid> entries..
*
* Note that the VFS-layer doesn't care about the return
* value of the readdir() call, as long as it's non-negative
* for success..
*/
int proc_readdir(struct inode * inode, struct file * filp,
void * dirent, filldir_t filldir)
{
struct proc_dir_entry * de;
unsigned int ino;
int i;
 
if (!inode || !S_ISDIR(inode->i_mode))
return -ENOTDIR;
ino = inode->i_ino;
de = (struct proc_dir_entry *) inode->u.generic_ip;
if (!de)
return -EINVAL;
i = filp->f_pos;
switch (i) {
case 0:
if (filldir(dirent, ".", 1, i, ino) < 0)
return 0;
i++;
filp->f_pos++;
/* fall through */
case 1:
if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0)
return 0;
i++;
filp->f_pos++;
/* fall through */
default:
ino &= ~0xffff;
de = de->subdir;
i -= 2;
for (;;) {
if (!de)
return 1;
if (!i)
break;
de = de->next;
i--;
}
 
do {
if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino | de->low_ino) < 0)
return 0;
filp->f_pos++;
de = de->next;
} while (de);
}
return 1;
}
 
#define NUMBUF 10
 
static int proc_root_readdir(struct inode * inode, struct file * filp,
void * dirent, filldir_t filldir)
{
char buf[NUMBUF];
unsigned int nr,pid;
unsigned long i,j;
 
nr = filp->f_pos;
if (nr < FIRST_PROCESS_ENTRY) {
int error = proc_readdir(inode, filp, dirent, filldir);
if (error <= 0)
return error;
filp->f_pos = nr = FIRST_PROCESS_ENTRY;
}
 
for (nr -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
struct task_struct * p = task[nr];
 
if (!p || !(pid = p->pid))
continue;
 
j = NUMBUF;
i = pid;
do {
j--;
buf[j] = '0' + (i % 10);
i /= 10;
} while (i);
 
if (filldir(dirent, buf+j, NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
break;
}
return 0;
}
/net.c
0,0 → 1,120
/*
* linux/fs/proc/net.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* gjh 3/'93 heim@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim)
* most of this file is stolen from base.c
* it works, but you shouldn't use it as a guideline
* for new proc-fs entries. once i'll make it better.
* fvk 3/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
* cleaned up the whole thing, moved "net" specific code to
* the NET kernel layer (where it belonged in the first place).
* Michael K. Johnson (johnsonm@stolaf.edu) 3/93
* Added support from my previous inet.c. Cleaned things up
* quite a bit, modularized the code.
* fvk 4/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
* Renamed "route_get_info()" to "rt_get_info()" for consistency.
* Alan Cox (gw4pts@gw4pts.ampr.org) 4/94
* Dusted off the code and added IPX. Fixed the 4K limit.
* Erik Schoenfelder (schoenfr@ibr.cs.tu-bs.de)
* /proc/net/snmp.
* Alan Cox (gw4pts@gw4pts.ampr.org) 1/95
* Added Appletalk slots
*
* proc net directory handling functions
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
 
#include <asm/segment.h>
 
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
 
static int proc_readnet(struct inode * inode, struct file * file,
char * buf, int count)
{
char * page;
int bytes=count;
int copied=0;
char *start;
struct proc_dir_entry * dp;
 
if (count < 0)
return -EINVAL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
if (!(page = (char*) __get_free_page(GFP_KERNEL)))
return -ENOMEM;
 
while (bytes>0)
{
int length, thistime=bytes;
if (bytes > PROC_BLOCK_SIZE)
thistime=PROC_BLOCK_SIZE;
 
length = dp->get_info(page, &start,
file->f_pos,
thistime,
(file->f_flags & O_ACCMODE) == O_RDWR);
 
/*
* We have been given a non page aligned block of
* the data we asked for + a bit. We have been given
* the start pointer and we know the length..
*/
 
if (length <= 0)
break;
/*
* Copy the bytes
*/
memcpy_tofs(buf+copied, start, length);
file->f_pos += length; /* Move down the file */
bytes -= length;
copied += length;
if (length<thistime)
break; /* End of file */
}
free_page((unsigned long) page);
return copied;
}
 
static struct file_operations proc_net_operations = {
NULL, /* lseek - default */
proc_readnet, /* read - bad */
NULL, /* write - bad */
NULL, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
/*
* proc directories can do almost nothing..
*/
struct inode_operations proc_net_inode_operations = {
&proc_net_operations, /* default net file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
/procfs_syms.c
0,0 → 1,47
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
 
/*
* This is all required so that if we load all of scsi as a module,
* that the scsi code will be able to talk to the /proc/scsi handling
* in the procfs.
*/
extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
off_t offset, int length, int inout);
extern struct inode_operations proc_scsi_inode_operations;
 
static struct symbol_table procfs_syms = {
/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
#include <linux/symtab_begin.h>
X(proc_register),
X(proc_register_dynamic),
X(proc_unregister),
X(proc_root),
X(in_group_p),
X(proc_net_inode_operations),
X(proc_net),
 
/*
* This is required so that if we load scsi later, that the
* scsi code can attach to /proc/scsi in the correct manner.
*/
X(proc_scsi),
X(proc_scsi_inode_operations),
X(dispatch_scsi_info_ptr),
#include <linux/symtab_end.h>
};
 
static struct file_system_type proc_fs_type = {
proc_read_super, "proc", 0, NULL
};
 
int init_proc_fs(void)
{
int status;
 
if ((status = register_filesystem(&proc_fs_type)) == 0)
status = register_symtab(&procfs_syms);
return status;
}
 
/fd.c
0,0 → 1,178
/*
* linux/fs/proc/fd.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* proc fd directory handling functions
*/
 
#include <asm/segment.h>
 
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
 
static int proc_readfd(struct inode *, struct file *, void *, filldir_t);
static int proc_lookupfd(struct inode *,const char *,int,struct inode **);
 
static struct file_operations proc_fd_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_readfd, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
/*
* proc directories can do almost nothing..
*/
struct inode_operations proc_fd_inode_operations = {
&proc_fd_operations, /* default base directory file-ops */
NULL, /* create */
proc_lookupfd, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
static int proc_lookupfd(struct inode * dir, const char * name, int len,
struct inode ** result)
{
unsigned int ino, pid, fd, c;
struct task_struct * p;
struct super_block * sb;
int i;
 
*result = NULL;
ino = dir->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
if (!dir)
return -ENOENT;
sb = dir->i_sb;
if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
if (!len || (name[0] == '.' && (len == 1 ||
(name[1] == '.' && len == 2)))) {
if (len < 2) {
*result = dir;
return 0;
}
if (!(*result = proc_get_inode(sb, (pid << 16)+PROC_PID_INO, &proc_pid))) {
iput(dir);
return -ENOENT;
}
iput(dir);
return 0;
}
iput(dir);
fd = 0;
while (len-- > 0) {
c = *name - '0';
name++;
if (c > 9) {
fd = 0xfffff;
break;
}
fd *= 10;
fd += c;
if (fd & 0xffff0000) {
fd = 0xfffff;
break;
}
}
for (i = 0 ; i < NR_TASKS ; i++)
if ((p = task[i]) && p->pid == pid)
break;
if (!pid || i >= NR_TASKS)
return -ENOENT;
 
if (fd >= NR_OPEN || !p->files || !p->files->fd[fd]
|| !p->files->fd[fd]->f_inode)
return -ENOENT;
 
ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
 
if (!(*result = proc_get_inode(sb, ino, NULL)))
return -ENOENT;
return 0;
}
 
#define NUMBUF 10
 
static int proc_readfd(struct inode * inode, struct file * filp,
void * dirent, filldir_t filldir)
{
char buf[NUMBUF];
int task_nr;
struct task_struct * p;
unsigned int fd, pid, ino;
unsigned long i,j;
 
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
ino = inode->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
if (ino != PROC_PID_FD)
return 0;
 
for (fd = filp->f_pos; fd < 2; fd++, filp->f_pos++) {
unsigned long ino = inode->i_ino;
if (fd)
ino = (ino & 0xffff0000) | PROC_PID_INO;
if (filldir(dirent, "..", fd+1, fd, ino) < 0)
return 0;
}
 
task_nr = 1;
for (;;) {
if ((p = task[task_nr]) && p->pid == pid)
break;
if (++task_nr >= NR_TASKS)
return 0;
}
 
for (fd -= 2 ; fd < NR_OPEN; fd++, filp->f_pos++) {
if (!p->files)
break;
if (!p->files->fd[fd] || !p->files->fd[fd]->f_inode)
continue;
 
j = NUMBUF;
i = fd;
do {
j--;
buf[j] = '0' + (i % 10);
i /= 10;
} while (i);
 
ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
break;
 
/* filldir() might have slept, so we must re-validate "p" */
if (p != task[task_nr] || p->pid != pid)
break;
}
return 0;
}
/base.c
0,0 → 1,174
/*
* linux/fs/proc/base.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* proc base directory handling functions
*/
 
/*
* uClinux revisions for NO_MM
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
* The Silver Hammer Group, Ltd.
*/
 
#include <asm/segment.h>
 
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
 
static struct file_operations proc_base_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_readdir, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
/*
* proc directories can do almost nothing..
*/
static struct inode_operations proc_base_inode_operations = {
&proc_base_operations, /* default base directory file-ops */
NULL, /* create */
proc_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
static void proc_pid_fill_inode(struct inode * inode)
{
struct task_struct * p;
int pid = inode->i_ino >> 16;
int ino = inode->i_ino & 0xffff;
 
for_each_task(p) {
if (p->pid == pid) {
if (p->dumpable || ino == PROC_PID_INO) {
inode->i_uid = p->euid;
inode->i_gid = p->gid;
}
return;
}
}
}
 
/*
* This is really a pseudo-entry, and only links
* backwards to the parent with no link from the
* root directory to this. This way we can have just
* one entry for every /proc/<pid>/ directory.
*/
struct proc_dir_entry proc_pid = {
PROC_PID_INO, 5, "<pid>",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_base_inode_operations,
NULL, proc_pid_fill_inode,
NULL, &proc_root, NULL
};
 
struct proc_dir_entry pde_status = {
PROC_PID_STATUS, 6, "status",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_array_inode_operations,
NULL, proc_pid_fill_inode,
};
struct proc_dir_entry pde_mem = {
PROC_PID_MEM, 3, "mem",
S_IFREG | S_IRUSR | S_IWUSR, 1, 0, 0,
0, &proc_mem_inode_operations,
NULL, proc_pid_fill_inode,
};
struct proc_dir_entry pde_cwd = {
PROC_PID_CWD, 3, "cwd",
S_IFLNK | S_IRWXU, 1, 0, 0,
0, &proc_link_inode_operations,
NULL, proc_pid_fill_inode,
};
struct proc_dir_entry pde_root = {
PROC_PID_ROOT, 4, "root",
S_IFLNK | S_IRWXU, 1, 0, 0,
0, &proc_link_inode_operations,
NULL, proc_pid_fill_inode,
};
struct proc_dir_entry pde_exe = {
PROC_PID_EXE, 3, "exe",
S_IFLNK | S_IRWXU, 1, 0, 0,
0, &proc_link_inode_operations,
NULL, proc_pid_fill_inode,
};
struct proc_dir_entry pde_fd = {
PROC_PID_FD, 2, "fd",
S_IFDIR | S_IRUSR | S_IXUSR, 1, 0, 0,
0, &proc_fd_inode_operations,
NULL, proc_pid_fill_inode,
};
struct proc_dir_entry pde_environ = {
PROC_PID_ENVIRON, 7, "environ",
S_IFREG | S_IRUSR, 1, 0, 0,
0, &proc_array_inode_operations,
NULL, proc_pid_fill_inode,
};
struct proc_dir_entry pde_pidcmdline = {
PROC_PID_CMDLINE, 7, "cmdline",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_array_inode_operations,
NULL, proc_pid_fill_inode,
};
struct proc_dir_entry pde_pidstat = {
PROC_PID_STAT, 4, "stat",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_array_inode_operations,
NULL, proc_pid_fill_inode,
};
#ifndef NO_MM
struct proc_dir_entry pde_statm = {
PROC_PID_STATM, 5, "statm",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_array_inode_operations,
NULL, proc_pid_fill_inode,
};
struct proc_dir_entry pde_maps = {
PROC_PID_MAPS, 4, "maps",
S_IFIFO | S_IRUGO, 1, 0, 0,
0, &proc_arraylong_inode_operations,
NULL, proc_pid_fill_inode,
};
#endif /* !NO_MM */
 
 
void proc_base_init(void)
{
proc_register(&proc_pid, &pde_status);
proc_register(&proc_pid, &pde_mem);
proc_register(&proc_pid, &pde_cwd);
proc_register(&proc_pid, &pde_root);
proc_register(&proc_pid, &pde_exe);
proc_register(&proc_pid, &pde_fd);
proc_register(&proc_pid, &pde_environ);
proc_register(&proc_pid, &pde_pidcmdline);
proc_register(&proc_pid, &pde_pidstat);
#ifndef NO_MM
proc_register(&proc_pid, &pde_statm);
proc_register(&proc_pid, &pde_maps);
#endif /* !NO_MM */
};
/.depend
0,0 → 1,117
array.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/types.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel_stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/tty.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/user.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/a.out.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mman.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/ioport.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/pagemap.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/swap.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/pgtable.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/io.h
base.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h
fd.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h
inode.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/locks.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/limits.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/system.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h
kmsg.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/types.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/io.h
link.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h
mem.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/types.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/page.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/io.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/pgtable.h
net.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fcntl.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h
procfs_syms.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/module.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/symtab_begin.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/symtab_end.h
root.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/bitops.h
scsi.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h
serial.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/types.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel_stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/tty.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/user.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/a.out.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mman.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/proc_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/ioport.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/config.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/pagemap.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/swap.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/pgtable.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/io.h
/Makefile
0,0 → 1,15
#
# Makefile for the linux proc-filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
 
O_TARGET := proc.o
O_OBJS := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o serial.o
OX_OBJS := procfs_syms.o
M_OBJS := $(O_TARGET)
 
include $(TOPDIR)/Rules.make
/link.c
0,0 → 1,176
/*
* linux/fs/proc/link.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* /proc link-file handling code
*/
 
/*
* uClinux revisions for NO_MM
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
* The Silver Hammer Group, Ltd.
*/
#include <asm/segment.h>
 
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
 
static int proc_readlink(struct inode *, char *, int);
static int proc_follow_link(struct inode *, struct inode *, int, int,
struct inode **);
 
/*
* PLAN9_SEMANTICS won't work any more: it used an ugly hack that broke
* when the files[] array was updated only after the open code
*/
#undef PLAN9_SEMANTICS
 
/*
* links can't do much...
*/
static struct file_operations proc_fd_link_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* very special open code */
NULL, /* no special release code */
NULL /* can't fsync */
};
 
struct inode_operations proc_link_inode_operations = {
&proc_fd_link_operations,/* file-operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
proc_readlink, /* readlink */
proc_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
 
static int proc_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode)
{
unsigned int pid, ino;
struct task_struct * p;
struct inode * new_inode;
int i, error;
 
*res_inode = NULL;
if (dir)
iput(dir);
if (!inode)
return -ENOENT;
if ((error = permission(inode, MAY_EXEC)) != 0){
iput(inode);
return error;
}
ino = inode->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
for (i = 0 ; i < NR_TASKS ; i++)
if ((p = task[i]) && p->pid == pid)
break;
if (i >= NR_TASKS) {
iput(inode);
return -ENOENT;
}
new_inode = NULL;
switch (ino) {
case PROC_PID_CWD:
if (!p->fs)
break;
new_inode = p->fs->pwd;
break;
case PROC_PID_ROOT:
if (!p->fs)
break;
new_inode = p->fs->root;
break;
#ifndef NO_MM
case PROC_PID_EXE: {
struct vm_area_struct * vma;
if (!p->mm)
break;
vma = p->mm->mmap;
while (vma) {
if (vma->vm_flags & VM_EXECUTABLE) {
new_inode = vma->vm_inode;
break;
}
vma = vma->vm_next;
}
break;
}
#else /* NO_MM */
case PROC_PID_EXE: {
new_inode = p->mm->executable;
break;
}
#endif /* NO_MM */
default:
switch (ino >> 8) {
case PROC_PID_FD_DIR:
if (!p->files)
break;
ino &= 0xff;
if (ino < NR_OPEN && p->files && p->files->fd[ino]) {
new_inode = p->files->fd[ino]->f_inode;
}
break;
}
}
iput(inode);
if (!new_inode)
return -ENOENT;
*res_inode = new_inode;
new_inode->i_count++;
return 0;
}
 
static int proc_readlink(struct inode * inode, char * buffer, int buflen)
{
int i;
unsigned int dev,ino;
char buf[64];
 
if (!S_ISLNK(inode->i_mode)) {
iput(inode);
return -EINVAL;
}
i = proc_follow_link(NULL, inode, 0, 0, &inode);
if (i)
return i;
if (!inode)
return -EIO;
dev = kdev_t_to_nr(inode->i_dev);
ino = inode->i_ino;
iput(inode);
i = sprintf(buf,"[%04x]:%u", dev, ino);
if (buflen > i)
buflen = i;
i = 0;
while (i < buflen)
put_user(buf[i++],buffer++);
return i;
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.