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