Perl for System Administration by David N. Blank-Edelman Unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. This page was updated April 18, 2007. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification UNCONFIRMED errors and comments from readers: (20) 4th paragraph, step 2; There appear to be two spaces between "you" and "reach" in "until you reach the center." [21] program flaw: This program could get stuck in a loop if you have two directories containing links to each other. I suggest putting the following above the check for -d: if (-l $name){ # skip links next; } This will not get stuck in an endless recursion path. There may be a more eloquent way to do this, but this works. {23} There is a subroutine called CheckFile, which has the following lines: for (my $i=0;$i< $stat[7];$i++){ my $r=sysread(T,$i,1); if ($r !=1) { close(T); return 0; } The line in question is the "my $r=sysread(T,$i,1);" line. The sysread is reading one byte into the iterator $i, so the second time the "for" loop is executed, it attempts to compare the first byte which could be a letter/number/non-printing character to the number of bytes of the file. This should be rewritten as follows: for (my $i=0;$i< $stat[7];$i++){ my $buf; my $r=sysread(T,$buf,1); if ($r !=1) { close(T); return 0; } This error can be discovered by turning strict on for the entire script. I would recommend to the author to turn strict on for every script in the book. It should improve things a bit. [27] source code at top of page using unlink function: I would like to see a warning about the use of "unlink". Using "unlink" to remove a directory could cause serious file system problems. Granted, in perl you would have to run the script as superuser with the "-U" flag on the perl interpreter. But because of the danger of using unlink I think the author should have mentioned this. [39] sub EdQuota: The line print NEWTEMP; should be outside the if (/^fs $fs\s+){ block. Otherwise, the only line printed to NEWTEMP and ultimately to $tfile is the changed line. (39) code example, first comment; In the comment, # open a scratch file, could use IO::File->new_tmpfile() instead the -> appears to have been typeset into an actual arrow character instead of the Perlish minus-greater. [40] code: $dev = Quota::getcarg should be $dev = Quota::getqcarg and ($curblock,$soft,$hard,$curinode,$btimeout,$curinode,$isoft,$ihard,$itimeout) should be ($curblock,$soft,$hard,$btimeout,$curinode,$isoft,$ihard,$itimeout) {48} code listing: if ($dirinfo->mode & 022 and (!$stat->mode & 01000)); should be: if ($dirinfo->mode & 022 and (!$dirinfo->mode & 01000)); [60] second and third code segments; Missing closing parenthesis before "die" in first segment; ";" instead of closing parenthesis before "die" in second segment. Both would be more idiomatically coded as Win32::Lanman::LsaLookupNames(..) or die ".."; (77) code; print OUTPUTFILE XMLout(TransformForWrite($queue),rootname => "queue"); should be: print OUTPUTFILE XMLout(TransformForWrite($queue),rootname => undef); (98) Example Perl code, 3rd paragraph ; In the example code, when extracting STDOUT from PULIST.EXE, there have been, what seem to be, a miss in printing. The following code is found in the book: $pulistexe = "\\bin\\PULIST.EXE"; # location of the executable open(PULIST,"$pulistexe|") or die "Can't execute $pulistexe:$!\n"; while(defined($_,)){ ($pname,$pid,$puser) = /^(\S+)\s*(\d+)\s*(.+)/; print "$pname:$pid:$puser\n"; close(PULIST); The code should look like this: $pulistexe = "\\bin\\PULIST.EXE"; # location of the executable open(PULIST,"$pulistexe|") or die "Can't execute $pulistexe:$!\n"; while(defined($_,)){ ($pname,$pid,$puser) = /^(\S+)\s*(\d+)\s*(.+)/; print "$pname:$pid:$puser\n"; } close(PULIST); The error was a missing closing curly-brace just before close(PULIST); {111-113} ... = Win32::OLE->GetObject('winmgmts:{impersonationLevel}=impersonate}!Win32_Proc ess') ... the } after impersonationLevel is wrong. The correct syntax should be ...= Win32::OLE->GetObject('winmgmts:{impersonationLevel=impersonate}!Win32_Proce ss')... {127} Source code; After comment "deal with a file set..." tVREG does not exist in lsof output. Change if (substr($_,0,5) eq "tVREG") { to if (substr($_,0,4) eq "tREG") { {134} code example, handling comments and blank lines; The code section next if /^#/; # skip comments lines next if /^$/; # skip empty lines s/\s*#.*$//; # delete in-line comments and preceding whitespace doesn't skip lines with indented comments, nor lines with only whitespace. I prefer the following construct, which surely many other people use but I've never run across elsewhere: s/\s*#.*//; # strip comments and optional preceding whitespace next if /^\s*$/; # skip (now-)blank lines (134) 3rd non-code paragraph; The final sentence ("Because it is so important, I'll return to this topic later in the chapter") is missing the final period. [152, 156] various lines of code: The code starts on the previous page defining a date format of yyyymmdd which is 8 characters. As the script progresses, this changes to 6 characters for the date instead of 8. For example, the line on page 152 (18 lines down the page) reads: $serial = sprintf("%6d%02d",$today,$count); It should read: $serial = sprintf("%8d%02d",$today,$count); There are equivalent errors on page 152 in lines 10, 15 and 16. Also on page 156, lines 17, 20, 21 and 23. {177} Table 6-1 now states that Net::LDAP does support SSL. It appears that the table originally indicated that SSL is not available for Net::LDAP. This correction would seem to indicate that SSL is available with Net::LDAP. Paragraph 2 of page 179 seems to contradict this by stating "Of the Perl modules available, only perLDAP offers LDAPS (SSL-encrypted sessions).". LDAPS (SSL) in Net::LDAP or not? (215) 3rd line from top; Shouldn't the line $u->SetInfo(); read $c->SetInfo() as $u is never set in the delete example block. [230] last example on page; the syntax in the for loop is incorrect. it reads: for ($i=0; $i < $sth->{NUM_OF_FIELDS};i++;) { but should read: for ($i=0; $i < $sth->{NUM_OF_FIELDS}; $i++) { ^^^^^^ (278) 1st Code section; The line: or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ; seems like it should be: or die "Cannot open file $blacklist: $! $BerkeleyDB::Error\n" ; (The filename is stored in the variable $blacklist) [402] paragraph preceding "SQL Stragglers": The example USE sysadm SELECT name,servicevendor,enddate FROM contracts, hosts WHERE contracts.name = hosts.name is followed by the explaination ON contracts.name = hosts.name ... Either the WHERE on ON must be incorrect.