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

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [fs/] [proc/] [array.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/fs/proc/array.c
3
 *
4
 *  Copyright (C) 1992  by Linus Torvalds
5
 *  based on ideas by Darren Senn
6
 *
7
 * Fixes:
8
 * Michael. K. Johnson: stat,statm extensions.
9
 *                      <johnsonm@stolaf.edu>
10
 *
11
 * Pauline Middelink :  Made cmdline,envline only break at '\0's, to
12
 *                      make sure SET_PROCTITLE works. Also removed
13
 *                      bad '!' which forced address recalculation for
14
 *                      EVERY character on the current page.
15
 *                      <middelin@polyware.iaf.nl>
16
 *
17
 * Danny ter Haar    :  added cpuinfo
18
 *                      <dth@cistron.nl>
19
 *
20
 * Alessandro Rubini :  profile extension.
21
 *                      <rubini@ipvvis.unipv.it>
22
 *
23
 * Jeff Tranter      :  added BogoMips field to cpuinfo
24
 *                      <Jeff_Tranter@Mitel.COM>
25
 *
26
 * Bruno Haible      :  remove 4K limit for the maps file
27
 * <haible@ma2s2.mathematik.uni-karlsruhe.de>
28
 *
29
 * Yves Arrouye      :  remove removal of trailing spaces in get_array.
30
 *                      <Yves.Arrouye@marin.fdn.fr>
31
 *
32
 * Alan Cox          :  security fixes. <Alan.Cox@linux.org>
33
 */
34
 
35
/*
36
 * uClinux revisions for NO_MM
37
 * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
38
 *                     The Silver Hammer Group, Ltd.
39
 */
40
 
41
#include <linux/types.h>
42
#include <linux/errno.h>
43
#include <linux/sched.h>
44
#include <linux/kernel.h>
45
#include <linux/kernel_stat.h>
46
#include <linux/tty.h>
47
#include <linux/user.h>
48
#include <linux/a.out.h>
49
#include <linux/string.h>
50
#include <linux/mman.h>
51
#include <linux/proc_fs.h>
52
#include <linux/ioport.h>
53
#include <linux/config.h>
54
#include <linux/mm.h>
55
#include <linux/pagemap.h>
56
#include <linux/swap.h>
57
 
58
#include <asm/segment.h>
59
#include <asm/pgtable.h>
60
#include <asm/io.h>
61
 
62
#define LOAD_INT(x) ((x) >> FSHIFT)
63
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
64
 
65
#ifdef CONFIG_DEBUG_MALLOC
66
int get_malloc(char * buffer);
67
#endif
68
 
69
extern unsigned long get_wchan(struct task_struct *);
70
 
71
static int read_core(struct inode * inode, struct file * file,char * buf, int count)
72
{
73
        unsigned long p = file->f_pos, memsize;
74
        int read;
75
        int count1;
76
        char * pnt;
77
        struct user dump;
78
#ifdef __i386__
79
#       define FIRST_MAPPED     PAGE_SIZE       /* we don't have page 0 mapped on x86.. */
80
#else
81
#       define FIRST_MAPPED     0
82
#endif
83
 
84
        memset(&dump, 0, sizeof(struct user));
85
        dump.magic = CMAGIC;
86
        dump.u_dsize = MAP_NR(high_memory);
87
#ifdef __alpha__
88
        dump.start_data = PAGE_OFFSET;
89
#endif
90
 
91
        if (count < 0)
92
                return -EINVAL;
93
        memsize = MAP_NR(high_memory + PAGE_SIZE) << PAGE_SHIFT;
94
        if (p >= memsize)
95
                return 0;
96
        if (count > memsize - p)
97
                count = memsize - p;
98
        read = 0;
99
 
100
        if (p < sizeof(struct user) && count > 0) {
101
                count1 = count;
102
                if (p + count1 > sizeof(struct user))
103
                        count1 = sizeof(struct user)-p;
104
                pnt = (char *) &dump + p;
105
                memcpy_tofs(buf,(void *) pnt, count1);
106
                buf += count1;
107
                p += count1;
108
                count -= count1;
109
                read += count1;
110
        }
111
 
112
        while (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
113
                put_user(0,buf);
114
                buf++;
115
                p++;
116
                count--;
117
                read++;
118
        }
119
        memcpy_tofs(buf, (void *) (PAGE_OFFSET + p - PAGE_SIZE), count);
120
        read += count;
121
        file->f_pos += read;
122
        return read;
123
}
124
 
125
static struct file_operations proc_kcore_operations = {
126
        NULL,           /* lseek */
127
        read_core,
128
};
129
 
130
struct inode_operations proc_kcore_inode_operations = {
131
        &proc_kcore_operations,
132
};
133
 
134
 
135
/*
136
 * This function accesses profiling information. The returned data is
137
 * binary: the sampling step and the actual contents of the profile
138
 * buffer. Use of the program readprofile is recommended in order to
139
 * get meaningful info out of these data.
140
 */
141
static int read_profile(struct inode *inode, struct file *file, char *buf, int count)
142
{
143
        unsigned long p = file->f_pos;
144
        int read;
145
        char * pnt;
146
        unsigned int sample_step = 1 << prof_shift;
147
 
148
        if (count < 0)
149
                return -EINVAL;
150
        if (p >= (prof_len+1)*sizeof(unsigned int))
151
                return 0;
152
        if (count > (prof_len+1)*sizeof(unsigned int) - p)
153
                count = (prof_len+1)*sizeof(unsigned int) - p;
154
        read = 0;
155
 
156
        while (p < sizeof(unsigned int) && count > 0) {
157
                put_user(*((char *)(&sample_step)+p),buf);
158
                buf++; p++; count--; read++;
159
        }
160
        pnt = (char *)prof_buffer + p - sizeof(unsigned int);
161
        memcpy_tofs(buf,(void *)pnt,count);
162
        read += count;
163
        file->f_pos += read;
164
        return read;
165
}
166
 
167
/* Writing to /proc/profile resets the counters */
168
static int write_profile(struct inode * inode, struct file * file, const char * buf, int count)
169
{
170
    int i=prof_len;
171
 
172
    while (i--)
173
            prof_buffer[i]=0UL;
174
    return count;
175
}
176
 
177
static struct file_operations proc_profile_operations = {
178
        NULL,           /* lseek */
179
        read_profile,
180
        write_profile,
181
};
182
 
183
struct inode_operations proc_profile_inode_operations = {
184
        &proc_profile_operations,
185
};
186
 
187
 
188
static int get_loadavg(char * buffer)
189
{
190
        int a, b, c;
191
 
192
        a = avenrun[0] + (FIXED_1/200);
193
        b = avenrun[1] + (FIXED_1/200);
194
        c = avenrun[2] + (FIXED_1/200);
195
        return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
196
                LOAD_INT(a), LOAD_FRAC(a),
197
                LOAD_INT(b), LOAD_FRAC(b),
198
                LOAD_INT(c), LOAD_FRAC(c),
199
                nr_running, nr_tasks, last_pid);
200
}
201
 
