blob: 9de080aabb18db3fd46dccc84f3e0e61e10df47c [file] [log] [blame]
Lucas De Marchi96573a02014-10-03 00:01:35 -03001/*
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
Lucas De Marchidea2dfe2014-12-25 23:32:03 -020019 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Lucas De Marchi96573a02014-10-03 00:01:35 -030020 */
21
22#include <assert.h>
Lucas De Marchic2e42862014-10-03 01:41:42 -030023#include <ctype.h>
24#include <errno.h>
25#include <stdarg.h>
26#include <stddef.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030027#include <stdio.h>
28#include <stdlib.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030029#include <string.h>
Lucas De Marchic2e42862014-10-03 01:41:42 -030030#include <unistd.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030031
Natanael Copaefb5bfa2014-11-17 09:36:29 +010032#include <shared/missing.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030033#include <shared/util.h>
34
35#define USEC_PER_SEC 1000000ULL
36#define NSEC_PER_USEC 1000ULL
37
Lucas De Marchif4e8c162014-10-09 01:14:16 -030038static 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
Lucas De Marchia6ede6c2016-08-10 12:42:12 -030052assert_cc(EAGAIN == EWOULDBLOCK);
53
Lucas De Marchi96573a02014-10-03 00:01:35 -030054/* string handling functions and memory allocations */
55/* ************************************************************************ */
56
57void *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
Lucas De Marchi9a437532014-10-09 11:03:29 -030067char *strchr_replace(char *s, char c, char r)
Lucas De Marchi96573a02014-10-03 00:01:35 -030068{
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
Lucas De Marchi2b0104f2014-10-09 00:43:01 -030079/* module-related functions */
80/* ************************************************************************ */
81int 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
111finish:
112 buf[i] = '\0';
113 if (len)
114 *len = i;
115
116 return 0;
117}
118
Lucas De Marchi52c9c992014-10-09 10:59:08 -0300119/*
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 */
125int 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
Lucas De Marchif4e8c162014-10-09 01:14:16 -0300150char *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
172char *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
183bool 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
Lucas De Marchi96573a02014-10-03 00:01:35 -0300197/* read-like and fread-like functions */
198/* ************************************************************************ */
199ssize_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 {
Lucas De Marchia6ede6c2016-08-10 12:42:12 -0300213 if (errno == EAGAIN || errno == EINTR)
Lucas De Marchi96573a02014-10-03 00:01:35 -0300214 continue;
215 else
216 return -errno;
217 }
218 } while (todo > 0);
219
220 buf[done] = '\0';
221 return done;
222}
223
224ssize_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 {
Lucas De Marchia6ede6c2016-08-10 12:42:12 -0300238 if (errno == EAGAIN || errno == EINTR)
Lucas De Marchi96573a02014-10-03 00:01:35 -0300239 continue;
240 else
241 return -errno;
242 }
243 } while (todo > 0);
244
245 return done;
246}
247
248int 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
267int 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 */
Lucas De Marchiaafd3832014-10-03 03:25:06 -0300295char *freadline_wrapped(FILE *fp, unsigned int *linenum)
Lucas De Marchi96573a02014-10-03 00:01:35 -0300296{
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 {
Caio Marcelo de Oliveira Filho88f6ffe2015-01-21 09:37:23 -0200317 char *ret = buf;
Lucas De Marchi96573a02014-10-03 00:01:35 -0300318 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
352bool path_is_absolute(const char *p)
353{
354 assert(p != NULL);
355
356 return p[0] == '/';
357}
358
359char *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
387static 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
397int 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
447int 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
458unsigned 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
464unsigned 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}