From: Daniel Berger Date: 2008-08-26T23:16:28+09:00 Subject: Re: Unraveling binary data out of the proc filesystem on Solaris On Aug 25, 7:59 pm, "Heesob Park" wrote: > Hi, > > 2008/8/26 Daniel Berger : > > > Hi all, > > > Ruby 1.8.6 > > Solaris 10 > > > I'm trying to get process information on a Solaris using pure Ruby. > > For the basic information, this is fairly straightforward, as I read > > out of /proc//psinfo. > > > However, where I'm having trouble is getting the command line > > arguments out of /proc//as. Basically, I need to know how to > > unravel the data I'm reading into a human readable string. > > > Here's some sample code: > > > # sunos.rb > > module Sys > > class ProcTable > > def self.ps(pid = nil) > > Dir.foreach("/proc") do |file| > > next if file =~ /\D/ > > next if pid && file.to_i != pid > > > psinfo = IO.read("/proc/#{file}/psinfo") > > > pid = psinfo[8,4].unpack("L")[0] > > puts "PID: #{pid}" > > > argc = psinfo[188,4].unpack("L")[0] # pr_argc > > addr = psinfo[192,4].unpack("L")[0] # pr_argv > > > size = argc * 4 # 4 is the sizeof(caddr32_t) > > asinfo = IO.read("/proc/#{file}/as", size, addr) > > > # How do I unravel asinfo? > > p asinfo > > end > > end > > end > > end > > > if $0 == __FILE__ > > include Sys > > ProcTable.ps(2764) # or whatever pid you prefer > > end > > > The C code I'm trying to simulate, which I pulled from a post by Roger > > Faulkner on comp.unix.questions, looks something like this: > > > addr_args = p.pr_argv; /* from the psinfo struct */ > > arg_count = p.pr_argc; /* from the psinfo struct */ > > > if((fd = open(as_file, O_RDONLY)) < 0){ > > /* Do nothing - you can only get info on processes you rights to */ > > } > > else > > { > > arg_vec = malloc(arg_count * sizeof(uintptr_t)); > > (void)pread(fd, arg_vec, arg_count * sizeof (uintptr_t), > > addr_args); > > > arg_len = 16; > > arg = malloc(arg_len+1); > > > for(i = 0; i < arg_count; i++) { > > if(pread(fd, arg, arg_len, arg_vec[i]) < 0) > > continue; > > > arg[arg_len] = '\0'; > > if(strlen(arg) == arg_len){ > > arg_len *= 2; > > arg = realloc(arg, arg_len + 1); > > i--; > > continue; > > } > > rb_ary_push(v_cmd_array, rb_str_new2(arg)); > > } > > free(arg); > > free(arg_vec); > > } > > > close(fd); > > > Any ideas how to get the string(s) I need out of /proc//as ? > > Roger Faulkner mentioned in the com.unix.solraris like this: > > /proc//as is not your ordinary sparse file. > Attempts to read from non-existent portions of it yield a zero read(). > > The accessible portions of the as file are described by the > /proc//map file. Reading the map file gives you an array > of structures describing the legitimate addresses in the process. That shouldn't be necessary. I don't do that in the C code. I wouldn't think I would have to do that in Ruby. > Read (and re-read) the proc(4) man page documentation > > Refer tohttp://unix.derkeiler.com/Newsgroups/comp.unix.solaris/2003-05/3189.html > > According to the man page proc(4): > > as > Contains the address-space image of the process; it can be opened for > both reading and writing. lseek(2) is used to position the file at the > virtual address of interest and then the address space can be examined > or changed through read(2) or write(2) (or by using pread(2) or > pwrite(2) for the combined operation). > > According to the man page pread(2): > > The pread() function performs the same action as read(), except that > it reads from a given position in the file without changing the file > pointer. The first three arguments to pread() are the same as read() > with the addition of a fourth argument offset for the desired position > inside the file. pread() will read up to the maximum offset value that > can be represented in an off_t for regular files. An attempt to > perform a pread() on a file that is incapable of seeking results in an > error. > > I guess you should use lseek and read combination. Ruby has no lseek that I'm aware of. I tried an open + seek + read approach, but I get the same result. I guess I'll have to wrap pread and pwrite unless there's a way to read from a specific point in a file without moving the file pointer in Ruby that I don't know of. Maybe I'll tinker with mmap. Thanks, Dan