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 #ifdef ENABLE_ZSTD
50 {".ko.zst", sizeof(".ko.zst") - 1},
51 #endif
52 { }
53 };
54
55 /* string handling functions and memory allocations */
56 /* ************************************************************************ */
57
memdup(const void * p,size_t n)58 void *memdup(const void *p, size_t n)
59 {
60 void *r = malloc(n);
61
62 if (r == NULL)
63 return NULL;
64
65 return memcpy(r, p, n);
66 }
67
strchr_replace(char * s,char c,char r)68 char *strchr_replace(char *s, char c, char r)
69 {
70 char *p;
71
72 for (p = s; *p != '\0'; p++) {
73 if (*p == c)
74 *p = r;
75 }
76
77 return s;
78 }
79
80 /* module-related functions */
81 /* ************************************************************************ */
alias_normalize(const char * alias,char buf[static PATH_MAX],size_t * len)82 int alias_normalize(const char *alias, char buf[static PATH_MAX], size_t *len)
83 {
84 size_t i;
85
86 for (i = 0; i < PATH_MAX - 1; i++) {
87 const char c = alias[i];
88 switch (c) {
89 case '-':
90 buf[i] = '_';
91 break;
92 case ']':
93 return -EINVAL;
94 case '[':
95 while (alias[i] != ']' && alias[i] != '\0') {
96 buf[i] = alias[i];
97 i++;
98 }
99
100 if (alias[i] != ']')
101 return -EINVAL;
102
103 buf[i] = alias[i];
104 break;
105 case '\0':
106 goto finish;
107 default:
108 buf[i] = c;
109 }
110 }
111
112 finish:
113 buf[i] = '\0';
114 if (len)
115 *len = i;
116
117 return 0;
118 }
119
120 /*
121 * Replace dashes with underscores.
122 * Dashes inside character range patterns (e.g. [0-9]) are left unchanged.
123 *
124 * For convenience, it returns error if @s is NULL
125 */
underscores(char * s)126 int underscores(char *s)
127 {
128 unsigned int i;
129
130 if (!s)
131 return -EINVAL;
132
133 for (i = 0; s[i]; i++) {
134 switch (s[i]) {
135 case '-':
136 s[i] = '_';
137 break;
138 case ']':
139 return -EINVAL;
140 case '[':
141 i += strcspn(&s[i], "]");
142 if (!s[i])
143 return -EINVAL;
144 break;
145 }
146 }
147
148 return 0;
149 }
150
modname_normalize(const char * modname,char buf[static PATH_MAX],size_t * len)151 char *modname_normalize(const char *modname, char buf[static PATH_MAX], size_t *len)
152 {
153 size_t s;
154
155 for (s = 0; s < PATH_MAX - 1; s++) {
156 const char c = modname[s];
157 if (c == '-')
158 buf[s] = '_';
159 else if (c == '\0' || c == '.')
160 break;
161 else
162 buf[s] = c;
163 }
164
165 buf[s] = '\0';
166
167 if (len)
168 *len = s;
169
170 return buf;
171 }
172
path_to_modname(const char * path,char buf[static PATH_MAX],size_t * len)173 char *path_to_modname(const char *path, char buf[static PATH_MAX], size_t *len)
174 {
175 char *modname;
176
177 modname = basename(path);
178 if (modname == NULL || modname[0] == '\0')
179 return NULL;
180
181 return modname_normalize(modname, buf, len);
182 }
183
path_ends_with_kmod_ext(const char * path,size_t len)184 bool path_ends_with_kmod_ext(const char *path, size_t len)
185 {
186 const struct kmod_ext *eitr;
187
188 for (eitr = kmod_exts; eitr->ext != NULL; eitr++) {
189 if (len <= eitr->len)
190 continue;
191 if (streq(path + len - eitr->len, eitr->ext))
192 return true;
193 }
194
195 return false;
196 }
197
198 /* read-like and fread-like functions */
199 /* ************************************************************************ */
read_str_safe(int fd,char * buf,size_t buflen)200 ssize_t read_str_safe(int fd, char *buf, size_t buflen)
201 {
202 size_t todo = buflen - 1;
203 size_t done = 0;
204
205 assert_cc(EAGAIN == EWOULDBLOCK);
206
207 do {
208 ssize_t r = read(fd, buf + done, todo);
209
210 if (r == 0)
211 break;
212 else if (r > 0) {
213 todo -= r;
214 done += r;
215 } else {
216 if (errno == EAGAIN || errno == EINTR)
217 continue;
218 else
219 return -errno;
220 }
221 } while (todo > 0);
222
223 buf[done] = '\0';
224 return done;
225 }
226
write_str_safe(int fd,const char * buf,size_t buflen)227 ssize_t write_str_safe(int fd, const char *buf, size_t buflen)
228 {
229 size_t todo = buflen;
230 size_t done = 0;
231
232 assert_cc(EAGAIN == EWOULDBLOCK);
233
234 do {
235 ssize_t r = write(fd, buf + done, todo);
236
237 if (r == 0)
238 break;
239 else if (r > 0) {
240 todo -= r;
241 done += r;
242 } else {
243 if (errno == EAGAIN || errno == EINTR)
244 continue;
245 else
246 return -errno;
247 }
248 } while (todo > 0);
249
250 return done;
251 }
252
read_str_long(int fd,long * value,int base)253 int read_str_long(int fd, long *value, int base)
254 {
255 char buf[32], *end;
256 long v;
257 int err;
258
259 *value = 0;
260 err = read_str_safe(fd, buf, sizeof(buf));
261 if (err < 0)
262 return err;
263 errno = 0;
264 v = strtol(buf, &end, base);
265 if (end == buf || !isspace(*end))
266 return -EINVAL;
267
268 *value = v;
269 return 0;
270 }
271
read_str_ulong(int fd,unsigned long * value,int base)272 int read_str_ulong(int fd, unsigned long *value, int base)
273 {
274 char buf[32], *end;
275 long v;
276 int err;
277
278 *value = 0;
279 err = read_str_safe(fd, buf, sizeof(buf));
280 if (err < 0)
281 return err;
282 errno = 0;
283 v = strtoul(buf, &end, base);
284 if (end == buf || !isspace(*end))
285 return -EINVAL;
286 *value = v;
287 return 0;
288 }
289
290 /*
291 * Read one logical line from a configuration file.
292 *
293 * Line endings may be escaped with backslashes, to form one logical line from
294 * several physical lines. No end of line character(s) are included in the
295 * result.
296 *
297 * If linenum is not NULL, it is incremented by the number of physical lines
298 * which have been read.
299 */
freadline_wrapped(FILE * fp,unsigned int * linenum)300 char *freadline_wrapped(FILE *fp, unsigned int *linenum)
301 {
302 int size = 256;
303 int i = 0, n = 0;
304 _cleanup_free_ char *buf = malloc(size);
305
306 if (buf == NULL)
307 return NULL;
308
309 for(;;) {
310 int ch = getc_unlocked(fp);
311
312 switch(ch) {
313 case EOF:
314 if (i == 0)
315 return NULL;
316 /* else fall through */
317
318 case '\n':
319 n++;
320
321 {
322 char *ret = buf;
323 ret[i] = '\0';
324 buf = NULL;
325 if (linenum)
326 *linenum += n;
327 return ret;
328 }
329
330 case '\\':
331 ch = getc_unlocked(fp);
332
333 if (ch == '\n') {
334 n++;
335 continue;
336 }
337 /* else fall through */
338
339 default:
340 buf[i++] = ch;
341
342 if (i == size) {
343 char *tmp;
344 size *= 2;
345 tmp = realloc(buf, size);
346 if (!tmp)
347 return NULL;
348 buf = tmp;
349 }
350 }
351 }
352 }
353
354 /* path handling functions */
355 /* ************************************************************************ */
356
path_is_absolute(const char * p)357 bool path_is_absolute(const char *p)
358 {
359 assert(p != NULL);
360
361 return p[0] == '/';
362 }
363
path_make_absolute_cwd(const char * p)364 char *path_make_absolute_cwd(const char *p)
365 {
366 _cleanup_free_ char *cwd = NULL;
367 size_t plen, cwdlen;
368 char *r;
369
370 if (path_is_absolute(p))
371 return strdup(p);
372
373 cwd = get_current_dir_name();
374 if (!cwd)
375 return NULL;
376
377 plen = strlen(p);
378 cwdlen = strlen(cwd);
379
380 /* cwd + '/' + p + '\0' */
381 r = realloc(cwd, cwdlen + 1 + plen + 1);
382 if (r == NULL)
383 return NULL;
384
385 cwd = NULL;
386 r[cwdlen] = '/';
387 memcpy(&r[cwdlen + 1], p, plen + 1);
388
389 return r;
390 }
391
is_dir(const char * path)392 static inline int is_dir(const char *path)
393 {
394 struct stat st;
395
396 if (stat(path, &st) >= 0)
397 return S_ISDIR(st.st_mode);
398
399 return -errno;
400 }
401
mkdir_p(const char * path,int len,mode_t mode)402 int mkdir_p(const char *path, int len, mode_t mode)
403 {
404 char *start, *end;
405
406 start = strndupa(path, len);
407 end = start + len;
408
409 /*
410 * scan backwards, replacing '/' with '\0' while the component doesn't
411 * exist
412 */
413 for (;;) {
414 int r = is_dir(start);
415 if (r > 0) {
416 end += strlen(end);
417
418 if (end == start + len)
419 return 0;
420
421 /* end != start, since it would be caught on the first
422 * iteration */
423 *end = '/';
424 break;
425 } else if (r == 0)
426 return -ENOTDIR;
427
428 if (end == start)
429 break;
430
431 *end = '\0';
432
433 /* Find the next component, backwards, discarding extra '/'*/
434 while (end > start && *end != '/')
435 end--;
436
437 while (end > start && *(end - 1) == '/')
438 end--;
439 }
440
441 for (; end < start + len;) {
442 if (mkdir(start, mode) < 0 && errno != EEXIST)
443 return -errno;
444
445 end += strlen(end);
446 *end = '/';
447 }
448
449 return 0;
450 }
451
mkdir_parents(const char * path,mode_t mode)452 int mkdir_parents(const char *path, mode_t mode)
453 {
454 char *end = strrchr(path, '/');
455
456 /* no parent directories */
457 if (end == NULL)
458 return 0;
459
460 return mkdir_p(path, end - path, mode);
461 }
462
ts_usec(const struct timespec * ts)463 unsigned long long ts_usec(const struct timespec *ts)
464 {
465 return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
466 (unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
467 }
468
ts_msec(const struct timespec * ts)469 unsigned long long ts_msec(const struct timespec *ts)
470 {
471 return (unsigned long long) ts->tv_sec * MSEC_PER_SEC +
472 (unsigned long long) ts->tv_nsec / NSEC_PER_MSEC;
473 }
474
msec_ts(unsigned long long msec)475 static struct timespec msec_ts(unsigned long long msec)
476 {
477 struct timespec ts = {
478 .tv_sec = msec / MSEC_PER_SEC,
479 .tv_nsec = (msec % MSEC_PER_SEC) * NSEC_PER_MSEC,
480 };
481
482 return ts;
483 }
484
sleep_until_msec(unsigned long long msec)485 int sleep_until_msec(unsigned long long msec)
486 {
487 struct timespec ts = msec_ts(msec);
488
489 if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL) < 0 &&
490 errno != EINTR)
491 return -errno;
492
493 return 0;
494 }
495
496 /*
497 * Exponential retry backoff with tail
498 */
get_backoff_delta_msec(unsigned long long t0,unsigned long long tend,unsigned long long * delta)499 unsigned long long get_backoff_delta_msec(unsigned long long t0,
500 unsigned long long tend,
501 unsigned long long *delta)
502 {
503 unsigned long long t;
504
505 t = now_msec();
506
507 if (!*delta)
508 *delta = 1;
509 else
510 *delta <<= 1;
511
512 while (t + *delta > tend)
513 *delta >>= 1;
514
515 if (!*delta && tend > t)
516 *delta = tend - t;
517
518 return t + *delta;
519 }
520
now_usec(void)521 unsigned long long now_usec(void)
522 {
523 struct timespec ts;
524
525 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
526 return 0;
527
528 return ts_usec(&ts);
529 }
530
now_msec(void)531 unsigned long long now_msec(void)
532 {
533 struct timespec ts;
534
535 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
536 return 0;
537
538 return ts_msec(&ts);
539 }
540
stat_mstamp(const struct stat * st)541 unsigned long long stat_mstamp(const struct stat *st)
542 {
543 #ifdef HAVE_STRUCT_STAT_ST_MTIM
544 return ts_usec(&st->st_mtim);
545 #else
546 return (unsigned long long) st->st_mtime;
547 #endif
548 }
549