Blame src/plugins/part.c

Packit Service 158247
/*
Packit Service 158247
 * Copyright (C) 2016  Red Hat, Inc.
Packit Service 158247
 *
Packit Service 158247
 * This library is free software; you can redistribute it and/or
Packit Service 158247
 * modify it under the terms of the GNU Lesser General Public
Packit Service 158247
 * License as published by the Free Software Foundation; either
Packit Service 158247
 * version 2.1 of the License, or (at your option) any later version.
Packit Service 158247
 *
Packit Service 158247
 * This library is distributed in the hope that it will be useful,
Packit Service 158247
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 158247
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 158247
 * Lesser General Public License for more details.
Packit Service 158247
 *
Packit Service 158247
 * You should have received a copy of the GNU Lesser General Public
Packit Service 158247
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit Service 158247
 *
Packit Service 158247
 * Author: Vratislav Podzimek <vpodzime@redhat.com>
Packit Service 158247
 */
Packit Service 158247
Packit Service 158247
#include <string.h>
Packit Service 158247
#include <parted/parted.h>
Packit Service 158247
#include <ctype.h>
Packit Service 158247
#include <stdlib.h>
Packit Service 158247
#include <math.h>
Packit Service 158247
#include <inttypes.h>
Packit Service 158247
#include <unistd.h>
Packit Service 158247
#include <sys/file.h>
Packit Service 158247
#include <fcntl.h>
Packit Service 158247
#include <sys/ioctl.h>
Packit Service 158247
#include <linux/fs.h>
Packit Service 158247
#include <blockdev/utils.h>
Packit Service 158247
#include <part_err.h>
Packit Service 158247
Packit Service 158247
#include "part.h"
Packit Service 158247
#include "check_deps.h"
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * SECTION: part
Packit Service 158247
 * @short_description: plugin for operations with partition tables
Packit Service 158247
 * @title: Part
Packit Service 158247
 * @include: part.h
Packit Service 158247
 *
Packit Service 158247
 * A plugin for operations with partition tables. Currently supported table
Packit Service 158247
 * (disk label) types are MBR and GPT. See the functions below to get an
Packit Service 158247
 * overview of which operations are supported. If there's anything missing,
Packit Service 158247
 * please don't hesitate to report it as this plugin (just like all the others)
Packit Service 158247
 * is subject to future development and enhancements.
Packit Service 158247
 *
Packit Service 158247
 * This particular implementation of the part plugin uses libparted for
Packit Service 158247
 * manipulations of both the MBR and GPT disk label types together with the
Packit Service 158247
 * sgdisk utility for some extra GPT-specific features libparted doesn't
Packit Service 158247
 * support. In the future, there's likely to be another implementation of this
Packit Service 158247
 * plugin based on libfdisk which provides full support for both MBR and GPT
Packit Service 158247
 * tables (and possibly some others).
Packit Service 158247
 */
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_error_quark: (skip)
Packit Service 158247
 */
