1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4
5 #include "sd-device.h"
6
7 #include "alloc-util.h"
8 #include "device-enumerator-private.h"
9 #include "glyph-util.h"
10 #include "path-util.h"
11 #include "string-util.h"
12 #include "sysfs-show.h"
13 #include "terminal-util.h"
14 #include "util.h"
15
show_sysfs_one(const char * seat,sd_device ** dev_list,size_t * i_dev,size_t n_dev,const char * sub,const char * prefix,unsigned n_columns,OutputFlags flags)16 static int show_sysfs_one(
17 const char *seat,
18 sd_device **dev_list,
19 size_t *i_dev,
20 size_t n_dev,
21 const char *sub,
22 const char *prefix,
23 unsigned n_columns,
24 OutputFlags flags) {
25
26 size_t max_width;
27 int r;
28
29 assert(seat);
30 assert(dev_list);
31 assert(i_dev);
32 assert(prefix);
33
34 if (flags & OUTPUT_FULL_WIDTH)
35 max_width = SIZE_MAX;
36 else if (n_columns < 10)
37 max_width = 10;
38 else
39 max_width = n_columns;
40
41 while (*i_dev < n_dev) {
42 const char *sysfs, *sn, *name = NULL, *subsystem, *sysname;
43 _cleanup_free_ char *k = NULL, *l = NULL;
44 size_t lookahead;
45 bool is_master;
46
47 if (sd_device_get_syspath(dev_list[*i_dev], &sysfs) < 0 ||
48 !path_startswith(sysfs, sub))
49 return 0;
50
51 if (sd_device_get_property_value(dev_list[*i_dev], "ID_SEAT", &sn) < 0 || isempty(sn))
52 sn = "seat0";
53
54 /* Explicitly also check for tag 'seat' here */
55 if (!streq(seat, sn) ||
56 sd_device_has_current_tag(dev_list[*i_dev], "seat") <= 0 ||
57 sd_device_get_subsystem(dev_list[*i_dev], &subsystem) < 0 ||
58 sd_device_get_sysname(dev_list[*i_dev], &sysname) < 0) {
59 (*i_dev)++;
60 continue;
61 }
62
63 is_master = sd_device_has_current_tag(dev_list[*i_dev], "master-of-seat") > 0;
64
65 if (sd_device_get_sysattr_value(dev_list[*i_dev], "name", &name) < 0)
66 (void) sd_device_get_sysattr_value(dev_list[*i_dev], "id", &name);
67
68 /* Look if there's more coming after this */
69 for (lookahead = *i_dev + 1; lookahead < n_dev; lookahead++) {
70 const char *lookahead_sysfs;
71
72 if (sd_device_get_syspath(dev_list[lookahead], &lookahead_sysfs) < 0)
73 continue;
74
75 if (path_startswith(lookahead_sysfs, sub) &&
76 !path_startswith(lookahead_sysfs, sysfs)) {
77 const char *lookahead_sn;
78
79 if (sd_device_get_property_value(dev_list[lookahead], "ID_SEAT", &lookahead_sn) < 0 ||
80 isempty(lookahead_sn))
81 lookahead_sn = "seat0";
82
83 if (streq(seat, lookahead_sn) && sd_device_has_current_tag(dev_list[lookahead], "seat") > 0)
84 break;
85 }
86 }
87
88 k = ellipsize(sysfs, max_width, 20);
89 if (!k)
90 return -ENOMEM;
91
92 printf("%s%s%s\n", prefix, special_glyph(lookahead < n_dev ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT), k);
93
94 if (asprintf(&l,
95 "%s%s:%s%s%s%s",
96 is_master ? "[MASTER] " : "",
97 subsystem, sysname,
98 name ? " \"" : "", strempty(name), name ? "\"" : "") < 0)
99 return -ENOMEM;
100
101 free(k);
102 k = ellipsize(l, max_width, 70);
103 if (!k)
104 return -ENOMEM;
105
106 printf("%s%s%s\n", prefix, lookahead < n_dev ? special_glyph(SPECIAL_GLYPH_TREE_VERTICAL) : " ", k);
107
108 if (++(*i_dev) < n_dev) {
109 _cleanup_free_ char *p = NULL;
110
111 p = strjoin(prefix, lookahead < n_dev ? special_glyph(SPECIAL_GLYPH_TREE_VERTICAL) : " ");
112 if (!p)
113 return -ENOMEM;
114
115 r = show_sysfs_one(seat, dev_list, i_dev, n_dev, sysfs, p,
116 n_columns == UINT_MAX || n_columns < 2 ? n_columns : n_columns - 2,
117 flags);
118 if (r < 0)
119 return r;
120 }
121
122 }
123
124 return 0;
125 }
126
show_sysfs(const char * seat,const char * prefix,unsigned n_columns,OutputFlags flags)127 int show_sysfs(const char *seat, const char *prefix, unsigned n_columns, OutputFlags flags) {
128 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
129 size_t n_dev = 0, i = 0;
130 sd_device **dev_list;
131 int r;
132
133 if (n_columns <= 0)
134 n_columns = columns();
135
136 prefix = strempty(prefix);
137
138 if (isempty(seat))
139 seat = "seat0";
140
141 r = sd_device_enumerator_new(&e);
142 if (r < 0)
143 return r;
144
145 r = sd_device_enumerator_allow_uninitialized(e);
146 if (r < 0)
147 return r;
148
149 r = sd_device_enumerator_add_match_tag(e, streq(seat, "seat0") ? "seat" : seat);
150 if (r < 0)
151 return r;
152
153 r = device_enumerator_scan_devices(e);
154 if (r < 0)
155 return r;
156
157 dev_list = device_enumerator_get_devices(e, &n_dev);
158
159 if (dev_list && n_dev > 0)
160 show_sysfs_one(seat, dev_list, &i, n_dev, "/", prefix, n_columns, flags);
161 else
162 printf("%s%s%s\n", prefix, special_glyph(SPECIAL_GLYPH_TREE_RIGHT), "(none)");
163
164 return 0;
165 }
166