mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 00:47:10 +09:00
Merge pull request #28373 from DaanDeMeyer/udevadm-query
Add --json and filtering options for --export-db to udevadm info
This commit is contained in:
@@ -229,7 +229,82 @@
|
||||
<xi:include href="version-info.xml" xpointer="v243"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--subsystem-match<optional>=SUBSYSTEM</optional></option></term>
|
||||
<term><option>--subsystem-nomatch<optional>=SUBSYSTEM</optional></option></term>
|
||||
<listitem>
|
||||
<para>When used with <option>--export-db</option>, only show devices of or not of the given
|
||||
subsystem respectively.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--attr-match<optional>=FILE[=VALUE]</optional></option></term>
|
||||
<term><option>--attr-nomatch<optional>=FILE[=VALUE]</optional></option></term>
|
||||
<listitem>
|
||||
<para>When used with <option>--export-db</option>, only show devices matching or not matching the
|
||||
given attribute respectively.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--property-match<optional>=KEY=VALUE</optional></option></term>
|
||||
<listitem>
|
||||
<para>When used with <option>--export-db</option>, only show devices matching the given property
|
||||
and value.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--tag-match<optional>=TAG</optional></option></term>
|
||||
<listitem>
|
||||
<para>When used with <option>--export-db</option>, only show devices with the given tag.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--sysname-match<optional>=NAME</optional></option></term>
|
||||
<listitem>
|
||||
<para>When used with <option>--export-db</option>, only show devices with the given
|
||||
<literal>/sys</literal> path.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--name-match<optional>=NAME</optional></option></term>
|
||||
<listitem>
|
||||
<para>When used with <option>--export-db</option>, only show devices with the given name in
|
||||
<literal>/dev</literal>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--parent-match<optional>=NAME</optional></option></term>
|
||||
<listitem>
|
||||
<para>When used with <option>--export-db</option>, only show devices with the given parent
|
||||
device.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--initialized-match</option></term>
|
||||
<term><option>--initialized-nomatch</option></term>
|
||||
<listitem>
|
||||
<para>When used with <option>--export-db</option>, only show devices that are initialized or not
|
||||
initialized respectively.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="json" />
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
</variablelist>
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
#include "device-enumerator-private.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "devnum-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "glyph-util.h"
|
||||
#include "json.h"
|
||||
#include "pager.h"
|
||||
#include "parse-argument.h"
|
||||
#include "sort-util.h"
|
||||
#include "static-destruct.h"
|
||||
#include "string-table.h"
|
||||
@@ -35,6 +38,7 @@ typedef enum ActionType {
|
||||
ACTION_ATTRIBUTE_WALK,
|
||||
ACTION_DEVICE_ID_FILE,
|
||||
ACTION_TREE,
|
||||
ACTION_EXPORT,
|
||||
} ActionType;
|
||||
|
||||
typedef enum QueryType {
|
||||
@@ -52,6 +56,7 @@ static bool arg_value = false;
|
||||
static const char *arg_export_prefix = NULL;
|
||||
static usec_t arg_wait_for_initialization_timeout = 0;
|
||||
PagerFlags arg_pager_flags = 0;
|
||||
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||
|
||||
/* Put a limit on --tree descent level to not exhaust our stack */
|
||||
#define TREE_DEPTH_MAX 64
|
||||
@@ -260,6 +265,39 @@ static int print_record(sd_device *device, const char *prefix) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int record_to_json(sd_device *device, JsonVariant **ret) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
const char *str;
|
||||
int r;
|
||||
|
||||
assert(device);
|
||||
assert(ret);
|
||||
|
||||
/* We don't show any shorthand fields here as done in print_record() except for SYSNAME and SYSNUM as
|
||||
* all the other ones have a matching property which will already be included. */
|
||||
|
||||
if (sd_device_get_sysname(device, &str) >= 0) {
|
||||
r = json_variant_set_field_string(&v, "SYSNAME", str);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (sd_device_get_sysnum(device, &str) >= 0) {
|
||||
r = json_variant_set_field_string(&v, "SYSNUM", str);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
FOREACH_DEVICE_PROPERTY(device, key, val) {
|
||||
r = json_variant_set_field_string(&v, key, val);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stat_device(const char *name, bool export, const char *prefix) {
|
||||
struct stat statbuf;
|
||||
|
||||
@@ -280,18 +318,11 @@ static int stat_device(const char *name, bool export, const char *prefix) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int export_devices(void) {
|
||||
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
|
||||
static int export_devices(sd_device_enumerator *e) {
|
||||
sd_device *d;
|
||||
int r;
|
||||
|
||||
r = sd_device_enumerator_new(&e);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = sd_device_enumerator_allow_uninitialized(e);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set allowing uninitialized flag: %m");
|
||||
assert(e);
|
||||
|
||||
r = device_enumerator_scan_devices(e);
|
||||
if (r < 0)
|
||||
@@ -300,7 +331,17 @@ static int export_devices(void) {
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
FOREACH_DEVICE_AND_SUBSYSTEM(e, d)
|
||||
(void) print_record(d, NULL);
|
||||
if (arg_json_format_flags & JSON_FORMAT_OFF)
|
||||
(void) print_record(d, NULL);
|
||||
else {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
|
||||
r = record_to_json(d, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) json_variant_dump(v, arg_json_format_flags, stdout, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -466,7 +507,19 @@ static int query_device(QueryType query, sd_device* device) {
|
||||
return 0;
|
||||
|
||||
case QUERY_ALL:
|
||||
return print_record(device, NULL);
|
||||
if (arg_json_format_flags & JSON_FORMAT_OFF)
|
||||
return print_record(device, NULL);
|
||||
else {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
|
||||
r = record_to_json(device, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) json_variant_dump(v, arg_json_format_flags, stdout, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
@@ -499,7 +552,24 @@ static int help(void) {
|
||||
" -c --cleanup-db Clean up the udev database\n"
|
||||
" -w --wait-for-initialization[=SECONDS]\n"
|
||||
" Wait for device to be initialized\n"
|
||||
" --no-pager Do not pipe output into a pager\n",
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --json=pretty|short|off Generate JSON output\n"
|
||||
" --subsystem-match=SUBSYSTEM\n"
|
||||
" Query devices matching a subsystem\n"
|
||||
" --subsystem-nomatch=SUBSYSTEM\n"
|
||||
" Query devices not matching a subsystem\n"
|
||||
" --attr-match=FILE[=VALUE]\n"
|
||||
" Query devices that match an attribute\n"
|
||||
" --attr-nomatch=FILE[=VALUE]\n"
|
||||
" Query devices that do not match an attribute\n"
|
||||
" --property-match=KEY=VALUE\n"
|
||||
" Query devices with matching properties\n"
|
||||
" --tag-match=TAG Query devices with a matching tag\n"
|
||||
" --sysname-match=NAME Query devices with this /sys path\n"
|
||||
" --name-match=NAME Query devices with this /dev name\n"
|
||||
" --parent-match=NAME Query devices with this parent device\n"
|
||||
" --initialized-match Query devices that are already initialized\n"
|
||||
" --initialized-nomatch Query devices that are not initialized yet\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
@@ -662,7 +732,49 @@ static int print_tree(sd_device* below) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ensure_device_enumerator(sd_device_enumerator **e) {
|
||||
int r;
|
||||
|
||||
assert(e);
|
||||
|
||||
if (*e)
|
||||
return 0;
|
||||
|
||||
r = sd_device_enumerator_new(e);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create device enumerator: %m");
|
||||
|
||||
r = sd_device_enumerator_allow_uninitialized(*e);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allow uninitialized devices: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_key_value_argument(const char *s, char **key, char **value) {
|
||||
_cleanup_free_ char *k = NULL, *v = NULL;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(key);
|
||||
assert(value);
|
||||
|
||||
r = extract_many_words(&s, "=", EXTRACT_DONT_COALESCE_SEPARATORS, &k, &v, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse key/value pair %s: %m", s);
|
||||
if (r < 2)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing '=' in key/value pair %s.", s);
|
||||
|
||||
if (!filename_is_valid(k))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a valid key name", k);
|
||||
|
||||
free_and_replace(*key, k);
|
||||
free_and_replace(*value, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int info_main(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
|
||||
_cleanup_strv_free_ char **devices = NULL;
|
||||
_cleanup_free_ char *name = NULL;
|
||||
int c, r, ret;
|
||||
@@ -671,26 +783,50 @@ int info_main(int argc, char *argv[], void *userdata) {
|
||||
ARG_PROPERTY = 0x100,
|
||||
ARG_VALUE,
|
||||
ARG_NO_PAGER,
|
||||
ARG_JSON,
|
||||
ARG_SUBSYSTEM_MATCH,
|
||||
ARG_SUBSYSTEM_NOMATCH,
|
||||
ARG_ATTR_MATCH,
|
||||
ARG_ATTR_NOMATCH,
|
||||
ARG_PROPERTY_MATCH,
|
||||
ARG_TAG_MATCH,
|
||||
ARG_SYSNAME_MATCH,
|
||||
ARG_NAME_MATCH,
|
||||
ARG_PARENT_MATCH,
|
||||
ARG_INITIALIZED_MATCH,
|
||||
ARG_INITIALIZED_NOMATCH,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "attribute-walk", no_argument, NULL, 'a' },
|
||||
{ "tree", no_argument, NULL, 't' },
|
||||
{ "cleanup-db", no_argument, NULL, 'c' },
|
||||
{ "device-id-of-file", required_argument, NULL, 'd' },
|
||||
{ "export", no_argument, NULL, 'x' },
|
||||
{ "export-db", no_argument, NULL, 'e' },
|
||||
{ "export-prefix", required_argument, NULL, 'P' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "name", required_argument, NULL, 'n' },
|
||||
{ "path", required_argument, NULL, 'p' },
|
||||
{ "property", required_argument, NULL, ARG_PROPERTY },
|
||||
{ "query", required_argument, NULL, 'q' },
|
||||
{ "root", no_argument, NULL, 'r' },
|
||||
{ "value", no_argument, NULL, ARG_VALUE },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "wait-for-initialization", optional_argument, NULL, 'w' },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
{ "attribute-walk", no_argument, NULL, 'a' },
|
||||
{ "tree", no_argument, NULL, 't' },
|
||||
{ "cleanup-db", no_argument, NULL, 'c' },
|
||||
{ "device-id-of-file", required_argument, NULL, 'd' },
|
||||
{ "export", no_argument, NULL, 'x' },
|
||||
{ "export-db", no_argument, NULL, 'e' },
|
||||
{ "export-prefix", required_argument, NULL, 'P' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "name", required_argument, NULL, 'n' },
|
||||
{ "path", required_argument, NULL, 'p' },
|
||||
{ "property", required_argument, NULL, ARG_PROPERTY },
|
||||
{ "query", required_argument, NULL, 'q' },
|
||||
{ "root", no_argument, NULL, 'r' },
|
||||
{ "value", no_argument, NULL, ARG_VALUE },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "wait-for-initialization", optional_argument, NULL, 'w' },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
{ "json", required_argument, NULL, ARG_JSON },
|
||||
{ "subsystem-match", required_argument, NULL, ARG_SUBSYSTEM_MATCH },
|
||||
{ "subsystem-nomatch", required_argument, NULL, ARG_SUBSYSTEM_NOMATCH },
|
||||
{ "attr-match", required_argument, NULL, ARG_ATTR_MATCH },
|
||||
{ "attr-nomatch", required_argument, NULL, ARG_ATTR_NOMATCH },
|
||||
{ "property-match", required_argument, NULL, ARG_PROPERTY_MATCH },
|
||||
{ "tag-match", required_argument, NULL, ARG_TAG_MATCH },
|
||||
{ "sysname-match", required_argument, NULL, ARG_SYSNAME_MATCH },
|
||||
{ "name-match", required_argument, NULL, ARG_NAME_MATCH },
|
||||
{ "parent-match", required_argument, NULL, ARG_PARENT_MATCH },
|
||||
{ "initialized-match", no_argument, NULL, ARG_INITIALIZED_MATCH },
|
||||
{ "initialized-nomatch", no_argument, NULL, ARG_INITIALIZED_NOMATCH },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -761,7 +897,8 @@ int info_main(int argc, char *argv[], void *userdata) {
|
||||
action = ACTION_TREE;
|
||||
break;
|
||||
case 'e':
|
||||
return export_devices();
|
||||
action = ACTION_EXPORT;
|
||||
break;
|
||||
case 'c':
|
||||
cleanup_db();
|
||||
return 0;
|
||||
@@ -787,6 +924,111 @@ int info_main(int argc, char *argv[], void *userdata) {
|
||||
case ARG_NO_PAGER:
|
||||
arg_pager_flags |= PAGER_DISABLE;
|
||||
break;
|
||||
|
||||
case ARG_JSON:
|
||||
r = parse_json_argument(optarg, &arg_json_format_flags);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case ARG_SUBSYSTEM_MATCH:
|
||||
case ARG_SUBSYSTEM_NOMATCH:
|
||||
r = ensure_device_enumerator(&e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_enumerator_add_match_subsystem(e, optarg, c == ARG_SUBSYSTEM_MATCH);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add%s subsystem match '%s': %m",
|
||||
c == ARG_SUBSYSTEM_MATCH ? "" : " negative", optarg);
|
||||
|
||||
break;
|
||||
|
||||
case ARG_ATTR_MATCH:
|
||||
case ARG_ATTR_NOMATCH: {
|
||||
_cleanup_free_ char *k = NULL, *v = NULL;
|
||||
|
||||
r = ensure_device_enumerator(&e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = parse_key_value_argument(optarg, &k, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_enumerator_add_match_sysattr(e, k, v, c == ARG_ATTR_MATCH);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add%s sysattr match '%s=%s': %m",
|
||||
c == ARG_ATTR_MATCH ? "" : " negative", k, v);
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_PROPERTY_MATCH: {
|
||||
_cleanup_free_ char *k = NULL, *v = NULL;
|
||||
|
||||
r = ensure_device_enumerator(&e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = parse_key_value_argument(optarg, &k, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_enumerator_add_match_property_required(e, k, v);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add property match '%s=%s': %m", k, v);
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_TAG_MATCH:
|
||||
r = ensure_device_enumerator(&e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_enumerator_add_match_tag(e, optarg);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add tag match '%s': %m", optarg);
|
||||
break;
|
||||
|
||||
case ARG_SYSNAME_MATCH:
|
||||
r = ensure_device_enumerator(&e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_enumerator_add_match_sysname(e, optarg);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add sysname match '%s': %m", optarg);
|
||||
break;
|
||||
|
||||
case ARG_NAME_MATCH:
|
||||
case ARG_PARENT_MATCH: {
|
||||
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||
|
||||
r = find_device(optarg, c == ARG_NAME_MATCH ? "/dev" : "/sys", &dev);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open the device '%s': %m", optarg);
|
||||
|
||||
r = ensure_device_enumerator(&e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = device_enumerator_add_match_parent_incremental(e, dev);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_INITIALIZED_MATCH:
|
||||
case ARG_INITIALIZED_NOMATCH:
|
||||
r = ensure_device_enumerator(&e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = device_enumerator_add_match_is_initialized(e, c == ARG_INITIALIZED_MATCH ? MATCH_INITIALIZED_YES : MATCH_INITIALIZED_NO);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set initialized filter: %m");
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
default:
|
||||
@@ -801,6 +1043,14 @@ int info_main(int argc, char *argv[], void *userdata) {
|
||||
return stat_device(name, arg_export, arg_export_prefix);
|
||||
}
|
||||
|
||||
if (action == ACTION_EXPORT) {
|
||||
r = ensure_device_enumerator(&e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return export_devices(e);
|
||||
}
|
||||
|
||||
r = strv_extend_strv(&devices, argv + optind, false);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build argument list: %m");
|
||||
|
||||
@@ -57,6 +57,9 @@ udevadm info --property DEVNAME --value /sys/class/net/$netdev
|
||||
udevadm info --property HELLO /sys/class/net/$netdev
|
||||
udevadm info -p class/net/$netdev
|
||||
udevadm info -p /class/net/$netdev
|
||||
udevadm info --json=off -p class/net/$netdev
|
||||
udevadm info --json=pretty -p class/net/$netdev | jq .
|
||||
udevadm info --json=short -p class/net/$netdev | jq .
|
||||
udevadm info -n null
|
||||
udevadm info -q all /sys/class/net/$netdev
|
||||
udevadm info -q name /dev/null
|
||||
@@ -74,6 +77,20 @@ udevadm info -x -q path /sys/class/net/$netdev
|
||||
udevadm info -P TEST_ /sys/class/net/$netdev
|
||||
udevadm info -d /dev/null
|
||||
udevadm info -e >/dev/null
|
||||
udevadm info -e --json=off >/dev/null
|
||||
udevadm info -e --json=pretty | jq . >/dev/null
|
||||
udevadm info -e --json=short | jq . >/dev/null
|
||||
udevadm info -e --subsystem-match acpi >/dev/null
|
||||
udevadm info -e --subsystem-nomatch acpi >/dev/null
|
||||
udevadm info -e --attr-match ifindex=2 >/dev/null
|
||||
udevadm info -e --attr-nomatch ifindex=2 >/dev/null
|
||||
udevadm info -e --property-match SUBSYSTEM=acpi >/dev/null
|
||||
udevadm info -e --tag-match systemd >/dev/null
|
||||
udevadm info -e --sysname-match lo >/dev/null
|
||||
udevadm info -e --name-match /sys/class/net/$netdev >/dev/null
|
||||
udevadm info -e --parent-match /sys/class/net/$netdev >/dev/null
|
||||
udevadm info -e --initialized-match >/dev/null
|
||||
udevadm info -e --initialized-nomatch >/dev/null
|
||||
# udevadm info -c
|
||||
udevadm info -w /sys/class/net/$netdev
|
||||
udevadm info --wait-for-initialization=5 /sys/class/net/$netdev
|
||||
|
||||
Reference in New Issue
Block a user