Получить UUID по пути к логическому объему без прав root

Вопрос или проблема

Мой вопрос простой: имея путь к логическому тому, возможно ли получить UUID устройства, к которому он принадлежит, без необходимости иметь root-доступ в C? И если да, то как бы вы подошли к этой задаче? (эффективность имеет значение)

Пока у вашей системы есть символические ссылки в /dev/disk/by-uuid, вы можете сопоставить устройство на основе его UUID без sudo. Эта директория содержит ссылки на блочные устройства, основанные на UUID, что означает, что вы можете найти UUID, не получая доступ к устройству напрямую.

Пример

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>

#define UUID_PATH_PREFIX "/dev/disk/by-uuid/"
#define UUID_PATH_LENGTH (18 + 36 + 1)  // Длина префикса + UUID + нуль-символ

int get_uuid_from(const char *volume_path, char *uuid_buf, size_t buf_size) {
    struct dirent *entry;
    DIR *dp = opendir(UUID_PATH_PREFIX);
    if (dp == NULL) {
        perror("не удалось открыть директорию");
        return -1;
    }

    struct stat volume_stat, link_stat;
    if (stat(volume_path, &volume_stat) != 0) {
        perror("не удалось получить информацию о volume_path");
        closedir(dp);
        return -1;
    }

    char path[UUID_PATH_LENGTH];
    while ((entry = readdir(dp)) != NULL) {
        snprintf(path, sizeof(path), "%s%s", UUID_PATH_PREFIX, entry->d_name);

        if (stat(path, &link_stat) == 0 && link_stat.st_rdev == volume_stat.st_rdev) {
            strncpy(uuid_buf, entry->d_name, buf_size - 1);
            uuid_buf[buf_size - 1] = '\0';  // Обеспечить нуль-терминацию
            closedir(dp);
            return 0;
        }
    }

    closedir(dp);
    return -1;
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Использование: %s <volume_path>\n", argv[0]);
        return EXIT_FAILURE;
    }

    char uuid[37];  // UUID состоит из 36 символов + нуль-терминатор
    if (get_uuid_from(argv[1], uuid, sizeof(uuid)) != 0) {
        fprintf(stderr, "Не удалось получить UUID для %s\n", argv[1]);
        return EXIT_FAILURE;
    }

    printf("UUID для %s: %s\n", argv[1], uuid);
    return EXIT_SUCCESS;
}
gcc -o get_uuid_test get_uuid_test.c
./get_uuid_test /dev/mapper/root

Ссылки

Отказ от ответственности

Я должен признать, что это ответ, который я получил в основном от chat-gpt, оценивал и уточнял я. Хотя я также нашел, что на него уже был дан ответ здесь, в конечном итоге я решил потратить время и предоставить полный ответ с примером в новом посте.

.

Ответ или решение

Чтобы получить UUID логического тома в Linux без прав администратора (root), вы можете воспользоваться символическими ссылками, которые располагаются в каталоге /dev/disk/by-uuid/. Этот метод эффективен и не требует прямого доступа к устройству, что делает его особенно полезным для программ на языке C.

Подход к решению задачи

  1. Открытие каталога UUID: Используйте стандартные системные вызовы для открытия директории, содержащей символические ссылки на устройства с их UUID.

  2. Получение актуального состояния устройства: Необходимо получить информацию о логическом томе через функцию stat(), чтобы извлечь важные параметры устройства, такие как st_rdev.

  3. Сравнение с символическими ссылками: Для каждой записи в директории /dev/disk/by-uuid/ следует проверять, указывает ли она на то же устройство, что и ваш логический том. Это достигается с помощью повторного вызова stat() для символических ссылок.

  4. Чтение и возврат UUID: Если найдена соответствующая запись, UUID можно скопировать в предоставленный буфер.

Пример кода

Вот пример реализации на языке C, который показывает, как это можно сделать:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>

#define UUID_PATH_PREFIX "/dev/disk/by-uuid/"
#define UUID_PATH_LENGTH (18 + 36 + 1)  // Длина префикса + UUID + нулевой символ

int get_uuid_from(const char *volume_path, char *uuid_buf, size_t buf_size) {
    struct dirent *entry;
    DIR *dp = opendir(UUID_PATH_PREFIX);
    if (dp == NULL) {
        perror("opendir failed");
        return -1;
    }

    struct stat volume_stat, link_stat;
    if (stat(volume_path, &volume_stat) != 0) {
        perror("stat on volume_path failed");
        closedir(dp);
        return -1;
    }

    char path[UUID_PATH_LENGTH];
    while ((entry = readdir(dp)) != NULL) {
        snprintf(path, sizeof(path), "%s%s", UUID_PATH_PREFIX, entry->d_name);

        if (stat(path, &link_stat) == 0 && link_stat.st_rdev == volume_stat.st_rdev) {
            strncpy(uuid_buf, entry->d_name, buf_size - 1);
            uuid_buf[buf_size - 1] = '\0';  // Гарантируем завершение строки
            closedir(dp);
            return 0;
        }
    }

    closedir(dp);
    return -1;
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <volume_path>\n", argv[0]);
        return EXIT_FAILURE;
    }

    char uuid[37];  // UUID состоит из 36 символов + нулевой символ
    if (get_uuid_from(argv[1], uuid, sizeof(uuid)) != 0) {
        fprintf(stderr, "Failed to retrieve UUID for %s\n", argv[1]);
        return EXIT_FAILURE;
    }

    printf("UUID for %s: %s\n", argv[1], uuid);
    return EXIT_SUCCESS;
}

Компиляция и запуск

Сохраните код в файл, например get_uuid_test.c, и скомпилируйте его с помощью GCC:

gcc -o get_uuid_test get_uuid_test.c

Запустите программу, указав путь к логическому тому:

./get_uuid_test /dev/mapper/root

Заключение

Приведенный выше метод позволяет эффективно извлечь UUID логического тома без необходимости иметь права суперпользователя. Это достигается использованием стандартных системных вызовов и возможностей работы с файловой системой в Linux, что делает его надежным и безопасным решением.

Оцените материал
Добавить комментарий

Капча загружается...