###
### Copyright 2000-2007 University of Illinois Board of Trustees
### All rights reserved.
###
### PSGConf::Action::MkNod - Make a device node action type for psgconf
###
### Campus Information Technologies and Educational Services
### University of Illinois at Urbana-Champaign
###
package PSGConf::Action::MkNod;
use strict;
use File::Basename;
use File::Path;
use File::stat;
use Unix::Mknod qw(major minor makedev mknod);
use Fcntl ':mode';
use PSGConf::Action::MkDir;
our @ISA = qw(PSGConf::Action::MkDir);
###############################################################################
### check method
###############################################################################
sub check
{
my ($self, $psgconf) = @_;
$self->{changed} = 1
if (! -b $self->{name} && $self->{type} eq 'b');
$self->{changed} = 1
if (! -c $self->{name} && $self->{type} eq 'c');
### check for major/minor differences
$self->{stat} = stat($self->{name});
return $self->{changed}
if (!defined $self->{stat});
$self->{changed} = 1
if (major($self->{stat}->rdev) != $self->{major} ||
minor($self->{stat}->rdev) != $self->{minor});
### check for permission differences
$self->PSGConf::Action::ChMod::check($psgconf);
### check for ownership differences
$self->PSGConf::Action::ChOwn::check($psgconf);
### check for group differences
$self->PSGConf::Action::ChGrp::check($psgconf);
return $self->{changed};
}
###############################################################################
### diff method
###############################################################################
sub diff
{
my ($self, $psgconf) = @_;
my ($mknod);
print "###############################################################################\n";
print "### DIFF FOR $self->{name}\n";
print "### (original file does not exist)\n"
if (! -e $self->{name});
print "###############################################################################\n";
if (-d $self->{name})
{
print "- directory: $self->{name}\n";
$mknod=1;
}
elsif (-l $self->{name})
{
print "- symlink: $self->{name}\n";
$mknod=1;
}
elsif (-f $self->{name})
{
print "- file: $self->{name}\n";
$mknod=1;
}
elsif (( -b $self->{name} || -c $self->{name} ) &&
((! -b $self->{name} && $self->{type} eq 'b') ||
(! -c $self->{name} && $self->{type} eq 'c')))
{
print "- wrong node type: $self->{name}\n";
$mknod=1;
}
elsif ( ! -e $self->{name} ) {
$mknod=1;
}
if (defined($self->{stat}))
{
if (major($self->{stat}->rdev) != $self->{major} ||
minor($self->{stat}->rdev) != $self->{minor})
{
printf "- wrong major/minor numbers: %04o -> %04o, %04o -> %04o\n",
major($self->{stat}->rdev),
$self->{major},
minor($self->{stat}->rdev),
$self->{minor};
$mknod=1;
}
}
print "+ mknod: $self->{name} $self->{type} $self->{major} $self->{minor}\n"
if ($mknod);
print "\n";
### check for permission differences
$self->PSGConf::Action::ChMod::diff($psgconf);
### check for ownership differences
$self->PSGConf::Action::ChOwn::diff($psgconf);
### check for group differences
$self->PSGConf::Action::ChGrp::diff($psgconf);
}
###############################################################################
### do() method
###############################################################################
sub do
{
my ($self, $psgconf) = @_;
my ($type);
### nuke pre-existing file if applicable
if ( -e $self->{name} &&
(-f $self->{name}
|| -l $self->{name}
|| ( ! -b $self->{name} && $self->{type} eq 'b')
|| ( ! -c $self->{name} && $self->{type} eq 'c')
|| (major($self->{stat}->rdev) != $self->{major})
|| (minor($self->{stat}->rdev) != $self->{minor})))
{
if (!$self->{backup})
{
rmtree($self->{name});
}
elsif (! $psgconf->save_file($self->{name}, $self->{backup}))
{
return -1;
}
}
### mknod
mkpath(dirname($self->{name}));
if ( ! -e $self->{name} ) {
$type = ($self->{type} eq 'b')? S_IFBLK: S_IFCHR;
if (mknod (
$self->{name},
$type|$self->{mode},
makedev($self->{major}, $self->{minor}))) {
warn "\t!!! mknod(\"$self->{name}\", $type|$self->{mode}, makedev($self->{major}, $self->{minor})): $!\n";
return -1;
}
}
### check for permission differences
$self->PSGConf::Action::ChMod::do($psgconf);
### check for ownership differences
$self->PSGConf::Action::ChOwn::do($psgconf);
### check for group differences
$self->PSGConf::Action::ChGrp::do($psgconf);
return 1;
}
###############################################################################
### documentation
###############################################################################
1;
__END__
=head1 NAME
PSGConf::Action::MkNod - mknod action class for PSGConf
=head1 SYNOPSIS
use PSGConf::Action::MkNod;
$psgconf->register_actions(
PSGConf::Action::MkNod->new(
'name' => '/path/to/device',
'type' => 'b|c', # block or character
'major' => number,
'minor' => number,
'mode' => file permissions,
'uid' => User ID,
'gid' => Group ID,
...
),
...
);
=head1 DESCRIPTION
The B<PSGConf::Action::MkNod> module provides a B<PSGConf> action class
for creating a block or character special file.
The B<PSGConf::Action::MkNod> class is derived from the
B<PSGConf::Action::MkDir> class, but it defines/overrides the
following methods:
=over 4
=item check()
If the file doesn't exist, is not a device, does not have the
correct permissions/major/minor then returns 1. Otherwise,
returns 0.
=item diff()
Prints a message indicating what changes will be done to the file.
=item do()
Properly creates the special file, optionally backing up the original file.
=back
In addition to the attributes supported by the B<PSGConf::Action>
class, the B<PSGConf::Action::MkNod> class supports the following
attributes:
=over 4
=item I<type>
What type of special file to create, C<b> for block, C<c> for character.
=item I<major>
What the major number is for the special file.
=item I<minor>
What the minor number is for the special file.
=item I<mode>
What the mode (in an octal number) should be for the file.
=item I<uid>
Who should own the file as in the UID.
=item I<gid>
What group should own the file as in the GID.
=item I<backup>
A boolean flag to indicate whether a backup copy of the existing file
will be saved. If enabled, existing files will be saved under their
original name but with the prefix ".<backupext>". Default is no
backup.
=back
=head1 SEE ALSO
L<perl>
L<File::stat>
L<Fcntl>
L<Unix::Mknod>
L<PSGConf>
L<PSGConf::Action::MkDir>
=cut
syntax highlighted by Code2HTML, v. 0.9.1