1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include "util.h" 7 8 #include <ctype.h> 9 #include <errno.h> 10 #include <limits.h> 11 #include <stdint.h> 12 #include <stdio.h> 13 #include <string.h> 14 15 #include "libconstants.h" 16 #include "libsyscalls.h" 17 18 /* 19 * These are syscalls used by the syslog() C library call. You can find them 20 * by running a simple test program. See below for x86_64 behavior: 21 * $ cat test.c 22 * #include <syslog.h> 23 * main() { syslog(0, "foo"); } 24 * $ gcc test.c -static 25 * $ strace ./a.out 26 * ... 27 * socket(PF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3 <- look for socket connection 28 * connect(...) <- important 29 * sendto(...) <- important 30 * exit_group(0) <- finish! 31 */ 32 #if defined(__x86_64__) 33 #if defined(__ANDROID__) 34 const char *log_syscalls[] = {"socket", "connect", "fcntl", "writev"}; 35 #else 36 const char *log_syscalls[] = {"connect", "sendto"}; 37 #endif 38 #elif defined(__i386__) 39 #if defined(__ANDROID__) 40 const char *log_syscalls[] = {"socketcall", "writev", "fcntl64", 41 "clock_gettime"}; 42 #else 43 const char *log_syscalls[] = {"socketcall", "time"}; 44 #endif 45 #elif defined(__arm__) 46 #if defined(__ANDROID__) 47 const char *log_syscalls[] = {"clock_gettime", "connect", "fcntl64", "socket", 48 "writev"}; 49 #else 50 const char *log_syscalls[] = {"connect", "gettimeofday", "send"}; 51 #endif 52 #elif defined(__aarch64__) 53 #if defined(__ANDROID__) 54 const char *log_syscalls[] = {"connect", "fcntl", "sendto", "socket", "writev"}; 55 #else 56 const char *log_syscalls[] = {"connect", "send"}; 57 #endif 58 #elif defined(__powerpc__) || defined(__ia64__) || defined(__hppa__) || \ 59 defined(__sparc__) || defined(__mips__) 60 const char *log_syscalls[] = {"connect", "send"}; 61 #else 62 #error "Unsupported platform" 63 #endif 64 65 const size_t log_syscalls_len = ARRAY_SIZE(log_syscalls); 66 67 int lookup_syscall(const char *name) 68 { 69 const struct syscall_entry *entry = syscall_table; 70 for (; entry->name && entry->nr >= 0; ++entry) 71 if (!strcmp(entry->name, name)) 72 return entry->nr; 73 return -1; 74 } 75 76 const char *lookup_syscall_name(int nr) 77 { 78 const struct syscall_entry *entry = syscall_table; 79 for (; entry->name && entry->nr >= 0; ++entry) 80 if (entry->nr == nr) 81 return entry->name; 82 return NULL; 83 } 84 85 long int parse_single_constant(char *constant_str, char **endptr) 86 { 87 const struct constant_entry *entry = constant_table; 88 long int res = 0; 89 for (; entry->name; ++entry) { 90 if (!strcmp(entry->name, constant_str)) { 91 if (endptr) 92 *endptr = constant_str + strlen(constant_str); 93 94 return entry->value; 95 } 96 } 97 98 errno = 0; 99 res = strtol(constant_str, endptr, 0); 100 if (errno == ERANGE) { 101 if (res == LONG_MAX) { 102 /* See if the constant fits in an unsigned long int. */ 103 errno = 0; 104 res = strtoul(constant_str, endptr, 0); 105 if (errno == ERANGE) { 106 /* 107 * On unsigned overflow, use the same convention 108 * as when strtol(3) finds no digits: set 109 * |*endptr| to |constant_str| and return 0. 110 */ 111 warn("unsigned overflow: '%s'", constant_str); 112 *endptr = constant_str; 113 res = 0; 114 } 115 } else if (res == LONG_MIN) { 116 /* 117 * Same for signed underflow: set |*endptr| to 118 * |constant_str| and return 0. 119 */ 120 warn("signed underflow: '%s'", constant_str); 121 *endptr = constant_str; 122 res = 0; 123 } 124 } 125 return res; 126 } 127 128 long int parse_constant(char *constant_str, char **endptr) 129 { 130 long int value = 0; 131 char *group, *lastpos = constant_str; 132 char *original_constant_str = constant_str; 133 134 /* 135 * Try to parse constants separated by pipes. Note that since 136 * |constant_str| is an atom, there can be no spaces between the 137 * constant and the pipe. Constants can be either a named constant 138 * defined in libconstants.gen.c or a number parsed with strtol(3). 139 * 140 * If there is an error parsing any of the constants, the whole process 141 * fails. 142 */ 143 while ((group = tokenize(&constant_str, "|")) != NULL) { 144 char *end = group; 145 value |= parse_single_constant(group, &end); 146 if (end == group) { 147 lastpos = original_constant_str; 148 value = 0; 149 break; 150 } 151 lastpos = end; 152 } 153 if (endptr) 154 *endptr = lastpos; 155 return value; 156 } 157 158 /* 159 * parse_size, specified as a string with a decimal number in bytes, 160 * possibly with one 1-character suffix like "10K" or "6G". 161 * Assumes both pointers are non-NULL. 162 * 163 * Returns 0 on success, negative errno on failure. 164 * Only writes to result on success. 165 */ 166 int parse_size(size_t *result, const char *sizespec) 167 { 168 const char prefixes[] = "KMGTPE"; 169 size_t i, multiplier = 1, nsize, size = 0; 170 unsigned long long parsed; 171 const size_t len = strlen(sizespec); 172 char *end; 173 174 if (len == 0 || sizespec[0] == '-') 175 return -EINVAL; 176 177 for (i = 0; i < sizeof(prefixes); ++i) { 178 if (sizespec[len - 1] == prefixes[i]) { 179 #if __WORDSIZE == 32 180 if (i >= 3) 181 return -ERANGE; 182 #endif 183 multiplier = 1024; 184 while (i-- > 0) 185 multiplier *= 1024; 186 break; 187 } 188 } 189 190 /* We only need size_t but strtoul(3) is too small on IL32P64. */ 191 parsed = strtoull(sizespec, &end, 10); 192 if (parsed == ULLONG_MAX) 193 return -errno; 194 if (parsed >= SIZE_MAX) 195 return -ERANGE; 196 if ((multiplier != 1 && end != sizespec + len - 1) || 197 (multiplier == 1 && end != sizespec + len)) 198 return -EINVAL; 199 size = (size_t)parsed; 200 201 nsize = size * multiplier; 202 if (nsize / multiplier != size) 203 return -ERANGE; 204 *result = nsize; 205 return 0; 206 } 207 208 char *strip(char *s) 209 { 210 char *end; 211 while (*s && isblank(*s)) 212 s++; 213 end = s + strlen(s) - 1; 214 while (end >= s && *end && (isblank(*end) || *end == '\n')) 215 end--; 216 *(end + 1) = '\0'; 217 return s; 218 } 219 220 char *tokenize(char **stringp, const char *delim) 221 { 222 char *ret = NULL; 223 224 /* If the string is NULL or empty, there are no tokens to be found. */ 225 if (stringp == NULL || *stringp == NULL || **stringp == '\0') 226 return NULL; 227 228 /* 229 * If the delimiter is NULL or empty, 230 * the full string makes up the only token. 231 */ 232 if (delim == NULL || *delim == '\0') { 233 ret = *stringp; 234 *stringp = NULL; 235 return ret; 236 } 237 238 char *found; 239 while (**stringp != '\0') { 240 found = strstr(*stringp, delim); 241 242 if (!found) { 243 /* 244 * The delimiter was not found, so the full string 245 * makes up the only token, and we're done. 246 */ 247 ret = *stringp; 248 *stringp = NULL; 249 break; 250 } 251 252 if (found != *stringp) { 253 /* There's a non-empty token before the delimiter. */ 254 *found = '\0'; 255 ret = *stringp; 256 *stringp = found + strlen(delim); 257 break; 258 } 259 260 /* 261 * The delimiter was found at the start of the string, 262 * skip it and keep looking for a non-empty token. 263 */ 264 *stringp += strlen(delim); 265 } 266 267 return ret; 268 } 269 270 char *path_join(const char *external_path, const char *internal_path) 271 { 272 char *path; 273 size_t pathlen; 274 275 /* One extra char for '/' and one for '\0', hence + 2. */ 276 pathlen = strlen(external_path) + strlen(internal_path) + 2; 277 path = malloc(pathlen); 278 snprintf(path, pathlen, "%s/%s", external_path, internal_path); 279 280 return path; 281 } 282 283 void *consumebytes(size_t length, char **buf, size_t *buflength) 284 { 285 char *p = *buf; 286 if (length > *buflength) 287 return NULL; 288 *buf += length; 289 *buflength -= length; 290 return p; 291 } 292 293 char *consumestr(char **buf, size_t *buflength) 294 { 295 size_t len = strnlen(*buf, *buflength); 296 if (len == *buflength) 297 /* There's no null-terminator. */ 298 return NULL; 299 return consumebytes(len + 1, buf, buflength); 300 } 301