202
static int get_kstat(char * buffer)
203
{
204
        int i, len;
205
        unsigned sum = 0;
206
        extern unsigned long total_forks;
207
 
208
        for (i = 0 ; i < NR_IRQS ; i++)
209
                sum += kstat.interrupts[i];
210
        len = sprintf(buffer,
211
                "cpu  %u %u %u %lu\n"
212
                "disk %u %u %u %u\n"
213
                "disk_rio %u %u %u %u\n"
214
                "disk_wio %u %u %u %u\n"
215
                "disk_rblk %u %u %u %u\n"
216
                "disk_wblk %u %u %u %u\n"
217
                "page %u %u\n"
218
                "swap %u %u\n"
219
                "intr %u",
220
                kstat.cpu_user,
221
                kstat.cpu_nice,
222
                kstat.cpu_system,
223
                jiffies - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
224
                kstat.dk_drive[0], kstat.dk_drive[1],
225
                kstat.dk_drive[2], kstat.dk_drive[3],
226
                kstat.dk_drive_rio[0], kstat.dk_drive_rio[1],
227
                kstat.dk_drive_rio[2], kstat.dk_drive_rio[3],
228
                kstat.dk_drive_wio[0], kstat.dk_drive_wio[1],
229
                kstat.dk_drive_wio[2], kstat.dk_drive_wio[3],
230
                kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1],
231
                kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3],
232
                kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1],
233
                kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3],
234
                kstat.pgpgin,
235
                kstat.pgpgout,
236
                kstat.pswpin,
237
                kstat.pswpout,
238
                sum);
239
        for (i = 0 ; i < NR_IRQS ; i++)
240
                len += sprintf(buffer + len, " %u", kstat.interrupts[i]);
241
        len += sprintf(buffer + len,
242
                "\nctxt %u\n"
243
                "btime %lu\n"
244
                "processes %lu\n",
245
                kstat.context_swtch,
246
                xtime.tv_sec - jiffies / HZ,
247
                total_forks);
248
        return len;
249
}
250
 
251
 
252
static int get_uptime(char * buffer)
253
{
254
        unsigned long uptime;
255
        unsigned long idle;
256
 
257
        uptime = jiffies;
258
        idle = task[0]->utime + task[0]->stime;
259
 
260
        /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
261
           that would overflow about every five days at HZ == 100.
262
           Therefore the identity a = (a / b) * b + a % b is used so that it is
263
           calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
264
           The part in front of the '+' always evaluates as 0 (mod 100). All divisions
265
           in the above formulas are truncating. For HZ being a power of 10, the
266
           calculations simplify to the version in the #else part (if the printf
267
           format is adapted to the same number of digits as zeroes in HZ.
268
         */
269
#if HZ!=100
270
        return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
271
                uptime / HZ,
272
                (((uptime % HZ) * 100) / HZ) % 100,
273
                idle / HZ,
274
                (((idle % HZ) * 100) / HZ) % 100);
275
#else
276
        return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
277
                uptime / HZ,
278
                uptime % HZ,
279
                idle / HZ,
280
                idle % HZ);
281
#endif
282
}
283
 
284
static int get_meminfo(char * buffer)
285
{
286
        struct sysinfo i;
287
        int len;
288
 
289
        si_meminfo(&i);
290
        si_swapinfo(&i);
291
        len = sprintf(buffer, "        total:    used:    free:  shared: buffers:  cached:\n"
292
                "Mem:  %8lu %8lu %8lu %8lu %8lu %8lu\n"
293
                "Swap: %8lu %8lu %8lu\n",
294
                i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, page_cache_size*PAGE_SIZE,
295
                i.totalswap, i.totalswap-i.freeswap, i.freeswap);
296
        /*
297
         * Tagged format, for easy grepping and expansion. The above will go away
298
         * eventually, once the tools have been updated.
299
         */
300
        return len + sprintf(buffer+len,
301
                "MemTotal:  %8lu kB\n"
302
                "MemFree:   %8lu kB\n"
303
                "MemShared: %8lu kB\n"
304
                "Buffers:   %8lu kB\n"
305
                "Cached:    %8lu kB\n"
306
                "SwapTotal: %8lu kB\n"
307
                "SwapFree:  %8lu kB\n",
308
                i.totalram >> 10,
309
                i.freeram >> 10,
310
                i.sharedram >> 10,
311
                i.bufferram >> 10,
312
                page_cache_size << (PAGE_SHIFT - 10),
313
                i.totalswap >> 10,
314
                i.freeswap >> 10);
315
}
316
 
