1 /*
2 * DisMan Schedule MIB:
3 * Implementation of the schedule MIB config handling
4 */
5
6 #include <net-snmp/net-snmp-config.h>
7 #include <net-snmp/net-snmp-features.h>
8 #include <net-snmp/net-snmp-includes.h>
9 #include <net-snmp/agent/net-snmp-agent-includes.h>
10 #include <ctype.h>
11 #include "disman/schedule/schedCore.h"
12 #include "disman/schedule/schedConf.h"
13
14 netsnmp_feature_require(iquery);
15 netsnmp_feature_require(string_time_to_secs);
16
17 static int schedEntries;
18
19 /** Initializes the schedConf module */
20 void
init_schedConf(void)21 init_schedConf(void)
22 {
23 DEBUGMSGTL(("disman:schedule:init", "Initializing config module\n"));
24 init_schedule_container();
25
26 /*
27 * Register public configuration directives
28 */
29 snmpd_register_config_handler("repeat", parse_sched_periodic, NULL,
30 "repeat period OID = value");
31 snmpd_register_config_handler("cron", parse_sched_timed, NULL,
32 "cron * * * * * OID = value");
33 snmpd_register_config_handler("at", parse_sched_timed, NULL,
34 "at * * * * * OID = value");
35
36 /*
37 * Register internal configuration directive,
38 * and arrange for dynamically configured entries to be saved
39 */
40 snmpd_register_config_handler("_schedTable", parse_schedTable, NULL, NULL);
41 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
42 store_schedTable, NULL);
43 schedEntries = 0;
44 }
45
46
47 /* =======================================================
48 *
49 * Handlers for user-configured (static) scheduled actions
50 *
51 * ======================================================= */
52
53 void
parse_sched_periodic(const char * token,char * line)54 parse_sched_periodic( const char *token, char *line )
55 {
56 netsnmp_tdata_row *row;
57 struct schedTable_entry *entry;
58 char buf[24], tmpbuf[SPRINT_MAX_LEN];
59 long frequency;
60 long value;
61 size_t tmpint;
62 oid variable[ MAX_OID_LEN], *var_ptr = variable;
63 size_t var_len = MAX_OID_LEN;
64
65 schedEntries++;
66 sprintf(buf, "_conf%03d", schedEntries);
67
68 DEBUGMSGTL(( "disman:schedule:conf", "periodic: %s %s\n", token, line));
69 /*
70 * Parse the configure directive line
71 */
72 line = copy_nword(line, tmpbuf, sizeof(tmpbuf));
73 frequency = netsnmp_string_time_to_secs(tmpbuf);
74 if (frequency == -1) {
75 config_perror("Illegal frequency specified");
76 return;
77 }
78
79 line = read_config_read_data(ASN_OBJECT_ID, line, &var_ptr, &var_len);
80 if (var_len == 0) {
81 config_perror("invalid specification for schedVariable");
82 return;
83 }
84 /*
85 * Skip over optional assignment in "var = value"
86 */
87 while (line && isspace((unsigned char)(*line)))
88 line++;
89 if (line && *line == '=' ) {
90 line++;
91 while (line && isspace((unsigned char)(*line))) {
92 line++;
93 }
94 }
95 line = read_config_read_data(ASN_INTEGER, line, &value, &tmpint);
96
97 /*
98 * Create an entry in the schedTable
99 */
100 row = schedTable_createEntry( "snmpd.conf", buf );
101 if (!row || !row->data) {
102 config_perror("create schedule entry failure");
103 return;
104 }
105 entry = (struct schedTable_entry *)row->data;
106
107 entry->schedInterval = frequency;
108 entry->schedValue = value;
109 entry->schedVariable_len = var_len;
110 memcpy(entry->schedVariable, variable, var_len*sizeof(oid));
111
112 entry->schedType = SCHED_TYPE_PERIODIC;
113 entry->schedStorageType = ST_READONLY; /* or PERMANENT */
114 entry->flags = SCHEDULE_FLAG_ENABLED |
115 SCHEDULE_FLAG_ACTIVE |
116 SCHEDULE_FLAG_VALID;
117 entry->session = netsnmp_query_get_default_session();
118 sched_nextTime( entry );
119 }
120
121
122 /*
123 * Timed-schedule utility:
124 * Convert from a cron-style specification to the equivalent set
125 * of bits. Note that minute, hour and weekday crontab fields are
126 * 0-based, while day and month more naturally start from 1.
127 */
128 void
_sched_convert_bits(char * cron_spec,char * bit_buf,int bit_buf_len,int max_val,int startAt1)129 _sched_convert_bits( char *cron_spec, char *bit_buf,
130 int bit_buf_len, int max_val, int startAt1 ) {
131 char *cp = cron_spec;
132 u_char b[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
133 int val, major, minor;
134 int overshoot;
135
136 if (!cron_spec || !bit_buf)
137 return;
138
139 /*
140 * Wildcard field - set all bits
141 */
142 if ( *cp == '*' ) {
143 memset( bit_buf, 0xff, bit_buf_len );
144
145 /*
146 * An "all-bits" specification may not be an exact multiple of 8.
147 * Work out how far we've overshot things, and tidy up the excess.
148 */
149 overshoot = 8*bit_buf_len-max_val;
150 while ( overshoot > 0 ) {
151 bit_buf[ bit_buf_len-1 ] ^= b[8-overshoot];
152 overshoot--;
153 }
154 return;
155 }
156
157 /*
158 * Otherwise, clear the bit string buffer,
159 * and start calculating which bits to set
160 */
161 memset( bit_buf, 0, bit_buf_len );
162
163 while (1) {
164 sscanf( cp, "%d", &val);
165 /* Handle negative day specification */
166 if ( val < 0 ) {
167 val = max_val - val;
168 }
169 if ( startAt1 )
170 val--;
171 major = val/8;
172 minor = val%8;
173 bit_buf[ major ] |= b[minor];
174
175 /* XXX - ideally we should handle "X-Y" syntax as well */
176 while (*cp && *cp!=',')
177 cp++;
178 if (!*cp)
179 break;
180 cp++;
181 }
182 }
183
184 void
parse_sched_timed(const char * token,char * line)185 parse_sched_timed( const char *token, char *line )
186 {
187 netsnmp_tdata_row *row;
188 struct schedTable_entry *entry;
189 char buf[24], *cp;
190
191 char minConf[512]; size_t min_len = sizeof(minConf); char minVal[8];
192 char hourConf[512]; size_t hour_len = sizeof(hourConf); char hourVal[3];
193 char dateConf[512]; size_t date_len = sizeof(dateConf); char dateVal[8];
194 char monConf[512]; size_t mon_len = sizeof(monConf); char monVal[2];
195 char dayConf[512]; size_t day_len = sizeof(dayConf); char dayVal;
196
197 long value;
198 size_t tmpint;
199 oid variable[ MAX_OID_LEN], *var_ptr = variable;
200 size_t var_len = MAX_OID_LEN;
201
202 schedEntries++;
203 sprintf(buf, "_conf%03d", schedEntries);
204
205 DEBUGMSGTL(( "sched", "config: %s %s\n", token, line));
206 /*
207 * Parse the configure directive line
208 */
209 cp = minConf;
210 line = read_config_read_data(ASN_OCTET_STR, line, &cp, &min_len);
211 cp = hourConf;
212 line = read_config_read_data(ASN_OCTET_STR, line, &cp, &hour_len);
213 cp = dateConf;
214 line = read_config_read_data(ASN_OCTET_STR, line, &cp, &date_len);
215 cp = monConf;
216 line = read_config_read_data(ASN_OCTET_STR, line, &cp, &mon_len);
217 cp = dayConf;
218 line = read_config_read_data(ASN_OCTET_STR, line, &cp, &day_len);
219 if (!line) {
220 config_perror("invalid schedule time specification");
221 return;
222 }
223
224 line = read_config_read_data(ASN_OBJECT_ID, line, &var_ptr, &var_len);
225 if (var_len == 0) {
226 config_perror("invalid specification for schedVariable");
227 return;
228 }
229 /*
230 * Skip over optional assignment in "var = value"
231 */
232 while (line && isspace((unsigned char)(*line)))
233 line++;
234 if ( *line == '=' ) {
235 line++;
236 while (line && isspace((unsigned char)(*line))) {
237 line++;
238 }
239 }
240 line = read_config_read_data(ASN_INTEGER, line, &value, &tmpint);
241
242 /*
243 * Convert from cron-style specifications into bits
244 */
245 _sched_convert_bits( minConf, minVal, 8, 60, 0 );
246 _sched_convert_bits( hourConf, hourVal, 3, 24, 0 );
247 memset(dateVal+4, 0, 4); /* Clear the reverse day bits */
248 _sched_convert_bits( dateConf, dateVal, 4, 31, 1 );
249 _sched_convert_bits( monConf, monVal, 2, 12, 1 );
250 _sched_convert_bits( dayConf, &dayVal, 1, 8, 0 );
251 if ( dayVal & 0x01 ) { /* sunday(7) = sunday(0) */
252 dayVal |= 0x80;
253 dayVal &= 0xfe;
254 }
255
256 /*
257 * Create an entry in the schedTable
258 */
259 row = schedTable_createEntry("snmpd.conf", buf);
260 if (!row || !row->data) {
261 config_perror("create schedule entry failure");
262 return;
263 }
264 entry = (struct schedTable_entry *)row->data;
265
266 entry->schedWeekDay = dayVal;
267 memcpy(entry->schedMonth, monVal, 2);
268 memcpy(entry->schedDay, dateVal, 4+4);
269 memcpy(entry->schedHour, hourVal, 3);
270 memcpy(entry->schedMinute, minVal, 8);
271
272 memcpy(entry->schedVariable, variable, var_len*sizeof(oid));
273 entry->schedVariable_len = var_len;
274 entry->schedValue = value;
275
276 if ( !strcmp( token, "at" ))
277 entry->schedType = SCHED_TYPE_ONESHOT;
278 else
279 entry->schedType = SCHED_TYPE_CALENDAR;
280 entry->schedStorageType = ST_READONLY; /* or PERMANENT */
281 entry->flags = SCHEDULE_FLAG_ENABLED |
282 SCHEDULE_FLAG_ACTIVE |
283 SCHEDULE_FLAG_VALID;
284 entry->session = netsnmp_query_get_default_session();
285 sched_nextTime( entry );
286 }
287
288
289 /* ========================================
290 *
291 * Handlers for persistent schedule entries
292 *
293 * ======================================== */
294
295 void
parse_schedTable(const char * token,char * line)296 parse_schedTable( const char *token, char *line )
297 {
298 char owner[SCHED_STR1_LEN+1];
299 char name[ SCHED_STR1_LEN+1];
300 char time_bits[22]; /* schedWeekDay..schedMinute */
301 void *vp;
302 size_t len;
303 netsnmp_tdata_row *row;
304 struct schedTable_entry *entry;
305
306 DEBUGMSGTL(("disman:schedule:conf", "Parsing schedTable config... "));
307
308 /*
309 * Read in the index information for this entry
310 * and create a (non-fixed) data structure for it.
311 */
312 memset( owner, 0, sizeof(owner));
313 memset( name, 0, sizeof(name));
314 len = SCHED_STR1_LEN; vp = owner;
315 line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len);
316 len = SCHED_STR1_LEN; vp = name;
317 line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len);
318 row = schedTable_createEntry(owner, name);
319 if (!row || !row->data) {
320 config_perror("create schedule entry failure");
321 return;
322 }
323 entry = (struct schedTable_entry *)row->data;
324 DEBUGMSG(("disman:schedule:conf", "(%s, %s) ", owner, name));
325
326 /*
327 * Read in the column values.
328 */
329 len = SCHED_STR2_LEN; vp = entry->schedDescr;
330 line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len);
331 line = read_config_read_data(ASN_UNSIGNED, line,
332 &entry->schedInterval, NULL);
333 /* Unpick the various timed bits */
334 len = 22; vp = time_bits;
335 line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len);
336 entry->schedWeekDay = time_bits[0];
337 entry->schedMonth[0] = time_bits[1];
338 entry->schedMonth[1] = time_bits[2];
339 entry->schedHour[0] = time_bits[11];
340 entry->schedHour[1] = time_bits[12];
341 entry->schedHour[2] = time_bits[13];
342 memcpy(entry->schedDay, time_bits+3, 8);
343 memcpy(entry->schedMinute, time_bits+14, 8);
344
345 len = SCHED_STR1_LEN; vp = entry->schedContextName;
346 line = read_config_read_data(ASN_OCTET_STR, line, &vp, &len);
347 len = MAX_OID_LEN; vp = entry->schedVariable;
348 line = read_config_read_data(ASN_OBJECT_ID, line, &vp, &len);
349 entry->schedVariable_len = len;
350 line = read_config_read_data(ASN_INTEGER, line,
351 &entry->schedValue, NULL);
352 line = read_config_read_data(ASN_UNSIGNED, line,
353 &entry->schedType, NULL);
354 line = read_config_read_data(ASN_UNSIGNED, line, &len, NULL);
355 entry->flags |= (len /* & WHAT ?? */);
356 /* XXX - Will need to read in the 'iquery' access information */
357 entry->flags |= SCHEDULE_FLAG_VALID;
358
359 DEBUGMSG(("disman:schedule:conf", "\n"));
360 }
361
362 /*
363 * Save dynamically-configured schedTable entries into persistent storage
364 */
365 int
store_schedTable(int majorID,int minorID,void * serverarg,void * clientarg)366 store_schedTable(int majorID, int minorID, void *serverarg, void *clientarg)
367 {
368 char line[SNMP_MAXBUF];
369 char time_bits[22]; /* schedWeekDay..schedMinute */
370 char *cptr, *cp;
371 void *vp;
372 size_t tint;
373 netsnmp_tdata_row *row;
374 struct schedTable_entry *entry;
375
376
377 DEBUGMSGTL(( "disman:schedule:conf", "Storing schedTable:\n"));
378
379 for (row = netsnmp_tdata_row_first( schedule_table );
380 row;
381 row = netsnmp_tdata_row_next( schedule_table, row )) {
382
383 if (!row->data)
384 continue;
385 entry = (struct schedTable_entry *)row->data;
386
387 /*
388 * Only save (dynamically-created) 'nonVolatile' entries
389 * (XXX - what about dynamic 'permanent' entries ??)
390 */
391 if (entry->schedStorageType != ST_NONVOLATILE )
392 continue;
393 DEBUGMSGTL(( "disman:schedule:conf", " Storing (%s, %s)\n",
394 entry->schedOwner, entry->schedName));
395
396 memset(line, 0, sizeof(line));
397 strcpy(line, "_schedTable ");
398 cptr = line + strlen(line);
399
400 cp = entry->schedOwner; tint = strlen( cp );
401 cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint );
402 cp = entry->schedName; tint = strlen( cp );
403 cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint );
404 cp = entry->schedDescr; tint = strlen( cp );
405 cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint );
406 tint = entry->schedInterval;
407 cptr = read_config_store_data(ASN_UNSIGNED, cptr, &tint, NULL );
408
409 /* Combine all the timed bits into a single field */
410 time_bits[0] = entry->schedWeekDay;
411 time_bits[1] = entry->schedMonth[0];
412 time_bits[2] = entry->schedMonth[1];
413 time_bits[11] = entry->schedHour[0];
414 time_bits[12] = entry->schedHour[1];
415 time_bits[13] = entry->schedHour[2];
416 memcpy(time_bits+3, entry->schedDay, 8);
417 memcpy(time_bits+14, entry->schedMinute, 8);
418 vp = time_bits; tint = 22;
419 cptr = read_config_store_data(ASN_OCTET_STR, cptr, &vp, &tint );
420
421 cp = entry->schedContextName; tint = strlen( cp );
422 cptr = read_config_store_data(ASN_OCTET_STR, cptr, &cp, &tint );
423 vp = entry->schedVariable;
424 tint = entry->schedVariable_len;
425 cptr = read_config_store_data(ASN_OBJECT_ID, cptr, &vp, &tint );
426 tint = entry->schedValue;
427 cptr = read_config_store_data(ASN_INTEGER, cptr, &tint, NULL );
428 tint = entry->schedType;
429 cptr = read_config_store_data(ASN_UNSIGNED, cptr, &tint, NULL );
430 tint = entry->flags /* & WHAT ?? */;
431 cptr = read_config_store_data(ASN_UNSIGNED, cptr, &tint, NULL );
432 /* XXX - Need to store the 'iquery' access information */
433 snmpd_store_config(line);
434 }
435 DEBUGMSGTL(( "disman:schedule:conf", " done.\n"));
436 return SNMPERR_SUCCESS;
437 }
438