document updated 12 years ago, on Jun 19, 2012
Things that are layered on top of pack/unpack, that let you define C structures so that the field-type and the field-name are located together. (normal pack() only uses the type)
DIY
Or you can just DIY:
sub parse_wtmp {
my ($fnames, $ftypes) = unzip(qw[
type l
pid i
line Z32
id Z4
user Z32
host A256
exit l
session l
tv_sec i
tv_usec i
addr_v6 a16
unused Z20
]);
#dump_size_offset($fnames, $ftypes); exit;
$ftypes = join(" ", @$ftypes);
open my $fin, '<', '/var/log/wtmp' or die $!;
local $/ = \(length pack $ftypes); # read fixed-length records
while (<$fin>) {
my %entry;
@entry{@$fnames} = unpack $ftypes, $_;
$entry{tv} = ~~localtime $entry{tv_sec};
$entry{addr_v6} = join ':', unpack 'H4H4H4H4H4H4H4H4', $entry{addr_v6};
print Dumper \%entry;
}
}
# split [1,'a',2,'b',3,'c'] into [[1,2,3],['a','b','c']]
sub unzip {my($i,$j)=(0,0); [grep{++$i%2}@_],[grep{$j++%2}@_]}
# For debugging purposes, show the size and offset of struct fields.
# Compare this to running 'c2ph' and looking at the "sizeof" and "offsetof" structures.
sub dump_size_offset {
my @field_names = @{shift()};
my @field_types = @{shift()};
my $offset = 0;
foreach my $fname (@field_names) {
my $ftype = shift @field_types;
my $size = length(pack($ftype));
printf "%-20s %-8s %8d %8d\n", $fname, $ftype, $size, $offset;
$offset += $size;
}
printf "%-20s %-8s %8s %8d\n", "", "", "", $offset;
}