File Coverage

blib/lib/Net/NIS.pm
Criterion Covered Total %
statement 44 98 44.9
branch 5 38 13.1
condition 1 6 16.6
subroutine 13 22 59.0
pod n/a
total 63 164 38.4


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # Net::NIS::Tied - interface to YP^H^HNIS
4             #
5             # $Id: 104 $
6             #
7             package Net::NIS;
8              
9 6     6   201096 use strict;
  6         18  
  6         505  
10 6     6   172 use 5.006;
  6         34  
  6         224  
11 6     6   43 use warnings; # Sigh, only available in 5.6 and above
  6         16  
  6         194  
12 6     6   92 use Carp;
  6         12  
  6         1000  
13              
14             ###############################################################################
15             # BEGIN user-configurable section
16              
17             # Linux and Solaris seem to have this file. It contains a number of
18             # lines, each with a key/value pair (separated by spaces).
19             my $Nicknames_File = '/var/yp/nicknames';
20              
21             # For those systems who don't have a nicknames file, here are some
22             # reasonable defaults.
23             my %Nicknames_Default =
24             (
25             passwd => 'passwd.byname',
26             group => 'group.byname',
27             networks => 'networks.byaddr',
28             hosts => 'hosts.byname',
29             protocols => 'protocols.bynumber',
30             services => 'services.byname',
31             aliases => 'mail.aliases',
32             ethers => 'ethers.byname',
33             );
34              
35              
36             # Special case: this magic map acts as a front end to yp_master()
37             our $Magic_ypmaster_map = '__YPMASTER';
38              
39             # Ouch. It really hurts to enumerate these here, manually, instead of
40             # somehow relying on the autogenerated list made by h2xs. But at least
41             # we have a test (t/15yperr_num.t) that should catch inconsistencies.
42             #
43             # Please be sure to keep these in numerical order, starting with 0. If
44             # There are ever gaps in the YPERR_xxx sequence, or duplicates, we will
45             # have to rethink this approach. But until then, let's not worry.
46 6     6   42 use vars qw(@YPERRS);
  6         12  
  6         1027  
47             @YPERRS = map { "YPERR_$_" }
48             qw(
49             SUCCESS
50             BADARGS
51             RPC
52             DOMAIN
53             MAP
54             KEY
55             YPERR
56             RESRC
57             NOMORE
58             PMAP
59             YPBIND
60             YPSERV
61             NODOM
62             BADDB
63             VERS
64             ACCESS
65             BUSY
66             );
67              
68             # Magic! This variable is magically tied to a global in our .xs which
69             # keeps track of the status returned from the last yp_xxx() function.
70             #
71             # This variable is exported by default. I'm not too happy with its
72             # name, but it seems like the best out of all the possibilities I
73             # considered. The primary benefit is that, given the fixed nature
74             # of the YPERR_xxx constant names, '$yperr' will be easier for someone
75             # to remember than $yp_status, $ypstatus, $yp_err, or anything like that.
76             #
77             # Any other suggestions, before it's too late to change it?
78 6     6   77 use vars qw($yperr);
  6         18  
  6         301  
79              
80             # END user-configurable section
81             ###############################################################################
82              
83 6     6   29 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $PKG);
  6         11  
  6         8665  
