15c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* 25c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * Copyright (C) 2010 The Android Open Source Project 35c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * All rights reserved. 45c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 55c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * Redistribution and use in source and binary forms, with or without 65c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * modification, are permitted provided that the following conditions 75c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * are met: 85c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * * Redistributions of source code must retain the above copyright 95c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * notice, this list of conditions and the following disclaimer. 105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * * Redistributions in binary form must reproduce the above copyright 115c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * notice, this list of conditions and the following disclaimer in 125c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the documentation and/or other materials provided with the 135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * distribution. 145c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 165c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 185c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 195c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 205c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * SUCH DAMAGE. 275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2918a206c81d9743481e364384affd43306911283dElliott Hughes#include <assert.h> 30870f165ceb3348d79499d40ce8b629f62a15ff2bMark Salyzyn#include <ctype.h> 31eababde2141c7128155200b213e45291cd876e46Elliott Hughes#include <errno.h> 320d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes#include <fcntl.h> 338f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes#include <pthread.h> 345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <stdarg.h> 35eababde2141c7128155200b213e45291cd876e46Elliott Hughes#include <stddef.h> 368f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes#include <stdlib.h> 375c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <string.h> 380d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes#include <sys/mman.h> 390336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn#include <sys/socket.h> 400336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn#include <sys/types.h> 410d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes#include <sys/uio.h> 420336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn#include <sys/un.h> 430336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn#include <time.h> 445c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include <unistd.h> 45eababde2141c7128155200b213e45291cd876e46Elliott Hughes 467a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris#include <android/set_abort_message.h> 477a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris#include <async_safe/log.h> 487a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 497a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris#include "private/CachedProperty.h" 508aecba7aa6b7f7b92f69c0d3febef59fdb135f87Elliott Hughes#include "private/ErrnoRestorer.h" 517a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris#include "private/ScopedPthreadMutexLocker.h" 527a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 530d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java. 540d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesenum AndroidEventLogType { 557a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris EVENT_TYPE_INT = 0, 567a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris EVENT_TYPE_LONG = 1, 577a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris EVENT_TYPE_STRING = 2, 587a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris EVENT_TYPE_LIST = 3, 597a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris EVENT_TYPE_FLOAT = 4, 6018a206c81d9743481e364384affd43306911283dElliott Hughes}; 615c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 620d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesstruct BufferOutputStream { 630d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes public: 6492476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris BufferOutputStream(char* buffer, size_t size) : total(0), pos_(buffer), avail_(size) { 6592476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris if (avail_ > 0) pos_[0] = '\0'; 660d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 6792476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris ~BufferOutputStream() = default; 680d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 690d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes void Send(const char* data, int len) { 7018a206c81d9743481e364384affd43306911283dElliott Hughes if (len < 0) { 710d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes len = strlen(data); 7218a206c81d9743481e364384affd43306911283dElliott Hughes } 73416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes total += len; 74416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes 7592476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris if (avail_ <= 1) { 7692476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris // No space to put anything else. 7792476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris return; 785c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 7992476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris 8092476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris if (static_cast<size_t>(len) >= avail_) { 8192476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris len = avail_ - 1; 8292476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris } 8392476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris memcpy(pos_, data, len); 8492476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris pos_ += len; 8592476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris pos_[0] = '\0'; 8692476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris avail_ -= len; 870d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 89416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes size_t total; 905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 910d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes private: 920d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes char* pos_; 9392476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris size_t avail_; 940d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes}; 955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 960d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesstruct FdOutputStream { 970d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes public: 987a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris explicit FdOutputStream(int fd) : total(0), fd_(fd) {} 995c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1000d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes void Send(const char* data, int len) { 1010d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes if (len < 0) { 1020d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes len = strlen(data); 1030d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 104416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes total += len; 105416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes 1060d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes while (len > 0) { 10792476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris ssize_t bytes = TEMP_FAILURE_RETRY(write(fd_, data, len)); 10892476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris if (bytes == -1) { 109416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes return; 1100d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 11192476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris data += bytes; 11292476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris len -= bytes; 1135c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 1141e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 1155c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 116416d7ddaff0946d480b6aa945a741b3eeaca5569Elliott Hughes size_t total; 1175c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1180d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes private: 1190d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes int fd_; 1200d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes}; 1215c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1225c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/*** formatted output implementation 1235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner ***/ 1245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1255c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Parse a decimal string from 'format + *ppos', 1265c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * return the value, and writes the new position past 1275c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * the decimal string in '*ppos' on exit. 1285c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * 1295c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner * NOTE: Does *not* handle a sign prefix. 1305c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner */ 1317a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisstatic unsigned parse_decimal(const char* format, int* ppos) { 1327a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris const char* p = format + *ppos; 1337a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris unsigned result = 0; 1345c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1357a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris for (;;) { 1367a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int ch = *p; 1377a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris unsigned d = static_cast<unsigned>(ch - '0'); 1385c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 1397a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (d >= 10U) { 1407a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 1415c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 1427a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 1437a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris result = result * 10 + d; 1447a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris p++; 1457a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 1467a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris *ppos = p - format; 1477a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris return result; 1485c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 1495c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 150eababde2141c7128155200b213e45291cd876e46Elliott Hughes// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes. 151eababde2141c7128155200b213e45291cd876e46Elliott Hughes// Assumes that buf_size > 0. 15241b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughesstatic void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) { 153eababde2141c7128155200b213e45291cd876e46Elliott Hughes char* p = buf; 154eababde2141c7128155200b213e45291cd876e46Elliott Hughes char* end = buf + buf_size - 1; 155eababde2141c7128155200b213e45291cd876e46Elliott Hughes 156eababde2141c7128155200b213e45291cd876e46Elliott Hughes // Generate digit string in reverse order. 157eababde2141c7128155200b213e45291cd876e46Elliott Hughes while (value) { 158eababde2141c7128155200b213e45291cd876e46Elliott Hughes unsigned d = value % base; 159eababde2141c7128155200b213e45291cd876e46Elliott Hughes value /= base; 160eababde2141c7128155200b213e45291cd876e46Elliott Hughes if (p != end) { 161eababde2141c7128155200b213e45291cd876e46Elliott Hughes char ch; 162eababde2141c7128155200b213e45291cd876e46Elliott Hughes if (d < 10) { 163eababde2141c7128155200b213e45291cd876e46Elliott Hughes ch = '0' + d; 164eababde2141c7128155200b213e45291cd876e46Elliott Hughes } else { 165eababde2141c7128155200b213e45291cd876e46Elliott Hughes ch = (caps ? 'A' : 'a') + (d - 10); 166eababde2141c7128155200b213e45291cd876e46Elliott Hughes } 167eababde2141c7128155200b213e45291cd876e46Elliott Hughes *p++ = ch; 1685c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 169eababde2141c7128155200b213e45291cd876e46Elliott Hughes } 1705c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 171eababde2141c7128155200b213e45291cd876e46Elliott Hughes // Special case for 0. 172eababde2141c7128155200b213e45291cd876e46Elliott Hughes if (p == buf) { 173eababde2141c7128155200b213e45291cd876e46Elliott Hughes if (p != end) { 174eababde2141c7128155200b213e45291cd876e46Elliott Hughes *p++ = '0'; 1755c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 176eababde2141c7128155200b213e45291cd876e46Elliott Hughes } 177eababde2141c7128155200b213e45291cd876e46Elliott Hughes *p = '\0'; 178eababde2141c7128155200b213e45291cd876e46Elliott Hughes 179eababde2141c7128155200b213e45291cd876e46Elliott Hughes // Reverse digit string in-place. 180eababde2141c7128155200b213e45291cd876e46Elliott Hughes size_t length = p - buf; 181eababde2141c7128155200b213e45291cd876e46Elliott Hughes for (size_t i = 0, j = length - 1; i < j; ++i, --j) { 182eababde2141c7128155200b213e45291cd876e46Elliott Hughes char ch = buf[i]; 183eababde2141c7128155200b213e45291cd876e46Elliott Hughes buf[i] = buf[j]; 184eababde2141c7128155200b213e45291cd876e46Elliott Hughes buf[j] = ch; 185eababde2141c7128155200b213e45291cd876e46Elliott Hughes } 1865c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 1875c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 18841b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughesstatic void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) { 18941b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes // Decode the conversion specifier. 19041b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o'); 19141b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes int base = 10; 19241b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes if (conversion == 'x' || conversion == 'X') { 19341b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes base = 16; 19441b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes } else if (conversion == 'o') { 19541b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes base = 8; 19641b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes } 19741b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes bool caps = (conversion == 'X'); 1985c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 19941b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes if (is_signed && static_cast<int64_t>(value) < 0) { 20041b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes buf[0] = '-'; 20141b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes buf += 1; 20241b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes buf_size -= 1; 20341b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes value = static_cast<uint64_t>(-static_cast<int64_t>(value)); 20441b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes } 20541b3179c9ef03ebb447cac7f5e8405dce399cb17Elliott Hughes format_unsigned(buf, buf_size, value, base, caps); 2065c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 2075c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2080d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughestemplate <typename Out> 2090d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesstatic void SendRepeat(Out& o, char ch, int count) { 2100d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes char pad[8]; 2110d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes memset(pad, ch, sizeof(pad)); 2120d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 2130d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes const int pad_size = static_cast<int>(sizeof(pad)); 2140d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes while (count > 0) { 2150d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes int avail = count; 2160d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes if (avail > pad_size) { 2170d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes avail = pad_size; 2180d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 2190d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes o.Send(pad, avail); 2200d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes count -= avail; 2210d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes } 2220d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 2230d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 2245c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner/* Perform formatted output to an output target 'o' */ 2250d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughestemplate <typename Out> 2260d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughesstatic void out_vformat(Out& o, const char* format, va_list args) { 2277a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int nn = 0; 2287a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 2297a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris for (;;) { 2307a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int mm; 2317a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int padZero = 0; 2327a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int padLeft = 0; 2337a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris char sign = '\0'; 2347a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int width = -1; 2357a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int prec = -1; 2367a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris size_t bytelen = sizeof(int); 2377a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int slen; 2387a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris char buffer[32]; /* temporary buffer used to format numbers */ 2397a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 2407a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris char c; 2417a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 2427a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* first, find all characters that are not 0 or '%' */ 2437a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* then send them to the output directly */ 2447a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris mm = nn; 2457a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris do { 2467a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris c = format[mm]; 2477a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (c == '\0' || c == '%') break; 2487a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris mm++; 2497a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } while (1); 2507a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 2517a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (mm > nn) { 2527a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris o.Send(format + nn, mm - nn); 2537a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris nn = mm; 2547a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 2557a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 2567a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* is this it ? then exit */ 2577a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (c == '\0') break; 2585c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2597a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* nope, we are at a '%' modifier */ 2607a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris nn++; // skip it 2617a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 2627a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* parse flags */ 2635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner for (;;) { 2647a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris c = format[nn++]; 2657a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (c == '\0') { /* single trailing '%' ? */ 2667a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris c = '%'; 2677a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris o.Send(&c, 1); 2687a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris return; 2697a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } else if (c == '0') { 2707a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris padZero = 1; 2717a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris continue; 2727a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } else if (c == '-') { 2737a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris padLeft = 1; 2747a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris continue; 2757a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } else if (c == ' ' || c == '+') { 2767a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris sign = c; 2777a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris continue; 2787a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 2797a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 2807a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 2815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2827a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* parse field width */ 2837a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if ((c >= '0' && c <= '9')) { 2847a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris nn--; 2857a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris width = static_cast<int>(parse_decimal(format, &nn)); 2867a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris c = format[nn++]; 2877a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 2885c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2897a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* parse precision */ 2907a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (c == '.') { 2917a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris prec = static_cast<int>(parse_decimal(format, &nn)); 2927a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris c = format[nn++]; 2937a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 2945c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 2957a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* length modifier */ 2967a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris switch (c) { 2977a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris case 'h': 2987a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris bytelen = sizeof(short); 2997a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (format[nn] == 'h') { 3007a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris bytelen = sizeof(char); 3017a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris nn += 1; 3027a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 3037a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris c = format[nn++]; 3047a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 3057a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris case 'l': 3067a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris bytelen = sizeof(long); 3077a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (format[nn] == 'l') { 3087a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris bytelen = sizeof(long long); 3097a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris nn += 1; 3105c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 3117a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris c = format[nn++]; 3127a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 3137a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris case 'z': 3147a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris bytelen = sizeof(size_t); 3157a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris c = format[nn++]; 3167a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 3177a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris case 't': 3187a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris bytelen = sizeof(ptrdiff_t); 3197a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris c = format[nn++]; 3207a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 3217a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris default:; 3227a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 3235c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3247a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* conversion specifier */ 3257a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris const char* str = buffer; 3267a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (c == 's') { 3277a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* string */ 3287a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris str = va_arg(args, const char*); 3297a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (str == NULL) { 3307a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris str = "(null)"; 3317a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 3327a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } else if (c == 'c') { 3337a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* character */ 3347a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* NOTE: char is promoted to int when passed through the stack */ 3357a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris buffer[0] = static_cast<char>(va_arg(args, int)); 3367a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris buffer[1] = '\0'; 3377a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } else if (c == 'p') { 3387a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris uint64_t value = reinterpret_cast<uintptr_t>(va_arg(args, void*)); 3397a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris buffer[0] = '0'; 3407a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris buffer[1] = 'x'; 3417a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x'); 3427a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') { 3437a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* integers - first read value from stack */ 3447a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris uint64_t value; 3457a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int is_signed = (c == 'd' || c == 'i' || c == 'o'); 3467a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 3477a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* NOTE: int8_t and int16_t are promoted to int when passed 3487a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris * through the stack 3497a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris */ 3507a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris switch (bytelen) { 3517a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris case 1: 3527a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris value = static_cast<uint8_t>(va_arg(args, int)); 3537a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 3547a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris case 2: 3557a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris value = static_cast<uint16_t>(va_arg(args, int)); 3567a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 3577a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris case 4: 3587a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris value = va_arg(args, uint32_t); 3597a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 3607a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris case 8: 3617a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris value = va_arg(args, uint64_t); 3627a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris break; 3635c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner default: 3647a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris return; /* should not happen */ 3657a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 3665c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3677a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* sign extension, if needed */ 3687a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (is_signed) { 3697a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int shift = 64 - 8 * bytelen; 3707a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift); 3717a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 3725c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3737a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* format the number properly into our buffer */ 3747a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris format_integer(buffer, sizeof(buffer), value, c); 3757a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } else if (c == '%') { 3767a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris buffer[0] = '%'; 3777a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris buffer[1] = '\0'; 3787a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } else { 3797a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris __assert(__FILE__, __LINE__, "conversion specifier unsupported"); 3807a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 3815c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3827a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris /* if we are here, 'str' points to the content that must be 3837a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris * outputted. handle padding and alignment now */ 3845c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3857a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris slen = strlen(str); 38618a206c81d9743481e364384affd43306911283dElliott Hughes 3877a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (sign != '\0' || prec != -1) { 3887a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris __assert(__FILE__, __LINE__, "sign/precision unsupported"); 3897a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 3905c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3917a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (slen < width && !padLeft) { 3927a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris char padChar = padZero ? '0' : ' '; 3937a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris SendRepeat(o, padChar, width - slen); 3947a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 3955c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner 3967a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris o.Send(str, slen); 3977a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris 3987a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris if (slen < width && padLeft) { 3997a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris char padChar = padZero ? '0' : ' '; 4007a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris SendRepeat(o, padChar, width - slen); 4015c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner } 4027a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris } 4035c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner} 4048f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes 4057a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisint async_safe_format_buffer_va_list(char* buffer, size_t buffer_size, const char* format, 4067a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris va_list args) { 407273991ceadac558ba3bca5238d81833a7b34cb2dJosh Gao BufferOutputStream os(buffer, buffer_size); 408273991ceadac558ba3bca5238d81833a7b34cb2dJosh Gao out_vformat(os, format, args); 409273991ceadac558ba3bca5238d81833a7b34cb2dJosh Gao return os.total; 410273991ceadac558ba3bca5238d81833a7b34cb2dJosh Gao} 411273991ceadac558ba3bca5238d81833a7b34cb2dJosh Gao 41292476407115f4431c5888c02cdb5f476b26e393aChristopher Ferrisint async_safe_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) { 41392476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris va_list args; 41492476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris va_start(args, format); 41592476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris int buffer_len = async_safe_format_buffer_va_list(buffer, buffer_size, format, args); 41692476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris va_end(args); 41792476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris return buffer_len; 41892476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris} 41992476407115f4431c5888c02cdb5f476b26e393aChristopher Ferris 4207a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisint async_safe_format_fd(int fd, const char* format, ...) { 4210d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes FdOutputStream os(fd); 4220d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_list args; 4230d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_start(args, format); 4240d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes out_vformat(os, format, args); 4250d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_end(args); 4260d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes return os.total; 4270d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 4280d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 4297a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisstatic int write_stderr(const char* tag, const char* msg) { 4300f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes iovec vec[4]; 4310f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[0].iov_base = const_cast<char*>(tag); 4320f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[0].iov_len = strlen(tag); 4330f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[1].iov_base = const_cast<char*>(": "); 4340f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[1].iov_len = 2; 4350f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[2].iov_base = const_cast<char*>(msg); 43642084a265329538a9e696e41971fb5d6abe3c14fElliott Hughes vec[2].iov_len = strlen(msg); 4370f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[3].iov_base = const_cast<char*>("\n"); 4380f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes vec[3].iov_len = 1; 4390f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes 44059bde2e8f4dacc059beb7269b86b276ec091ad57Josh Gao int result = TEMP_FAILURE_RETRY(writev(STDERR_FILENO, vec, 4)); 4410f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes return result; 4420f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes} 4430f395b7ba056ccec3915737cfece81ca2161e980Elliott Hughes 4447a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisstatic int open_log_socket() { 4450336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // ToDo: Ideally we want this to fail if the gid of the current 4460336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // process is AID_LOGD, but will have to wait until we have 4470336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // registered this in private/android_filesystem_config.h. We have 4480336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // found that all logd crashes thus far have had no problem stuffing 4490336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // the UNIX domain socket and moving on so not critical *today*. 4500336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4510f67d5ffa41ecc73f52e81f18f2a10229cc33de5Elliott Hughes int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)); 4520f67d5ffa41ecc73f52e81f18f2a10229cc33de5Elliott Hughes if (log_fd == -1) { 4530336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn return -1; 4540336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn } 4550336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4560336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn union { 4577a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris struct sockaddr addr; 4580336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn struct sockaddr_un addrUn; 4590336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn } u; 4600336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn memset(&u, 0, sizeof(u)); 4610336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn u.addrUn.sun_family = AF_UNIX; 4620336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path)); 4630336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4640336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) { 4650336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn close(log_fd); 4660336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn return -1; 4670336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn } 4680336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4690336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn return log_fd; 4700336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn} 4719fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn 4727a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisstruct log_time { // Wire format 4739fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn uint32_t tv_sec; 4749fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn uint32_t tv_nsec; 4759fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn}; 4760336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4777a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisint async_safe_write_log(int priority, const char* tag, const char* msg) { 4787a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int main_log_fd = open_log_socket(); 4790336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn if (main_log_fd == -1) { 4800336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn // Try stderr instead. 4817a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris return write_stderr(tag, msg); 4820336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn } 4830336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn 4848664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn iovec vec[6]; 485011101905d91b770893e8a2fb6c09552d1c63652Elliott Hughes char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN; 4860336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn vec[0].iov_base = &log_id; 4870336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn vec[0].iov_len = sizeof(log_id); 4888664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn uint16_t tid = gettid(); 4898664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[1].iov_base = &tid; 4908664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[1].iov_len = sizeof(tid); 4919fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn timespec ts; 49253dc9dd70155fd75af744cbebecc563658c69818Elliott Hughes clock_gettime(CLOCK_REALTIME, &ts); 4939fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn log_time realtime_ts; 4949fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn realtime_ts.tv_sec = ts.tv_sec; 4959fc76027f3e1e02193f3dd98063c55918e1b4066Mark Salyzyn realtime_ts.tv_nsec = ts.tv_nsec; 4968664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[2].iov_base = &realtime_ts; 4978664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[2].iov_len = sizeof(realtime_ts); 4988664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn 4998664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[3].iov_base = &priority; 5008664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[3].iov_len = 1; 5018664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[4].iov_base = const_cast<char*>(tag); 502aba6f712d46577c45a89fd0626dc251885d7989dElliott Hughes vec[4].iov_len = strlen(tag) + 1; 5038664be583a4556e5ca132288e989d307d2df92ceMark Salyzyn vec[5].iov_base = const_cast<char*>(msg); 504aba6f712d46577c45a89fd0626dc251885d7989dElliott Hughes vec[5].iov_len = strlen(msg) + 1; 5050d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 5060336e35368aa161f1fed04ccde39553db4740b97Mark Salyzyn int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0]))); 50717fc25d20f4d61f7fc3dfb3de095719ada89e38bNick Kralevich close(main_log_fd); 50817fc25d20f4d61f7fc3dfb3de095719ada89e38bNick Kralevich return result; 5090d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 5100d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 5117a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisint async_safe_format_log_va_list(int priority, const char* tag, const char* format, va_list args) { 5128aecba7aa6b7f7b92f69c0d3febef59fdb135f87Elliott Hughes ErrnoRestorer errno_restorer; 5130d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes char buffer[1024]; 5140d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes BufferOutputStream os(buffer, sizeof(buffer)); 5150d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes out_vformat(os, format, args); 5167a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris return async_safe_write_log(priority, tag, buffer); 5170d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 5180d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 5197a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisint async_safe_format_log(int priority, const char* tag, const char* format, ...) { 5200d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_list args; 5210d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_start(args, format); 5227a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris int result = async_safe_format_log_va_list(priority, tag, format, args); 5230d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes va_end(args); 5240d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes return result; 5250d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes} 5268f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes 5277a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferrisvoid async_safe_fatal_va_list(const char* prefix, const char* format, va_list args) { 528b83d6747facc5d819a0df0bcb8762477eecfd962Elliott Hughes char msg[1024]; 529b83d6747facc5d819a0df0bcb8762477eecfd962Elliott Hughes BufferOutputStream os(msg, sizeof(msg)); 5308f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes 531b83d6747facc5d819a0df0bcb8762477eecfd962Elliott Hughes if (prefix) { 532b83d6747facc5d819a0df0bcb8762477eecfd962Elliott Hughes os.Send(prefix, strlen(prefix)); 533b83d6747facc5d819a0df0bcb8762477eecfd962Elliott Hughes os.Send(": ", 2); 5348f2a5a0b40fc82126c691d5c30131d908772aab7Elliott Hughes } 5350d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 5360d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes out_vformat(os, format, args); 5370d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 5385e6cf05aab0a2fcc6177482606c1b1f2d958a7f9Elliott Hughes // Log to stderr for the benefit of "adb shell" users and gtests. 53997e31dedf056b07bcfcd46c49b60bf0798c60843Dan Albert struct iovec iov[2] = { 5407a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris {msg, os.total}, {const_cast<char*>("\n"), 1}, 54197e31dedf056b07bcfcd46c49b60bf0798c60843Dan Albert }; 54242084a265329538a9e696e41971fb5d6abe3c14fElliott Hughes TEMP_FAILURE_RETRY(writev(2, iov, 2)); 5430d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 5440d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed). 5457a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris async_safe_write_log(ANDROID_LOG_FATAL, "libc", msg); 5460d787c1fa18c6a1f29ef9840e28a68cf077be1deElliott Hughes 547ce6b1abbb1da797e716d8ec03da4e3b6304fd11dDan Albert android_set_abort_message(msg); 54861e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes} 54961e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes 550695713e931f0436aca56be9c0dacf2a5dd4e56e7Elliott Hughesvoid async_safe_fatal_no_abort(const char* fmt, ...) { 55161e699a133a4807fe878a6cb0d7190d7c96e21f8Elliott Hughes va_list args; 552b83d6747facc5d819a0df0bcb8762477eecfd962Elliott Hughes va_start(args, fmt); 5537a3681e5b6c39bc2b3b62031ca5941dbf7bc4e63Christopher Ferris async_safe_fatal_va_list(nullptr, fmt, args); 5542e3b7108b5b3d3f3a4a0fb369016e854bcf92212Elliott Hughes va_end(args); 5552e3b7108b5b3d3f3a4a0fb369016e854bcf92212Elliott Hughes} 556