tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / tools / gator / daemon / FSDriver.cpp
1 /**
2  * Copyright (C) ARM Limited 2014. 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(__FILE__, __LINE__, "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                         regerror(result, &mReg, buf, sizeof(buf));
83                         logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", mPath, buf);
84                         handleException();
85                 }
86
87                 if (match[1].rm_so < 0) {
88                         logg->logError(__FILE__, __LINE__, "Parsing %s failed", mPath);
89                         handleException();
90                 }
91
92                 errno = 0;
93                 value = strtoll(buf + match[1].rm_so, NULL, 0);
94                 if (errno != 0) {
95                         logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", mPath, strerror(errno));
96                         handleException();
97                 }
98         } else {
99                 if (DriverSource::readInt64Driver(mPath, &value) != 0) {
100                         goto fail;
101                 }
102         }
103         return value;
104
105  fail:
106         logg->logError(__FILE__, __LINE__, "Unable to read %s", mPath);
107         handleException();
108 }
109
110 FSDriver::FSDriver() {
111 }
112
113 FSDriver::~FSDriver() {
114 }
115
116 void FSDriver::readEvents(mxml_node_t *const xml) {
117         mxml_node_t *node = xml;
118         while (true) {
119                 node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
120                 if (node == NULL) {
121                         break;
122                 }
123                 const char *counter = mxmlElementGetAttr(node, "counter");
124                 if (counter == NULL) {
125                         continue;
126                 }
127
128                 if (counter[0] == '/') {
129                         logg->logError(__FILE__, __LINE__, "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);
130                         handleException();
131                 }
132
133                 if (strncmp(counter, "filesystem_", 11) != 0) {
134                         continue;
135                 }
136
137                 const char *path = mxmlElementGetAttr(node, "path");
138                 if (path == NULL) {
139                         logg->logError(__FILE__, __LINE__, "The filesystem counter %s is missing the required path attribute", counter);
140                         handleException();
141                 }
142                 const char *regex = mxmlElementGetAttr(node, "regex");
143                 setCounters(new FSCounter(getCounters(), strdup(counter), strdup(path), regex));
144         }
145 }
146
147 int FSDriver::writeCounters(mxml_node_t *root) const {
148         int count = 0;
149         for (FSCounter *counter = static_cast<FSCounter *>(getCounters()); counter != NULL; counter = static_cast<FSCounter *>(counter->getNext())) {
150                 if (access(counter->getPath(), R_OK) == 0) {
151                         mxml_node_t *node = mxmlNewElement(root, "counter");
152                         mxmlElementSetAttr(node, "name", counter->getName());
153                         ++count;
154                 }
155         }
156
157         return count;
158 }