84              
85             require Exporter;
86             require DynaLoader;
87             require AutoLoader;
88              
89             @ISA = qw(Exporter DynaLoader);
90              
91             %EXPORT_TAGS = ( all => [ '$yperr', @YPERRS ] );
92             @EXPORT_OK = ( '$yperr', @YPERRS );
93             @EXPORT = ( '$yperr' );
94              
95             $VERSION = '0.44';
96              
97             $PKG = __PACKAGE__; # For interpolating into error messages
98              
99             #############
100             # DESTROY # Not really used, but needed so AUTOLOAD doesn't trap it
101             #############
102 0     0   0 sub DESTROY {}
103              
104             ##############
105             # AUTOLOAD # from h2xs
106             ##############
107             sub AUTOLOAD {
108             # This AUTOLOAD is used to 'autoload' constants from the constant()
109             # XS function. If a constant is not found then control is passed
110             # to the AUTOLOAD in AutoLoader.
111              
112 19     19   7915 my $constname;
113 6     6   48 use vars qw($AUTOLOAD);
  6         17  
  6         2274  
114 19         96 ($constname = $AUTOLOAD) =~ s/.*:://;
115 19 50       54 croak "& not defined" if $constname eq 'constant';
116 19 50       102 my $val = constant($constname, @_ ? $_[0] : 0);
117 19 50       133 if ($! != 0) {
118 0 0       0 if ($! =~ /Invalid/) {
119 0 0       0 if ($constname =~ /^YP/) {
120 0         0 croak "No such constant, ${PKG}::$constname";
121             } else {
122 0         0 croak "No such function, ${PKG}::$constname()";
123             }
124             }
125             else {
126 0         0 croak "Your vendor has not defined Net::NIS macro $constname";
127             }
128             }
129              
130             {
131 6     6   40 no strict 'refs';
  6         11  
  6         1898  
  19         20  
132 19     19   125 *$AUTOLOAD = sub { $val };
  19         3834  
133             }
134 19         82 goto &$AUTOLOAD;
135             }
136              
137             bootstrap Net::NIS $VERSION;
138              
139             # Magic: The $yperr variable will now have the YP status, int & string form
140             _yp_tie_status ($yperr);
141              
142              
143             ######################
144             # _expand_nickname # Look for a string in the /var/yp/nicknames file
145             ######################
146             sub _expand_nickname($) {
147 0     0   0 my $map = shift;
148              
149 6     6   85 use vars '%nickname';
  6         15  
  6         8604  
150              
151             # First time through? Read the nicknames file, or initialize to a
152             # reasonable default (hardcoded above).
153 0 0       0 if (keys %nickname == 0) {
154 0 0       0 if (open NICKNAMES, '<', $Nicknames_File) {
155 0         0 while (defined (my $line = )) {
156 0 0       0 $line =~ /^\s*(\S+)\s+(\S+)$/
157             or next;
158 0         0 $nickname{$1} = $2;
159             }
160 0         0 close NICKNAMES;
161             } else {
162             # No nicknames file
163 0         0 %nickname = %Nicknames_Default;
164             }
165             }
166              
167             # If there's a nickname defined for this map, return it... otherwise,
168             # the map name itself.
169 0 0       0 $nickname{$map} || $map;
170             }
171              
172              
173             #############
174             # TIEHASH # establish the relationship between a hash and a YP map.
175             #############
176             sub TIEHASH {
177 1     1   504 my $class = shift;
178              
179             # Second argument must be a map name (passwd, mail.aliases, etc)
180 1 50       4 my $map = shift
181             or croak "Usage: tie \%hash, $PKG, 'MAP NAME' [, 'DOMAIN' ]\n";
182              
183             # Third argument (optional) is the NIS domain. If unset, bail out
184             # now, setting error to NODOM ("Local domain name not set"). Otherwise,
185             # if we try the yp_match, it fails with the less-than-helpful BADARGS.
186             my $domain = shift || yp_get_default_domain()
187 1 50 33     31 or do {
188 1         6 $yperr = YPERR_NODOM();
189 1         3 return undef;
190             };
191              
192             # Check validity of map name.
193             # As a special case, use '__YPMASTER' to act as a front end to yp_master()
194 0           $map = _expand_nickname($map);
195 0 0         unless ($map eq $Magic_ypmaster_map) {
196 0 0         if (! Net::NIS::yp_master( $domain, $map )) {
197 0           $yperr = YPERR_MAP();
198 0           return undef;
199             }
200             }
201              
202             # All OK. Force $yperr to OK, and return a blessed object
203 0           $yperr = YPERR_SUCCESS();
204 0           bless { map => $map, domain => $domain }, $class;
205             }
206              
207              
208             ###########
209             # FETCH # read-only access to a key.
210             ###########
211             sub FETCH {
212 0     0     my $self = shift;
213 0           my $key = shift;
214              
215             # Special case for magic yp_master map
216 0 0         if ($self->{map} eq $Magic_ypmaster_map) {
217 0           return Net::NIS::yp_master($self->{domain}, $key);
218             }
219              
220             # Have we slurped in all keys using yp_all() ? Look up our key therein.
221 0 0 0       if (exists $self->{_alldata} && exists $self->{_alldata}->{$key}) {
222 0           return $self->{_alldata}->{$key};
223             }
224              
225             # Haven't called yp_all(), or key not found there. Do a real YP lookup.
226 0 0         if (defined (my $val = yp_match($self->{domain}, $self->{map}, $key))) {
227 0           return $val;
228             }
229              
230             # Error... is it 'no such key in map'? That's OK
231 0 0         if ($yperr == YPERR_KEY()) {
232 0           return undef;
233             }
234              
235             # Any other error: fatal
236 0           croak sprintf("Unable to find '%s' in %s. Reason: %s",
237             $key, $self->{map}, $yperr);
238             }
239              
240              
241             ############
242             # EXISTS # Does a key exist? This isn't cheap, it still incurs a yp_match
243             ############
244             sub EXISTS {
245 0     0     my $self = shift;
246              
247 0           defined $self->FETCH (@_);
248             }
249              
250              
251             ##############
252             # FIRSTKEY # For iterating with each() or keys()
253             ##############
254             #
255             # Important note: this uses the yp_all() mechanism to slurp in a complete
256             # hash containing all the key/value pairs. It is delayed until here,
257             # because our caller could simply want to perform lookups (via FETCH)
258             # without iterating over all keys.
259             #
260             sub FIRSTKEY {
261 0     0     my $self = shift;
262              
263             # Special case when called with magic yp_master key
264 0 0         if ($self->{map} eq $Magic_ypmaster_map) {
265 0           my %master;
266              
267 0           for my $map (Net::NIS::yp_maplist( $self->{domain} )) {
268 0           $master{$map} = Net::NIS::yp_master( $self->{domain},$map );
269             }
270 0           $self->{_alldata} = \%master;
271             }
272             else {
273             # Each time we get called, slurp across again... just in case any
274             # values have changed. This is suboptimal: in effect, we're keeping
275             # a cache around for who-knows-how-long. Suggestions welcome for
276             # improving it (perhaps keeping a {_last_updated} time??)
277 0           $self->{_alldata} = yp_all ($self->{domain}, $self->{map});
278              
279             # Returned value must be a hash. If it isn't, something bad happened.
280 0 0         if (ref $self->{_alldata} ne 'HASH') {
281 0           croak sprintf("No such map '%s'. Reason: %s",
282             $self->{map}, $yperr);
283             }
284             }
285              
286             # Reset the each() operator, and let it do the rest.
287 0           my $trashme = keys %{ $self->{_alldata} };
  0            
288 0           return scalar each %{ $self->{_alldata} };
  0            
289             }
290              
291             #############
292             # NEXTKEY # no-brainer, just lets each() do the work on our internal hash
293             #############
294             sub NEXTKEY {
295 0     0     my $self = shift;
296              
297 0           return each %{ $self->{_alldata} };
  0            
298             }
299              
300              
301             # ------NO WRITE ACCESS ALLOWED------
302             sub _read_only(@) {
303 0     0     croak "$PKG provides read-only access";
304             }
305              
306 0     0     sub STORE { _read_only(@_); }
307 0     0     sub DELETE { _read_only(@_); }
308              
309             ###############################################################################
310              
311             1;
312              
313             __END__