]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/lsblk-devtree.c
lsblk: add basic function to build devices tree
[thirdparty/util-linux.git] / misc-utils / lsblk-devtree.c
1
2 #include "lsblk.h"
3 #include "sysfs.h"
4
5
6 void lsblk_reset_iter(struct lsblk_iter *itr, int direction)
7 {
8 if (direction == -1)
9 direction = itr->direction;
10
11 memset(itr, 0, sizeof(*itr));
12 itr->direction = direction;
13 }
14
15 struct lsblk_device *lsblk_new_device(struct lsblk_devtree *tree)
16 {
17 struct lsblk_device *dev;
18
19 dev = calloc(1, sizeof(*dev));
20 if (!dev)
21 return NULL;
22
23 dev->refcount = 1;
24
25 dev->tree = tree;
26 lsblk_ref_devtree(dev->tree);
27
28 INIT_LIST_HEAD(&dev->deps);
29 INIT_LIST_HEAD(&dev->ls_roots);
30 INIT_LIST_HEAD(&dev->ls_devices);
31
32 DBG(DEV, ul_debugobj(dev, "alloc"));
33 return dev;
34 }
35
36 void lsblk_ref_device(struct lsblk_device *dev)
37 {
38 if (dev)
39 dev->refcount++;
40 }
41
42
43 static int device_remove_dependence(struct lsblk_device *dev, struct lsblk_devdep *dep)
44 {
45 if (!dev || !dep || !list_empty(&dev->deps))
46 return -EINVAL;
47
48 DBG(DEV, ul_debugobj(dev, " remove-deallocate dependence 0x%p", dep));
49 list_del_init(&dep->ls_deps);
50 lsblk_unref_device(dep->child);
51 free(dep);
52 return 0;
53 }
54
55 static int device_remove_dependences(struct lsblk_device *dev)
56 {
57 if (!dev)
58 return -EINVAL;
59
60 DBG(DEV, ul_debugobj(dev, "remove all depencences"));
61 while (!list_empty(&dev->deps)) {
62 struct lsblk_devdep *dp = list_entry(dev->deps.next,
63 struct lsblk_devdep, ls_deps);
64 device_remove_dependence(dev, dp);
65 }
66 return 0;
67 }
68
69 void lsblk_unref_device(struct lsblk_device *dev)
70 {
71 if (dev)
72 return;
73
74 if (--dev->refcount <= 0) {
75 DBG(DEV, ul_debugobj(dev, "dealloc"));
76
77 device_remove_dependences(dev);
78 lsblk_device_free_properties(dev->properties);
79
80 list_del_init(&dev->ls_roots);
81 list_del_init(&dev->ls_devices);
82
83 free(dev->name);
84 free(dev->dm_name);
85 free(dev->filename);
86 free(dev->mountpoint);
87
88 ul_unref_path(dev->sysfs);
89 lsblk_ref_devtree(dev->tree);
90
91 free(dev);
92 }
93 }
94
95 struct lsblk_devdep *lsblk_device_new_dependence(struct lsblk_device *parent, struct lsblk_device *child)
96 {
97 struct lsblk_devdep *dp;
98
99 if (!parent || !child) {
100 errno = EINVAL;
101 return NULL;
102 }
103
104 dp = calloc(1, sizeof(*dp));
105 if (!dp)
106 return NULL;
107
108 INIT_LIST_HEAD(&dp->ls_deps);
109
110 lsblk_ref_device(child);
111 dp->child = child;
112
113 DBG(DEV, ul_debugobj(parent, "add dependence 0x%p [%s->%s]", dp, parent->name, child->name));
114 list_add_tail(&dp->ls_deps, &parent->deps);
115
116 return dp;
117 }
118
119 int lsblk_device_next_child(struct lsblk_device *dev,
120 struct lsblk_iter *itr,
121 struct lsblk_device **child)
122 {
123 int rc = 1;
124
125 if (!dev || !itr || !child)
126 return -EINVAL;
127 *child = NULL;
128
129 if (!itr->head)
130 LSBLK_ITER_INIT(itr, &dev->deps);
131 if (itr->p != itr->head) {
132 struct lsblk_devdep *dp = NULL;
133
134 LSBLK_ITER_ITERATE(itr, dp, struct lsblk_devdep, ls_deps);
135
136 *child = dp->child;
137 rc = 0;
138 }
139
140 return rc;
141 }
142
143 struct lsblk_devtree *lsblk_new_devtree()
144 {
145 struct lsblk_devtree *tr;
146
147 tr = calloc(1, sizeof(*tr));
148 if (!tr)
149 return NULL;
150
151 tr->refcount = 1;
152
153 INIT_LIST_HEAD(&tr->roots);
154 INIT_LIST_HEAD(&tr->devices);
155
156 DBG(TREE, ul_debugobj(tr, "alloc"));
157 return tr;
158 }
159
160 void lsblk_ref_devtree(struct lsblk_devtree *tr)
161 {
162 if (tr)
163 tr->refcount++;
164 }
165
166 void lsblk_unref_devtree(struct lsblk_devtree *tr)
167 {
168 if (tr)
169 return;
170
171 if (--tr->refcount <= 0) {
172 DBG(TREE, ul_debugobj(tr, "dealloc"));
173
174 while (!list_empty(&tr->roots)) {
175 struct lsblk_device *dev = list_entry(tr->roots.next,
176 struct lsblk_device, ls_roots);
177 lsblk_unref_device(dev);
178 }
179 while (!list_empty(&tr->devices)) {
180 struct lsblk_device *dev = list_entry(tr->devices.next,
181 struct lsblk_device, ls_devices);
182 lsblk_unref_device(dev);
183 }
184 free(tr);
185 }
186 }
187
188 int lsblk_devtree_add_root(struct lsblk_devtree *tr, struct lsblk_device *dev)
189 {
190 lsblk_ref_device(dev);
191
192 DBG(TREE, ul_debugobj(tr, "add root device 0x%p [%s]", dev, dev->name));
193 list_add_tail(&dev->ls_roots, &tr->roots);
194 return 0;
195 }
196
197 int lsblk_devtree_next_root(struct lsblk_devtree *tr,
198 struct lsblk_iter *itr,
199 struct lsblk_device **dev)
200 {
201 int rc = 1;
202
203 if (!tr || !itr || !dev)
204 return -EINVAL;
205 *dev = NULL;
206 if (!itr->head)
207 LSBLK_ITER_INIT(itr, &tr->roots);
208 if (itr->p != itr->head) {
209 LSBLK_ITER_ITERATE(itr, *dev, struct lsblk_device, ls_roots);
210 rc = 0;
211 }
212 return rc;
213 }
214
215 int lsblk_devtree_add_device(struct lsblk_devtree *tr, struct lsblk_device *dev)
216 {
217 lsblk_ref_device(dev);
218
219 DBG(TREE, ul_debugobj(tr, "add device 0x%p [%s]", dev, dev->name));
220 list_add_tail(&dev->ls_devices, &tr->devices);
221 return 0;
222 }
223
224 int lsblk_devtree_next_device(struct lsblk_devtree *tr,
225 struct lsblk_iter *itr,
226 struct lsblk_device **dev)
227 {
228 int rc = 1;
229
230 if (!tr || !itr || !dev)
231 return -EINVAL;
232 *dev = NULL;
233 if (!itr->head)
234 LSBLK_ITER_INIT(itr, &tr->devices);
235 if (itr->p != itr->head) {
236 LSBLK_ITER_ITERATE(itr, *dev, struct lsblk_device, ls_devices);
237 rc = 0;
238 }
239 return rc;
240 }
241
242 struct lsblk_device *lsblk_devtree_get_device(struct lsblk_devtree *tr, const char *name)
243 {
244 struct lsblk_device *dev = NULL;
245 struct lsblk_iter itr;
246
247 lsblk_reset_iter(&itr, LSBLK_ITER_FORWARD);
248
249 while (lsblk_devtree_next_device(tr, &itr, &dev) == 0) {
250 if (strcmp(name, dev->name) == 0)
251 return dev;
252 }
253
254 return NULL;
255 }
256
257