Stefan Schuermans commited on 2020-09-19 15:03:32
Showing 11 changed files, with 248 additions and 18 deletions.
... | ... |
@@ -103,6 +103,14 @@ Syntax: |
103 | 103 |
* `<niceness value>`: Linux niceness value for daemon process, |
104 | 104 |
`19` for nicest (lowest CPU priority) |
105 | 105 |
* `idle`: set I/O priority class to idle |
106 |
+ * sleep time after each file: `sleepTime <seconds>` |
|
107 |
+ * range 0 - 1 s, default 1e-6 s |
|
108 |
+ * wait time factor: `waitFactor <floating-point factor>` |
|
109 |
+ * how long to wait after each tree traversal relative to the duration of |
|
110 |
+ the traversal |
|
111 |
+ * range 0 - 1000, default 10 |
|
112 |
+ * additional wait time after each tree traversal: `waitTime <seconds>` |
|
113 |
+ * range 0 - 3600 s, default 1 s |
|
106 | 114 |
* owership and permission configuration: |
107 | 115 |
`tree <user> <group> <permissions> <directory>` |
108 | 116 |
* `<user>`: User name to set as user/owner, `-` to not change the user/owner. |
... | ... |
@@ -3,6 +3,7 @@ add_library( |
3 | 3 |
STATIC |
4 | 4 |
include/permissioner/Callback.h |
5 | 5 |
include/permissioner/Config.h |
6 |
+ include/permissioner/Float.h |
|
6 | 7 |
include/permissioner/Group.h |
7 | 8 |
include/permissioner/Nice.h |
8 | 9 |
include/permissioner/Permissions.h |
... | ... |
@@ -11,6 +12,7 @@ add_library( |
11 | 12 |
include/permissioner/User.h |
12 | 13 |
src/Callback.cpp |
13 | 14 |
src/Config.cpp |
15 |
+ src/Float.cpp |
|
14 | 16 |
src/Group.cpp |
15 | 17 |
src/Nice.cpp |
16 | 18 |
src/Permissions.cpp |
... | ... |
@@ -8,6 +8,7 @@ |
8 | 8 |
#define CONFIG_H |
9 | 9 |
|
10 | 10 |
#include <permissioner/Callback.h> |
11 |
+#include <permissioner/Float.h> |
|
11 | 12 |
#include <permissioner/Nice.h> |
12 | 13 |
#include <permissioner/Tree.h> |
13 | 14 |
|
... | ... |
@@ -18,6 +19,8 @@ |
18 | 19 |
/// configuration file |
19 | 20 |
class Config { |
20 | 21 |
public: |
22 |
+ Config(); |
|
23 |
+ |
|
21 | 24 |
/** |
22 | 25 |
* @brief parse configuration file |
23 | 26 |
* @param[in] configFileName name of configuation file |
... | ... |
@@ -28,6 +31,15 @@ public: |
28 | 31 |
/// return nice settings |
29 | 32 |
Nice const & getNice() const; |
30 | 33 |
|
34 |
+ /// return sleep time setting |
|
35 |
+ Float const & getSleepTime() const; |
|
36 |
+ |
|
37 |
+ /// return wait factor setting |
|
38 |
+ Float const & getWaitFactor() const; |
|
39 |
+ |
|
40 |
+ /// return wait time setting |
|
41 |
+ Float const & getWaitTime() const; |
|
42 |
+ |
|
31 | 43 |
/// return trees |
32 | 44 |
TreeMap const & getTrees() const; |
33 | 45 |
|
... | ... |
@@ -40,6 +52,9 @@ public: |
40 | 52 |
|
41 | 53 |
protected: |
42 | 54 |
Nice nice; |
55 |
+ Float sleepTime; |
|
56 |
+ Float waitFactor; |
|
57 |
+ Float waitTime; |
|
43 | 58 |
TreeMap trees; |
44 | 59 |
}; |
45 | 60 |
|
... | ... |
@@ -0,0 +1,41 @@ |
1 |
+/** |
|
2 |
+ * Permissioner: set file ownerships and permissions |
|
3 |
+ * Copyright 2020: Stefan Schuermans, Aachen, Germany <stefan@schuermans.info> |
|
4 |
+ * Copyleft: GNU GENERAL PUBLIC LICENSE version 3 (see LICENSE) |
|
5 |
+ */ |
|
6 |
+ |
|
7 |
+#ifndef FLOAT_H |
|
8 |
+#define FLOAT_H |
|
9 |
+ |
|
10 |
+#include <string> |
|
11 |
+ |
|
12 |
+/// a floating point number in the settings |
|
13 |
+class Float { |
|
14 |
+public: |
|
15 |
+ /** |
|
16 |
+ * @brief initialize floating-point setting |
|
17 |
+ * @param[in] name name of value for error messages |
|
18 |
+ * @param[in] defVal default value |
|
19 |
+ * @param[in] minVal minimum value |
|
20 |
+ * @param[in] maxVal maximum value |
|
21 |
+ */ |
|
22 |
+ Float(std::string const &name, float minVal, float maxVal, float defVal); |
|
23 |
+ |
|
24 |
+ /** |
|
25 |
+ * @brief parse floating-point value parameter |
|
26 |
+ * @param[in] parmStr parameter string |
|
27 |
+ * @throws std::exception if something goes wrong |
|
28 |
+ */ |
|
29 |
+ void parseParams(std::string const ¶mStr); |
|
30 |
+ |
|
31 |
+ /// return floating-point value |
|
32 |
+ float get() const; |
|
33 |
+ |
|
34 |
+protected: |
|
35 |
+ std::string name; ///< name for error messages |
|
36 |
+ float minVal; ///< minimum value |
|
37 |
+ float maxVal; ///< maximum value |
|
38 |
+ float val; ///< configured value |
|
39 |
+}; |
|
40 |
+ |
|
41 |
+#endif // #ifndef FLOAT_H |
... | ... |
@@ -42,6 +42,27 @@ public: |
42 | 42 |
*/ |
43 | 43 |
static int str2intRange(std::string const &str, int minVal, int maxVal, |
44 | 44 |
std::string const &name); |
45 |
+ |
|
46 |
+ /** |
|
47 |
+ * @brief convert a string to a floating-point value |
|
48 |
+ * @param[in] str string on which to operate |
|
49 |
+ * @param[in] name filed name for exception |
|
50 |
+ * @return floating-point value |
|
51 |
+ * @throws std::exception if something goes wrong |
|
52 |
+ */ |
|
53 |
+ static float str2float(std::string const &str, std::string const &name); |
|
54 |
+ |
|
55 |
+ /** |
|
56 |
+ * @brief convert a string to a floating-point value and check range |
|
57 |
+ * @param[in] str string on which to operate |
|
58 |
+ * @param[in] minVal minium value |
|
59 |
+ * @param[in] maxVal maxium value |
|
60 |
+ * @param[in] name filed name for exception |
|
61 |
+ * @return floating-point value |
|
62 |
+ * @throws std::exception if something goes wrong |
|
63 |
+ */ |
|
64 |
+ static float str2floatRange(std::string const &str, float minVal, |
|
65 |
+ float maxVal, std::string const &name); |
|
45 | 66 |
}; |
46 | 67 |
|
47 | 68 |
#endif // #ifndef STRING_UTILS_H |
... | ... |
@@ -7,6 +7,7 @@ |
7 | 7 |
#include <permissioner/Config.h> |
8 | 8 |
|
9 | 9 |
#include <permissioner/Callback.h> |
10 |
+#include <permissioner/Float.h> |
|
10 | 11 |
#include <permissioner/StringUtils.h> |
11 | 12 |
#include <permissioner/Tree.h> |
12 | 13 |
|
... | ... |
@@ -17,6 +18,11 @@ |
17 | 18 |
#include <stdexcept> |
18 | 19 |
#include <string> |
19 | 20 |
|
21 |
+Config::Config() |
|
22 |
+ : sleepTime("sleepTime", 0.0f, 1.0f, 1.0e-6f), |
|
23 |
+ waitFactor("waitFactor", 0.0f, 1.0e3f, 10.0f), |
|
24 |
+ waitTime("waitTime", 0.0f, 3.6e3f, 1.0f) {} |
|
25 |
+ |
|
20 | 26 |
void Config::parseFile(std::string const &configFileName) { |
21 | 27 |
std::ifstream configFile(configFileName, std::ios::in); |
22 | 28 |
if (!configFile.is_open()) { |
... | ... |
@@ -41,6 +47,18 @@ void Config::parseFile(std::string const &configFileName) { |
41 | 47 |
nice.parseParams(line.substr(pos)); |
42 | 48 |
continue; |
43 | 49 |
} |
50 |
+ if (typeStr == "sleepTime") { |
|
51 |
+ sleepTime.parseParams(line.substr(pos)); |
|
52 |
+ continue; |
|
53 |
+ } |
|
54 |
+ if (typeStr == "waitFactor") { |
|
55 |
+ waitFactor.parseParams(line.substr(pos)); |
|
56 |
+ continue; |
|
57 |
+ } |
|
58 |
+ if (typeStr == "waitTime") { |
|
59 |
+ waitTime.parseParams(line.substr(pos)); |
|
60 |
+ continue; |
|
61 |
+ } |
|
44 | 62 |
if (typeStr == "tree") { |
45 | 63 |
Tree tree; |
46 | 64 |
tree.parseParams(line.substr(pos)); |
... | ... |
@@ -54,13 +72,15 @@ void Config::parseFile(std::string const &configFileName) { |
54 | 72 |
} |
55 | 73 |
} |
56 | 74 |
|
57 |
-Nice const & Config::getNice() const { |
|
58 |
- return nice; |
|
59 |
-} |
|
75 |
+Nice const &Config::getNice() const { return nice; } |
|
60 | 76 |
|
61 |
-TreeMap const & Config::getTrees() const { |
|
62 |
- return trees; |
|
63 |
-} |
|
77 |
+Float const &Config::getSleepTime() const { return sleepTime; } |
|
78 |
+ |
|
79 |
+Float const &Config::getWaitFactor() const { return waitFactor; } |
|
80 |
+ |
|
81 |
+Float const &Config::getWaitTime() const { return waitTime; } |
|
82 |
+ |
|
83 |
+TreeMap const &Config::getTrees() const { return trees; } |
|
64 | 84 |
|
65 | 85 |
bool Config::setPermissions(Callback &callback) const { |
66 | 86 |
for (auto const &path_tree : trees) { |
... | ... |
@@ -0,0 +1,31 @@ |
1 |
+/** |
|
2 |
+ * Permissioner: set file ownerships and permissions |
|
3 |
+ * Copyright 2020: Stefan Schuermans, Aachen, Germany <stefan@schuermans.info> |
|
4 |
+ * Copyleft: GNU GENERAL PUBLIC LICENSE version 3 (see LICENSE) |
|
5 |
+ */ |
|
6 |
+ |
|
7 |
+#include <permissioner/Float.h> |
|
8 |
+ |
|
9 |
+#include <permissioner/StringUtils.h> |
|
10 |
+ |
|
11 |
+#include <sstream> |
|
12 |
+#include <stdexcept> |
|
13 |
+#include <string> |
|
14 |
+ |
|
15 |
+Float::Float(std::string const &name, float minVal, float maxVal, float defVal) |
|
16 |
+ : name(name), minVal(minVal), maxVal(maxVal), val(defVal) {} |
|
17 |
+ |
|
18 |
+void Float::parseParams(std::string const ¶mStr) { |
|
19 |
+ // format of paramStr is: <floating-point-value> |
|
20 |
+ std::string valStr; |
|
21 |
+ std::string::size_type pos = 0; |
|
22 |
+ StringUtils::getNextField(paramStr, pos, valStr, name); |
|
23 |
+ if (pos < paramStr.length()) { |
|
24 |
+ std::stringstream msg; |
|
25 |
+ msg << "too many fields for \"" << name << "\" in \"" << paramStr << "\""; |
|
26 |
+ throw std::runtime_error(msg.str()); |
|
27 |
+ } |
|
28 |
+ val = StringUtils::str2floatRange(valStr, minVal, maxVal, name); |
|
29 |
+} |
|
30 |
+ |
|
31 |
+float Float::get() const { return val; } |
... | ... |
@@ -58,3 +58,28 @@ int StringUtils::str2intRange(std::string const &str, int minVal, int maxVal, |
58 | 58 |
} |
59 | 59 |
return val; |
60 | 60 |
} |
61 |
+ |
|
62 |
+float StringUtils::str2float(std::string const &str, std::string const &name) { |
|
63 |
+ char const *c_str = str.c_str(); |
|
64 |
+ char *end; |
|
65 |
+ float val = strtof(c_str, &end); |
|
66 |
+ if (end == c_str || *end != 0) { |
|
67 |
+ std::stringstream msg; |
|
68 |
+ msg << "invalid floating-point value \"" << str << "\" for <" << name |
|
69 |
+ << "> field"; |
|
70 |
+ throw std::runtime_error(msg.str()); |
|
71 |
+ } |
|
72 |
+ return val; |
|
73 |
+} |
|
74 |
+ |
|
75 |
+float StringUtils::str2floatRange(std::string const &str, float minVal, |
|
76 |
+ float maxVal, std::string const &name) { |
|
77 |
+ float val = str2float(str, name); |
|
78 |
+ if (val < minVal || val > maxVal) { |
|
79 |
+ std::stringstream msg; |
|
80 |
+ msg << "value " << val << " of <" << name << "> field out of range " |
|
81 |
+ << minVal << " - " << maxVal; |
|
82 |
+ throw std::runtime_error(msg.str()); |
|
83 |
+ } |
|
84 |
+ return val; |
|
85 |
+} |
... | ... |
@@ -18,20 +18,24 @@ |
18 | 18 |
class DaemonCallback : public Callback { |
19 | 19 |
public: |
20 | 20 |
DaemonCallback() : go_on(true) {} |
21 |
- bool callback() { return go_on; } |
|
21 |
+ bool callback(); |
|
22 |
+ std::chrono::duration<float, std::ratio<1>> sleepTime; |
|
23 |
+ template <class Rep, class Period> |
|
24 |
+ bool iterativeSleep(std::chrono::duration<Rep, Period> duration) const; |
|
22 | 25 |
bool go_on; |
23 | 26 |
}; |
24 | 27 |
|
25 |
-DaemonCallback daemonCallback; |
|
26 |
- |
|
27 |
-void sighandler(int) { daemonCallback.go_on = false; } |
|
28 |
+bool DaemonCallback::callback() { |
|
29 |
+ iterativeSleep(sleepTime); |
|
30 |
+ return go_on; |
|
31 |
+} |
|
28 | 32 |
|
29 | 33 |
// iterative sleep, watching go_on, returns whether sleep completed |
30 | 34 |
template <class Rep, class Period> |
31 |
-bool iterativeSleep(std::chrono::duration<Rep, Period> duration, |
|
32 |
- DaemonCallback &daemonCallback) { |
|
33 |
- std::chrono::duration<int, std::milli> zero(0), step(100); |
|
34 |
- while (duration > zero && daemonCallback.go_on) { |
|
35 |
+bool DaemonCallback::iterativeSleep( |
|
36 |
+ std::chrono::duration<Rep, Period> duration) const { |
|
37 |
+ const std::chrono::duration<int, std::milli> zero(0), step(100); |
|
38 |
+ while (duration > zero && go_on) { |
|
35 | 39 |
if (duration >= step) { |
36 | 40 |
std::this_thread::sleep_for(step); |
37 | 41 |
duration -= step; |
... | ... |
@@ -43,6 +47,10 @@ bool iterativeSleep(std::chrono::duration<Rep, Period> duration, |
43 | 47 |
return duration <= zero; |
44 | 48 |
} |
45 | 49 |
|
50 |
+DaemonCallback daemonCallback; |
|
51 |
+ |
|
52 |
+void sighandler(int) { daemonCallback.go_on = false; } |
|
53 |
+ |
|
46 | 54 |
int main(int argc, char const **argv) { |
47 | 55 |
if (argc != 2) { |
48 | 56 |
std::cerr << "usage: " << argv[0] << " <config file>" << std::endl; |
... | ... |
@@ -59,6 +67,13 @@ int main(int argc, char const **argv) { |
59 | 67 |
return EXIT_FAILURE; |
60 | 68 |
} |
61 | 69 |
|
70 |
+ // get timing from config |
|
71 |
+ std::chrono::duration<float, std::ratio<1>> sleepTime( |
|
72 |
+ config.getSleepTime().get()); |
|
73 |
+ float waitFactor = config.getWaitFactor().get(); |
|
74 |
+ std::chrono::duration<float, std::ratio<1>> waitTime( |
|
75 |
+ config.getWaitTime().get()); |
|
76 |
+ |
|
62 | 77 |
// catch signals to exit properly on Ctrl-C and so on |
63 | 78 |
signal(SIGINT, sighandler); |
64 | 79 |
signal(SIGPIPE, sighandler); |
... | ... |
@@ -70,6 +85,9 @@ int main(int argc, char const **argv) { |
70 | 85 |
// set nicecess of process |
71 | 86 |
config.getNice().apply(); |
72 | 87 |
|
88 |
+ // set sleep time after each file in daemon callback |
|
89 |
+ daemonCallback.sleepTime = sleepTime; |
|
90 |
+ |
|
73 | 91 |
// continuously set ownership and permissions |
74 | 92 |
int ret = EXIT_SUCCESS; |
75 | 93 |
while (daemonCallback.go_on) { |
... | ... |
@@ -92,10 +110,8 @@ int main(int argc, char const **argv) { |
92 | 110 |
std::cout << "permissionerd (" << configFileName << "): took " |
93 | 111 |
<< duration.count() << " s" << std::endl; |
94 | 112 |
|
95 |
- // sleep 10 times as long as the work took plus one second |
|
96 |
- auto sleep_time = |
|
97 |
- 10 * duration + std::chrono::duration<int, std::ratio<1>>(1); |
|
98 |
- if (! iterativeSleep(sleep_time, daemonCallback)) { |
|
113 |
+ // wait after tree traversal |
|
114 |
+ if (!daemonCallback.iterativeSleep(waitFactor * duration + waitTime)) { |
|
99 | 115 |
break; |
100 | 116 |
} |
101 | 117 |
|
... | ... |
@@ -34,6 +34,25 @@ int testEmpty() { |
34 | 34 |
ret = EXIT_FAILURE; |
35 | 35 |
} |
36 | 36 |
|
37 |
+ float sleepTime = config.getSleepTime().get(); |
|
38 |
+ if (sleepTime != 1.0e-6f) { |
|
39 |
+ std::cerr << "unexpected sleepTime " << sleepTime << ", expected " |
|
40 |
+ << 1.0e-6f << std::endl; |
|
41 |
+ ret = EXIT_FAILURE; |
|
42 |
+ } |
|
43 |
+ float waitFactor = config.getWaitFactor().get(); |
|
44 |
+ if (waitFactor != 10.0f) { |
|
45 |
+ std::cerr << "unexpected waitFactor " << waitFactor << ", expected " |
|
46 |
+ << 10.0f << std::endl; |
|
47 |
+ ret = EXIT_FAILURE; |
|
48 |
+ } |
|
49 |
+ float waitTime = config.getWaitTime().get(); |
|
50 |
+ if (waitTime != 1.0f) { |
|
51 |
+ std::cerr << "unexpected waitTime " << waitTime << ", expected " << 1.0f |
|
52 |
+ << std::endl; |
|
53 |
+ ret = EXIT_FAILURE; |
|
54 |
+ } |
|
55 |
+ |
|
37 | 56 |
TreeMap const &treeMap = config.getTrees(); |
38 | 57 |
if (treeMap.size() != 0) { |
39 | 58 |
std::cerr << "unexpected trees: " << treeMap.size() << std::endl; |
... | ... |
@@ -103,6 +122,34 @@ int testNice() { |
103 | 122 |
return ret; |
104 | 123 |
} |
105 | 124 |
|
125 |
+int testSleepWait() { |
|
126 |
+ Config config; |
|
127 |
+ config.parseFile("sleep_wait.cfg"); |
|
128 |
+ |
|
129 |
+ int ret = EXIT_SUCCESS; |
|
130 |
+ |
|
131 |
+ float sleepTime = config.getSleepTime().get(); |
|
132 |
+ if (sleepTime != 42.42e-3f) { |
|
133 |
+ std::cerr << "unexpected sleepTime " << sleepTime << ", expected " |
|
134 |
+ << 42.42e-3f << std::endl; |
|
135 |
+ ret = EXIT_FAILURE; |
|
136 |
+ } |
|
137 |
+ float waitFactor = config.getWaitFactor().get(); |
|
138 |
+ if (waitFactor != 5.5f) { |
|
139 |
+ std::cerr << "unexpected waitFactor " << waitFactor << ", expected " |
|
140 |
+ << 5.5f << std::endl; |
|
141 |
+ ret = EXIT_FAILURE; |
|
142 |
+ } |
|
143 |
+ float waitTime = config.getWaitTime().get(); |
|
144 |
+ if (waitTime != 23.23f) { |
|
145 |
+ std::cerr << "unexpected waitTime " << waitTime << ", expected " << 23.23f |
|
146 |
+ << std::endl; |
|
147 |
+ ret = EXIT_FAILURE; |
|
148 |
+ } |
|
149 |
+ |
|
150 |
+ return ret; |
|
151 |
+} |
|
152 |
+ |
|
106 | 153 |
bool checkTrees(TreeMap const &treeMap, std::string const &rel_path, |
107 | 154 |
boost::optional<std::string> user, |
108 | 155 |
boost::optional<std::string> group, mode_t setMode, |
... | ... |
@@ -195,6 +242,7 @@ int main() { |
195 | 242 |
int ret = EXIT_SUCCESS; |
196 | 243 |
merge_ret(ret, testEmpty()); |
197 | 244 |
merge_ret(ret, testNice()); |
245 |
+ merge_ret(ret, testSleepWait()); |
|
198 | 246 |
merge_ret(ret, testTrees()); |
199 | 247 |
return ret; |
200 | 248 |
} |
201 | 249 |