blob: afac9dfb676147fc492c7c96ddd25d34d0576a1c [file] [log] [blame]
Jon Medhurste31266f2014-08-04 15:47:44 +01001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2014-2015. All rights reserved.
Jon Medhurste31266f2014-08-04 15:47:44 +01003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "FSDriver.h"
10
11#include <fcntl.h>
12#include <regex.h>
13#include <sys/stat.h>
14#include <sys/types.h>
15#include <unistd.h>
16
Jon Medhurste31266f2014-08-04 15:47:44 +010017#include "DriverSource.h"
18#include "Logging.h"
Jon Medhurste31266f2014-08-04 15:47:44 +010019
Jon Medhurst96b56152014-10-30 18:01:15 +000020class FSCounter : public DriverCounter {
Jon Medhurste31266f2014-08-04 15:47:44 +010021public:
Jon Medhurst96b56152014-10-30 18:01:15 +000022 FSCounter(DriverCounter *next, char *name, char *path, const char *regex);
Jon Medhurste31266f2014-08-04 15:47:44 +010023 ~FSCounter();
24
Jon Medhurst96b56152014-10-30 18:01:15 +000025 const char *getPath() const { return mPath; }
26
Jon Medhurste31266f2014-08-04 15:47:44 +010027 int64_t read();
28
29private:
Jon Medhurst96b56152014-10-30 18:01:15 +000030 char *const mPath;
31 regex_t mReg;
32 bool mUseRegex;
Jon Medhurste31266f2014-08-04 15:47:44 +010033
34 // Intentionally unimplemented
35 FSCounter(const FSCounter &);
36 FSCounter &operator=(const FSCounter &);
37};
38
Jon Medhurst96b56152014-10-30 18:01:15 +000039FSCounter::FSCounter(DriverCounter *next, char *name, char *path, const char *regex) : DriverCounter(next, name), mPath(path), mUseRegex(regex != NULL) {
40 if (mUseRegex) {
41 int result = regcomp(&mReg, regex, REG_EXTENDED);
Jon Medhurste31266f2014-08-04 15:47:44 +010042 if (result != 0) {
43 char buf[128];
Jon Medhurst96b56152014-10-30 18:01:15 +000044 regerror(result, &mReg, buf, sizeof(buf));
Jon Medhurstb1d07442015-05-08 12:04:18 +010045 logg->logError("Invalid regex '%s': %s", regex, buf);
Jon Medhurste31266f2014-08-04 15:47:44 +010046 handleException();
47 }
48 }
49}
50
51FSCounter::~FSCounter() {
Jon Medhurst96b56152014-10-30 18:01:15 +000052 free(mPath);
53 if (mUseRegex) {
54 regfree(&mReg);
Jon Medhurste31266f2014-08-04 15:47:44 +010055 }
56}
57
58int64_t FSCounter::read() {
59 int64_t value;
Jon Medhurst96b56152014-10-30 18:01:15 +000060 if (mUseRegex) {
Jon Medhurste31266f2014-08-04 15:47:44 +010061 char buf[4096];
62 size_t pos = 0;
Jon Medhurst96b56152014-10-30 18:01:15 +000063 const int fd = open(mPath, O_RDONLY | O_CLOEXEC);
Jon Medhurste31266f2014-08-04 15:47:44 +010064 if (fd < 0) {
65 goto fail;
66 }
67 while (pos < sizeof(buf) - 1) {
68 const ssize_t bytes = ::read(fd, buf + pos, sizeof(buf) - pos - 1);
69 if (bytes < 0) {
70 goto fail;
71 } else if (bytes == 0) {
72 break;
73 }
74 pos += bytes;
75 }
76 close(fd);
77 buf[pos] = '\0';
78
79 regmatch_t match[2];
Jon Medhurst96b56152014-10-30 18:01:15 +000080 int result = regexec(&mReg, buf, 2, match, 0);
Jon Medhurste31266f2014-08-04 15:47:44 +010081 if (result != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010082 // No match
83 return 0;
Jon Medhurste31266f2014-08-04 15:47:44 +010084 }
85
86 if (match[1].rm_so < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010087 value = 1;
88 } else {
89 errno = 0;
90 value = strtoll(buf + match[1].rm_so, NULL, 0);
91 if (errno != 0) {
92 logg->logError("Parsing %s failed: %s", mPath, strerror(errno));
93 handleException();
94 }
Jon Medhurste31266f2014-08-04 15:47:44 +010095 }
96 } else {
Jon Medhurst96b56152014-10-30 18:01:15 +000097 if (DriverSource::readInt64Driver(mPath, &value) != 0) {
Jon Medhurste31266f2014-08-04 15:47:44 +010098 goto fail;
99 }
100 }
101 return value;
102
103 fail:
Jon Medhurstb1d07442015-05-08 12:04:18 +0100104 logg->logError("Unable to read %s", mPath);
Jon Medhurste31266f2014-08-04 15:47:44 +0100105 handleException();
106}
107
Jon Medhurst96b56152014-10-30 18:01:15 +0000108FSDriver::FSDriver() {
Jon Medhurste31266f2014-08-04 15:47:44 +0100109}
110
111FSDriver::~FSDriver() {
Jon Medhurste31266f2014-08-04 15:47:44 +0100112}
113
Jon Medhurst96b56152014-10-30 18:01:15 +0000114void FSDriver::readEvents(mxml_node_t *const xml) {
Jon Medhurste31266f2014-08-04 15:47:44 +0100115 mxml_node_t *node = xml;
116 while (true) {
117 node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
118 if (node == NULL) {
119 break;
120 }
121 const char *counter = mxmlElementGetAttr(node, "counter");
Jon Medhurst96b56152014-10-30 18:01:15 +0000122 if (counter == NULL) {
123 continue;
Jon Medhurste31266f2014-08-04 15:47:44 +0100124 }
Jon Medhurste31266f2014-08-04 15:47:44 +0100125
Jon Medhurst96b56152014-10-30 18:01:15 +0000126 if (counter[0] == '/') {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100127 logg->logError("Old style filesystem counter (%s) detected, please create a new unique counter value and move the filename into the path attribute, see events-Filesystem.xml for examples", counter);
Jon Medhurst96b56152014-10-30 18:01:15 +0000128 handleException();
Jon Medhurste31266f2014-08-04 15:47:44 +0100129 }
Jon Medhurste31266f2014-08-04 15:47:44 +0100130
Jon Medhurst96b56152014-10-30 18:01:15 +0000131 if (strncmp(counter, "filesystem_", 11) != 0) {
132 continue;
Jon Medhurste31266f2014-08-04 15:47:44 +0100133 }
Jon Medhurste31266f2014-08-04 15:47:44 +0100134
Jon Medhurst96b56152014-10-30 18:01:15 +0000135 const char *path = mxmlElementGetAttr(node, "path");
136 if (path == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100137 logg->logError("The filesystem counter %s is missing the required path attribute", counter);
Jon Medhurst96b56152014-10-30 18:01:15 +0000138 handleException();
139 }
140 const char *regex = mxmlElementGetAttr(node, "regex");
141 setCounters(new FSCounter(getCounters(), strdup(counter), strdup(path), regex));
Jon Medhurste31266f2014-08-04 15:47:44 +0100142 }
143}
144
Jon Medhurste31266f2014-08-04 15:47:44 +0100145int FSDriver::writeCounters(mxml_node_t *root) const {
146 int count = 0;
Jon Medhurst96b56152014-10-30 18:01:15 +0000147 for (FSCounter *counter = static_cast<FSCounter *>(getCounters()); counter != NULL; counter = static_cast<FSCounter *>(counter->getNext())) {
148 if (access(counter->getPath(), R_OK) == 0) {
Jon Medhurste31266f2014-08-04 15:47:44 +0100149 mxml_node_t *node = mxmlNewElement(root, "counter");
150 mxmlElementSetAttr(node, "name", counter->getName());
151 ++count;
152 }
153 }
154
155 return count;
156}