summaryrefslogtreecommitdiffstats
path: root/src/udev/udevadm-util.c
blob: 9649e5a2075b9672913152f5c654043dc8550956 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* SPDX-License-Identifier: GPL-2.0-or-later */

#include <errno.h>

#include "alloc-util.h"
#include "bus-error.h"
#include "bus-util.h"
#include "device-private.h"
#include "path-util.h"
#include "udevadm-util.h"
#include "unit-name.h"

static int find_device_from_path(const char *path, sd_device **ret) {
        if (path_startswith(path, "/sys/"))
                return sd_device_new_from_syspath(ret, path);

        if (path_startswith(path, "/dev/")) {
                struct stat st;

                if (stat(path, &st) < 0)
                        return -errno;

                return sd_device_new_from_stat_rdev(ret, &st);
        }

        return -EINVAL;
}

static int find_device_from_unit(const char *unit_name, sd_device **ret) {
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
        _cleanup_free_ char *unit_path = NULL, *syspath = NULL;
        int r;

        if (!unit_name_is_valid(unit_name, UNIT_NAME_PLAIN))
                return -EINVAL;

        if (unit_name_to_type(unit_name) != UNIT_DEVICE)
                return -EINVAL;

        r = bus_connect_system_systemd(&bus);
        if (r < 0) {
                _cleanup_free_ char *path = NULL;

                log_debug_errno(r, "Failed to open connection to systemd, using unit name as syspath: %m");

                r = unit_name_to_path(unit_name, &path);
                if (r < 0)
                        return log_debug_errno(r, "Failed to convert \"%s\" to a device path: %m", unit_name);

                return find_device_from_path(path, ret);
        }

        unit_path = unit_dbus_path_from_name(unit_name);
        if (!unit_path)
                return -ENOMEM;

        r = sd_bus_get_property_string(
                        bus,
                        "org.freedesktop.systemd1",
                        unit_path,
                        "org.freedesktop.systemd1.Device",
                        "SysFSPath",
                        &error,
                        &syspath);
        if (r < 0)
                return log_debug_errno(r, "Failed to get SysFSPath= dbus property for %s: %s",
                                       unit_name, bus_error_message(&error, r));

        return sd_device_new_from_syspath(ret, syspath);
}

int find_device(const char *id, const char *prefix, sd_device **ret) {
        _cleanup_free_ char *path = NULL;
        int r;

        assert(id);
        assert(ret);

        if (prefix) {
                if (!path_startswith(id, prefix)) {
                        id = path = path_join(prefix, id);
                        if (!path)
                                return -ENOMEM;
                }
        } else {
                /* In cases where the argument is generic (no prefix specified),
                 * check if the argument looks like a device unit name. */
                r = find_device_from_unit(id, ret);
                if (r >= 0)
                        return r;
        }

        return find_device_from_path(id, ret);
}

int find_device_with_action(const char *id, sd_device_action_t action, sd_device **ret) {
        _cleanup_free_ char *path = NULL;

        assert(id);
        assert(ret);
        assert(action >= 0 && action < _SD_DEVICE_ACTION_MAX);

        if (!path_startswith(id, "/sys")) {
                path = path_join("/sys", id);
                if (!path)
                        return -ENOMEM;
                id = path;
        }

        return device_new_from_synthetic_event(ret, id, device_action_to_string(action));
}

int parse_device_action(const char *str, sd_device_action_t *action) {
        sd_device_action_t a;

        assert(str);
        assert(action);

        if (streq(str, "help")) {
                dump_device_action_table();
                return 0;
        }

        a = device_action_from_string(str);
        if (a < 0)
                return a;

        *action = a;
        return 1;
}