• 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 	{ }
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