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 /* string handling functions and memory allocations                         */
     53 /* ************************************************************************ */
     54 
     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 
     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 /* ************************************************************************ */
     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  */
    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 
    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 
    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 
    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 /* ************************************************************************ */
    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 
    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 
    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 
    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  */
    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 
    354 bool path_is_absolute(const char *p)
    355 {
    356 	assert(p != NULL);
    357 
    358 	return p[0] == '/';
    359 }
    360 
    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 
    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 
    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 
    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 
    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 
    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