• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
stat_mstamp(const struct stat * st)469 unsigned long long stat_mstamp(const struct stat *st)
470 {
471 #ifdef HAVE_STRUCT_STAT_ST_MTIM
472 	return ts_usec(&st->st_mtim);
473 #else
474 	return (unsigned long long) st->st_mtime;
475 #endif
476 }
477