/usr/lib/slack/Slack.pm is in slack 1:0.15.2-9.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | # $Id: Slack.pm 189 2008-04-21 00:52:56Z sundell $
# vim:sw=2
# vim600:fdm=marker
# Copyright (C) 2004-2008 Alan Sundell <alan@sundell.net>
# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY.
# See the file COPYING for details.
package Slack;
require 5.006;
use strict;
use Carp qw(cluck confess croak);
use File::Find;
use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG);
use base qw(Exporter);
use vars qw($VERSION @EXPORT @EXPORT_OK $DEFAULT_CONFIG_FILE);
$VERSION = '0.15.2';
@EXPORT = qw();
@EXPORT_OK = qw();
$DEFAULT_CONFIG_FILE = '/etc/slack.conf';
my $term;
my @default_options = (
'help|h|?',
'version',
'verbose|v+',
'quiet',
'config|C=s',
'source|s=s',
'rsh|e=s',
'cache|c=s',
'stage|t=s',
'root|r=s',
'dry-run|n',
'backup|b',
'backup-dir=s',
'hostname|H=s',
);
sub default_usage ($) {
my ($synopsis) = @_;
return <<EOF;
Usage: $synopsis
Options:
-h, -?, --help
Print this help message and exit.
--version
Print the version number and exit.
-v, --verbose
Be verbose.
--quiet
Don't be verbose (Overrides previous uses of --verbose)
-C, --config FILE
Use this config file instead of '$DEFAULT_CONFIG_FILE'.
-s, --source DIR
Source for slack files
-e, --rsh COMMAND
Remote shell for rsync
-c, --cache DIR
Local cache directory for slack files
-t, --stage DIR
Local staging directory for slack files
-r, --root DIR
Root destination for slack files
-n, --dry-run
Don't write any files to disk -- just report what would have been done.
-b, --backup
Make backups of existing files in ROOT that are overwritten.
--backup-dir DIR
Put backups into this directory.
-H, --hostname HOST
Pretend to be running on HOST, instead of the name given by
gethostname(2).
EOF
}
# Read options from a config file. Arguments:
# file => config file to read
# opthash => hashref in which to store the options
# verbose => whether to be verbose
sub read_config (%) {
my %arg = @_;
my ($config_fh);
local $_;
confess "Slack::read_config: no config file given"
if not defined $arg{file};
$arg{opthash} = {}
if not defined $arg{opthash};
open($config_fh, '<', $arg{file})
or confess "Could not open config file '$arg{file}': $!";
# Make this into a hash so we can quickly see if we're looking
# for a particular option
my %looking_for;
if (ref $arg{options} eq 'ARRAY') {
%looking_for = map { $_ => 1 } @{$arg{options}};
}
while(<$config_fh>) {
chomp;
s/#.*//; # delete comments
s/\s+$//; # delete trailing spaces
next if m/^$/; # skip empty lines
if (m/^[A-Z_]+=\S+/) {
my ($key, $value) = split(/=/, $_, 2);
$key =~ tr/A-Z_/a-z-/;
# Only set options we're looking for
next if (%looking_for and not $looking_for{$key});
# Don't set options that are already set
next if defined $arg{opthash}->{$key};
$arg{verbose} and print STDERR "Slack::read_config: Setting '$key' to '$value'\n";
$arg{opthash}->{$key} = $value;
} else {
cluck "Slack::read_config: Garbage line '$_' in '$arg{file}' line $. ignored";
}
}
close($config_fh)
or confess "Slack::read_config: Could not close config file: $!";
# The verbose option is treated specially in so many places that
# we need to make sure it's defined.
$arg{opthash}->{verbose} ||= 0;
return $arg{opthash};
}
# Just get the exit code from a command that failed.
# croaks if anything weird happened.
sub get_system_exit (@) {
my @command = @_;
if (WIFEXITED($?)) {
my $exit = WEXITSTATUS($?);
return $exit if $exit;
}
if (WIFSIGNALED($?)) {
my $sig = WTERMSIG($?);
croak "'@command' caught sig $sig";
}
if ($!) {
croak "Syserr on system '@command': $!";
}
croak "Unknown error on '@command'";
}
sub check_system_exit (@) {
my @command = @_;
my $exit = get_system_exit(@command);
# Exit is non-zero if get_system_exit() didn't croak.
croak "'@command' exited $exit";
}
# get options from the command line and the config file
# Arguments
# opthash => hashref in which to store options
# usage => usage statement
# required_options => arrayref of options to require -- an exception
# will be thrown if these options are not defined
# command_line_hash => store options specified on the command line here
sub get_options {
my %arg = @_;
use Getopt::Long;
Getopt::Long::Configure('bundling');
if (not defined $arg{opthash}) {
$arg{opthash} = {};
}
if (not defined $arg{usage}) {
$arg{usage} = default_usage($0);
}
my @extra_options = (); # extra arguments to getoptions
if (defined $arg{command_line_options}) {
@extra_options = @{$arg{command_line_options}};
}
# Make a --quiet function that turns off verbosity
$arg{opthash}->{quiet} = sub { $arg{opthash}->{verbose} = 0; };
unless (GetOptions($arg{opthash},
@default_options,
@extra_options,
)) {
print STDERR $arg{usage};
exit 1;
}
if ($arg{opthash}->{help}) {
print $arg{usage};
exit 0;
}
if ($arg{opthash}->{version}) {
print "slack version $VERSION\n";
exit 0;
}
# Get rid of the quiet handler
delete $arg{opthash}->{quiet};
# If we've been given a hashref, save our options there at this
# stage, so the caller can see what was passed on the command line.
# Unfortunately, perl has no .replace function, so we iterate.
if (ref $arg{command_line_hash} eq 'HASH') {
while (my ($k, $v) = each %{$arg{opthash}}) {
$arg{command_line_hash}->{$k} = $v;
}
}
# Use the default config file
if (not defined $arg{opthash}->{config}) {
$arg{opthash}->{config} = $DEFAULT_CONFIG_FILE;
}
# We need to decide whether to be verbose about reading the config file
# Currently we just do it if global verbosity > 2
my $verbose_config = 0;
if (defined $arg{opthash}->{verbose}
and $arg{opthash}->{verbose} > 2) {
$verbose_config = 1;
}
# Read options from the config file, passing along the options we've
# gotten so far
read_config(
file => $arg{opthash}->{config},
opthash => $arg{opthash},
verbose => $verbose_config,
);
# The "verbose" option gets compared a lot and needs to be defined
$arg{opthash}->{verbose} ||= 0;
# The "hostname" option is set specially if it's not defined
if (not defined $arg{opthash}->{hostname}) {
use Sys::Hostname;
$arg{opthash}->{hostname} = hostname;
}
# We can require some options to be set
if (ref $arg{required_options} eq 'ARRAY') {
for my $option (@{$arg{required_options}}) {
if (not defined $arg{opthash}->{$option}) {
croak "Required option '$option' not given on command line or specified in config file!\n";
}
}
}
return $arg{opthash};
}
sub prompt ($) {
my ($prompt) = @_;
if (not defined $term) {
require Term::ReadLine;
$term = new Term::ReadLine 'slack'
}
$term->readline($prompt);
}
# Calls the callback on absolute pathnames of files in the source directory,
# and also on names of directories that don't exist in the destination
# directory (i.e. where $source/foo exists but $destination/foo does not).
sub find_files_to_install ($$$) {
my ($source, $destination, $callback) = @_;
return find ({
wanted => sub {
if (-l or not -d _) {
# Copy all files, links, etc
my $file = $File::Find::name;
&$callback($file);
} elsif (-d _) {
# For directories, we only want to copy it if it doesn't
# exist in the destination yet.
my $dir = $File::Find::name;
# We know the root directory will exist (we make it above),
# so skip the base of the source
(my $short_source = $source) =~ s#/$##;
return if $dir eq $short_source;
# Strip the $source from the path,
# so we can build the destination dir from it.
my $subdir = $dir;
($subdir =~ s#^$source##)
or croak "sub failed: $source|$subdir";
if (not -d "$destination/$subdir") {
&$callback($dir);
}
}
}
},
$source,
);
}
# Runs rsync with the necessary redirection to its filehandles
sub wrap_rsync (@) {
my @command = @_;
my ($pid);
if ($pid = fork) {
# Parent
} elsif (defined $pid) {
# Child
open(STDIN, "<", "/dev/null")
or die "Could not redirect STDIN from /dev/null\n";
# This redirection is necessary because rsync sends
# verbose output to STDOUT
open(STDOUT, ">&STDERR")
or die "Could not redirect STDOUT to STDERR\n";
exec(@command);
die "Could not exec '@command': $!\n";
} else {
die "Could not fork: $!\n";
}
my $kid = waitpid($pid, 0);
if ($kid != $pid) {
die "waitpid returned $kid\n";
} elsif ($?) {
Slack::check_system_exit(@command);
}
}
# Runs rsync with the necessary redirection to its filehandles, but also
# returns an FH to stdin and a PID.
sub wrap_rsync_fh (@) {
my @command = @_;
my ($fh, $pid);
if ($pid = open($fh, "|-")) {
# Parent
} elsif (defined $pid) {
# Child
# This redirection is necessary because rsync sends
# verbose output to STDOUT
open(STDOUT, ">&STDERR")
or die "Could not redirect STDOUT to STDERR\n";
exec(@command);
die "Could not exec '@command': $!\n";
} else {
die "Could not fork: $!\n";
}
return($fh, $pid);
}
1;
|