3 # LvmTab -- encapsulate LVM output
4 # Copyright (C) 2005 Erik van Konijnenburg
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.
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.
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
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.
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.
48 if (defined ($lvMap)) {
54 $lvList = [ values %{$lvMap} ];
55 $vgList = [ values %{$vgMap} ];
56 $pvList = [ values %{$pvMap} ];
59 sub allLogicalVolumes () {
64 sub allVolumeGroups () {
69 sub allPhysicalVolumes () {
74 sub findLVByDevno ($) {
76 return $lvMap->{$_[0]};
79 sub findVGByVgnam ($) {
81 return $vgMap->{$_[0]};
84 sub findPVsByVgnam ($) {
87 for my $pv (@{allPhysicalVolumes()}) {
88 if ($pv->vgnam() eq $vgnam) {
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
101 sub findPVPathsByLVDevno ($) {
103 my $lv = LvmTab::findLVByDevno ($devno);
104 if (! defined ($lv)) {
107 my $vgnam = $lv->vgnam();
108 if (! defined (LvmTab::findVGByVgnam($vgnam))) {
109 Base::fatal ("unknown LVM volume group $vgnam for Logical Volume $devno");
112 for my $pv (@{LvmTab::findPVsByVgnam ($vgnam)}) {
113 push @{$result}, $pv->pvnam();
119 # build map from devno to logical volume descriptor,
120 # built on lvdisplay.
122 # /dev/vg0/root:vg0:3:1:-1:1:2097152:256:-1:0:0:254:0
126 if (! open (IN, "-|", "lvdisplay -c 2> /dev/null")) {
127 Base::fatal ("can't run lvdisplay");
129 while (defined (my $line = <IN>)) {
132 my @fields = split (/:/, $line, 500);
133 if ($#fields != 12) {
134 Base::fatal ("malformed output from lvdisplay");
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");
145 if ($minor !~ /^\d+$/) {
146 Base::fatal ("malformed output (minor) from lvdisplay");
148 my $devno = "$major:$minor";
149 if (exists ($lvMap->{$devno})) {
150 Base::fatal ("duplicate output ($devno) from lvdisplay");
152 $lvMap->{$devno} = LogicalVolume->new (
159 Base::fatal ("error running lvdisplay");
163 # build map from vgnam to volume group descriptor,
164 # built on vgdisplay.
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
171 if (! open (IN, "-|", "vgdisplay -c 2> /dev/null")) {
172 Base::fatal ("can't run vgdisplay");
174 while (defined (my $line = <IN>)) {
177 my @fields = split (/:/, $line, 500);
178 if ($#fields != 16) {
179 Base::fatal ("malformed output from vgdisplay");
181 my ($vgnam, $vgacc, $vgstat,
182 $vgnum, $maxlv, $curlv, $openlv,
183 $maxlvsiz, $maxpvcnt, $curpvcnt, $actpvcnt,
184 $vgsiz, $extsiz, $extcnt, $extalloc, $extfree,
188 if (exists ($vgMap->{$vgnam})) {
189 Base::fatal ("duplicate output ($vgnam) from vgdisplay");
191 $vgMap->{$vgnam} = VolumeGroup->new (
197 Base::fatal ("error running vgdisplay");
201 # build map from pvnam to physical volume descriptor,
202 # built on pvdisplay.
204 # /dev/sda3:vg0:155598848:-1:8:8:-1:4096:18994: \
205 # 12082:6912:X5hDer-dYpy-jpAB-IhXQ-44j4-kyj0-cOQkyE
209 if (! open (IN, "-|", "pvdisplay -c 2> /dev/null")) {
210 Base::fatal ("can't run pvdisplay");
212 while (defined (my $line = <IN>)) {
215 my @fields = split (/:/, $line, 500);
216 if ($#fields != 11) {
217 Base::fatal ("malformed output from pvdisplay");
219 my ($pvnam,$vgnam,$pvsiz,$pvnum,$pvstat,
220 $pvalloc,$lvcnt,$extsiz,$extcnt,
221 $extfree,$extalloc,$uuid)
224 if (exists ($pvMap->{$pvnam})) {
225 Base::fatal ("duplicate output ($pvnam) from vgdisplay");
227 $pvMap->{$pvnam} = PhysicalVolume->new (
234 Base::fatal ("error running pvdisplay");