Home | History | Annotate | Download | only in shared
      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 (at) 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 
     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 
     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 /* ************************************************************************ */
     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  */
    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 
    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 
    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 
    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 /* ************************************************************************ */
    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 
    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 
    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 
    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  */
    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 
    352 bool path_is_absolute(const char *p)
    353 {
    354 	assert(p != NULL);
    355 
    356 	return p[0] == '/';
    357 }
    358 
    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 
    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 
    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 
    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 
    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 
    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