|
Packit |
2ba279 |
/*
|
|
Packit |
2ba279 |
* Copyright (C) 2017 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 <libudev.h>
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
#include "dev_utils.h"
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_utils_dev_utils_error_quark: (skip)
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
GQuark bd_utils_dev_utils_error_quark (void)
|
|
Packit |
2ba279 |
{
|
|
Packit |
2ba279 |
return g_quark_from_static_string ("g-bd-utils-dev_utils-error-quark");
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_utils_resolve_device:
|
|
Packit |
2ba279 |
* @dev_spec: specification of the device (e.g. "/dev/sda", any symlink, or the name of a file
|
|
Packit |
2ba279 |
* under "/dev")
|
|
Packit |
2ba279 |
* @error: (out): place to store error (if any)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: (transfer full): the full real path of the device (e.g. "/dev/md126"
|
|
Packit |
2ba279 |
* for "/dev/md/my_raid") or %NULL in case of error
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gchar* bd_utils_resolve_device (const gchar *dev_spec, GError **error) {
|
|
Packit |
2ba279 |
gchar *path = NULL;
|
|
Packit |
2ba279 |
gchar *symlink = NULL;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/* TODO: check that the resulting path is a block device? */
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (!g_str_has_prefix (dev_spec, "/dev/"))
|
|
Packit |
2ba279 |
path = g_strdup_printf ("/dev/%s", dev_spec);
|
|
Packit |
2ba279 |
else
|
|
Packit |
2ba279 |
path = g_strdup (dev_spec);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
symlink = g_file_read_link (path, error);
|
|
Packit |
2ba279 |
if (!symlink) {
|
|
Packit |
2ba279 |
if (g_error_matches (*error, G_FILE_ERROR, G_FILE_ERROR_INVAL)) {
|
|
Packit |
2ba279 |
/* invalid argument -> not a symlink -> nothing to resolve */
|
|
Packit |
2ba279 |
g_clear_error (error);
|
|
Packit |
2ba279 |
return path;
|
|
Packit |
2ba279 |
} else {
|
|
Packit |
2ba279 |
/* some other error, just report it */
|
|
Packit |
2ba279 |
g_free (path);
|
|
Packit |
2ba279 |
return NULL;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
g_free (path);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (g_str_has_prefix (symlink, "../"))
|
|
Packit |
2ba279 |
path = g_strdup_printf ("/dev/%s", symlink + 3);
|
|
Packit |
2ba279 |
else
|
|
Packit |
2ba279 |
path = g_strdup_printf ("/dev/%s", symlink);
|
|
Packit |
2ba279 |
g_free (symlink);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
return path;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
/**
|
|
Packit |
2ba279 |
* bd_utils_get_device_symlinks:
|
|
Packit |
2ba279 |
* @dev_spec: specification of the device (e.g. "/dev/sda", any symlink, or the name of a file
|
|
Packit |
2ba279 |
* under "/dev")
|
|
Packit |
2ba279 |
* @error: (out): place to store error (if any)
|
|
Packit |
2ba279 |
*
|
|
Packit |
2ba279 |
* Returns: (transfer full) (array zero-terminated=1): a list of all symlinks (known to udev) for the
|
|
Packit |
2ba279 |
* device specified with @dev_spec or %NULL in
|
|
Packit |
2ba279 |
* case of error
|
|
Packit |
2ba279 |
*/
|
|
Packit |
2ba279 |
gchar** bd_utils_get_device_symlinks (const gchar *dev_spec, GError **error) {
|
|
Packit |
2ba279 |
gchar *dev_path;
|
|
Packit |
2ba279 |
struct udev *context;
|
|
Packit |
2ba279 |
struct udev_device *device;
|
|
Packit |
2ba279 |
struct udev_list_entry *entry = NULL;
|
|
Packit |
2ba279 |
struct udev_list_entry *ent_it = NULL;
|
|
Packit |
2ba279 |
guint64 n_links = 0;
|
|
Packit |
2ba279 |
guint64 i = 0;
|
|
Packit |
2ba279 |
gchar **ret = NULL;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
dev_path = bd_utils_resolve_device (dev_spec, error);
|
|
Packit |
2ba279 |
if (!dev_path)
|
|
Packit |
2ba279 |
return NULL;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
context = udev_new ();
|
|
Packit |
2ba279 |
/* dev_path is the full path like "/dev/sda", we only need the device name ("sda") */
|
|
Packit |
2ba279 |
device = udev_device_new_from_subsystem_sysname (context, "block", dev_path + 5);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
if (!device) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_UTILS_DEV_UTILS_ERROR, BD_UTILS_DEV_UTILS_ERROR_FAILED,
|
|
Packit |
2ba279 |
"Failed to get information about the device '%s' from udev database",
|
|
Packit |
2ba279 |
dev_path);
|
|
Packit |
2ba279 |
g_free (dev_path);
|
|
Packit |
2ba279 |
udev_unref (context);
|
|
Packit |
2ba279 |
return NULL;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
entry = udev_device_get_devlinks_list_entry (device);
|
|
Packit |
2ba279 |
if (!entry) {
|
|
Packit |
2ba279 |
g_set_error (error, BD_UTILS_DEV_UTILS_ERROR, BD_UTILS_DEV_UTILS_ERROR_FAILED,
|
|
Packit |
2ba279 |
"Failed to get symlinks for the device '%s'", dev_path);
|
|
Packit |
2ba279 |
g_free (dev_path);
|
|
Packit |
2ba279 |
udev_device_unref (device);
|
|
Packit |
2ba279 |
udev_unref (context);
|
|
Packit |
2ba279 |
return NULL;
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
g_free (dev_path);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
ent_it = entry;
|
|
Packit |
2ba279 |
while (ent_it) {
|
|
Packit |
2ba279 |
n_links++;
|
|
Packit |
2ba279 |
ent_it = udev_list_entry_get_next (ent_it);
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
ret = g_new0 (gchar*, n_links + 1);
|
|
Packit |
2ba279 |
ent_it = entry;
|
|
Packit |
2ba279 |
while (ent_it) {
|
|
Packit |
2ba279 |
ret[i++] = g_strdup (udev_list_entry_get_name (ent_it));
|
|
Packit |
2ba279 |
ent_it = udev_list_entry_get_next (ent_it);
|
|
Packit |
2ba279 |
}
|
|
Packit |
2ba279 |
ret[i] = NULL;
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
udev_device_unref (device);
|
|
Packit |
2ba279 |
udev_unref (context);
|
|
Packit |
2ba279 |
|
|
Packit |
2ba279 |
return ret;
|
|
Packit |
2ba279 |
}
|