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