1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/*
2700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn * Copyright (C) 2007-2016 The Android Open Source Project
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * you may not use this file except in compliance with the License.
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * You may obtain a copy of the License at
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * See the License for the specific language governing permissions and
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * limitations under the License.
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
17a04464adaf5b95ae953f8577632d3cf8aa2c80a3Mark Salyzyn#include <assert.h>
1870a83dc7b3bfd56098079c95de5d80daa9998a77Mark Salyzyn#include <ctype.h>
19a04464adaf5b95ae953f8577632d3cf8aa2c80a3Mark Salyzyn#include <errno.h>
20a04464adaf5b95ae953f8577632d3cf8aa2c80a3Mark Salyzyn#include <fcntl.h>
2170a83dc7b3bfd56098079c95de5d80daa9998a77Mark Salyzyn#include <inttypes.h>
22c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn#include <limits.h>
23cfd5b080af8de527d768f0ff7902c26af8d49307Mark Salyzyn#include <stdio.h>
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/mman.h>
27a04464adaf5b95ae953f8577632d3cf8aa2c80a3Mark Salyzyn
28700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn#include <experimental/string_view>
29700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn#include <functional>
30c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn#include <string>
31700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn#include <unordered_map>
32700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn
33a04464adaf5b95ae953f8577632d3cf8aa2c80a3Mark Salyzyn#include <log/event_tag_map.h>
341f83aa424f537cf3f07e1d27dbbcc524818b5358Steven Moreland#include <log/log_properties.h>
352ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn#include <private/android_logger.h>
36c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn#include <utils/FastStrcmp.h>
37c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn#include <utils/RWLock.h>
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
39018a96d03f0d452bf078084eedcd5693da42308dMark Salyzyn#include "log_portability.h"
40c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn#include "logd_reader.h"
41be1d3c21b57d3e67c6a9682f3b2f0838486a3ee8Mark Salyzyn
42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define OUT_TAG "EventTagMap"
43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
44c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzynclass MapString {
452ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn private:
462ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  const std::string* alloc;                  // HAS-AN
472ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  const std::experimental::string_view str;  // HAS-A
482ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
492ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn public:
502ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  operator const std::experimental::string_view() const {
512ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return str;
522ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
532ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
542ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  const char* data() const {
552ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return str.data();
562ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
572ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t length() const {
582ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return str.length();
592ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
602ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
612ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  bool operator==(const MapString& rval) const {
622ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (length() != rval.length()) return false;
632ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (length() == 0) return true;
642ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
652ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
662ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  bool operator!=(const MapString& rval) const {
672ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return !(*this == rval);
682ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
692ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
702ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  MapString(const char* str, size_t len) : alloc(NULL), str(str, len) {
712ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
722ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  explicit MapString(const std::string& str)
732ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      : alloc(new std::string(str)), str(alloc->data(), alloc->length()) {
742ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
752ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  MapString(MapString&& rval)
762ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      : alloc(rval.alloc), str(rval.data(), rval.length()) {
772ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    rval.alloc = NULL;
782ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
792ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  explicit MapString(const MapString& rval)
802ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      : alloc(rval.alloc ? new std::string(*rval.alloc) : NULL),
812ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        str(alloc ? alloc->data() : rval.data(), rval.length()) {
822ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
832ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
842ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  ~MapString() {
852ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (alloc) delete alloc;
862ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
87c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn};
88c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn
89c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn// Hash for MapString
902ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyntemplate <>
912ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzynstruct std::hash<MapString>
922ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    : public std::unary_function<const MapString&, size_t> {
932ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t operator()(const MapString& __t) const noexcept {
942ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (!__t.length()) return 0;
952ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return std::hash<std::experimental::string_view>()(
962ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        std::experimental::string_view(__t));
972ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
98c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn};
99700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn
100700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyntypedef std::pair<MapString, MapString> TagFmt;
101700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn
1022ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyntemplate <>
1032ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzynstruct std::hash<TagFmt> : public std::unary_function<const TagFmt&, size_t> {
1042ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t operator()(const TagFmt& __t) const noexcept {
1052ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    // Tag is typically unique.  Will cost us an extra 100ns for the
1062ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    // unordered_map lookup if we instead did a hash that combined
1072ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    // both of tag and fmt members, e.g.:
1082ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    //
1092ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    // return std::hash<MapString>()(__t.first) ^
1102ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    //        std::hash<MapString>()(__t.second);
1112ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return std::hash<MapString>()(__t.first);
1122ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
113700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn};
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
115700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// Map
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstruct EventTagMap {
1172ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn#define NUM_MAPS 2
1182ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // memory-mapped source file; we get strings from here
1192ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  void* mapAddr[NUM_MAPS];
1202ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t mapLen[NUM_MAPS];
1212ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
1222ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn private:
1232ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
1242ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  std::unordered_map<TagFmt, uint32_t> TagFmt2Idx;
1252ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  std::unordered_map<MapString, uint32_t> Tag2Idx;
1262ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // protect unordered sets
1272ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  android::RWLock rwlock;
1282ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
1292ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn public:
1302ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  EventTagMap() {
1312ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    memset(mapAddr, 0, sizeof(mapAddr));
1322ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    memset(mapLen, 0, sizeof(mapLen));
1332ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
1342ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
1352ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  ~EventTagMap() {
1362ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    Idx2TagFmt.clear();
1372ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    TagFmt2Idx.clear();
1382ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    Tag2Idx.clear();
1392ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    for (size_t which = 0; which < NUM_MAPS; ++which) {
1402ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if (mapAddr[which]) {
1412ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        munmap(mapAddr[which], mapLen[which]);
1422ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        mapAddr[which] = 0;
1432ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
1447da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzyn    }
1452ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1472ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
1482ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  const TagFmt* find(uint32_t tag) const;
1492ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  int find(TagFmt&& tagfmt) const;
1502ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  int find(MapString&& tag) const;
151700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn};
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1532ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzynbool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt,
1542ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                bool verbose) {
1552ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  bool ret = true;
1562ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  static const char errorFormat[] =
1572ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      OUT_TAG ": duplicate tag entries %" PRIu32 ":%.*s:%.*s and %" PRIu32
1582ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn              ":%.*s:%.*s)\n";
1592ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  android::RWLock::AutoWLock writeLock(rwlock);
1602ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  {
1612ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    std::unordered_map<uint32_t, TagFmt>::const_iterator it;
1622ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    it = Idx2TagFmt.find(tag);
1632ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (it != Idx2TagFmt.end()) {
1642ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if (verbose) {
1652ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        fprintf(stderr, errorFormat, it->first, (int)it->second.first.length(),
1662ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                it->second.first.data(), (int)it->second.second.length(),
1672ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                it->second.second.data(), tag, (int)tagfmt.first.length(),
1682ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                tagfmt.first.data(), (int)tagfmt.second.length(),
1692ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                tagfmt.second.data());
1702ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
1712ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      ret = false;
1722ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    } else {
1732ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
174c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn    }
1752ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
176c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn
1772ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  {
1782ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    std::unordered_map<TagFmt, uint32_t>::const_iterator it;
1792ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    it = TagFmt2Idx.find(tagfmt);
1802ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (it != TagFmt2Idx.end()) {
1812ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if (verbose) {
1822ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        fprintf(stderr, errorFormat, it->second, (int)it->first.first.length(),
1832ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                it->first.first.data(), (int)it->first.second.length(),
1842ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                it->first.second.data(), tag, (int)tagfmt.first.length(),
1852ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                tagfmt.first.data(), (int)tagfmt.second.length(),
1862ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                tagfmt.second.data());
1872ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
1882ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      ret = false;
1892ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    } else {
1902ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      TagFmt2Idx.emplace(std::make_pair(tagfmt, tag));
191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1922ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1942ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  {
1952ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    std::unordered_map<MapString, uint32_t>::const_iterator it;
1962ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    it = Tag2Idx.find(tagfmt.first);
1972ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (!tagfmt.second.length() && (it != Tag2Idx.end())) {
1982ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      Tag2Idx.erase(it);
1992ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      it = Tag2Idx.end();
200c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn    }
2012ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (it == Tag2Idx.end()) {
2022ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      Tag2Idx.emplace(std::make_pair(tagfmt.first, tag));
2032ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    }
2042ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
205c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn
2062ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return ret;
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
209700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzynconst TagFmt* EventTagMap::find(uint32_t tag) const {
2102ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  std::unordered_map<uint32_t, TagFmt>::const_iterator it;
2112ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
2122ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  it = Idx2TagFmt.find(tag);
2132ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (it == Idx2TagFmt.end()) return NULL;
2142ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return &(it->second);
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
217c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzynint EventTagMap::find(TagFmt&& tagfmt) const {
2182ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  std::unordered_map<TagFmt, uint32_t>::const_iterator it;
2192ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
2202ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  it = TagFmt2Idx.find(std::move(tagfmt));
2212ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (it == TagFmt2Idx.end()) return -1;
2222ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return it->second;
223c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn}
224c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn
225c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzynint EventTagMap::find(MapString&& tag) const {
2262ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  std::unordered_map<MapString, uint32_t>::const_iterator it;
2272ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
2282ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  it = Tag2Idx.find(std::move(tag));
2292ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (it == Tag2Idx.end()) return -1;
2302ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return it->second;
231c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn}
232c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn
233700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// Scan one tag line.
234700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn//
235700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// "*pData" should be pointing to the first digit in the tag number.  On
236700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// successful return, it will be pointing to the last character in the
237700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// tag line (i.e. the character before the start of the next line).
238700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn//
2392a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn// lineNum = 0 removes verbose comments and requires us to cache the
2402a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn// content rather than make direct raw references since the content
2412a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn// will disappear after the call. A non-zero lineNum means we own the
2422a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn// data and it will outlive the call.
2432a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn//
244700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// Returns 0 on success, nonzero on failure.
245700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzynstatic int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
2462ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  char* cp;
2472ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  unsigned long val = strtoul(*pData, &cp, 10);
2482ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (cp == *pData) {
2492ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (lineNum) {
2502ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
251700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn    }
2522ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    errno = EINVAL;
2532ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return -1;
2542ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
255807e40ecc9786755e2f74a7a6a9b20c812588119Mark Salyzyn
2562ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  uint32_t tagIndex = val;
2572ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (tagIndex != val) {
2582ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (lineNum) {
2592ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
26070a83dc7b3bfd56098079c95de5d80daa9998a77Mark Salyzyn    }
2612ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    errno = ERANGE;
2622ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return -1;
2632ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
264dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
2652ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  while ((*++cp != '\n') && isspace(*cp)) {
2662ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
267dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
2682ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (*cp == '\n') {
2692ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (lineNum) {
2702ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
271700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn    }
2722ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    errno = EINVAL;
2732ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return -1;
2742ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
275dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
2762ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  const char* tag = cp;
2772ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // Determine whether "c" is a valid tag char.
2782ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  while (isalnum(*++cp) || (*cp == '_')) {
2792ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
2802ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t tagLen = cp - tag;
281dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
2822ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (!isspace(*cp)) {
2832ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (lineNum) {
2842ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      fprintf(stderr, OUT_TAG ": invalid tag chars on line %d\n", lineNum);
2857da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzyn    }
2862ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    errno = EINVAL;
2872ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return -1;
2882ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
2892ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
2902ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  while (isspace(*cp) && (*cp != '\n')) ++cp;
2912ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  const char* fmt = NULL;
2922ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t fmtLen = 0;
2932ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (*cp != '#') {
2942ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    fmt = cp;
2952ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    while ((*cp != '\n') && (*cp != '#')) ++cp;
2962ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    while ((cp > fmt) && isspace(*(cp - 1))) --cp;
2972ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    fmtLen = cp - fmt;
2982ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
2992ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
3002ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // KISS Only report identicals if they are global
3012ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // Ideally we want to check if there are identicals
3022ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // recorded for the same uid, but recording that
3032ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // unused detail in our database is too burdensome.
3042ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  bool verbose = true;
3052ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  while ((*cp != '#') && (*cp != '\n')) ++cp;
3062ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (*cp == '#') {
3072ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    do {
3082ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      ++cp;
3092ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    } while (isspace(*cp) && (*cp != '\n'));
3102ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
3112ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
3122ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
3132ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  while (*cp != '\n') ++cp;
314700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn#ifdef DEBUG
3152ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
316700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn#endif
3172ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  *pData = cp;
3182ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
3192ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (lineNum) {
3202ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (map->emplaceUnique(tagIndex,
3212ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                           TagFmt(std::make_pair(MapString(tag, tagLen),
3222ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                                 MapString(fmt, fmtLen))),
3232ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                           verbose)) {
3242ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      return 0;
325dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
3262ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  } else {
3272ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    // cache
3282ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (map->emplaceUnique(
3292ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn            tagIndex,
3302ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn            TagFmt(std::make_pair(MapString(std::string(tag, tagLen)),
3312ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                  MapString(std::string(fmt, fmtLen)))))) {
3322ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      return 0;
3332ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    }
3342ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
3352ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  errno = EMLINK;
3362ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return -1;
337dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
338dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
3397da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzynstatic const char* eventTagFiles[NUM_MAPS] = {
3402ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  EVENT_TAG_MAP_FILE, "/dev/event-log-tags",
3417da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzyn};
3427da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzyn
343700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// Parse the tags out of the file.
3447da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzynstatic int parseMapLines(EventTagMap* map, size_t which) {
3452ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  char* cp = static_cast<char*>(map->mapAddr[which]);
3462ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t len = map->mapLen[which];
3472ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  char* endp = cp + len;
348700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn
3492ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // insist on EOL at EOF; simplifies parsing and null-termination
3502ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (!len || (*(endp - 1) != '\n')) {
351700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn#ifdef DEBUG
3522ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    fprintf(stderr, OUT_TAG ": map file %zu[%zu] missing EOL on last line\n",
3532ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn            which, len);
354700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn#endif
3552ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (which) {  // do not propagate errors for other files
3562ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      return 0;
357dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
3582ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    errno = EINVAL;
3592ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return -1;
3602ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
361dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
3622ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  bool lineStart = true;
3632ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  int lineNum = 1;
3642ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  while (cp < endp) {
3652ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (*cp == '\n') {
3662ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      lineStart = true;
3672ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      lineNum++;
3682ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    } else if (lineStart) {
3692ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if (*cp == '#') {
3702ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        // comment; just scan to end
3712ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        lineStart = false;
3722ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      } else if (isdigit(*cp)) {
3732ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        // looks like a tag; scan it out
3742ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        if (scanTagLine(map, &cp, lineNum) != 0) {
3752ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          if (!which || (errno != EMLINK)) {
3762ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn            return -1;
3772ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          }
378dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
3792ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        lineNum++;  // we eat the '\n'
3802ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                    // leave lineStart==true
3812ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      } else if (isspace(*cp)) {
3822ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        // looks like leading whitespace; keep scanning
3832ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      } else {
3842ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        fprintf(stderr,
3852ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                OUT_TAG
3862ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                ": unexpected chars (0x%02x) in tag number on line %d\n",
3872ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                *cp, lineNum);
3882ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        errno = EINVAL;
3892ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        return -1;
3902ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
3912ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    } else {
3922ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      // this is a blank or comment line
393dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
3942ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    cp++;
3952ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
396dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
3972ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return 0;
398dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
399dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
400700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// Open the map file and allocate a structure to manage it.
401700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn//
402700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// We create a private mapping because we want to terminate the log tag
403700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// strings with '\0'.
404700fb87648047d23c947d9020fd35cd47621dc7cMark SalyzynLIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
4052ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  EventTagMap* newTagMap;
4062ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  off_t end[NUM_MAPS];
4072ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  int save_errno, fd[NUM_MAPS];
4082ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t which;
4097da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzyn
4102ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  memset(fd, -1, sizeof(fd));
4112ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  memset(end, 0, sizeof(end));
4127da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzyn
4132ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  for (which = 0; which < NUM_MAPS; ++which) {
4142ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    const char* tagfile = fileName ? fileName : eventTagFiles[which];
4157da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzyn
4162ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    fd[which] = open(tagfile, O_RDONLY | O_CLOEXEC);
4172ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (fd[which] < 0) {
4182ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if (!which) {
419700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn        save_errno = errno;
4202ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n", tagfile,
4212ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                strerror(save_errno));
4222ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        goto fail_errno;
4232ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
4242ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      continue;
42570a83dc7b3bfd56098079c95de5d80daa9998a77Mark Salyzyn    }
4262ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    end[which] = lseek(fd[which], 0L, SEEK_END);
4272ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    save_errno = errno;
4282ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    (void)lseek(fd[which], 0L, SEEK_SET);
4292ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (!which && (end[0] < 0)) {
4302ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n", tagfile,
4312ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn              strerror(save_errno));
4322ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      goto fail_close;
433dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
4342ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (fileName) break;  // Only allow one as specified
4352ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
4362ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
4372ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  newTagMap = new EventTagMap;
4382ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (newTagMap == NULL) {
4392ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    save_errno = errno;
4402ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    goto fail_close;
4412ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
4422ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
4432ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  for (which = 0; which < NUM_MAPS; ++which) {
4442ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (fd[which] >= 0) {
4452ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      newTagMap->mapAddr[which] =
4462ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          mmap(NULL, end[which], which ? PROT_READ : PROT_READ | PROT_WRITE,
4472ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn               which ? MAP_SHARED : MAP_PRIVATE, fd[which], 0);
4482ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      save_errno = errno;
4492ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      close(fd[which]);
4502ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      fd[which] = -1;
4512ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if ((newTagMap->mapAddr[which] != MAP_FAILED) &&
4522ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          (newTagMap->mapAddr[which] != NULL)) {
4532ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        newTagMap->mapLen[which] = end[which];
4542ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      } else if (!which) {
4552ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        const char* tagfile = fileName ? fileName : eventTagFiles[which];
456dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
4572ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n", tagfile,
4582ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                strerror(save_errno));
4592ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        goto fail_unmap;
4602ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
46170a83dc7b3bfd56098079c95de5d80daa9998a77Mark Salyzyn    }
4622ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
463dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
4642ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  for (which = 0; which < NUM_MAPS; ++which) {
4652ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (parseMapLines(newTagMap, which) != 0) {
4662ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      delete newTagMap;
4672ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      return NULL;
468530711b39e0447b0ce6824de936cedc294634e0eMark Salyzyn    }
4692ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
470530711b39e0447b0ce6824de936cedc294634e0eMark Salyzyn
4712ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return newTagMap;
4727da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzyn
4737da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzynfail_unmap:
4742ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  save_errno = EINVAL;
4752ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  delete newTagMap;
4767da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzynfail_close:
4772ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  for (which = 0; which < NUM_MAPS; ++which) close(fd[which]);
4787da7fab790ca6cfff2755cf8c86b20b739b919adMark Salyzynfail_errno:
4792ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  errno = save_errno;
4802ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return NULL;
481dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
482dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
483700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// Close the map.
484700fb87648047d23c947d9020fd35cd47621dc7cMark SalyzynLIBLOG_ABI_PUBLIC void android_closeEventTagMap(EventTagMap* map) {
4852ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (map) delete map;
486dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
487dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
4882a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn// Cache miss, go to logd to acquire a public reference.
4892a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn// Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
4902a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzynstatic const TagFmt* __getEventTag(EventTagMap* map, unsigned int tag) {
4912ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // call event tag service to arrange for a new tag
4922ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  char* buf = NULL;
4932ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // Can not use android::base::StringPrintf, asprintf + free instead.
4942ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  static const char command_template[] = "getEventTag id=%u";
4952ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  int ret = asprintf(&buf, command_template, tag);
4962ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (ret > 0) {
4972ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    // Add some buffer margin for an estimate of the full return content.
4982ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    char* cp;
4992ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    size_t size =
5002ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        ret - strlen(command_template) +
5012ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
5022ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (size > (size_t)ret) {
5032ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      cp = static_cast<char*>(realloc(buf, size));
5042ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if (cp) {
5052ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        buf = cp;
5062ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      } else {
5072ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        size = ret;
5082ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
5092ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    } else {
5102ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      size = ret;
5112ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    }
5122ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    // Ask event log tag service for an existing entry
5132ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (__send_log_msg(buf, size) >= 0) {
5142ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      buf[size - 1] = '\0';
5152ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      unsigned long val = strtoul(buf, &cp, 10);        // return size
5162ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
5172ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        ++cp;
5182ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        if (!scanTagLine(map, &cp, 0)) {
5192ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          free(buf);
5202ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          return map->find(tag);
5212a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn        }
5222ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
5232a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn    }
5242ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    free(buf);
5252ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
5262ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return NULL;
5272a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn}
5282a0044e4b00e7529dc8bc49464ec7b31b2e544f4Mark Salyzyn
529700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// Look up an entry in the map.
530700fb87648047d23c947d9020fd35cd47621dc7cMark SalyzynLIBLOG_ABI_PUBLIC const char* android_lookupEventTag_len(const EventTagMap* map,
5312ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                                         size_t* len,
532700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn                                                         unsigned int tag) {
5332ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (len) *len = 0;
5342ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  const TagFmt* str = map->find(tag);
5352ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (!str) {
5362ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    str = __getEventTag(const_cast<EventTagMap*>(map), tag);
5372ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
5382ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (!str) return NULL;
5392ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (len) *len = str->first.length();
5402ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return str->first.data();
541700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn}
542dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
543700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// Look up an entry in the map.
544700fb87648047d23c947d9020fd35cd47621dc7cMark SalyzynLIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
5452ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    const EventTagMap* map, size_t* len, unsigned int tag) {
5462ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (len) *len = 0;
5472ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  const TagFmt* str = map->find(tag);
5482ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (!str) {
5492ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    str = __getEventTag(const_cast<EventTagMap*>(map), tag);
5502ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
5512ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (!str) return NULL;
5522ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (len) *len = str->second.length();
5532ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return str->second.data();
554700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn}
555dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
556700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// This function is deprecated and replaced with android_lookupEventTag_len
557700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// since it will cause the map to change from Shared and backed by a file,
558700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// to Private Dirty and backed up by swap, albeit highly compressible. By
559700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn// deprecating this function everywhere, we save 100s of MB of memory space.
560700fb87648047d23c947d9020fd35cd47621dc7cMark SalyzynLIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
561700fb87648047d23c947d9020fd35cd47621dc7cMark Salyzyn                                                     unsigned int tag) {
5622ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t len;
5632ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  const char* tagStr = android_lookupEventTag_len(map, &len, tag);
5642ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
5652ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (!tagStr) return tagStr;
5662ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  char* cp = const_cast<char*>(tagStr);
5672ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  cp += len;
5682ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (*cp) *cp = '\0';  // Trigger copy on write :-( and why deprecated.
5692ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return tagStr;
570dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
571c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn
572c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn// Look up tagname, generate one if necessary, and return a tag
573c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark SalyzynLIBLOG_ABI_PUBLIC int android_lookupEventTagNum(EventTagMap* map,
574c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn                                                const char* tagname,
5752ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                                const char* format, int prio) {
5762ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  size_t len = strlen(tagname);
5772ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (!len) {
5782ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    errno = EINVAL;
5792ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return -1;
5802ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
5812ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
5822ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if ((prio != ANDROID_LOG_UNKNOWN) && (prio < ANDROID_LOG_SILENT) &&
5832ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      !__android_log_is_loggable_len(prio, tagname, len,
5842ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                     __android_log_is_debuggable()
5852ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                         ? ANDROID_LOG_VERBOSE
5862ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                         : ANDROID_LOG_DEBUG)) {
5872ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    errno = EPERM;
5882ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    return -1;
5892ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
5902ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
5912ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (!format) format = "";
5922ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  ssize_t fmtLen = strlen(format);
5932ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  int ret = map->find(TagFmt(
5942ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      std::make_pair(MapString(tagname, len), MapString(format, fmtLen))));
5952ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (ret != -1) return ret;
5962ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn
5972ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // call event tag service to arrange for a new tag
5982ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  char* buf = NULL;
5992ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // Can not use android::base::StringPrintf, asprintf + free instead.
6002ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  static const char command_template[] = "getEventTag name=%s format=\"%s\"";
6012ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  ret = asprintf(&buf, command_template, tagname, format);
6022ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (ret > 0) {
6032ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    // Add some buffer margin for an estimate of the full return content.
6042ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    char* cp;
6052ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    size_t size =
6062ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        ret - strlen(command_template) +
6072ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
6082ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (size > (size_t)ret) {
6092ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      cp = static_cast<char*>(realloc(buf, size));
6102ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if (cp) {
6112ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        buf = cp;
6122ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      } else {
6132ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        size = ret;
6142ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
6152ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    } else {
6162ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      size = ret;
617c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn    }
6182ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    // Ask event log tag service for an allocation
6192ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    if (__send_log_msg(buf, size) >= 0) {
6202ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      buf[size - 1] = '\0';
6212ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      unsigned long val = strtoul(buf, &cp, 10);        // return size
6222ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
6232ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        val = strtoul(cp + 1, &cp, 10);                 // allocated tag number
6242ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn        if ((val > 0) && (val < UINT32_MAX) && (*cp == '\t')) {
6252ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          free(buf);
6262ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          ret = val;
6272ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          // cache
6282ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          map->emplaceUnique(ret, TagFmt(std::make_pair(
6292ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                      MapString(std::string(tagname, len)),
6302ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn                                      MapString(std::string(format, fmtLen)))));
6312ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn          return ret;
632c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn        }
6332ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn      }
634c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn    }
6352ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn    free(buf);
6362ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  }
637c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn
6382ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  // Hail Mary
6392ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  ret = map->find(MapString(tagname, len));
6402ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  if (ret == -1) errno = ESRCH;
6412ed51d708eda64516ec79ac6397f690de38f0075Mark Salyzyn  return ret;
642c9e5f3716626fb8fcbde87c2f7324cc9292a0bd5Mark Salyzyn}
643