blob: 2728a2dc562ac7a830a3fd43f0f652e6630298c6 [file] [log] [blame]
Daniel Lezcano7c15fad2016-02-18 15:57:43 +00001/*
2 * Power debug tool (powerdebug)
Daniel Lezcanoc193b602011-06-08 23:30:00 +02003 *
Daniel Lezcano7c15fad2016-02-18 15:57:43 +00004 * Copyright (C) 2016, Linaro Limited.
Daniel Lezcanoc193b602011-06-08 23:30:00 +02005 *
Daniel Lezcano7c15fad2016-02-18 15:57:43 +00006 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
Daniel Lezcanoc193b602011-06-08 23:30:00 +020010 *
Daniel Lezcano7c15fad2016-02-18 15:57:43 +000011 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Daniel Lezcanoc193b602011-06-08 23:30:00 +020015 *
Daniel Lezcano7c15fad2016-02-18 15:57:43 +000016 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 */
Daniel Lezcanoc193b602011-06-08 23:30:00 +020021
22#define _GNU_SOURCE
23#include <stdio.h>
24#undef _GNU_SOURCE
25#include <stdlib.h>
Daniel Lezcano25fc4a32011-08-25 15:46:13 +020026#include <stdbool.h>
Daniel Lezcanoc193b602011-06-08 23:30:00 +020027#include <string.h>
28#include <dirent.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <unistd.h>
32
33#include "tree.h"
34
35/*
36 * Allocate a tree structure and initialize the different fields.
37 *
38 * @path : the absolute path to the directory
39 * @depth : the depth in the tree
40 * Returns a tree structure on success, NULL otherwise
41 */
42static inline struct tree *tree_alloc(const char *path, int depth)
43{
44 struct tree *t;
45
46 t = malloc(sizeof(*t));
47 if (!t)
48 return NULL;
49
50 /* Full pathname */
51 t->path = strdup(path);
52 if (!t->path) {
53 free(t);
54 return NULL;
55 }
56
57 /* Basename pointer on the full path name */
58 t->name = strrchr(t->path, '/') + 1;
59
60 t->depth = depth;
61 t->tail = t;
62 t->child = NULL;
63 t->parent = NULL;
64 t->next = NULL;
65 t->prev = NULL;
66 t->private = NULL;
Daniel Lezcanocb86e1d2011-06-08 23:30:01 +020067 t->nrchild = 0;
Daniel Lezcanoc193b602011-06-08 23:30:00 +020068
69 return t;
70}
71
72/*
73 * Free a tree structure and the fields we allocated in the
74 * tree_alloc function.
75 *
76 * @t : the tree structure to be freed
77 */
78static inline void tree_free(struct tree *t)
79{
80 free(t->path);
81 free(t);
82}
83
84/*
85 * Add at the end of the list the new list element.
86 *
87 * @head : the list to be appened
88 * @new : the new element to be added at the end of the list
89 */
90static inline void tree_add_tail(struct tree *head, struct tree *new)
91{
92 new->prev = head->tail;
93 head->tail->next = new;
94 head->tail = new;
95}
96
97/*
98 * Add a child in to a parent list, at the end of this list.
99 *
100 * @parent : the parent list to add the child
101 * @child : the child to be added
102 */
103static inline void tree_add_child(struct tree *parent, struct tree *child)
104{
105 child->parent = parent;
106
107 if (parent->child)
108 return tree_add_tail(parent->child, child);
109
110 parent->child = child;
111}
112
113/*
114 * This function will browse the directory structure and build a
115 * tree reflecting the content of the directory tree.
116 *
117 * @tree : the root node of the tree
118 * @filter : a callback to filter out the directories
119 * Returns 0 on success, -1 otherwise
120 */
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200121static int tree_scan(struct tree *tree, tree_filter_t filter, bool follow)
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200122{
123 DIR *dir;
124 char *basedir, *newpath;
125 struct dirent dirent, *direntp;
126 struct stat s;
127 int ret = 0;
128
129 dir = opendir(tree->path);
Sanjay Singh Rawat5fef0052013-04-17 15:02:01 +0530130 if (!dir) {
131 printf("error: unable to open directory %s\n", tree->path);
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200132 return -1;
Sanjay Singh Rawat5fef0052013-04-17 15:02:01 +0530133 }
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200134
135 while (!readdir_r(dir, &dirent, &direntp)) {
136
137 struct tree *child;
138
139 if (!direntp)
140 break;
141
142 if (direntp->d_name[0] == '.')
143 continue;
144
145 if (filter && filter(direntp->d_name))
146 continue;
147
148 ret = asprintf(&basedir, "%s", tree->path);
149 if (ret < 0)
150 return -1;
151
152 ret = basename(basedir) ? 0 : -1;
153 if (ret < 0)
154 goto out_free_basedir;
155
156 ret = asprintf(&newpath, "%s/%s", basedir, direntp->d_name);
157 if (ret < 0)
158 goto out_free_basedir;
159
160 ret = stat(newpath, &s);
161 if (ret)
162 goto out_free_newpath;
163
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200164 if (S_ISDIR(s.st_mode) || (S_ISLNK(s.st_mode) && follow)) {
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200165
166 ret = -1;
167
168 child = tree_alloc(newpath, tree->depth + 1);
169 if (!child)
170 goto out_free_newpath;
171
172 tree_add_child(tree, child);
173
Daniel Lezcanocb86e1d2011-06-08 23:30:01 +0200174 tree->nrchild++;
175
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200176 ret = tree_scan(child, filter, follow);
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200177 }
178
179 out_free_newpath:
180 free(newpath);
181
182 out_free_basedir:
183 free(basedir);
184
185 if (ret)
186 break;
187 }
188
189 closedir(dir);
190
191 return ret;
192}
193
194/*
195 * This function takes the topmost directory path and populate the
196 * directory tree structures.
197 *
198 * @tree : a path to the topmost directory path
199 * Returns a tree structure corresponding to the root node of the
200 * directory tree representation on success, NULL otherwise
201 */
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200202struct tree *tree_load(const char *path, tree_filter_t filter, bool follow)
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200203{
204 struct tree *tree;
205
206 tree = tree_alloc(path, 0);
207 if (!tree)
208 return NULL;
209
Daniel Lezcano25fc4a32011-08-25 15:46:13 +0200210 if (tree_scan(tree, filter, follow)) {
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200211 tree_free(tree);
212 return NULL;
213 }
214
215 return tree;
216}
217
218/*
219 * This function will go over the tree passed as parameter and
220 * will call the callback passed as parameter for each node.
221 *
222 * @tree : the topmost node where we begin to browse the tree
223 * Returns 0 on success, < 0 otherwise
224 */
225int tree_for_each(struct tree *tree, tree_cb_t cb, void *data)
226{
227 if (!tree)
228 return 0;
229
230 if (cb(tree, data))
231 return -1;
232
233 if (tree_for_each(tree->child, cb, data))
234 return -1;
235
236 return tree_for_each(tree->next, cb, data);
237}
Daniel Lezcano357dd8a2011-06-08 23:30:00 +0200238
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200239/*
240 * This function will go over the tree passed as parameter at the reverse
241 * order and will call the callback passed as parameter for each.
242 * @tree : the lower node where we begin to browse the tree at the reverse
243 * order
244 * cb : a callback for each node the function will go over
245 * data : some private data to be passed across the callbacks
246 * Returns 0 on success, < 0 otherwise
247 */
Daniel Lezcano6d42e812011-06-08 23:30:01 +0200248int tree_for_each_reverse(struct tree *tree, tree_cb_t cb, void *data)
249{
250 if (!tree)
251 return 0;
252
253 if (cb(tree, data))
254 return -1;
255
256 if (tree_for_each_reverse(tree->prev, cb, data))
257 return -1;
258
259 return tree_for_each_reverse(tree->parent, cb, data);
260}
261
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200262
263/*
264 * The function will go over all the parent of the specified node passed
265 * as parameter.
266 * @tree : the child node from where we back path to the parent
267 * cb : a callback for each node the function will go over
268 * data : some private data to be passed across the callbacks
269 * Returns 0 on success, < 0 otherwise
270 */
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200271int tree_for_each_parent(struct tree *tree, tree_cb_t cb, void *data)
272{
273 if (!tree)
274 return 0;
275
276 if (tree_for_each_parent(tree->parent, cb, data))
277 return -1;
278
279 return cb(tree, data);
280}
281
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200282/*
283 * The function will return the first node which match with the name as
284 * parameter.
285 * @tree : the tree where we begin to find
286 * @name : the name of the node the function must look for.
287 * Returns a pointer to the tree structure if found, NULL otherwise.
288 */
Daniel Lezcano357dd8a2011-06-08 23:30:00 +0200289struct tree *tree_find(struct tree *tree, const char *name)
290{
291 struct tree *t;
292
293 if (!tree)
294 return NULL;
295
296 if (!strcmp(tree->name, name))
297 return tree;
298
299 t = tree_find(tree->child, name);
300 if (t)
301 return t;
302
303 return tree_find(tree->next, name);
304}
Daniel Lezcanofabe20a2011-06-08 23:30:01 +0200305
306struct struct_find {
307 int nr;
308 const char *name;
309 struct tree ***ptree;
310};
311
312static int tree_finds_cb(struct tree *tree, void *data)
313{
314 struct struct_find *sf = data;
315
Daniel Lezcano528bb3f2011-06-21 00:57:08 +0200316 if (!strlen(sf->name))
317 return 0;
318
Daniel Lezcanofabe20a2011-06-08 23:30:01 +0200319 if (strncmp(sf->name, tree->name, strlen(sf->name)))
320 return 0;
321
322 if (sf->ptree)
323 (*(sf->ptree))[sf->nr] = tree;
324
325 sf->nr++;
326
327 return 0;
328}
329
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200330/*
331 * This function will search for all the nodes where the name begin
332 * with the name passed as parameter. *Note* the function allocates
333 * the array, it is up to the caller to free this array.
334 * @tree : the topmost node of the tree where we being to search
335 * @name : the name to find in the tree
336 * @ptr : a pointer to a pointer of pointer of tree structure :)
337 * Returns the number of elements found in the tree, < 0 if something
338 * went wrong.
339 */
Daniel Lezcanofabe20a2011-06-08 23:30:01 +0200340int tree_finds(struct tree *tree, const char *name, struct tree ***ptr)
341{
342 struct struct_find sf = { .nr = 0, .ptree = NULL, .name = name };
343 int nmatch;
344
345 /* first pass : count # of matching nodes */
346 tree_for_each(tree, tree_finds_cb, &sf);
347
348 /* no match */
349 if (!sf.nr)
350 return 0;
351
352 *ptr = malloc(sizeof(struct tree *) * sf.nr);
353 if (!*ptr)
354 return -1;
355
356 /* store the result as it will be overwritten by the next call */
357 nmatch = sf.nr;
358 sf.nr = 0;
359 sf.ptree = ptr;
360
361 /* second pass : fill with the matching nodes */
362 tree_for_each(tree, tree_finds_cb, &sf);
363
364 return nmatch;
365}