]> git.ipfire.org Git - thirdparty/kmod.git/blob - shared/util.c
libkmod: modinfo: implement signature output
[thirdparty/kmod.git] / shared / util.c
1 /*
2 * kmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
5 * Copyright (C) 2012 Lucas De Marchi <lucas.de.marchi@gmail.com>
6 * Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <assert.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <stdarg.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include <shared/missing.h>
33 #include <shared/util.h>
34
35 #define USEC_PER_SEC 1000000ULL
36 #define NSEC_PER_USEC 1000ULL
37
38 static const struct kmod_ext {
39 const char *ext;
40 size_t len;
41 } kmod_exts[] = {
42 {KMOD_EXTENSION_UNCOMPRESSED, sizeof(KMOD_EXTENSION_UNCOMPRESSED) - 1},
43 #ifdef ENABLE_ZLIB
44 {".ko.gz", sizeof(".ko.gz") - 1},
45 #endif
46 #ifdef ENABLE_XZ
47 {".ko.xz", sizeof(".ko.xz") - 1},
48 #endif
49 { }
50 };
51
52 assert_cc(EAGAIN == EWOULDBLOCK);
53
54 /* string handling functions and memory allocations */
55 /* ************************************************************************ */
56
57 void *memdup(const void *p, size_t n)
58 {
59 void *r = malloc(n);
60
61 if (r == NULL)
62 return NULL;
63
64 return memcpy(r, p, n);
65 }
66
67 char *strchr_replace(char *s, char c, char r)
68 {
69 char *p;
70
71 for (p = s; *p != '\0'; p++) {
72 if (*p == c)
73 *p = r;
74 }
75
76 return s;
77 }
78
79 /* module-related functions */
80 /* ************************************************************************ */
81 int alias_normalize(const char *alias, char buf[static PATH_MAX], size_t *len)
82 {
83 size_t i;
84
85 for (i = 0; i < PATH_MAX - 1; i++) {
86 const char c = alias[i];
87 switch (c) {
88 case '-':
89 buf[i] = '_';
90 break;
91 case ']':
92 return -EINVAL;
93 case '[':
94 while (alias[i] != ']' && alias[i] != '\0') {
95 buf[i] = alias[i];
96 i++;
97 }
98
99 if (alias[i] != ']')
100 return -EINVAL;
101
102 buf[i] = alias[i];
103 break;
104 case '\0':
105 goto finish;
106 default:
107 buf[i] = c;
108 }
109 }
110
111 finish:
112 buf[i] = '\0';
113 if (len)
114 *len = i;
115
116 return 0;
117 }
118
119 /*
120 * Replace dashes with underscores.
121 * Dashes inside character range patterns (e.g. [0-9]) are left unchanged.
122 *
123 * For convenience, it returns error if @s is NULL
124 */
125 int underscores(char *s)
126 {
127 unsigned int i;
128
129 if (!s)
130 return -EINVAL;
131
132 for (i = 0; s[i]; i++) {
133 switch (s[i]) {
134 case '-':
135 s[i] = '_';
136 break;
137 case ']':
138 return -EINVAL;
139 case '[':
140 i += strcspn(&s[i], "]");
141 if (!s[i])
142 return -EINVAL;
143 break;
144 }
145 }
146
147 return 0;
148 }
149
150 char *modname_normalize(const char *modname, char buf[static PATH_MAX], size_t *len)
151 {
152 size_t s;
153
154 for (s = 0; s < PATH_MAX - 1; s++) {
155 const char c = modname[s];
156 if (c == '-')
157 buf[s] = '_';
158 else if (c == '\0' || c == '.')
159 break;
160 else
161 buf[s] = c;
162 }
163
164 buf[s] = '\0';
165
166 if (len)
167 *len = s;
168
169 return buf;
170 }
171
172 char *path_to_modname(const char *path, char buf[static PATH_MAX], size_t *len)
173 {
174 char *modname;
175
176 modname = basename(path);
177 if (modname == NULL || modname[0] == '\0')
178 return NULL;
179
180 return modname_normalize(modname, buf, len);
181 }
182
183 bool path_ends_with_kmod_ext(const char *path, size_t len)
184 {
185 const struct kmod_ext *eitr;
186
187 for (eitr = kmod_exts; eitr->ext != NULL; eitr++) {
188 if (len <= eitr->len)
189 continue;
190 if (streq(path + len - eitr->len, eitr->ext))
191 return true;
192 }
193
194 return false;
195 }
196
197 /* read-like and fread-like functions */
198 /* ************************************************************************ */
199 ssize_t read_str_safe(int fd, char *buf, size_t buflen)
200 {
201 size_t todo = buflen - 1;
202 size_t done = 0;
203
204 do {
205 ssize_t r = read(fd, buf + done, todo);
206
207 if (r == 0)
208 break;
209 else if (r > 0) {
210 todo -= r;
211 done += r;
212 } else {
213 if (errno == EAGAIN || errno == EINTR)
214 continue;
215 else
216 return -errno;
217 }
218 } while (todo > 0);
219
220 buf[done] = '\0';
221 return done;
222 }
223
224 ssize_t write_str_safe(int fd, const char *buf, size_t buflen)
225 {
226 size_t todo = buflen;
227 size_t done = 0;
228
229 do {
230 ssize_t r = write(fd, buf + done, todo);
231
232 if (r == 0)
233 break;
234 else if (r > 0) {
235 todo -= r;
236 done += r;
237 } else {
238 if (errno == EAGAIN || errno == EINTR)
239 continue;
240 else
241 return -errno;
242 }
243 } while (todo > 0);
244
245 return done;
246 }
247
248 int read_str_long(int fd, long *value, int base)
249 {
250 char buf[32], *end;
251 long v;
252 int err;
253
254 *value = 0;
255 err = read_str_safe(fd, buf, sizeof(buf));
256 if (err < 0)
257 return err;
258 errno = 0;
259 v = strtol(buf, &end, base);
260 if (end == buf || !isspace(*end))
261 return -EINVAL;
262
263 *value = v;
264 return 0;
265 }
266
267 int read_str_ulong(int fd, unsigned long *value, int base)
268 {
269 char buf[32], *end;
270 long v;
271 int err;
272
273 *value = 0;
274 err = read_str_safe(fd, buf, sizeof(buf));
275 if (err < 0)
276 return err;
277 errno = 0;
278 v = strtoul(buf, &end, base);
279 if (end == buf || !isspace(*end))
280 return -EINVAL;
281 *value = v;
282 return 0;
283 }
284
285 /*
286 * Read one logical line from a configuration file.
287 *
288 * Line endings may be escaped with backslashes, to form one logical line from
289 * several physical lines. No end of line character(s) are included in the
290 * result.
291 *
292 * If linenum is not NULL, it is incremented by the number of physical lines
293 * which have been read.
294 */
295 char *freadline_wrapped(FILE *fp, unsigned int *linenum)
296 {
297 int size = 256;
298 int i = 0, n = 0;
299 _cleanup_free_ char *buf = malloc(size);
300
301 if (buf == NULL)
302 return NULL;
303
304 for(;;) {
305 int ch = getc_unlocked(fp);
306
307 switch(ch) {
308 case EOF:
309 if (i == 0)
310 return NULL;
311 /* else fall through */
312
313 case '\n':
314 n++;
315
316 {
317 char *ret = buf;
318 ret[i] = '\0';
319 buf = NULL;
320 if (linenum)
321 *linenum += n;
322 return ret;
323 }
324
325 case '\\':
326 ch = getc_unlocked(fp);
327
328 if (ch == '\n') {
329 n++;
330 continue;
331 }
332 /* else fall through */
333
334 default:
335 buf[i++] = ch;
336
337 if (i == size) {
338 char *tmp;
339 size *= 2;
340 tmp = realloc(buf, size);
341 if (!tmp)
342 return NULL;
343 buf = tmp;
344 }
345 }
346 }
347 }
348
349 /* path handling functions */
350 /* ************************************************************************ */
351
352 bool path_is_absolute(const char *p)
353 {
354 assert(p != NULL);
355
356 return p[0] == '/';
357 }
358
359 char *path_make_absolute_cwd(const char *p)
360 {
361 _cleanup_free_ char *cwd = NULL;
362 size_t plen, cwdlen;
363 char *r;
364
365 if (path_is_absolute(p))
366 return strdup(p);
367
368 cwd = get_current_dir_name();
369 if (!cwd)
370 return NULL;
371
372 plen = strlen(p);
373 cwdlen = strlen(cwd);
374
375 /* cwd + '/' + p + '\0' */
376 r = realloc(cwd, cwdlen + 1 + plen + 1);
377 if (r == NULL)
378 return NULL;
379
380 cwd = NULL;
381 r[cwdlen] = '/';
382 memcpy(&r[cwdlen + 1], p, plen + 1);
383
384 return r;
385 }
386
387 static inline int is_dir(const char *path)
388 {
389 struct stat st;
390
391 if (stat(path, &st) >= 0)
392 return S_ISDIR(st.st_mode);
393
394 return -errno;
395 }
396
397 int mkdir_p(const char *path, int len, mode_t mode)
398 {
399 char *start, *end;
400
401 start = strndupa(path, len);
402 end = start + len;
403
404 /*
405 * scan backwards, replacing '/' with '\0' while the component doesn't
406 * exist
407 */
408 for (;;) {
409 int r = is_dir(start);
410 if (r > 0) {
411 end += strlen(end);
412
413 if (end == start + len)
414 return 0;
415
416 /* end != start, since it would be caught on the first
417 * iteration */
418 *end = '/';
419 break;
420 } else if (r == 0)
421 return -ENOTDIR;
422
423 if (end == start)
424 break;
425
426 *end = '\0';
427
428 /* Find the next component, backwards, discarding extra '/'*/
429 while (end > start && *end != '/')
430 end--;
431
432 while (end > start && *(end - 1) == '/')
433 end--;
434 }
435
436 for (; end < start + len;) {
437 if (mkdir(start, mode) < 0 && errno != EEXIST)
438 return -errno;
439
440 end += strlen(end);
441 *end = '/';
442 }
443
444 return 0;
445 }
446
447 int mkdir_parents(const char *path, mode_t mode)
448 {
449 char *end = strrchr(path, '/');
450
451 /* no parent directories */
452 if (end == NULL)
453 return 0;
454
455 return mkdir_p(path, end - path, mode);
456 }
457
458 unsigned long long ts_usec(const struct timespec *ts)
459 {
460 return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
461 (unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
462 }
463
464 unsigned long long stat_mstamp(const struct stat *st)
465 {
466 #ifdef HAVE_STRUCT_STAT_ST_MTIM
467 return ts_usec(&st->st_mtim);
468 #else
469 return (unsigned long long) st->st_mtime;
470 #endif
471 }