cunixpathrootuuid

Given a path to a logical volume get UUID without root


My question is simple, given a path to a logical volume: is it possible to get the UUID of the device it belongs to, without the need of root access in C? and if so, how would you approach this problem? (efficiency matters)


Solution

  • As long as your system has symbolic links in /dev/disk/by-uuid, you can match the device based on its UUID without sudo. This directory contains UUID-based links to block devices, which means you can find the UUID without accessing the device directly.

    Example

    #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)  // Length of prefix + UUID + null terminator
    
    
    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';  // Ensure null termination
                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 is 36 chars + null terminator
        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;
    }
    
    gcc -o get_uuid_test get_uuid_test.c
    
    ./get_uuid_test /dev/mapper/root
    

    References

    Disclaimer

    I have to admit this is an answer I got primarly from chat-gpt, evaluated and refined by me. While I did also found it was already answered here, eventually I decided to take the time and provide a complete answer with an example, in a new post.