make timing configurable, sleep after each file
Stefan Schuermans

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 &paramStr);
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 &paramStr) {
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
 
... ...
@@ -0,0 +1,3 @@
1
+sleepTime 42.42e-3
2
+waitFactor 5.5
3
+waitTime 23.23
... ...
@@ -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