317
static int get_version(char * buffer)
318
{
319
        extern const char *linux_banner;
320
 
321
        strcpy(buffer, linux_banner);
322
        return strlen(buffer);
323
}
324
 
325
static int get_cmdline(char * buffer)
326
{
327
        extern char saved_command_line[];
328
 
329
        return sprintf(buffer, "%s\n", saved_command_line);
330
}
331
 
332
static struct task_struct ** get_task(pid_t pid)
333
{
334
        struct task_struct ** p;
335
 
336
        p = task;
337
        while (++p < task+NR_TASKS) {
338
                if (*p && (*p)->pid == pid)
339
                        return p;
340
        }
341
        return NULL;
342
}
343
 
344
static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
345
{
346
#ifndef NO_MM
347
        pgd_t *page_dir;
348
        pmd_t *page_middle;
349
        pte_t pte;
350
 
351
        if (!p || !p->mm || ptr >= TASK_SIZE)
352
                return 0;
353
        page_dir = pgd_offset(p->mm,ptr);
354
        if (pgd_none(*page_dir))
355
                return 0;
356
        if (pgd_bad(*page_dir)) {
357
                printk("bad page directory entry %08lx\n", pgd_val(*page_dir));
358
                pgd_clear(page_dir);
359
                return 0;
360
        }
361
        page_middle = pmd_offset(page_dir,ptr);
362
        if (pmd_none(*page_middle))
363
                return 0;
364
        if (pmd_bad(*page_middle)) {
365
                printk("bad page middle entry %08lx\n", pmd_val(*page_middle));
366
                pmd_clear(page_middle);
367
                return 0;
368
        }
369
        pte = *pte_offset(page_middle,ptr);
370
        if (!pte_present(pte))
371
                return 0;
372
        return pte_page(pte) + (ptr & ~PAGE_MASK);
373
#else /* NO_MM */
374
        return ptr;
375
#endif /* NO_MM */
376
}
377
 
378
static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer)
379
{
380
        unsigned long addr;
381
        int size = 0, result = 0;
382
        char c;
383
 
384
        if (start >= end)
385
                return result;
386
        for (;;) {
387
                addr = get_phys_addr(*p, start);
388
                if (!addr)
389
                        return result;
390
                do {
391
                        c = *(char *) addr;
392
                        if (!c)
393
                                result = size;
394
                        if (size < PAGE_SIZE)
395
                                buffer[size++] = c;
396
                        else
397
                                return result;
398
                        addr++;
399
                        start++;
400
                        if (!c && start >= end)
401
                                return result;
402
                } while (addr & ~PAGE_MASK);
403
        }
404
        return result;
405
}
406
 
407
static int get_env(int pid, char * buffer)
408
{
409
        struct task_struct ** p = get_task(pid);
410
 
411
        if (!p || !*p || !(*p)->mm)
412
                return 0;
413
        return get_array(p, (*p)->mm->env_start, (*p)->mm->env_end, buffer);
414
}
415
 
416
static int get_arg(int pid, char * buffer)
417
{
418
        struct task_struct ** p = get_task(pid);
419
 
420
        if (!p || !*p || !(*p)->mm)
421
                return 0;
422
        return get_array(p, (*p)->mm->arg_start, (*p)->mm->arg_end, buffer);
423
}
424
 
425
#if defined(__i386__)
426
# define KSTK_EIP(tsk)  (((unsigned long *)tsk->kernel_stack_page)[1019])
427
# define KSTK_ESP(tsk)  (((unsigned long *)tsk->kernel_stack_page)[1022])
428
#elif defined(__alpha__)
429
  /*
430
   * See arch/alpha/kernel/ptrace.c for details.
431
   */
432
# define PT_REG(reg)            (PAGE_SIZE - sizeof(struct pt_regs)     \
433
                                 + (long)&((struct pt_regs *)0)->reg)
434
# define KSTK_EIP(tsk)  (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
435
# define KSTK_ESP(tsk)  ((tsk) == current ? rdusp() : (tsk)->tss.usp)
436
#elif defined(__sparc__)
437
# define PT_REG(reg)            (PAGE_SIZE - sizeof(struct pt_regs)     \
438
                                 + (long)&((struct pt_regs *)0)->reg)
439
# define KSTK_EIP(tsk)  (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
440
# define KSTK_ESP(tsk)  (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(u_regs[UREG_FP])))
441
#endif
442
 
443
/* Gcc optimizes away "strlen(x)" for constant x */
444
#define ADDBUF(buffer, string) \
445
do { memcpy(buffer, string, strlen(string)); \
446
     buffer += strlen(string); } while (0)
447
 
448
static inline char * task_name(struct task_struct *p, char * buf)
449
{
450
        int i;
451
        char * name;
452
 
453
        ADDBUF(buf, "Name:\t");
454
        name = p->comm;
455
        i = sizeof(p->comm);
456
        do {
457
                unsigned char c = *name;
458
                name++;
459
                i--;
460
                *buf = c;
461
                if (!c)
462
                        break;
463
                if (c == '\\') {
464
                        buf[1] = c;
465
                        buf += 2;
466
                        continue;
467
                }
468
                if (c == '\n') {
469
                        buf[0] = '\\';
470
                        buf[1] = 'n';
471
                        buf += 2;
472
                        continue;
473
                }
474
                buf++;
475
        } while (i);
476
        *buf = '\n';
477
        return buf+1;
478
}
479
 
