parthelper.c 6.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * parthelper.c: Helper program to talk to parted with.
 *
 * This helper exists because parted is GPLv3+, while libvirt is LGPLv2+.
 * Thus we can't link to parted in libvirt.so without the combined work
 * being GPLv3+. Thus we separate via an external command. NB, this source
 * code is still LGPLv2+, but the binary helper is effectively GPLv3+
 *
 * The existing 'parted' command line tool is also incredibly hard to parse
 * in a reliable fashion if merely after a list of partitions & sizes,
 * though it is fine for creating partitions.
 *
13
 * Copyright (C) 2007-2008, 2010, 2013, 2016 Red Hat, Inc.
14 15 16 17 18 19 20 21 22 23 24 25 26
 * Copyright (C) 2007-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
27
 * License along with this library.  If not, see
O
Osier Yang 已提交
28
 * <http://www.gnu.org/licenses/>.
29 30 31 32 33 34 35 36
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <parted/parted.h>
#include <stdio.h>
37
#include <string.h>
38 39 40 41
#include <libdevmapper.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
42

43
#include "virutil.h"
44
#include "virfile.h"
45
#include "c-ctype.h"
46
#include "virstring.h"
47
#include "virgettext.h"
48

49
/* we don't need to include the full internal.h just for this */
M
Michal Privoznik 已提交
50
#define STREQ(a, b) (strcmp(a, b) == 0)
51

J
Jim Meyering 已提交
52 53 54 55 56 57
/* Make the comparisons below fail if your parted headers
   are so old that they lack the definition.  */
#ifndef PED_PARTITION_PROTECTED
# define PED_PARTITION_PROTECTED 0
#endif

58 59 60 61 62
enum diskCommand {
    DISK_LAYOUT = 0,
    DISK_GEOMETRY
};

63 64 65 66 67
int main(int argc, char **argv)
{
    PedDevice *dev;
    PedDisk *disk;
    PedPartition *part;
68
    int cmd = DISK_LAYOUT;
69
    const char *path;
70
    char *canonical_path;
71
    const char *partsep;
72
    bool devmap_partsep = false;
73

74
    if (virGettextInitialize() < 0)
E
Eric Blake 已提交
75 76
        exit(EXIT_FAILURE);

77
    if (argc == 3 && STREQ(argv[2], "-g")) {
78
        cmd = DISK_GEOMETRY;
79
    } else if (argc == 3 && STREQ(argv[2], "-p")) {
80
        devmap_partsep = true;
81
    } else if (argc != 2) {
82
        fprintf(stderr, _("syntax: %s DEVICE [-g]|[-p]\n"), argv[0]);
83 84 85
        return 1;
    }

86
    path = argv[1];
87
    if (virIsDevMapperDevice(path)) {
88 89 90
        /* If the path ends with a number or we explicitly request it for
         * path, then append the "p" partition separator. Otherwise, if
         * the path ends with a letter already, then no need for a separator.
91
         */
92
        if (c_isdigit(path[strlen(path)-1]) || devmap_partsep)
93 94 95
            partsep = "p";
        else
            partsep = "";
96
        if (VIR_STRDUP_QUIET(canonical_path, path) < 0)
97 98
            return 2;
    } else {
99
        if (virFileResolveLink(path, &canonical_path) != 0)
100 101 102 103 104
            return 2;

        partsep = *canonical_path &&
            c_isdigit(canonical_path[strlen(canonical_path)-1]) ? "p" : "";
    }
105 106

    if ((dev = ped_device_get(path)) == NULL) {
E
Eric Blake 已提交
107
        fprintf(stderr, _("unable to access device %s\n"), path);
108 109 110
        return 2;
    }

111
    /* return the geometry of the disk and then exit */
112
    if (cmd == DISK_GEOMETRY) {
113
        printf("%d%c%d%c%d%c",
114 115 116 117 118 119
               dev->hw_geom.cylinders, '\0',
               dev->hw_geom.heads, '\0',
               dev->hw_geom.sectors, '\0');
        return 0;
    }

120
    if ((disk = ped_disk_new(dev)) == NULL) {
E
Eric Blake 已提交
121
        fprintf(stderr, _("unable to access disk %s\n"), argv[1]);
122 123 124 125
        return 2;
    }

    /* Get the first partition, and then iterate over all */
126
    part = ped_disk_next_partition(disk, NULL);
127 128 129 130 131 132 133 134 135
    while (part) {
        const char *type;
        const char *content;
        if (part->type & PED_PARTITION_LOGICAL) {
            type = "logical";
            if (part->type & PED_PARTITION_FREESPACE)
                content = "free";
            else if (part->type & PED_PARTITION_METADATA)
                content = "metadata";
136
            /* coverity[dead_error_condition] - not true if defined */
137 138 139 140 141 142 143 144 145 146 147 148 149
            else if (part->type & PED_PARTITION_PROTECTED)
                content = "protected";
            else
                content = "data";
        } else if (part->type == PED_PARTITION_EXTENDED) {
            type = "extended";
            content = "metadata";
        } else {
            type = "normal";
            if (part->type & PED_PARTITION_FREESPACE)
                content = "free";
            else if (part->type & PED_PARTITION_METADATA)
                content = "metadata";
150
            /* coverity[dead_error_condition] - not true if defined */
151 152 153 154 155 156 157 158 159 160
            else if (part->type & PED_PARTITION_PROTECTED)
                content = "protected";
            else
                content = "data";
        }

        /* We do +1 on geom.end, because we want end of the last sector
         * in bytes, not the last sector number
         */
        if (part->num != -1) {
161
            printf("%s%s%d%c%s%c%s%c%llu%c%llu%c%llu%c",
162
                   canonical_path, partsep,
163 164 165
                   part->num, '\0',
                   type, '\0',
                   content, '\0',
166
                   part->geom.start * dev->sector_size, '\0',
167
                   (part->geom.end + 1) * dev->sector_size, '\0',
168
                   part->geom.length * dev->sector_size, '\0');
169 170 171 172 173
        } else {
            printf("%s%c%s%c%s%c%llu%c%llu%c%llu%c",
                   "-", '\0',
                   type, '\0',
                   content, '\0',
174
                   part->geom.start * dev->sector_size, '\0',
175
                   (part->geom.end + 1) * dev->sector_size, '\0',
176
                   part->geom.length * dev->sector_size, '\0');
177 178 179 180 181 182
        }
        part = ped_disk_next_partition(disk, part);
    }

    return 0;
}