/*
 * Copyright (C) 2005-2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <sys/types.h>

/* deal with possible sys/cdefs.h conflict with fcntl.h */
#ifdef __unused
#define __unused_defined __unused
#undef __unused
#endif

#include <fcntl.h> /* Pick up O_* macros */

/* restore definitions from above */
#ifdef __unused_defined
#define __unused __attribute__((__unused__))
#endif

#include <stdint.h>

#include <log/log_id.h>
#include <log/log_time.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Native log reading interface section. See logcat for sample code.
 *
 * The preferred API is an exec of logcat. Likely uses of this interface
 * are if native code suffers from exec or filtration being too costly,
 * access to raw information, or parsing is an issue.
 */

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wzero-length-array"
/*
 * The userspace structure for version 1 of the logger_entry ABI.
 */
#ifndef __struct_logger_entry_defined
#define __struct_logger_entry_defined
struct logger_entry {
  uint16_t len;   /* length of the payload */
  uint16_t __pad; /* no matter what, we get 2 bytes of padding */
  int32_t pid;    /* generating process's pid */
  int32_t tid;    /* generating process's tid */
  int32_t sec;    /* seconds since Epoch */
  int32_t nsec;   /* nanoseconds */
  char msg[0]; /* the entry's payload */
};
#endif

/*
 * The userspace structure for version 2 of the logger_entry ABI.
 */
#ifndef __struct_logger_entry_v2_defined
#define __struct_logger_entry_v2_defined
struct logger_entry_v2 {
  uint16_t len;      /* length of the payload */
  uint16_t hdr_size; /* sizeof(struct logger_entry_v2) */
  int32_t pid;       /* generating process's pid */
  int32_t tid;       /* generating process's tid */
  int32_t sec;       /* seconds since Epoch */
  int32_t nsec;      /* nanoseconds */
  uint32_t euid;     /* effective UID of logger */
  char msg[0]; /* the entry's payload */
} __attribute__((__packed__));
#endif

/*
 * The userspace structure for version 3 of the logger_entry ABI.
 */
#ifndef __struct_logger_entry_v3_defined
#define __struct_logger_entry_v3_defined
struct logger_entry_v3 {
  uint16_t len;      /* length of the payload */
  uint16_t hdr_size; /* sizeof(struct logger_entry_v3) */
  int32_t pid;       /* generating process's pid */
  int32_t tid;       /* generating process's tid */
  int32_t sec;       /* seconds since Epoch */
  int32_t nsec;      /* nanoseconds */
  uint32_t lid;      /* log id of the payload */
  char msg[0]; /* the entry's payload */
} __attribute__((__packed__));
#endif

/*
 * The userspace structure for version 4 of the logger_entry ABI.
 */
#ifndef __struct_logger_entry_v4_defined
#define __struct_logger_entry_v4_defined
struct logger_entry_v4 {
  uint16_t len;      /* length of the payload */
  uint16_t hdr_size; /* sizeof(struct logger_entry_v4) */
  int32_t pid;       /* generating process's pid */
  uint32_t tid;      /* generating process's tid */
  uint32_t sec;      /* seconds since Epoch */
  uint32_t nsec;     /* nanoseconds */
  uint32_t lid;      /* log id of the payload, bottom 4 bits currently */
  uint32_t uid;      /* generating process's uid */
  char msg[0]; /* the entry's payload */
};
#endif
#pragma clang diagnostic pop

/*
 * The maximum size of the log entry payload that can be
 * written to the logger. An attempt to write more than
 * this amount will result in a truncated log entry.
 */
#define LOGGER_ENTRY_MAX_PAYLOAD 4068

/*
 * The maximum size of a log entry which can be read.
 * An attempt to read less than this amount may result
 * in read() returning EINVAL.
 */
#define LOGGER_ENTRY_MAX_LEN (5 * 1024)