480
static inline char * task_state(struct task_struct *p, char *buffer)
481
{
482
#define NR_STATES (sizeof(states)/sizeof(const char *))
483
        unsigned int n = p->state;
484
        static const char * states[] = {
485
                "R (running)",
486
                "S (sleeping)",
487
                "D (disk sleep)",
488
                "Z (zombie)",
489
                "T (stopped)",
490
                "W (paging)",
491
                ". Huh?"
492
        };
493
 
494
        if (n >= NR_STATES)
495
                n = NR_STATES-1;
496
 
497
        buffer += sprintf(buffer,
498
                "State:\t%s\n"
499
                "Pid:\t%d\n"
500
                "PPid:\t%d\n"
501
                "Uid:\t%d\t%d\t%d\t%d\n"
502
                "Gid:\t%d\t%d\t%d\t%d\n",
503
                states[n],
504
                p->pid, p->p_pptr->pid,
505
                p->uid, p->euid, p->suid, p->fsuid,
506
                p->gid, p->egid, p->sgid, p->fsgid);
507
        return buffer;
508
}
509
 
510
static inline char * task_mem(struct task_struct *p, char *buffer)
511
{
512
#ifndef NO_MM
513
        struct mm_struct * mm = p->mm;
514
 
515
        if (mm && mm != &init_mm) {
516
                struct vm_area_struct * vma = mm->mmap;
517
                unsigned long data = 0, stack = 0;
518
                unsigned long exec = 0, lib = 0;
519
 
520
                for (vma = mm->mmap; vma; vma = vma->vm_next) {
521
                        unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
522
                        if (!vma->vm_inode) {
523
                                data += len;
524
                                if (vma->vm_flags & VM_GROWSDOWN)
525
                                        stack += len;
526
                                continue;
527
                        }
528
                        if (vma->vm_flags & VM_WRITE)
529
                                continue;
530
                        if (vma->vm_flags & VM_EXEC) {
531
                                exec += len;
532
                                if (vma->vm_flags & VM_EXECUTABLE)
533
                                        continue;
534
                                lib += len;
535
                        }
536
                }
537
                buffer += sprintf(buffer,
538
                        "VmSize:\t%8lu kB\n"
539
                        "VmLck:\t%8lu kB\n"
540
                        "VmRSS:\t%8lu kB\n"
541
                        "VmData:\t%8lu kB\n"
542
                        "VmStk:\t%8lu kB\n"
543
                        "VmExe:\t%8lu kB\n"
544
                        "VmLib:\t%8lu kB\n",
545
                        mm->total_vm << (PAGE_SHIFT-10),
546
                        mm->locked_vm << (PAGE_SHIFT-10),
547
                        mm->rss << (PAGE_SHIFT-10),
548
                        data - stack, stack,
549
                        exec - lib, lib);
550
        }
551
#else /* NO_MM */
552
        unsigned long bytes = 0, sbytes = 0;
553
        struct mm_tblock_struct * tblock;
554
 
555
        /* Logic: we've got two memory sums for each process, "shared", and
556
         * "non-shared". Shared memory may get counted more then once, for
557
         * each process that owns it. Non-shared memory is counted
558
         * accurately.
559
         *
560
         *      -- Kenneth Albanowski
561
         */
562
 
563
        for(tblock = &p->mm->tblock;tblock;tblock=tblock->next) {
564
 
565
                if (tblock->rblock) {
566
 
567
                        bytes += ksize(tblock);
568
 
569
                        if ((p->mm->count > 1) || (tblock->rblock->refcount > 1)) {
570
                                sbytes += ksize(tblock->rblock->kblock);
571
                                sbytes += ksize(tblock->rblock) ;
572
                        } else {
573
                                bytes += ksize(tblock->rblock->kblock);
574
                                bytes += ksize(tblock->rblock) ;
575
                        }
576
 
577
                }
578
 
579
 
580
        }
581
 
582
        ((p->mm->count > 1) ? sbytes : bytes) += ksize(p->mm);
583
        ((p->fs->count > 1) ? sbytes : bytes) += ksize(p->fs);
584
        ((p->files->count > 1) ? sbytes : bytes) += ksize(p->files);
585
        ((p->sig->count > 1) ? sbytes : bytes) += ksize(p->sig);
586
        bytes += ksize(p);
587
 
588
        bytes += PAGE_SIZE; /* Kernel stack */
589
 
590
        buffer += sprintf(buffer,
591
                "Mem:\t%8lu bytes\n"
592
                "Shared:\t%8lu bytes\n",
593
                bytes,
594
                sbytes);
595
#endif /* NO_MM */
596
        return buffer;
597
}
598
 
599
static inline char * task_sig(struct task_struct *p, char *buffer)
600
{
601
        buffer += sprintf(buffer,
602
                "SigPnd:\t%08lx\n"
603
                "SigBlk:\t%08lx\n",
604
                p->signal, p->blocked);
605
        if (p->sig) {
606
                struct sigaction * action = p->sig->action;
607
                unsigned long sig_ign = 0, sig_caught = 0;
608
                unsigned long bit = 1;
609
                int i;
610
 
611
                for (i = 0; i < 32; i++) {
612
                        switch((unsigned long) action->sa_handler) {
613
                                case 0:
614
                                        break;
615
                                case 1:
616
                                        sig_ign |= bit;
617
                                        break;
618
                                default:
619
                                        sig_caught |= bit;
620
                        }
621
                        bit <<= 1;
622
                        action++;
623
                }
624
 
625
                buffer += sprintf(buffer,
626
                        "SigIgn:\t%08lx\n"
627
                        "SigCgt:\t%08lx\n",
628
                        sig_ign, sig_caught);
629
        }
630
        return buffer;
631
}
632
 
