nfs-ganesha 1.4
|
00001 00007 #ifdef HAVE_CONFIG_H 00008 #include "config.h" 00009 #endif 00010 00011 #include <net-snmp/net-snmp-config.h> 00012 #include <net-snmp/net-snmp-includes.h> 00013 #include <net-snmp/agent/net-snmp-agent-includes.h> 00014 00015 #include <pthread.h> 00016 #include <unistd.h> 00017 00018 #include "snmp_adm.h" 00019 00020 #include "register.h" 00021 00022 #include "get_set_proc.h" 00023 #include "parse_type.h" 00024 #include "config_daemon.h" 00025 00026 static pthread_t thread_id = 0; 00027 00028 static int running = 1; 00029 00030 static int configured = 0; 00031 static int registered = 0; 00032 00033 static int product_id = 0; 00034 00035 static int issyslog = 0; 00036 00038 register_info *register_info_list = NULL; 00040 pthread_t *polling_threads = NULL; 00042 polling_arg *polling_args = NULL; 00044 int polling_list_size = 0; 00045 00046 oid *root_oid = NULL; 00047 int root_oid_len = 0; 00048 00049 static void *pool(void *v) 00050 { 00051 while(running) 00052 { 00053 agent_check_and_process(1); /* 0 == don't block */ 00054 } 00055 return NULL; 00056 } 00057 00062 static void *polling_fct(void *arg) 00063 { 00064 polling_arg *parg = (polling_arg *) arg; 00065 00066 for(;;) 00067 { 00068 if(parg->test_fct(parg->args) == 1) 00069 snmp_adm_send_trap(parg->type, parg->value); 00070 sleep(parg->second); 00071 } 00072 return NULL; 00073 } 00074 00075 /*get oid from environment variable SNMP_ADM_ROOT 00076 syntax is .1.3.6.1.4.1.12384.999 00077 */ 00078 static int get_conf_from_env() 00079 { 00080 char *str_root = getenv("SNMP_ADM_ROOT"); 00081 char *ptr, *save; 00082 int pos = 0; 00083 00084 if(!str_root) 00085 { 00086 /*no environment var, use default */ 00087 oid tmp_root[] = { DEFAULT_ROOT_OID }; 00088 root_oid_len = sizeof(tmp_root) / sizeof(oid); 00089 root_oid = malloc(root_oid_len * sizeof(oid)); 00090 memcpy(root_oid, tmp_root, root_oid_len * sizeof(oid)); 00091 } 00092 else 00093 { 00094 /* parse str_root 00095 */ 00096 00097 /* compute length */ 00098 for(ptr = str_root; *ptr != '\0'; ptr++) 00099 if(*ptr == '.') 00100 root_oid_len++; 00101 00102 root_oid = malloc(root_oid_len * sizeof(oid)); 00103 00104 /* create root array */ 00105 save = str_root + 1; 00106 for(ptr = str_root + 1; *ptr != '\0'; ptr++) 00107 if(*ptr == '.' || ptr == '\0') 00108 { 00109 *ptr = '\0'; 00110 /*FIXME arch spec? */ 00111 root_oid[pos++] = atol(save); 00112 save = ++ptr; 00113 } 00114 root_oid[pos++] = atol(save); 00115 } 00116 return 0; 00117 } 00118 00126 static register_info *new_register(char *label, char *desc, int type, int reg_len) 00127 { 00128 register_info *new = malloc(sizeof(register_info)); 00129 00130 /*fill the struct */ 00131 new->label = strdup(label); 00132 new->desc = strdup(desc); 00133 00134 /* set function to NULL (avoid undetermined value if scalar) */ 00135 memset(&(new->function_info), 0, sizeof(new->function_info)); 00136 00137 new->type = type; 00138 00139 new->reg = malloc(reg_len * sizeof(netsnmp_handler_registration *)); 00140 new->reg_len = reg_len; 00141 00142 /* link the cell (insert in first) */ 00143 new->next = register_info_list; 00144 register_info_list = new; 00145 00146 return new; 00147 } 00148 00149 /* 00150 register desc and name 00151 */ 00152 static int register_meta(oid * myoid, int len, char *name, char *desc, 00153 netsnmp_handler_registration ** tab_reg) 00154 { 00155 int err1, err2; 00156 00157 /* description */ 00158 myoid[len - 1] = DESC_OID; 00159 err1 = register_ro_string(myoid, len, desc, &(tab_reg[0])); 00160 00161 /* label */ 00162 myoid[len - 1] = NAME_OID; 00163 err2 = register_ro_string(myoid, len, name, &(tab_reg[1])); 00164 00165 return err1 != MIB_REGISTERED_OK || err2 != MIB_REGISTERED_OK; 00166 } 00167 00168 /* id of the object, incremented after each record */ 00169 int branch_num[NUM_BRANCH]; 00170 00171 /* fill a oid with root|prod_id|stat_num 00172 * len value is the oid length from root to the name|desc level +1. 00173 */ 00174 static void get_oid(oid * myoid, int branch, size_t * plen) 00175 { 00176 *plen = root_oid_len; 00177 memcpy(myoid, root_oid, sizeof(oid) * root_oid_len); 00178 00179 myoid[(*plen)++] = product_id; 00180 myoid[(*plen)++] = branch; 00181 myoid[(*plen)++] = branch_num[branch]++; 00182 (*plen)++; 00183 00184 /* output : oid=$(ROOT).prodId.stat.branch_num[branch].***.***.*** 00185 <-------------- len ----------> 00186 <---------- MAX_OID_LEN ----------> 00187 */ 00188 } 00189 00190 static const char *branch_to_str(int branch) 00191 { 00192 static char bstr[12]; 00193 switch(branch) 00194 { 00195 case STAT_OID: return "stat"; 00196 case LOG_OID: return "log"; 00197 #ifdef _ERROR_INJECTION 00198 case INJECT_OID: return "inject"; 00199 #endif 00200 case CONF_OID: return "conf"; 00201 case PROC_OID: return "proc"; 00202 default: 00203 snprintf(bstr, sizeof(bstr), "%d", branch); 00204 return bstr; 00205 } 00206 } 00207 00208 /* register a scalar in the tree */ 00209 static int register_scal_instance(int type, const register_scal * instance) 00210 { 00211 int err1, err2 = 0; 00212 register_info *info; 00213 00214 oid myoid[MAX_OID_LEN]; 00215 size_t len; 00216 00217 if(instance->value != NULL) 00218 { 00219 /* create a register object of scalar type. 00220 we know we need 4 netsnmp register objects to record a scalar 00221 */ 00222 info = new_register(instance->label, instance->desc, SCAL, 4); /* name+desc+type+value = 4 */ 00223 00224 get_oid(myoid, type, &len); 00225 00226 /* This function will register two value in the tree (name and desc) 00227 */ 00228 err1 = register_meta(myoid, len, info->label, info->desc, info->reg); 00229 00230 /* value */ 00231 myoid[len - 1] = VAR_OID; 00232 /* register a scalar in the tree 00233 we use the last two netsnmp register (type and value) 00234 */ 00235 err2 = reg_scal(myoid, len, instance->value, instance->type, instance->access, info->reg + 2); /* name+desc offset */ 00236 } 00237 else 00238 { 00239 err1 = 1; 00240 snmp_adm_log("Cannot register NULL value for \"%s\"", instance->label); 00241 } 00242 00243 return err1 || err2; 00244 } 00245 00246 /* register a getset in the tree */ 00247 static int register_get_set_instance(int branch, const register_get_set * instance) 00248 { 00249 int err1, err2 = 0; 00250 register_info *info; 00251 get_set_info *gs_info; 00252 00253 oid myoid[MAX_OID_LEN]; 00254 size_t len; 00255 00256 if(instance->getter != NULL && 00257 !(instance->access == SNMP_ADM_ACCESS_RW && instance->setter == NULL)) 00258 { 00259 00260 get_oid(myoid, branch, &len); 00261 /* create a register object of get/set type. 00262 we know we need 4 netsnmp register objects to record a get/set 00263 */ 00264 info = new_register(instance->label, instance->desc, GET_SET, 4); /* name+desc+type+value = 4 */ 00265 00266 /* add get/set specific information on register */ 00267 gs_info = info->function_info.get_set = malloc(sizeof(get_set_info)); 00268 00269 gs_info->getter = instance->getter; 00270 gs_info->setter = instance->setter; 00271 gs_info->type = instance->type; 00272 gs_info->branch = branch; 00273 gs_info->num = myoid[len - 2]; 00274 gs_info->opt_arg = instance->opt_arg; 00275 00276 /* This function will register two value in the tree (name and desc) 00277 */ 00278 err1 = register_meta(myoid, len, info->label, info->desc, info->reg); 00279 /* value */ 00280 myoid[len - 1] = VAR_OID; 00281 /* register a get/set in the tree 00282 we use the last two netsnmp register (type and value) 00283 */ 00284 err2 = reg_get_set(myoid, len, instance->type, instance->access, info->reg + 2); /* name+desc offset */ 00285 } 00286 else 00287 { 00288 err1 = 1; 00289 snmp_adm_log("Cannot register NULL function for \"%s\"", instance->label); 00290 } 00291 00292 return err1 || err2; 00293 } 00294 00295 /* register a proc in the tree */ 00296 static int register_proc_instance(const register_proc * instance) 00297 { 00298 int err1, err2; 00299 int i, j; 00300 oid myoid[MAX_OID_LEN]; 00301 size_t len; 00302 register_info *info; 00303 proc_info *p_info; 00304 int tab_reg_offset = 0; 00305 00306 if(instance->myproc == NULL) 00307 { 00308 snmp_adm_log("Cannot register NULL procedure for \"%s\"", instance->label); 00309 return 1; 00310 } 00311 00312 get_oid(myoid, PROC_OID, &len); 00313 00314 /* create a register object of proc type. 00315 we know we need 2 + 1 (name,desc + trigger) 00316 + n_in * types + n_in * val 00317 + n_out * types + n_out * val 00318 netsnmp register objects to record a proc 00319 This function will register the first and the second (name and desc) 00320 */ 00321 info = new_register(instance->label, instance->desc, PROC, 00322 3 + 2 * (instance->nb_in + instance->nb_out)); 00323 00324 /* add register specific info */ 00325 p_info = info->function_info.proc = malloc(sizeof(proc_info)); 00326 00327 p_info->num = myoid[len - 2]; 00328 p_info->nb_in = instance->nb_in; 00329 p_info->nb_out = instance->nb_out; 00330 p_info->myproc = instance->myproc; 00331 p_info->trigger = 0; 00332 p_info->opt_arg = instance->opt_arg; 00333 00334 /* input */ 00335 p_info->inputs = malloc(p_info->nb_in * sizeof(snmp_adm_type_union *)); 00336 for(j = 0; j < p_info->nb_in; j++) 00337 p_info->inputs[j] = calloc(1, sizeof(snmp_adm_type_union)); 00338 00339 /* output */ 00340 p_info->outputs = malloc(p_info->nb_out * sizeof(snmp_adm_type_union *)); 00341 for(j = 0; j < p_info->nb_out; j++) 00342 p_info->outputs[j] = calloc(1, sizeof(snmp_adm_type_union)); 00343 00344 /* This function will register two value in the tree (name and desc) 00345 */ 00346 err1 = register_meta(myoid, len, info->label, info->desc, info->reg); 00347 tab_reg_offset += 2; 00348 00349 myoid[len - 1] = TRIGGER_OID; 00350 err2 = reg_proc(myoid, len, info->reg + tab_reg_offset); /* register the instance and save info */ 00351 tab_reg_offset++; 00352 00353 /* 00354 * register values 00355 */ 00356 /* we need a longer tree */ 00357 len += 2; 00358 myoid[len - 3] = VAR_OID; 00359 00360 /* values are like scalars */ 00361 /* input */ 00362 for(i = 0; i < instance->nb_in; i++) 00363 { 00364 myoid[len - 2] = INPUT_OID; 00365 myoid[len - 1] = i; 00366 reg_scal(myoid, len, p_info->inputs[i]->string, instance->type_in[i], 00367 SNMP_ADM_ACCESS_RW, info->reg + tab_reg_offset); 00368 tab_reg_offset += 2; 00369 } 00370 /* output */ 00371 for(i = 0; i < instance->nb_out; i++) 00372 { 00373 myoid[len - 2] = OUTPUT_OID; 00374 myoid[len - 1] = i; 00375 reg_scal(myoid, len, p_info->outputs[i]->string, instance->type_out[i], 00376 SNMP_ADM_ACCESS_RO, info->reg + tab_reg_offset); 00377 tab_reg_offset += 2; 00378 } 00379 return err1 || err2; 00380 } 00381 00382 static void free_register_info(register_info * ptr) 00383 { 00384 int i; 00385 proc_info *pinfo; 00386 get_set_info *gsinfo; 00387 00388 free(ptr->label); 00389 free(ptr->desc); 00390 free(ptr->reg); 00391 ptr->reg = NULL; 00392 00393 if(ptr->type == PROC) 00394 { 00395 pinfo = ptr->function_info.proc; 00396 for(i = 0; i < pinfo->nb_in; i++) 00397 free(pinfo->inputs[i]); 00398 00399 free(pinfo->inputs); 00400 pinfo->inputs = NULL; 00401 00402 for(i = 0; i < pinfo->nb_out; i++) 00403 free(pinfo->outputs[i]); 00404 00405 free(pinfo->outputs); 00406 pinfo->outputs = NULL; 00407 00408 free(pinfo); 00409 } 00410 else if(ptr->type == GET_SET) 00411 { 00412 gsinfo = ptr->function_info.get_set; 00413 free(gsinfo); 00414 } 00415 } 00416 00426 int snmp_adm_config_daemon(char *agent_x_socket, char *filelog, int prod_id) 00427 { 00428 int err_init; 00429 00430 product_id = prod_id; 00431 00432 /* make us a agentx client. */ 00433 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); 00434 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 00435 NETSNMP_DS_AGENT_X_SOCKET, agent_x_socket); 00436 00437 /* error logging */ 00438 if(strncmp(filelog, "syslog", 10) == 0) 00439 { 00440 snmp_enable_syslog(); 00441 issyslog = 1; 00442 } 00443 else 00444 snmp_enable_filelog(filelog, 1); /* 1:append 0:write */ 00445 00446 if(get_conf_from_env() == 0) 00447 { 00448 int i, len = 1024, write = 0, offset = 0; 00449 char buf[1024]; 00450 for(i = 0; i < root_oid_len; i++) 00451 { 00452 offset += write; 00453 len -= write; 00454 write = snprintf(buf + offset, len, ".%lu", (unsigned long) root_oid[i]); 00455 } 00456 snmp_adm_log("ROOT_OID=%s", buf); 00457 } 00458 else 00459 { 00460 snmp_adm_log("cannot find a valid ROOT_OID"); 00461 configured = 0; 00462 return 1; 00463 } 00464 00465 /* initialize the agent library */ 00466 err_init = init_agent("libdaemon"); 00467 init_snmp("libdaemon"); 00468 00469 if(!err_init) 00470 configured = 1; 00471 return err_init; 00472 } 00473 00485 int snmp_adm_register_scalars(int branch, register_scal * tab, int len) 00486 { 00487 int i, err; 00488 00489 for(i = 0; i < len; i++) 00490 { 00491 /* register the instance and save info */ 00492 err = register_scal_instance(branch, &(tab[i])); 00493 if(err) 00494 { 00495 snmp_adm_log("ERROR registering %s %s", 00496 branch_to_str(branch), tab[i].label); 00497 return 1; 00498 } 00499 else 00500 snmp_adm_log("register %s %s", branch_to_str(branch), tab[i].label); 00501 } 00502 registered = 1; 00503 return 0; 00504 } 00505 00515 int snmp_adm_register_get_set_function(int branch, register_get_set * tab, int len) 00516 { 00517 int i, err; 00518 00519 for(i = 0; i < len; i++) 00520 { 00521 /* register the instance and save info */ 00522 err = register_get_set_instance(branch, &(tab[i])); 00523 if(err) 00524 { 00525 snmp_adm_log("ERROR registering getset %s %s", 00526 branch_to_str(branch), tab[i].label); 00527 return 1; 00528 } 00529 else 00530 snmp_adm_log("register getset %s %s", branch_to_str(branch), 00531 tab[i].label); 00532 00533 } 00534 registered = 1; 00535 00536 return 0; 00537 } 00538 00547 int snmp_adm_register_procedure(register_proc * tab, int len) 00548 { 00549 int i, err; 00550 00551 for(i = 0; i < len; i++) 00552 { 00553 err = register_proc_instance(&(tab[i])); 00554 if(err) 00555 { 00556 snmp_adm_log("register proc %s", tab[i].label); 00557 return 1; 00558 } 00559 else 00560 snmp_adm_log("register proc %s", tab[i].label); 00561 00562 } 00563 registered = 1; 00564 return 0; 00565 } 00566 00572 int snmp_adm_unregister(char *label) 00573 { 00574 register_info *prev, *ptr; 00575 int i; 00576 00577 prev = register_info_list; 00578 00579 for(ptr = register_info_list; ptr; ptr = ptr->next) 00580 { 00581 if(strncmp(ptr->label, label, strlen(label)) == 0) 00582 break; 00583 prev = ptr; 00584 } 00585 00586 if(ptr) 00587 { 00588 /* unlink */ 00589 prev->next = ptr->next; 00590 /* unreg */ 00591 for(i = 0; i < ptr->reg_len; i++) 00592 if(unreg_instance(ptr->reg[i]) != MIB_UNREGISTERED_OK) 00593 return 1; 00594 /* free */ 00595 free_register_info(ptr); 00596 00597 return 0; 00598 } 00599 return 2; 00600 } 00601 00607 void snmp_adm_send_trap(unsigned char type, snmp_adm_type_union value) 00608 { 00609 char str[256]; 00610 int err = 0; 00611 struct variable_list vars; /* NetSNMP type */ 00612 00613 /* trap oid==root_oid.999 */ 00614 int len = root_oid_len + 1; 00615 oid trap[root_oid_len + 1]; 00616 00617 memcpy(trap, root_oid, root_oid_len * sizeof(oid)); 00618 trap[root_oid_len] = 999; 00619 00620 vars.next_variable = NULL; 00621 vars.name = trap; 00622 vars.name_length = len; 00623 00624 switch (type) 00625 { 00626 case SNMP_ADM_INTEGER: 00627 vars.val.integer = (long *)&(value.integer); 00628 vars.val_len = sizeof(value.integer); 00629 vars.type = ASN_INTEGER; 00630 break; 00631 case SNMP_ADM_STRING: 00632 vars.val.string = (unsigned char *)&(value.string); 00633 vars.val_len = strlen(value.string); 00634 vars.type = ASN_OCTET_STR; 00635 break; 00636 case SNMP_ADM_REAL: 00637 err = real2str(str, value.real); 00638 vars.val.string = str; 00639 vars.val_len = strlen(str); 00640 vars.type = ASN_OCTET_STR; 00641 break; 00642 case SNMP_ADM_BIGINT: 00643 err = big2str(str, value.real); 00644 vars.val.string = str; 00645 vars.val_len = strlen(str); 00646 vars.type = ASN_OCTET_STR; 00647 break; 00648 } 00649 if(!err) 00650 send_trap_vars(6, 0, &vars); 00651 } 00652 00661 int snmp_adm_register_poll_trap(unsigned int second, trap_test test_fct, void *args, 00662 unsigned char type, snmp_adm_type_union value) 00663 { 00664 static int capacity = 10; 00665 00666 if(polling_list_size == 0) 00667 { 00668 if( ( polling_threads = malloc(capacity * sizeof(pthread_t)) ) == NULL ) 00669 return -1 ; 00670 00671 if( ( polling_args = malloc(capacity * sizeof(polling_arg)) ) == NULL ) 00672 { 00673 free( polling_threads ) ; 00674 return -1 ; 00675 } 00676 } 00677 if(polling_list_size >= capacity - 1) 00678 { 00679 capacity *= 2; 00680 00681 if ( ( polling_threads = realloc(polling_threads, sizeof(pthread_t) * capacity) ) == NULL ) 00682 { 00683 free( polling_args ) ; 00684 free( polling_threads ) ; 00685 return -1 ; 00686 } 00687 if( ( polling_args = realloc(polling_args, sizeof(polling_arg) * capacity) ) == NULL ) 00688 { 00689 free( polling_args ) ; 00690 free( polling_threads ) ; 00691 return -1 ; 00692 } 00693 } 00694 00695 polling_args[polling_list_size].second = second; 00696 polling_args[polling_list_size].test_fct = test_fct; 00697 polling_args[polling_list_size].type = type; 00698 polling_args[polling_list_size].value = value; 00699 polling_args[polling_list_size].args = args; 00700 00701 pthread_create(&polling_threads[polling_list_size], NULL, polling_fct, 00702 &polling_args[polling_list_size]); 00703 polling_list_size++; 00704 00705 return 0; 00706 } 00707 00711 void snmp_adm_close() 00712 { 00713 int err, i; 00714 register_info *ptr, *next; 00715 00716 running = 0; 00717 00718 if(thread_id) 00719 { 00720 err = pthread_cancel(thread_id); 00721 if(!err) 00722 pthread_join(thread_id, NULL); 00723 } 00724 for(ptr = register_info_list; ptr;) 00725 { 00726 next = ptr->next; 00727 00728 for(i = 0; i < ptr->reg_len; i++) 00729 unreg_instance(ptr->reg[i]); 00730 free_register_info(ptr); 00731 free(ptr); 00732 00733 ptr = next; 00734 } 00735 register_info_list = NULL; 00736 00737 for(i = 0; i < polling_list_size; i++) 00738 { 00739 err = pthread_cancel(polling_threads[i]); 00740 if(!err) 00741 pthread_join(polling_threads[i], NULL); 00742 } 00743 free(polling_threads); 00744 free(polling_args); 00745 00746 polling_threads = NULL; 00747 polling_args = NULL; 00748 00749 if(root_oid) 00750 free(root_oid); 00751 00752 snmp_adm_log("terminated"); 00753 snmp_shutdown("libdaemon"); 00754 } 00755 00763 int snmp_adm_start() 00764 { 00765 int err; 00766 00767 if(registered == 0) 00768 { 00769 snmp_adm_log("Warning nothing has been registered !"); 00770 return 1; 00771 } 00772 if(configured == 0) 00773 { 00774 snmp_adm_log("Warning snmp is not configured !\t" 00775 "Did you called config_daemon? snmpd is running?"); 00776 return 2; 00777 } 00778 00779 err = pthread_create(&thread_id, NULL, pool, NULL); 00780 if(err) 00781 { 00782 snmp_adm_log("cannot create thread"); 00783 snmp_adm_close(); 00784 return 3; 00785 } 00786 snmp_adm_log("started"); 00787 return 0; 00788 } 00789 00794 void snmp_adm_log(char *format, ...) 00795 { 00796 va_list pa; 00797 char msg_buf[256]; 00798 struct tm the_date; 00799 00800 va_start(pa, format); 00801 00802 if(issyslog) 00803 { 00804 vsnprintf(msg_buf, 256, format, pa); 00805 snmp_log(LOG_NOTICE, "%s", msg_buf); 00806 } 00807 else 00808 { 00809 /* emulate a syslog like format on a file */ 00810 00811 char now[128]; 00812 time_t clock = time(NULL); 00813 00814 static pid_t pid = 0; 00815 static char constant_buf[256]; 00816 00817 if(!pid) 00818 { 00819 int name_len; 00820 /* first call, let's configure */ 00821 gethostname(constant_buf, 256); 00822 pid = getpid(); 00823 name_len = strlen(constant_buf); 00824 snprintf(constant_buf + name_len, 256 - name_len, ": snmp_adm-%d: ", pid); 00825 } 00826 00827 localtime_r(&clock, &the_date); 00828 snprintf(now, 128, "%.2d/%.2d/%.4d %.2d:%.2d:%.2d epoch=%ld: ", 00829 the_date.tm_mday, the_date.tm_mon + 1, 1900 + the_date.tm_year, 00830 the_date.tm_hour, the_date.tm_min, the_date.tm_sec, clock); 00831 00832 vsnprintf(msg_buf, 256, format, pa); 00833 00834 snmp_log(LOG_NOTICE, "%s => %s : %s\n", now, constant_buf, msg_buf); 00835 } 00836 va_end(pa); 00837 }