Packit Service 158247
GQuark bd_part_error_quark (void)
Packit Service 158247
{
Packit Service 158247
    return g_quark_from_static_string ("g-bd-part-error-quark");
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
BDPartSpec* bd_part_spec_copy (BDPartSpec *data) {
Packit Service 158247
    if (data == NULL)
Packit Service 158247
        return NULL;
Packit Service 158247
Packit Service 158247
    BDPartSpec *ret = g_new0 (BDPartSpec, 1);
Packit Service 158247
Packit Service 158247
    ret->path = g_strdup (data->path);
Packit Service 158247
    ret->name = g_strdup (data->name);
Packit Service 158247
    ret->type_guid = g_strdup (data->type_guid);
Packit Service 158247
    ret->type = data->type;
Packit Service 158247
    ret->start = data->start;
Packit Service 158247
    ret->size = data->size;
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
void bd_part_spec_free (BDPartSpec *data) {
Packit Service 158247
    if (data == NULL)
Packit Service 158247
        return;
Packit Service 158247
Packit Service 158247
    g_free (data->path);
Packit Service 158247
    g_free (data->name);
Packit Service 158247
    g_free (data->type_guid);
Packit Service 158247
    g_free (data);
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
BDPartDiskSpec* bd_part_disk_spec_copy (BDPartDiskSpec *data) {
Packit Service 158247
    if (data == NULL)
Packit Service 158247
        return NULL;
Packit Service 158247
Packit Service 158247
    BDPartDiskSpec *ret = g_new0 (BDPartDiskSpec, 1);
Packit Service 158247
Packit Service 158247
    ret->path = g_strdup (data->path);
Packit Service 158247
    ret->table_type = data->table_type;
Packit Service 158247
    ret->size = data->size;
Packit Service 158247
    ret->sector_size = data->sector_size;
Packit Service 158247
    ret->flags = data->flags;
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
void bd_part_disk_spec_free (BDPartDiskSpec *data) {
Packit Service 158247
    if (data == NULL)
Packit Service 158247
        return;
Packit Service 158247
Packit Service 158247
    g_free (data->path);
Packit Service 158247
    g_free (data);
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * set_parted_error: (skip)
Packit Service 158247
 *
Packit Service 158247
 * Set error from the parted error stored in 'error_msg'. In case there is none,
Packit Service 158247
 * the error is set up with an empty string. Otherwise it is set up with the
Packit Service 158247
 * parted's error message and is a subject to later g_prefix_error() call.
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether there was some message from parted or not
Packit Service 158247
 */
Packit Service 158247
static gboolean set_parted_error (GError **error, BDPartError type) {
Packit Service 158247
    gchar *error_msg = NULL;
Packit Service 158247
    error_msg = bd_get_error_msg ();
Packit Service 158247
    if (error_msg) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, type,
Packit Service 158247
                     " (%s)", error_msg);
Packit Service 158247
        g_free (error_msg);
Packit Service 158247
        error_msg = NULL;
Packit Service 158247
        return TRUE;
Packit Service 158247
    } else {
Packit Service 158247
        g_set_error_literal (error, BD_PART_ERROR, type, "");
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
Packit Service 158247
static volatile guint avail_deps = 0;
Packit Service 158247
static GMutex deps_check_lock;
Packit Service 158247
Packit Service 158247
#define DEPS_SGDISK 0
Packit Service 158247
#define DEPS_SGDISK_MASK (1 << DEPS_SGDISK)
Packit Service 158247
#define DEPS_SFDISK 1
Packit Service 158247
#define DEPS_SFDISK_MASK (1 << DEPS_SFDISK)
Packit Service 158247
#define DEPS_LAST 2
Packit Service 158247
Packit Service 158247
static const UtilDep deps[DEPS_LAST] = {
Packit Service 158247
    {"sgdisk", "0.8.6", NULL, "GPT fdisk \\(sgdisk\\) version ([\\d\\.]+)"},
Packit Service 158247
    {"sfdisk", NULL, NULL, NULL},
Packit Service 158247
};
Packit Service 158247
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_check_deps:
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the plugin's runtime dependencies are satisfied or not
Packit Service 158247
 *
Packit Service 158247
 * Function checking plugin's runtime dependencies.
Packit Service 158247
 *
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_check_deps (void) {
Packit Service 158247
    GError *error = NULL;
Packit Service 158247
    guint i = 0;
Packit Service 158247
    gboolean status = FALSE;
Packit Service 158247
    gboolean ret = TRUE;
Packit Service 158247
Packit Service 158247
    for (i=0; i < DEPS_LAST; i++) {
Packit Service 158247
        status = bd_utils_check_util_version (deps[i].name, deps[i].version,
Packit Service 158247
                                              deps[i].ver_arg, deps[i].ver_regexp, &error);
Packit Service 158247
        if (!status)
Packit Service 158247
            g_warning ("%s", error->message);
Packit Service 158247
        else
Packit Service 158247
            g_atomic_int_or (&avail_deps, 1 << i);
Packit Service 158247
        g_clear_error (&error);
Packit Service 158247
        ret = ret && status;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (!ret)
Packit Service 158247
        g_warning("Cannot load the part plugin");
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_init:
Packit Service 158247
 *
Packit Service 158247
 * Initializes the plugin. **This function is called automatically by the
Packit Service 158247
 * library's initialization functions.**
Packit Service 158247
 *
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_init (void) {
Packit Service 158247
    ped_exception_set_handler ((PedExceptionHandler*) bd_exc_handler);
Packit Service 158247
    return TRUE;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_close:
Packit Service 158247
 *
Packit Service 158247
 * Cleans up after the plugin. **This function is called automatically by the
Packit Service 158247
 * library's functions that unload it.**
Packit Service 158247
 *
Packit Service 158247
 */
Packit Service 158247
void bd_part_close (void) {
Packit Service 158247
    ped_exception_set_handler (NULL);
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_is_tech_avail:
Packit Service 158247
 * @tech: the queried tech
Packit Service 158247
 * @mode: a bit mask of queried modes of operation (#BDPartTechMode) for @tech
Packit Service 158247
 * @error: (out): place to store error (details about why the @tech-@mode combination is not available)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the @tech-@mode combination is available -- supported by the
Packit Service 158247
 *          plugin implementation and having all the runtime dependencies available
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_is_tech_avail (BDPartTech tech, guint64 mode, GError **error) {
Packit Service 158247
    switch (tech) {
Packit Service 158247
    case BD_PART_TECH_MBR:
Packit Service 158247
        /* all MBR-mode combinations are supported by this implementation of the
Packit Service 158247
         * plugin, nothing extra is needed */
Packit Service 158247
        return TRUE;
Packit Service 158247
    case BD_PART_TECH_GPT:
Packit Service 158247
        if (mode & (BD_PART_TECH_MODE_MODIFY_PART|BD_PART_TECH_MODE_QUERY_PART))
Packit Service 158247
            return check_deps (&avail_deps, DEPS_SGDISK_MASK|DEPS_SFDISK_MASK,
Packit Service 158247
                               deps, DEPS_LAST, &deps_check_lock, error);
Packit Service 158247
        else
Packit Service 158247
            return TRUE;
Packit Service 158247
    default:
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_TECH_UNAVAIL, "Unknown technology");
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
static const gchar *table_type_str[BD_PART_TABLE_UNDEF] = {"msdos", "gpt"};
Packit Service 158247
Packit Service 158247
static gboolean disk_commit (PedDisk *disk, const gchar *path, GError **error) {
Packit Service 158247
    gint ret = 0;
Packit Service 158247
    gint dev_fd = 0;
Packit Service 158247
    guint num_tries = 1;
Packit Service 158247
Packit Service 158247
    /* XXX: try to grab a lock for the device so that udev doesn't step in
Packit Service 158247
       between the two operations we need to perform (see below) with its
Packit Service 158247
       BLKRRPART ioctl() call which makes the device busy */
Packit Service 158247
    dev_fd = open (disk->dev->path, O_RDONLY|O_CLOEXEC);
Packit Service 158247
    if (dev_fd >= 0) {
Packit Service 158247
        ret = flock (dev_fd, LOCK_SH|LOCK_NB);
Packit Service 158247
        while ((ret != 0) && (num_tries <= 5)) {
Packit Service 158247
            g_usleep (100 * 1000); /* microseconds */
Packit Service 158247
            ret = flock (dev_fd, LOCK_SH|LOCK_NB);
Packit Service 158247
            num_tries++;
Packit Service 158247
        }
Packit Service 158247
    }
Packit Service 158247
    /* Just continue even in case we don't get the lock, there's still a
Packit Service 158247
       chance things will just work. If not, an error will be reported
Packit Service 158247
       anyway with no harm. */
Packit Service 158247
Packit Service 158247
    /* XXX: Sometimes it happens that when we try to commit the partition table
Packit Service 158247
       to disk below, libparted kills the process due to the
Packit Service 158247
       assert(disk->dev->open_count > 0). This looks like a bug to me, but we
Packit Service 158247
       have no reproducer for it. Let's just try to (re)open the device in such
Packit Service 158247
       cases. It is later closed by the ped_device_destroy() call. */
Packit Service 158247
    if (disk->dev->open_count <= 0)
Packit Service 158247
        ped_device_open (disk->dev);
Packit Service 158247
Packit Service 158247
    ret = ped_disk_commit_to_dev (disk);
Packit Service 158247
    if (ret == 0) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to commit changes to device '%s'", path);
Packit Service 158247
        if (dev_fd >= 0)
Packit Service 158247
            close (dev_fd);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ret = ped_disk_commit_to_os (disk);
Packit Service 158247
    if (ret == 0) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to inform OS about changes on the '%s' device", path);
Packit Service 158247
        if (dev_fd >= 0)
Packit Service 158247
            close (dev_fd);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (dev_fd >= 0)
Packit Service 158247
        close (dev_fd);
Packit Service 158247
    return TRUE;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_create_table:
Packit Service 158247
 * @disk: path of the disk block device to create partition table on
Packit Service 158247
 * @type: type of the partition table to create
Packit Service 158247
 * @ignore_existing: whether to ignore/overwrite the existing table or not
Packit Service 158247
 *                   (reports an error if %FALSE and there's some table on @disk)
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the partition table was successfully created or not
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_CREATE_TABLE + the tech according to @type
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_create_table (const gchar *disk, BDPartTableType type, gboolean ignore_existing, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedDiskType *disk_type = NULL;
Packit Service 158247
    gboolean ret = FALSE;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Starting creation of a new partition table on '%s'", disk);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (!ignore_existing) {
Packit Service 158247
        ped_disk = ped_disk_new (dev);
Packit Service 158247
        if (ped_disk) {
Packit Service 158247
            /* no parted error */
Packit Service 158247
            g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_EXISTS,
Packit Service 158247
                         "Device '%s' already contains a partition table", disk);
Packit Service 158247
            ped_disk_destroy (ped_disk);
Packit Service 158247
            ped_device_destroy (dev);
Packit Service 158247
            bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
            return FALSE;
Packit Service 158247
        }
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    disk_type = ped_disk_type_get (table_type_str[type]);
Packit Service 158247
    ped_disk = ped_disk_new_fresh (dev, disk_type);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to create a new partition table of type '%s' on device '%s'",
Packit Service 158247
                        table_type_str[type], disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    /* commit changes to disk */
Packit Service 158247
    ret = disk_commit (ped_disk, disk, error);
Packit Service 158247
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    /* just return what we got (error may be set) */
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
static gchar* get_part_type_guid_and_gpt_flags (const gchar *device, int part_num, guint64 *flags, GError **error) {
Packit Service 158247
    const gchar *args[4] = {"sgdisk", NULL, device, NULL};
Packit Service 158247
    gchar *output = NULL;
Packit Service 158247
    gchar **lines = NULL;
Packit Service 158247
    gchar **line_p = NULL;
Packit Service 158247
    gchar *guid_line = NULL;
Packit Service 158247
    gchar *attrs_line = NULL;
Packit Service 158247
    gchar *guid_start = NULL;
Packit Service 158247
    gchar *attrs_start = NULL;
Packit Service 158247
    guint64 flags_mask = 0;
Packit Service 158247
    gboolean success = FALSE;
Packit Service 158247
    gchar *space = NULL;
Packit Service 158247
    gchar *ret = NULL;
Packit Service 158247
Packit Service 158247
    if (!check_deps (&avail_deps, DEPS_SGDISK_MASK, deps, DEPS_LAST, &deps_check_lock, error))
Packit Service 158247
        return FALSE;
Packit Service 158247
Packit Service 158247
    args[1] = g_strdup_printf ("-i%d", part_num);
Packit Service 158247
    success = bd_utils_exec_and_capture_output (args, NULL, &output, error);
Packit Service 158247
    g_free ((gchar *) args[1]);
Packit Service 158247
    if (!success)
Packit Service 158247
        return FALSE;
Packit Service 158247
Packit Service 158247
    lines = g_strsplit (output, "\n", 0);
Packit Service 158247
    g_free (output);
Packit Service 158247
    for (line_p=lines; *line_p && (!guid_line || !attrs_line); line_p++) {
Packit Service 158247
        if (g_str_has_prefix (*line_p, "Partition GUID code: "))
Packit Service 158247
            guid_line = *line_p;
Packit Service 158247
        else if (g_str_has_prefix (*line_p, "Attribute flags: "))
Packit Service 158247
            attrs_line = *line_p;
Packit Service 158247
    }
Packit Service 158247
    if (!guid_line && !attrs_line) {
Packit Service 158247
        g_strfreev (lines);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (guid_line) {
Packit Service 158247
        guid_start = guid_line + 21; /* strlen("Partition GUID...") */
Packit Service 158247
        space = strchr (guid_start, ' '); /* find the first space after the GUID */
Packit Service 158247
        if (space)
Packit Service 158247
            *space = '\0';
Packit Service 158247
        ret = g_strdup (guid_start);
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (attrs_line) {
Packit Service 158247
        attrs_start = attrs_line + 17; /* strlen("Attribute flags: ") */
Packit Service 158247
        flags_mask = strtoull (attrs_start, NULL, 16);
Packit Service 158247
Packit Service 158247
        if (flags_mask & 1) /* 1 << 0 */
Packit Service 158247
            *flags |= BD_PART_FLAG_GPT_SYSTEM_PART;
Packit Service 158247
        if (flags_mask & 4) /* 1 << 2 */
Packit Service 158247
            *flags |= BD_PART_FLAG_LEGACY_BOOT;
Packit Service 158247
        if (flags_mask & 0x1000000000000000) /* 1 << 60 */
Packit Service 158247
            *flags |= BD_PART_FLAG_GPT_READ_ONLY;
Packit Service 158247
        if (flags_mask & 0x4000000000000000) /* 1 << 62 */
Packit Service 158247
            *flags |= BD_PART_FLAG_GPT_HIDDEN;
Packit Service 158247
        if (flags_mask & 0x8000000000000000) /* 1 << 63 */
Packit Service 158247
            *flags |= BD_PART_FLAG_GPT_NO_AUTOMOUNT;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    g_strfreev (lines);
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
static BDPartSpec* get_part_spec (PedDevice *dev, PedDisk *disk, PedPartition *part, GError **error) {
Packit Service 158247
    BDPartSpec *ret = NULL;
Packit Service 158247
    PedPartitionFlag flag = PED_PARTITION_FIRST_FLAG;
Packit Service 158247
Packit Service 158247
    ret = g_new0 (BDPartSpec, 1);
Packit Service 158247
    /* the no-partition "partitions" have num equal to -1 which never really
Packit Service 158247
       creates a valid block device path, so let's just not set path to
Packit Service 158247
       nonsense */
Packit Service 158247
    if (part->num != -1) {
Packit Service 158247
        if (isdigit (dev->path[strlen(dev->path) - 1]))
Packit Service 158247
            ret->path = g_strdup_printf ("%sp%d", dev->path, part->num);
Packit Service 158247
        else
Packit Service 158247
            ret->path = g_strdup_printf ("%s%d", dev->path, part->num);
Packit Service 158247
    }
Packit Service 158247
    if (ped_partition_is_active (part) && disk->type->features & PED_DISK_TYPE_PARTITION_NAME)
Packit Service 158247
        ret->name = g_strdup (ped_partition_get_name (part));
Packit Service 158247
    if (g_strcmp0 (disk->type->name, "gpt") == 0) {
Packit Service 158247
        ret->type_guid = get_part_type_guid_and_gpt_flags (dev->path, part->num, &(ret->flags), error);
Packit Service 158247
        if (!ret->type_guid && *error) {
Packit Service 158247
            bd_part_spec_free (ret);
Packit Service 158247
            return NULL;
Packit Service 158247
        }
Packit Service 158247
    }
Packit Service 158247
    ret->type = (BDPartType) part->type;
Packit Service 158247
    ret->start = part->geom.start * dev->sector_size;
Packit Service 158247
    ret->size = part->geom.length * dev->sector_size;
Packit Service 158247
    for (flag=PED_PARTITION_FIRST_FLAG; flag
Packit Service 158247
        /* beware of partition types that segfault when asked for flags */
Packit Service 158247
        if ((part->type <= PED_PARTITION_EXTENDED) &&
Packit Service 158247
            ped_partition_is_flag_available (part, flag) && ped_partition_get_flag (part, flag))
Packit Service 158247
            /* our flags are 1s shifted to the bit determined by parted's flags
Packit Service 158247
             * (i.e. 1 << 3 instead of 3, etc.) */
Packit Service 158247
            ret->flags = ret->flags | (1 << flag);
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_part_spec:
Packit Service 158247
 * @disk: disk to remove the partition from
Packit Service 158247
 * @part: partition to get spec for
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer full): spec of the @part partition from @disk or %NULL in case of error
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_QUERY_PART + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
BDPartSpec* bd_part_get_part_spec (const gchar *disk, const gchar *part, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedPartition *ped_part = NULL;
Packit Service 158247
    const gchar *part_num_str = NULL;
Packit Service 158247
    gint part_num = 0;
Packit Service 158247
    BDPartSpec *ret = NULL;
Packit Service 158247
Packit Service 158247
    if (!part || (part && (*part == '\0'))) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'", part);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part_num_str = part + (strlen (part) - 1);
Packit Service 158247
    while (isdigit (*part_num_str) || (*part_num_str == '-')) {
Packit Service 158247
        part_num_str--;
Packit Service 158247
    }
Packit Service 158247
    part_num_str++;
Packit Service 158247
Packit Service 158247
    part_num = atoi (part_num_str);
Packit Service 158247
    if (part_num == 0) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'. Cannot extract partition number", part);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_part = ped_disk_get_partition (ped_disk, part_num);
Packit Service 158247
    if (!ped_part) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to get partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ret = get_part_spec (dev, ped_disk, ped_part, error);
Packit Service 158247
Packit Service 158247
    /* the partition gets destroyed together with the disk */
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_part_by_pos:
Packit Service 158247
 * @disk: disk to remove the partition from
Packit Service 158247
 * @position: position (in bytes) determining the partition
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer full): spec of the partition from @disk spanning over the @position or %NULL if no such
Packit Service 158247
 *          partition exists or in case of error (@error is set)
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_QUERY_PART + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
BDPartSpec* bd_part_get_part_by_pos (const gchar *disk, guint64 position, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedPartition *ped_part = NULL;
Packit Service 158247
    BDPartSpec *ret = NULL;
Packit Service 158247
    PedSector sector = 0;
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    sector = (PedSector) (position / dev->sector_size);
Packit Service 158247
    ped_part = ped_disk_get_partition_by_sector (ped_disk, sector);
Packit Service 158247
    if (!ped_part) {
Packit Service 158247
        if (set_parted_error (error, BD_PART_ERROR_FAIL))
Packit Service 158247
            g_prefix_error (error, "Failed to get partition at position %"G_GUINT64_FORMAT" (device '%s')",
Packit Service 158247
                            position, disk);
Packit Service 158247
        else
Packit Service 158247
            /* no such partition, but no error */
Packit Service 158247
            g_clear_error (error);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ret = get_part_spec (dev, ped_disk, ped_part, error);
Packit Service 158247
Packit Service 158247
    /* the partition gets destroyed together with the disk */
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_disk_spec:
Packit Service 158247
 * @disk: disk to get information about
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer full): information about the given @disk or %NULL (in case of error)
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_QUERY_TABLE + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
BDPartDiskSpec* bd_part_get_disk_spec (const gchar *disk, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    BDPartDiskSpec *ret = NULL;
Packit Service 158247
    PedConstraint *constr = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    BDPartTableType type = BD_PART_TABLE_UNDEF;
Packit Service 158247
    gboolean found = FALSE;
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ret = g_new0 (BDPartDiskSpec, 1);
Packit Service 158247
    ret->path = g_strdup (dev->path);
Packit Service 158247
    ret->sector_size = (guint64) dev->sector_size;
Packit Service 158247
    constr = ped_device_get_constraint (dev);
Packit Service 158247
    ret->size = (constr->max_size - 1) * dev->sector_size;
Packit Service 158247
    ped_constraint_destroy (constr);
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (ped_disk) {
Packit Service 158247
        for (type=BD_PART_TABLE_MSDOS; !found && type < BD_PART_TABLE_UNDEF; type++) {
Packit Service 158247
            if (g_strcmp0 (ped_disk->type->name, table_type_str[type]) == 0) {
Packit Service 158247
                ret->table_type = type;
Packit Service 158247
                found = TRUE;
Packit Service 158247
            }
Packit Service 158247
        }
Packit Service 158247
        if (!found)
Packit Service 158247
            ret->table_type = BD_PART_TABLE_UNDEF;
Packit Service 158247
        if (ped_disk_is_flag_available (ped_disk, PED_DISK_GPT_PMBR_BOOT) &&
Packit Service 158247
            ped_disk_get_flag (ped_disk, PED_DISK_GPT_PMBR_BOOT))
Packit Service 158247
            ret->flags = BD_PART_DISK_FLAG_GPT_PMBR_BOOT;
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
    } else {
Packit Service 158247
        ret->table_type = BD_PART_TABLE_UNDEF;
Packit Service 158247
        ret->flags = 0;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
static BDPartSpec** get_disk_parts (const gchar *disk, guint64 incl, guint64 excl, gboolean incl_normal, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedPartition *ped_part = NULL;
Packit Service 158247
    guint num_parts = 0;
Packit Service 158247
    BDPartSpec **ret = NULL;
Packit Service 158247
    guint i = 0;
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    /* count the partitions we care about */
Packit Service 158247
    ped_part = ped_disk_next_partition (ped_disk, NULL);
Packit Service 158247
    while (ped_part) {
Packit Service 158247
        if (((ped_part->type & incl) && !(ped_part->type & excl)) ||
Packit Service 158247
            ((ped_part->type == 0) && incl_normal))
Packit Service 158247
            num_parts++;
Packit Service 158247
        ped_part = ped_disk_next_partition (ped_disk, ped_part);
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ret = g_new0 (BDPartSpec*, num_parts + 1);
Packit Service 158247
    i = 0;
Packit Service 158247
    ped_part = ped_disk_next_partition (ped_disk, NULL);
Packit Service 158247
    while (ped_part) {
Packit Service 158247
        if (((ped_part->type & incl) && !(ped_part->type & excl)) ||
Packit Service 158247
            ((ped_part->type == 0) && incl_normal))
Packit Service 158247
            ret[i++] = get_part_spec (dev, ped_disk, ped_part, error);
Packit Service 158247
        ped_part = ped_disk_next_partition (ped_disk, ped_part);
Packit Service 158247
    }
Packit Service 158247
    ret[i] = NULL;
Packit Service 158247
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_disk_parts:
Packit Service 158247
 * @disk: disk to get information about partitions for
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer full) (array zero-terminated=1): specs of the partitions from @disk or %NULL in case of error
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_QUERY_TABLE + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
BDPartSpec** bd_part_get_disk_parts (const gchar *disk, GError **error) {
Packit Service 158247
    return get_disk_parts (disk, BD_PART_TYPE_NORMAL|BD_PART_TYPE_LOGICAL|BD_PART_TYPE_EXTENDED,
Packit Service 158247
                           BD_PART_TYPE_FREESPACE|BD_PART_TYPE_METADATA|BD_PART_TYPE_PROTECTED, TRUE, error);
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_disk_free_regions:
Packit Service 158247
 * @disk: disk to get free regions for
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer full) (array zero-terminated=1): specs of the free regions from @disk or %NULL in case of error
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_QUERY_TABLE + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
BDPartSpec** bd_part_get_disk_free_regions (const gchar *disk, GError **error) {
Packit Service 158247
    return get_disk_parts (disk, BD_PART_TYPE_FREESPACE, 0, FALSE, error);
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_best_free_region:
Packit Service 158247
 * @disk: disk to get the best free region for
Packit Service 158247
 * @type: type of the partition that is planned to be added
Packit Service 158247
 * @size: size of the partition to be added
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer full): spec of the best free region on @disk for a new partition of type @type
Packit Service 158247
 *                           with the size of @size or %NULL if there is none such region or if
Packit Service 158247
 *                           there was an error (@error gets populated)
Packit Service 158247
 *
Packit Service 158247
 * Note: For the @type %BD_PART_TYPE_NORMAL, the smallest possible space that *is not* in an extended partition
Packit Service 158247
 *       is found. For the @type %BD_PART_TYPE_LOGICAL, the smallest possible space that *is* in an extended
Packit Service 158247
 *       partition is found. For %BD_PART_TYPE_EXTENDED, the biggest possible space is found as long as there
Packit Service 158247
 *       is no other extended partition (there can only be one).
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_QUERY_TABLE + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
BDPartSpec* bd_part_get_best_free_region (const gchar *disk, BDPartType type, guint64 size, GError **error) {
Packit Service 158247
    BDPartSpec **free_regs = NULL;
Packit Service 158247
    BDPartSpec **free_reg_p = NULL;
Packit Service 158247
    BDPartSpec *ret = NULL;
Packit Service 158247
Packit Service 158247
    free_regs = bd_part_get_disk_free_regions (disk, error);
Packit Service 158247
    if (!free_regs)
Packit Service 158247
        /* error should be populated */
Packit Service 158247
        return NULL;
Packit Service 158247
    if (!(*free_regs)) {
Packit Service 158247
        /* no free regions */
Packit Service 158247
        g_free (free_regs);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (type == BD_PART_TYPE_NORMAL) {
Packit Service 158247
        for (free_reg_p=free_regs; *free_reg_p; free_reg_p++) {
Packit Service 158247
            /* check if it has enough space and is not inside an extended partition */
Packit Service 158247
            if ((*free_reg_p)->size > size && !((*free_reg_p)->type & BD_PART_TYPE_LOGICAL))
Packit Service 158247
                /* if it is the first that would fit or if it is smaller than
Packit Service 158247
                   what we found earlier, it is a better match */
Packit Service 158247
                if (!ret || ((*free_reg_p)->size < ret->size))
Packit Service 158247
                    ret = *free_reg_p;
Packit Service 158247
        }
Packit Service 158247
    } else if (type == BD_PART_TYPE_EXTENDED) {
Packit Service 158247
        for (free_reg_p=free_regs; *free_reg_p; free_reg_p++) {
Packit Service 158247
            /* if there already is an extended partition, there cannot be another one */
Packit Service 158247
            if ((*free_reg_p)->type & BD_PART_TYPE_LOGICAL) {
Packit Service 158247
                for (free_reg_p=free_regs; *free_reg_p; free_reg_p++)
Packit Service 158247
                    bd_part_spec_free (*free_reg_p);
Packit Service 158247
                g_free (free_regs);
Packit Service 158247
                return NULL;
Packit Service 158247
            }
Packit Service 158247
            /* check if it has enough space */
Packit Service 158247
            if ((*free_reg_p)->size > size)
Packit Service 158247
                /* if it is the first that would fit or if it is bigger than
Packit Service 158247
                   what we found earlier, it is a better match */
Packit Service 158247
                if (!ret || ((*free_reg_p)->size > ret->size))
Packit Service 158247
                    ret = *free_reg_p;
Packit Service 158247
        }
Packit Service 158247
    } else if (type == BD_PART_TYPE_LOGICAL) {
Packit Service 158247
        for (free_reg_p=free_regs; *free_reg_p; free_reg_p++) {
Packit Service 158247
            /* check if it has enough space and is inside an extended partition */
Packit Service 158247
            if ((*free_reg_p)->size > size && ((*free_reg_p)->type & BD_PART_TYPE_LOGICAL))
Packit Service 158247
                /* if it is the first that would fit or if it is smaller than
Packit Service 158247
                   what we found earlier, it is a better match */
Packit Service 158247
                if (!ret || ((*free_reg_p)->size < ret->size))
Packit Service 158247
                    ret = *free_reg_p;
Packit Service 158247
        }
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    /* free all the other specs and return the best one */
Packit Service 158247
    for (free_reg_p=free_regs; *free_reg_p; free_reg_p++)
Packit Service 158247
        if (*free_reg_p != ret)
Packit Service 158247
            bd_part_spec_free (*free_reg_p);
Packit Service 158247
    g_free (free_regs);
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
static PedConstraint* prepare_alignment_constraint (PedDevice *dev, PedDisk *disk, BDPartAlign align, gint *orig_flag_state) {
Packit Service 158247
    if (align == BD_PART_ALIGN_OPTIMAL) {
Packit Service 158247
        /* cylinder alignment does really weird things when turned on, let's not
Packit Service 158247
           deal with it in 21st century (the flag is reset back in the end) */
Packit Service 158247
        if (ped_disk_is_flag_available (disk, PED_DISK_CYLINDER_ALIGNMENT)) {
Packit Service 158247
            *orig_flag_state = ped_disk_get_flag (disk, PED_DISK_CYLINDER_ALIGNMENT);
Packit Service 158247
            ped_disk_set_flag (disk, PED_DISK_CYLINDER_ALIGNMENT, 0);
Packit Service 158247
        }
Packit Service 158247
        return ped_device_get_optimal_aligned_constraint (dev);
Packit Service 158247
    } else if (align == BD_PART_ALIGN_MINIMAL)
Packit Service 158247
        return ped_device_get_minimal_aligned_constraint (dev);
Packit Service 158247
    else
Packit Service 158247
        return NULL;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
static void finish_alignment_constraint (PedDisk *disk, gint orig_flag_state) {
Packit Service 158247
    if (ped_disk_is_flag_available (disk, PED_DISK_CYLINDER_ALIGNMENT)) {
Packit Service 158247
        ped_disk_set_flag (disk, PED_DISK_CYLINDER_ALIGNMENT, orig_flag_state);
Packit Service 158247
    }
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
static gboolean resize_part (PedPartition *part, PedDevice *dev, PedDisk *disk, guint64 size, BDPartAlign align, GError **error) {
Packit Service 158247
    PedConstraint *constr = NULL;
Packit Service 158247
    PedGeometry *geom;
Packit Service 158247
    gint orig_flag_state = 0;
Packit Service 158247
    PedSector start;
Packit Service 158247
    PedSector end;
Packit Service 158247
    PedSector max_end;
Packit Service 158247
    PedSector new_size = 0;
Packit Service 158247
    gint status = 0;
Packit Service 158247
    PedSector tolerance = 0;
Packit Service 158247
Packit Service 158247
    /* It should be possible to pass the whole drive size a partition size,
Packit Service 158247
     * so -1 MiB for the first partition alignment,
Packit Service 158247
     * -1 MiB for creating this here as a logial partition
Packit Service 158247
     * and -1 MiB for end alingment.
Packit Service 158247
     * But only if the caller doesn't request no alignment which also means
Packit Service 158247
     * they strictly care about precise numbers. */
Packit Service 158247
    if (align != BD_PART_ALIGN_NONE)
Packit Service 158247
        tolerance = (PedSector) (4 MiB /  dev->sector_size);
Packit Service 158247
Packit Service 158247
    constr = prepare_alignment_constraint (dev, disk, align, &orig_flag_state);
Packit Service 158247
    start = part->geom.start;
Packit Service 158247
Packit Service 158247
    if (!constr)
Packit Service 158247
        constr = ped_constraint_any (dev);
Packit Service 158247
Packit Service 158247
    geom = ped_disk_get_max_partition_geometry (disk, part, constr);
Packit Service 158247
    if (!ped_geometry_set_start (geom, start)) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to set partition start on device '%s'", dev->path);
Packit Service 158247
        ped_constraint_destroy (constr);
Packit Service 158247
        ped_geometry_destroy (geom);
Packit Service 158247
        finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
    if (size == 0) {
Packit Service 158247
        new_size = geom->length;
Packit Service 158247
    } else {
Packit Service 158247
        new_size = (size + dev->sector_size - 1) / dev->sector_size;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    /* If the maximum partition geometry is smaller than the requested size, but
Packit Service 158247
       the difference is acceptable, just adapt the size. */
Packit Service 158247
    if (new_size > geom->length && (new_size - geom->length) < tolerance)
Packit Service 158247
        new_size = geom->length;
Packit Service 158247
Packit Service 158247
    max_end = geom->end;
Packit Service 158247
    ped_geometry_destroy (geom);
Packit Service 158247
    geom = ped_geometry_new (dev, start, new_size);
Packit Service 158247
    if (!geom) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to create geometry for partition on device '%s'", dev->path);
Packit Service 158247
        ped_constraint_destroy (constr);
Packit Service 158247
        finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (size != 0) {
Packit Service 158247
        end = ped_alignment_align_up (constr->end_align, constr->end_range, geom->end);
Packit Service 158247
        if (end > max_end && end < max_end + tolerance) {
Packit Service 158247
            end = max_end;
Packit Service 158247
        }
Packit Service 158247
    } else {
Packit Service 158247
        end = geom->end;
Packit Service 158247
    }
Packit Service 158247
    ped_constraint_destroy (constr);
Packit Service 158247
    if (!ped_geometry_set_end (geom, end)) {
Packit Service 158247
       set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
       g_prefix_error (error, "Failed to change geometry for partition on device '%s'", dev->path);
Packit Service 158247
       ped_constraint_destroy (constr);
Packit Service 158247
       ped_geometry_destroy (geom);
Packit Service 158247
       finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
       return FALSE;
Packit Service 158247
    }
Packit Service 158247
    constr = ped_constraint_exact (geom);
Packit Service 158247
    status = ped_disk_set_partition_geom (disk, part, constr, start, end);
Packit Service 158247
Packit Service 158247
    if (status == 0) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to set partition size on device '%s'", dev->path);
Packit Service 158247
        ped_geometry_destroy (geom);
Packit Service 158247
        ped_constraint_destroy (constr);
Packit Service 158247
        finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
        return FALSE;
Packit Service 158247
    } else if (part->geom.start != start) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_FAIL, "Failed to meet partition start on device '%s'", dev->path);
Packit Service 158247
        ped_geometry_destroy (geom);
Packit Service 158247
        ped_constraint_destroy (constr);
Packit Service 158247
        finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
        return FALSE;
Packit Service 158247
    } else if (part->geom.length < new_size - tolerance) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_FAIL, "Failed to meet partition size on device '%s'", dev->path);
Packit Service 158247
        ped_geometry_destroy (geom);
Packit Service 158247
        ped_constraint_destroy (constr);
Packit Service 158247
        finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_geometry_destroy (geom);
Packit Service 158247
    ped_constraint_destroy (constr);
Packit Service 158247
    finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
    return TRUE;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
static PedPartition* add_part_to_disk (PedDevice *dev, PedDisk *disk, BDPartTypeReq type, guint64 start, guint64 size, BDPartAlign align, GError **error) {
Packit Service 158247
    PedPartition *part = NULL;
Packit Service 158247
    PedConstraint *constr = NULL;
Packit Service 158247
    PedGeometry *geom;
Packit Service 158247
    gint orig_flag_state = 0;
Packit Service 158247
    gint status = 0;
Packit Service 158247
Packit Service 158247
    /* convert start to sectors */
Packit Service 158247
    start = (start + (guint64)dev->sector_size - 1) / dev->sector_size;
Packit Service 158247
Packit Service 158247
    constr = prepare_alignment_constraint (dev, disk, align, &orig_flag_state);
Packit Service 158247
Packit Service 158247
    if (constr)
Packit Service 158247
        start = ped_alignment_align_up (constr->start_align, constr->start_range, (PedSector) start);
Packit Service 158247
Packit Service 158247
    geom = ped_geometry_new (dev, (PedSector) start, (PedSector) 1 MiB / dev->sector_size);
Packit Service 158247
    if (!geom) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to create geometry for a new partition on device '%s'", dev->path);
Packit Service 158247
        ped_constraint_destroy (constr);
Packit Service 158247
        finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part = ped_partition_new (disk, (PedPartitionType)type, NULL, geom->start, geom->end);
Packit Service 158247
    if (!part) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to create new partition on device '%s'", dev->path);
Packit Service 158247
        ped_constraint_destroy (constr);
Packit Service 158247
        ped_geometry_destroy (geom);
Packit Service 158247
        finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (!constr)
Packit Service 158247
        constr = ped_constraint_exact (geom);
Packit Service 158247
Packit Service 158247
    status = ped_disk_add_partition (disk, part, constr);
Packit Service 158247
    if (status == 0) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed add partition to device '%s'", dev->path);
Packit Service 158247
        ped_geometry_destroy (geom);
Packit Service 158247
        ped_constraint_destroy (constr);
Packit Service 158247
        ped_partition_destroy (part);
Packit Service 158247
        finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (!resize_part (part, dev, disk, size, align, error)) {
Packit Service 158247
        ped_geometry_destroy (geom);
Packit Service 158247
        ped_constraint_destroy (constr);
Packit Service 158247
        ped_disk_delete_partition (disk, part);
Packit Service 158247
        finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    finish_alignment_constraint (disk, orig_flag_state);
Packit Service 158247
    ped_geometry_destroy (geom);
Packit Service 158247
    ped_constraint_destroy (constr);
Packit Service 158247
Packit Service 158247
    return part;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_create_part:
Packit Service 158247
 * @disk: disk to create partition on
Packit Service 158247
 * @type: type of the partition to create (if %BD_PART_TYPE_REQ_NEXT, the
Packit Service 158247
 *        partition type will be determined automatically based on the existing
Packit Service 158247
 *        partitions)
Packit Service 158247
 * @start: where the partition should start (i.e. offset from the disk start)
Packit Service 158247
 * @size: desired size of the partition (if 0, a max-sized partition is created)
Packit Service 158247
 * @align: alignment to use for the partition
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer full): specification of the created partition or %NULL in case of error
Packit Service 158247
 *
Packit Service 158247
 * NOTE: The resulting partition may start at a different position than given by
Packit Service 158247
 *       @start and can have different size than @size due to alignment.
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_MODIFY_TABLE + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
BDPartSpec* bd_part_create_part (const gchar *disk, BDPartTypeReq type, guint64 start, guint64 size, BDPartAlign align, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedPartition *ped_part = NULL;
Packit Service 158247
    PedPartition *ext_part = NULL;
Packit Service 158247
    PedSector start_sector = 0;
Packit Service 158247
    gint last_num = 0;
Packit Service 158247
    gboolean succ = FALSE;
Packit Service 158247
    BDPartSpec *ret = NULL;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Started adding partition to '%s'", disk);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (type == BD_PART_TYPE_REQ_NEXT) {
Packit Service 158247
        ext_part = ped_disk_extended_partition (ped_disk);
Packit Service 158247
        start_sector = (PedSector) (start + dev->sector_size - 1) / dev->sector_size;
Packit Service 158247
        if (ext_part && (start_sector > ext_part->geom.start) && (start_sector < ext_part->geom.end)) {
Packit Service 158247
            /* partition's start is in the extended partition -> must be logical */
Packit Service 158247
            type = BD_PART_TYPE_REQ_LOGICAL;
Packit Service 158247
        } else if ((ped_disk_get_max_primary_partition_count (ped_disk) - 1 > ped_disk_get_primary_partition_count (ped_disk)) || ext_part) {
Packit Service 158247
            /* we have room for another primary partition or there already is an extended partition -> should/must be primary */
Packit Service 158247
            type = BD_PART_TYPE_REQ_NORMAL;
Packit Service 158247
        } else {
Packit Service 158247
            ped_part = add_part_to_disk (dev, ped_disk, BD_PART_TYPE_REQ_EXTENDED, start, 0, align, error);
Packit Service 158247
            if (!ped_part) {
Packit Service 158247
                /* error is already populated */
Packit Service 158247
                ped_disk_destroy (ped_disk);
Packit Service 158247
                ped_device_destroy (dev);
Packit Service 158247
                bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
                return NULL;
Packit Service 158247
            }
Packit Service 158247
            type = BD_PART_TYPE_REQ_LOGICAL;
Packit Service 158247
        }
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (type == BD_PART_TYPE_REQ_LOGICAL) {
Packit Service 158247
        /* Find the previous logical partition (if there's any) because we need
Packit Service 158247
           its end. If there's no such logical partition, we are creating the
Packit Service 158247
           first one and thus should only care about the extended partition's
Packit Service 158247
           start*/
Packit Service 158247
        last_num = ped_disk_get_last_partition_num (ped_disk);
Packit Service 158247
        ped_part = ped_disk_get_partition (ped_disk, last_num);
Packit Service 158247
        while (ped_part && (ped_part->type != PED_PARTITION_EXTENDED) &&
Packit Service 158247
               (ped_part->geom.start > (PedSector) (start / dev->sector_size)))
Packit Service 158247
            ped_part = ped_part->prev;
Packit Service 158247
Packit Service 158247
        if (!ped_part) {
Packit Service 158247
            g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                         "Failed to find suitable free region for a new logical partition.");
Packit Service 158247
            ped_disk_destroy (ped_disk);
Packit Service 158247
            ped_device_destroy (dev);
Packit Service 158247
            bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
            return NULL;
Packit Service 158247
        }
Packit Service 158247
Packit Service 158247
        if (ped_part->type == PED_PARTITION_EXTENDED) {
Packit Service 158247
            /* can at minimal start where the first logical partition can start - the start of the extended partition + 1 MiB aligned up */
Packit Service 158247
            if (start < ((ped_part->geom.start * dev->sector_size) + 1 MiB + dev->sector_size - 1))
Packit Service 158247
                start = (ped_part->geom.start * dev->sector_size) + 1 MiB + dev->sector_size - 1;
Packit Service 158247
        } else {
Packit Service 158247
            /* can at minimal start where the next logical partition can start - the end of the previous partition + 1 MiB aligned up */
Packit Service 158247
            if (start < ((ped_part->geom.end * dev->sector_size) + 1 MiB + dev->sector_size - 1))
Packit Service 158247
                start = (ped_part->geom.end * dev->sector_size) + 1 MiB + dev->sector_size - 1;
Packit Service 158247
        }
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_part = add_part_to_disk (dev, ped_disk, type, start, size, align, error);
Packit Service 158247
    if (!ped_part) {
Packit Service 158247
        /* error is already populated */
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    succ = disk_commit (ped_disk, disk, error);
Packit Service 158247
    if (succ)
Packit Service 158247
        ret = get_part_spec (dev, ped_disk, ped_part, error);
Packit Service 158247
Packit Service 158247
    /* the partition gets destroyed together with the disk*/
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_delete_part:
Packit Service 158247
 * @disk: disk to remove the partition from
Packit Service 158247
 * @part: partition to remove
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the @part partition was successfully deleted from @disk
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_MODIFY_TABLE + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_delete_part (const gchar *disk, const gchar *part, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedPartition *ped_part = NULL;
Packit Service 158247
    const gchar *part_num_str = NULL;
Packit Service 158247
    gint part_num = 0;
Packit Service 158247
    gint status = 0;
Packit Service 158247
    gboolean ret = FALSE;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Started deleting partition '%s'", part);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    if (!part || (part && (*part == '\0'))) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'", part);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part_num_str = part + (strlen (part) - 1);
Packit Service 158247
    while (isdigit (*part_num_str) || (*part_num_str == '-')) {
Packit Service 158247
        part_num_str--;
Packit Service 158247
    }
Packit Service 158247
    part_num_str++;
Packit Service 158247
Packit Service 158247
    part_num = atoi (part_num_str);
Packit Service 158247
    if (part_num == 0) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'. Cannot extract partition number", part);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_part = ped_disk_get_partition (ped_disk, part_num);
Packit Service 158247
    if (!ped_part) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to get partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    status = ped_disk_delete_partition (ped_disk, ped_part);
Packit Service 158247
    if (status == 0) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to delete partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ret = disk_commit (ped_disk, disk, error);
Packit Service 158247
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_resize_part:
Packit Service 158247
 * @disk: disk containing the paritition
Packit Service 158247
 * @part: partition to resize
Packit Service 158247
 * @size: new partition size, 0 for maximal size
Packit Service 158247
 * @align: alignment to use for the partition end
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the @part partition was successfully resized on @disk to @size
Packit Service 158247
 *
Packit Service 158247
 * NOTE: The resulting partition may be slightly bigger than requested due to alignment.
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_MODIFY_TABLE + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_resize_part (const gchar *disk, const gchar *part, guint64 size, BDPartAlign align, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedPartition *ped_part = NULL;
Packit Service 158247
    const gchar *part_num_str = NULL;
Packit Service 158247
    gint part_num = 0;
Packit Service 158247
    gboolean ret = FALSE;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
    guint64 old_size = 0;
Packit Service 158247
    guint64 new_size = 0;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Started resizing partition '%s'", part);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    if (!part || (part && (*part == '\0'))) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'", part);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part_num_str = part + (strlen (part) - 1);
Packit Service 158247
    while (isdigit (*part_num_str) || (*part_num_str == '-')) {
Packit Service 158247
        part_num_str--;
Packit Service 158247
    }
Packit Service 158247
    part_num_str++;
Packit Service 158247
Packit Service 158247
    part_num = atoi (part_num_str);
Packit Service 158247
    if (part_num == 0) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'. Cannot extract partition number", part);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_part = ped_disk_get_partition (ped_disk, part_num);
Packit Service 158247
    if (!ped_part) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to get partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    old_size = ped_part->geom.length * dev->sector_size;
Packit Service 158247
    if (!resize_part (ped_part, dev, ped_disk, size, align, error)) {
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    new_size = ped_part->geom.length * dev->sector_size;
Packit Service 158247
    if (old_size != new_size) {
Packit Service 158247
        gint fd = 0;
Packit Service 158247
        gint wait_us = 10 * 1000 * 1000; /* 10 seconds */
Packit Service 158247
        gint step_us = 100 * 1000; /* 100 microseconds */
Packit Service 158247
        guint64 block_size = 0;
Packit Service 158247
Packit Service 158247
        ret = disk_commit (ped_disk, disk, error);
Packit Service 158247
        /* wait for partition to appear with new size */
Packit Service 158247
        while (wait_us > 0) {
Packit Service 158247
            fd = open (part, O_RDONLY);
Packit Service 158247
            if (fd != -1) {
Packit Service 158247
                if (ioctl (fd, BLKGETSIZE64, &block_size) != -1 && block_size == new_size) {
Packit Service 158247
                    close (fd);
Packit Service 158247
                    break;
Packit Service 158247
                }
Packit Service 158247
Packit Service 158247
                close (fd);
Packit Service 158247
            }
Packit Service 158247
Packit Service 158247
            g_usleep (step_us);
Packit Service 158247
            wait_us -= step_us;
Packit Service 158247
        }
Packit Service 158247
    } else {
Packit Service 158247
        ret = TRUE; /* not committing to disk */
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
Packit Service 158247
static gboolean set_gpt_flag (const gchar *device, int part_num, BDPartFlag flag, gboolean state, GError **error) {
Packit Service 158247
    const gchar *args[5] = {"sgdisk", "--attributes", NULL, device, NULL};
Packit Service 158247
    int bit_num = 0;
Packit Service 158247
    gboolean success = FALSE;
Packit Service 158247
Packit Service 158247
    if (!check_deps (&avail_deps, DEPS_SGDISK_MASK, deps, DEPS_LAST, &deps_check_lock, error))
Packit Service 158247
        return FALSE;
Packit Service 158247
Packit Service 158247
    if (flag == BD_PART_FLAG_GPT_SYSTEM_PART)
Packit Service 158247
        bit_num = 0;
Packit Service 158247
    else if (flag == BD_PART_FLAG_LEGACY_BOOT)
Packit Service 158247
        bit_num = 2;
Packit Service 158247
    else if (flag == BD_PART_FLAG_GPT_READ_ONLY)
Packit Service 158247
        bit_num = 60;
Packit Service 158247
    else if (flag == BD_PART_FLAG_GPT_HIDDEN)
Packit Service 158247
        bit_num = 62;
Packit Service 158247
    else if (flag == BD_PART_FLAG_GPT_NO_AUTOMOUNT)
Packit Service 158247
        bit_num = 63;
Packit Service 158247
Packit Service 158247
    args[2] = g_strdup_printf ("%d:%s:%d", part_num, state ? "set" : "clear", bit_num);
Packit Service 158247
Packit Service 158247
    success = bd_utils_exec_and_report_error (args, NULL, error);
Packit Service 158247
    g_free ((gchar *) args[2]);
Packit Service 158247
    return success;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
static gboolean set_gpt_flags (const gchar *device, int part_num, guint64 flags, GError **error) {
Packit Service 158247
    const gchar *args[5] = {"sgdisk", "--attributes", NULL, device, NULL};
Packit Service 158247
    guint64 real_flags = 0;
Packit Service 158247
    gchar *mask_str = NULL;
Packit Service 158247
    gboolean success = FALSE;
Packit Service 158247
Packit Service 158247
    if (!check_deps (&avail_deps, DEPS_SGDISK_MASK, deps, DEPS_LAST, &deps_check_lock, error))
Packit Service 158247
        return FALSE;
Packit Service 158247
Packit Service 158247
    if (flags & BD_PART_FLAG_GPT_SYSTEM_PART)
Packit Service 158247
        real_flags |=  1;       /* 1 << 0 */
Packit Service 158247
    if (flags & BD_PART_FLAG_LEGACY_BOOT)
Packit Service 158247
        real_flags |=  4;       /* 1 << 2 */
Packit Service 158247
    if (flags & BD_PART_FLAG_GPT_READ_ONLY)
Packit Service 158247
        real_flags |= 0x1000000000000000; /* 1 << 60 */
Packit Service 158247
    if (flags & BD_PART_FLAG_GPT_HIDDEN)
Packit Service 158247
        real_flags |= 0x4000000000000000; /* 1 << 62 */
Packit Service 158247
    if (flags & BD_PART_FLAG_GPT_NO_AUTOMOUNT)
Packit Service 158247
        real_flags |= 0x8000000000000000; /* 1 << 63 */
Packit Service 158247
    mask_str = g_strdup_printf ("%.16"PRIx64, real_flags);
Packit Service 158247
Packit Service 158247
    args[2] = g_strdup_printf ("%d:=:%s", part_num, mask_str);
Packit Service 158247
    g_free (mask_str);
Packit Service 158247
Packit Service 158247
    success = bd_utils_exec_and_report_error (args, NULL, error);
Packit Service 158247
    g_free ((gchar *) args[2]);
Packit Service 158247
    return success;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_set_part_flag:
Packit Service 158247
 * @disk: disk the partition belongs to
Packit Service 158247
 * @part: partition to set the flag on
Packit Service 158247
 * @flag: flag to set
Packit Service 158247
 * @state: state to set for the @flag (%TRUE = enabled)
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the flag @flag was successfully set on the @part partition
Packit Service 158247
 * or not.
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_MODIFY_PART + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_set_part_flag (const gchar *disk, const gchar *part, BDPartFlag flag, gboolean state, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedPartition *ped_part = NULL;
Packit Service 158247
    PedPartitionFlag ped_flag = PED_PARTITION_FIRST_FLAG;
Packit Service 158247
    const gchar *part_num_str = NULL;
Packit Service 158247
    gint part_num = 0;
Packit Service 158247
    gint status = 0;
Packit Service 158247
    gboolean ret = FALSE;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Started setting flag on the partition '%s'", part);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    /* TODO: share this code with the other functions modifying a partition */
Packit Service 158247
    if (!part || (part && (*part == '\0'))) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'", part);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part_num_str = part + (strlen (part) - 1);
Packit Service 158247
    while (isdigit (*part_num_str) || (*part_num_str == '-')) {
Packit Service 158247
        part_num_str--;
Packit Service 158247
    }
Packit Service 158247
    part_num_str++;
Packit Service 158247
Packit Service 158247
    part_num = atoi (part_num_str);
Packit Service 158247
    if (part_num == 0) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'. Cannot extract partition number", part);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_part = ped_disk_get_partition (ped_disk, part_num);
Packit Service 158247
    if (!ped_part) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to get partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    /* our flags are 1s shifted to the bit determined by parted's flags
Packit Service 158247
     * (i.e. 1 << 3 instead of 3, etc.) */
Packit Service 158247
    if (flag < BD_PART_FLAG_BASIC_LAST) {
Packit Service 158247
        ped_flag = (PedPartitionFlag) log2 ((double) flag);
Packit Service 158247
        status = ped_partition_set_flag (ped_part, ped_flag, (int) state);
Packit Service 158247
        if (status == 0) {
Packit Service 158247
            set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
            g_prefix_error (error, "Failed to set flag on partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
            ped_disk_destroy (ped_disk);
Packit Service 158247
            ped_device_destroy (dev);
Packit Service 158247
            bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
            return FALSE;
Packit Service 158247
        }
Packit Service 158247
Packit Service 158247
        ret = disk_commit (ped_disk, disk, error);
Packit Service 158247
    } else {
Packit Service 158247
        if (g_strcmp0 (ped_disk->type->name, "gpt") == 0)
Packit Service 158247
            ret = set_gpt_flag (disk, part_num, flag, state, error);
Packit Service 158247
        else
Packit Service 158247
            g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                         "Cannot set a GPT flag on a non-GPT disk");
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_set_disk_flag:
Packit Service 158247
 * @disk: disk the partition belongs to
Packit Service 158247
 * @flag: flag to set
Packit Service 158247
 * @state: state to set for the @flag (%TRUE = enabled)
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the flag @flag was successfully set on the @disk or not
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_MODIFY_TABLE + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_set_disk_flag (const gchar *disk, BDPartDiskFlag flag, gboolean state, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    gint status = 0;
Packit Service 158247
    gboolean ret = FALSE;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Started setting flag on the disk '%s'", disk);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    /* right now we only support this one flag */
Packit Service 158247
    if (flag == BD_PART_DISK_FLAG_GPT_PMBR_BOOT) {
Packit Service 158247
        status = ped_disk_set_flag (ped_disk, PED_DISK_GPT_PMBR_BOOT, (int) state);
Packit Service 158247
        if (status == 0) {
Packit Service 158247
            set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
            g_prefix_error (error, "Failed to set flag on disk '%s'", disk);
Packit Service 158247
            ped_disk_destroy (ped_disk);
Packit Service 158247
            ped_device_destroy (dev);
Packit Service 158247
            bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
            return FALSE;
Packit Service 158247
        }
Packit Service 158247
Packit Service 158247
        ret = disk_commit (ped_disk, disk, error);
Packit Service 158247
    } else {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid or unsupported flag given: %d", flag);
Packit Service 158247
        ret = FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_set_part_flags:
Packit Service 158247
 * @disk: disk the partition belongs to
Packit Service 158247
 * @part: partition to set the flag on
Packit Service 158247
 * @flags: flags to set (mask combined from #BDPartFlag numbers)
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the @flags were successfully set on the @part partition or
Packit Service 158247
 *          not
Packit Service 158247
 *
Packit Service 158247
 * Note: Unsets all the other flags on the partition.
Packit Service 158247
 *       Only GPT-specific flags and the legacy boot flag are supported on GPT
Packit Service 158247
 *       partition tables.
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_MODIFY_PART + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_set_part_flags (const gchar *disk, const gchar *part, guint64 flags, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedPartition *ped_part = NULL;
Packit Service 158247
    const gchar *part_num_str = NULL;
Packit Service 158247
    gint part_num = 0;
Packit Service 158247
    int i = 0;
Packit Service 158247
    gint status = 0;
Packit Service 158247
    gboolean ret = FALSE;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Started setting flags on the partition '%s'", part);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    /* TODO: share this code with the other functions modifying a partition */
Packit Service 158247
    if (!part || (part && (*part == '\0'))) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'", part);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part_num_str = part + (strlen (part) - 1);
Packit Service 158247
    while (isdigit (*part_num_str) || (*part_num_str == '-')) {
Packit Service 158247
        part_num_str--;
Packit Service 158247
    }
Packit Service 158247
    part_num_str++;
Packit Service 158247
Packit Service 158247
    part_num = atoi (part_num_str);
Packit Service 158247
    if (part_num == 0) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'. Cannot extract partition number", part);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    /* Do not let libparted touch gpt partition tables */
Packit Service 158247
    if (g_strcmp0 (ped_disk->type->name, "gpt") == 0) {
Packit Service 158247
        ret = set_gpt_flags (disk, part_num, flags, error);
Packit Service 158247
    } else {
Packit Service 158247
        ped_part = ped_disk_get_partition (ped_disk, part_num);
Packit Service 158247
        if (!ped_part) {
Packit Service 158247
            set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
            g_prefix_error (error, "Failed to get partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
            ped_disk_destroy (ped_disk);
Packit Service 158247
            ped_device_destroy (dev);
Packit Service 158247
            bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
            return FALSE;
Packit Service 158247
        }
Packit Service 158247
Packit Service 158247
        /* our flags are 1s shifted to the bit determined by parted's flags
Packit Service 158247
         * (i.e. 1 << 3 instead of 3, etc.) */
Packit Service 158247
        for (i=1; i <= (int) log2 ((double)BD_PART_FLAG_BASIC_LAST); i++) {
Packit Service 158247
            if ((1 << i) & flags)
Packit Service 158247
                status = ped_partition_set_flag (ped_part, (PedPartitionFlag) i, (int) 1);
Packit Service 158247
            else if (ped_partition_is_flag_available (ped_part, (PedPartitionFlag) i))
Packit Service 158247
                status = ped_partition_set_flag (ped_part, (PedPartitionFlag) i, (int) 0);
Packit Service 158247
            if (status == 0) {
Packit Service 158247
                set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
                g_prefix_error (error, "Failed to set flag on the partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
                ped_disk_destroy (ped_disk);
Packit Service 158247
                ped_device_destroy (dev);
Packit Service 158247
                bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
                return FALSE;
Packit Service 158247
            }
Packit Service 158247
        }
Packit Service 158247
Packit Service 158247
        ret = disk_commit (ped_disk, disk, error);
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_set_part_name:
Packit Service 158247
 * @disk: device the partition belongs to
Packit Service 158247
 * @part: partition the should be set for
Packit Service 158247
 * @name: name to set
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the name was successfully set or not
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_MODIFY_PART + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_set_part_name (const gchar *disk, const gchar *part, const gchar *name, GError **error) {
Packit Service 158247
    PedDevice *dev = NULL;
Packit Service 158247
    PedDisk *ped_disk = NULL;
Packit Service 158247
    PedPartition *ped_part = NULL;
Packit Service 158247
    const gchar *part_num_str = NULL;
Packit Service 158247
    gint part_num = 0;
Packit Service 158247
    gint status = 0;
Packit Service 158247
    gboolean ret = FALSE;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Started setting name on the partition '%s'", part);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    /* TODO: share this code with the other functions modifying a partition */
Packit Service 158247
    if (!part || (part && (*part == '\0'))) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'", part);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    dev = ped_device_get (disk);
Packit Service 158247
    if (!dev) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_INVAL);
Packit Service 158247
        g_prefix_error (error, "Device '%s' invalid or not existing", disk);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_disk = ped_disk_new (dev);
Packit Service 158247
    if (!ped_disk) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to read partition table on device '%s'", disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
    if (!(ped_disk->type->features & PED_DISK_TYPE_PARTITION_NAME)) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Partition names unsupported on the device '%s' ('%s')", disk,
Packit Service 158247
                     ped_disk->type->name);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part_num_str = part + (strlen (part) - 1);
Packit Service 158247
    while (isdigit (*part_num_str) || (*part_num_str == '-')) {
Packit Service 158247
        part_num_str--;
Packit Service 158247
    }
Packit Service 158247
    part_num_str++;
Packit Service 158247
Packit Service 158247
    part_num = atoi (part_num_str);
Packit Service 158247
    if (part_num == 0) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'. Cannot extract partition number", part);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ped_part = ped_disk_get_partition (ped_disk, part_num);
Packit Service 158247
    if (!ped_part) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to get partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    status = ped_partition_set_name (ped_part, name);
Packit Service 158247
    if (status == 0) {
Packit Service 158247
        set_parted_error (error, BD_PART_ERROR_FAIL);
Packit Service 158247
        g_prefix_error (error, "Failed to set name on the partition '%d' on device '%s'", part_num, disk);
Packit Service 158247
        ped_disk_destroy (ped_disk);
Packit Service 158247
        ped_device_destroy (dev);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    ret = disk_commit (ped_disk, disk, error);
Packit Service 158247
Packit Service 158247
    ped_disk_destroy (ped_disk);
Packit Service 158247
    ped_device_destroy (dev);
Packit Service 158247
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_set_part_type:
Packit Service 158247
 * @disk: device the partition belongs to
Packit Service 158247
 * @part: partition the should be set for
Packit Service 158247
 * @type_guid: GUID of the type
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the @type_guid type was successfully set for @part or not
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_GPT-%BD_PART_TECH_MODE_MODIFY_PART
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_set_part_type (const gchar *disk, const gchar *part, const gchar *type_guid, GError **error) {
Packit Service 158247
    const gchar *args[5] = {"sgdisk", "--typecode", NULL, disk, NULL};
Packit Service 158247
    const gchar *part_num_str = NULL;
Packit Service 158247
    gboolean success = FALSE;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
Packit Service 158247
    if (!check_deps (&avail_deps, DEPS_SGDISK_MASK, deps, DEPS_LAST, &deps_check_lock, error))
Packit Service 158247
        return FALSE;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Started setting type on the partition '%s'", part);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    if (!part || (part && (*part == '\0'))) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'", part);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part_num_str = part + (strlen (part) - 1);
Packit Service 158247
    while (isdigit (*part_num_str) || (*part_num_str == '-')) {
Packit Service 158247
        part_num_str--;
Packit Service 158247
    }
Packit Service 158247
    part_num_str++;
Packit Service 158247
Packit Service 158247
    if ((g_strcmp0 (part_num_str, "0") != 0) && (atoi (part_num_str) == 0)) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'. Cannot extract partition number", part);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    args[2] = g_strdup_printf ("%s:%s", part_num_str, type_guid);
Packit Service 158247
Packit Service 158247
    success = bd_utils_exec_and_report_error (args, NULL, error);
Packit Service 158247
    g_free ((gchar*) args[2]);
Packit Service 158247
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    return success;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_set_part_id:
Packit Service 158247
 * @disk: device the partition belongs to
Packit Service 158247
 * @part: partition the should be set for
Packit Service 158247
 * @part_id: partition Id
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: whether the @part_id type was successfully set for @part or not
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_MODIFY_PART + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
gboolean bd_part_set_part_id (const gchar *disk, const gchar *part, const gchar *part_id, GError **error) {
Packit Service 158247
    const gchar *args[6] = {"sfdisk", "--id", disk, NULL, part_id, NULL};
Packit Service 158247
    const gchar *part_num_str = NULL;
Packit Service 158247
    gboolean success = FALSE;
Packit Service 158247
    guint64 progress_id = 0;
Packit Service 158247
    guint64 part_id_int = 0;
Packit Service 158247
    gchar *msg = NULL;
Packit Service 158247
Packit Service 158247
    if (!check_deps (&avail_deps, DEPS_SFDISK_MASK, deps, DEPS_LAST, &deps_check_lock, error))
Packit Service 158247
        return FALSE;
Packit Service 158247
Packit Service 158247
    msg = g_strdup_printf ("Started setting id on the partition '%s'", part);
Packit Service 158247
    progress_id = bd_utils_report_started (msg);
Packit Service 158247
    g_free (msg);
Packit Service 158247
Packit Service 158247
    if (!part || (part && (*part == '\0'))) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'", part);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part_num_str = part + (strlen (part) - 1);
Packit Service 158247
    while (isdigit (*part_num_str) || (*part_num_str == '-')) {
Packit Service 158247
        part_num_str--;
Packit Service 158247
    }
Packit Service 158247
    part_num_str++;
Packit Service 158247
Packit Service 158247
    part_id_int = g_ascii_strtoull (part_id, NULL, 0);
Packit Service 158247
Packit Service 158247
    if (part_id_int == 0) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition id given: '%s'.", part_id);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if (part_id_int == 0x05 || part_id_int == 0x0f || part_id_int == 0x85) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Cannot change partition id to extended.");
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    if ((g_strcmp0 (part_num_str, "0") != 0) && (atoi (part_num_str) == 0)) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'. Cannot extract partition number", part);
Packit Service 158247
        bd_utils_report_finished (progress_id, (*error)->message);
Packit Service 158247
        return FALSE;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    args[3] = g_strdup (part_num_str);
Packit Service 158247
Packit Service 158247
    success = bd_utils_exec_and_report_error (args, NULL, error);
Packit Service 158247
    g_free ((gchar*) args[3]);
Packit Service 158247
Packit Service 158247
    bd_utils_report_finished (progress_id, "Completed");
Packit Service 158247
Packit Service 158247
    return success;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_part_id:
Packit Service 158247
 * @disk: device the partition belongs to
Packit Service 158247
 * @part: partition the should be set for
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns (transfer full): partition id type or %NULL in case of error
Packit Service 158247
 *
Packit Service 158247
 * Tech category: %BD_PART_TECH_MODE_QUERY_PART + the tech according to the partition table type
Packit Service 158247
 */
Packit Service 158247
gchar* bd_part_get_part_id (const gchar *disk, const gchar *part, GError **error) {
Packit Service 158247
    const gchar *args[5] = {"sfdisk", "--id", disk, NULL, NULL};
Packit Service 158247
    const gchar *part_num_str = NULL;
Packit Service 158247
    gchar *output = NULL;
Packit Service 158247
    gchar *ret = NULL;
Packit Service 158247
    gboolean success = FALSE;
Packit Service 158247
Packit Service 158247
    if (!check_deps (&avail_deps, DEPS_SFDISK_MASK, deps, DEPS_LAST, &deps_check_lock, error))
Packit Service 158247
        return FALSE;
Packit Service 158247
Packit Service 158247
    if (!part || (part && (*part == '\0'))) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'", part);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    part_num_str = part + (strlen (part) - 1);
Packit Service 158247
    while (isdigit (*part_num_str) || (*part_num_str == '-')) {
Packit Service 158247
        part_num_str--;
Packit Service 158247
    }
Packit Service 158247
    part_num_str++;
Packit Service 158247
Packit Service 158247
    if ((g_strcmp0 (part_num_str, "0") != 0) && (atoi (part_num_str) == 0)) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition path given: '%s'. Cannot extract partition number", part);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    args[3] = g_strdup (part_num_str);
Packit Service 158247
Packit Service 158247
    success = bd_utils_exec_and_capture_output (args, NULL, &output, error);
Packit Service 158247
    if (!success) {
Packit Service 158247
        g_free ((gchar *) args[3]);
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    output =  g_strstrip (output);
Packit Service 158247
    ret = g_strdup_printf ("0x%s", output);
Packit Service 158247
Packit Service 158247
    g_free (output);
Packit Service 158247
    g_free ((gchar*) args[3]);
Packit Service 158247
Packit Service 158247
    return ret;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_part_table_type_str:
Packit Service 158247
 * @type: table type to get string representation for
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer none): string representation of @table_type
Packit Service 158247
 *
Packit Service 158247
 * Tech category: the tech according to @type
Packit Service 158247
 */
Packit Service 158247
const gchar* bd_part_get_part_table_type_str (BDPartTableType type, GError **error) {
Packit Service 158247
    if (type >= BD_PART_TABLE_UNDEF) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL,
Packit Service 158247
                     "Invalid partition table type given");
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    return table_type_str[type];
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_flag_str:
Packit Service 158247
 * @flag: flag to get string representation for
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer none): string representation of @flag
Packit Service 158247
 *
Packit Service 158247
 * Tech category: always available
Packit Service 158247
 */
Packit Service 158247
const gchar* bd_part_get_flag_str (BDPartFlag flag, GError **error) {
Packit Service 158247
    if (flag < BD_PART_FLAG_BASIC_LAST)
Packit Service 158247
        return ped_partition_flag_get_name ((PedPartitionFlag) log2 ((double) flag));
Packit Service 158247
    if (flag == BD_PART_FLAG_GPT_SYSTEM_PART)
Packit Service 158247
        return "system partition";
Packit Service 158247
    if (flag == BD_PART_FLAG_GPT_READ_ONLY)
Packit Service 158247
        return "read-only";
Packit Service 158247
    if (flag == BD_PART_FLAG_GPT_HIDDEN)
Packit Service 158247
        return "hidden";
Packit Service 158247
    if (flag == BD_PART_FLAG_GPT_NO_AUTOMOUNT)
Packit Service 158247
        return "do not automount";
Packit Service 158247
Packit Service 158247
    /* no other choice */
Packit Service 158247
    g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL, "Invalid flag given");
Packit Service 158247
    return NULL;
Packit Service 158247
}
Packit Service 158247
Packit Service 158247
/**
Packit Service 158247
 * bd_part_get_type_str:
Packit Service 158247
 * @type: type to get string representation for
Packit Service 158247
 * @error: (out): place to store error (if any)
Packit Service 158247
 *
Packit Service 158247
 * Returns: (transfer none): string representation of @type
Packit Service 158247
 *
Packit Service 158247
 * Tech category: always available
Packit Service 158247
 */
Packit Service 158247
const gchar* bd_part_get_type_str (BDPartType type, GError **error) {
Packit Service 158247
    if (type > BD_PART_TYPE_PROTECTED) {
Packit Service 158247
        g_set_error (error, BD_PART_ERROR, BD_PART_ERROR_INVAL, "Invalid partition type given");
Packit Service 158247
        return NULL;
Packit Service 158247
    }
Packit Service 158247
Packit Service 158247
    return ped_partition_type_get_name ((PedPartitionType) type);
Packit Service 158247
}