Coverage Report

Created: 2026-10-17 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/common/file-list.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-only
2
3
#define pr_fmt(fmt) "file_list: " fmt
4
5
#include <common.h>
6
#include <malloc.h>
7
#include <fs.h>
8
#include <file-list.h>
9
#include <stringlist.h>
10
#include <linux/err.h>
11
#include <driver.h>
12
#include <block.h>
13
14
0
#define PARSE_DEVICE  0
15
0
#define PARSE_NAME  1
16
0
#define PARSE_FLAGS 2
17
18
struct file_list_entry *file_list_entry_by_name(struct file_list *files, const char *name)
19
0
{
20
0
  struct file_list_entry *entry;
21
22
0
  file_list_for_each_entry(files, entry) {
23
0
    if (!strcmp(entry->name, name))
24
0
      return entry;
25
0
  }
26
27
0
  return NULL;
28
0
}
29
30
static int __file_list_add_entry(struct file_list *files,
31
         const char *name,
32
         const char *filename,
33
         unsigned long flags)
34
0
{
35
0
  struct file_list_entry *entry;
36
37
0
  entry = file_list_entry_by_name(files, name);
38
0
  if (entry)
39
0
    return -EEXIST;
40
41
0
  entry = xzalloc(sizeof(*entry));
42
43
0
  entry->name = name;
44
0
  entry->filename = filename;
45
0
  entry->flags = flags;
46
47
0
  list_add_tail(&entry->list, &files->list);
48
49
0
  return 0;
50
0
}
51
52
int file_list_add_entry(struct file_list *files, const char *name, const char *filename,
53
      unsigned long flags)
54
0
{
55
0
  return __file_list_add_entry(files,
56
0
             xstrdup_const(name), xstrdup_const(filename),
57
0
             flags);
58
0
}
59
60
int file_list_add_cdev_entry(struct file_list *files, struct cdev *cdev,
61
           unsigned long flags)
