blob: d91d068f50c00b7f94c1e6a7bb58d47507aa3c29 [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
6#include <ctype.h>
Jorge Lucangeli Obesf205fff2016-08-06 09:06:21 -04007#include <errno.h>
8#include <fcntl.h>
Jorge Lucangeli Obes07459372016-10-19 15:33:31 -04009#include <limits.h>
Luis Hector Chavez40b25742013-09-22 19:44:06 -070010#include <stdio.h>
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -070011#include <string.h>
Jorge Lucangeli Obesf205fff2016-08-06 09:06:21 -040012#include <sys/stat.h>
13#include <sys/types.h>
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -070014
15#include "util.h"
16
Luis Hector Chavez40b25742013-09-22 19:44:06 -070017#include "libconstants.h"
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -070018#include "libsyscalls.h"
19
Mike Frysingerfccb4c92013-10-19 02:42:07 -040020/*
21 * These are syscalls used by the syslog() C library call. You can find them
22 * by running a simple test program. See below for x86_64 behavior:
23 * $ cat test.c
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080024 * #include <syslog.h>
Mike Frysingerfccb4c92013-10-19 02:42:07 -040025 * main() { syslog(0, "foo"); }
26 * $ gcc test.c -static
27 * $ strace ./a.out
28 * ...
29 * socket(PF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3 <- look for socket connection
30 * connect(...) <- important
31 * sendto(...) <- important
32 * exit_group(0) <- finish!
33 */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070034#if defined(__x86_64__)
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080035#if defined(__ANDROID__)
36const char *log_syscalls[] = {"socket", "connect", "fcntl", "writev"};
Alex Deymo7c6899c2016-01-27 18:24:19 -080037#else
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080038const char *log_syscalls[] = {"connect", "sendto"};
39#endif
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070040#elif defined(__i386__)
Jeff Vander Stoep1482f202016-01-07 11:21:31 -080041#if defined(__ANDROID__)
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080042const char *log_syscalls[] = {"socketcall", "writev", "fcntl64",
43 "clock_gettime"};
Jeff Vander Stoep1482f202016-01-07 11:21:31 -080044#else
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080045const char *log_syscalls[] = {"socketcall", "time"};
Jeff Vander Stoep1482f202016-01-07 11:21:31 -080046#endif
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070047#elif defined(__arm__)
Jeff Vander Stoepd38f3992015-12-02 10:54:51 -080048#if defined(__ANDROID__)
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080049const char *log_syscalls[] = {"clock_gettime", "connect", "fcntl64", "socket",
50 "writev"};
Jeff Vander Stoepd38f3992015-12-02 10:54:51 -080051#else
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080052const char *log_syscalls[] = {"connect", "gettimeofday", "send"};
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
Jorge Lucangeli Obesb98ad292016-01-25 15:07:30 -080058const char *log_syscalls[] = {"connect", "send"};
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__)
62const char *log_syscalls[] = {"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
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -070069int lookup_syscall(const char *name)
70{
71 const struct syscall_entry *entry = syscall_table;
72 for (; entry->name && entry->nr >= 0; ++entry)
73 if (!strcmp(entry->name, name))
74 return entry->nr;
75 return -1;
76}
77
78const char *lookup_syscall_name(int nr)
79{
80 const struct syscall_entry *entry = syscall_table;
81 for (; entry->name && entry->nr >= 0; ++entry)
82 if (entry->nr == nr)
83 return entry->name;
84 return NULL;
85}
86
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -040087long int parse_single_constant(char *constant_str, char **endptr)
88{
89 const struct constant_entry *entry = constant_table;
Jorge Lucangeli Obes07459372016-10-19 15:33:31 -040090 long int res = 0;
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -040091 for (; entry->name; ++entry) {
92 if (!strcmp(entry->name, constant_str)) {
93 if (endptr)
94 *endptr = constant_str + strlen(constant_str);
95
96 return entry->value;
97 }
98 }
99
Jorge Lucangeli Obes07459372016-10-19 15:33:31 -0400100 errno = 0;
101 res = strtol(constant_str, endptr, 0);
102 if (errno == ERANGE) {
103 if (res == LONG_MAX) {
104 /* See if the constant fits in an unsigned long int. */
105 errno = 0;
106 res = strtoul(constant_str, endptr, 0);
107 if (errno == ERANGE) {
108 /*
109 * On unsigned overflow, use the same convention
110 * as when strtol(3) finds no digits: set
111 * |*endptr| to |constant_str| and return 0.
112 */
113 warn("unsigned overflow: '%s'", constant_str);
114 *endptr = constant_str;
115 res = 0;
116 }
117 } else if (res == LONG_MIN) {
118 /*
119 * Same for signed underflow: set |*endptr| to
120 * |constant_str| and return 0.
121 */
122 warn("signed underflow: '%s'", constant_str);
123 *endptr = constant_str;
124 res = 0;
125 }
126 }
127 return res;
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -0400128}
129
Luis Hector Chavez40b25742013-09-22 19:44:06 -0700130long int parse_constant(char *constant_str, char **endptr)
131{
Luis Hector Chavez21224552015-06-27 18:10:39 +0000132 long int value = 0;
133 char *group, *lastpos = constant_str;
134 char *original_constant_str = constant_str;
135
136 /*
137 * Try to parse constants separated by pipes. Note that since
138 * |constant_str| is an atom, there can be no spaces between the
139 * constant and the pipe. Constants can be either a named constant
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -0400140 * defined in libconstants.gen.c or a number parsed with strtol(3).
Luis Hector Chavez21224552015-06-27 18:10:39 +0000141 *
142 * If there is an error parsing any of the constants, the whole process
143 * fails.
144 */
145 while ((group = tokenize(&constant_str, "|")) != NULL) {
146 char *end = group;
147 value |= parse_single_constant(group, &end);
148 if (end == group) {
149 lastpos = original_constant_str;
150 value = 0;
151 break;
152 }
153 lastpos = end;
154 }
155 if (endptr)
156 *endptr = lastpos;
157 return value;
158}
159
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -0700160char *strip(char *s)
161{
162 char *end;
163 while (*s && isblank(*s))
164 s++;
165 end = s + strlen(s) - 1;
166 while (end >= s && *end && (isblank(*end) || *end == '\n'))
167 end--;
168 *(end + 1) = '\0';
169 return s;
170}
Jorge Lucangeli Obes66cfc142012-11-30 15:42:52 -0800171
Jorge Lucangeli Obesc8b21e12014-06-13 14:26:16 -0700172char *tokenize(char **stringp, const char *delim)
173{
Jorge Lucangeli Obes66cfc142012-11-30 15:42:52 -0800174 char *ret = NULL;
175
176 /* If the string is NULL or empty, there are no tokens to be found. */
177 if (stringp == NULL || *stringp == NULL || **stringp == '\0')
178 return NULL;
179
180 /*
181 * If the delimiter is NULL or empty,
182 * the full string makes up the only token.
183 */
184 if (delim == NULL || *delim == '\0') {
185 ret = *stringp;
186 *stringp = NULL;
187 return ret;
188 }
189
190 char *found;
191 while (**stringp != '\0') {
192 found = strstr(*stringp, delim);
193
194 if (!found) {
195 /*
196 * The delimiter was not found, so the full string
197 * makes up the only token, and we're done.
198 */
199 ret = *stringp;
200 *stringp = NULL;
201 break;
202 }
203
204 if (found != *stringp) {
205 /* There's a non-empty token before the delimiter. */
206 *found = '\0';
207 ret = *stringp;
208 *stringp = found + strlen(delim);
209 break;
210 }
211
212 /*
213 * The delimiter was found at the start of the string,
214 * skip it and keep looking for a non-empty token.
215 */
216 *stringp += strlen(delim);
217 }
218
219 return ret;
220}
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -0400221
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -0400222char *path_join(const char *external_path, const char *internal_path)
223{
224 char *path;
225 size_t pathlen;
226
227 /* One extra char for '/' and one for '\0', hence + 2. */
228 pathlen = strlen(external_path) + strlen(internal_path) + 2;
229 path = malloc(pathlen);
230 snprintf(path, pathlen, "%s/%s", external_path, internal_path);
231
232 return path;
233}
234
Jorge Lucangeli Obesf205fff2016-08-06 09:06:21 -0400235int write_proc_file(pid_t pid, const char *content, const char *basename)
236{
237 int fd, ret;
238 size_t sz, len;
239 ssize_t written;
240 char filename[32];
241
242 sz = sizeof(filename);
243 ret = snprintf(filename, sz, "/proc/%d/%s", pid, basename);
244 if (ret < 0 || (size_t)ret >= sz) {
245 warn("failed to generate %s filename", basename);
246 return -1;
247 }
248
249 fd = open(filename, O_WRONLY | O_CLOEXEC);
250 if (fd < 0) {
251 pwarn("failed to open '%s'", filename);
252 return -errno;
253 }
254
255 len = strlen(content);
256 written = write(fd, content, len);
257 if (written < 0) {
258 pwarn("failed to write '%s'", filename);
259 return -1;
260 }
261
262 if ((size_t)written < len) {
263 warn("failed to write %zu bytes to '%s'", len, filename);
264 return -1;
265 }
266 close(fd);
267 return 0;
268}
269
270int write_pid_to_path(pid_t pid, const char *path)
271{
272 FILE *fp = fopen(path, "w");
273
274 if (!fp) {
275 pwarn("failed to open '%s'", path);
276 return -errno;
277 }
278 if (fprintf(fp, "%d\n", (int)pid) < 0) {
279 /* fprintf(3) does not set errno on failure. */
280 warn("fprintf(%s) failed", path);
281 return -1;
282 }
283 if (fclose(fp)) {
284 pwarn("fclose(%s) failed", path);
285 return -errno;
286 }
287
288 return 0;
289}
290
Jorge Lucangeli Obes7b2e29c2016-08-04 12:21:03 -0400291void *consumebytes(size_t length, char **buf, size_t *buflength)
292{
293 char *p = *buf;
294 if (length > *buflength)
295 return NULL;
296 *buf += length;
297 *buflength -= length;
298 return p;
299}
300
301char *consumestr(char **buf, size_t *buflength)
302{
303 size_t len = strnlen(*buf, *buflength);
304 if (len == *buflength)
305 /* There's no null-terminator. */
306 return NULL;
307 return consumebytes(len + 1, buf, buflength);
308}