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