633
static int get_status(int pid, char * buffer)
634
{
635
        char * orig = buffer;
636
        struct task_struct ** p = get_task(pid), *tsk;
637
 
638
        if (!p || (tsk = *p) == NULL)
639
                return 0;
640
        buffer = task_name(tsk, buffer);
641
        buffer = task_state(tsk, buffer);
642
        buffer = task_mem(tsk, buffer);
643
        buffer = task_sig(tsk, buffer);
644
        return buffer - orig;
645
}
646
 
647
static int get_stat(int pid, char * buffer)
648
{
649
        struct task_struct ** p = get_task(pid), *tsk;
650
        unsigned long sigignore=0, sigcatch=0, wchan;
651
        unsigned long vsize, eip, esp;
652
        long priority, nice;
653
        int i,tty_pgrp;
654
        char state;
655
 
656
        if (!p || (tsk = *p) == NULL)
657
                return 0;
658
        if (tsk->state < 0 || tsk->state > 5)
659
                state = '.';
660
        else
661
                state = "RSDZTW"[tsk->state];
662
        vsize = eip = esp = 0;
663
        if (tsk->mm && tsk->mm != &init_mm) {
664
#ifndef NO_MM
665
                struct vm_area_struct *vma = tsk->mm->mmap;
666
                while (vma) {
667
                        vsize += vma->vm_end - vma->vm_start;
668
                        vma = vma->vm_next;
669
                }
670
                if (tsk->kernel_stack_page) {
671
                        eip = KSTK_EIP(tsk);
672
                        esp = KSTK_ESP(tsk);
673
                }
674
#endif /* !NO_MM */
675
        }
676
        wchan = get_wchan(tsk);
677
        if (tsk->sig) {
678
                unsigned long bit = 1;
679
                for(i=0; i<32; ++i) {
680
                        switch((unsigned long) tsk->sig->action[i].sa_handler) {
681
                                case 0:
682
                                        break;
683
                                case 1:
684
                                        sigignore |= bit;
685
                                        break;
686
                                default:
687
                                        sigcatch |= bit;
688
                        }
689
                        bit <<= 1;
690
                }
691
        }
692
        if (tsk->tty)
693
                tty_pgrp = tsk->tty->pgrp;
694
        else
695
                tty_pgrp = -1;
696
 
697
        /* scale priority and nice values from timeslices to -20..20 */
698
        /* to make it look like a "normal" unix priority/nice value  */
699
        priority = tsk->counter;
700
        priority = 20 - (priority * 10 + DEF_PRIORITY / 2) / DEF_PRIORITY;
701
        nice = tsk->priority;
702
        nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY;
703
 
704
        return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
705
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
706
%lu %lu %lu %lu %lu %lu %lu %lu\n",
707
                pid,
708
                tsk->comm,
709
                state,
710
                tsk->p_pptr->pid,
711
                tsk->pgrp,
712
                tsk->session,
713
                tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0,
714
                tty_pgrp,
715
                tsk->flags,
716
                tsk->min_flt,
717
                tsk->cmin_flt,
718
                tsk->maj_flt,
719
                tsk->cmaj_flt,
720
                tsk->utime,
721
                tsk->stime,
722
                tsk->cutime,
723
                tsk->cstime,
724
                priority,
725
                nice,
726
                tsk->timeout,
727
                tsk->it_real_value,
728
                tsk->start_time,
729
                vsize,
730
                tsk->mm ? tsk->mm->rss : 0, /* you might want to shift this left 3 */
731
                tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0,
732
                tsk->mm ? tsk->mm->start_code : 0,
733
                tsk->mm ? tsk->mm->end_code : 0,
734
                tsk->mm ? tsk->mm->start_stack : 0,
735
                esp,
736
                eip,
737
                tsk->signal,
738
                tsk->blocked,
739
                sigignore,
740
                sigcatch,
741
                wchan,
742
                tsk->nswap,
743
                tsk->cnswap);
744
}
745
 
746
#ifndef NO_MM
747
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
748
        int * pages, int * shared, int * dirty, int * total)
749
{
750
        pte_t * pte;
751
        unsigned long end;
752
 
753
        if (pmd_none(*pmd))
754
                return;
755
        if (pmd_bad(*pmd)) {
756
                printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
757
                pmd_clear(pmd);
758
                return;
759
        }
760
        pte = pte_offset(pmd, address);
761
        address &= ~PMD_MASK;
762
        end = address + size;
763
        if (end > PMD_SIZE)
764
                end = PMD_SIZE;
765
        do {
766
                pte_t page = *pte;
767
 
768
                address += PAGE_SIZE;
769
                pte++;
770
                if (pte_none(page))
771
                        continue;
772
                ++*total;
773
                if (!pte_present(page))
774
                        continue;
775
                ++*pages;
776
                if (pte_dirty(page))
777
                        ++*dirty;
778
                if (pte_page(page) >= high_memory)
779
                        continue;
780
                if (mem_map[MAP_NR(pte_page(page))].count > 1)
781
                        ++*shared;
782
        } while (address < end);
783
}
784
 
785
static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size,
786
        int * pages, int * shared, int * dirty, int * total)
