While developing a Perl script this weekend to summarize Solaris zone usage, I wanted to display some type of status while my script did it’s thing. My friend Clay came up with a cool way to do this, and I thought I would share it here in case others needed to do something similar. Here is the code:

#!/usr/bin/perl -w

# Initialize the index.
my $index=0;

# The characters to use as spinners.
my @spinners = ("-", "\\", "|", "/");
my $totalspinners =  $#spinners + 1;

# Turn on autoflush.
$| = 1;

print "Factoring primes:  ";

while (1) {
    print "\\b$spinners[$index++ % $totalspinners]";
    sleep 1;
}

# If you were to exit the loop, turn off autoflush.
$| = 0;

There may be a better way to do this (adding an additional module isn’t an option), but I have yet to find it. Niiiiiice!

Posted by matty, filed under Perl. Date: November 5, 2007, 1:05 pm | 1 Comment »

This week I needed to install a few Perl modules on a Solaris 10 host. I didn’t want to download and install a fourth perl interpreter (Solaris 10 comes with 5.6.1, 5.8.3 and 5.8.4 for some reason), since Solaris 10 comes with a relatively recent version of Perl (5.8.4). To build the module in question (DBD::mysql), I downloaded the module from CPAN, verified that the MD5 checksum was correct, and used the following steps to compile the module:

$ perl Makefile.PL

$ make

$ make install

The ‘make Makefile.PL’ completed succesfully, but the make failed with the following errors:

$ make

