Cover V12, I05

Article

may2003.tar

Questions and Answers

Amy Rich

Q I'm using the version of Perl that came with Solaris 8. I tried to install a new Perl module, but the install failed because the Perl that Sun shipped was built with Sun's C compiler. I'm not about to fork over a good chunk of money to buy a license when I can get gcc for free. But, do I need to recompile Perl from scratch, or is there a way to work around this issue?

A Sun's C complier does have some benefits over gcc on the SPARC platform, but if you don't want to purchase the license, there appears to be a Perl module on CPAN that will allow you to use Sun's existing Perl with gcc:

http://cpan.org/modules/by-authors/id/ABURLISON/
Solaris/PerlGcc version 1.1
============================
perlgcc - Compile perl modules using gcc.

The perl 5.005_03 and 5.6.1 shipped with Solaris 8, 9 and 10 were built with the Forte compilers, and therefore assume that any add-on modules will also be built with the Forte compiler. The perlgcc command will allow gcc to be used to compile add-on modules for use with the perl versions shipped with Solaris.

INSTALLATION

$ perl Makefile.PL; make install
USAGE

$ perlgcc Makefile.PL; make install

$ perlgcc -MCPAN -e shell
Q I'm running BIND 9 and have a problem with my secondary server not being able to successfully transfer a zone from the primary. I can see that the primary server is allowing the transfer, but on the secondary server I get the following error messages:

named[4175]: dumping master file: /etc/namedb/tmp-XXXXIt5Dc3: open:
permission denied

named[5327]: transfer of 'my.domain/IN' from 192.168.1.1#53: failed
while receiving responses: permission denied

named[5327]: transfer of 'my.domain/IN' from 192.168.1.1#53: end of
transfer
I'm stumped as to what the issue is, since the named.conf on both machines looks just fine as far as I can tell. The primary server (192.168.1.1) has:

zone "my.domain" {
   type master;
   file "my.domain";
   allow-transfer {
         192.168.1.2;
   };
};
The secondary server (192.168.1.2) has:

zone "my.domain" {
   type slave;
   file "my.domain";
   masters {
         192.168.1.1;
   };
};
Any pointers would be greatly appreciated.

A Your issue is with the file/directory permissions on the secondary server. Presumably you've set up bind to run as a non-root user. This is a good idea for security purposes, but you need to make sure that this non-root user can write to the directory in which your zone files reside. If you change the permissions of /etc/namedb so that your bind user can create files (and you make sure that the bind user also owns the existing zone files in that directory), the problem reported by your error messages should be solved.

Q We need to do a bunch of maintenance work on a Sun 220R running Solaris 8, and I want to change around the disk controller hardware without incrementing the controller numbers. Is there a way to make it "forget" that it previously allocated a controller number to another I/O slot? I want to continue using c0, c1, c2, and c3. I'm trying to avoid winding up with things like c4, c5, c6, and c7.

A If the boot disk does not hang off the specified controller, you can do the following:

  • Remove the /etc/path_to_inst files:
