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