|
1 /* |
|
2 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. |
|
3 * |
|
4 * U.S. Government Rights - Commercial software. Government users are subject to |
|
5 * the Sun Microsystems, Inc. standard license agreement and applicable |
|
6 * provisions of the FAR and its supplements. |
|
7 * |
|
8 * |
|
9 * This distribution may include materials developed by third parties. Sun, Sun |
|
10 * Microsystems, the Sun logo and Solaris are trademarks or registered |
|
11 * trademarks of Sun Microsystems, Inc. in the U.S. and other countries. |
|
12 */ |
|
13 |
|
14 |
|
15 /* |
|
16 * Note: this file originally auto-generated by mib2c using : |
|
17 * mib2c.iterate.conf,v 1.1.1.1 2003/03/26 18:12:29 pcarroll Exp $ |
|
18 */ |
|
19 |
|
20 #include <sys/types.h> |
|
21 #include <sys/stat.h> |
|
22 #include <stdio.h> |
|
23 #include <errno.h> |
|
24 |
|
25 #include <net-snmp/net-snmp-config.h> |
|
26 #include <net-snmp/net-snmp-includes.h> |
|
27 #include <net-snmp/agent/net-snmp-agent-includes.h> |
|
28 #include "demo_module_5.h" |
|
29 #include <net-snmp/agent/agent_trap.h> |
|
30 |
|
31 /* |
|
32 * MAXNAMELEN is the maximum permissible file name defined in param.h |
|
33 */ |
|
34 |
|
35 fileEntry *fileList = 0; |
|
36 char file1[MAXNAMELEN], file2[MAXNAMELEN], file3[MAXNAMELEN], |
|
37 file4[MAXNAMELEN]; |
|
38 |
|
39 |
|
40 |
|
41 /** Initialize the me5FileTable table by defining its contents and how it's structured */ |
|
42 |
|
43 void |
|
44 initialize_table_me5FileTable(void) |
|
45 { |
|
46 static oid me5FileTable_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 5, 2, 1}; |
|
47 netsnmp_table_registration_info *table_info; |
|
48 netsnmp_handler_registration *my_handler; |
|
49 netsnmp_iterator_info *iinfo; |
|
50 |
|
51 /* create the table structure itself */ |
|
52 table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); |
|
53 iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info); |
|
54 |
|
55 /* |
|
56 * if your table is read only, it's easiest to change the |
|
57 * HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY |
|
58 */ |
|
59 my_handler = netsnmp_create_handler_registration("me5FileTable", |
|
60 me5FileTable_handler, |
|
61 me5FileTable_oid, |
|
62 OID_LENGTH(me5FileTable_oid), |
|
63 HANDLER_CAN_RWRITE); |
|
64 |
|
65 if (!my_handler || !table_info || !iinfo) { |
|
66 return; /* mallocs failed */ |
|
67 } |
|
68 |
|
69 /*************************************************** |
|
70 * Setting up the table's definition |
|
71 */ |
|
72 |
|
73 netsnmp_table_helper_add_indexes(table_info, |
|
74 ASN_UNSIGNED, /* index: me5FileIndex */ |
|
75 0); |
|
76 |
|
77 table_info->min_column = 1; |
|
78 table_info->max_column = 4; |
|
79 |
|
80 /* iterator access routines */ |
|
81 iinfo->get_first_data_point = me5FileTable_get_first_data_point; |
|
82 iinfo->get_next_data_point = me5FileTable_get_next_data_point; |
|
83 |
|
84 iinfo->table_reginfo = table_info; |
|
85 |
|
86 /*************************************************** |
|
87 * registering the table with the master agent |
|
88 */ |
|
89 |
|
90 DEBUGMSGTL(("initialize_table_me5FileTable", |
|
91 "Registering table me5FileTable as a table iterator\n")); |
|
92 netsnmp_register_table_iterator(my_handler, iinfo); |
|
93 } |
|
94 |
|
95 |
|
96 /** Initializes the demo_module_5 module */ |
|
97 |
|
98 |
|
99 void |
|
100 init_demo_module_5(void) |
|
101 { |
|
102 |
|
103 /* here we initialize all the tables we're planning on supporting */ |
|
104 |
|
105 |
|
106 initialize_table_me5FileTable(); |
|
107 |
|
108 |
|
109 /* |
|
110 * These are the default files that are monitored by the module if there |
|
111 * is no persistent data (file names to be monitored). This is likely |
|
112 * during the first running on the module, when the .conf file does not |
|
113 * have any file related information. |
|
114 */ |
|
115 |
|
116 strcpy(file1, "/etc/hosts"); |
|
117 strcpy(file2, "/etc/group"); |
|
118 strcpy(file3, "/etc/passwd"); |
|
119 strcpy(file4, "/etc/system"); |
|
120 |
|
121 |
|
122 /* |
|
123 * Register for tokens from demo_module_5.conf file. The names of the |
|
124 * tokens are demo5_file1,demo5_file2,demo5_file3,demo5_file4. The function |
|
125 * demo5_load_tokens is called whenever these 4 tokens are encountered in |
|
126 * demo_module_5.conf file. |
|
127 */ |
|
128 |
|
129 register_config_handler(DEMO5_CONF_FILE, "demo5_file1", |
|
130 demo5_load_tokens, NULL, NULL); |
|
131 |
|
132 register_config_handler(DEMO5_CONF_FILE, "demo5_file2", |
|
133 demo5_load_tokens, NULL, NULL); |
|
134 |
|
135 register_config_handler(DEMO5_CONF_FILE, "demo5_file3", |
|
136 demo5_load_tokens, NULL, NULL); |
|
137 |
|
138 register_config_handler(DEMO5_CONF_FILE, "demo5_file4", |
|
139 demo5_load_tokens, NULL, NULL); |
|
140 |
|
141 |
|
142 |
|
143 /* |
|
144 * Register for a callback when all the configuration files are read. The |
|
145 * callback function here is demo5_post_read_config |
|
146 */ |
|
147 |
|
148 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG, |
|
149 demo5_post_read_config, NULL); |
|
150 |
|
151 |
|
152 } |
|
153 |
|
154 |
|
155 /** returns the first data point within the me5FileTable table data. |
|
156 |
|
157 Set the my_loop_context variable to the first data point structure |
|
158 of your choice (from which you can find the next one). This could |
|
159 be anything from the first node in a linked list, to an integer |
|
160 pointer containing the beginning of an array variable. |
|
161 |
|
162 Set the my_data_context variable to something to be returned to |
|
163 you later that will provide you with the data to return in a given |
|
164 row. This could be the same pointer as what my_loop_context is |
|
165 set to, or something different. |
|
166 |
|
167 The put_index_data variable contains a list of snmp variable |
|
168 bindings, one for each index in your table. Set the values of |
|
169 each appropriately according to the data matching the first row |
|
170 and return the put_index_data variable at the end of the function. |
|
171 */ |
|
172 |
|
173 |
|
174 netsnmp_variable_list * |
|
175 me5FileTable_get_first_data_point(void **my_loop_context, void **my_data_context, |
|
176 netsnmp_variable_list * put_index_data, |
|
177 netsnmp_iterator_info * mydata) |
|
178 { |
|
179 |
|
180 netsnmp_variable_list *vptr; |
|
181 |
|
182 fileEntry *firstFile = fileList; |
|
183 if (!firstFile) { |
|
184 return NULL; |
|
185 } |
|
186 *my_loop_context = firstFile; |
|
187 *my_data_context = firstFile; |
|
188 |
|
189 |
|
190 vptr = put_index_data; |
|
191 |
|
192 snmp_set_var_value(vptr, (u_char *) & fileList->findex, sizeof(fileList->findex)); |
|
193 vptr = vptr->next_variable; |
|
194 |
|
195 return put_index_data; |
|
196 } |
|
197 |
|
198 |
|
199 /** functionally the same as me5FileTable_get_first_data_point, but |
|
200 my_loop_context has already been set to a previous value and should |
|
201 be updated to the next in the list. For example, if it was a |
|
202 linked list, you might want to cast it and the return |
|
203 my_loop_context->next. The my_data_context pointer should be set |
|
204 to something you need later and the indexes in put_index_data |
|
205 updated again. */ |
|
206 |
|
207 |
|
208 |
|
209 netsnmp_variable_list * |
|
210 me5FileTable_get_next_data_point(void **my_loop_context, void **my_data_context, |
|
211 netsnmp_variable_list * put_index_data, |
|
212 netsnmp_iterator_info * mydata) |
|
213 { |
|
214 |
|
215 netsnmp_variable_list *vptr; |
|
216 fileEntry *nextNode = (fileEntry *) * my_loop_context; |
|
217 nextNode = nextNode->next; |
|
218 |
|
219 if (!nextNode) { |
|
220 return NULL; |
|
221 } |
|
222 *my_loop_context = nextNode; |
|
223 *my_data_context = nextNode; |
|
224 |
|
225 vptr = put_index_data; |
|
226 |
|
227 |
|
228 |
|
229 snmp_set_var_value(vptr, (u_char *) & nextNode->findex, |
|
230 sizeof(nextNode->findex)); |
|
231 vptr = vptr->next_variable; |
|
232 |
|
233 return put_index_data; |
|
234 } |
|
235 |
|
236 |
|
237 /** handles requests for the me5FileTable table, if anything else needs to be done */ |
|
238 |
|
239 int |
|
240 me5FileTable_handler( |
|
241 netsnmp_mib_handler * handler, |
|
242 netsnmp_handler_registration * reginfo, |
|
243 netsnmp_agent_request_info * reqinfo, |
|
244 netsnmp_request_info * requests) |
|
245 { |
|
246 |
|
247 netsnmp_request_info *request; |
|
248 netsnmp_table_request_info *table_info; |
|
249 netsnmp_variable_list *var; |
|
250 fileEntry *data; |
|
251 char *fileName = NULL; |
|
252 char *undofn; |
|
253 int len; |
|
254 |
|
255 char filebuf[255]; |
|
256 |
|
257 for (request = requests; request; request = request->next) { |
|
258 |
|
259 var = request->requestvb; |
|
260 if (request->processed != 0) |
|
261 continue; |
|
262 |
|
263 /* |
|
264 * the following extracts the my_data_context pointer set in the loop |
|
265 * functions above. You can then use the results to help return data |
|
266 * for the columns of the me5FileTable table in question |
|
267 */ |
|
268 |
|
269 data = (fileEntry *) netsnmp_extract_iterator_context(request); |
|
270 if (data == NULL) { |
|
271 if (reqinfo->mode == MODE_GET) { |
|
272 netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); |
|
273 } else { |
|
274 netsnmp_set_request_error(reqinfo, request, |
|
275 SNMP_ERR_NOCREATION); |
|
276 } |
|
277 continue; |
|
278 } else { |
|
279 struct stat fAttrib; |
|
280 if (stat(GetFileName(data->findex), &fAttrib) != -1) { |
|
281 data->fileSize = fAttrib.st_size; |
|
282 sprintf(data->filePerm, "%o", fAttrib.st_mode & 0777); |
|
283 } else { |
|
284 data->fileSize = 0; |
|
285 sprintf(data->filePerm, "%d", -1); |
|
286 } |
|
287 |
|
288 } |
|
289 |
|
290 /* extracts the information about the table from the request */ |
|
291 table_info = netsnmp_extract_table_info(request); |
|
292 /* table_info->colnum contains the column number requested */ |
|
293 /* |
|
294 * table_info->indexes contains a linked list of snmp variable |
|
295 * bindings for the indexes of the table. Values in the list have |
|
296 * been set corresponding to the indexes of the request |
|
297 */ |
|
298 |
|
299 if (table_info == NULL) { |
|
300 continue; |
|
301 } |
|
302 switch (reqinfo->mode) { |
|
303 /* |
|
304 * the table_iterator helper should change all GETNEXTs into GETs |
|
305 * for you automatically, so you don't have to worry about the |
|
306 * GETNEXT case. Only GETs and SETs need to be dealt with here |
|
307 */ |
|
308 case MODE_GET: |
|
309 switch (table_info->colnum) { |
|
310 case COLUMN_ME5FILEINDEX: |
|
311 snmp_set_var_typed_value(var, ASN_UNSIGNED, |
|
312 (u_char *) & data->findex, |
|
313 sizeof(data->findex)); |
|
314 break; |
|
315 |
|
316 case COLUMN_ME5FILENAME: |
|
317 snmp_set_var_typed_value(var, ASN_OCTET_STR, |
|
318 (u_char *) data->fileName, |
|
319 strlen(data->fileName)); |
|
320 break; |
|
321 |
|
322 case COLUMN_ME5FILESIZE: |
|
323 snmp_set_var_typed_value(var, ASN_UNSIGNED, |
|
324 (u_char *) & data->fileSize, |
|
325 sizeof(data->fileSize)); |
|
326 break; |
|
327 |
|
328 case COLUMN_ME5FILEPERM: |
|
329 snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->filePerm, |
|
330 strlen(data->filePerm)); |
|
331 break; |
|
332 |
|
333 default: |
|
334 /* We shouldn't get here */ |
|
335 snmp_log(LOG_ERR, |
|
336 "problem encountered in me5FileTable_handler: unknown column\n"); |
|
337 } |
|
338 break; |
|
339 |
|
340 case MODE_SET_RESERVE1: |
|
341 /* set handling... */ |
|
342 switch (table_info->colnum) { |
|
343 /* |
|
344 * Check that the value being set is acceptable |
|
345 */ |
|
346 case COLUMN_ME5FILENAME: |
|
347 if (var->type != ASN_OCTET_STR) { |
|
348 DEBUGMSGTL(("me5FileTable", "COLUMN NAME\n")); |
|
349 DEBUGMSGTL(("me5FileTable", "%x not octet string type", var->type)); |
|
350 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE); |
|
351 return SNMP_ERR_WRONGTYPE; |
|
352 } |
|
353 if (!var->val.string) { |
|
354 DEBUGMSGTL(("me2FileTable", "Empty file name")); |
|
355 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE); |
|
356 return SNMP_ERR_WRONGVALUE; |
|
357 } |
|
358 break; |
|
359 default: |
|
360 /* We shouldn't get here */ |
|
361 snmp_log(LOG_ERR, |
|
362 "problem encountered in me5FileTable_handler: unknown column\n"); |
|
363 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_READONLY); |
|
364 return SNMP_ERR_NOTWRITABLE; |
|
365 } |
|
366 break; |
|
367 case MODE_SET_RESERVE2: |
|
368 /* |
|
369 * This is conventially where any necesary resources are |
|
370 * allocated (e.g. calls to malloc) |
|
371 */ |
|
372 |
|
373 /* Store old info for undo later */ |
|
374 |
|
375 undofn = GetFileName(data->findex); |
|
376 if (undofn) { |
|
377 if (!(fileName = strdup(undofn))) { |
|
378 netsnmp_set_request_error(reqinfo, request, |
|
379 SNMP_ERR_RESOURCEUNAVAILABLE); |
|
380 } else |
|
381 netsnmp_request_add_list_data(request, |
|
382 netsnmp_create_data_list |
|
383 (ME5FILE_SET_FILENAME, fileName, |
|
384 free)); |
|
385 |
|
386 } |
|
387 break; |
|
388 case MODE_SET_FREE: |
|
389 |
|
390 /* |
|
391 * This is where any of the above resources are freed again |
|
392 * (because one of the other values being SET failed for some |
|
393 * reason). |
|
394 */ |
|
395 |
|
396 /* |
|
397 * The netsnmp_free_list_data should take care of the alocated |
|
398 * resources |
|
399 */ |
|
400 |
|
401 break; |
|
402 case MODE_SET_ACTION: |
|
403 /* |
|
404 * Set the variable as requested. Note that this may need to be |
|
405 * reversed, so save any information needed to do this. |
|
406 */ |
|
407 len = var->val_len; |
|
408 var->val.string[len] = '\0'; |
|
409 if (!ChangeItem(data->findex, (char *) var->val.string )) { |
|
410 netsnmp_set_request_error(reqinfo, request, |
|
411 SNMP_ERR_COMMITFAILED); |
|
412 } |
|
413 break; |
|
414 |
|
415 case MODE_SET_COMMIT: |
|
416 /* |
|
417 * Everything worked, so we can discard any saved information, |
|
418 * and make the change permanent (e.g. write to the config file). |
|
419 * We also free any allocated resources. |
|
420 * |
|
421 */ |
|
422 |
|
423 /* Persist the file information */ |
|
424 |
|
425 snprintf(&filebuf[0], MAXNAMELEN, "demo5_file%d %s", |
|
426 data->findex, data->fileName); |
|
427 |
|
428 |
|
429 |
|
430 read_config_store(DEMO5_CONF_FILE, &filebuf[0]); |
|
431 |
|
432 /* |
|
433 * The netsnmp_free_list_data should take care of the alocated |
|
434 * resources |
|
435 */ |
|
436 |
|
437 |
|
438 break; |
|
439 case MODE_SET_UNDO: |
|
440 /* |
|
441 * Something failed, so re-set the variable to its previous value |
|
442 * (and free any allocated resources). |
|
443 */ |
|
444 |
|
445 if (GetFileName(data->findex)) { |
|
446 /******* Get the saved value ************/ |
|
447 undofn = (char *) netsnmp_request_get_list_data(request, |
|
448 ME5FILE_SET_FILENAME); |
|
449 if (!ChangeItem(data->findex, undofn)) { |
|
450 netsnmp_set_request_error(reqinfo, request, |
|
451 SNMP_ERR_UNDOFAILED); |
|
452 } |
|
453 } |
|
454 break; |
|
455 |
|
456 default: |
|
457 snmp_log(LOG_ERR, |
|
458 "problem encountered in me5FileTable_handler: unsupported mode\n"); |
|
459 } |
|
460 } |
|
461 |
|
462 return SNMP_ERR_NOERROR; |
|
463 } |
|
464 |
|
465 /* Function to add a fileName to the linked list of files */ |
|
466 |
|
467 int |
|
468 AddItem(char *fileName) |
|
469 { |
|
470 |
|
471 fileEntry *fprt = fileList; |
|
472 struct stat fAttrib; /* Need to check if memory is valid */ |
|
473 if (!fileName || !strlen(fileName)) { |
|
474 return FALSE; |
|
475 } |
|
476 if (stat(fileName, &fAttrib) == -1) { |
|
477 /* |
|
478 * Unable to get the file information, it could be more than file not |
|
479 * exists if (errno == ENOENT) { return FALSE; } return FALSE; |
|
480 */ |
|
481 DEBUGMSGTL(("demo_module_5", "Can't access the file %s", fileName)); |
|
482 } |
|
483 if (fprt != NULL) { |
|
484 while (fprt->next != NULL) { |
|
485 fprt = fprt->next; |
|
486 } |
|
487 fprt->next = (fileEntry *) malloc(sizeof(fileEntry)); |
|
488 fprt->next->findex = fprt->findex + 1; |
|
489 fprt = fprt->next; |
|
490 fprt->next = NULL; |
|
491 strcpy(fprt->fileName, fileName); |
|
492 fprt->fileSize = fAttrib.st_size; |
|
493 sprintf(fprt->filePerm, "%d", fAttrib.st_mode); |
|
494 } else { |
|
495 fprt = (fileEntry *) malloc(sizeof(fileEntry)); |
|
496 fprt->next = NULL; |
|
497 fprt->findex = 1; |
|
498 strcpy(fprt->fileName, fileName); |
|
499 fprt->fileSize = fAttrib.st_size; |
|
500 sprintf(fprt->filePerm, "%d", fAttrib.st_mode); |
|
501 fileList = fprt; |
|
502 } |
|
503 |
|
504 return TRUE; |
|
505 } |
|
506 |
|
507 /* |
|
508 * Function to change the file for a particular index. This function is |
|
509 * called when a snmp set request arrives to change the list of files being |
|
510 * monitored. |
|
511 */ |
|
512 |
|
513 int |
|
514 ChangeItem(int fileIndex, char *fileName) |
|
515 { |
|
516 |
|
517 fileEntry *tempp = fileList; |
|
518 |
|
519 if (!fileName || !strlen(fileName)) { |
|
520 return FALSE; |
|
521 } |
|
522 |
|
523 while (tempp != NULL) { |
|
524 if (tempp->findex == fileIndex) { |
|
525 strcpy(tempp->fileName, fileName); |
|
526 switch(fileIndex) { |
|
527 case 1: |
|
528 strcpy(file1, fileName); |
|
529 case 2: |
|
530 strcpy(file2, fileName); |
|
531 case 3: |
|
532 strcpy(file3, fileName); |
|
533 case 4: |
|
534 strcpy(file4, fileName); |
|
535 } |
|
536 return TRUE; |
|
537 |
|
538 } |
|
539 tempp = tempp->next; |
|
540 } |
|
541 |
|
542 return FALSE; |
|
543 } |
|
544 |
|
545 /* Function to return the filename corresponding to an index */ |
|
546 |
|
547 char * |
|
548 GetFileName(int fIndex) |
|
549 { |
|
550 fileEntry *fprt = fileList; |
|
551 while (fprt != NULL) { |
|
552 if (fprt->findex == fIndex) { |
|
553 return fprt->fileName; |
|
554 } |
|
555 fprt = fprt->next; |
|
556 } |
|
557 return NULL; |
|
558 |
|
559 } |
|
560 |
|
561 /* |
|
562 * Function that is called whenever interested tokens are encountered in |
|
563 * demo_module_5.conf file. The token values represent the persistent filename |
|
564 * information. |
|
565 */ |
|
566 |
|
567 void |
|
568 demo5_load_tokens(const char *token, char *cptr) |
|
569 { |
|
570 |
|
571 if (strcmp(token, "demo5_file1") == 0) { |
|
572 strcpy(file1, cptr); |
|
573 } else if (strcmp(token, "demo5_file2") == 0) { |
|
574 strcpy(file2, cptr); |
|
575 } else if (strcmp(token, "demo5_file3") == 0) { |
|
576 strcpy(file3, cptr); |
|
577 } else if (strcmp(token, "demo5_file4") == 0) { |
|
578 strcpy(file4, cptr); |
|
579 } else { |
|
580 /* Do Nothing */ |
|
581 } |
|
582 |
|
583 return; |
|
584 |
|
585 } |
|
586 |
|
587 /* |
|
588 * Function that persists file information. This is called by the agent |
|
589 * whenever data needs to be persisted. |
|
590 */ |
|
591 |
|
592 int |
|
593 demo5_persist_data(int a, int b, void *c, void *d) |
|
594 { |
|
595 |
|
596 char filebuf[300]; |
|
597 |
|
598 |
|
599 sprintf(filebuf, "demo5_file1 %s", file1); |
|
600 read_config_store(DEMO5_CONF_FILE, filebuf); |
|
601 |
|
602 |
|
603 sprintf(filebuf, "demo5_file2 %s", file2); |
|
604 read_config_store(DEMO5_CONF_FILE, filebuf); |
|
605 |
|
606 |
|
607 sprintf(filebuf, "demo5_file3 %s", file3); |
|
608 read_config_store(DEMO5_CONF_FILE, filebuf); |
|
609 |
|
610 |
|
611 sprintf(filebuf, "demo5_file4 %s", file4); |
|
612 read_config_store(DEMO5_CONF_FILE, filebuf); |
|
613 |
|
614 } |
|
615 |
|
616 /* |
|
617 * Callback function that is called after all the configuration files are |
|
618 * read by the agent. See init_demo_module_5 function to see how this |
|
619 * callback is specified. |
|
620 * |
|
621 * When this function is called, any persistent file information would have been |
|
622 * read into the module. These files are added to the file list. |
|
623 * |
|
624 * The callback function to persist data (demo5_persist_data) is registered. |
|
625 */ |
|
626 |
|
627 int |
|
628 demo5_post_read_config(int a, int b, void *c, void *d) |
|
629 { |
|
630 |
|
631 if (!AddItem(file1)) |
|
632 snmp_log(LOG_ERR, "Failed to add instance in init_demo_module_5\n"); |
|
633 if (!AddItem(file2)) |
|
634 snmp_log(LOG_ERR, "Failed to add instance in init_demo_module_5\n"); |
|
635 if (!AddItem(file3)) |
|
636 snmp_log(LOG_ERR, "Failed to add instance in init_demo_module_5\n"); |
|
637 if (!AddItem(file4)) |
|
638 snmp_log(LOG_ERR, "Failed to add instance in init_demo_module_5\n"); |
|
639 |
|
640 |
|
641 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, |
|
642 demo5_persist_data, NULL); |
|
643 |
|
644 |
|
645 } |
|
646 |