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