nfs-ganesha 1.4

libdaemon.c

Go to the documentation of this file.
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 }