cp lib/DBD/mysql.pm blib/lib/DBD/mysql.pm
cp lib/DBD/mysql/GetInfo.pm blib/lib/DBD/mysql/GetInfo.pm
cp lib/Mysql.pm blib/lib/Mysql.pm
cp lib/DBD/mysql/INSTALL.pod blib/lib/DBD/mysql/INSTALL.pod
cp lib/Mysql/Statement.pm blib/lib/Mysql/Statement.pm
cp lib/Bundle/DBD/mysql.pm blib/lib/Bundle/DBD/mysql.pm
cc -c  -I/usr/perl5/site_perl/5.8.4/i86pc-solaris-64int/auto/DBI -I/home/apps/mysql/mysql/include/mysql -DDBD_MYSQL_INSERT_ID_I
S_GOOD -g  -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_TS_ERRNO -xO3 -xspace -xildoff    -DVERSION=\"3.0006\"  -DXS_VERSION=\
"3.0006\" -KPIC "-I/usr/perl5/5.8.4/lib/i86pc-solaris-64int/CORE"   dbdimp.c
cc: unrecognized option `-KPIC'
cc: language ildoff not recognized
cc: dbdimp.c: linker input file unused because linking not done
/usr/bin/perl -p -e "s/~DRIVER~/mysql/g" /usr/perl5/site_perl/5.8.4/i86pc-solaris-64int/auto/DBI/Driver.xst > mysql.xsi
/usr/bin/perl /usr/perl5/5.8.4/lib/ExtUtils/xsubpp  -typemap /usr/perl5/5.8.4/lib/ExtUtils/typemap  mysql.xs > mysql.xsc && mv
mysql.xsc mysql.c
Warning: duplicate function definition 'do' detected in mysql.xs, line 224
Warning: duplicate function definition 'rows' detected in mysql.xs, line 567
cc -c  -I/usr/perl5/site_perl/5.8.4/i86pc-solaris-64int/auto/DBI -I/home/apps/mysql/mysql/include/mysql -DDBD_MYSQL_INSERT_ID_I
S_GOOD -g  -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_TS_ERRNO -xO3 -xspace -xildoff    -DVERSION=\"3.0006\"  -DXS_VERSION=\
"3.0006\" -KPIC "-I/usr/perl5/5.8.4/lib/i86pc-solaris-64int/CORE"   mysql.c
cc: unrecognized option `-KPIC'
cc: language ildoff not recognized
cc: mysql.c: linker input file unused because linking not done
Running Mkbootstrap for DBD::mysql ()
chmod 644 mysql.bs
rm -f blib/arch/auto/DBD/mysql/mysql.so
LD_RUN_PATH="/home/apps/mysql/mysql/lib/mysql:/lib:/usr/lib" /usr/bin/perl myld cc  -G dbdimp.o  mysql.o  -o blib/arch/auto/DBD
/mysql/mysql.so   -L/home/apps/mysql/mysql/lib/mysql -lmysqlclient -lz -lposix4 -lcrypt -lgen -lsocket -lnsl -lm
cc: dbdimp.o: No such file or directory
cc: mysql.o: No such file or directory
*** Error code 1
make: Fatal error: Command failed for target `blib/arch/auto/DBD/mysql/mysql.so'

Since I was building the module with gcc, the compiler and linker got a bit confused when they were passed Sun studio compiler flags (i.e., -KPIC in this example). There are two fixes for this problem. If you want to build a single module with gcc, you can edit the Makefile that was produced by ‘perl Makefile.PL’, and remove the “-KPIC” and “-xO3 -xspace -xildoff” values from the following variables:

$ egrep ‘(KPIC|O3)’ Makefile
CCCDLFLAGS = -KPIC
OPTIMIZE = -xO3 -xspace -xildoff

If you want to use gcc to build all Perl modules on a system, you can permanently* remove the Sun Studio compiler references by adjusting the “cccdlflags” and “optimize” variables in /usr/perl5/5.8.4/lib/sun4-solaris-64int/Config.pm:

$ egrep ‘(KPIC|O3)’ Config.pm
cccdlflags=’-KPIC’
optimize=’-xO3 -xspace -xildoff’

Since I don’t want to support two compiler packages, I decided to use option #2 since gcc comes on the Solaris installation CDs.

* If you edit Config.pm, you should be aware that Solaris Perl patches will overwrite this file.

Posted by matty, filed under Perl. Date: July 29, 2006, 9:07 am | 8 Comments »

I have recently started using perldoc to access the Perl documentation collection, and can’t believe it took me this long to do so. Perldoc has a slew of nifty options, including “-l” (print the path to a Perl module) to print the full path to a given module:

$ /usr/perl5/5.8.4/bin/perldoc -l Net::DNS

/usr/perl5/site_perl/5.8.4/sun4-solaris-64int/Net/DNS.pm

And “-m” (display the modules Perl code) to display the modules code and pod documentation (if it exists):

$ /usr/perl5/5.8.4/bin/perldoc -m Net::DNS

package Net::DNS;
#
# $Id: DNS.pm 468 2005-07-22 12:12:55Z olaf $
#
use strict;

BEGIN {
    eval { require bytes; }
}

If you haven’t used perldoc to access the Perl documentation, I highly recommend doing so. You can get started with perldoc by running perldoc with the argument perldoc (e.g., $perldoc perldoc).

Posted by matty, filed under Perl. Date: July 2, 2006, 11:07 pm | No Comments »

While reading up on website performance monitoring applications last week, I came across the cricket HTTP-performance module. HTTP-performance allows you to graph the time it takes to connect to a website and to render a page. This sounded interesting, so I decided to download and install cricket. After reading through the beginners guide, I installed all of the required Perl modules, and proceeded to run the cricket compile script:

$ ./compile

Can't load '/usr/perl5/5.8.4/lib/i86pc-solaris-64int/auto/DB_File/DB_File.so' for module DB_File: ld.so.1: /usr/perl5/5.8.4/bin/perl: fatal: libdb-4.2.so: open failed: No such file or
directory at /usr/perl5/5.8.4/lib/i86pc-solaris-64int/XSLoader.pm line 68.
 at /usr/perl5/5.8.4/lib/i86pc-solaris-64int/DB_File.pm line 251
Compilation failed in require at /home/rmatteso/cricket-1.0.5/lib/ConfigTree/Node.pm line 25.
BEGIN failed--compilation aborted at /home/rmatteso/cricket-1.0.5/lib/ConfigTree/Node.pm line 25.
Compilation failed in require at ./compile line 39.
BEGIN failed--compilation aborted at ./compile line 39.I 

Ack!!!! — it looks like DB_File.so can’t find the BerkelyDB shared library:

$ ldd /usr/perl5/5.8.4/lib/i86pc-solaris-64int/auto/DB_File/DB_File.so

        libdb-4.2.so =>  (file not found)
        libc.so.1 =>     /lib/libc.so.1
        libm.so.2 =>     /lib/libm.so.2

Since I hate using LD_LIBRARY_PATH, I decided to adjust the link line to include a hard coded runtime path. To determine which variable to edit, I searched the Makefile until I came to the following line:

$ less Makefile

$(LD) $(LDDLFLAGS) $(LDFROM) $(OTHERLDFLAGS) -o $@ $(MYEXTLIB) $(PERL_ARCHIVE) \ $(LDLOADLIBS) $(PERL_ARCHIVE_AFTER) $(EXPORT_LIST) $(INST_DYNAMIC_FIX)

After locating this line, I added “-R/usr/sfw/lib:/usr/local/BerkeleyDB/lib” to the LDDLFLAGS variable and rebuilt the Perl module:

$ make

cc -c  -I/usr/local/BerkeleyDB/include  -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_TS_ERR
NO     -DVERSION="1.814"  -DXS_VERSION="1.814"  "-I/usr/perl5/5.8.4/lib/i86pc-solaris-64
int/CORE"  -D_NOT_CORE  -DmDB_Prefix_t=size_t -DmDB_Hash_t=u_int32_t version.c
cc -c  -I/usr/local/BerkeleyDB/include  -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_TS_ERR
NO     -DVERSION="1.814"  -DXS_VERSION="1.814"  "-I/usr/perl5/5.8.4/lib/i86pc-solaris-64
int/CORE"  -D_NOT_CORE  -DmDB_Prefix_t=size_t -DmDB_Hash_t=u_int32_t DB_File.c
Running Mkbootstrap for DB_File ()
chmod 644 DB_File.bs
rm -f blib/arch/auto/DB_File/DB_File.so
LD_RUN_PATH="/usr/local/BerkeleyDB/lib"
cc  -G -R/usr/sfw/lib:/usr/local/BerkeleyDB/lib version.o DB_File.o  -o blib/arch/auto/DB_File/DB_File.so   -L/usr/local/BerkeleyDB/lib -ldb
chmod 755 blib/arch/auto/DB_File/DB_File.so
cp DB_File.bs blib/arch/auto/DB_File/DB_File.bs
chmod 644 blib/arch/auto/DB_File/DB_File.bs
Manifying blib/man3/DB_File.3

$ make install

Installing /usr/perl5/5.8.4/lib/i86pc-solaris-64int/auto/DB_File/DB_File.so
Files found in blib/arch: installing files in blib/lib into architecture dependent library tree
Installing /usr/perl5/5.8.4/man/man3/DB_File.3
Writing /usr/perl5/5.8.4/lib/i86pc-solaris-64int/auto/DB_File/.packlist
Appending installation info to /usr/perl5/5.8.4/lib/i86pc-solaris-64int/perllocal.pod

Everything seemed to work, but did the runpath get set correctly? A quick check revealed that it did:

$ dump -Lv /usr/perl5/5.8.4/lib/i86pc-solaris-64int/auto/DB_File/DB_File.so

/usr/perl5/5.8.4/lib/i86pc-solaris-64int/auto/DB_File/DB_File.so:

  **** DYNAMIC SECTION INFORMATION ****
.dynamic:
[INDEX] Tag         Value
[1]     NEEDED          libdb-4.2.so
[2]     NEEDED          libc.so.1
[3]     INIT            0xe030
[4]     FINI            0xe050
[5]     RUNPATH         /usr/sfw/lib:/usr/local/BerkeleyDB/lib
[6]     RPATH           /usr/sfw/lib:/usr/local/BerkeleyDB/lib

This was a fun experience, since it finally forced me to sit down and read through the ELF standard (great read if you are into that kind of stuff).

Posted by matty, filed under Perl, Solaris Debugging. Date: February 25, 2006, 11:10 am | 1 Comment »

I recently added name resolution support to ldap-stats.pl. This was super easy to do, and only required three lines of Perl code:

### Import the required modules
use Socket;

### Convert the IP address string to an Internet address
my $ipaddr = inet_aton($index);

### Resolve the IP address to a hostname
my $host = gethostbyaddr($ipaddr, AF_INET);

Once the conversion and resolution complete, the name will be available in the $host scalar variable. Giddie up!

Posted by matty, filed under Perl. Date: October 7, 2005, 2:43 pm | No Comments »

When developing Perl scripts, it is often useful to process a range of characters or numbers. This is easily accomplished with Perl’s “..” range operator:

$ perl -e ‘foreach (1 .. 10 ) { print “$_\n”; }’
1
2
3
4
5
6
7
8
9
10

Perl seems to contain just about everything, and is definitely the Cadillac of programming lanaguages.

Posted by matty, filed under Perl. Date: October 7, 2005, 2:29 pm | No Comments »

While messing around with Perl I ran into the following error:

$ perl -e ‘use Time::Local print (localtime)[5] + 1900;’
syntax error at -e line 1, near “)[”
Execution of -e aborted due to compilation errors.

I asked Perl guru Peter Marschall if he knew what was wrong with this statement, and Peter mentioned that ‘print’ is trying to use the ‘(’ and ‘)’ to enclose it’s argument list (which is not applicable here). Since I am still learning Perl, I don’t feel bad making mistakes (I am learning lots!)!

Posted by matty, filed under Perl. Date: September 26, 2005, 2:11 pm | No Comments »

While updating some Perl code I wrote quite some time back, I came across the following:

my ($sec, $min, $hour, $day, $month, $year, $wd, $day, $dst) = localtime(time);
print $year + 1900 . “\n”;

This code is rather wasteful, especially when the program only needs the year. A much simpler solution is to put the localtime() result into array context, and index into it:

$year = (localtime)[5] + 1900;
print “$year\n”;

I am currently reading two Perl books, and it amazes me just how versatile Perl is!

Posted by matty, filed under Perl. Date: September 23, 2005, 8:51 pm | 5 Comments »

« Previous Entries