LCOV - code coverage report
Current view: top level - utils - dev_utils.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 80.0 % 60 48
Test Date: 2026-01-26 13:19:28 Functions: 66.7 % 3 2
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2017  Red Hat, Inc.
       3              :  *
       4              :  * This library is free software; you can redistribute it and/or
       5              :  * modify it under the terms of the GNU Lesser General Public
       6              :  * License as published by the Free Software Foundation; either
       7              :  * version 2.1 of the License, or (at your option) any later version.
       8              :  *
       9              :  * This library is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12              :  * Lesser General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU Lesser General Public
      15              :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      16              :  *
      17              :  * Author: Vratislav Podzimek <vpodzime@redhat.com>
      18              :  */
      19              : 
      20              : #include <glib.h>
      21              : #include <libudev.h>
      22              : 
      23              : #include "dev_utils.h"
      24              : 
      25              : /**
      26              :  * bd_utils_dev_utils_error_quark: (skip)
      27              :  */
      28            0 : GQuark bd_utils_dev_utils_error_quark (void)
      29              : {
      30            0 :     return g_quark_from_static_string ("g-bd-utils-dev_utils-error-quark");
      31              : }
      32              : 
      33              : /**
      34              :  * bd_utils_resolve_device:
      35              :  * @dev_spec: specification of the device (e.g. "/dev/sda", any symlink, or the name of a file
      36              :  *            under "/dev")
      37              :  * @error: (out) (optional): place to store error (if any)
      38              :  *
      39              :  * Returns: (transfer full): the full real path of the device (e.g. "/dev/md126"
      40              :  *                           for "/dev/md/my_raid") or %NULL in case of error
      41              :  */
      42           55 : gchar* bd_utils_resolve_device (const gchar *dev_spec, GError **error) {
      43           55 :     gchar *path = NULL;
      44           55 :     gchar *symlink = NULL;
      45           55 :     GError *l_error = NULL;
      46              : 
      47              :     /* TODO: check that the resulting path is a block device? */
      48              : 
      49           55 :     if (!g_str_has_prefix (dev_spec, "/dev/"))
      50            6 :         path = g_strdup_printf ("/dev/%s", dev_spec);
      51              :     else
      52           49 :         path = g_strdup (dev_spec);
      53              : 
      54           55 :     symlink = g_file_read_link (path, &l_error);
      55           55 :     if (!symlink) {
      56           25 :         if (g_error_matches (l_error, G_FILE_ERROR, G_FILE_ERROR_INVAL)) {
      57              :             /* invalid argument -> not a symlink -> nothing to resolve */
      58            6 :             g_clear_error (&l_error);
      59            6 :             return path;
      60              :         } else {
      61              :             /* some other error, just report it */
      62           19 :             g_propagate_error (error, l_error);
      63           19 :             g_free (path);
      64           19 :             return NULL;
      65              :         }
      66              :     }
      67           30 :     g_free (path);
      68              : 
      69           30 :     if (g_str_has_prefix (symlink, "../"))
      70           30 :         path = g_strdup_printf ("/dev/%s", symlink + 3);
      71              :     else
      72            0 :         path = g_strdup_printf ("/dev/%s", symlink);
      73           30 :     g_free (symlink);
      74              : 
      75           30 :     return path;
      76              : }
      77              : 
      78              : /**
      79              :  * bd_utils_get_device_symlinks:
      80              :  * @dev_spec: specification of the device (e.g. "/dev/sda", any symlink, or the name of a file
      81              :  *            under "/dev")
      82              :  * @error: (out) (optional): place to store error (if any)
      83              :  *
      84              :  * Returns: (transfer full) (array zero-terminated=1): a list of all symlinks (known to udev) for the
      85              :  *                                                     device specified with @dev_spec or %NULL in
      86              :  *                                                     case of error
      87              :  */
      88            4 : gchar** bd_utils_get_device_symlinks (const gchar *dev_spec, GError **error) {
      89              :     gchar *dev_path;
      90              :     struct udev *context;
      91              :     struct udev_device *device;
      92            4 :     struct udev_list_entry *entry = NULL;
      93            4 :     struct udev_list_entry *ent_it = NULL;
      94            4 :     guint64 n_links = 0;
      95            4 :     guint64 i = 0;
      96            4 :     gchar **ret = NULL;
      97              : 
      98            4 :     dev_path = bd_utils_resolve_device (dev_spec, error);
      99            4 :     if (!dev_path)
     100            1 :         return NULL;
     101              : 
     102            3 :     context = udev_new ();
     103              :     /* dev_path is the full path like "/dev/sda", we only need the device name ("sda") */
     104            3 :     device = udev_device_new_from_subsystem_sysname (context, "block", dev_path + 5);
     105              : 
     106            3 :     if (!device) {
     107            0 :         g_set_error (error, BD_UTILS_DEV_UTILS_ERROR, BD_UTILS_DEV_UTILS_ERROR_FAILED,
     108              :                      "Failed to get information about the device '%s' from udev database",
     109              :                      dev_path);
     110            0 :         g_free (dev_path);
     111            0 :         udev_unref (context);
     112            0 :         return NULL;
     113              :     }
     114              : 
     115            3 :     entry = udev_device_get_devlinks_list_entry (device);
     116            3 :     if (!entry) {
     117            0 :         g_set_error (error, BD_UTILS_DEV_UTILS_ERROR, BD_UTILS_DEV_UTILS_ERROR_FAILED,
     118              :                      "Failed to get symlinks for the device '%s'", dev_path);
     119            0 :         g_free (dev_path);
     120            0 :         udev_device_unref (device);
     121            0 :         udev_unref (context);
     122            0 :         return NULL;
     123              :     }
     124            3 :     g_free (dev_path);
     125              : 
     126            3 :     ent_it = entry;
     127           14 :     while (ent_it) {
     128           11 :         n_links++;
     129           11 :         ent_it = udev_list_entry_get_next (ent_it);
     130              :     }
     131              : 
     132            3 :     ret = g_new0 (gchar*, n_links + 1);
     133            3 :     ent_it = entry;
     134           14 :     while (ent_it) {
     135           11 :         ret[i++] = g_strdup (udev_list_entry_get_name (ent_it));
     136           11 :         ent_it = udev_list_entry_get_next (ent_it);
     137              :     }
     138            3 :     ret[i] = NULL;
     139              : 
     140            3 :     udev_device_unref (device);
     141            3 :     udev_unref (context);
     142              : 
     143            3 :     return ret;
     144              : }
        

Generated by: LCOV version 2.0-1