787
{
788
        pmd_t * pmd;
789
        unsigned long end;
790
 
791
        if (pgd_none(*pgd))
792
                return;
793
        if (pgd_bad(*pgd)) {
794
                printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
795
                pgd_clear(pgd);
796
                return;
797
        }
798
        pmd = pmd_offset(pgd, address);
799
        address &= ~PGDIR_MASK;
800
        end = address + size;
801
        if (end > PGDIR_SIZE)
802
                end = PGDIR_SIZE;
803
        do {
804
                statm_pte_range(pmd, address, end - address, pages, shared, dirty, total);
805
                address = (address + PMD_SIZE) & PMD_MASK;
806
                pmd++;
807
        } while (address < end);
808
}
809
 
810
static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end,
811
        int * pages, int * shared, int * dirty, int * total)
812
{
813
        while (address < end) {
814
                statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total);
815
                address = (address + PGDIR_SIZE) & PGDIR_MASK;
816
                pgd++;
817
        }
818
}
819
 
820
static int get_statm(int pid, char * buffer)
821
{
822
        struct task_struct ** p = get_task(pid), *tsk;
823
        int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
824
 
825
        if (!p || (tsk = *p) == NULL)
826
                return 0;
827
        if (tsk->mm && tsk->mm != &init_mm) {
828
                struct vm_area_struct * vma = tsk->mm->mmap;
829
 
830
                while (vma) {
831
                        pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
832
                        int pages = 0, shared = 0, dirty = 0, total = 0;
833
 
834
                        statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
835
                        resident += pages;
836
                        share += shared;
837
                        dt += dirty;
838
                        size += total;
839
                        if (vma->vm_flags & VM_EXECUTABLE)
840
                                trs += pages;   /* text */
841
                        else if (vma->vm_flags & VM_GROWSDOWN)
842
                                drs += pages;   /* stack */
843
                        else if (vma->vm_end > 0x60000000)
844
                                lrs += pages;   /* library */
845
                        else
846
                                drs += pages;
847
                        vma = vma->vm_next;
848
                }
849
        }
850
        return sprintf(buffer,"%d %d %d %d %d %d %d\n",
851
                       size, resident, share, trs, lrs, drs, dt);
852
}
853
 
854
/*
855
 * The way we support synthetic files > 4K
856
 * - without storing their contents in some buffer and
857
 * - without walking through the entire synthetic file until we reach the
858
 *   position of the requested data
859
 * is to cleverly encode the current position in the file's f_pos field.
860
 * There is no requirement that a read() call which returns `count' bytes
861
 * of data increases f_pos by exactly `count'.
862
 *
863
 * This idea is Linus' one. Bruno implemented it.
864
 */
865
 
866
/*
867
 * For the /proc/<pid>/maps file, we use fixed length records, each containing
868
 * a single line.
869
 */
870
#define MAPS_LINE_LENGTH        1024
871
#define MAPS_LINE_SHIFT         10
872
/*
873
 * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH
874
 *         + (index into the line)
875
 */
876
/* for systems with sizeof(void*) == 4: */
877
#define MAPS_LINE_FORMAT4         "%08lx-%08lx %s %08lx %s %lu\n"
878
#define MAPS_LINE_MAX4  49 /* sum of 8  1  8  1 4 1 8 1 5 1 10 1 */
879
 
880
/* for systems with sizeof(void*) == 8: */
881
#define MAPS_LINE_FORMAT8         "%016lx-%016lx %s %016lx %s %lu\n"
882
#define MAPS_LINE_MAX8  73 /* sum of 16  1  16  1 4 1 16 1 5 1 10 1 */
883
 
884
#define MAPS_LINE_MAX   MAPS_LINE_MAX8
885
 
886
 
