42 0444|S_IFREG
, "cpuinfo",
43 0444|S_IFREG
, "meminfo",
44 0444|S_IFREG
, "uptime",
45 0444|S_IFREG
, "loadavg",
49 0444|S_IFREG
, "cmdline",
50 0444|S_IFREG
, "environ",
54 0444|S_IFREG
, "statm",
55 0444|S_IFREG
, "status",
63 typedef struct Procfile Procfile
;
75 path2q(char *path
, int *ppid
, int *pfd
)
84 for(i
=Qproc
; i
<Qmax
; i
++){
85 if(x
= strchr(path
, '/'))
87 if(path
[0]>='0' && path
[0]<='9'){
98 if(strcmp(path
, procdevtab
[i
].name
) == 0){
103 if(i
== Qself
){ /* hack */
107 if((procdevtab
[i
].mode
& ~0777) == S_IFDIR
){
124 * the proc device also implements the functionality
125 * for /dev/std^(in out err) and /dev/fd. we just
126 * rewrite the path to the names used in /proc.
129 rewritepath(char *path
)
131 if(strcmp(path
, "/dev/stdin")==0){
132 path
= kstrdup("/proc/self/fd/0");
133 } else if(strcmp(path
, "/dev/stdout")==0){
134 path
= kstrdup("/proc/self/fd/1");
135 } else if(strcmp(path
, "/dev/stderr")==0){
136 path
= kstrdup("/proc/self/fd/2");
137 } else if(strncmp(path
, "/dev/fd", 7) == 0){
138 path
= allocpath("/proc/self", "fd", path
+7);
140 path
= kstrdup(path
);
146 readlinkproc(char *path
, char *buf
, int len
);
149 openproc(char *path
, int mode
, int perm
, Ufile
**pf
)
156 path
= rewritepath(path
);
157 if((q
= path2q(path
, &pid
, nil
)) < 0)
159 if((procdevtab
[q
].mode
& ~0777) == S_IFLNK
){
160 n
= readlinkproc(path
, buf
, sizeof(buf
)-1);
163 err
= fsopen(buf
, mode
, perm
, pf
);
167 if((mode
& O_ACCMODE
) != O_RDONLY
){
173 if(getproc(pid
) == nil
){
181 if(strncmp(path
, "/proc/self", 10) == 0){
182 t
= ksmprint("/proc/%d%s", pid
, path
+10);
183 free(path
); path
= t
;
186 f
= kmallocz(sizeof(*f
), 1);
189 f
->path
= path
; path
= nil
;
203 closeproc(Ufile
*file
)
205 Procfile
*f
= (Procfile
*)file
;
227 sysstat(ulong
*prun
, ulong
*pidle
, ulong
*pload
)
229 char buf
[1024], *p
, *e
, *t
, *data
;
230 ulong dt
, swtch
, user
, sys
, load
;
231 static ulong run
, idle
, intr
;
235 swtch
= user
= sys
= load
= 0;
237 dt
= (ulong
)(((nsec() - boottime
) * HZ
) / 1000000000LL) - run
;
241 if((fd
= open("/dev/sysstat", OREAD
)) >= 0){
242 n
= read(fd
, buf
, sizeof(buf
)-1);
248 while(e
= strchr(p
, '\n')){
251 if(getfields(p
, f
, SSmax
, 1, "\t ") != SSmax
)
255 swtch
+= atoi(f
[SSswitches
]);
257 idle
+= (atoi(f
[SSidletime
]) * dt
)/100;
258 intr
+= (atoi(f
[SSintrtime
]) * dt
)/100;
260 load
= 100-atoi(f
[SSidletime
]);
262 user
= run
- idle
- intr
;
265 data
= ksmprint("cpu %lud %lud %lud %lud %lud %lud %lud\n",
266 user
, 0UL, sys
, idle
, 0UL, intr
, 0UL);
268 t
= ksmprint("%scpu%d %lud %lud %lud %lud %lud %lud %lud\n",
269 data
, atoi(f
[SScpu
]), user
, 0UL, sys
, idle
, 0UL, intr
, 0UL);
275 t
= ksmprint("%sbtime %lud\nctxt %lud\n", data
,
276 (ulong
)(boottime
/1000000000LL), swtch
);
294 (p
->wstate
& WEXITED
) ? "Z (zombie)" :
295 (p
->wstate
& WSTOPPED
) ? "T (stopped)" :
296 (p
->state
== nil
) ? "R (running)" : "S (sleeping)";
305 if(p
== nil
|| p
->comm
== nil
)
307 if(s
= strrchr(p
->comm
, '/'))
317 int i
, nproc
, nready
;
329 ulong vmsize
, vmdat
, vmlib
, vmshr
, vmstk
, vmexe
;
332 if((p
= getproc(f
->pid
)) == nil
){
339 if(p
== nil
|| p
->comm
== nil
)
341 i
= strlen(p
->comm
)+1;
344 f
->ndata
= p
->ncomm
-i
-2;
345 f
->data
= kmalloc(f
->ndata
);
346 memmove(f
->data
, p
->comm
+ i
, f
->ndata
);
353 if(proctimes(p
, tms
) != 0)
354 memset(tms
, 0, sizeof(tms
));
355 vmsize
= procmemstat(p
, nil
, nil
, nil
, nil
, nil
);
357 "%d (%s) %c %d %d %d %d %d %lud %lud "
358 "%lud %lud %lud %lud %lud %ld %ld %ld %ld %ld "
359 "%ld %lud %lud %ld %lud %lud %lud %lud %lud %lud "
360 "%lud %lud %lud %lud %lud %lud %lud %d %d\n",
370 0UL, 0UL, 0UL, 0UL, /* pagefault stats */
377 0UL, /* always 0UL */
378 0UL, /* time to next alarm */
379 (ulong
)(((p
->starttime
- boottime
) * HZ
) / 1000000000LL),
380 vmsize
, /* vm size in bytes */
381 vmsize
, /* vm working set */
388 0UL, /* pending signal mask */
389 0UL, /* blocked signal mask */
390 0UL, /* ignored signal mask */
391 0UL, /* catched signal mask */
394 0UL, /* nswap children */
399 vmsize
= procmemstat(p
, &vmdat
, &vmlib
, &vmshr
, &vmstk
, &vmexe
);
400 s
= ksmprint("%lud %lud %lud %lud %lud %lud %lud\n",
401 vmsize
/PAGESIZE
, vmsize
/PAGESIZE
, vmshr
/PAGESIZE
,
402 vmexe
/PAGESIZE
, vmstk
/PAGESIZE
, vmlib
/PAGESIZE
, 0UL);
411 "Uid:\t%d\t%d\t%d\t%d\n"
412 "Gid:\t%d\t%d\t%d\t%d\n"
420 p
->uid
, p
->uid
, p
->uid
, p
->uid
,
421 p
->gid
, p
->gid
, p
->gid
, p
->gid
,
423 threadcount(p
->pid
));
430 ulong run
, idle
, load
;
434 for(i
=0; i
<MAXPROC
; i
++){
447 s
= sysstat(nil
, nil
, nil
);
452 "procs_blocked %d\n",
465 free(sysstat(&run
, &idle
, nil
));
466 s
= ksmprint("%lud.%lud %lud.%lud\n", run
/HZ
, run%HZ
, idle
/HZ
, idle%HZ
);
469 free(sysstat(nil
, nil
, &load
));
470 s
= ksmprint("%lud.%lud 0 0 %d/%d %d\n", load
/100, load%100
, nready
, nproc
, i
);
476 f
->ndata
= s
? strlen(s
) : 0;
480 sizeproc(Ufile
*file
)
482 Procfile
*f
= (Procfile
*)file
;
490 readproc(Ufile
*file
, void *buf
, int len
, vlong off
)
492 Procfile
*f
= (Procfile
*)file
;
495 if((f
->data
== nil
) || (off
!= f
->lastoff
))
498 if(f
->data
&& (off
< f
->ndata
)){
499 ret
= f
->ndata
- off
;
502 memmove(buf
, f
->data
+ off
, ret
);
503 f
->lastoff
= off
+ ret
;
509 readlinkproc(char *path
, char *buf
, int len
)
517 path
= rewritepath(path
);
518 if((q
= path2q(path
, &pid
, &fd
)) < 0)
523 if((p
= getproc(pid
)) == nil
){
529 data
= kstrdup(p
->cwd
);
533 if(p
== nil
|| p
->comm
== nil
)
535 data
= kstrdup(p
->comm
);
538 data
= kstrdup(p
->root
? p
->root
: "/");
541 a
= procfdgetfile(p
, fd
);
542 if(a
== nil
|| a
->path
== nil
){
547 data
= kstrdup(a
->path
);
555 data
= ksmprint("/proc/%d", current
->pid
);
564 memmove(buf
, data
, err
);
573 readdirproc(Ufile
*file
, Udirent
**pd
)
575 Procfile
*f
= (Procfile
*)file
;
584 for(i
=f
->q
+1; (procdevtab
[i
].mode
& ~0777) != S_IFDIR
; i
++){
585 if((*pd
= newdirent(f
->path
, procdevtab
[i
].name
, procdevtab
[i
].mode
)) == nil
)
593 for(i
=0; i
<MAXPROC
; i
++){
597 if((f
->q
== Qproc
) && (p
->pid
!= p
->tid
))
599 if((f
->q
== Qtask
) && (p
->pid
!= f
->pid
))
601 snprint(buf
, sizeof(buf
), "%d", p
->tid
);
602 if((*pd
= newdirent(f
->path
, buf
, procdevtab
[i
].mode
)) == nil
)
611 if((*pd
= newdirent(f
->path
, procdevtab
[Qtask
].name
, procdevtab
[Qtask
].mode
)) == nil
)
617 if((*pd
= newdirent(f
->path
, procdevtab
[Qfd
].name
, procdevtab
[Qfd
].mode
)) == nil
)
621 for(i
=Qpid
+1; (procdevtab
[i
].mode
& ~0777) != S_IFDIR
; i
++){
622 if((*pd
= newdirent(f
->path
, procdevtab
[i
].name
, procdevtab
[i
].mode
)) == nil
)
631 if((p
= getproc(f
->pid
)) == nil
){
635 for(i
=0; i
<MAXFD
; i
++){
636 a
= procfdgetfile(p
, i
);
637 if(a
== nil
|| a
->path
== nil
){
642 snprint(buf
, sizeof(buf
), "%d", i
);
643 if((*pd
= newdirent(f
->path
, buf
, procdevtab
[Qfd1
].mode
)) == nil
)
656 statproc(char *path
, int, Ustat
*s
)
658 int q
, pid
, fd
, uid
, gid
, err
;
664 path
= rewritepath(path
);
665 if((q
= path2q(path
, &pid
, &fd
)) < 0)
669 if((p
= getproc(pid
)) == nil
){
674 a
= procfdgetfile(p
, fd
);
675 if(a
== nil
|| a
->path
== nil
){
684 ctime
= p
->starttime
/1000000000LL;
689 ctime
= boottime
/1000000000LL;
692 s
->mode
= procdevtab
[q
].mode
;
696 s
->ino
= hashpath(path
);
699 s
->atime
= s
->mtime
= s
->ctime
= ctime
;
706 fstatproc(Ufile
*f
, Ustat
*s
)
708 return fsstat(f
->path
, 0, s
);
711 static Udev procdev
=
716 .readlink
= readlinkproc
,
717 .readdir
= readdirproc
,
723 void procdevinit(void)
725 devtab
[PROCDEV
] = &procdev
;
727 fsmount(&procdev
, "/proc");
728 fsmount(&procdev
, "/dev/fd");
729 fsmount(&procdev
, "/dev/stdin");
730 fsmount(&procdev
, "/dev/stdout");
731 fsmount(&procdev
, "/dev/stderr");