blob: 7a89e5d5429c951c9bcee3d461acd871ffdf398f [file] [log] [blame]
Mark Salyzyn018a96d2016-03-01 13:45:42 -08001/*
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));
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 (pmsgLoggerWrite.context.fd < 0) {
77 if (access("/dev/pmsg0", W_OK) == 0) {
78 return 0;
79 }
80 return -EBADF;
81 }
82 return 1;
83}
84
85static int pmsgWrite(log_id_t logId, struct timespec *ts,
86 struct iovec *vec, size_t nr)
87{
88 static const unsigned headerLength = 2;
89 struct iovec newVec[nr + headerLength];
90 android_log_header_t header;
91 android_pmsg_log_header_t pmsgHeader;
92 size_t i, payloadSize;
93 ssize_t ret;
94
95 if (pmsgLoggerWrite.context.fd < 0) {
96 return -EBADF;
97 }
98
99 /*
100 * struct {
101 * // what we provide to pstore
102 * android_pmsg_log_header_t pmsgHeader;
103 * // what we provide to file
104 * android_log_header_t header;
105 * // caller provides
106 * union {
107 * struct {
108 * char prio;
109 * char payload[];
110 * } string;
111 * struct {
112 * uint32_t tag
113 * char payload[];
114 * } binary;
115 * };
116 * };
117 */
118
119 pmsgHeader.magic = LOGGER_MAGIC;
120 pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
121 pmsgHeader.uid = __android_log_uid();
122 pmsgHeader.pid = __android_log_pid();
123
124 header.id = logId;
125 header.tid = gettid();
126 header.realtime.tv_sec = ts->tv_sec;
127 header.realtime.tv_nsec = ts->tv_nsec;
128
129 newVec[0].iov_base = (unsigned char *)&pmsgHeader;
130 newVec[0].iov_len = sizeof(pmsgHeader);
131 newVec[1].iov_base = (unsigned char *)&header;
132 newVec[1].iov_len = sizeof(header);
133
134 for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
135 newVec[i].iov_base = vec[i - headerLength].iov_base;
136 payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
137
138 if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
139 newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
140 if (newVec[i].iov_len) {
141 ++i;
142 }
143 payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
144 break;
145 }
146 }
147 pmsgHeader.len += payloadSize;
148
149 ret = TEMP_FAILURE_RETRY(writev(pmsgLoggerWrite.context.fd, newVec, i));
150 if (ret < 0) {
151 ret = errno ? -errno : -ENOTCONN;
152 }
153
154 if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
155 ret -= sizeof(header) - sizeof(pmsgHeader);
156 }
157
158 return ret;
159}