#ifndef __struct_log_msg_defined
#define __struct_log_msg_defined
struct log_msg {
  union {
    unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
    struct logger_entry_v4 entry;
    struct logger_entry_v4 entry_v4;
    struct logger_entry_v3 entry_v3;
    struct logger_entry_v2 entry_v2;
    struct logger_entry entry_v1;
  } __attribute__((aligned(4)));
#ifdef __cplusplus
  /* Matching log_time operators */
  bool operator==(const log_msg& T) const {
    return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
  }
  bool operator!=(const log_msg& T) const {
    return !(*this == T);
  }
  bool operator<(const log_msg& T) const {
    return (entry.sec < T.entry.sec) ||
           ((entry.sec == T.entry.sec) && (entry.nsec < T.entry.nsec));
  }
  bool operator>=(const log_msg& T) const {
    return !(*this < T);
  }
  bool operator>(const log_msg& T) const {
    return (entry.sec > T.entry.sec) ||
           ((entry.sec == T.entry.sec) && (entry.nsec > T.entry.nsec));
  }
  bool operator<=(const log_msg& T) const {
    return !(*this > T);
  }
  uint64_t nsec() const {
    return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
  }

  /* packet methods */
  log_id_t id() {
    return static_cast<log_id_t>(entry.lid);
  }
  char* msg() {
    unsigned short hdr_size = entry.hdr_size;
    if (!hdr_size) {
      hdr_size = sizeof(entry_v1);
    }
    if ((hdr_size < sizeof(entry_v1)) || (hdr_size > sizeof(entry))) {
      return nullptr;
    }
    return reinterpret_cast<char*>(buf) + hdr_size;
  }
  unsigned int len() {
    return (entry.hdr_size ? entry.hdr_size
                           : static_cast<uint16_t>(sizeof(entry_v1))) +
           entry.len;
  }
#endif
};
#endif

struct logger;

log_id_t android_logger_get_id(struct logger* logger);

int android_logger_clear(struct logger* logger);
long android_logger_get_log_size(struct logger* logger);
int android_logger_set_log_size(struct logger* logger, unsigned long size);
long android_logger_get_log_readable_size(struct logger* logger);
int android_logger_get_log_version(struct logger* logger);

struct logger_list;

ssize_t android_logger_get_statistics(struct logger_list* logger_list,
                                      char* buf, size_t len);
ssize_t android_logger_get_prune_list(struct logger_list* logger_list,
                                      char* buf, size_t len);
int android_logger_set_prune_list(struct logger_list* logger_list, char* buf,
                                  size_t len);

#define ANDROID_LOG_RDONLY O_RDONLY
#define ANDROID_LOG_WRONLY O_WRONLY
#define ANDROID_LOG_RDWR O_RDWR
#define ANDROID_LOG_ACCMODE O_ACCMODE
#ifndef O_NONBLOCK
#define ANDROID_LOG_NONBLOCK 0x00000800
#else
#define ANDROID_LOG_NONBLOCK O_NONBLOCK
#endif
#define ANDROID_LOG_WRAP 0x40000000 /* Block until buffer about to wrap */
#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
#define ANDROID_LOG_PSTORE 0x80000000

struct logger_list* android_logger_list_alloc(int mode, unsigned int tail,
                                              pid_t pid);
struct logger_list* android_logger_list_alloc_time(int mode, log_time start,
                                                   pid_t pid);
void android_logger_list_free(struct logger_list* logger_list);
/* In the purest sense, the following two are orthogonal interfaces */
int android_logger_list_read(struct logger_list* logger_list,
                             struct log_msg* log_msg);

/* Multiple log_id_t opens */
struct logger* android_logger_open(struct logger_list* logger_list, log_id_t id);
#define android_logger_close android_logger_free
/* Single log_id_t open */
struct logger_list* android_logger_list_open(log_id_t id, int mode,
                                             unsigned int tail, pid_t pid);
#define android_logger_list_close android_logger_list_free

#ifdef __cplusplus
}
#endif
