root / lvm / lvm-util.c @ abdb293f
History | View | Annotate | Download (7.6 kB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 2008, XenSource Inc.
|
3 |
* All rights reserved.
|
4 |
*
|
5 |
* Redistribution and use in source and binary forms, with or without
|
6 |
* modification, are permitted provided that the following conditions are met:
|
7 |
* * Redistributions of source code must retain the above copyright
|
8 |
* notice, this list of conditions and the following disclaimer.
|
9 |
* * Redistributions in binary form must reproduce the above copyright
|
10 |
* notice, this list of conditions and the following disclaimer in the
|
11 |
* documentation and/or other materials provided with the distribution.
|
12 |
* * Neither the name of XenSource Inc. nor the names of its contributors
|
13 |
* may be used to endorse or promote products derived from this software
|
14 |
* without specific prior written permission.
|
15 |
*
|
16 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
18 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
19 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
20 |
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
21 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
23 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
24 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
25 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
26 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27 |
*/
|
28 |
|
29 |
#ifdef HAVE_CONFIG_H
|
30 |
#include "config.h" |
31 |
#endif
|
32 |
|
33 |
#include <stdio.h> |
34 |
#include <errno.h> |
35 |
#include <stdlib.h> |
36 |
#include <string.h> |
37 |
#include <syslog.h> |
38 |
|
39 |
#include "lvm-util.h" |
40 |
|
41 |
#define EPRINTF(_f, _a...) \
|
42 |
do { \
|
43 |
syslog(LOG_INFO, "%s: " _f, __func__, ##_a); \ |
44 |
} while (0) |
45 |
|
46 |
#define _NAME "%255s" |
47 |
static char line[1024]; |
48 |
|
49 |
static inline int |
50 |
lvm_read_line(FILE *scan) |
51 |
{ |
52 |
memset(line, 0, sizeof(line)); |
53 |
return (fscanf(scan, "%1023[^\n]", line) != 1); |
54 |
} |
55 |
|
56 |
static inline int |
57 |
lvm_next_line(FILE *scan) |
58 |
{ |
59 |
return (fscanf(scan, "%1023[\n]", line) != 1); |
60 |
} |
61 |
|
62 |
static int |
63 |
lvm_copy_name(char *dst, const char *src, size_t size) |
64 |
{ |
65 |
if (strnlen(src, size) == size)
|
66 |
return -ENAMETOOLONG;
|
67 |
|
68 |
strcpy(dst, src); |
69 |
return 0; |
70 |
} |
71 |
|
72 |
static int |
73 |
lvm_parse_pv(struct vg *vg, const char *name, int pvs, uint64_t start) |
74 |
{ |
75 |
int i, err;
|
76 |
struct pv *pv;
|
77 |
|
78 |
pv = NULL;
|
79 |
|
80 |
if (!vg->pvs) {
|
81 |
vg->pvs = calloc(pvs, sizeof(struct pv)); |
82 |
if (!vg->pvs)
|
83 |
return -ENOMEM;
|
84 |
} |
85 |
|
86 |
for (i = 0; i < pvs; i++) { |
87 |
pv = vg->pvs + i; |
88 |
|
89 |
if (!pv->name[0]) |
90 |
break;
|
91 |
|
92 |
if (!strcmp(pv->name, name))
|
93 |
return -EEXIST;
|
94 |
} |
95 |
|
96 |
if (!pv)
|
97 |
return -ENOENT;
|
98 |
|
99 |
if (i == pvs)
|
100 |
return -ENOMEM;
|
101 |
|
102 |
err = lvm_copy_name(pv->name, name, sizeof(pv->name) - 1); |
103 |
if (err)
|
104 |
return err;
|
105 |
|
106 |
pv->start = start; |
107 |
return 0; |
108 |
} |
109 |
|
110 |
static int |
111 |
lvm_open_vg(const char *vgname, struct vg *vg) |
112 |
{ |
113 |
FILE *scan; |
114 |
int i, err, pvs, lvs;
|
115 |
char *cmd, pvname[256]; |
116 |
uint64_t size, pv_start; |
117 |
|
118 |
memset(vg, 0, sizeof(*vg)); |
119 |
|
120 |
err = asprintf(&cmd, "/sbin/vgs %s --noheadings --nosuffix --units=b "
|
121 |
"--options=vg_name,vg_extent_size,lv_count,pv_count,"
|
122 |
"pv_name,pe_start --unbuffered 2> /dev/null", vgname);
|
123 |
if (err == -1) |
124 |
return -ENOMEM;
|
125 |
|
126 |
errno = 0;
|
127 |
scan = popen(cmd, "r");
|
128 |
if (!scan) {
|
129 |
err = (errno ? -errno : ENOMEM); |
130 |
goto out;
|
131 |
} |
132 |
|
133 |
for (;;) {
|
134 |
if (lvm_read_line(scan))
|
135 |
break;
|
136 |
|
137 |
err = -EINVAL; |
138 |
if (sscanf(line, _NAME" %"PRIu64" %d %d "_NAME" %"PRIu64, vg->name, |
139 |
&size, &lvs, &pvs, pvname, &pv_start) != 6) {
|
140 |
EPRINTF("sscanf failed on '%s'\n", line);
|
141 |
goto out;
|
142 |
} |
143 |
|
144 |
if (strcmp(vg->name, vgname)) {
|
145 |
EPRINTF("VG name '%s' != '%s'\n", vg->name, vgname);
|
146 |
goto out;
|
147 |
} |
148 |
err = lvm_parse_pv(vg, pvname, pvs, pv_start); |
149 |
if (err)
|
150 |
goto out;
|
151 |
|
152 |
if (lvm_next_line(scan))
|
153 |
break;
|
154 |
} |
155 |
|
156 |
err = -EINVAL; |
157 |
if (strcmp(vg->name, vgname)) {
|
158 |
EPRINTF("VG name '%s' != '%s'\n", vg->name, vgname);
|
159 |
goto out;
|
160 |
} |
161 |
|
162 |
for (i = 0; i < pvs; i++) |
163 |
if (!vg->pvs[i].name[0]) { |
164 |
EPRINTF("pvs %d name empty\n", i);
|
165 |
goto out;
|
166 |
} |
167 |
|
168 |
err = -ENOMEM; |
169 |
vg->lvs = calloc(lvs, sizeof(struct lv)); |
170 |
if (!vg->lvs)
|
171 |
goto out;
|
172 |
|
173 |
err = 0;
|
174 |
vg->lv_cnt = lvs; |
175 |
vg->pv_cnt = pvs; |
176 |
vg->extent_size = size; |
177 |
|
178 |
out:
|
179 |
if (scan)
|
180 |
pclose(scan); |
181 |
if (err)
|
182 |
lvm_free_vg(vg); |
183 |
free(cmd); |
184 |
return err;
|
185 |
} |
186 |
|
187 |
static int |
188 |
lvm_parse_lv_devices(struct vg *vg, struct lv_segment *seg, char *devices) |
189 |
{ |
190 |
int i;
|
191 |
uint64_t start, pe_start; |
192 |
|
193 |
for (i = 0; i < strlen(devices); i++) |
194 |
if (strchr(",()", devices[i])) |
195 |
devices[i] = ' ';
|
196 |
|
197 |
if (sscanf(devices, _NAME" %"PRIu64, seg->device, &start) != 2) { |
198 |
EPRINTF("sscanf failed on '%s'\n", devices);
|
199 |
return -EINVAL;
|
200 |
} |
201 |
|
202 |
pe_start = -1;
|
203 |
for (i = 0; i < vg->pv_cnt; i++) |
204 |
if (!strcmp(vg->pvs[i].name, seg->device)) {
|
205 |
pe_start = vg->pvs[i].start; |
206 |
break;
|
207 |
} |
208 |
|
209 |
if (pe_start == -1) { |
210 |
EPRINTF("invalid pe_start value\n");
|
211 |
return -EINVAL;
|
212 |
} |
213 |
|
214 |
seg->pe_start = (start * vg->extent_size) + pe_start; |
215 |
return 0; |
216 |
} |
217 |
|
218 |
static int |
219 |
lvm_scan_lvs(struct vg *vg)
|
220 |
{ |
221 |
char *cmd;
|
222 |
FILE *scan; |
223 |
int i, err;
|
224 |
|
225 |
err = asprintf(&cmd, "/sbin/lvs %s --noheadings --nosuffix --units=b "
|
226 |
"--options=lv_name,lv_size,segtype,seg_count,seg_start,"
|
227 |
"seg_size,devices --unbuffered 2> /dev/null", vg->name);
|
228 |
if (err == -1) |
229 |
return -ENOMEM;
|
230 |
|
231 |
errno = 0;
|
232 |
scan = popen(cmd, "r");
|
233 |
if (!scan) {
|
234 |
err = (errno ? -errno : -ENOMEM); |
235 |
goto out;
|
236 |
} |
237 |
|
238 |
for (i = 0;;) { |
239 |
int segs;
|
240 |
struct lv *lv;
|
241 |
struct lv_segment seg;
|
242 |
unsigned long long size, seg_start; |
243 |
char type[32], name[256], devices[1024]; |
244 |
|
245 |
if (i >= vg->lv_cnt)
|
246 |
break;
|
247 |
|
248 |
if (lvm_read_line(scan)) {
|
249 |
vg->lv_cnt = i; |
250 |
break;
|
251 |
} |
252 |
|
253 |
err = -EINVAL; |
254 |
lv = vg->lvs + i; |
255 |
|
256 |
if (sscanf(line, _NAME" %llu %31s %u %llu %"PRIu64" %1023s", |
257 |
name, &size, type, &segs, &seg_start, |
258 |
&seg.pe_size, devices) != 7) {
|
259 |
EPRINTF("sscanf failed on '%s'\n", line);
|
260 |
goto out;
|
261 |
} |
262 |
|
263 |
if (seg_start)
|
264 |
goto next;
|
265 |
|
266 |
if (!strcmp(type, "linear")) |
267 |
seg.type = LVM_SEG_TYPE_LINEAR; |
268 |
else
|
269 |
seg.type = LVM_SEG_TYPE_UNKNOWN; |
270 |
|
271 |
if (lvm_parse_lv_devices(vg, &seg, devices))
|
272 |
goto out;
|
273 |
|
274 |
i++; |
275 |
lv->size = size; |
276 |
lv->segments = segs; |
277 |
lv->first_segment = seg; |
278 |
|
279 |
err = lvm_copy_name(lv->name, name, sizeof(lv->name) - 1); |
280 |
if (err)
|
281 |
goto out;
|
282 |
err = -EINVAL; |
283 |
|
284 |
next:
|
285 |
if (lvm_next_line(scan)) {
|
286 |
if (err)
|
287 |
EPRINTF("fscanf failed\n");
|
288 |
goto out;
|
289 |
} |
290 |
} |
291 |
|
292 |
err = 0;
|
293 |
|
294 |
out:
|
295 |
if (scan)
|
296 |
pclose(scan); |
297 |
free(cmd); |
298 |
return err;
|
299 |
} |
300 |
|
301 |
void
|
302 |
lvm_free_vg(struct vg *vg)
|
303 |
{ |
304 |
free(vg->lvs); |
305 |
free(vg->pvs); |
306 |
memset(vg, 0, sizeof(*vg)); |
307 |
} |
308 |
|
309 |
int
|
310 |
lvm_scan_vg(const char *vg_name, struct vg *vg) |
311 |
{ |
312 |
int err;
|
313 |
|
314 |
memset(vg, 0, sizeof(*vg)); |
315 |
|
316 |
err = lvm_open_vg(vg_name, vg); |
317 |
if (err)
|
318 |
return err;
|
319 |
|
320 |
err = lvm_scan_lvs(vg); |
321 |
if (err) {
|
322 |
lvm_free_vg(vg); |
323 |
return err;
|
324 |
} |
325 |
|
326 |
return 0; |
327 |
} |
328 |
|
329 |
#ifdef LVM_UTIL
|
330 |
static int |
331 |
usage(void)
|
332 |
{ |
333 |
printf("usage: lvm-util <vgname>\n");
|
334 |
exit(EINVAL); |
335 |
} |
336 |
|
337 |
int
|
338 |
main(int argc, char **argv) |
339 |
{ |
340 |
int i, err;
|
341 |
struct vg vg;
|
342 |
struct pv *pv;
|
343 |
struct lv *lv;
|
344 |
struct lv_segment *seg;
|
345 |
|
346 |
if (argc != 2) |
347 |
usage(); |
348 |
|
349 |
err = lvm_scan_vg(argv[1], &vg);
|
350 |
if (err) {
|
351 |
printf("scan failed: %d\n", err);
|
352 |
return (err >= 0 ? err : -err); |
353 |
} |
354 |
|
355 |
printf("vg %s: extent_size: %"PRIu64", pvs: %d, lvs: %d\n", |
356 |
vg.name, vg.extent_size, vg.pv_cnt, vg.lv_cnt); |
357 |
|
358 |
for (i = 0; i < vg.pv_cnt; i++) { |
359 |
pv = vg.pvs + i; |
360 |
printf("pv %s: start %"PRIu64"\n", pv->name, pv->start); |
361 |
} |
362 |
|
363 |
for (i = 0; i < vg.lv_cnt; i++) { |
364 |
lv = vg.lvs + i; |
365 |
seg = &lv->first_segment; |
366 |
printf("lv %s: size: %"PRIu64", segments: %u, type: %u, " |
367 |
"dev: %s, pe_start: %"PRIu64", pe_size: %"PRIu64"\n", |
368 |
lv->name, lv->size, lv->segments, seg->type, |
369 |
seg->device, seg->pe_start, seg->pe_size); |
370 |
} |
371 |
|
372 |
lvm_free_vg(&vg); |
373 |
return 0; |
374 |
} |
375 |
#endif
|