Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief unit plugin
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : #include "unit.h"
11 : #include <kdberrors.h>
12 : #include <kdbhelper.h>
13 : #include <kdbtypes.h>
14 : #include <stdio.h>
15 : #include <stdlib.h>
16 :
17 : // @param input string, of which possibly occurring spaces are removed
18 : static void deblank (char * input)
19 : {
20 : int count = 0;
21 :
22 144 : for (int i = 0; input[i]; i++)
23 : {
24 144 : if (input[i] != ' ')
25 : {
26 130 : input[count++] = input[i];
27 : }
28 : }
29 :
30 58 : input[count] = '\0';
31 : }
32 :
33 72 : static kdb_unsigned_long_long_t isValidKey (Key * key)
34 : {
35 :
36 72 : const char * value = keyString (key);
37 : // else we manipulate the original
38 72 : char * tempval = elektraStrDup (value);
39 :
40 : char * endPtr;
41 :
42 :
43 : // convert to long, if valid key, pointer should point to spaces or unit suffix like MB, GB
44 72 : ELEKTRA_UNSIGNED_LONG_LONG_S (tempval, &endPtr, 10);
45 :
46 : // before deblanking check if pointer is invalid
47 72 : if (endPtr == tempval)
48 : {
49 14 : elektraFree (tempval);
50 14 : return 0;
51 : }
52 :
53 : // remove possibly occurring blanks
54 58 : deblank (endPtr);
55 58 : kdb_unsigned_long_long_t factor = 0;
56 :
57 : // calculate the factor based on the suffix of the mameory value, return 0 if there is no matching to indicate an error of the
58 : // function
59 58 : if (strcmp (endPtr, "KB") == 0)
60 : {
61 : factor = 1000;
62 : }
63 58 : else if (strcmp (endPtr, "MB") == 0)
64 : {
65 : factor = 1000000;
66 : }
67 42 : else if (strcmp (endPtr, "GB") == 0)
68 : {
69 : factor = 1000000000;
70 : }
71 38 : else if (strcmp (endPtr, "TB") == 0)
72 : {
73 : factor = 1000000000000;
74 : }
75 34 : else if (strcmp (endPtr, "PB") == 0)
76 : {
77 : factor = 1000000000000000;
78 : }
79 26 : else if (strcmp (endPtr, "B") == 0)
80 : {
81 8 : factor = 1;
82 : }
83 :
84 58 : elektraFree (tempval);
85 58 : return factor;
86 : }
87 :
88 : // @param formatFactor unsigned long, used to determine the factor for normalizing to bytes
89 18 : static int elektraUnitConvertToByteString (Key * key, kdb_unsigned_long_long_t formatFactor)
90 18 : {
91 :
92 18 : const char * str = keyString (key);
93 18 : char * origvalue = elektraStrDup (str);
94 : char * ptr;
95 : kdb_unsigned_long_long_t ret;
96 : kdb_unsigned_long_long_t normalizedMemVal;
97 :
98 18 : ret = ELEKTRA_UNSIGNED_LONG_LONG_S (str, &ptr, 10);
99 :
100 : // check if return value within bounds
101 18 : if (ret > UINT64_MAX / formatFactor)
102 : {
103 0 : elektraFree (origvalue);
104 0 : return 1;
105 : }
106 :
107 18 : normalizedMemVal = ret * formatFactor;
108 :
109 : // convert back to string
110 18 : const int n = snprintf (NULL, 0, ELEKTRA_UNSIGNED_LONG_LONG_F, normalizedMemVal);
111 18 : char buf[n + 1];
112 :
113 18 : snprintf (buf, n + 1, ELEKTRA_UNSIGNED_LONG_LONG_F, normalizedMemVal);
114 :
115 18 : keySetString (key, buf);
116 18 : keySetMeta (key, "origvalue", origvalue);
117 18 : elektraFree (origvalue);
118 18 : return 0;
119 : }
120 :
121 42 : static void elektraUnitRestore (Key * key)
122 : {
123 42 : const Key * oldval = keyGetMeta (key, "origvalue");
124 42 : if (oldval != NULL)
125 : {
126 18 : keySetString (key, keyString (oldval));
127 : }
128 42 : }
129 :
130 :
131 50 : int elektraUnitGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
132 : {
133 50 : if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/unit"))
134 : {
135 20 : KeySet * contract =
136 20 : ksNew (30, keyNew ("system/elektra/modules/unit", KEY_VALUE, "unit plugin waits for your orders", KEY_END),
137 : keyNew ("system/elektra/modules/unit/exports", KEY_END),
138 : keyNew ("system/elektra/modules/unit/exports/get", KEY_FUNC, elektraUnitGet, KEY_END),
139 : keyNew ("system/elektra/modules/unit/exports/set", KEY_FUNC, elektraUnitSet, KEY_END),
140 : #include ELEKTRA_README
141 : keyNew ("system/elektra/modules/unit/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
142 20 : ksAppend (returned, contract);
143 20 : ksDel (contract);
144 :
145 20 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
146 : }
147 :
148 : Key * cur;
149 : int rc = 1;
150 48 : while ((cur = ksNext (returned)) != NULL)
151 : {
152 30 : const Key * meta = keyGetMeta (cur, "check/unit");
153 30 : if (meta)
154 : {
155 30 : kdb_unsigned_long_long_t format = isValidKey (cur);
156 :
157 30 : if (format == 0)
158 : {
159 12 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (
160 : parentKey,
161 : "The string '%s' is not following the format guidelines of (<numerical value><optional "
162 : "space><memory unit>, e.g. 128 MB) !",
163 : keyString (cur));
164 12 : return ELEKTRA_PLUGIN_STATUS_ERROR;
165 : }
166 18 : elektraUnitConvertToByteString (cur, format);
167 : }
168 : }
169 : return rc;
170 : }
171 :
172 42 : int elektraUnitSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
173 : {
174 :
175 : Key * cur;
176 42 : ksRewind (returned);
177 106 : while ((cur = ksNext (returned)) != NULL)
178 : {
179 42 : const Key * meta = keyGetMeta (cur, "check/unit");
180 42 : if (!meta)
181 : {
182 0 : continue;
183 : }
184 :
185 42 : elektraUnitRestore (cur);
186 42 : kdb_unsigned_long_long_t format = isValidKey (cur);
187 :
188 42 : if (format == 0)
189 : {
190 20 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (parentKey,
191 : "The string '%s' is not following the format guidelines of (<numerical "
192 : "value><optional space><memory unit>, "
193 : "e.g. 128 MB) !",
194 : keyString (cur));
195 20 : return ELEKTRA_PLUGIN_STATUS_ERROR;
196 : }
197 : }
198 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
199 : }
200 :
201 :
202 62 : Plugin * ELEKTRA_PLUGIN_EXPORT
203 : {
204 62 : return elektraPluginExport ("unit", ELEKTRA_PLUGIN_GET, &elektraUnitGet, ELEKTRA_PLUGIN_SET, &elektraUnitSet, ELEKTRA_PLUGIN_END);
205 : }
|