Statistics
| Branch: | Revision:

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