LCOV - code coverage report
Current view: top level - lvm - lvm-util.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 121 0.0 %
Date: 2024-06-19 15:27:45 Functions: 0 9 0.0 %
Branches: 0 88 0.0 %

           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                 :            : }

Generated by: LCOV version 1.13