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