user21053811
user21053811

Reputation:

GNU/Linux systemd/sd-device problems creating and filtering an sd_device_enumerator

Preface:

I am not a good developer and am just getting started, the code below is part of a larger program I am building and has only been temporarily placed in the main cpp file. I am aware that the structure still needs improvement only I want to get it running first.

Problem:

I have the last days desperately trying to find documentation, but since I could find nothing but this [https://www.freedesktop.org/software/systemd/man/sd-device.html] and I have tried to work through the source code on github.

I had previously used the libudev library to read BLOCK devices and get values from them which worked, however after further exposure to this topic I read that it is no longer recommended to use libudev and switch to systemd/sd-device.

The code below doesn't output an error but it also doesn't run through the loop because "sd_device_enumerator_get_device_next(enumerator)" always returns a NULL pointer. Even after a very long search I can't find any documentation for systemd/sd-device and even reading through the src data I can't figure it out.

This is my attempt, this should basically run through all BLOCK devices and read out certain values, for testing I have entered "ID_PART_TABLE_TYPE".

main.h

#ifndef main_h
#define main_h

#include <string>
#include <bitset>
#include <iostream>
#include <fstream>
#include <sstream>
#include <regex>
#include <vector>
#include <cstring>

#include <stdio.h>
#include <dirent.h>

#include <systemd/sd-device.h>

using std::cout;
using std::endl;
using std::string;
using std::to_string;
using std::cin;
using std::fstream;
using std::ifstream;
using std::ofstream;
using std::vector;

// File: classes/drives-info.cpp
/*
class drivesInfo{
public:

    vector<string> blockDevs;
    vector< vector<string> > blockDevsParts;
        
    int get_blockDevs();


};
*/



#endif

main.cpp

#include "main.h"


int test0() {
    int r;
    sd_device_enumerator *enumerator = NULL;
    sd_device *dev = NULL;

    // Initialize the Device-Enumerator
    r = sd_device_enumerator_new(&enumerator);
    if (r < 0) {
        printf("Error | Initialize the Device-Enumerator: %s\n", strerror(-r));
    }

    // Set Filter to BLOCK
    r = sd_device_enumerator_add_match_subsystem(enumerator, "block", 0);
    if (r < 0) {
        printf("Error | Set Filter to BLOCK: %s\n", strerror(-r));
    }
    
    // Loop to run through all BLOCK devices
    if (r >= 0) {
        while ((dev = sd_device_enumerator_get_device_next(enumerator)) != NULL) {
            const char *pt_type = NULL;
            r = sd_device_get_property_value(dev, "ID_PART_TABLE_TYPE", &pt_type);
            if (r >= 0) {
                printf("Device: %s\n");
                printf("ID_PART_TABLE_TYPE: %s\n", pt_type);
            }

            sd_device_unref(dev);
            dev = NULL;
            cout << "loop" << endl;
        }
    }

    if (r < 0) {
        printf("Error | at Loop to run through all BLOCK devices: %s\n", strerror(-r));
    }

    if (enumerator) {
        sd_device_enumerator_unref(enumerator);
    }
    if (dev) {
        sd_device_unref(dev);
    }

    return r < 0 ? 1 : 0;
}

int main() {

//     drivesInfo drives;
//     
//     drives.get_blockDevs();
// 
//     for (const string &entry : drives.blockDevs){
//         cout << entry << endl;
//     }

    
    test0();

    return 0;
}

Upvotes: 1

Views: 635

Answers (2)

JFBonzo
JFBonzo

Reputation: 13

The call to sd_device_enumerator_add_match_subsystem() needs to be sd_device_enumerator_add_match_subsystem(enumerator, "block", 1) (notice the third argument). A keyboard and mouse are not block devices. See source:

https://github.com/systemd/systemd/blob/91010bd6ccd363be9e09f22c60d45f5e27c1d2a8/src/libsystemd/sd-device/device-enumerator.c#L126

A "community bot" claims my answer is unclear. My impression from the source is that the third argument decides whether the subsystem (second argument) is filtered for, or filtered out. I'm assuming that the OP is trying to filter for block devices but they are actually filtering them out. This is shown by the working code from KamilCuk that lists keyboards and mice while presumably trying to filter for block devices.

Upvotes: 0

KamilCuk
KamilCuk

Reputation: 140880

You have to first call sd_device_enumerator_get_device_first.

int test0() {
    sd_device_enumerator *enumerator = NULL;
    int r = sd_device_enumerator_new(&enumerator);
    if (r < 0) {
        printf("Error | Initialize the Device-Enumerator: %s\n", strerror(-r));
        return -1;
    }
    r = sd_device_enumerator_add_match_subsystem(enumerator, "block", 0);
    if (r < 0) {
        printf("Error | Set Filter to BLOCK: %s\n", strerror(-r));
        return -1;
    }
    sd_device *dev = NULL;
    for (dev = sd_device_enumerator_get_device_first(enumerator); dev != NULL;
         dev = sd_device_enumerator_get_device_next(enumerator)) {
        const char *pt_type = NULL;
        r = sd_device_get_property_value(dev, "ID_MODEL", &pt_type);
        if (r >= 0) {
            printf("%s\n", pt_type);
        }
        sd_device_unref(dev);
    }
    sd_device_enumerator_unref(enumerator);
    return r < 0 ? 1 : 0;
}

outputs on my pc:

$ g++ -fsanitize=address,undefined -lsystemd 1.cpp && ./a.out 
xHCI_Host_Controller
GK630_Gaming_Keyboard
GK630_Gaming_Keyboard
GK630_Gaming_Keyboard
GK630_Gaming_Keyboard
GK630_Gaming_Keyboard
GK630_Gaming_Keyboard
GK630_Gaming_Keyboard
GK630_Gaming_Keyboard
GK630_Gaming_Keyboard
GK630_Gaming_Keyboard
xHCI_Host_Controller
EHCI_Host_Controller
0024
CSR8510_A10
EHCI_Host_Controller
0024
UDisk
USB_Optical_Mouse
USB_Optical_Mouse
USB_Optical_Mouse
USB_Optical_Mouse
D3162-B1

You might be interested in https://github.com/systemd/systemd/blob/91010bd6ccd363be9e09f22c60d45f5e27c1d2a8/src/libsystemd/sd-device/device-util.h#L52

Upvotes: 2

Related Questions