gator: Version 5.21.1
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / FSDriver.cpp
1 /**
2  * Copyright (C) ARM Limited 2014-2015. All rights reserved.
3  *
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
17 #include "DriverSource.h"
18 #include "Logging.h"
19
20 class FSCounter : public DriverCounter {
21 public:
22         FSCounter(DriverCounter *next, char *name, char *path, const char *regex);
23         ~FSCounter();
24
25         const char *getPath() const { return mPath; }
26
27         int64_t read();
28
29 private:
30         char *const mPath;
31         regex_t mReg;
32         bool mUseRegex;
33
34         // Intentionally unimplemented
35         FSCounter(const FSCounter &);
36         FSCounter &operator=(const FSCounter &);
37 };
38
39 FSCounter::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);
42                 if (result != 0) {
43                         char buf[128];
44                         regerror(result, &mReg, buf, sizeof(buf));
45                         logg->logError("Invalid regex '%s': %s", regex, buf);
46                         handleException();
47                 }
48         }
49 }
50
51 FSCounter::~FSCounter() {
52         free(mPath);
53         if (mUseRegex) {
54                 regfree(&mReg);
55         }
56 }
57
58 int64_t FSCounter::read() {
59         int64_t value;
60         if (mUseRegex) {
61                 char buf[4096];
62                 size_t pos = 0;
63                 const int fd = open(mPath, O_RDONLY | O_CLOEXEC);
64                 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];
80                 int result = regexec(&mReg, buf, 2, match, 0);
81                 if (result != 0) {
82                         // No match
83                         return 0;
84                 }
85
86                 if (match[1].rm_so < 0) {
87                         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                         }
95                 }
96         } else {
97                 if (DriverSource::readInt64Driver(mPath, &value) != 0) {
98                         goto fail;
99                 }
100         }
101         return value;
102
103  fail:
104         logg->logError("Unable to read %s", mPath);
105         handleException();
106 }
107
108 FSDriver::FSDriver() {
109 }
110
111 FSDriver::~FSDriver() {
112 }
113
114 void FSDriver::readEvents(mxml_node_t *const xml) {
115         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");
122                 if (counter == NULL) {
123                         continue;
124                 }
125
126                 if (counter[0] == '/') {
127                         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);
128                         handleException();
129                 }
130
131                 if (strncmp(counter, "filesystem_", 11) != 0) {
132                         continue;
133                 }
134
135                 const char *path = mxmlElementGetAttr(node, "path");
136                 if (path == NULL) {
137                         logg->logError("The filesystem counter %s is missing the required path attribute", counter);
138                         handleException();
139                 }
140                 const char *regex = mxmlElementGetAttr(node, "regex");
141                 setCounters(new FSCounter(getCounters(), strdup(counter), strdup(path), regex));
142         }
143 }
144
145 int FSDriver::writeCounters(mxml_node_t *root) const {
146         int count = 0;
147         for (FSCounter *counter = static_cast<FSCounter *>(getCounters()); counter != NULL; counter = static_cast<FSCounter *>(counter->getNext())) {
148                 if (access(counter->getPath(), R_OK) == 0) {
149                         mxml_node_t *node = mxmlNewElement(root, "counter");
150                         mxmlElementSetAttr(node, "name", counter->getName());
151                         ++count;
152                 }
153         }
154
155         return count;
156 }