mv /etc/path_to_inst /etc/path_to_inst.orig
rm /etc/path_to_inst.old
  • Remove all the devices except the boot device in both /dev/dsk and /dev/rdsk (I'll assume your boot disk is at c0):
cd /dev/dsk
rm c1* c2* c3* c4* (etc)
cd /dev/rdsk
rm c1* c2* c3* c4* (etc)
  • Make sure to record the device name of the boot disk if it's under Volume Manager. If you look in /etc/system, there should be a line that starts with "rootdev:".
  • Shut down the system and boot interactively:
init 0
boot -ar
Since /etc/path_to_inst does not exist, the interactive boot will ask you for the location and name of all the important system files. You should be able to accept the default for all of these files (just hit return) except when it asks you if you want to rebuild /etc/path_to_inst. Here you should type Y and hit return. If you have the boot disk under Volume Manager, do not take the default when asked for the physical root device, instead, enter the device name you recorded from /etc/system.

If the boot disk is attached to the controller you want to change, then you can boot from the CDROM and then make changes to said boot disk:

  • boot cdrom -sw
  • mount /dev/dsk/c0t3d0s0 /a
  • cd /a/dev/dsk
  • rm c*
  • cd /a/dev/rdsk
  • rm c*
  • cd /
  • devfsadm -r /a
  • cd /
  • umount /a
  • reboot
  • You may also find Sun Infodoc ID 13774 useful if you have a SPARC Storage Array.

    Q I'm a C programmer trying to write a Perl program where I push an element onto a multidimensional array, but I can't seem to get this to work correctly. Here's the code I'm using:

    $myarray[0][0] = 'hello';
    push $myarray[0], 'world';
    
    I'm trying to wind up with:

    $myarray[0][1] = 'world';
    
    Obviously, I'm not doing this right, but Perl must have something as simple as a multidimensional array. Any hints on how I can get my code working?

    A Perl is a bit different from C, as I'm sure you've discovered. In Perl, $array[0] is not an array, but an array reference. An important note to remember from the Perl documentation: "Perl does no implicit referencing or dereferencing. When a scalar is holding a reference, it always behaves as a simple scalar. It doesn't magically start being an array or hash or subroutine; you have to tell it explicitly to do so, by dereferencing it." For information on Perl's use of references, do:

    perldoc perlref
    perldoc perlreftut
    
    The section most pertinent to your question can be found in the Perl reference tutorial:

    Let's see a quick example of how all this is useful.

    First, remember that [1, 2, 3] makes an anonymous array containing (1, 2, 3), and gives you a reference to that array.

    Now think about

    @a = ( [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
    );

    @a is an array with three elements, and each one is a reference to another array.

    $a[1] is one of these references. It refers to an array, the array containing (4, 5, 6), and because it is a reference to an array, USE RULE 2 says that we can write $a[1]->[2] to get the third element from that array. $a[1]->[2] is the 6. Similarly, $a[0]->[1] is the 2. What we have here is like a two-dimensional array; you can write $a[ROW]->[COLUMN] to get or set the element in any row and any column of the array.

    The notation still looks a little cumbersome, so there's one more abbreviation:

    Arrow Rule In between two subscripts, the arrow is optional.

    Instead of $a[1]->[2], we can write $a[1][2]; it means the same thing. Instead of $a[0]->[1], we can write $a[0][1]; it means the same thing.

    Now it really looks like two-dimensional arrays!

    You can see why the arrows are important. Without them, we would have had to write ${$a[1]}[2] instead of $a[1][2]. For three-dimensional arrays, they let us write $x[2][3][5] instead of the unreadable ${${$x[2]}[3]}[5].

    Anywhere you'd put an identifier as part of a variable or subroutine name, you can replace the identifier with a block returning a reference of the correct type:

    $myarray[0][0] = 'hello';
    push @{$myarray[0]}, 'world';
    
    You can print out your "hello world" statement by using the same notation as the push:

    print "myarray == @{$myarray[0]}.\n";
    
    Q I'm running Solaris 8 and Sun's stock sendmail (8.11.6). I have about 30 lines of denied addresses and IPs in /etc/mail/access. The problem is that, because my connection to the Internet is rather poor, a good chunk of my mail goes through two lower-priority MX hosts on which I do not have administrative control. Unfortunately, this means that all of the mail that gets blocked on Connect to my machine now gets through.

    Is there any way to get around this? Is there some sort of per-host (or domain) way to apply access lists? If so, then I can request that the admins of the MX hosts just use this setting to apply my access rules to my mail coming through their machines?

    A Unfortunately, access rules apply to all incoming mail and there is no way to apply rules on a per-host or domain basis. This would be quite useful for people who are doing virtual hosting of many domains, though. In your case, it might be more trouble than it's worth if you're frequently updating your access list. You'd not only have to modify your own, but then send a copy out to all of your MX hosts as well.

    Though you won't be able to reject on Connect, you could write a ruleset to bounce mail back based on the received headers. Below lies some code from Greg Shapiro at Sendmail, Inc. that you could add to your mc file (note that the syntax is different for the current version of sendmail, 8.12).

    Replace the hosts in the MXers class, C{MXers}, with any hosts that MX for you. Remember to generate a new /etc/mail/sendmail.cf from the mc file and HUP the sendmail daemon.

    FEATURE('access_db')dnl
    
    LOCAL_CONFIG
    HReceived: $>+CheckRecvd
    C{MXers}your.first.mxhost your.second.mxhost
    
    LOCAL_RULESETS
    SCheckRecvd
    Rfrom $* ( $+ [ $+ ] ) by $={MXers} $*  $: <?> $2 $| $3
    R<?> $+ $| $+           $: $>LookUpDomain <$1> <?> <$2> <+ Connect>
    R<?> <$+>               $: $>LookUpAddress <$1> <?> <> <+ Connect>
    R<?> $*                 $@ok        
    R<$={Accept}> <$*>      $@ $1        
    R<<TMPF>> $*            $#error $@ tempfail $: "450 Temporary lookup failure"
    R<REJECT> $*            $#error $@ 5.7.1 $: "550 Access denied"
    R<DISCARD> <$*>         $#discard $: discard
    R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4
    R<ERROR:$+> $*          $#error $: $1
    R<$+> $*                $#error $: $1
    
    If the message came to your machine from one of the machines listed in the MXers class, then the above ruleset will take the host and IP information from the previous relaying machine by parsing the Received: header. It will then check the access file with the "new" information, and reject it if necessary. I suggest that your MX hosts turn off DoubleBounceAddress if you choose to use this ruleset. Most spam you get will have forged headers and no valid address capable of accepting a bounce back.

    Q Due to a runaway program that one of our junior people was working on, we're left with a very large directory structure that has some valid data in it (which we don't want deleted), and a lot of empty directories, or directories that only contain other empty directories. These levels of nested directories are at least 20 deep in some cases, and there are thousands of top-level directories to start with. What's the best way to remove all of the directories that have no leaf nodes (a.k.a. files) somewhere along the way?

    A Find is the perfect tool for this job. Because you have nested subdirectories with no actual data (files) in them, you want to do a depth-first search and removal. Depending on your operating system, the command might be:

    find /starting/dir/name -d -type d -exec rmdir {} \;
    
    as with FreeBSD, in the case of Solaris and GNU-like versions of find:

    find /starting/dir/name -depth -type d -exec rmdir {} \;
    
    You'll almost certainly want to redirect STDERR to /dev/null since it sounds like there's a lot of "good" directories that you're going to receive errors on when you try to use rmdir.

    If, for some reason, you know all of the "bad" leafnode directories, you can also use rmdir -p for each of them. This is much more time consuming and more prone to error, though.

    Q Solaris package creation seems like a big pain. When building third-party software from source, sometimes it's easy to install into a different root and sometimes it's not. Is there any software out there that can take all or even most source bundles and make packages from them?

    A I've heard good things about Simes's PkgTools:

    http://www.bpfh.net/computing/software/pkg-tools/
    
    PkgTools requires Solaris 2.6 (or later) and Perl, and it's useful to have the Digest::MD5 Perl module.

    Amy Rich, president of the Boston-based Oceanwave Consulting, Inc. (http://www.oceanwave.com), has been a UNIX systems administrator for more than 10 years. She received a BSCS at Worcester Polytechnic Institute, and can be reached at: qna@oceanwave.com.