log_read.c revision 17947103154ad16a47333655b02546df306e819a
1/* 2** Copyright 2013-2014, The Android Open Source Project 3** 4** Licensed under the Apache License, Version 2.0 (the "License"); 5** you may not use this file except in compliance with the License. 6** You may obtain a copy of the License at 7** 8** http://www.apache.org/licenses/LICENSE-2.0 9** 10** Unless required by applicable law or agreed to in writing, software 11** distributed under the License is distributed on an "AS IS" BASIS, 12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13** See the License for the specific language governing permissions and 14** limitations under the License. 15*/ 16 17#include <errno.h> 18#include <fcntl.h> 19#include <signal.h> 20#include <stddef.h> 21#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */ 22#include <stdlib.h> 23#include <string.h> 24#include <unistd.h> 25 26#include <cutils/list.h> 27#include <cutils/sockets.h> 28#include <log/log.h> 29#include <log/logger.h> 30 31/* branchless on many architectures. */ 32#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y)))) 33 34#define WEAK __attribute__((weak)) 35#define UNUSED __attribute__((unused)) 36 37/* Private copy of ../libcutils/socket_local_client.c prevent library loops */ 38 39#ifdef HAVE_WINSOCK 40 41int WEAK socket_local_client(const char *name, int namespaceId, int type) 42{ 43 errno = ENOSYS; 44 return -ENOSYS; 45} 46 47#else /* !HAVE_WINSOCK */ 48 49#include <sys/socket.h> 50#include <sys/un.h> 51#include <sys/select.h> 52#include <sys/types.h> 53 54/* Private copy of ../libcutils/socket_local.h prevent library loops */ 55#define FILESYSTEM_SOCKET_PREFIX "/tmp/" 56#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/" 57/* End of ../libcutils/socket_local.h */ 58 59#define LISTEN_BACKLOG 4 60 61/* Documented in header file. */ 62int WEAK socket_make_sockaddr_un(const char *name, int namespaceId, 63 struct sockaddr_un *p_addr, socklen_t *alen) 64{ 65 memset (p_addr, 0, sizeof (*p_addr)); 66 size_t namelen; 67 68 switch (namespaceId) { 69 case ANDROID_SOCKET_NAMESPACE_ABSTRACT: 70#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 71 namelen = strlen(name); 72 73 /* Test with length +1 for the *initial* '\0'. */ 74 if ((namelen + 1) > sizeof(p_addr->sun_path)) { 75 goto error; 76 } 77 78 /* 79 * Note: The path in this case is *not* supposed to be 80 * '\0'-terminated. ("man 7 unix" for the gory details.) 81 */ 82 83 p_addr->sun_path[0] = 0; 84 memcpy(p_addr->sun_path + 1, name, namelen); 85#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/ 86 /* this OS doesn't have the Linux abstract namespace */ 87 88 namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX); 89 /* unix_path_max appears to be missing on linux */ 90 if (namelen > sizeof(*p_addr) 91 - offsetof(struct sockaddr_un, sun_path) - 1) { 92 goto error; 93 } 94 95 strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX); 96 strcat(p_addr->sun_path, name); 97#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/ 98 break; 99 100 case ANDROID_SOCKET_NAMESPACE_RESERVED: 101 namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX); 102 /* unix_path_max appears to be missing on linux */ 103 if (namelen > sizeof(*p_addr) 104 - offsetof(struct sockaddr_un, sun_path) - 1) { 105 goto error; 106 } 107 108 strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX); 109 strcat(p_addr->sun_path, name); 110 break; 111 112 case ANDROID_SOCKET_NAMESPACE_FILESYSTEM: 113 namelen = strlen(name); 114 /* unix_path_max appears to be missing on linux */ 115 if (namelen > sizeof(*p_addr) 116 - offsetof(struct sockaddr_un, sun_path) - 1) { 117 goto error; 118 } 119 120 strcpy(p_addr->sun_path, name); 121 break; 122 123 default: 124 /* invalid namespace id */ 125 return -1; 126 } 127 128 p_addr->sun_family = AF_LOCAL; 129 *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; 130 return 0; 131error: 132 return -1; 133} 134 135/** 136 * connect to peer named "name" on fd 137 * returns same fd or -1 on error. 138 * fd is not closed on error. that's your job. 139 * 140 * Used by AndroidSocketImpl 141 */ 142int WEAK socket_local_client_connect(int fd, const char *name, int namespaceId, 143 int type UNUSED) 144{ 145 struct sockaddr_un addr; 146 socklen_t alen; 147 size_t namelen; 148 int err; 149 150 err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen); 151 152 if (err < 0) { 153 goto error; 154 } 155 156 if(connect(fd, (struct sockaddr *) &addr, alen) < 0) { 157 goto error; 158 } 159 160 return fd; 161 162error: 163 return -1; 164} 165 166/** 167 * connect to peer named "name" 168 * returns fd or -1 on error 169 */ 170int WEAK socket_local_client(const char *name, int namespaceId, int type) 171{ 172 int s; 173 174 s = socket(AF_LOCAL, type, 0); 175 if(s < 0) return -1; 176 177 if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) { 178 close(s); 179 return -1; 180 } 181 182 return s; 183} 184 185#endif /* !HAVE_WINSOCK */ 186/* End of ../libcutils/socket_local_client.c */ 187 188#define logger_for_each(logger, logger_list) \ 189 for (logger = node_to_item((logger_list)->node.next, struct logger, node); \ 190 logger != node_to_item(&(logger_list)->node, struct logger, node); \ 191 logger = node_to_item((logger)->node.next, struct logger, node)) 192 193/* In the future, we would like to make this list extensible */ 194static const char *LOG_NAME[LOG_ID_MAX] = { 195 [LOG_ID_MAIN] = "main", 196 [LOG_ID_RADIO] = "radio", 197 [LOG_ID_EVENTS] = "events", 198 [LOG_ID_SYSTEM] = "system" 199}; 200 201const char *android_log_id_to_name(log_id_t log_id) 202{ 203 if (log_id >= LOG_ID_MAX) { 204 log_id = LOG_ID_MAIN; 205 } 206 return LOG_NAME[log_id]; 207} 208 209log_id_t android_name_to_log_id(const char *logName) 210{ 211 const char *b; 212 int ret; 213 214 if (!logName) { 215 return -1; /* NB: log_id_t is unsigned */ 216 } 217 b = strrchr(logName, '/'); 218 if (!b) { 219 b = logName; 220 } else { 221 ++b; 222 } 223 224 for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) { 225 const char *l = LOG_NAME[ret]; 226 if (l && !strcmp(b, l)) { 227 return ret; 228 } 229 } 230 return -1; /* should never happen */ 231} 232 233struct logger_list { 234 struct listnode node; 235 int mode; 236 unsigned int tail; 237 pid_t pid; 238 int sock; 239}; 240 241struct logger { 242 struct listnode node; 243 struct logger_list *top; 244 log_id_t id; 245}; 246 247/* android_logger_alloc unimplemented, no use case */ 248/* android_logger_free not exported */ 249static void android_logger_free(struct logger *logger) 250{ 251 if (!logger) { 252 return; 253 } 254 255 list_remove(&logger->node); 256 257 free(logger); 258} 259 260/* android_logger_alloc unimplemented, no use case */ 261 262/* method for getting the associated sublog id */ 263log_id_t android_logger_get_id(struct logger *logger) 264{ 265 return logger->id; 266} 267 268/* worker for sending the command to the logger */ 269static ssize_t send_log_msg(struct logger *logger, 270 const char *msg, char *buf, size_t buf_size) 271{ 272 ssize_t ret; 273 int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, 274 SOCK_STREAM); 275 if (sock < 0) { 276 ret = sock; 277 goto done; 278 } 279 280 if (msg) { 281 snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1); 282 } 283 284 ret = write(sock, buf, strlen(buf) + 1); 285 if (ret <= 0) { 286 goto done; 287 } 288 289 ret = read(sock, buf, buf_size); 290 291done: 292 if ((ret == -1) && errno) { 293 ret = -errno; 294 } 295 close(sock); 296 return ret; 297} 298 299int android_logger_clear(struct logger *logger) 300{ 301 char buf[512]; 302 303 ssize_t ret = send_log_msg(logger, "clear %d", buf, sizeof(buf)); 304 if (ret < 0) { 305 return ret; 306 } 307 308 if (strncmp(buf, "success", 7)) { 309 return -1; 310 } 311 312 return 0; 313} 314 315/* returns the total size of the log's ring buffer */ 316int android_logger_get_log_size(struct logger *logger) 317{ 318 char buf[512]; 319 320 ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf)); 321 if (ret < 0) { 322 return ret; 323 } 324 325 if ((buf[0] < '0') || ('9' < buf[0])) { 326 return -1; 327 } 328 329 return atoi(buf); 330} 331 332/* 333 * returns the readable size of the log's ring buffer (that is, amount of the 334 * log consumed) 335 */ 336int android_logger_get_log_readable_size(struct logger *logger) 337{ 338 char buf[512]; 339 340 ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf)); 341 if (ret < 0) { 342 return ret; 343 } 344 345 if ((buf[0] < '0') || ('9' < buf[0])) { 346 return -1; 347 } 348 349 return atoi(buf); 350} 351 352/* 353 * returns the logger version 354 */ 355int android_logger_get_log_version(struct logger *logger UNUSED) 356{ 357 return 3; 358} 359 360struct logger_list *android_logger_list_alloc(int mode, 361 unsigned int tail, 362 pid_t pid) 363{ 364 struct logger_list *logger_list; 365 366 logger_list = calloc(1, sizeof(*logger_list)); 367 if (!logger_list) { 368 return NULL; 369 } 370 371 list_init(&logger_list->node); 372 logger_list->mode = mode; 373 logger_list->tail = tail; 374 logger_list->pid = pid; 375 logger_list->sock = -1; 376 377 return logger_list; 378} 379 380/* android_logger_list_register unimplemented, no use case */ 381/* android_logger_list_unregister unimplemented, no use case */ 382 383/* Open the named log and add it to the logger list */ 384struct logger *android_logger_open(struct logger_list *logger_list, 385 log_id_t id) 386{ 387 struct listnode *node; 388 struct logger *logger; 389 char *n; 390 391 if (!logger_list || (id >= LOG_ID_MAX)) { 392 goto err; 393 } 394 395 logger_for_each(logger, logger_list) { 396 if (logger->id == id) { 397 goto ok; 398 } 399 } 400 401 logger = calloc(1, sizeof(*logger)); 402 if (!logger) { 403 goto err; 404 } 405 406 logger->id = id; 407 list_add_tail(&logger_list->node, &logger->node); 408 logger->top = logger_list; 409 goto ok; 410 411err: 412 logger = NULL; 413ok: 414 return logger; 415} 416 417/* Open the single named log and make it part of a new logger list */ 418struct logger_list *android_logger_list_open(log_id_t id, 419 int mode, 420 unsigned int tail, 421 pid_t pid) 422{ 423 struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid); 424 if (!logger_list) { 425 return NULL; 426 } 427 428 if (!android_logger_open(logger_list, id)) { 429 android_logger_list_free(logger_list); 430 return NULL; 431 } 432 433 return logger_list; 434} 435 436static void caught_signal(int signum UNUSED) 437{ 438} 439 440/* Read from the selected logs */ 441int android_logger_list_read(struct logger_list *logger_list, 442 struct log_msg *log_msg) 443{ 444 int ret, e; 445 struct logger *logger; 446 struct sigaction ignore; 447 struct sigaction old_sigaction; 448 unsigned int old_alarm = 0; 449 450 if (!logger_list) { 451 return -EINVAL; 452 } 453 454 if (logger_list->mode & O_NONBLOCK) { 455 memset(&ignore, 0, sizeof(ignore)); 456 ignore.sa_handler = caught_signal; 457 sigemptyset(&ignore.sa_mask); 458 } 459 460 if (logger_list->sock < 0) { 461 char buffer[256], *cp, c; 462 463 int sock = socket_local_client("logdr", 464 ANDROID_SOCKET_NAMESPACE_RESERVED, 465 SOCK_SEQPACKET); 466 if (sock < 0) { 467 if ((sock == -1) && errno) { 468 return -errno; 469 } 470 return sock; 471 } 472 473 strcpy(buffer, 474 (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream"); 475 cp = buffer + strlen(buffer); 476 477 strcpy(cp, " lids"); 478 cp += 5; 479 c = '='; 480 int remaining = sizeof(buffer) - (cp - buffer); 481 logger_for_each(logger, logger_list) { 482 ret = snprintf(cp, remaining, "%c%u", c, logger->id); 483 ret = min(ret, remaining); 484 remaining -= ret; 485 cp += ret; 486 c = ','; 487 } 488 489 if (logger_list->tail) { 490 ret = snprintf(cp, remaining, " tail=%u", logger_list->tail); 491 ret = min(ret, remaining); 492 remaining -= ret; 493 cp += ret; 494 } 495 496 if (logger_list->pid) { 497 ret = snprintf(cp, remaining, " pid=%u", logger_list->pid); 498 ret = min(ret, remaining); 499 remaining -= ret; 500 cp += ret; 501 } 502 503 if (logger_list->mode & O_NONBLOCK) { 504 /* Deal with an unresponsive logd */ 505 sigaction(SIGALRM, &ignore, &old_sigaction); 506 old_alarm = alarm(30); 507 } 508 ret = write(sock, buffer, cp - buffer); 509 e = errno; 510 if (logger_list->mode & O_NONBLOCK) { 511 if (e == EINTR) { 512 e = ETIMEDOUT; 513 } 514 alarm(old_alarm); 515 sigaction(SIGALRM, &old_sigaction, NULL); 516 } 517 518 if (ret <= 0) { 519 close(sock); 520 if ((ret == -1) && e) { 521 return -e; 522 } 523 if (ret == 0) { 524 return -EIO; 525 } 526 return ret; 527 } 528 529 logger_list->sock = sock; 530 } 531 532 ret = 0; 533 while(1) { 534 memset(log_msg, 0, sizeof(*log_msg)); 535 536 if (logger_list->mode & O_NONBLOCK) { 537 /* particularily useful if tombstone is reporting for logd */ 538 sigaction(SIGALRM, &ignore, &old_sigaction); 539 old_alarm = alarm(30); 540 } 541 /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */ 542 ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0); 543 e = errno; 544 if (logger_list->mode & O_NONBLOCK) { 545 if ((ret == 0) || (e == EINTR)) { 546 e = EAGAIN; 547 ret = -1; 548 } 549 alarm(old_alarm); 550 sigaction(SIGALRM, &old_sigaction, NULL); 551 } 552 553 if (ret <= 0) { 554 if ((ret == -1) && e) { 555 return -e; 556 } 557 return ret; 558 } 559 560 logger_for_each(logger, logger_list) { 561 if (log_msg->entry.lid == logger->id) { 562 return ret; 563 } 564 } 565 } 566 /* NOTREACH */ 567 return ret; 568} 569 570/* Close all the logs */ 571void android_logger_list_free(struct logger_list *logger_list) 572{ 573 if (logger_list == NULL) { 574 return; 575 } 576 577 while (!list_empty(&logger_list->node)) { 578 struct listnode *node = list_head(&logger_list->node); 579 struct logger *logger = node_to_item(node, struct logger, node); 580 android_logger_free(logger); 581 } 582 583 if (logger_list->sock >= 0) { 584 close (logger_list->sock); 585 } 586 587 free(logger_list); 588} 589