1/* 2 * Copyright (C) 2007-2016 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/* 18 * pmsg write handler 19 */ 20 21#include <errno.h> 22#include <fcntl.h> 23#include <stdbool.h> 24#include <stdlib.h> 25#include <string.h> 26#include <sys/types.h> 27#include <time.h> 28 29#include <log/log_properties.h> 30#include <private/android_filesystem_config.h> 31#include <private/android_logger.h> 32 33#include "config_write.h" 34#include "log_portability.h" 35#include "logger.h" 36 37static int pmsgOpen(); 38static void pmsgClose(); 39static int pmsgAvailable(log_id_t logId); 40static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, 41 size_t nr); 42 43LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = { 44 .node = { &pmsgLoggerWrite.node, &pmsgLoggerWrite.node }, 45 .context.fd = -1, 46 .name = "pmsg", 47 .available = pmsgAvailable, 48 .open = pmsgOpen, 49 .close = pmsgClose, 50 .write = pmsgWrite, 51}; 52 53static int pmsgOpen() { 54 int fd = atomic_load(&pmsgLoggerWrite.context.fd); 55 if (fd < 0) { 56 int i; 57 58 fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC)); 59 i = atomic_exchange(&pmsgLoggerWrite.context.fd, fd); 60 if ((i >= 0) && (i != fd)) { 61 close(i); 62 } 63 } 64 65 return fd; 66} 67 68static void pmsgClose() { 69 int fd = atomic_exchange(&pmsgLoggerWrite.context.fd, -1); 70 if (fd >= 0) { 71 close(fd); 72 } 73} 74 75static int pmsgAvailable(log_id_t logId) { 76 if (logId > LOG_ID_SECURITY) { 77 return -EINVAL; 78 } 79 if ((logId != LOG_ID_SECURITY) && (logId != LOG_ID_EVENTS) && 80 !__android_log_is_debuggable()) { 81 return -EINVAL; 82 } 83 if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) { 84 if (access("/dev/pmsg0", W_OK) == 0) { 85 return 0; 86 } 87 return -EBADF; 88 } 89 return 1; 90} 91 92/* 93 * Extract a 4-byte value from a byte stream. 94 */ 95static inline uint32_t get4LE(const uint8_t* src) { 96 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); 97} 98 99static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, 100 size_t nr) { 101 static const unsigned headerLength = 2; 102 struct iovec newVec[nr + headerLength]; 103 android_log_header_t header; 104 android_pmsg_log_header_t pmsgHeader; 105 size_t i, payloadSize; 106 ssize_t ret; 107 108 if ((logId == LOG_ID_EVENTS) && !__android_log_is_debuggable()) { 109 if (vec[0].iov_len < 4) { 110 return -EINVAL; 111 } 112 113 if (SNET_EVENT_LOG_TAG != get4LE(vec[0].iov_base)) { 114 return -EPERM; 115 } 116 } 117 118 if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) { 119 return -EBADF; 120 } 121 122 /* 123 * struct { 124 * // what we provide to pstore 125 * android_pmsg_log_header_t pmsgHeader; 126 * // what we provide to file 127 * android_log_header_t header; 128 * // caller provides 129 * union { 130 * struct { 131 * char prio; 132 * char payload[]; 133 * } string; 134 * struct { 135 * uint32_t tag 136 * char payload[]; 137 * } binary; 138 * }; 139 * }; 140 */ 141 142 pmsgHeader.magic = LOGGER_MAGIC; 143 pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header); 144 pmsgHeader.uid = __android_log_uid(); 145 pmsgHeader.pid = getpid(); 146 147 header.id = logId; 148 header.tid = gettid(); 149 header.realtime.tv_sec = ts->tv_sec; 150 header.realtime.tv_nsec = ts->tv_nsec; 151 152 newVec[0].iov_base = (unsigned char*)&pmsgHeader; 153 newVec[0].iov_len = sizeof(pmsgHeader); 154 newVec[1].iov_base = (unsigned char*)&header; 155 newVec[1].iov_len = sizeof(header); 156 157 for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) { 158 newVec[i].iov_base = vec[i - headerLength].iov_base; 159 payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len; 160 161 if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) { 162 newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD; 163 if (newVec[i].iov_len) { 164 ++i; 165 } 166 payloadSize = LOGGER_ENTRY_MAX_PAYLOAD; 167 break; 168 } 169 } 170 pmsgHeader.len += payloadSize; 171 172 ret = TEMP_FAILURE_RETRY( 173 writev(atomic_load(&pmsgLoggerWrite.context.fd), newVec, i)); 174 if (ret < 0) { 175 ret = errno ? -errno : -ENOTCONN; 176 } 177 178 if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) { 179 ret -= sizeof(header) - sizeof(pmsgHeader); 180 } 181 182 return ret; 183} 184 185/* 186 * Virtual pmsg filesystem 187 * 188 * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a 189 * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the 190 * file. 191 * 192 * Will hijack the header.realtime.tv_nsec field for a sequence number in usec. 193 */ 194 195static inline const char* strnrchr(const char* buf, size_t len, char c) { 196 const char* cp = buf + len; 197 while ((--cp > buf) && (*cp != c)) 198 ; 199 if (cp <= buf) { 200 return buf + len; 201 } 202 return cp; 203} 204 205/* Write a buffer as filename references (tag = <basedir>:<basename>) */ 206LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_write(log_id_t logId, 207 char prio, 208 const char* filename, 209 const char* buf, 210 size_t len) { 211 bool weOpened; 212 size_t length, packet_len; 213 const char* tag; 214 char *cp, *slash; 215 struct timespec ts; 216 struct iovec vec[3]; 217 218 /* Make sure the logId value is not a bad idea */ 219 if ((logId == LOG_ID_KERNEL) || /* Verbotten */ 220 (logId == LOG_ID_EVENTS) || /* Do not support binary content */ 221 (logId == LOG_ID_SECURITY) || /* Bad idea to allow */ 222 ((unsigned)logId >= 32)) { /* fit within logMask on arch32 */ 223 return -EINVAL; 224 } 225 226 clock_gettime(android_log_clockid(), &ts); 227 228 cp = strdup(filename); 229 if (!cp) { 230 return -ENOMEM; 231 } 232 233 tag = cp; 234 slash = strrchr(cp, '/'); 235 if (slash) { 236 *slash = ':'; 237 slash = strrchr(cp, '/'); 238 if (slash) { 239 tag = slash + 1; 240 } 241 } 242 243 length = strlen(tag) + 1; 244 packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length; 245 246 vec[0].iov_base = &prio; 247 vec[0].iov_len = sizeof(char); 248 vec[1].iov_base = (unsigned char*)tag; 249 vec[1].iov_len = length; 250 251 weOpened = false; 252 for (ts.tv_nsec = 0, length = len; length; 253 ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) { 254 ssize_t ret; 255 size_t transfer; 256 257 if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >= 258 ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) { 259 len -= length; 260 break; 261 } 262 263 transfer = length; 264 if (transfer > packet_len) { 265 transfer = strnrchr(buf, packet_len - 1, '\n') - buf; 266 if ((transfer < length) && (buf[transfer] == '\n')) { 267 ++transfer; 268 } 269 } 270 271 vec[2].iov_base = (unsigned char*)buf; 272 vec[2].iov_len = transfer; 273 274 if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) { 275 if (!weOpened) { /* Impossible for weOpened = true here */ 276 __android_log_lock(); 277 } 278 weOpened = atomic_load(&pmsgLoggerWrite.context.fd) < 0; 279 if (!weOpened) { 280 __android_log_unlock(); 281 } else if (pmsgOpen() < 0) { 282 __android_log_unlock(); 283 free(cp); 284 return -EBADF; 285 } 286 } 287 288 ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0])); 289 290 if (ret <= 0) { 291 if (weOpened) { 292 pmsgClose(); 293 __android_log_unlock(); 294 } 295 free(cp); 296 return ret ? ret : (len - length); 297 } 298 length -= transfer; 299 buf += transfer; 300 } 301 if (weOpened) { 302 pmsgClose(); 303 __android_log_unlock(); 304 } 305 free(cp); 306 return len; 307} 308