|
Packit |
2ba279 |
/*
|
|
Packit |
2ba279 |
* Copyright (C) 2014 Red Hat, Inc.
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
2ba279 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
2ba279 |
* License as published by the Free Software Foundation; either
|
|
Packit |
2ba279 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
2ba279 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
2ba279 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
2ba279 |
* Lesser General Public License for more details.
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
2ba279 |
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Author: Vratislav Podzimek <vpodzime@redhat.com>
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
#include <glib.h>
|
|
Packit |
2ba279 |
#include <unistd.h>
|
|
Packit |
2ba279 |
#include <glob.h>
|
|
Packit |
2ba279 |
#include <string.h>
|
|
Packit |
2ba279 |
#include <fcntl.h>
|
|
Packit |
2ba279 |
#include <sys/ioctl.h>
|
|
Packit |
2ba279 |
#include <linux/loop.h>
|
|
Packit |
2ba279 |
#include <blockdev/utils.h>
|
|
Packit |
2ba279 |
#include "loop.h"
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* SECTION: loop
|
|
Packit |
2ba279 |
* @short_description: plugin for operations with loop devices
|
|
Packit |
2ba279 |
* @title: Loop
|
|
Packit |
2ba279 |
* @include: loop.h
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* A plugin for operations with loop devices. All sizes passed
|
|
Packit |
2ba279 |
* in/out to/from the functions are in bytes.
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
static GMutex loop_control_lock;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_error_quark: (skip)
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
GQuark bd_loop_error_quark (void)
|
|
Packit |
2ba279 |
{
|
|
Packit |
2ba279 |
return g_quark_from_static_string ("g-bd-loop-error-quark");
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_check_deps:
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: whether the plugin's runtime dependencies are satisfied or not
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Function checking plugin's runtime dependencies.
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gboolean bd_loop_check_deps (void) {
|
|
Packit |
2ba279 |
/* nothing to check here */
|
|
Packit |
2ba279 |
return TRUE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_init:
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Initializes the plugin. **This function is called automatically by the
|
|
Packit |
2ba279 |
* library's initialization functions.**
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gboolean bd_loop_init (void) {
|
|
Packit |
2ba279 |
/* nothing to do here */
|
|
Packit |
2ba279 |
return TRUE;
|
|
Packit |
2ba279 |
};
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_close:
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Cleans up after the plugin. **This function is called automatically by the
|
|
Packit |
2ba279 |
* library's functions that unload it.**
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
void bd_loop_close (void) {
|
|
Packit |
2ba279 |
/* nothing to do here */
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
#define UNUSED __attribute__((unused))
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_is_tech_avail:
|
|
Packit |
2ba279 |
* @tech: the queried tech
|
|
Packit |
2ba279 |
* @mode: a bit mask of queried modes of operation (#BDLoopTechMode) for @tech
|
|
Packit |
2ba279 |
* @error: (out): place to store error (details about why the @tech-@mode combination is not available)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: whether the @tech-@mode combination is available -- supported by the
|
|
Packit |
2ba279 |
* plugin implementation and having all the runtime dependencies available
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gboolean bd_loop_is_tech_avail (BDLoopTech tech UNUSED, guint64 mode UNUSED, GError **error UNUSED) {
|
|
Packit |
2ba279 |
/* all combinations are supported by this implementation of the plugin */
|
|
Packit |
2ba279 |
return TRUE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_get_backing_file:
|
|
Packit |
2ba279 |
* @dev_name: name of the loop device to get backing file for (e.g. "loop0")
|
|
Packit |
2ba279 |
* @error: (out): place to store error (if any)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: (transfer full): path of the device's backing file or %NULL if none
|
|
Packit |
2ba279 |
* is found
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gchar* bd_loop_get_backing_file (const gchar *dev_name, GError **error) {
|
|
Packit |
2ba279 |
gchar *sys_path = g_strdup_printf ("/sys/class/block/%s/loop/backing_file", dev_name);
|
|
Packit |
2ba279 |
gchar *ret = NULL;
|
|
Packit |
2ba279 |
gboolean success = FALSE;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (access (sys_path, R_OK) != 0) {
|
|
Packit |
2ba279 |
g_free (sys_path);
|
|
Packit |
2ba279 |
return NULL;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
success = g_file_get_contents (sys_path, &ret, NULL, error);
|
|
Packit |
2ba279 |
if (!success) {
|
|
Packit |
2ba279 |
/* error is alraedy populated */
|
|
Packit |
2ba279 |
g_free (sys_path);
|
|
Packit |
2ba279 |
return NULL;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
g_free (sys_path);
|
|
Packit |
2ba279 |
return g_strstrip (ret);
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_get_loop_name:
|
|
Packit |
2ba279 |
* @file: path of the backing file to get loop name for
|
|
Packit |
2ba279 |
* @error: (out): place to store error (if any)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: (transfer full): name of the loop device associated with the given
|
|
Packit |
2ba279 |
* @file or %NULL if failed to determine
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gchar* bd_loop_get_loop_name (const gchar *file, GError **error __attribute__((unused))) {
|
|
Packit |
2ba279 |
glob_t globbuf;
|
|
Packit |
2ba279 |
gchar **path_p;
|
|
Packit |
2ba279 |
gboolean success = FALSE;
|
|
Packit |
2ba279 |
GError *tmp_error = NULL;
|
|
Packit |
2ba279 |
gchar *content = NULL;
|
|
Packit |
2ba279 |
gboolean found = FALSE;
|
|
Packit |
2ba279 |
gchar **parts;
|
|
Packit |
2ba279 |
gchar *ret;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (glob ("/sys/block/loop*/loop/backing_file", GLOB_NOSORT, NULL, &globbuf) != 0) {
|
|
Packit |
2ba279 |
return NULL;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
for (path_p = globbuf.gl_pathv; *path_p && !found; path_p++) {
|
|
Packit |
2ba279 |
success = g_file_get_contents (*path_p, &content, NULL, &tmp_error);
|
|
Packit |
2ba279 |
if (!success) {
|
|
Packit |
2ba279 |
g_clear_error (&tmp_error);
|
|
Packit |
2ba279 |
continue;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
g_strstrip (content);
|
|
Packit |
2ba279 |
found = (g_strcmp0 (content, file) == 0);
|
|
Packit |
2ba279 |
g_free (content);
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (!found) {
|
|
Packit |
2ba279 |
globfree (&globbuf);
|
|
Packit |
2ba279 |
return NULL;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
parts = g_strsplit (*(path_p - 1), "/", 5);
|
|
Packit |
2ba279 |
ret = g_strdup (parts[3]);
|
|
Packit |
2ba279 |
g_strfreev (parts);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
globfree (&globbuf);
|
|
Packit |
2ba279 |
return ret;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_setup:
|
|
Packit |
2ba279 |
* @file: file to setup as a loop device
|
|
Packit |
2ba279 |
* @offset: offset of the start of the device (in @file)
|
|
Packit |
2ba279 |
* @size: maximum size of the device (or 0 to leave unspecified)
|
|
Packit |
2ba279 |
* @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE)
|
|
Packit |
2ba279 |
* @part_scan: whether to enforce partition scan on the newly created device or not
|
|
Packit |
2ba279 |
* @loop_name: (allow-none) (out): if not %NULL, it is used to store the name of the loop device
|
|
Packit |
2ba279 |
* @error: (out): place to store error (if any)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: whether the @file was successfully setup as a loop device or not
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gboolean bd_loop_setup (const gchar *file, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, const gchar **loop_name, GError **error) {
|
|
Packit |
2ba279 |
gint fd = -1;
|
|
Packit |
2ba279 |
gboolean ret = FALSE;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/* open as RDWR so that @read_only determines whether the device is
|
|
Packit |
2ba279 |
read-only or not */
|
|
Packit |
2ba279 |
fd = open (file, O_RDWR);
|
|
Packit |
2ba279 |
if (fd < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to open the backing file '%s': %m", file);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
ret = bd_loop_setup_from_fd (fd, offset, size, read_only, part_scan, loop_name, error);
|
|
Packit |
2ba279 |
close (fd);
|
|
Packit |
2ba279 |
return ret;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_setup_from_fd:
|
|
Packit |
2ba279 |
* @fd: file descriptor for a file to setup as a new loop device
|
|
Packit |
2ba279 |
* @offset: offset of the start of the device (in file given by @fd)
|
|
Packit |
2ba279 |
* @size: maximum size of the device (or 0 to leave unspecified)
|
|
Packit |
2ba279 |
* @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE)
|
|
Packit |
2ba279 |
* @part_scan: whether to enforce partition scan on the newly created device or not
|
|
Packit |
2ba279 |
* @loop_name: (allow-none) (out): if not %NULL, it is used to store the name of the loop device
|
|
Packit |
2ba279 |
* @error: (out): place to store error (if any)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: whether an new loop device was successfully setup for @fd or not
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gboolean bd_loop_setup_from_fd (gint fd, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, const gchar **loop_name, GError **error) {
|
|
Packit |
2ba279 |
gint loop_control_fd = -1;
|
|
Packit |
2ba279 |
gint loop_number = -1;
|
|
Packit |
2ba279 |
gchar *loop_device = NULL;
|
|
Packit |
2ba279 |
gint loop_fd = -1;
|
|
Packit |
2ba279 |
struct loop_info64 li64;
|
|
Packit |
2ba279 |
guint64 progress_id = 0;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
progress_id = bd_utils_report_started ("Started setting up loop device");
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
loop_control_fd = open ("/dev/loop-control", O_RDWR);
|
|
Packit |
2ba279 |
if (loop_control_fd == -1) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to open the loop-control device: %m");
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/* XXX: serialize access to loop-control (seems to be required, but it's not
|
|
Packit |
2ba279 |
documented anywhere) */
|
|
Packit |
2ba279 |
g_mutex_lock (&loop_control_lock);
|
|
Packit |
2ba279 |
loop_number = ioctl (loop_control_fd, LOOP_CTL_GET_FREE);
|
|
Packit |
2ba279 |
g_mutex_unlock (&loop_control_lock);
|
|
Packit |
2ba279 |
close (loop_control_fd);
|
|
Packit |
2ba279 |
if (loop_number < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to open the loop-control device: %m");
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
bd_utils_report_progress (progress_id, 33, "Got free loop device");
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
loop_device = g_strdup_printf ("/dev/loop%d", loop_number);
|
|
Packit |
2ba279 |
loop_fd = open (loop_device, read_only ? O_RDONLY : O_RDWR);
|
|
Packit |
2ba279 |
if (loop_fd == -1) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to open the %s device: %m", loop_device);
|
|
Packit |
2ba279 |
g_free (loop_device);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
memset (&li64, '\0', sizeof (li64));
|
|
Packit |
2ba279 |
if (read_only)
|
|
Packit |
2ba279 |
li64.lo_flags |= LO_FLAGS_READ_ONLY;
|
|
Packit |
2ba279 |
if (part_scan)
|
|
Packit |
2ba279 |
li64.lo_flags |= LO_FLAGS_PARTSCAN;
|
|
Packit |
2ba279 |
if (offset > 0)
|
|
Packit |
2ba279 |
li64.lo_offset = offset;
|
|
Packit |
2ba279 |
if (size > 0)
|
|
Packit |
2ba279 |
li64.lo_sizelimit = size;
|
|
Packit |
2ba279 |
if (ioctl (loop_fd, LOOP_SET_FD, fd) < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
|
|
Packit |
2ba279 |
"Failed to associate the %s device with the file descriptor: %m", loop_device);
|
|
Packit |
2ba279 |
g_free (loop_device);
|
|
Packit |
2ba279 |
close (loop_fd);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
bd_utils_report_progress (progress_id, 66, "Associated the loop device");
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (ioctl (loop_fd, LOOP_SET_STATUS64, &li64) < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to set status for the %s device: %m", loop_device);
|
|
Packit |
2ba279 |
g_free (loop_device);
|
|
Packit |
2ba279 |
close (loop_fd);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (loop_name)
|
|
Packit |
2ba279 |
*loop_name = g_strdup_printf ("loop%d", loop_number);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
g_free (loop_device);
|
|
Packit |
2ba279 |
close (loop_fd);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, "Completed");
|
|
Packit |
2ba279 |
return TRUE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_teardown:
|
|
Packit |
2ba279 |
* @loop: path or name of the loop device to tear down
|
|
Packit |
2ba279 |
* @error: (out): place to store error (if any)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: whether the @loop device was successfully torn down or not
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_DESTROY
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gboolean bd_loop_teardown (const gchar *loop, GError **error) {
|
|
Packit |
2ba279 |
gchar *dev_loop = NULL;
|
|
Packit |
2ba279 |
gint loop_fd = -1;
|
|
Packit |
2ba279 |
guint64 progress_id = 0;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
progress_id = bd_utils_report_started ("Started tearing down loop device");
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (!g_str_has_prefix (loop, "/dev/"))
|
|
Packit |
2ba279 |
dev_loop = g_strdup_printf ("/dev/%s", loop);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
loop_fd = open (dev_loop ? dev_loop : loop, O_RDONLY);
|
|
Packit |
2ba279 |
g_free (dev_loop);
|
|
Packit |
2ba279 |
if (loop_fd == -1) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to open the %s device: %m", loop);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (ioctl (loop_fd, LOOP_CLR_FD) < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to detach the backing file from the %s device: %m", loop);
|
|
Packit |
2ba279 |
close (loop_fd);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
close (loop_fd);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, "Completed");
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
return TRUE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_get_autoclear:
|
|
Packit |
2ba279 |
* @loop: path or name of the loop device
|
|
Packit |
2ba279 |
* @error: (out): place to store error (if any)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: whether the autoclear flag is set on the @loop device or not (if %FALSE, @error may be set)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gboolean bd_loop_get_autoclear (const gchar *loop, GError **error) {
|
|
Packit |
2ba279 |
gchar *sys_path = NULL;
|
|
Packit |
2ba279 |
gboolean success = FALSE;
|
|
Packit |
2ba279 |
gchar *contents = NULL;
|
|
Packit |
2ba279 |
gboolean ret = FALSE;
|
|
Packit |
2ba279 |
gchar *dev_loop = NULL;
|
|
Packit |
2ba279 |
gint fd = -1;
|
|
Packit |
2ba279 |
struct loop_info64 li64;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/* first try reading the value from /sys which seems to be safer than
|
|
Packit |
2ba279 |
potentially stepping on each other's toes with udev during the ioctl() */
|
|
Packit |
2ba279 |
if (g_str_has_prefix (loop, "/dev/"))
|
|
Packit |
2ba279 |
sys_path = g_strdup_printf ("/sys/class/block/%s/loop/autoclear", loop + 5);
|
|
Packit |
2ba279 |
else
|
|
Packit |
2ba279 |
sys_path = g_strdup_printf ("/sys/class/block/%s/loop/autoclear", loop);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
success = g_file_get_contents (sys_path, &contents, NULL, error);
|
|
Packit |
2ba279 |
g_free (sys_path);
|
|
Packit |
2ba279 |
if (success) {
|
|
Packit |
2ba279 |
g_strstrip (contents);
|
|
Packit |
2ba279 |
ret = g_strcmp0 (contents, "1") == 0;
|
|
Packit |
2ba279 |
g_free (contents);
|
|
Packit |
2ba279 |
return ret;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/* else try using the ioctl() (and ignore all previous errors) */
|
|
Packit |
2ba279 |
g_clear_error (error);
|
|
Packit |
2ba279 |
if (!g_str_has_prefix (loop, "/dev/"))
|
|
Packit |
2ba279 |
dev_loop = g_strdup_printf ("/dev/%s", loop);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
fd = open (dev_loop ? dev_loop : loop, O_RDONLY);
|
|
Packit |
2ba279 |
g_free (dev_loop);
|
|
Packit |
2ba279 |
if (fd < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
|
|
Packit |
2ba279 |
"Failed to open device %s: %m", loop);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
memset (&li64, 0, sizeof (li64));
|
|
Packit |
2ba279 |
if (ioctl (fd, LOOP_GET_STATUS64, &li64) < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to get status of the device %s: %m", loop);
|
|
Packit |
2ba279 |
close (fd);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
close (fd);
|
|
Packit |
2ba279 |
return (li64.lo_flags & LO_FLAGS_AUTOCLEAR) != 0;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_loop_set_autoclear:
|
|
Packit |
2ba279 |
* @loop: path or name of the loop device
|
|
Packit |
2ba279 |
* @autoclear: whether to set or unset the autoclear flag
|
|
Packit |
2ba279 |
* @error: (out): place to store error (if any)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: whether the autoclear flag was successfully set on the @loop device or not
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_MODIFY
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gboolean bd_loop_set_autoclear (const gchar *loop, gboolean autoclear, GError **error) {
|
|
Packit |
2ba279 |
gchar *dev_loop = NULL;
|
|
Packit |
2ba279 |
gint fd = -1;
|
|
Packit |
2ba279 |
struct loop_info64 li64;
|
|
Packit |
2ba279 |
guint64 progress_id = 0;
|
|
Packit |
2ba279 |
gchar *msg = NULL;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (!g_str_has_prefix (loop, "/dev/"))
|
|
Packit |
2ba279 |
dev_loop = g_strdup_printf ("/dev/%s", loop);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
msg = g_strdup_printf ("Started setting up the autoclear flag on the /dev/%s device",
|
|
Packit |
2ba279 |
dev_loop ? dev_loop : loop);
|
|
Packit |
2ba279 |
progress_id = bd_utils_report_started (msg);
|
|
Packit |
2ba279 |
g_free (msg);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
fd = open (dev_loop ? dev_loop : loop, O_RDWR);
|
|
Packit |
2ba279 |
g_free (dev_loop);
|
|
Packit |
2ba279 |
if (fd < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_DEVICE,
|
|
Packit |
2ba279 |
"Failed to open device %s: %m", loop);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
memset (&li64, 0, sizeof (li64));
|
|
Packit |
2ba279 |
if (ioctl (fd, LOOP_GET_STATUS64, &li64) < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to get status of the device %s: %m", loop);
|
|
Packit |
2ba279 |
close (fd);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (autoclear)
|
|
Packit |
2ba279 |
li64.lo_flags |= LO_FLAGS_AUTOCLEAR;
|
|
Packit |
2ba279 |
else
|
|
Packit |
2ba279 |
li64.lo_flags &= (~LO_FLAGS_AUTOCLEAR);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (ioctl (fd, LOOP_SET_STATUS64, &li64) < 0) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_LOOP_ERROR, BD_LOOP_ERROR_FAIL,
|
|
Packit |
2ba279 |
"Failed to set status of the device %s: %m", loop);
|
|
Packit |
2ba279 |
close (fd);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, (*error)->message);
|
|
Packit |
2ba279 |
return FALSE;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
close (fd);
|
|
Packit |
2ba279 |
bd_utils_report_finished (progress_id, "Completed");
|
|
Packit |
2ba279 |
return TRUE;
|
|
Packit |
2ba279 |
}
|