Xref: utzoo comp.lang.perl:5221 comp.unix.sysv386:7835 Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!pacific.mps.ohio-state.edu!linac!att!pacbell.com!ucsd!nosc!humu!pegasus!pinhead!todd From: todd@pinhead.pegasus.com (Todd Ogasawara) Newsgroups: comp.lang.perl,comp.unix.sysv386 Subject: Re: Perl unpack/tacct file Keywords: pack, unpack, tacct files Message-ID: <1991May06.235754.29292@pinhead.pegasus.com> Date: 6 May 91 23:57:54 GMT References: <1991May04.185409.24228@pinhead.pegasus.com> Organization: Hawaii Medical Service Association Lines: 81 I posted a query last week. No responses so far, but I found a workaround. My question now is, "Why does my workaround work?" Here is my original posting. In article <1991May04.185409.24228@pinhead.pegasus.com> todd@pinhead.pegasus.com (Todd Ogasawara) writes: ]I just started using Perl a few weeks ago and have run into a problem when ]trying to use unpack to look at 'tacct' type accounting files on an 386 box ]running Interactive UNIX 2.2 (UNIX System V/386 R3). I'm pretty sure I ]understand the structure of this file type since C programs I've written to ]read it work fine. The C structure of this file looks like this: ]#p = prime time, np = non-prime time ]#struct tacct { ]# unsigned short ta_uid; /* userid */ ]# char ta_name[8]; /* login name */ ]# float ta_cpu[2]; /* cum cpu time, p/np (mins) */ ]# float ta_kcore[2]; /* cum kcore-minutes, p/np */ ]# float ta_con[2]; /* cum connect time p/np, mins */ ]# float ta_du; /* cum disk usage */ ]# long ta_pc; /* count of processes */ ]# unsigned short ta_sc; /* count of login sessions */ ]# unsigned short ta_dc; /* count of disk samples */ ]# unsigned short ta_fee; /* fee for special services */ ]#}; ] ]Here's the perl program I've tried to use to read a tacct file with. (BTW, ]I'm using Perl 4.0 patch level 3). ] ]open(TACCT,"/usr/adm/acct/sum/tacct"); ] ]while(read(TACCT,$tacct,52)) { ] ($uid,$name,$cpuP,$cpuNP,$kcoreP,$kcoreNP,$conP,$conNP, ] $du,$pc,$sc,$dc,$fee) = ] unpack("S A8 f f f f f f f l S S S",$tacct); ] local($TCONNECT) = $conP + $conNP; ] printf "%4d %8s %7.2f %d %d\n", ] $uid, $name, $TCONNECT, $sc, $dc; ]} ] ]The $uid and $name variables contain what I expect it to. However, ]everything else that follows seems to be one off. I.e., The $dc variable ]should contain the number of disk samples but seems to contain the number ]of login sessions instead. The floating point values are all over the ]place. I know that I must be reading in the floating point variables ]incorrectly, but I don't know what it is that I'm doing wrong. BTW, I have ]the Wall & Schwartz "Programming Perl" book and have gone through the ]sections describing pack and unpack several times to try to understand what ]is going on here. The following Perl program reads tacct type files correctly. My only problem is I don't understand why it works. I had to place two skips of x2 in the unpack template (see $stbuf_def) to get the program to work. I'm pretty sure my problem is not understanding exactly how C structures are built. I found that a C sizeof(tacctstruct) told me the structure is 52 bytes large. However, when I added the size of each individual structure member it added up to 48 bytes. I had to do a hex dump to find that there were four bytes in two places (two bytes in each place) that never seemed to be used. Is there some easy rule I can follow when using Perl to unpack files created using C structures? #! /usr/local/bin/perl open(TACCT,"/usr/adm/acct/sum/tacct"); $stbuf_def = "SA8x2f2f2f2flS3x2"; $streclen = length(pack($stbuf_def, 0)); print " UID NAME cpuP cpuNP conP conNP disksamp login\n"; while(read(TACCT,$tacct,$streclen)) { ($uid,$name,$cpuP,$cpuNP,$kcoreP,$kcoreNP,$conP,$conNP, $du,$pc,$sc,$dc,$fee) = unpack($stbuf_def,$tacct); printf "%4d %8s %9.2f %9.2f %7.2f %7.2f %9.2f %4d\n", $uid, $name, $cpuP, $cpuNP, $conP, $conNP, $du, $sc; } -- Todd Ogasawara ::: Hawaii Medical Service Association Internet ::: todd@pinhead.pegasus.com Telephone ::: (808) 536-9162 ext. 7