Strip redundant Emacs mode markers from Perl scripts.
[distorted-backup] / snap.in
CommitLineData
99248ed2 1#! @PERL@
99248ed2
MW
2###
3### Create and remove snapshots of block devices
4###
5### (c) 2011 Mark Wooding
6###
7
8###----- Licensing notice ---------------------------------------------------
9###
10### This program is free software; you can redistribute it and/or modify
11### it under the terms of the GNU General Public License as published by
12### the Free Software Foundation; either version 2 of the License, or
13### (at your option) any later version.
14###
15### This program is distributed in the hope that it will be useful,
16### but WITHOUT ANY WARRANTY; without even the implied warranty of
17### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18### GNU General Public License for more details.
19###
20### You should have received a copy of the GNU General Public License
21### along with this program; if not, write to the Free Software Foundation,
22### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24use Getopt::Long qw(:config gnu_compat bundling no_ignore_case);
25use Text::ParseWords;
26
27our $VERSION = "@VERSION@";
28
29our %C = ( etc => "@sysconfdir@",
30 sbin => "@sbindir@",
31 snap => "@snaplibexecdir@" );
32
33###--------------------------------------------------------------------------
34### Utilities.
35
36(our $QUIS = $0) =~ s:^.*/::;
37sub whine ($) { my ($msg) = @_; print STDERR "$QUIS: $msg\n"; }
38sub fail ($) { my ($msg) = @_; whine $msg; exit $! || ($? >> 8) || 255; }
39
40###--------------------------------------------------------------------------
41### Parse command line.
42
43our $USAGE = "usage: $QUIS [-u] [-c FILE] DEVICE [KEY=VALUE ...]";
44sub version { print "$QUIS, version $VERSION\n"; }
45sub help {
46 print <<EOF;
47$USAGE
48
49Options:
50 -h, --help Show this help text.
51 -v, --version Show the program version number.
52 -c, --config=FILE Use configuration FILE, not $CONF.
53 -n, --no-act Don't actually do anything; show what would be done.
54 -u, --unsnap Remove a snapshot taken earlier.
55EOF
56}
57
58our $CONF = "$C{etc}/snaptab";
59our $OP = "snap";
60our $NOACT = 0;
61GetOptions('help|h|?' => sub { version; help; exit; },
62 'version|v' => sub { version; exit; },
63 'config-file|c=s' => \$CONF,
64 'no-act|n' => \$NOACT,
65 'unsnap|u' => sub { $OP = "unsnap"; })
66 and @ARGV >= 1
67 or do { print STDERR $USAGE, "\n"; exit 1; };
68
69our $DEV = shift;
70our $TYPE = undef;
71
72###--------------------------------------------------------------------------
73### Parse the configuration file.
74
75open CF, "<", $CONF or fail "open config ($CONF): $!";
76our @KV = ();
77our %DEF = ();
78while (my $line = <CF>) {
79 chomp $line;
80 while ($line =~ /\\\s*$/) {
81 chomp (my $more = <CF>);
82 $line =~ s/\\\s*$/$more/;
83 }
84 next if $line =~ /^\s*(\#|$)/;
85 my ($dev, $type, @opts) = shellwords $line;
86 my @nopts = ();
87 for my $i (@opts) {
88 if ($i !~ /^\*\.(.+)$/) { push @nopts, $i; next; }
89 my $ty = $1;
90 for my $o (@{$DEF{$ty}}) {
91 $o =~ /^([^=]+)=(.*)$/;
92 my ($k, $v) = ($1, $2);
93 ($k, $ty) = ($1, $2) if $k =~ /^(.+)\.([^.]+)/;
94 push @nopts, "$k.$ty=$v";
95 }
96 }
97 @opts = @nopts;
98 if ($dev eq "*") { push @{$DEF{$type}}, @opts; }
99 elsif ($dev eq $DEV) { push @KV, "type=$type", @{$DEF{$type}}, @opts; }
100}
101close CF or fail "close config ($CONF): $!";
102
103###--------------------------------------------------------------------------
104### Pick out the winning options.
105
106our @OPT = ();
107my $seen = ();
108
109for my $i (reverse @KV, "op=$OP", @ARGV) {
110 $i =~ /^([^=]+)=(.*)$/ or fail "malformed option `$i': missing `='";
111 my ($k, $v) = ($1, $2);
112 unless (exists $seen{$k}) {
113 $seen{$k} = 1;
114 if ($k eq "type") { $TYPE = $v; }
115 else { push @OPT, "$k=$v"; }
116 }
117}
118
119defined $TYPE or fail "no snapshot type for device `$DEV'";
120@OPT = reverse @OPT;
121
122###--------------------------------------------------------------------------
123### Invoke the type-specific handler.
124
125## Fix up the path, to make sure our tools are available.
126my $path = $ENV{PATH};
127my %path = map { $_ => 1 } split /:/, $path;
128for my $p (qw( /bin /sbin /usr/bin /usr/sbin ), $C{sbin}) {
129 $path = "$p:$path" unless exists $path{$p};
130}
131$ENV{PATH} = $path;
132
133## Prepare the arguments.
134my @args = ("$C{snap}/snap.$TYPE", $DEV, @OPT);
135
136## Do the job.
137if ($NOACT) {
138 whine "run " . join(" ",
139 map { "`$_'" }
140 grep { s/'/\\'/g; 1 }
141 (my @x = @args));
142} else {
143 exec @args;
144 fail "exec (snap.$TYPE): $!";
145}
146
147###----- That's all, folks --------------------------------------------------
148
149exit 0;