blob: 616ac935f22b1c0ed395ea156c8569b8235f2d3f [file] [log] [blame]
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -07001/* 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
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -04006#include "util.h"
7
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -07008#include <ctype.h>
Jorge Lucangeli Obesf205fff2016-08-06 09:06:21 -04009#include <errno.h>
Jorge Lucangeli Obes07459372016-10-19 15:33:31 -040010#include <limits.h>
Luis Hector Chavez114a9302017-09-05 20:36:58 -070011#include <stdarg.h>
Martin Pelikánab9eb442017-01-25 11:53:58 +110012#include <stdint.h>
Luis Hector Chavez40b25742013-09-22 19:44:06 -070013#include <stdio.h>
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -070014#include <string.h>
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -070015
Luis Hector Chavez40b25742013-09-22 19:44:06 -070016#include "libconstants.h"
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -070017#include "libsyscalls.h"
18
Mike Frysingerfccb4c92013-10-19 02:42:07 -040019/*
20 * These are syscalls used by the syslog() C library call. You can find them
21 * by running a simple test program. See below for x86_64 behavior:
22 * $ cat test.c
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080023 * #include <syslog.h>
Mike Frysingerfccb4c92013-10-19 02:42:07 -040024 * main() { syslog(0, "foo"); }
25 * $ gcc test.c -static
26 * $ strace ./a.out
27 * ...
28 * socket(PF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3 <- look for socket connection
29 * connect(...) <- important
30 * sendto(...) <- important
31 * exit_group(0) <- finish!
32 */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070033#if defined(__x86_64__)
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080034#if defined(__ANDROID__)
35const char *log_syscalls[] = {"socket", "connect", "fcntl", "writev"};
Alex Deymo7c6899c2016-01-27 18:24:19 -080036#else
Zach Reiznerb1f517e2018-03-30 16:44:26 -070037const char *log_syscalls[] = {"socket", "connect", "sendto", "writev"};
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080038#endif
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070039#elif defined(__i386__)
Jeff Vander Stoep1482f202016-01-07 11:21:31 -080040#if defined(__ANDROID__)
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080041const char *log_syscalls[] = {"socketcall", "writev", "fcntl64",
42 "clock_gettime"};
Jeff Vander Stoep1482f202016-01-07 11:21:31 -080043#else
Sonny Rao33d49852018-05-18 13:38:43 -070044const char *log_syscalls[] = {"socketcall", "time", "writev"};
Jeff Vander Stoep1482f202016-01-07 11:21:31 -080045#endif
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070046#elif defined(__arm__)
Jeff Vander Stoepd38f3992015-12-02 10:54:51 -080047#if defined(__ANDROID__)
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080048const char *log_syscalls[] = {"clock_gettime", "connect", "fcntl64", "socket",
49 "writev"};
Jeff Vander Stoepd38f3992015-12-02 10:54:51 -080050#else
Sonny Rao33d49852018-05-18 13:38:43 -070051const char *log_syscalls[] = {"socket", "connect", "gettimeofday", "send",
52 "writev"};
Jeff Vander Stoepd38f3992015-12-02 10:54:51 -080053#endif
54#elif defined(__aarch64__)
55#if defined(__ANDROID__)
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080056const char *log_syscalls[] = {"connect", "fcntl", "sendto", "socket", "writev"};
Jeff Vander Stoepd38f3992015-12-02 10:54:51 -080057#else
Sonny Rao33d49852018-05-18 13:38:43 -070058const char *log_syscalls[] = {"socket", "connect", "send", "writev"};
Jeff Vander Stoepd38f3992015-12-02 10:54:51 -080059#endif
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080060#elif defined(__powerpc__) || defined(__ia64__) || defined(__hppa__) || \
61 defined(__sparc__) || defined(__mips__)
Mike Frysinger09560862017-09-27 01:13:15 -040062const char *log_syscalls[] = {"socket", "connect", "send"};
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070063#else
64#error "Unsupported platform"
65#endif
66
Mike Frysinger404d2bb2017-01-17 19:29:00 -050067const size_t log_syscalls_len = ARRAY_SIZE(log_syscalls);
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070068
Luis Hector Chavez114a9302017-09-05 20:36:58 -070069/* clang-format off */
70static struct logging_config_t {
71 /* The logging system to use. The default is syslog. */
72 enum logging_system_t logger;
73
74 /* File descriptor to log to. Only used when logger is LOG_TO_FD. */
75 int fd;
76
77 /* Minimum priority to log. Only used when logger is LOG_TO_FD. */
78 int min_priority;
79} logging_config = {
80 .logger = LOG_TO_SYSLOG,
81};
82/* clang-format on */
83
84void do_log(int priority, const char *format, ...)
85{
86 if (logging_config.logger == LOG_TO_SYSLOG) {
87 va_list args;
88 va_start(args, format);
89 vsyslog(priority, format, args);
90 va_end(args);
91 return;
92 }
93
94 if (logging_config.min_priority < priority)
95 return;
96
97 va_list args;
98 va_start(args, format);
99 vdprintf(logging_config.fd, format, args);
100 va_end(args);
101 dprintf(logging_config.fd, "\n");
102}
103
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -0700104int lookup_syscall(const char *name)
105{
106 const struct syscall_entry *entry = syscall_table;
107 for (; entry->name && entry->nr >= 0; ++entry)
108 if (!strcmp(entry->name, name))
109 return entry->nr;
110 return -1;
111}
112
113const char *lookup_syscall_name(int nr)
114{
115 const struct syscall_entry *entry = syscall_table;
116 for (; entry->name && entry->nr >= 0; ++entry)
117 if (entry->nr == nr)
118 return entry->name;
119 return NULL;
120}
121
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -0400122long int parse_single_constant(char *constant_str, char **endptr)
123{
124 const struct constant_entry *entry = constant_table;
Jorge Lucangeli Obes07459372016-10-19 15:33:31 -0400125 long int res = 0;
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -0400126 for (; entry->name; ++entry) {
127 if (!strcmp(entry->name, constant_str)) {
128 if (endptr)
129 *endptr = constant_str + strlen(constant_str);
130
131 return entry->value;
132 }
133 }
134
Jorge Lucangeli Obes07459372016-10-19 15:33:31 -0400135 errno = 0;
136 res = strtol(constant_str, endptr, 0);
137 if (errno == ERANGE) {
138 if (res == LONG_MAX) {
139 /* See if the constant fits in an unsigned long int. */
140 errno = 0;
141 res = strtoul(constant_str, endptr, 0);
142 if (errno == ERANGE) {
143 /*
144 * On unsigned overflow, use the same convention
145 * as when strtol(3) finds no digits: set
146 * |*endptr| to |constant_str| and return 0.
147 */
148 warn("unsigned overflow: '%s'", constant_str);
149 *endptr = constant_str;
150 res = 0;
151 }
152 } else if (res == LONG_MIN) {
153 /*
154 * Same for signed underflow: set |*endptr| to
155 * |constant_str| and return 0.
156 */
157 warn("signed underflow: '%s'", constant_str);
158 *endptr = constant_str;
159 res = 0;
160 }
161 }
162 return res;
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -0400163}
164
Luis Hector Chavez40b25742013-09-22 19:44:06 -0700165long int parse_constant(char *constant_str, char **endptr)
166{
Luis Hector Chavez21224552015-06-27 18:10:39 +0000167 long int value = 0;
168 char *group, *lastpos = constant_str;
169 char *original_constant_str = constant_str;
170
171 /*
172 * Try to parse constants separated by pipes. Note that since
173 * |constant_str| is an atom, there can be no spaces between the
174 * constant and the pipe. Constants can be either a named constant
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -0400175 * defined in libconstants.gen.c or a number parsed with strtol(3).
Luis Hector Chavez21224552015-06-27 18:10:39 +0000176 *
177 * If there is an error parsing any of the constants, the whole process
178 * fails.
179 */
180 while ((group = tokenize(&constant_str, "|")) != NULL) {
181 char *end = group;
182 value |= parse_single_constant(group, &end);
183 if (end == group) {
184 lastpos = original_constant_str;
185 value = 0;
186 break;
187 }
188 lastpos = end;
189 }
190 if (endptr)
191 *endptr = lastpos;
192 return value;
193}
194
Martin Pelikánab9eb442017-01-25 11:53:58 +1100195/*
196 * parse_size, specified as a string with a decimal number in bytes,
197 * possibly with one 1-character suffix like "10K" or "6G".
198 * Assumes both pointers are non-NULL.
199 *
200 * Returns 0 on success, negative errno on failure.
201 * Only writes to result on success.
202 */
203int parse_size(size_t *result, const char *sizespec)
204{
205 const char prefixes[] = "KMGTPE";
206 size_t i, multiplier = 1, nsize, size = 0;
207 unsigned long long parsed;
208 const size_t len = strlen(sizespec);
209 char *end;
210
211 if (len == 0 || sizespec[0] == '-')
212 return -EINVAL;
213
214 for (i = 0; i < sizeof(prefixes); ++i) {
215 if (sizespec[len - 1] == prefixes[i]) {
216#if __WORDSIZE == 32
217 if (i >= 3)
218 return -ERANGE;
219#endif
220 multiplier = 1024;
221 while (i-- > 0)
222 multiplier *= 1024;
223 break;
224 }
225 }
226
227 /* We only need size_t but strtoul(3) is too small on IL32P64. */
228 parsed = strtoull(sizespec, &end, 10);
229 if (parsed == ULLONG_MAX)
230 return -errno;
231 if (parsed >= SIZE_MAX)
232 return -ERANGE;
233 if ((multiplier != 1 && end != sizespec + len - 1) ||
234 (multiplier == 1 && end != sizespec + len))
235 return -EINVAL;
236 size = (size_t)parsed;
237
238 nsize = size * multiplier;
239 if (nsize / multiplier != size)
240 return -ERANGE;
241 *result = nsize;
242 return 0;
243}
244
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -0700245char *strip(char *s)
246{
247 char *end;
248 while (*s && isblank(*s))
249 s++;
250 end = s + strlen(s) - 1;
251 while (end >= s && *end && (isblank(*end) || *end == '\n'))
252 end--;
253 *(end + 1) = '\0';
254 return s;
255}
Jorge Lucangeli Obes66cfc142012-11-30 15:42:52 -0800256
Jorge Lucangeli Obesc8b21e12014-06-13 14:26:16 -0700257char *tokenize(char **stringp, const char *delim)
258{
Jorge Lucangeli Obes66cfc142012-11-30 15:42:52 -0800259 char *ret = NULL;
260
Mike Frysingerb4c7e772018-01-17 17:40:15 -0500261 /* If the string is NULL, there are no tokens to be found. */
262 if (stringp == NULL || *stringp == NULL)
Jorge Lucangeli Obes66cfc142012-11-30 15:42:52 -0800263 return NULL;
264
265 /*
266 * If the delimiter is NULL or empty,
267 * the full string makes up the only token.
268 */
269 if (delim == NULL || *delim == '\0') {
270 ret = *stringp;
271 *stringp = NULL;
272 return ret;
273 }
274
Mike Frysingerb4c7e772018-01-17 17:40:15 -0500275 char *found = strstr(*stringp, delim);
276 if (!found) {
Jorge Lucangeli Obes66cfc142012-11-30 15:42:52 -0800277 /*
Mike Frysingerb4c7e772018-01-17 17:40:15 -0500278 * The delimiter was not found, so the full string
279 * makes up the only token, and we're done.
Jorge Lucangeli Obes66cfc142012-11-30 15:42:52 -0800280 */
Mike Frysingerb4c7e772018-01-17 17:40:15 -0500281 ret = *stringp;
282 *stringp = NULL;
283 } else {
284 /* There's a token here, possibly empty. That's OK. */
285 *found = '\0';
286 ret = *stringp;
287 *stringp = found + strlen(delim);
Jorge Lucangeli Obes66cfc142012-11-30 15:42:52 -0800288 }
289
290 return ret;
291}
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -0400292
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -0400293char *path_join(const char *external_path, const char *internal_path)
294{
295 char *path;
296 size_t pathlen;
297
298 /* One extra char for '/' and one for '\0', hence + 2. */
299 pathlen = strlen(external_path) + strlen(internal_path) + 2;
300 path = malloc(pathlen);
301 snprintf(path, pathlen, "%s/%s", external_path, internal_path);
302
303 return path;
304}
305
306void *consumebytes(size_t length, char **buf, size_t *buflength)
307{
308 char *p = *buf;
309 if (length > *buflength)
310 return NULL;
311 *buf += length;
312 *buflength -= length;
313 return p;
314}
315
316char *consumestr(char **buf, size_t *buflength)
317{
318 size_t len = strnlen(*buf, *buflength);
319 if (len == *buflength)
320 /* There's no null-terminator. */
321 return NULL;
322 return consumebytes(len + 1, buf, buflength);
323}
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700324
325void init_logging(enum logging_system_t logger, int fd, int min_priority)
326{
327 logging_config.logger = logger;
328 logging_config.fd = fd;
329 logging_config.min_priority = min_priority;
330}