]> git.sur5r.net Git - bacula/rescue/blob - rescue/linux/cdrom/yaird-0.0.5/perl/LvmTab.pm
834631312ac07f1b46ae62ecc8cf59da377816ed
[bacula/rescue] / rescue / linux / cdrom / yaird-0.0.5 / perl / LvmTab.pm
1 #!perl -w
2 #
3 # LvmTab -- encapsulate LVM output
4 #   Copyright (C) 2005  Erik van Konijnenburg
5 #
6 #   This program is free software; you can redistribute it and/or modify
7 #   it under the terms of the GNU General Public License as published by
8 #   the Free Software Foundation; either version 2 of the License, or
9 #   (at your option) any later version.
10 #
11 #   This program is distributed in the hope that it will be useful,
12 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #   GNU General Public License for more details.
15 #
16 #   You should have received a copy of the GNU General Public License
17 #   along with this program; if not, write to the Free Software
18 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 #
20 # The trick here is to find all block devices that back a physical
21 # volume that is part of a volume group, where in that volume group
22 # there is a logical volume with maj:min that contains a filesystem
23 # to be mounted at boot time.  In particular, if there are two
24 # volume groups, one for OS and one for database, you don't want
25 # the modules for the database drives on your initrd image.
26 #
27 # NOTE: There seem to be newer reporting tools (vgs, lvs, pvs)
28 # that produce more flexible reports for easier grepping than with
29 # the commands used here.
30 #
31 use strict;
32 use warnings;
33 use Base;
34 use LogicalVolume;
35 use VolumeGroup;
36 use PhysicalVolume;
37 package LvmTab;
38
39
40 my $lvMap = undef;
41 my $vgMap = undef;
42 my $pvMap = undef;
43 my $lvList = undef;
44 my $vgList = undef;
45 my $pvList = undef;
46
47 sub init () {
48         if (defined ($lvMap)) {
49                 return;
50         }
51         initLvMap ();
52         initVgMap ();
53         initPvMap ();
54         $lvList = [ values %{$lvMap} ];
55         $vgList = [ values %{$vgMap} ];
56         $pvList = [ values %{$pvMap} ];
57 }
58
59 sub allLogicalVolumes () {
60         init;
61         return $lvList;
62 }
63
64 sub allVolumeGroups () {
65         init;
66         return $vgList;
67 }
68
69 sub allPhysicalVolumes () {
70         init;
71         return $pvList;
72 }
73
74 sub findLVByDevno ($) {
75         init;
76         return $lvMap->{$_[0]};
77 }
78
79 sub findVGByVgnam ($) {
80         init;
81         return $vgMap->{$_[0]};
82 }
83
84 sub findPVsByVgnam ($) {
85         my ($vgnam) = @_;
86         my $result = [];
87         for my $pv (@{allPhysicalVolumes()}) {
88                 if ($pv->vgnam() eq $vgnam) {
89                         push @{$result}, $pv;
90                 }
91         }
92         return $result;
93 }
94
95 #
96 # findPhysicalVolumePathsByLVDevno -- return a list of special file names
97 # that make up the physical volumes underlying a logical volume
98 # identified by maj:min, or undef if the devno seems not to be
99 # implemented by lvm.
100 #
101 sub findPVPathsByLVDevno ($) {
102         my ($devno) = @_;
103         my $lv = LvmTab::findLVByDevno ($devno);
104         if (! defined ($lv)) {
105                 return undef;
106         }
107         my $vgnam = $lv->vgnam();
108         if (! defined (LvmTab::findVGByVgnam($vgnam))) {
109                 Base::fatal ("unknown LVM volume group $vgnam for Logical Volume $devno");
110         }
111         my $result = [];
112         for my $pv (@{LvmTab::findPVsByVgnam ($vgnam)}) {
113                 push @{$result}, $pv->pvnam();
114         }
115         return $result;
116 }
117
118
119 # build map from devno to logical volume descriptor,
120 # built on lvdisplay.
121 #
122 # /dev/vg0/root:vg0:3:1:-1:1:2097152:256:-1:0:0:254:0
123 #
124 sub initLvMap () {
125         $lvMap = {};
126         if (! open (IN, "-|", "lvdisplay -c 2> /dev/null")) {
127                 Base::fatal ("can't run lvdisplay");
128         }
129         while (defined (my $line = <IN>)) {
130                 chomp $line;
131                 $line =~ s/^\s*//;
132                 my @fields = split (/:/, $line, 500);
133                 if ($#fields != 12) {
134                         Base::fatal ("malformed output from lvdisplay");
135                 }
136                 my $lvnam = $fields[0];
137                 my $vgnam = $fields[1];
138                 # Hide this, since lvdisplay output is inconsistent with docs.
139                 my $lvsiz = $fields[6];
140                 my $major = $fields[11];
141                 my $minor = $fields[12];
142                 if ($major !~ /^\d+$/) {
143                         Base::fatal ("malformed output (major) from lvdisplay");
144                 }
145                 if ($minor !~ /^\d+$/) {
146                         Base::fatal ("malformed output (minor) from lvdisplay");
147                 }
148                 my $devno = "$major:$minor";
149                 if (exists ($lvMap->{$devno})) {
150                         Base::fatal ("duplicate output ($devno) from lvdisplay");
151                 }
152                 $lvMap->{$devno} = LogicalVolume->new (
153                         lvnam => $lvnam,
154                         vgnam => $vgnam,
155                         devno => $devno,
156                         );
157         }
158         if (! close (IN)) {
159                 Base::fatal ("error running lvdisplay");
160         }
161 }
162
163 # build map from vgnam to volume group descriptor,
164 # built on vgdisplay.
165 #
166 #  vg0:r/w:772:-1:0:7:6:-1:0:1:1:77799424:4096: \
167 #       18994:6912:12082:MO1svc-uvVC-TFCL-qvrB-29wD-bh9K-V2e3U2
168 #
169 sub initVgMap () {
170         $vgMap = {};
171         if (! open (IN, "-|", "vgdisplay -c 2> /dev/null")) {
172                 Base::fatal ("can't run vgdisplay");
173         }
174         while (defined (my $line = <IN>)) {
175                 chomp $line;
176                 $line =~ s/^\s*//;
177                 my @fields = split (/:/, $line, 500);
178                 if ($#fields != 16) {
179                         Base::fatal ("malformed output from vgdisplay");
180                 }
181                 my ($vgnam, $vgacc, $vgstat,
182                         $vgnum, $maxlv, $curlv, $openlv,
183                         $maxlvsiz, $maxpvcnt, $curpvcnt, $actpvcnt,
184                         $vgsiz, $extsiz, $extcnt, $extalloc, $extfree,
185                         $uuid)
186                         = @fields;
187
188                 if (exists ($vgMap->{$vgnam})) {
189                         Base::fatal ("duplicate output ($vgnam) from vgdisplay");
190                 }
191                 $vgMap->{$vgnam} = VolumeGroup->new (
192                         vgnam => $vgnam,
193                         uuid => $uuid,
194                         );
195         }
196         if (! close (IN)) {
197                 Base::fatal ("error running vgdisplay");
198         }
199 }
200
201 # build map from pvnam to physical volume descriptor,
202 # built on pvdisplay.
203 #
204 #  /dev/sda3:vg0:155598848:-1:8:8:-1:4096:18994: \
205 #       12082:6912:X5hDer-dYpy-jpAB-IhXQ-44j4-kyj0-cOQkyE
206 #
207 sub initPvMap () {
208         $pvMap = {};
209         if (! open (IN, "-|", "pvdisplay -c 2> /dev/null")) {
210                 Base::fatal ("can't run pvdisplay");
211         }
212         while (defined (my $line = <IN>)) {
213                 chomp $line;
214                 $line =~ s/^\s*//;
215                 my @fields = split (/:/, $line, 500);
216                 if ($#fields != 11) {
217                         Base::fatal ("malformed output from pvdisplay");
218                 }
219                 my ($pvnam,$vgnam,$pvsiz,$pvnum,$pvstat,
220                         $pvalloc,$lvcnt,$extsiz,$extcnt,
221                         $extfree,$extalloc,$uuid)
222                         = @fields;
223
224                 if (exists ($pvMap->{$pvnam})) {
225                         Base::fatal ("duplicate output ($pvnam) from vgdisplay");
226                 }
227                 $pvMap->{$pvnam} = PhysicalVolume->new (
228                         pvnam => $pvnam,
229                         vgnam => $vgnam,
230                         uuid => $uuid,
231                         );
232         }
233         if (! close (IN)) {
234                 Base::fatal ("error running pvdisplay");
235         }
236 }
237
238 1;
239
240