Вопрос или проблема
Мой вопрос простой: имея путь к логическому тому, возможно ли получить 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
Ссылки
- Как получить uuid устройства/раздела в linux программно?
- libblkid работает только с root и после запуска от имени root
- как получить uuid файловой системы, заданной по пути?
- Использование libblkid для поиска UUID раздела
Отказ от ответственности
Я должен признать, что это ответ, который я получил в основном от chat-gpt, оценивал и уточнял я. Хотя я также нашел, что на него уже был дан ответ здесь, в конечном итоге я решил потратить время и предоставить полный ответ с примером в новом посте.
.
Ответ или решение
Чтобы получить UUID логического тома в Linux без прав администратора (root), вы можете воспользоваться символическими ссылками, которые располагаются в каталоге /dev/disk/by-uuid/
. Этот метод эффективен и не требует прямого доступа к устройству, что делает его особенно полезным для программ на языке C.
Подход к решению задачи
-
Открытие каталога UUID: Используйте стандартные системные вызовы для открытия директории, содержащей символические ссылки на устройства с их UUID.
-
Получение актуального состояния устройства: Необходимо получить информацию о логическом томе через функцию
stat()
, чтобы извлечь важные параметры устройства, такие какst_rdev
. -
Сравнение с символическими ссылками: Для каждой записи в директории
/dev/disk/by-uuid/
следует проверять, указывает ли она на то же устройство, что и ваш логический том. Это достигается с помощью повторного вызоваstat()
для символических ссылок. -
Чтение и возврат 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, что делает его надежным и безопасным решением.