blob: 390282326bb6f8be2f0941a1bc86be7d51a27497 [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
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <assert.h>
Lucas De Marchic2e42862014-10-03 01:41:42 -030024#include <ctype.h>
25#include <errno.h>
26#include <stdarg.h>
27#include <stddef.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030028#include <stdio.h>
29#include <stdlib.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030030#include <string.h>
Lucas De Marchic2e42862014-10-03 01:41:42 -030031#include <unistd.h>
Lucas De Marchi96573a02014-10-03 00:01:35 -030032
33#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 Marchi96573a02014-10-03 00:01:35 -030052/* string handling functions and memory allocations */
53/* ************************************************************************ */
54
55void *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
65char *strchr_replace(char *s, int 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
Lucas De Marchi2b0104f2014-10-09 00:43:01 -030077/* module-related functions */
78/* ************************************************************************ */
79int 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
109finish:
110 buf[i] = '\0';
111 if (len)
112 *len = i;
113
114 return 0;
115}
116
Lucas De Marchif4e8c162014-10-09 01:14:16 -0300117char *modname_normalize(const char *modname, char buf[static PATH_MAX], size_t *len)
118{
119 size_t s;
120
121 for (s = 0; s < PATH_MAX - 1; s++) {
122 const char c = modname[s];
123 if (c == '-')
124 buf[s] = '_';
125 else if (c == '\0' || c == '.')
126 break;
127 else
128 buf[s] = c;
129 }
130
131 buf[s] = '\0';
132
133 if (len)
134 *len = s;
135
136 return buf;
137}
138
139char *path_to_modname(const char *path, char buf[static PATH_MAX], size_t *len)
140{
141 char *modname;
142
143 modname = basename(path);
144 if (modname == NULL || modname[0] == '\0')
145 return NULL;
146
147 return modname_normalize(modname, buf, len);
148}
149
150bool path_ends_with_kmod_ext(const char *path, size_t len)
151{
152 const struct kmod_ext *eitr;
153
154 for (eitr = kmod_exts; eitr->ext != NULL; eitr++) {
155 if (len <= eitr->len)
156 continue;
157 if (streq(path + len - eitr->len, eitr->ext))
158 return true;
159 }
160
161 return false;
162}
163
Lucas De Marchi96573a02014-10-03 00:01:35 -0300164/* read-like and fread-like functions */
165/* ************************************************************************ */
166ssize_t read_str_safe(int fd, char *buf, size_t buflen)
167{
168 size_t todo = buflen - 1;
169 size_t done = 0;
170
171 do {
172 ssize_t r = read(fd, buf + done, todo);
173
174 if (r == 0)
175 break;
176 else if (r > 0) {
177 todo -= r;
178 done += r;
179 } else {
180 if (errno == EAGAIN || errno == EWOULDBLOCK ||
181 errno == EINTR)
182 continue;
183 else
184 return -errno;
185 }
186 } while (todo > 0);
187
188 buf[done] = '\0';
189 return done;
190}
191
192ssize_t write_str_safe(int fd, const char *buf, size_t buflen)
193{
194 size_t todo = buflen;
195 size_t done = 0;
196
197 do {
198 ssize_t r = write(fd, buf + done, todo);
199
200 if (r == 0)
201 break;
202 else if (r > 0) {
203 todo -= r;
204 done += r;
205 } else {
206 if (errno == EAGAIN || errno == EWOULDBLOCK ||
207 errno == EINTR)
208 continue;
209 else
210 return -errno;
211 }
212 } while (todo > 0);
213
214 return done;
215}
216
217int read_str_long(int fd, long *value, int base)
218{
219 char buf[32], *end;
220 long v;
221 int err;
222
223 *value = 0;
224 err = read_str_safe(fd, buf, sizeof(buf));
225 if (err < 0)
226 return err;
227 errno = 0;
228 v = strtol(buf, &end, base);
229 if (end == buf || !isspace(*end))
230 return -EINVAL;
231
232 *value = v;
233 return 0;
234}
235
236int read_str_ulong(int fd, unsigned long *value, int base)
237{
238 char buf[32], *end;
239 long v;
240 int err;
241
242 *value = 0;
243 err = read_str_safe(fd, buf, sizeof(buf));
244 if (err < 0)
245 return err;
246 errno = 0;
247 v = strtoul(buf, &end, base);
248 if (end == buf || !isspace(*end))
249 return -EINVAL;
250 *value = v;
251 return 0;
252}
253
254/*
255 * Read one logical line from a configuration file.
256 *
257 * Line endings may be escaped with backslashes, to form one logical line from
258 * several physical lines. No end of line character(s) are included in the
259 * result.
260 *
261 * If linenum is not NULL, it is incremented by the number of physical lines
262 * which have been read.
263 */
Lucas De Marchiaafd3832014-10-03 03:25:06 -0300264char *freadline_wrapped(FILE *fp, unsigned int *linenum)
Lucas De Marchi96573a02014-10-03 00:01:35 -0300265{
266 int size = 256;
267 int i = 0, n = 0;
268 _cleanup_free_ char *buf = malloc(size);
269
270 if (buf == NULL)
271 return NULL;
272
273 for(;;) {
274 int ch = getc_unlocked(fp);
275
276 switch(ch) {
277 case EOF:
278 if (i == 0)
279 return NULL;
280 /* else fall through */
281
282 case '\n':
283 n++;
284
285 {
286 char *ret;
287 if (i == size) {
288 ret = realloc(buf, size + 1);
289 if (!ret)
290 return NULL;
291 } else
292 ret = buf;
293 ret[i] = '\0';
294 buf = NULL;
295 if (linenum)
296 *linenum += n;
297 return ret;
298 }
299
300 case '\\':
301 ch = getc_unlocked(fp);
302
303 if (ch == '\n') {
304 n++;
305 continue;
306 }
307 /* else fall through */
308
309 default:
310 buf[i++] = ch;
311
312 if (i == size) {
313 char *tmp;
314 size *= 2;
315 tmp = realloc(buf, size);
316 if (!tmp)
317 return NULL;
318 buf = tmp;
319 }
320 }
321 }
322}
323
324/* path handling functions */
325/* ************************************************************************ */
326
327bool path_is_absolute(const char *p)
328{
329 assert(p != NULL);
330
331 return p[0] == '/';
332}
333
334char *path_make_absolute_cwd(const char *p)
335{
336 _cleanup_free_ char *cwd = NULL;
337 size_t plen, cwdlen;
338 char *r;
339
340 if (path_is_absolute(p))
341 return strdup(p);
342
343 cwd = get_current_dir_name();
344 if (!cwd)
345 return NULL;
346
347 plen = strlen(p);
348 cwdlen = strlen(cwd);
349
350 /* cwd + '/' + p + '\0' */
351 r = realloc(cwd, cwdlen + 1 + plen + 1);
352 if (r == NULL)
353 return NULL;
354
355 cwd = NULL;
356 r[cwdlen] = '/';
357 memcpy(&r[cwdlen + 1], p, plen + 1);
358
359 return r;
360}
361
362static inline int is_dir(const char *path)
363{
364 struct stat st;
365
366 if (stat(path, &st) >= 0)
367 return S_ISDIR(st.st_mode);
368
369 return -errno;
370}
371
372int mkdir_p(const char *path, int len, mode_t mode)
373{
374 char *start, *end;
375
376 start = strndupa(path, len);
377 end = start + len;
378
379 /*
380 * scan backwards, replacing '/' with '\0' while the component doesn't
381 * exist
382 */
383 for (;;) {
384 int r = is_dir(start);
385 if (r > 0) {
386 end += strlen(end);
387
388 if (end == start + len)
389 return 0;
390
391 /* end != start, since it would be caught on the first
392 * iteration */
393 *end = '/';
394 break;
395 } else if (r == 0)
396 return -ENOTDIR;
397
398 if (end == start)
399 break;
400
401 *end = '\0';
402
403 /* Find the next component, backwards, discarding extra '/'*/
404 while (end > start && *end != '/')
405 end--;
406
407 while (end > start && *(end - 1) == '/')
408 end--;
409 }
410
411 for (; end < start + len;) {
412 if (mkdir(start, mode) < 0 && errno != EEXIST)
413 return -errno;
414
415 end += strlen(end);
416 *end = '/';
417 }
418
419 return 0;
420}
421
422int mkdir_parents(const char *path, mode_t mode)
423{
424 char *end = strrchr(path, '/');
425
426 /* no parent directories */
427 if (end == NULL)
428 return 0;
429
430 return mkdir_p(path, end - path, mode);
431}
432
433unsigned long long ts_usec(const struct timespec *ts)
434{
435 return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
436 (unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
437}
438
439unsigned long long stat_mstamp(const struct stat *st)
440{
441#ifdef HAVE_STRUCT_STAT_ST_MTIM
442 return ts_usec(&st->st_mtim);
443#else
444 return (unsigned long long) st->st_mtime;
445#endif
446}