62
0
{
63
0
  return __file_list_add_entry(files, xstrdup_const(cdev->name),
64
0
             xasprintf("/dev/%s", cdev->name), flags);
65
0
}
66
67
static bool file_list_handle_spec(struct file_list *files, const char *spec)
68
0
{
69
0
  unsigned count = 0;
70
0
  bool autoadd;
71
72
0
  autoadd = !strcmp(spec, "auto");
73
0
  if (autoadd || !strcmp(spec, "block"))
74
0
    count += file_list_add_blockdevs(files);
75
0
  else
76
0
    return false;
77
78
0
  pr_debug("'%s' spcifier resulted in %u entries\n", spec, count);
79
0
  return true;
80
0
}
81
82
static int file_list_parse_one(struct file_list *files, const char *partstr, const char **endstr)
83
0
{
84
0
  int i = 0, state = PARSE_DEVICE;
85
0
  char filename[PATH_MAX];
86
0
  char name[PATH_MAX];
87
0
  unsigned long flags = 0;
88
0
  bool special = false;
89
90
0
  memset(filename, 0, sizeof(filename));
91
0
  memset(name, 0, sizeof(name));
92
93
0
  while (*partstr && *partstr != ',') {
94
0
    switch (state) {
95
0
    case PARSE_DEVICE:
96
0
      if (*partstr == '(') {
97
0
        state = PARSE_NAME;
98
0
        i = 0;
99
0
      } else {
100
0
        filename[i++] = *partstr;
101
0
      }
102
0
      break;
103
0
    case PARSE_NAME:
104
0
      if (*partstr == ')') {
105
0
        state = PARSE_FLAGS;
106
0
        i = 0;
107
0
      } else {
108
0
        name[i++] = *partstr;
109
0
      }
110
0
      break;
111
0
    case PARSE_FLAGS:
112
0
      switch (*partstr) {
113
0
      case 's':
114
0
        flags |= FILE_LIST_FLAG_SAFE;
115
0
        break;
116
0
      case 'r':
117
0
        flags |= FILE_LIST_FLAG_READBACK;
118
0
        break;
119
0
      case 'c':
120
0
        flags |= FILE_LIST_FLAG_CREATE;
121
0
        break;
122
0
      case 'u':
123
0
        flags |= FILE_LIST_FLAG_UBI;
124
0
        break;
125
0
      case 'o':
126
0
        flags |= FILE_LIST_FLAG_OPTIONAL;
127
0
        break;
128
0
      default:
129
0
        pr_err("Unknown flag '%c'\n", *partstr);
130
0
        return -EINVAL;
131
0
      }
132
0
      break;
133
0
    default:
134
0
      return -EINVAL;
135
0
    }
136
0
    partstr++;
137
0
  }
138
139
0
  if (state == PARSE_DEVICE)
140
0
    special = file_list_handle_spec(files, filename);
141
142
0
  if (!special && state != PARSE_FLAGS) {
143
0
    pr_err("Missing ')'\n");
144
0
    return -EINVAL;
145
0
  }
146
147
0
  if (*partstr == ',')
148
0
    partstr++;
149
0
  *endstr = partstr;
150
151
0
  return special ? 0 : file_list_add_entry(files, name, filename, flags);
152
0
}
153
154
static const char *flags_to_str(int flags)
155
0
{
156
0
  static char str[sizeof "srcuo"];
157
0
  char *s = str;;
158
159
0
  if (flags & FILE_LIST_FLAG_SAFE)
160
0
    *s++ = 's';
161
0
  if (flags & FILE_LIST_FLAG_READBACK)
162
0
    *s++ = 'r';
163
0
  if (flags & FILE_LIST_FLAG_CREATE)
164
0
    *s++ = 'c';
165
0
  if (flags & FILE_LIST_FLAG_UBI)
166
0
    *s++ = 'u';
167
0
  if (flags & FILE_LIST_FLAG_OPTIONAL)
168
0
    *s++ = 'o';
169
170
0
  *s = '\0';
171
172
0
  return str;
173
0
}
174
175
struct file_list *file_list_new(void)
176
0
{
177
0
  struct file_list *files;
178
179
0
  files = xzalloc(sizeof(*files));
180
181
0
  INIT_LIST_HEAD(&files->list);
182
183
0
  return files;
184
0
}
185
186
struct file_list *file_list_parse(const char *str)
187
0
{
188
0
  struct file_list *files;
189
0
  int ret;
190
0
  const char *endptr;
191
192
0
  files = file_list_new();
193
194
0
  while (*str) {
195
0
    ret = file_list_parse_one(files, str, &endptr);
196
0
    if (ret) {
197
0
      pr_err("parse error\n");
198
0
      goto out;
199
0
    }
200
0
    str = endptr;
201
0
  }
202
203
0
  return files;
204
0
out:
205
0
  file_list_free(files);
206
207
0
  return ERR_PTR(ret);
208
0
}
209
210
struct file_list *file_list_parse_null(const char *files)
211
0
{
212
0
  struct file_list *list;
213
214
0
  if (!files)
215
0
    return NULL;
216
217
0
  list = file_list_parse(files);
218
0
  if (IS_ERR(list)) {
219
0
    pr_err("Parsing file list \"%s\" failed: %pe\n", files, list);
220
0
    return NULL;
221
0
  }
222
223
0
  return list;
224
0
}
225
226
void file_list_free(struct file_list *files)
227
0
{
228
0
  struct file_list_entry *entry, *tmp;
229
230
0
  if (!files)
231
0
    return;
232
233
0
  list_for_each_entry_safe(entry, tmp, &files->list, list) {
234
0
    free_const(entry->name);
235
0
    free_const(entry->filename);
236
0
    free(entry);
237
0
  }
238
239
0
  free(files);
240
0
}
241
242
struct file_list *file_list_dup(struct file_list *old)
243
0
{
244
0
  struct file_list_entry *old_entry;
245
0
  struct file_list *new;
246
247
0
  new = file_list_new();
248
249
0
  list_for_each_entry(old_entry, &old->list, list)
250
0
    (void)file_list_add_entry(new, old_entry->name, old_entry->filename,
251
0
            old_entry->flags); /* can't fail */
252
253
0
  return new;
254
0
}
255
256
char *file_list_to_str(const struct file_list *files)
257
0
{
258
0
  struct file_list_entry *entry;
259
0
  struct string_list sl;
260
0
  char *str;
261
262
0
  if (!files)
263
0
    return strdup("");
264
265
0
  string_list_init(&sl);
266
267
0
  list_for_each_entry(entry, &files->list, list) {
268
0
    int ret = string_list_add_asprintf(&sl, "%s(%s)%s", entry->filename, entry->name,
269
0
               flags_to_str(entry->flags));
270
0
    if (ret) {
271
0
      str = ERR_PTR(ret);
272
0
      goto out;
273
0
    }
274
0
  }
275
276
0
  str = string_list_join(&sl, ",");
277
0
out:
278
0
  string_list_free(&sl);
279
280
0
  return str;
281
0
}
282
283
int file_list_detect_all(const struct file_list *files)
284
0
{
285
0
  struct file_list_entry *fentry;
286
0
  struct stat s;
287
0
  int i = 0;
288
289
0
  list_for_each_entry(fentry, &files->list, list) {
290
0
    if (!stat(fentry->filename, &s))
291
0
      continue;
292
0
    if (device_detect_by_name(devpath_to_name(fentry->filename)) == 0)
293
0
      i++;
294
0
  }
295
296
0
  return i;
297
0
}