xref: /aosp_15_r20/system/logging/liblog/pmsg_reader.cpp (revision 598139dc91b21518d67c408eaea2644226490971)
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_reader.h"
18*598139dcSAndroid Build Coastguard Worker 
19*598139dcSAndroid Build Coastguard Worker #include <ctype.h>
20*598139dcSAndroid Build Coastguard Worker #include <errno.h>
21*598139dcSAndroid Build Coastguard Worker #include <fcntl.h>
22*598139dcSAndroid Build Coastguard Worker #include <stdlib.h>
23*598139dcSAndroid Build Coastguard Worker #include <string.h>
24*598139dcSAndroid Build Coastguard Worker #include <sys/types.h>
25*598139dcSAndroid Build Coastguard Worker 
26*598139dcSAndroid Build Coastguard Worker #include <cutils/list.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 
PmsgRead(struct logger_list * logger_list,struct log_msg * log_msg)31*598139dcSAndroid Build Coastguard Worker int PmsgRead(struct logger_list* logger_list, struct log_msg* log_msg) {
32*598139dcSAndroid Build Coastguard Worker   ssize_t ret;
33*598139dcSAndroid Build Coastguard Worker   off_t current, next;
34*598139dcSAndroid Build Coastguard Worker   struct __attribute__((__packed__)) {
35*598139dcSAndroid Build Coastguard Worker     android_pmsg_log_header_t p;
36*598139dcSAndroid Build Coastguard Worker     android_log_header_t l;
37*598139dcSAndroid Build Coastguard Worker     uint8_t prio;
38*598139dcSAndroid Build Coastguard Worker   } buf;
39*598139dcSAndroid Build Coastguard Worker   static uint8_t preread_count;
40*598139dcSAndroid Build Coastguard Worker 
41*598139dcSAndroid Build Coastguard Worker   memset(log_msg, 0, sizeof(*log_msg));
42*598139dcSAndroid Build Coastguard Worker 
43*598139dcSAndroid Build Coastguard Worker   if (atomic_load(&logger_list->fd) <= 0) {
44*598139dcSAndroid Build Coastguard Worker     int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
45*598139dcSAndroid Build Coastguard Worker 
46*598139dcSAndroid Build Coastguard Worker     if (fd < 0) {
47*598139dcSAndroid Build Coastguard Worker       return -errno;
48*598139dcSAndroid Build Coastguard Worker     }
49*598139dcSAndroid Build Coastguard Worker     if (fd == 0) { /* Argggg */
50*598139dcSAndroid Build Coastguard Worker       fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
51*598139dcSAndroid Build Coastguard Worker       close(0);
52*598139dcSAndroid Build Coastguard Worker       if (fd < 0) {
53*598139dcSAndroid Build Coastguard Worker         return -errno;
54*598139dcSAndroid Build Coastguard Worker       }
55*598139dcSAndroid Build Coastguard Worker     }
56*598139dcSAndroid Build Coastguard Worker     i = atomic_exchange(&logger_list->fd, fd);
57*598139dcSAndroid Build Coastguard Worker     if ((i > 0) && (i != fd)) {
58*598139dcSAndroid Build Coastguard Worker       close(i);
59*598139dcSAndroid Build Coastguard Worker     }
60*598139dcSAndroid Build Coastguard Worker     preread_count = 0;
61*598139dcSAndroid Build Coastguard Worker   }
62*598139dcSAndroid Build Coastguard Worker 
63*598139dcSAndroid Build Coastguard Worker   while (1) {
64*598139dcSAndroid Build Coastguard Worker     int fd;
65*598139dcSAndroid Build Coastguard Worker 
66*598139dcSAndroid Build Coastguard Worker     if (preread_count < sizeof(buf)) {
67*598139dcSAndroid Build Coastguard Worker       fd = atomic_load(&logger_list->fd);
68*598139dcSAndroid Build Coastguard Worker       if (fd <= 0) {
69*598139dcSAndroid Build Coastguard Worker         return -EBADF;
70*598139dcSAndroid Build Coastguard Worker       }
71*598139dcSAndroid Build Coastguard Worker       ret = TEMP_FAILURE_RETRY(read(fd, &buf.p.magic + preread_count, sizeof(buf) - preread_count));
72*598139dcSAndroid Build Coastguard Worker       if (ret < 0) {
73*598139dcSAndroid Build Coastguard Worker         return -errno;
74*598139dcSAndroid Build Coastguard Worker       }
75*598139dcSAndroid Build Coastguard Worker       preread_count += ret;
76*598139dcSAndroid Build Coastguard Worker     }
77*598139dcSAndroid Build Coastguard Worker     if (preread_count != sizeof(buf)) {
78*598139dcSAndroid Build Coastguard Worker       return preread_count ? -EIO : -EAGAIN;
79*598139dcSAndroid Build Coastguard Worker     }
80*598139dcSAndroid Build Coastguard Worker     if ((buf.p.magic != LOGGER_MAGIC) || (buf.p.len <= sizeof(buf)) ||
81*598139dcSAndroid Build Coastguard Worker         (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) ||
82*598139dcSAndroid Build Coastguard Worker         !__android_log_id_is_valid(static_cast<log_id_t>(buf.l.id)) ||
83*598139dcSAndroid Build Coastguard Worker         (buf.l.realtime.tv_nsec >= NS_PER_SEC) ||
84*598139dcSAndroid Build Coastguard Worker         ((buf.l.id != LOG_ID_EVENTS) && (buf.l.id != LOG_ID_SECURITY) &&
85*598139dcSAndroid Build Coastguard Worker          ((buf.prio == ANDROID_LOG_UNKNOWN) || (buf.prio == ANDROID_LOG_DEFAULT) ||
86*598139dcSAndroid Build Coastguard Worker           (buf.prio >= ANDROID_LOG_SILENT)))) {
87*598139dcSAndroid Build Coastguard Worker       do {
88*598139dcSAndroid Build Coastguard Worker         memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
89*598139dcSAndroid Build Coastguard Worker       } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
90*598139dcSAndroid Build Coastguard Worker       continue;
91*598139dcSAndroid Build Coastguard Worker     }
92*598139dcSAndroid Build Coastguard Worker     preread_count = 0;
93*598139dcSAndroid Build Coastguard Worker 
94*598139dcSAndroid Build Coastguard Worker     if ((logger_list->log_mask & (1 << buf.l.id)) &&
95*598139dcSAndroid Build Coastguard Worker         ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
96*598139dcSAndroid Build Coastguard Worker          ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
97*598139dcSAndroid Build Coastguard Worker           ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
98*598139dcSAndroid Build Coastguard Worker            (logger_list->start.tv_nsec <= buf.l.realtime.tv_nsec)))) &&
99*598139dcSAndroid Build Coastguard Worker         (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
100*598139dcSAndroid Build Coastguard Worker       char* msg = reinterpret_cast<char*>(&log_msg->entry) + sizeof(log_msg->entry);
101*598139dcSAndroid Build Coastguard Worker       *msg = buf.prio;
102*598139dcSAndroid Build Coastguard Worker       fd = atomic_load(&logger_list->fd);
103*598139dcSAndroid Build Coastguard Worker       if (fd <= 0) {
104*598139dcSAndroid Build Coastguard Worker         return -EBADF;
105*598139dcSAndroid Build Coastguard Worker       }
106*598139dcSAndroid Build Coastguard Worker       ret = TEMP_FAILURE_RETRY(read(fd, msg + sizeof(buf.prio), buf.p.len - sizeof(buf)));
107*598139dcSAndroid Build Coastguard Worker       if (ret < 0) {
108*598139dcSAndroid Build Coastguard Worker         return -errno;
109*598139dcSAndroid Build Coastguard Worker       }
110*598139dcSAndroid Build Coastguard Worker       if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
111*598139dcSAndroid Build Coastguard Worker         return -EIO;
112*598139dcSAndroid Build Coastguard Worker       }
113*598139dcSAndroid Build Coastguard Worker 
114*598139dcSAndroid Build Coastguard Worker       log_msg->entry.len = buf.p.len - sizeof(buf) + sizeof(buf.prio);
115*598139dcSAndroid Build Coastguard Worker       log_msg->entry.hdr_size = sizeof(log_msg->entry);
116*598139dcSAndroid Build Coastguard Worker       log_msg->entry.pid = buf.p.pid;
117*598139dcSAndroid Build Coastguard Worker       log_msg->entry.tid = buf.l.tid;
118*598139dcSAndroid Build Coastguard Worker       log_msg->entry.sec = buf.l.realtime.tv_sec;
119*598139dcSAndroid Build Coastguard Worker       log_msg->entry.nsec = buf.l.realtime.tv_nsec;
120*598139dcSAndroid Build Coastguard Worker       log_msg->entry.lid = buf.l.id;
121*598139dcSAndroid Build Coastguard Worker       log_msg->entry.uid = buf.p.uid;
122*598139dcSAndroid Build Coastguard Worker 
123*598139dcSAndroid Build Coastguard Worker       return ret + sizeof(buf.prio) + log_msg->entry.hdr_size;
124*598139dcSAndroid Build Coastguard Worker     }
125*598139dcSAndroid Build Coastguard Worker 
126*598139dcSAndroid Build Coastguard Worker     fd = atomic_load(&logger_list->fd);
127*598139dcSAndroid Build Coastguard Worker     if (fd <= 0) {
128*598139dcSAndroid Build Coastguard Worker       return -EBADF;
129*598139dcSAndroid Build Coastguard Worker     }
130*598139dcSAndroid Build Coastguard Worker     current = TEMP_FAILURE_RETRY(lseek(fd, (off_t)0, SEEK_CUR));
131*598139dcSAndroid Build Coastguard Worker     if (current < 0) {
132*598139dcSAndroid Build Coastguard Worker       return -errno;
133*598139dcSAndroid Build Coastguard Worker     }
134*598139dcSAndroid Build Coastguard Worker     fd = atomic_load(&logger_list->fd);
135*598139dcSAndroid Build Coastguard Worker     if (fd <= 0) {
136*598139dcSAndroid Build Coastguard Worker       return -EBADF;
137*598139dcSAndroid Build Coastguard Worker     }
138*598139dcSAndroid Build Coastguard Worker     next = TEMP_FAILURE_RETRY(lseek(fd, (off_t)(buf.p.len - sizeof(buf)), SEEK_CUR));
139*598139dcSAndroid Build Coastguard Worker     if (next < 0) {
140*598139dcSAndroid Build Coastguard Worker       return -errno;
141*598139dcSAndroid Build Coastguard Worker     }
142*598139dcSAndroid Build Coastguard Worker     if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
143*598139dcSAndroid Build Coastguard Worker       return -EIO;
144*598139dcSAndroid Build Coastguard Worker     }
145*598139dcSAndroid Build Coastguard Worker   }
146*598139dcSAndroid Build Coastguard Worker }
147*598139dcSAndroid Build Coastguard Worker 
PmsgClose(struct logger_list * logger_list)148*598139dcSAndroid Build Coastguard Worker void PmsgClose(struct logger_list* logger_list) {
149*598139dcSAndroid Build Coastguard Worker   int fd = atomic_exchange(&logger_list->fd, 0);
150*598139dcSAndroid Build Coastguard Worker   if (fd > 0) {
151*598139dcSAndroid Build Coastguard Worker     close(fd);
152*598139dcSAndroid Build Coastguard Worker   }
153*598139dcSAndroid Build Coastguard Worker }
154*598139dcSAndroid Build Coastguard Worker 
realloc_or_free(void * ptr,size_t new_size)155*598139dcSAndroid Build Coastguard Worker static void* realloc_or_free(void* ptr, size_t new_size) {
156*598139dcSAndroid Build Coastguard Worker   void* result = realloc(ptr, new_size);
157*598139dcSAndroid Build Coastguard Worker   if (!result) {
158*598139dcSAndroid Build Coastguard Worker     free(ptr);
159*598139dcSAndroid Build Coastguard Worker   }
160*598139dcSAndroid Build Coastguard Worker   return result;
161*598139dcSAndroid Build Coastguard Worker }
162*598139dcSAndroid Build Coastguard Worker 
__android_log_pmsg_file_read(log_id_t logId,char prio,const char * prefix,__android_log_pmsg_file_read_fn fn,void * arg)163*598139dcSAndroid Build Coastguard Worker ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio, const char* prefix,
164*598139dcSAndroid Build Coastguard Worker                                      __android_log_pmsg_file_read_fn fn, void* arg) {
165*598139dcSAndroid Build Coastguard Worker   ssize_t ret;
166*598139dcSAndroid Build Coastguard Worker   struct content {
167*598139dcSAndroid Build Coastguard Worker     struct listnode node;
168*598139dcSAndroid Build Coastguard Worker     struct logger_entry entry;
169*598139dcSAndroid Build Coastguard Worker   } * content;
170*598139dcSAndroid Build Coastguard Worker   struct names {
171*598139dcSAndroid Build Coastguard Worker     struct listnode node;
172*598139dcSAndroid Build Coastguard Worker     struct listnode content;
173*598139dcSAndroid Build Coastguard Worker     log_id_t id;
174*598139dcSAndroid Build Coastguard Worker     char prio;
175*598139dcSAndroid Build Coastguard Worker     char name[];
176*598139dcSAndroid Build Coastguard Worker   } * names;
177*598139dcSAndroid Build Coastguard Worker   struct listnode name_list;
178*598139dcSAndroid Build Coastguard Worker   struct listnode *node, *n;
179*598139dcSAndroid Build Coastguard Worker   size_t len, prefix_len;
180*598139dcSAndroid Build Coastguard Worker 
181*598139dcSAndroid Build Coastguard Worker   if (!fn) {
182*598139dcSAndroid Build Coastguard Worker     return -EINVAL;
183*598139dcSAndroid Build Coastguard Worker   }
184*598139dcSAndroid Build Coastguard Worker 
185*598139dcSAndroid Build Coastguard Worker   /* Add just enough clues in logger_list and transp to make API function */
186*598139dcSAndroid Build Coastguard Worker   struct logger_list logger_list = {
187*598139dcSAndroid Build Coastguard Worker       .mode = static_cast<int>(ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK),
188*598139dcSAndroid Build Coastguard Worker       .log_mask = (unsigned)-1};
189*598139dcSAndroid Build Coastguard Worker   logger_list.log_mask = (1 << logId);
190*598139dcSAndroid Build Coastguard Worker   logger_list.log_mask &= ~((1 << LOG_ID_KERNEL) | (1 << LOG_ID_EVENTS) | (1 << LOG_ID_SECURITY));
191*598139dcSAndroid Build Coastguard Worker   if (!logger_list.log_mask) {
192*598139dcSAndroid Build Coastguard Worker     return -EINVAL;
193*598139dcSAndroid Build Coastguard Worker   }
194*598139dcSAndroid Build Coastguard Worker 
195*598139dcSAndroid Build Coastguard Worker   /* Initialize name list */
196*598139dcSAndroid Build Coastguard Worker   list_init(&name_list);
197*598139dcSAndroid Build Coastguard Worker 
198*598139dcSAndroid Build Coastguard Worker   ret = SSIZE_MAX;
199*598139dcSAndroid Build Coastguard Worker 
200*598139dcSAndroid Build Coastguard Worker   /* Validate incoming prefix, shift until it contains only 0 or 1 : or / */
201*598139dcSAndroid Build Coastguard Worker   prefix_len = 0;
202*598139dcSAndroid Build Coastguard Worker   if (prefix) {
203*598139dcSAndroid Build Coastguard Worker     const char *prev = NULL, *last = NULL, *cp = prefix;
204*598139dcSAndroid Build Coastguard Worker     while ((cp = strpbrk(cp, "/:"))) {
205*598139dcSAndroid Build Coastguard Worker       prev = last;
206*598139dcSAndroid Build Coastguard Worker       last = cp;
207*598139dcSAndroid Build Coastguard Worker       cp = cp + 1;
208*598139dcSAndroid Build Coastguard Worker     }
209*598139dcSAndroid Build Coastguard Worker     if (prev) {
210*598139dcSAndroid Build Coastguard Worker       prefix = prev + 1;
211*598139dcSAndroid Build Coastguard Worker     }
212*598139dcSAndroid Build Coastguard Worker     prefix_len = strlen(prefix);
213*598139dcSAndroid Build Coastguard Worker   }
214*598139dcSAndroid Build Coastguard Worker 
215*598139dcSAndroid Build Coastguard Worker   /* Read the file content */
216*598139dcSAndroid Build Coastguard Worker   log_msg log_msg;
217*598139dcSAndroid Build Coastguard Worker   while (PmsgRead(&logger_list, &log_msg) > 0) {
218*598139dcSAndroid Build Coastguard Worker     const char* cp;
219*598139dcSAndroid Build Coastguard Worker     size_t hdr_size = log_msg.entry.hdr_size;
220*598139dcSAndroid Build Coastguard Worker 
221*598139dcSAndroid Build Coastguard Worker     char* msg = (char*)&log_msg + hdr_size;
222*598139dcSAndroid Build Coastguard Worker     const char* split = NULL;
223*598139dcSAndroid Build Coastguard Worker 
224*598139dcSAndroid Build Coastguard Worker     if (hdr_size != sizeof(log_msg.entry)) {
225*598139dcSAndroid Build Coastguard Worker       continue;
226*598139dcSAndroid Build Coastguard Worker     }
227*598139dcSAndroid Build Coastguard Worker     /* Check for invalid sequence number */
228*598139dcSAndroid Build Coastguard Worker     if (log_msg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE ||
229*598139dcSAndroid Build Coastguard Worker         (log_msg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
230*598139dcSAndroid Build Coastguard Worker             ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
231*598139dcSAndroid Build Coastguard Worker       continue;
232*598139dcSAndroid Build Coastguard Worker     }
233*598139dcSAndroid Build Coastguard Worker 
234*598139dcSAndroid Build Coastguard Worker     /* Determine if it has <dirbase>:<filebase> format for tag */
235*598139dcSAndroid Build Coastguard Worker     len = log_msg.entry.len - sizeof(prio);
236*598139dcSAndroid Build Coastguard Worker     for (cp = msg + sizeof(prio); *cp && isprint(*cp) && !isspace(*cp) && --len; ++cp) {
237*598139dcSAndroid Build Coastguard Worker       if (*cp == ':') {
238*598139dcSAndroid Build Coastguard Worker         if (split) {
239*598139dcSAndroid Build Coastguard Worker           break;
240*598139dcSAndroid Build Coastguard Worker         }
241*598139dcSAndroid Build Coastguard Worker         split = cp;
242*598139dcSAndroid Build Coastguard Worker       }
243*598139dcSAndroid Build Coastguard Worker     }
244*598139dcSAndroid Build Coastguard Worker     if (*cp || !split) {
245*598139dcSAndroid Build Coastguard Worker       continue;
246*598139dcSAndroid Build Coastguard Worker     }
247*598139dcSAndroid Build Coastguard Worker 
248*598139dcSAndroid Build Coastguard Worker     /* Filters */
249*598139dcSAndroid Build Coastguard Worker     if (prefix_len && strncmp(msg + sizeof(prio), prefix, prefix_len)) {
250*598139dcSAndroid Build Coastguard Worker       size_t offset;
251*598139dcSAndroid Build Coastguard Worker       /*
252*598139dcSAndroid Build Coastguard Worker        *   Allow : to be a synonym for /
253*598139dcSAndroid Build Coastguard Worker        * Things we do dealing with const char * and do not alloc
254*598139dcSAndroid Build Coastguard Worker        */
255*598139dcSAndroid Build Coastguard Worker       split = strchr(prefix, ':');
256*598139dcSAndroid Build Coastguard Worker       if (split) {
257*598139dcSAndroid Build Coastguard Worker         continue;
258*598139dcSAndroid Build Coastguard Worker       }
259*598139dcSAndroid Build Coastguard Worker       split = strchr(prefix, '/');
260*598139dcSAndroid Build Coastguard Worker       if (!split) {
261*598139dcSAndroid Build Coastguard Worker         continue;
262*598139dcSAndroid Build Coastguard Worker       }
263*598139dcSAndroid Build Coastguard Worker       offset = split - prefix;
264*598139dcSAndroid Build Coastguard Worker       if ((msg[offset + sizeof(prio)] != ':') || strncmp(msg + sizeof(prio), prefix, offset)) {
265*598139dcSAndroid Build Coastguard Worker         continue;
266*598139dcSAndroid Build Coastguard Worker       }
267*598139dcSAndroid Build Coastguard Worker       ++offset;
268*598139dcSAndroid Build Coastguard Worker       if ((prefix_len > offset) &&
269*598139dcSAndroid Build Coastguard Worker           strncmp(&msg[offset + sizeof(prio)], split + 1, prefix_len - offset)) {
270*598139dcSAndroid Build Coastguard Worker         continue;
271*598139dcSAndroid Build Coastguard Worker       }
272*598139dcSAndroid Build Coastguard Worker     }
273*598139dcSAndroid Build Coastguard Worker 
274*598139dcSAndroid Build Coastguard Worker     if ((prio != ANDROID_LOG_ANY) && (*msg < prio)) {
275*598139dcSAndroid Build Coastguard Worker       continue;
276*598139dcSAndroid Build Coastguard Worker     }
277*598139dcSAndroid Build Coastguard Worker 
278*598139dcSAndroid Build Coastguard Worker     /* check if there is an existing entry */
279*598139dcSAndroid Build Coastguard Worker     list_for_each(node, &name_list) {
280*598139dcSAndroid Build Coastguard Worker       names = node_to_item(node, struct names, node);
281*598139dcSAndroid Build Coastguard Worker       if (!strcmp(names->name, msg + sizeof(prio)) && names->id == log_msg.entry.lid &&
282*598139dcSAndroid Build Coastguard Worker           names->prio == *msg) {
283*598139dcSAndroid Build Coastguard Worker         break;
284*598139dcSAndroid Build Coastguard Worker       }
285*598139dcSAndroid Build Coastguard Worker     }
286*598139dcSAndroid Build Coastguard Worker 
287*598139dcSAndroid Build Coastguard Worker     /* We do not have an existing entry, create and add one */
288*598139dcSAndroid Build Coastguard Worker     if (node == &name_list) {
289*598139dcSAndroid Build Coastguard Worker       static const char numbers[] = "0123456789";
290*598139dcSAndroid Build Coastguard Worker       unsigned long long nl;
291*598139dcSAndroid Build Coastguard Worker 
292*598139dcSAndroid Build Coastguard Worker       len = strlen(msg + sizeof(prio)) + 1;
293*598139dcSAndroid Build Coastguard Worker       names = static_cast<struct names*>(calloc(1, sizeof(*names) + len));
294*598139dcSAndroid Build Coastguard Worker       if (!names) {
295*598139dcSAndroid Build Coastguard Worker         ret = -ENOMEM;
296*598139dcSAndroid Build Coastguard Worker         break;
297*598139dcSAndroid Build Coastguard Worker       }
298*598139dcSAndroid Build Coastguard Worker       strcpy(names->name, msg + sizeof(prio));
299*598139dcSAndroid Build Coastguard Worker       names->id = static_cast<log_id_t>(log_msg.entry.lid);
300*598139dcSAndroid Build Coastguard Worker       names->prio = *msg;
301*598139dcSAndroid Build Coastguard Worker       list_init(&names->content);
302*598139dcSAndroid Build Coastguard Worker       /*
303*598139dcSAndroid Build Coastguard Worker        * Insert in reverse numeric _then_ alpha sorted order as
304*598139dcSAndroid Build Coastguard Worker        * representative of log rotation:
305*598139dcSAndroid Build Coastguard Worker        *
306*598139dcSAndroid Build Coastguard Worker        *   log.10
307*598139dcSAndroid Build Coastguard Worker        *   klog.10
308*598139dcSAndroid Build Coastguard Worker        *   . . .
309*598139dcSAndroid Build Coastguard Worker        *   log.2
310*598139dcSAndroid Build Coastguard Worker        *   klog.2
311*598139dcSAndroid Build Coastguard Worker        *   log.1
312*598139dcSAndroid Build Coastguard Worker        *   klog.1
313*598139dcSAndroid Build Coastguard Worker        *   log
314*598139dcSAndroid Build Coastguard Worker        *   klog
315*598139dcSAndroid Build Coastguard Worker        *
316*598139dcSAndroid Build Coastguard Worker        * thus when we present the content, we are provided the oldest
317*598139dcSAndroid Build Coastguard Worker        * first, which when 'refreshed' could spill off the end of the
318*598139dcSAndroid Build Coastguard Worker        * pmsg FIFO but retaining the newest data for last with best
319*598139dcSAndroid Build Coastguard Worker        * chances to survive.
320*598139dcSAndroid Build Coastguard Worker        */
321*598139dcSAndroid Build Coastguard Worker       nl = 0;
322*598139dcSAndroid Build Coastguard Worker       cp = strpbrk(names->name, numbers);
323*598139dcSAndroid Build Coastguard Worker       if (cp) {
324*598139dcSAndroid Build Coastguard Worker         nl = strtoull(cp, NULL, 10);
325*598139dcSAndroid Build Coastguard Worker       }
326*598139dcSAndroid Build Coastguard Worker       list_for_each_reverse(node, &name_list) {
327*598139dcSAndroid Build Coastguard Worker         struct names* a_name = node_to_item(node, struct names, node);
328*598139dcSAndroid Build Coastguard Worker         const char* r = a_name->name;
329*598139dcSAndroid Build Coastguard Worker         int compare = 0;
330*598139dcSAndroid Build Coastguard Worker 
331*598139dcSAndroid Build Coastguard Worker         unsigned long long nr = 0;
332*598139dcSAndroid Build Coastguard Worker         cp = strpbrk(r, numbers);
333*598139dcSAndroid Build Coastguard Worker         if (cp) {
334*598139dcSAndroid Build Coastguard Worker           nr = strtoull(cp, NULL, 10);
335*598139dcSAndroid Build Coastguard Worker         }
336*598139dcSAndroid Build Coastguard Worker         if (nr != nl) {
337*598139dcSAndroid Build Coastguard Worker           compare = (nl > nr) ? 1 : -1;
338*598139dcSAndroid Build Coastguard Worker         }
339*598139dcSAndroid Build Coastguard Worker         if (compare == 0) {
340*598139dcSAndroid Build Coastguard Worker           compare = strcmp(names->name, r);
341*598139dcSAndroid Build Coastguard Worker         }
342*598139dcSAndroid Build Coastguard Worker         if (compare <= 0) {
343*598139dcSAndroid Build Coastguard Worker           break;
344*598139dcSAndroid Build Coastguard Worker         }
345*598139dcSAndroid Build Coastguard Worker       }
346*598139dcSAndroid Build Coastguard Worker       list_add_head(node, &names->node);
347*598139dcSAndroid Build Coastguard Worker     }
348*598139dcSAndroid Build Coastguard Worker 
349*598139dcSAndroid Build Coastguard Worker     /* Remove any file fragments that match our sequence number */
350*598139dcSAndroid Build Coastguard Worker     list_for_each_safe(node, n, &names->content) {
351*598139dcSAndroid Build Coastguard Worker       content = node_to_item(node, struct content, node);
352*598139dcSAndroid Build Coastguard Worker       if (log_msg.entry.nsec == content->entry.nsec) {
353*598139dcSAndroid Build Coastguard Worker         list_remove(&content->node);
354*598139dcSAndroid Build Coastguard Worker         free(content);
355*598139dcSAndroid Build Coastguard Worker       }
356*598139dcSAndroid Build Coastguard Worker     }
357*598139dcSAndroid Build Coastguard Worker 
358*598139dcSAndroid Build Coastguard Worker     /* Add content */
359*598139dcSAndroid Build Coastguard Worker     content = static_cast<struct content*>(
360*598139dcSAndroid Build Coastguard Worker         calloc(1, sizeof(content->node) + hdr_size + log_msg.entry.len));
361*598139dcSAndroid Build Coastguard Worker     if (!content) {
362*598139dcSAndroid Build Coastguard Worker       ret = -ENOMEM;
363*598139dcSAndroid Build Coastguard Worker       break;
364*598139dcSAndroid Build Coastguard Worker     }
365*598139dcSAndroid Build Coastguard Worker     memcpy(&content->entry, &log_msg.entry, hdr_size + log_msg.entry.len);
366*598139dcSAndroid Build Coastguard Worker 
367*598139dcSAndroid Build Coastguard Worker     /* Insert in sequence number sorted order, to ease reconstruction */
368*598139dcSAndroid Build Coastguard Worker     list_for_each_reverse(node, &names->content) {
369*598139dcSAndroid Build Coastguard Worker       if ((node_to_item(node, struct content, node))->entry.nsec < log_msg.entry.nsec) {
370*598139dcSAndroid Build Coastguard Worker         break;
371*598139dcSAndroid Build Coastguard Worker       }
372*598139dcSAndroid Build Coastguard Worker     }
373*598139dcSAndroid Build Coastguard Worker     list_add_head(node, &content->node);
374*598139dcSAndroid Build Coastguard Worker   }
375*598139dcSAndroid Build Coastguard Worker   PmsgClose(&logger_list);
376*598139dcSAndroid Build Coastguard Worker 
377*598139dcSAndroid Build Coastguard Worker   /* Progress through all the collected files */
378*598139dcSAndroid Build Coastguard Worker   list_for_each_safe(node, n, &name_list) {
379*598139dcSAndroid Build Coastguard Worker     struct listnode *content_node, *m;
380*598139dcSAndroid Build Coastguard Worker     char* buf;
381*598139dcSAndroid Build Coastguard Worker     size_t sequence, tag_len;
382*598139dcSAndroid Build Coastguard Worker 
383*598139dcSAndroid Build Coastguard Worker     names = node_to_item(node, struct names, node);
384*598139dcSAndroid Build Coastguard Worker 
385*598139dcSAndroid Build Coastguard Worker     /* Construct content into a linear buffer */
386*598139dcSAndroid Build Coastguard Worker     buf = NULL;
387*598139dcSAndroid Build Coastguard Worker     len = 0;
388*598139dcSAndroid Build Coastguard Worker     sequence = 0;
389*598139dcSAndroid Build Coastguard Worker     tag_len = strlen(names->name) + sizeof(char); /* tag + nul */
390*598139dcSAndroid Build Coastguard Worker     list_for_each_safe(content_node, m, &names->content) {
391*598139dcSAndroid Build Coastguard Worker       ssize_t add_len;
392*598139dcSAndroid Build Coastguard Worker 
393*598139dcSAndroid Build Coastguard Worker       content = node_to_item(content_node, struct content, node);
394*598139dcSAndroid Build Coastguard Worker       add_len = content->entry.len - tag_len - sizeof(prio);
395*598139dcSAndroid Build Coastguard Worker       if (add_len <= 0) {
396*598139dcSAndroid Build Coastguard Worker         list_remove(content_node);
397*598139dcSAndroid Build Coastguard Worker         free(content);
398*598139dcSAndroid Build Coastguard Worker         continue;
399*598139dcSAndroid Build Coastguard Worker       }
400*598139dcSAndroid Build Coastguard Worker 
401*598139dcSAndroid Build Coastguard Worker       if (!buf) {
402*598139dcSAndroid Build Coastguard Worker         buf = static_cast<char*>(malloc(sizeof(char)));
403*598139dcSAndroid Build Coastguard Worker         if (!buf) {
404*598139dcSAndroid Build Coastguard Worker           ret = -ENOMEM;
405*598139dcSAndroid Build Coastguard Worker           list_remove(content_node);
406*598139dcSAndroid Build Coastguard Worker           free(content);
407*598139dcSAndroid Build Coastguard Worker           continue;
408*598139dcSAndroid Build Coastguard Worker         }
409*598139dcSAndroid Build Coastguard Worker         *buf = '\0';
410*598139dcSAndroid Build Coastguard Worker       }
411*598139dcSAndroid Build Coastguard Worker 
412*598139dcSAndroid Build Coastguard Worker       /* Missing sequence numbers */
413*598139dcSAndroid Build Coastguard Worker       while (sequence < content->entry.nsec) {
414*598139dcSAndroid Build Coastguard Worker         /* plus space for enforced nul */
415*598139dcSAndroid Build Coastguard Worker         buf = static_cast<char*>(realloc_or_free(buf, len + sizeof(char) + sizeof(char)));
416*598139dcSAndroid Build Coastguard Worker         if (!buf) {
417*598139dcSAndroid Build Coastguard Worker           break;
418*598139dcSAndroid Build Coastguard Worker         }
419*598139dcSAndroid Build Coastguard Worker         buf[len] = '\f'; /* Mark missing content with a form feed */
420*598139dcSAndroid Build Coastguard Worker         buf[++len] = '\0';
421*598139dcSAndroid Build Coastguard Worker         sequence += ANDROID_LOG_PMSG_FILE_SEQUENCE;
422*598139dcSAndroid Build Coastguard Worker       }
423*598139dcSAndroid Build Coastguard Worker       if (!buf) {
424*598139dcSAndroid Build Coastguard Worker         ret = -ENOMEM;
425*598139dcSAndroid Build Coastguard Worker         list_remove(content_node);
426*598139dcSAndroid Build Coastguard Worker         free(content);
427*598139dcSAndroid Build Coastguard Worker         continue;
428*598139dcSAndroid Build Coastguard Worker       }
429*598139dcSAndroid Build Coastguard Worker       /* plus space for enforced nul */
430*598139dcSAndroid Build Coastguard Worker       buf = static_cast<char*>(realloc_or_free(buf, len + add_len + sizeof(char)));
431*598139dcSAndroid Build Coastguard Worker       if (!buf) {
432*598139dcSAndroid Build Coastguard Worker         ret = -ENOMEM;
433*598139dcSAndroid Build Coastguard Worker         list_remove(content_node);
434*598139dcSAndroid Build Coastguard Worker         free(content);
435*598139dcSAndroid Build Coastguard Worker         continue;
436*598139dcSAndroid Build Coastguard Worker       }
437*598139dcSAndroid Build Coastguard Worker       memcpy(buf + len, (char*)&content->entry + content->entry.hdr_size + tag_len + sizeof(prio),
438*598139dcSAndroid Build Coastguard Worker              add_len);
439*598139dcSAndroid Build Coastguard Worker       len += add_len;
440*598139dcSAndroid Build Coastguard Worker       buf[len] = '\0'; /* enforce trailing hidden nul */
441*598139dcSAndroid Build Coastguard Worker       sequence = content->entry.nsec + ANDROID_LOG_PMSG_FILE_SEQUENCE;
442*598139dcSAndroid Build Coastguard Worker 
443*598139dcSAndroid Build Coastguard Worker       list_remove(content_node);
444*598139dcSAndroid Build Coastguard Worker       free(content);
445*598139dcSAndroid Build Coastguard Worker     }
446*598139dcSAndroid Build Coastguard Worker     if (buf) {
447*598139dcSAndroid Build Coastguard Worker       if (len) {
448*598139dcSAndroid Build Coastguard Worker         /* Buffer contains enforced trailing nul just beyond length */
449*598139dcSAndroid Build Coastguard Worker         ssize_t r;
450*598139dcSAndroid Build Coastguard Worker         *strchr(names->name, ':') = '/'; /* Convert back to filename */
451*598139dcSAndroid Build Coastguard Worker         r = (*fn)(names->id, names->prio, names->name, buf, len, arg);
452*598139dcSAndroid Build Coastguard Worker         if ((ret >= 0) && (r > 0)) {
453*598139dcSAndroid Build Coastguard Worker           if (ret == SSIZE_MAX) {
454*598139dcSAndroid Build Coastguard Worker             ret = r;
455*598139dcSAndroid Build Coastguard Worker           } else {
456*598139dcSAndroid Build Coastguard Worker             ret += r;
457*598139dcSAndroid Build Coastguard Worker           }
458*598139dcSAndroid Build Coastguard Worker         } else if (r < ret) {
459*598139dcSAndroid Build Coastguard Worker           ret = r;
460*598139dcSAndroid Build Coastguard Worker         }
461*598139dcSAndroid Build Coastguard Worker       }
462*598139dcSAndroid Build Coastguard Worker       free(buf);
463*598139dcSAndroid Build Coastguard Worker     }
464*598139dcSAndroid Build Coastguard Worker     list_remove(node);
465*598139dcSAndroid Build Coastguard Worker     free(names);
466*598139dcSAndroid Build Coastguard Worker   }
467*598139dcSAndroid Build Coastguard Worker   return (ret == SSIZE_MAX) ? -ENOENT : ret;
468*598139dcSAndroid Build Coastguard Worker }
469