1"""
2Manage and query udev info
3
4.. versionadded:: 2015.8.0
5
6"""
7
8import logging
9
10import salt.modules.cmdmod
11import salt.utils.path
12from salt.exceptions import CommandExecutionError
13
14__salt__ = {
15    "cmd.run_all": salt.modules.cmdmod.run_all,
16}
17
18log = logging.getLogger(__name__)
19
20
21def __virtual__():
22    """
23    Only work when udevadm is installed.
24    """
25    return salt.utils.path.which_bin(["udevadm"]) is not None
26
27
28def _parse_udevadm_info(udev_info):
29    """
30    Parse the info returned by udevadm command.
31    """
32    devices = []
33    dev = {}
34
35    for line in (line.strip() for line in udev_info.splitlines()):
36        if line:
37            line = line.split(":", 1)
38            if len(line) != 2:
39                continue
40            query, data = line
41            if query == "E":
42                if query not in dev:
43                    dev[query] = {}
44                key, val = data.strip().split("=", 1)
45
46                try:
47                    val = int(val)
48                except ValueError:
49                    try:
50                        val = float(val)
51                    except ValueError:
52                        pass  # Quiet, this is not a number.
53
54                dev[query][key] = val
55            else:
56                if query not in dev:
57                    dev[query] = []
58                dev[query].append(data.strip())
59        else:
60            if dev:
61                devices.append(_normalize_info(dev))
62                dev = {}
63    if dev:
64        _normalize_info(dev)
65        devices.append(_normalize_info(dev))
66
67    return devices
68
69
70def _normalize_info(dev):
71    """
72    Replace list with only one element to the value of the element.
73
74    :param dev:
75    :return:
76    """
77    for sect, val in dev.items():
78        if len(val) == 1:
79            dev[sect] = val[0]
80
81    return dev
82
83
84def info(dev):
85    """
86    Extract all info delivered by udevadm
87
88    CLI Example:
89
90    .. code-block:: bash
91
92        salt '*' udev.info /dev/sda
93        salt '*' udev.info /sys/class/net/eth0
94    """
95    if "sys" in dev:
96        qtype = "path"
97    else:
98        qtype = "name"
99
100    cmd = "udevadm info --export --query=all --{}={}".format(qtype, dev)
101    udev_result = __salt__["cmd.run_all"](cmd, output_loglevel="quiet")
102
103    if udev_result["retcode"] != 0:
104        raise CommandExecutionError(udev_result["stderr"])
105
106    return _parse_udevadm_info(udev_result["stdout"])[0]
107
108
109def env(dev):
110    """
111    Return all environment variables udev has for dev
112
113    CLI Example:
114
115    .. code-block:: bash
116
117        salt '*' udev.env /dev/sda
118        salt '*' udev.env /sys/class/net/eth0
119    """
120    return info(dev).get("E", None)
121
122
123def name(dev):
124    """
125    Return the actual dev name(s?) according to udev for dev
126
127    CLI Example:
128
129    .. code-block:: bash
130
131        salt '*' udev.dev /dev/sda
132        salt '*' udev.dev /sys/class/net/eth0
133    """
134    return info(dev).get("N", None)
135
136
137def path(dev):
138    """
139    Return the physical device path(s?) according to udev for dev
140
141    CLI Example:
142
143    .. code-block:: bash
144
145        salt '*' udev.path /dev/sda
146        salt '*' udev.path /sys/class/net/eth0
147    """
148    return info(dev).get("P", None)
149
150
151def links(dev):
152    """
153    Return all udev-created device symlinks
154
155    CLI Example:
156
157    .. code-block:: bash
158
159        salt '*' udev.links /dev/sda
160        salt '*' udev.links /sys/class/net/eth0
161    """
162    return info(dev).get("S", None)
163
164
165def exportdb():
166    """
167    Return all the udev database
168
169    CLI Example:
170
171    .. code-block:: bash
172
173        salt '*' udev.exportdb
174    """
175
176    cmd = "udevadm info --export-db"
177    udev_result = __salt__["cmd.run_all"](cmd, output_loglevel="quiet")
178
179    if udev_result["retcode"]:
180        raise CommandExecutionError(udev_result["stderr"])
181
182    return _parse_udevadm_info(udev_result["stdout"])
183