1*598139dcSAndroid Build Coastguard Worker /*
2*598139dcSAndroid Build Coastguard Worker * Copyright (C) 2007-2016 The Android Open Source Project
3*598139dcSAndroid Build Coastguard Worker *
4*598139dcSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*598139dcSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*598139dcSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*598139dcSAndroid Build Coastguard Worker *
8*598139dcSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*598139dcSAndroid Build Coastguard Worker *
10*598139dcSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*598139dcSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*598139dcSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*598139dcSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*598139dcSAndroid Build Coastguard Worker * limitations under the License.
15*598139dcSAndroid Build Coastguard Worker */
16*598139dcSAndroid Build Coastguard Worker
17*598139dcSAndroid Build Coastguard Worker #include "pmsg_writer.h"
18*598139dcSAndroid Build Coastguard Worker
19*598139dcSAndroid Build Coastguard Worker #include <errno.h>
20*598139dcSAndroid Build Coastguard Worker #include <fcntl.h>
21*598139dcSAndroid Build Coastguard Worker #include <stdlib.h>
22*598139dcSAndroid Build Coastguard Worker #include <string.h>
23*598139dcSAndroid Build Coastguard Worker #include <sys/types.h>
24*598139dcSAndroid Build Coastguard Worker #include <time.h>
25*598139dcSAndroid Build Coastguard Worker
26*598139dcSAndroid Build Coastguard Worker #include <log/log_properties.h>
27*598139dcSAndroid Build Coastguard Worker #include <private/android_logger.h>
28*598139dcSAndroid Build Coastguard Worker
29*598139dcSAndroid Build Coastguard Worker #include "logger.h"
30*598139dcSAndroid Build Coastguard Worker #include "uio.h"
31*598139dcSAndroid Build Coastguard Worker
32*598139dcSAndroid Build Coastguard Worker static atomic_int pmsg_fd;
33*598139dcSAndroid Build Coastguard Worker
GetPmsgFd()34*598139dcSAndroid Build Coastguard Worker static void GetPmsgFd() {
35*598139dcSAndroid Build Coastguard Worker // Note if open() fails and returns -1, that value is stored into pmsg_fd as an indication that
36*598139dcSAndroid Build Coastguard Worker // pmsg is not available and open() should not be retried.
37*598139dcSAndroid Build Coastguard Worker if (pmsg_fd != 0) {
38*598139dcSAndroid Build Coastguard Worker return;
39*598139dcSAndroid Build Coastguard Worker }
40*598139dcSAndroid Build Coastguard Worker
41*598139dcSAndroid Build Coastguard Worker int new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
42*598139dcSAndroid Build Coastguard Worker
43*598139dcSAndroid Build Coastguard Worker // Unlikely that new_fd is 0, but that is synonymous with our uninitialized value, and we'd prefer
44*598139dcSAndroid Build Coastguard Worker // STDIN_FILENO != stdin, so we call open() to get a new fd value in this case.
45*598139dcSAndroid Build Coastguard Worker if (new_fd == 0) {
46*598139dcSAndroid Build Coastguard Worker new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
47*598139dcSAndroid Build Coastguard Worker close(0);
48*598139dcSAndroid Build Coastguard Worker }
49*598139dcSAndroid Build Coastguard Worker
50*598139dcSAndroid Build Coastguard Worker // pmsg_fd should only be opened once. If we see that pmsg_fd is uninitialized, we open
51*598139dcSAndroid Build Coastguard Worker // "/dev/pmsg0" then attempt to compare/exchange it into pmsg_fd. If the compare/exchange was
52*598139dcSAndroid Build Coastguard Worker // successful, then that will be the fd used for the duration of the program, otherwise a
53*598139dcSAndroid Build Coastguard Worker // different thread has already opened and written the fd to the atomic, so close the new fd and
54*598139dcSAndroid Build Coastguard Worker // return.
55*598139dcSAndroid Build Coastguard Worker int uninitialized_value = 0;
56*598139dcSAndroid Build Coastguard Worker if (!pmsg_fd.compare_exchange_strong(uninitialized_value, new_fd)) {
57*598139dcSAndroid Build Coastguard Worker if (new_fd != -1) {
58*598139dcSAndroid Build Coastguard Worker close(new_fd);
59*598139dcSAndroid Build Coastguard Worker }
60*598139dcSAndroid Build Coastguard Worker }
61*598139dcSAndroid Build Coastguard Worker }
62*598139dcSAndroid Build Coastguard Worker
PmsgClose()63*598139dcSAndroid Build Coastguard Worker void PmsgClose() {
64*598139dcSAndroid Build Coastguard Worker if (pmsg_fd > 0) {
65*598139dcSAndroid Build Coastguard Worker close(pmsg_fd);
66*598139dcSAndroid Build Coastguard Worker }
67*598139dcSAndroid Build Coastguard Worker pmsg_fd = 0;
68*598139dcSAndroid Build Coastguard Worker }
69*598139dcSAndroid Build Coastguard Worker
PmsgWrite(log_id_t logId,struct timespec * ts,struct iovec * vec,size_t nr)70*598139dcSAndroid Build Coastguard Worker int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
71*598139dcSAndroid Build Coastguard Worker static const unsigned headerLength = 2;
72*598139dcSAndroid Build Coastguard Worker struct iovec newVec[nr + headerLength];
73*598139dcSAndroid Build Coastguard Worker android_log_header_t header;
74*598139dcSAndroid Build Coastguard Worker android_pmsg_log_header_t pmsgHeader;
75*598139dcSAndroid Build Coastguard Worker size_t i, payloadSize;
76*598139dcSAndroid Build Coastguard Worker ssize_t ret;
77*598139dcSAndroid Build Coastguard Worker
78*598139dcSAndroid Build Coastguard Worker if (!ANDROID_DEBUGGABLE) {
79*598139dcSAndroid Build Coastguard Worker if (logId != LOG_ID_EVENTS && logId != LOG_ID_SECURITY) {
80*598139dcSAndroid Build Coastguard Worker return -1;
81*598139dcSAndroid Build Coastguard Worker }
82*598139dcSAndroid Build Coastguard Worker
83*598139dcSAndroid Build Coastguard Worker if (logId == LOG_ID_EVENTS) {
84*598139dcSAndroid Build Coastguard Worker if (vec[0].iov_len < 4) {
85*598139dcSAndroid Build Coastguard Worker return -EINVAL;
86*598139dcSAndroid Build Coastguard Worker }
87*598139dcSAndroid Build Coastguard Worker
88*598139dcSAndroid Build Coastguard Worker if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
89*598139dcSAndroid Build Coastguard Worker return -EPERM;
90*598139dcSAndroid Build Coastguard Worker }
91*598139dcSAndroid Build Coastguard Worker }
92*598139dcSAndroid Build Coastguard Worker }
93*598139dcSAndroid Build Coastguard Worker
94*598139dcSAndroid Build Coastguard Worker GetPmsgFd();
95*598139dcSAndroid Build Coastguard Worker
96*598139dcSAndroid Build Coastguard Worker if (pmsg_fd <= 0) {
97*598139dcSAndroid Build Coastguard Worker return -EBADF;
98*598139dcSAndroid Build Coastguard Worker }
99*598139dcSAndroid Build Coastguard Worker
100*598139dcSAndroid Build Coastguard Worker /*
101*598139dcSAndroid Build Coastguard Worker * struct {
102*598139dcSAndroid Build Coastguard Worker * // what we provide to pstore
103*598139dcSAndroid Build Coastguard Worker * android_pmsg_log_header_t pmsgHeader;
104*598139dcSAndroid Build Coastguard Worker * // what we provide to file
105*598139dcSAndroid Build Coastguard Worker * android_log_header_t header;
106*598139dcSAndroid Build Coastguard Worker * // caller provides
107*598139dcSAndroid Build Coastguard Worker * union {
108*598139dcSAndroid Build Coastguard Worker * struct {
109*598139dcSAndroid Build Coastguard Worker * char prio;
110*598139dcSAndroid Build Coastguard Worker * char payload[];
111*598139dcSAndroid Build Coastguard Worker * } string;
112*598139dcSAndroid Build Coastguard Worker * struct {
113*598139dcSAndroid Build Coastguard Worker * uint32_t tag
114*598139dcSAndroid Build Coastguard Worker * char payload[];
115*598139dcSAndroid Build Coastguard Worker * } binary;
116*598139dcSAndroid Build Coastguard Worker * };
117*598139dcSAndroid Build Coastguard Worker * };
118*598139dcSAndroid Build Coastguard Worker */
119*598139dcSAndroid Build Coastguard Worker
120*598139dcSAndroid Build Coastguard Worker pmsgHeader.magic = LOGGER_MAGIC;
121*598139dcSAndroid Build Coastguard Worker pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
122*598139dcSAndroid Build Coastguard Worker pmsgHeader.uid = getuid();
123*598139dcSAndroid Build Coastguard Worker pmsgHeader.pid = getpid();
124*598139dcSAndroid Build Coastguard Worker
125*598139dcSAndroid Build Coastguard Worker header.id = logId;
126*598139dcSAndroid Build Coastguard Worker header.tid = gettid();
127*598139dcSAndroid Build Coastguard Worker header.realtime.tv_sec = ts->tv_sec;
128*598139dcSAndroid Build Coastguard Worker header.realtime.tv_nsec = ts->tv_nsec;
129*598139dcSAndroid Build Coastguard Worker
130*598139dcSAndroid Build Coastguard Worker newVec[0].iov_base = (unsigned char*)&pmsgHeader;
131*598139dcSAndroid Build Coastguard Worker newVec[0].iov_len = sizeof(pmsgHeader);
132*598139dcSAndroid Build Coastguard Worker newVec[1].iov_base = (unsigned char*)&header;
133*598139dcSAndroid Build Coastguard Worker newVec[1].iov_len = sizeof(header);
134*598139dcSAndroid Build Coastguard Worker
135*598139dcSAndroid Build Coastguard Worker for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
136*598139dcSAndroid Build Coastguard Worker newVec[i].iov_base = vec[i - headerLength].iov_base;
137*598139dcSAndroid Build Coastguard Worker payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
138*598139dcSAndroid Build Coastguard Worker
139*598139dcSAndroid Build Coastguard Worker if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
140*598139dcSAndroid Build Coastguard Worker newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
141*598139dcSAndroid Build Coastguard Worker if (newVec[i].iov_len) {
142*598139dcSAndroid Build Coastguard Worker ++i;
143*598139dcSAndroid Build Coastguard Worker }
144*598139dcSAndroid Build Coastguard Worker payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
145*598139dcSAndroid Build Coastguard Worker break;
146*598139dcSAndroid Build Coastguard Worker }
147*598139dcSAndroid Build Coastguard Worker }
148*598139dcSAndroid Build Coastguard Worker pmsgHeader.len += payloadSize;
149*598139dcSAndroid Build Coastguard Worker
150*598139dcSAndroid Build Coastguard Worker ret = TEMP_FAILURE_RETRY(writev(pmsg_fd, newVec, i));
151*598139dcSAndroid Build Coastguard Worker if (ret < 0) {
152*598139dcSAndroid Build Coastguard Worker ret = errno ? -errno : -ENOTCONN;
153*598139dcSAndroid Build Coastguard Worker }
154*598139dcSAndroid Build Coastguard Worker
155*598139dcSAndroid Build Coastguard Worker if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
156*598139dcSAndroid Build Coastguard Worker ret -= sizeof(header) - sizeof(pmsgHeader);
157*598139dcSAndroid Build Coastguard Worker }
158*598139dcSAndroid Build Coastguard Worker
159*598139dcSAndroid Build Coastguard Worker return ret;
160*598139dcSAndroid Build Coastguard Worker }
161*598139dcSAndroid Build Coastguard Worker
162*598139dcSAndroid Build Coastguard Worker /*
163*598139dcSAndroid Build Coastguard Worker * Virtual pmsg filesystem
164*598139dcSAndroid Build Coastguard Worker *
165*598139dcSAndroid Build Coastguard Worker * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a
166*598139dcSAndroid Build Coastguard Worker * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the
167*598139dcSAndroid Build Coastguard Worker * file.
168*598139dcSAndroid Build Coastguard Worker *
169*598139dcSAndroid Build Coastguard Worker * Will hijack the header.realtime.tv_nsec field for a sequence number in usec.
170*598139dcSAndroid Build Coastguard Worker */
171*598139dcSAndroid Build Coastguard Worker
strnrchr(const char * buf,size_t len,char c)172*598139dcSAndroid Build Coastguard Worker static inline const char* strnrchr(const char* buf, size_t len, char c) {
173*598139dcSAndroid Build Coastguard Worker const char* cp = buf + len;
174*598139dcSAndroid Build Coastguard Worker while ((--cp > buf) && (*cp != c))
175*598139dcSAndroid Build Coastguard Worker ;
176*598139dcSAndroid Build Coastguard Worker if (cp <= buf) {
177*598139dcSAndroid Build Coastguard Worker return buf + len;
178*598139dcSAndroid Build Coastguard Worker }
179*598139dcSAndroid Build Coastguard Worker return cp;
180*598139dcSAndroid Build Coastguard Worker }
181*598139dcSAndroid Build Coastguard Worker
182*598139dcSAndroid Build Coastguard Worker /* Write a buffer as filename references (tag = <basedir>:<basename>) */
__android_log_pmsg_file_write(log_id_t logId,char prio,const char * filename,const char * buf,size_t len)183*598139dcSAndroid Build Coastguard Worker ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename,
184*598139dcSAndroid Build Coastguard Worker const char* buf, size_t len) {
185*598139dcSAndroid Build Coastguard Worker size_t length, packet_len;
186*598139dcSAndroid Build Coastguard Worker const char* tag;
187*598139dcSAndroid Build Coastguard Worker char *cp, *slash;
188*598139dcSAndroid Build Coastguard Worker struct timespec ts;
189*598139dcSAndroid Build Coastguard Worker struct iovec vec[3];
190*598139dcSAndroid Build Coastguard Worker
191*598139dcSAndroid Build Coastguard Worker /* Make sure the logId value is not a bad idea */
192*598139dcSAndroid Build Coastguard Worker if ((logId == LOG_ID_KERNEL) || /* Verbotten */
193*598139dcSAndroid Build Coastguard Worker (logId == LOG_ID_EVENTS) || /* Do not support binary content */
194*598139dcSAndroid Build Coastguard Worker (logId == LOG_ID_SECURITY) || /* Bad idea to allow */
195*598139dcSAndroid Build Coastguard Worker ((unsigned)logId >= 32)) { /* fit within logMask on arch32 */
196*598139dcSAndroid Build Coastguard Worker return -EINVAL;
197*598139dcSAndroid Build Coastguard Worker }
198*598139dcSAndroid Build Coastguard Worker
199*598139dcSAndroid Build Coastguard Worker clock_gettime(CLOCK_REALTIME, &ts);
200*598139dcSAndroid Build Coastguard Worker
201*598139dcSAndroid Build Coastguard Worker cp = strdup(filename);
202*598139dcSAndroid Build Coastguard Worker if (!cp) {
203*598139dcSAndroid Build Coastguard Worker return -ENOMEM;
204*598139dcSAndroid Build Coastguard Worker }
205*598139dcSAndroid Build Coastguard Worker
206*598139dcSAndroid Build Coastguard Worker tag = cp;
207*598139dcSAndroid Build Coastguard Worker slash = strrchr(cp, '/');
208*598139dcSAndroid Build Coastguard Worker if (slash) {
209*598139dcSAndroid Build Coastguard Worker *slash = ':';
210*598139dcSAndroid Build Coastguard Worker slash = strrchr(cp, '/');
211*598139dcSAndroid Build Coastguard Worker if (slash) {
212*598139dcSAndroid Build Coastguard Worker tag = slash + 1;
213*598139dcSAndroid Build Coastguard Worker }
214*598139dcSAndroid Build Coastguard Worker }
215*598139dcSAndroid Build Coastguard Worker
216*598139dcSAndroid Build Coastguard Worker length = strlen(tag) + 1;
217*598139dcSAndroid Build Coastguard Worker packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length;
218*598139dcSAndroid Build Coastguard Worker
219*598139dcSAndroid Build Coastguard Worker vec[0].iov_base = &prio;
220*598139dcSAndroid Build Coastguard Worker vec[0].iov_len = sizeof(char);
221*598139dcSAndroid Build Coastguard Worker vec[1].iov_base = (unsigned char*)tag;
222*598139dcSAndroid Build Coastguard Worker vec[1].iov_len = length;
223*598139dcSAndroid Build Coastguard Worker
224*598139dcSAndroid Build Coastguard Worker for (ts.tv_nsec = 0, length = len; length; ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
225*598139dcSAndroid Build Coastguard Worker ssize_t ret;
226*598139dcSAndroid Build Coastguard Worker size_t transfer;
227*598139dcSAndroid Build Coastguard Worker
228*598139dcSAndroid Build Coastguard Worker if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >= ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
229*598139dcSAndroid Build Coastguard Worker len -= length;
230*598139dcSAndroid Build Coastguard Worker break;
231*598139dcSAndroid Build Coastguard Worker }
232*598139dcSAndroid Build Coastguard Worker
233*598139dcSAndroid Build Coastguard Worker transfer = length;
234*598139dcSAndroid Build Coastguard Worker if (transfer > packet_len) {
235*598139dcSAndroid Build Coastguard Worker transfer = strnrchr(buf, packet_len - 1, '\n') - buf;
236*598139dcSAndroid Build Coastguard Worker if ((transfer < length) && (buf[transfer] == '\n')) {
237*598139dcSAndroid Build Coastguard Worker ++transfer;
238*598139dcSAndroid Build Coastguard Worker }
239*598139dcSAndroid Build Coastguard Worker }
240*598139dcSAndroid Build Coastguard Worker
241*598139dcSAndroid Build Coastguard Worker vec[2].iov_base = (unsigned char*)buf;
242*598139dcSAndroid Build Coastguard Worker vec[2].iov_len = transfer;
243*598139dcSAndroid Build Coastguard Worker
244*598139dcSAndroid Build Coastguard Worker ret = PmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
245*598139dcSAndroid Build Coastguard Worker
246*598139dcSAndroid Build Coastguard Worker if (ret <= 0) {
247*598139dcSAndroid Build Coastguard Worker free(cp);
248*598139dcSAndroid Build Coastguard Worker return ret ? ret : (len - length);
249*598139dcSAndroid Build Coastguard Worker }
250*598139dcSAndroid Build Coastguard Worker length -= transfer;
251*598139dcSAndroid Build Coastguard Worker buf += transfer;
252*598139dcSAndroid Build Coastguard Worker }
253*598139dcSAndroid Build Coastguard Worker free(cp);
254*598139dcSAndroid Build Coastguard Worker return len;
255*598139dcSAndroid Build Coastguard Worker }
256