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