;Copyright (C) 1999 Dmitry Bakhvalov
;
;$Id: ps.asm,v 1.4 2000/09/03 16:13:54 konst Exp $
;
;hackers' ps
;
;0.01: 28-Oct-1999 initial release
;
;syntax: ps
; No options are supported yet (and probably wont be) :)
;
;Always returns 0
;
; Please keep in mind that this is a hackers' ps, in other words it is
; in no way a replacement for standard GNU ps. Still it's usefull to find
; out what processes are running in your system (In case you want to kill some:)
;
; Hint: If you are surprised with TTY field, than substruct 1024 from its value
; to get the real tty number. If the field is 0 than the process doesnt
; have a tty :)
;
; RSS field is measured in pages.
;
; Send me any feedback,suggestions,additional code, etc.
;
%include "system.inc"
%assign statbuf_size 1024
%assign dirbuf_size 4096
CODESEG
START:
mov ecx,title ; print title
call print
mov ebx,_proc ; open /proc
sys_open EMPTY,O_RDONLY
test eax,eax
js near error
mov ebp,eax ; ebp holds filehandle
get_next_dentry:
sys_getdents ebp,dirbuf,dirbuf_size ; read this dir
test eax,eax
js near error ; cant read the dir
jz near no_more_files_in_proc ; no more entries in this dir
mov ebx,ecx ; ebx=dirbuf
mov ecx,eax ; ecx = the number of bytes
; that actually have been read
next_filename:
pushad ; save regs
lea esi,[ebx+10] ; esi=next entry name
call is_number ; is it a process?
test eax,eax
jnz near not_a_number ; nope
push esi ; save entry's name
mov esi,_proc ;
mov edi,file_buf ;
call strcpy ; file_buf="/proc/"
pop esi ; restore entry's name
; edi already holds file_buf
call strcat ; file_buf="/proc/pid"
mov esi,_stat ; esi="/stat"
; edi already holds file_buf
call strcat ; file_buf="/proc/pid/stat"
sys_open edi,O_RDONLY ; open /proc/pid/stat
test eax,eax
js not_a_number
sys_read eax,statbuf,statbuf_size ; read it
test eax,eax
js not_a_number
sys_close ; close it
mov edi,ecx ; edi=statbuf ptr
call print_fields
mov ecx,cr
call print
not_a_number:
; lets get to the next
; dentry
popad ; restore regs
xor eax,eax
mov ax,[ebx+8] ; eax=rec_len
add ebx,eax ; point ebx to next entry
sub ecx,eax ; rc-=rec_len
jz near get_next_dentry ; read more dentries
jmp next_filename ; our buf is not empty
error:
no_more_files_in_proc:
sys_exit_true
;
; -------------------------------- procedures ---------------------------------
;
; edi=buf, ecx=field num (begins at 1)
; -
print_field:
pushad
.next_field:
push ecx
xor eax,eax
xor ecx,ecx
dec ecx
mov esi,edi ; esi = ptr
repnz scasb ; look for \0
pop ecx
loop .next_field
mov ecx,esi ; our field
call print
mov ecx,tab ; \t
call print
popad
ret
; edi=buf
;
print_fields:
pushad
; replace all ' ' with \0
mov esi,edi
.next_char:
lodsb
test al,al
jz .end_of_buf
cmp al,' '
jnz .next_char
mov byte [esi-1],0 ; replace ' ' with \0
jmp .next_char
.end_of_buf:
; now print the fields we are interested in
mov esi,fields
.next_f:
lodsb
test al,al
jz .ret ; end of table
movzx ecx,al
call print_field
jmp .next_f
.ret:
popad
ret
; esi=string
; eax= 0 if it consists only of digits
is_number:
push esi
xor eax,eax
.next_char:
lodsb
test al,al
jz .done
cmp al,'0'
jae .next_test
inc ah ; set flag
jmp .done
.next_test:
cmp al,'9'
jle .next_char
inc ah ; set flag
.done:
xchg ah,al ; put flag in al
xor ah,ah ; wipe ah
pop esi
ret
; ecx=string to print
print:
pushad
mov esi,ecx
call strlen
; ecx already holds string, edx holds strlen
sys_write STDOUT
popad
ret
; esi=string
; edx=strlen
strlen:
push eax
push esi
xor edx,edx
dec edx
.do_strlen:
inc edx
lodsb
test al,al
jnz .do_strlen
pop esi
pop eax
ret
; esi=source edi=dest
; -
strcpy:
pushad
call strlen
inc edx ; copy NULL too
mov ecx,edx
rep movsb
popad
ret
; esi=source edi=dest
; -
strcat:
pushad
xchg esi,edi
call strlen
xchg esi,edi
add edi,edx
call strlen
inc edx ; copy NULL byte too
mov ecx,edx
rep movsb ; copy
popad
ret
DATASEG
title: db "PID",9,"TTY",9,"STAT",9,"RSS",9,"COMMAND",10,0
_proc: db "/proc/",0
_stat: db "/stat",0
cr: db 10,0
tab: db 9,0
fields: db 1,7,3,24,2,0
UDATASEG
file_buf: resb 256
statbuf resb statbuf_size
dirbuf resb dirbuf_size
END