887
static int read_maps (int pid, struct file * file, char * buf, int count)
888
{
889
        struct task_struct ** p = get_task(pid);
890
        char * destptr;
891
        loff_t lineno;
892
        int column;
893
        struct vm_area_struct * map;
894
        int i;
895
 
896
        if (!p || !*p)
897
                return -EINVAL;
898
 
899
        if (!(*p)->mm || (*p)->mm == &init_mm || count == 0)
900
                return 0;
901
 
902
        /* decode f_pos */
903
        lineno = file->f_pos >> MAPS_LINE_SHIFT;
904
        column = file->f_pos & (MAPS_LINE_LENGTH-1);
905
 
906
        /* quickly go to line lineno */
907
        for (map = (*p)->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
908
                continue;
909
 
910
        destptr = buf;
911
 
912
        for ( ; map ; ) {
913
                /* produce the next line */
914
                char line[MAPS_LINE_MAX+1];
915
                char str[5], *cp = str;
916
                int flags;
917
                kdev_t dev;
918
                unsigned long ino;
919
                int len;
920
 
921
                flags = map->vm_flags;
922
 
923
                *cp++ = flags & VM_READ ? 'r' : '-';
924
                *cp++ = flags & VM_WRITE ? 'w' : '-';
925
                *cp++ = flags & VM_EXEC ? 'x' : '-';
926
                *cp++ = flags & VM_MAYSHARE ? 's' : 'p';
927
                *cp++ = 0;
928
 
929
                if (map->vm_inode != NULL) {
930
                        dev = map->vm_inode->i_dev;
931
                        ino = map->vm_inode->i_ino;
932
                } else {
933
                        dev = 0;
934
                        ino = 0;
935
                }
936
 
937
                len = sprintf(line,
938
                              sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8,
939
                              map->vm_start, map->vm_end, str, map->vm_offset,
940
                              kdevname(dev), ino);
941
 
942
                if (column >= len) {
943
                        column = 0; /* continue with next line at column 0 */
944
                        lineno++;
945
                        map = map->vm_next;
946
                        continue;
947
                }
948
 
949
                i = len-column;
950
                if (i > count)
951
                        i = count;
952
                memcpy_tofs(destptr, line+column, i);
953
                destptr += i; count -= i;
954
                column += i;
955
                if (column >= len) {
956
                        column = 0; /* next time: next line at column 0 */
957
                        lineno++;
958
                        map = map->vm_next;
959
                }
960
 
961
                /* done? */
962
                if (count == 0)
963
                        break;
964
 
965
                /* By writing to user space, we might have slept.
966
                 * Stop the loop, to avoid a race condition.
967
                 */
968
                if (*p != current)
969
                        break;
970
        }
971
 
972
        /* encode f_pos */
973
        file->f_pos = (lineno << MAPS_LINE_SHIFT) + column;
974
 
975
        return destptr-buf;
976
}
977
#endif /* !NO_MM */
978
 
979
#ifdef CONFIG_MODULES
980
extern int get_module_list(char *);
981
extern int get_ksyms_list(char *, char **, off_t, int);
982
#endif
983
extern int get_device_list(char *);
984
extern int get_filesystem_list(char *);
985
extern int get_filesystem_info( char * );
986
extern int get_irq_list(char *);
987
extern int get_serialinfo(char *);
988
extern int get_dma_list(char *);
989
extern int get_cpuinfo(char *);
990
extern int get_pci_list(char*);
991
extern int get_md_status (char *);
992
extern int get_rtc_status (char *);
993
extern int get_locks_status (char *, char **, off_t, int);
994
#ifdef __SMP_PROF__
995
extern int get_smp_prof_list(char *);
996
#endif
997
 
998
static int get_root_array(char * page, int type, char **start, off_t offset, int length)
999
{
1000
        switch (type) {
1001
                case PROC_LOADAVG:
1002
                        return get_loadavg(page);
1003
 
1004
                case PROC_UPTIME:
1005
                        return get_uptime(page);
1006
 
1007
                case PROC_MEMINFO:
1008
                        return get_meminfo(page);
1009
 
1010
#ifdef CONFIG_PCI
1011
                case PROC_PCI:
1012
                        return get_pci_list(page);
1013
#endif
1014
 
1015
                case PROC_CPUINFO:
1016
                        return get_cpuinfo(page);
1017
 
1018
                case PROC_VERSION:
1019
                        return get_version(page);
1020
 
1021
#ifdef CONFIG_DEBUG_MALLOC
1022
                case PROC_MALLOC:
1023
                        return get_malloc(page);
1024
#endif
1025
 
1026
#ifdef CONFIG_MODULES
1027
                case PROC_MODULES:
1028
                        return get_module_list(page);
1029
 
1030
                case PROC_KSYMS:
1031
                        return get_ksyms_list(page, start, offset, length);
1032
#endif
1033
 
1034
                case PROC_STAT:
1035
                        return get_kstat(page);
1036
 
1037
                case PROC_DEVICES:
1038
                        return get_device_list(page);
1039
 
1040
                case PROC_INTERRUPTS:
1041
                        return get_irq_list(page);
1042
 
1043
                case PROC_SERIAL:
1044
                        return get_serialinfo(page);
1045
 
1046
                case PROC_FILESYSTEMS:
1047
                        return get_filesystem_list(page);
1048
 
1049
                case PROC_DMA:
1050
                        return get_dma_list(page);
1051
 
1052
                case PROC_IOPORTS:
1053
                        return get_ioport_list(page);
1054
#ifdef CONFIG_BLK_DEV_MD
1055
                case PROC_MD:
1056
                        return get_md_status(page);
1057
#endif
1058
#ifdef __SMP_PROF__
1059
                case PROC_SMP_PROF:
1060
                        return get_smp_prof_list(page);
1061
#endif
1062
                case PROC_CMDLINE:
1063
                        return get_cmdline(page);
1064
 
1065
                case PROC_MTAB:
1066
                       return get_filesystem_info( page );
1067
#ifdef CONFIG_RTC
1068
                case PROC_RTC:
1069
                        return get_rtc_status(page);
1070
#endif
1071
                case PROC_LOCKS:
1072
                        return get_locks_status(page, start, offset, length);
1073
        }
1074
        return -EBADF;
1075
}
1076
 
1077
static int process_unauthorized(int type, int pid)
1078
{
1079
        struct task_struct ** p = get_task(pid);
1080
 
1081
        if (!p || !*p || !(*p)->mm)
1082
                return 1;
1083
 
1084
        switch(type)
1085
        {
1086
                case PROC_PID_STATUS:
1087
                case PROC_PID_STAT:
1088
                case PROC_PID_CMDLINE:
1089
#ifndef NO_MM
1090
                case PROC_PID_STATM:
1091
                case PROC_PID_MAPS:
1092
#endif
1093
                        return 0;
1094
        }
1095
        if(suser() || current->fsuid == (*p)->euid)
1096
                return 0;
1097
        return 1;
1098
}
1099
 
1100
 
1101
static int get_process_array(char * page, int pid, int type)
1102
{
1103
        switch (type) {
1104
                case PROC_PID_STATUS:
1105
                        return get_status(pid, page);
1106
                case PROC_PID_ENVIRON:
1107
                        return get_env(pid, page);
1108
                case PROC_PID_CMDLINE:
1109
                        return get_arg(pid, page);
1110
                case PROC_PID_STAT:
1111
                        return get_stat(pid, page);
1112
#ifndef NO_MM
1113
                case PROC_PID_STATM:
1114
                        return get_statm(pid, page);
1115
#endif /* !NO_MM */
1116
        }
1117
        return -EBADF;
1118
}
1119
 
1120
 
1121
static inline int fill_array(char * page, int pid, int type, char **start, off_t offset, int length)
1122
{
1123
        if (pid)
1124
                return get_process_array(page, pid, type);
1125
        return get_root_array(page, type, start, offset, length);
1126
}
1127
 
1128
#define PROC_BLOCK_SIZE (3*1024)                /* 4K page size but our output routines use some slack for overruns */
1129
 
1130
static int array_read(struct inode * inode, struct file * file,char * buf, int count)
1131
{
1132
        unsigned long page;
1133
        char *start;
1134
        int length;
1135
        int end;
1136
        unsigned int type, pid;
1137
        struct proc_dir_entry *dp;
1138
 
1139
        if (count < 0)
1140
                return -EINVAL;
1141
        if (count > PROC_BLOCK_SIZE)
1142
                count = PROC_BLOCK_SIZE;
1143
        if (!(page = __get_free_page(GFP_KERNEL)))
1144
                return -ENOMEM;
1145
        type = inode->i_ino;
1146
        pid = type >> 16;
1147
        type &= 0x0000ffff;
1148
        start = NULL;
1149
        dp = (struct proc_dir_entry *) inode->u.generic_ip;
1150
 
1151
        if (pid && process_unauthorized(type, pid))
1152
        {
1153
                free_page(page);
1154
                return -EIO;
1155
        }
1156
 
1157
        if (dp->get_info)
1158
                length = dp->get_info((char *)page, &start, file->f_pos,
1159
                                      count, 0);
1160
        else
1161
                length = fill_array((char *) page, pid, type,
1162
                                    &start, file->f_pos, count);
1163
        if (length < 0) {
1164
                free_page(page);
1165
                return length;
1166
        }
1167
        if (start != NULL) {
1168
                /* We have had block-adjusting processing! */
1169
                memcpy_tofs(buf, start, length);
1170
                file->f_pos += length;
1171
                count = length;
1172
        } else {
1173
                /* Static 4kB (or whatever) block capacity */
1174
                if (file->f_pos >= length) {
1175
                        free_page(page);
1176
                        return 0;
1177
                }
1178
                if (count + file->f_pos > length)
1179
                        count = length - file->f_pos;
1180
                end = count + file->f_pos;
1181
                memcpy_tofs(buf, (char *) page + file->f_pos, count);
1182
                file->f_pos = end;
1183
        }
1184
        free_page(page);
1185
        return count;
1186
}
1187
 
1188
static struct file_operations proc_array_operations = {
1189
        NULL,           /* array_lseek */
1190
        array_read,
1191
        NULL,           /* array_write */
1192
        NULL,           /* array_readdir */
1193
        NULL,           /* array_select */
1194
        NULL,           /* array_ioctl */
1195
        NULL,           /* mmap */
1196
        NULL,           /* no special open code */
1197
        NULL,           /* no special release code */
1198
        NULL            /* can't fsync */
1199
};
1200
 
1201
struct inode_operations proc_array_inode_operations = {
1202
        &proc_array_operations, /* default base directory file-ops */
1203
        NULL,                   /* create */
1204
        NULL,                   /* lookup */
1205
        NULL,                   /* link */
1206
        NULL,                   /* unlink */
1207
        NULL,                   /* symlink */
1208
        NULL,                   /* mkdir */
1209
        NULL,                   /* rmdir */
1210
        NULL,                   /* mknod */
1211
        NULL,                   /* rename */
1212
        NULL,                   /* readlink */
1213
        NULL,                   /* follow_link */
1214
        NULL,                   /* readpage */
1215
        NULL,                   /* writepage */
1216
        NULL,                   /* bmap */
1217
        NULL,                   /* truncate */
1218
        NULL                    /* permission */
1219
};
1220
 
1221
static int arraylong_read (struct inode * inode, struct file * file, char * buf, int count)
1222
{
1223
#ifndef NO_MM
1224
        unsigned int pid = inode->i_ino >> 16;
1225
        unsigned int type = inode->i_ino & 0x0000ffff;
1226
 
1227
        if (count < 0)
1228
                return -EINVAL;
1229
 
1230
        switch (type) {
1231
                case PROC_PID_MAPS:
1232
                        return read_maps(pid, file, buf, count);
1233
        }
1234
#endif /* !NO_MM */
1235
        return -EINVAL;
1236
}
1237
 
1238
static struct file_operations proc_arraylong_operations = {
1239
        NULL,           /* array_lseek */
1240
        arraylong_read,
1241
        NULL,           /* array_write */
1242
        NULL,           /* array_readdir */
1243
        NULL,           /* array_select */
1244
        NULL,           /* array_ioctl */
1245
        NULL,           /* mmap */
1246
        NULL,           /* no special open code */
1247
        NULL,           /* no special release code */
1248
        NULL            /* can't fsync */
1249
};
1250
 
1251
struct inode_operations proc_arraylong_inode_operations = {
1252
        &proc_arraylong_operations,     /* default base directory file-ops */
1253
        NULL,                   /* create */
1254
        NULL,                   /* lookup */
1255
        NULL,                   /* link */
1256
        NULL,                   /* unlink */
1257
        NULL,                   /* symlink */
1258
        NULL,                   /* mkdir */
1259
        NULL,                   /* rmdir */
1260
        NULL,                   /* mknod */
1261
        NULL,                   /* rename */
1262
        NULL,                   /* readlink */
1263
        NULL,                   /* follow_link */
1264
        NULL,                   /* readpage */
1265
        NULL,                   /* writepage */
1266
        NULL,                   /* bmap */
1267
        NULL,                   /* truncate */
1268
        NULL                    /* permission */
1269
};

powered by: WebSVN 2.1.0

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