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 <stdlib.h> 24#include <string.h> 25#include <sys/types.h> 26#include <time.h> 27 28#include <log/log.h> 29#include <log/logger.h> 30 31#include <private/android_filesystem_config.h> 32#include <private/android_logger.h> 33 34#include "config_write.h" 35#include "log_portability.h" 36#include "logger.h" 37 38static int pmsgOpen(); 39static void pmsgClose(); 40static int pmsgAvailable(log_id_t logId); 41static int pmsgWrite(log_id_t logId, struct timespec *ts, 42 struct iovec *vec, size_t nr); 43 44LIBLOG_HIDDEN struct android_log_transport_write pmsgLoggerWrite = { 45 .node = { &pmsgLoggerWrite.node, &pmsgLoggerWrite.node }, 46 .context.fd = -1, 47 .name = "pmsg", 48 .available = pmsgAvailable, 49 .open = pmsgOpen, 50 .close = pmsgClose, 51 .write = pmsgWrite, 52}; 53 54static int pmsgOpen() 55{ 56 if (pmsgLoggerWrite.context.fd < 0) { 57 pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC)); 58 } 59 60 return pmsgLoggerWrite.context.fd; 61} 62 63static void pmsgClose() 64{ 65 if (pmsgLoggerWrite.context.fd >= 0) { 66 close(pmsgLoggerWrite.context.fd); 67 pmsgLoggerWrite.context.fd = -1; 68 } 69} 70 71static int pmsgAvailable(log_id_t logId) 72{ 73 if (logId > LOG_ID_SECURITY) { 74 return -EINVAL; 75 } 76 if ((logId != LOG_ID_SECURITY) && 77 (logId != LOG_ID_EVENTS) && 78 !__android_log_is_debuggable()) { 79 return -EINVAL; 80 } 81 if (pmsgLoggerWrite.context.fd < 0) { 82 if (access("/dev/pmsg0", W_OK) == 0) { 83 return 0; 84 } 85 return -EBADF; 86 } 87 return 1; 88} 89 90/* 91 * Extract a 4-byte value from a byte stream. 92 */ 93static inline uint32_t get4LE(const uint8_t* src) 94{ 95 return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); 96} 97 98static int pmsgWrite(log_id_t logId, struct timespec *ts, 99 struct iovec *vec, size_t nr) 100{ 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 (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(writev(pmsgLoggerWrite.context.fd, newVec, i)); 173 if (ret < 0) { 174 ret = errno ? -errno : -ENOTCONN; 175 } 176 177 if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) { 178 ret -= sizeof(header) - sizeof(pmsgHeader); 179 } 180 181 return ret; 182} 183 184/* 185 * Virtual pmsg filesystem 186 * 187 * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a 188 * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the 189 * file. 190 * 191 * Will hijack the header.realtime.tv_nsec field for a sequence number in usec. 192 */ 193 194static inline const char *strnrchr(const char *buf, size_t len, char c) { 195 const char *cp = buf + len; 196 while ((--cp > buf) && (*cp != c)); 197 if (cp <= buf) { 198 return buf + len; 199 } 200 return cp; 201} 202 203/* Write a buffer as filename references (tag = <basedir>:<basename>) */ 204LIBLOG_ABI_PRIVATE ssize_t __android_log_pmsg_file_write( 205 log_id_t logId, 206 char prio, 207 const char *filename, 208 const char *buf, size_t len) { 209 int fd; 210 size_t length, packet_len; 211 const char *tag; 212 char *cp, *slash; 213 struct timespec ts; 214 struct iovec vec[3]; 215 216 /* Make sure the logId value is not a bad idea */ 217 if ((logId == LOG_ID_KERNEL) || /* Verbotten */ 218 (logId == LOG_ID_EVENTS) || /* Do not support binary content */ 219 (logId == LOG_ID_SECURITY) || /* Bad idea to allow */ 220 ((unsigned)logId >= 32)) { /* fit within logMask on arch32 */ 221 return -EINVAL; 222 } 223 224 clock_gettime(android_log_clockid(), &ts); 225 226 cp = strdup(filename); 227 if (!cp) { 228 return -ENOMEM; 229 } 230 231 fd = pmsgLoggerWrite.context.fd; 232 if (fd < 0) { 233 __android_log_lock(); 234 fd = pmsgOpen(); 235 __android_log_unlock(); 236 if (fd < 0) { 237 return -EBADF; 238 } 239 } 240 241 tag = cp; 242 slash = strrchr(cp, '/'); 243 if (slash) { 244 *slash = ':'; 245 slash = strrchr(cp, '/'); 246 if (slash) { 247 tag = slash + 1; 248 } 249 } 250 251 length = strlen(tag) + 1; 252 packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length; 253 254 vec[0].iov_base = &prio; 255 vec[0].iov_len = sizeof(char); 256 vec[1].iov_base = (unsigned char *)tag; 257 vec[1].iov_len = length; 258 259 for (ts.tv_nsec = 0, length = len; 260 length; 261 ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) { 262 ssize_t ret; 263 size_t transfer; 264 265 if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >= 266 ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) { 267 len -= length; 268 break; 269 } 270 271 transfer = length; 272 if (transfer > packet_len) { 273 transfer = strnrchr(buf, packet_len - 1, '\n') - buf; 274 if ((transfer < length) && (buf[transfer] == '\n')) { 275 ++transfer; 276 } 277 } 278 279 vec[2].iov_base = (unsigned char *)buf; 280 vec[2].iov_len = transfer; 281 282 ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0])); 283 284 if (ret <= 0) { 285 free(cp); 286 return ret; 287 } 288 length -= transfer; 289 buf += transfer; 290 } 291 free(cp); 292 return len; 293} 294