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