Whamcloud - gitweb
LU-11303 out: clean up osp_update_rpc_pack() macro
[fs/lustre-release.git] / snmp / lustre-snmp-util.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*
27  * This file is part of Lustre, http://www.lustre.org/
28  * Lustre is a trademark of Sun Microsystems, Inc.
29  *
30  * snmp/lustre-snmp-util.c
31  *
32  * Author: PJ Kirner <pjkirner@clusterfs.com>
33  */
34
35 /*
36  *   include important headers
37  */
38
39 #include <net-snmp/net-snmp-config.h>
40 #include <net-snmp/net-snmp-includes.h>
41 #include <net-snmp/agent/net-snmp-agent-includes.h>
42
43 /*
44  *  include our .h file
45  */ 
46
47 #include <sys/types.h>
48 #include <sys/vfs.h>
49 #include <dirent.h>
50 #include <sys/stat.h>
51 #include <unistd.h>
52 #include <stdio.h>
53 #include <stdarg.h>
54 #include <string.h>
55 #include "lustre-snmp-util.h"
56
57 /*********************************************************************
58  * Function:    get_file_list
59  *
60  * Description: For the given valid directory  path, returns the list
61  *              all directories or files in that path.
62  *
63  * Input:   'dirname' the directory path.
64  *          'file_type' if this takes the value DIR_TYPE then
65  *              returns the list of directories in that path.
66  *          If its of type FILE_TYPE then returns the list of files
67  *          in that path.
68  *          'count' pointer to number of elements returned in the
69  *          return string. 
70  *
71  * Output:  List of  directories/files in that path.
72  *
73  *********************************************************************/
74
75 char *get_file_list(const char *dirname, int file_type, uint32_t *count)
76 {
77
78     DIR           *pdir = NULL;
79     struct dirent *pdirent = NULL;
80     int           curr_offset = 0;
81     int           byte_count = 0;
82     int           file_count = 0;
83     char          *ret_str = NULL;
84     char          filename[MAX_PATH_SIZE];
85     int           cond1, cond2;
86
87     if ((dirname == NULL) || ((pdir = opendir(dirname)) == NULL )) {
88         if (dirname == NULL) {
89             report("%s %s:line %d %s", __FILE__, __FUNCTION__, __LINE__,
90                    "NULL directory is passed as parameter to funtion");
91         } else {
92             report("%s %s:line %d Error in opening the dir %s", __FILE__,
93                    __FUNCTION__, __LINE__, dirname);
94         }
95         if (count)
96             *count = 0;
97         return NULL;
98     }
99
100     while (1) {
101         if ((pdirent = readdir(pdir)) == NULL)
102             break;
103
104         /* Skip over '.' and '..' directores */
105         if ((pdirent->d_name[0] == '.') ||
106             !strcmp(pdirent->d_name, FILENAME_NUM_REF))
107             continue;
108         
109         sprintf(filename, "%s/%s", dirname, pdirent->d_name);
110         cond1 = (file_type == FILE_TYPE) && is_directory(filename);
111         cond2 = (file_type == DIR_TYPE) && (!is_directory(filename));
112
113         if (cond1 || cond2)
114             continue;
115
116         /* Calculate the number of bytes for this new entry.*/                    
117         byte_count += strlen(pdirent->d_name) + 1;
118         file_count++;
119     }
120     if (count)
121         *count = file_count;
122     
123     if (file_count != 0) {
124         
125         /* need one extra one for the finall NULL terminator*/
126         if ((ret_str = (char *) malloc(byte_count + 1)) == NULL) {
127             report("get_file_list() failed to malloc(%d)",byte_count+1);
128             closedir(pdir);
129             return NULL;
130         }    
131         
132         rewinddir(pdir);
133         
134         while (file_count != 0) {
135             if ((pdirent = readdir(pdir)) == NULL)
136                 break;
137
138             if ((pdirent->d_name[0] == '.') ||
139                 !strcmp(pdirent->d_name, FILENAME_NUM_REF))
140                 continue;
141             
142             sprintf(filename, "%s/%s", dirname, pdirent->d_name);
143             cond1 = (file_type == FILE_TYPE) && is_directory(filename);
144             cond2 = (file_type == DIR_TYPE) && (!is_directory(filename));
145
146             if (cond1 || cond2)
147                 continue;
148
149             strcpy(ret_str + curr_offset, pdirent->d_name);
150             curr_offset = curr_offset + strlen(pdirent->d_name) + 1;
151             file_count--;
152         }
153         /* Put in the finall null terminator*/
154         ret_str[byte_count] = '\0';
155     }
156     closedir(pdir);
157     return ret_str;
158 }
159
160
161 /*********************************************************************
162  * Function:    is_directory
163  *
164  * Description: Checks if given filename is a directory or not.
165  *              all directories or files in that path.
166  *
167  * Input:   'filename' the directory path to be checked.
168  *
169  * Output:  Returns 1 if its a directory else 0.
170  *
171  *********************************************************************/
172
173 int is_directory(const char *filename)
174 {
175
176     struct stat statf;
177     int result;
178
179     result = stat(filename, &statf);
180     return ((result == SUCCESS) && (statf.st_mode & S_IFDIR));
181 }
182
183 /*********************************************************************
184  * Function:    read_string
185  *
186  * Description: For the given valid file path, reads the data in
187  *              that file.
188  *
189  * Input:   'filepath' the file whose data is to be accessed.
190  *          'lustre_var' the data from the file is read into
191  *           this variable, returned to the requestor.
192  *          'var_max_size' the max size of the string
193  *          'report_error' boolean if error should be reported on 
194  *           missing filepath
195  *
196  * Output:  Returns SUCCESS if read successfully from file else
197  *          returns ERROR.
198  *********************************************************************/
199  
200 int  read_string(const char *filepath, char *lustre_var, size_t var_max_size)
201 {
202     FILE    *fptr = NULL;
203     int     len = 0;
204     int     ret_val = SUCCESS;
205     int     report_error = 1;
206
207     if ((filepath == NULL) || (lustre_var == NULL)) {
208         report("%s %s:line %d %s", __FILE__, __FUNCTION__, __LINE__,
209                "Input parameter is NULL");
210         ret_val = ERROR;
211     } else {
212         fptr = fopen(filepath, "r");
213
214         if (fptr == NULL) {
215             if(report_error)
216                 report("%s %s:line %d Unable to open the file %s", __FILE__,
217                        __FUNCTION__, __LINE__, filepath);
218             ret_val = ERROR;
219         } else {
220             if (fgets(lustre_var, var_max_size, fptr) == NULL) {
221                 report("%s %s:line %d read failed for file %s", __FILE__,
222                        __FUNCTION__, __LINE__, filepath);
223                  ret_val = ERROR;
224             } else {
225                 len = strlen(lustre_var);
226                 /*
227                     Last char is EOF, before string ends,
228                     so '\0' is moved to last but one.
229                 */
230                 lustre_var[len-1] = lustre_var[len];
231             }
232             fclose(fptr);
233         }
234     }
235     return ret_val;
236 }
237
238 /**************************************************************************
239  * Function:   lustrefs_ctrl
240  *
241  * Description: Execute /etc/init.d/lustre script for starting,
242  *              stopping and restarting Lustre services in child process.
243  *
244  * Input:  Start/Stop/Restart Command Number.
245  * Output: Returns  void
246  *
247  **************************************************************************/
248
249 void lustrefs_ctrl(int command)
250 {
251     char *cmd[3];
252
253     cmd[0] = LUSTRE_SERVICE;
254     switch (command) {
255     case ONLINE:
256         cmd[1] = "start";
257         break;
258     case OFFLINE:
259         cmd[1] = "stop";
260         break;
261     case RESTART:
262         cmd[1] = "restart";
263         break;
264     default:
265         return;
266     }
267
268     cmd[2] = (char *)0;
269
270     if (fork() == 0) {
271         execvp(cmd[0], cmd);
272         report("failed to execvp(\'%s %s\')",cmd[0],cmd[1]);
273     }
274     return;
275 }
276
277 /*****************************************************************************
278  * Function:     get_sysstatus
279  *
280  * Description:  Read /var/lustre/sysStatus file, and based on file contents
281  *               return the status of Lustre services.
282  *
283  * Input:   void
284  * Output:  Return ONLINE/OFFLINE/ONLINE PENDING/OFFLINE PENDING status
285  *          values.
286  *
287  ****************************************************************************/
288
289 int get_sysstatus(void)
290 {
291     int     ret_val = ERROR ;
292     char    sys_status[50] = {0};
293     
294     if(SUCCESS == read_string(FILENAME_SYS_STATUS,sys_status,sizeof(sys_status)))
295     {
296         if (memcmp(sys_status, STR_ONLINE_PENDING,strlen(STR_ONLINE_PENDING)) == 0)
297             ret_val = ONLINE_PENDING;
298         else if (memcmp(sys_status, STR_ONLINE, strlen(STR_ONLINE)) == 0)
299             ret_val = ONLINE;
300         else if (memcmp(sys_status, STR_OFFLINE_PENDING,strlen(STR_OFFLINE_PENDING)) == 0)
301             ret_val = OFFLINE_PENDING;
302         else if (memcmp(sys_status, STR_OFFLINE, strlen(STR_OFFLINE)) == 0)
303             ret_val = OFFLINE;
304         else
305             report("%s %s:line %d Bad Contents in file %s \'%s\'", __FILE__,
306                 __FUNCTION__, __LINE__, FILENAME_SYS_STATUS,sys_status);
307     }
308     return ret_val;
309 }
310
311
312 /*****************************************************************************
313  * Function:     read_ulong
314  *
315  * Description:  Read long values from lproc and copy to the location
316  *               pointed by input parameter.
317  *
318  * Input:   file path, and pointer for data to be copied
319  *
320  * Output:  Return ERROR or SUCCESS.
321  *
322  ****************************************************************************/
323
324 int read_ulong(const char *file_path, unsigned long *valuep)
325 {
326     char    file_data[MAX_LINE_SIZE];
327     int     ret_val;
328
329     if ((ret_val = read_string(file_path, file_data,sizeof(file_data))) == SUCCESS){
330         *valuep = strtoul(file_data,NULL,10);
331     }
332     return ret_val;
333 }
334
335 /*****************************************************************************
336  * Function:     read_counter64
337  *
338  * Description:  Read counter64 values from lproc and copy to the location
339  *               pointed by input parameter.
340  *
341  * Input:   file path, and pointer for data to be copied
342  *
343  * Output:  Return ERROR or SUCCESS.
344  *
345  ****************************************************************************/
346
347 int read_counter64(const char *file_path, counter64 *c64,int factor)
348 {
349     char    file_data[MAX_LINE_SIZE];
350     int     ret_val;
351     unsigned long long tmp = 0;
352
353     if ((ret_val = read_string(file_path, file_data,sizeof(file_data))) == SUCCESS) {
354         tmp = atoll(file_data) * factor;
355         c64->low = (unsigned long) (0x0FFFFFFFF & tmp);
356         tmp >>= 32; /* Shift right by 4 bytes */
357         c64->high = (unsigned long) (0x0FFFFFFFF & tmp);
358     }
359     return ret_val;
360 }
361
362 /*****************************************************************************
363  * Function:     get_nth_entry_from_list
364  *
365  * Description:  Find the n'th entry from a null terminated list of string
366  *
367  * Input:   dir_list - the list
368  *          num - the number of elements in the list
369  *          index - the index we are looking for
370  *
371  * Output:  Return NULL on failure, or the string name on success.
372  *
373  ****************************************************************************/
374
375 const char *get_nth_entry_from_list(const char* dir_list,int num,int index)
376 {
377     int i;
378     int cur_ptr = 0;
379     for(i=0;i<num;i++){
380         
381         /* 
382          * if we've reached the end of the list for some reason
383          * because num was wrong then stop processing
384          */
385         if( *(dir_list+cur_ptr) == 0)
386             break;
387             
388         /* If we've found the right one */    
389         if( i == index )
390             return dir_list+cur_ptr;
391             
392         /* Move to the next one*/            
393         cur_ptr += strlen(dir_list + cur_ptr)+1;
394     }
395     return NULL;
396 }
397
398 /*****************************************************************************
399  * Function:    report
400  *
401  * Description: This function used to report error msg to stderr and log into
402  *    log file(default file:/var/log/snmpd.log) when agent is started with
403  *    debug option -Dlsnmpd
404  * Input:   format string and variable arguments.
405  * Output:  void
406  ****************************************************************************/
407
408 void report(const char *fmt, ...)
409 {
410     char buf[1024];
411
412     va_list arg_list;
413     va_start(arg_list, fmt);
414     vsprintf(buf, fmt, arg_list);
415     va_end(arg_list);
416
417     DEBUGMSGTL(("lsnmpd", "%s\n", buf));
418     fprintf(stderr, "%s\n", buf);
419     return;
420 }
421
422
423
424 /**************************************************************************
425  * Function:   oid_table_ulong_handler
426  *
427  * Description: Fetch a unsigned long from the given location.
428  *              Setup var_len, and return a pointer to the data.
429  *
430  * Input:  file_path, and var_len pointer
431  *
432  * Output: NULL on failure, or pointer to data
433  *
434  **************************************************************************/
435
436 unsigned char* 
437     oid_table_ulong_handler(
438         const char* file_path,
439         size_t  *var_len)
440 {
441     static unsigned long ulong_ret;
442     if (SUCCESS != read_ulong(file_path,&ulong_ret))
443         return NULL;
444     *var_len = sizeof(ulong_ret);
445     return  (unsigned char *) &ulong_ret;
446 }
447
448 /**************************************************************************
449  * Function:   oid_table_c64_handler
450  *
451  * Description: Fetch a counter64 from the given location.
452  *              Setup var_len, and return a pointer to the data.
453  *
454  * Input:  file_path, and var_len pointer
455  *
456  * Output: NULL on failure, or pointer to data
457  *
458  **************************************************************************/
459
460 unsigned char* oid_table_c64_handler(const char* file_path,size_t  *var_len)
461 {
462     static counter64 c64;
463     if (SUCCESS != read_counter64(file_path,&c64,1))
464         return NULL;
465     *var_len = sizeof(c64);
466     return (unsigned char *) &c64;
467 }
468
469 /**************************************************************************
470  * Function:   oid_table_c64_kb_handler
471  *
472  * Description: Fetch a counter64 from the given location.
473  *              Setup var_len, and return a pointer to the data.
474  *              Different than oid_table_c64_handler in that
475  *              the original value is multiplied by 1024 before converting
476  *              to a counter64.  (e.g. turn KB into a Byte scaled value)
477  *
478  * Input:  file_path, and var_len pointer
479  *
480  * Output: NULL on failure, or pointer to data
481  *
482  **************************************************************************/
483
484 unsigned char* oid_table_c64_kb_handler(const char* file_path,size_t  *var_len)
485 {
486     static counter64 c64;
487     /* scale by factor of 1024*/
488     if (SUCCESS != read_counter64(file_path,&c64,1024))
489         return NULL;
490     *var_len = sizeof(c64);
491     return (unsigned char *) &c64;
492 }
493
494 /**************************************************************************
495  * Function:   oid_table_obj_name_handler
496  *
497  * Description: Just copy the file_path and return as the output value.
498  *
499  * Input:  file_path, and var_len pointer
500  *
501  * Output: NULL on failure, or pointer to data
502  *
503  **************************************************************************/
504
505 unsigned char* 
506     oid_table_obj_name_handler(
507         const char* file_path,
508         size_t  *var_len)
509 {
510     static unsigned char string[SPRINT_MAX_LEN];
511     *var_len = strlen(file_path);
512     *var_len = MIN_LEN(*var_len, sizeof(string));
513     memcpy(string, file_path, *var_len);
514     return (unsigned char *) string;
515 }
516
517 /**************************************************************************
518  * Function:   oid_table_string_handler
519  *
520  * Description: Fetch a string from the given location.
521  *              Setup var_len, and return a pointer to the data.
522  *
523  * Input:  file_path, and var_len pointer
524  *
525  * Output: NULL on failure, or pointer to data
526  *
527  **************************************************************************/
528
529 unsigned char* 
530     oid_table_string_handler(
531         const char* file_path,
532         size_t  *var_len)
533 {
534     static unsigned char string[SPRINT_MAX_LEN];
535     if( SUCCESS != read_string(file_path, (char *)string,sizeof(string)))
536         return NULL;
537     *var_len = strlen((char *)string);
538     return (unsigned char *) string;
539 }
540
541
542 /**************************************************************************
543  * Function:   oid_table_is_directory_handler
544  *
545  * Description: Determine if the file_path is a directory.  
546  *              Setup a boolean return value.
547  *              Setup var_len, and return a pointer to the data.
548  *
549  * Input:  file_path, and var_len pointer
550  *
551  * Output: NULL on failure, or pointer to data
552  *
553  **************************************************************************/
554
555 unsigned char* 
556     oid_table_is_directory_handler(
557         const char* file_path,
558         size_t *var_len)
559 {
560     static long long_ret;
561     long_ret =  is_directory(file_path);
562     *var_len = sizeof(long_ret);
563     return (unsigned char *) &long_ret;
564 }
565
566 /**************************************************************************
567  * Function:   var_genericTable
568  *
569  * Description: Handle Table driven OID processing
570  *
571  **************************************************************************/
572
573 unsigned char *
574 var_genericTable(struct variable *vp,
575             oid     *name,
576             size_t  *length,
577             int     exact,
578             size_t  *var_len,
579             WriteMethod **write_method,
580             const char *path,
581             struct oid_table *ptable)
582 {
583     char *dir_list;
584     uint32_t num;
585     int  deviceindex;
586     unsigned char *ret_val = NULL;
587     int i=0;
588     const char* obj_name;
589     
590     
591     /*
592      * Get the list of file.  If there are no elements
593      * return nothing
594      */
595     if( 0 == (dir_list = get_file_list(path, DIR_TYPE, &num)))
596         return NULL;
597
598     /*
599      * Setup the table
600      */
601     if (header_simple_table(vp,name,length,exact,var_len,write_method, num)
602                                                 == MATCH_FAILED )
603         goto cleanup_and_exit;
604
605     /*
606      * The number of the device we're looking at
607      */
608     deviceindex = name[*length - 1] - 1;
609
610     /*
611      * If we couldn't find this element
612      * something must have recently changed return
613      * nothing
614      */
615     if(deviceindex >= num){
616         report("deviceindex=%d exceeds number of elements=%d",deviceindex,num);
617         goto cleanup_and_exit;
618     }
619
620     /*
621      * Fetch the object name from the list
622      */
623     obj_name = get_nth_entry_from_list(dir_list,num,deviceindex);
624     if(obj_name == NULL){
625         /*
626          * Note this should never really happen because we check deviceindex >=num
627          * above.  And dir_list should be consitent with num
628          * but just in case...
629          */
630         report("object name not found in list",deviceindex,num);
631         goto cleanup_and_exit;
632     }
633
634     /*
635      * Find the matching magic - or the end of the list
636      */
637     while(ptable[i].magic != vp->magic && ptable[i].magic != 0)
638         i++;
639
640     /*
641      * If we didn't find a matching entry return
642      */
643     if(ptable[i].magic==0)
644         goto cleanup_and_exit;
645
646     /*
647      * If the name is NULL is a special case and 
648      * just just pass the obj_name as the file_path
649      * otherwise we create a file path from the given components
650      */
651     if(ptable[i].name != 0){
652         char file_path[MAX_PATH_SIZE];
653         sprintf(file_path, "%s%s/%s",path,obj_name,ptable[i].name);
654         ret_val =  ptable[i].fhandler(file_path,var_len);
655     }
656     else
657         ret_val =  ptable[i].fhandler(obj_name,var_len);
658
659 cleanup_and_exit:
660     free(dir_list);
661     return ret_val;
662 };
663
664 /**************************************************************************
665  * Function:   stats_values
666  *
667  * Description: Setup nb_sample, min, max, sum and sum_square stats values
668                 for name_value from filepath.
669  *
670  * Input:  filepath, name_value,
671  *         pointer to nb_sample, min, max, sum, sum_square
672  *
673  * Output: SUCCESS or ERROR on failure
674  *
675  **************************************************************************/
676 int stats_values(char * filepath,char * name_value, unsigned long long * nb_sample, unsigned long long * min, unsigned long long * max, unsigned long long * sum, unsigned long long * sum_square)
677 {
678   FILE * statfile;
679   char line[MAX_LINE_SIZE];
680   int nbReadValues = 0;
681
682   if( (statfile=fopen(filepath,"r")) == NULL) {
683     report("stats_value() failed to open %s",filepath);
684     return ERROR;
685   }
686 /*find the good line for name_value*/
687   do {
688     if( fgets(line,MAX_LINE_SIZE,statfile) == NULL ) {
689       report("stats_values() failed to find %s values in %s stat_file",name_value,statfile);
690       goto error_out;
691     }
692   } while ( strstr(line,name_value) == NULL );
693 /*get stats*/
694   if((nbReadValues=sscanf(line,"%*s %llu %*s %*s %llu %llu %llu %llu",nb_sample,min,max,sum,sum_square)) == 5) {
695     goto success_out;
696   } else if( nbReadValues == 1 && *nb_sample == 0) {
697     *min = *max = *sum = *sum_square = 0;
698     goto success_out;
699   } else {
700     report("stats_values() failed to read stats_values for %s value in %s stat_file",name_value,statfile);
701     goto error_out;
702   }
703
704 success_out :
705   fclose(statfile);
706   return SUCCESS;
707 error_out :
708   fclose(statfile);
709   return ERROR;
710 }
711
712 /**************************************************************************
713  * Function:   mds_stats_values
714  *
715  * Description: Setup nb_sample, min, max, sum and sum_square stats values
716                 for mds stats name_value .
717  *
718  * Input:  name_value,
719  *         pointer to nb_sample, min, max, sum, sum_square
720  *
721  * Output: SUCCESS or ERROR on failure
722  *
723  **************************************************************************/
724 extern int mds_stats_values(char * name_value, unsigned long long * nb_sample, unsigned long long * min, unsigned long long * max, unsigned long long * sum, unsigned long long * sum_square)
725 {
726   unsigned long long tmp_nb_sample=0,tmp_min=0,tmp_max=0,tmp_sum=0,tmp_sum_square=0;
727   glob_t path;
728
729 /*we parse the three MDS stat files and sum values*/
730   if (cfs_get_param_paths(&path, "mdt/MDS/mds/stats") != 0)
731     return ERROR;
732   if( stats_values(path.gl_pathv[0],name_value,&tmp_nb_sample,&tmp_min,&tmp_max,&tmp_sum,&tmp_sum_square) == ERROR ) {
733     cfs_free_param_data(&path);
734     return ERROR;
735   } else {
736     *nb_sample=tmp_nb_sample;
737     *min=tmp_min;
738     *max=tmp_max;
739     *sum=tmp_sum;
740     *sum_square=tmp_sum_square;
741   }
742   cfs_free_param_data(&path);
743
744   if (cfs_get_param_paths(&path, "mdt/MDS/mds_readpage/stats") != 0)
745     return ERROR;
746   if( stats_values(path.gl_pathv[0],name_value,&tmp_nb_sample,&tmp_min,&tmp_max,&tmp_sum,&tmp_sum_square) == ERROR ) {
747     cfs_free_param_data(&path);
748     return ERROR;
749   } else {
750     *nb_sample += tmp_nb_sample;
751     *min += tmp_min;
752     *max += tmp_max;
753     *sum += tmp_sum;
754     *sum_square += tmp_sum_square;
755   }
756   cfs_free_param_data(&path);
757
758   if (cfs_get_param_paths(&path, "mdt/MDS/mds_setattr/stats") != 0)
759     return ERROR;
760   if( stats_values(path.gl_pathv[0],name_value,&tmp_nb_sample,&tmp_min,&tmp_max,&tmp_sum,&tmp_sum_square) == ERROR ) {
761     cfs_free_param_data(&path);
762     return ERROR;
763   } else {
764     *nb_sample += tmp_nb_sample;
765     *min += tmp_min;
766     *max += tmp_max;
767     *sum += tmp_sum;
768     *sum_square += tmp_sum_square;
769   }
770   cfs_free_param_data(&path);
771   
772   return SUCCESS;
773 }
774
775 void convert_ull(counter64 *c64, unsigned long long ull, size_t *var_len)
776 {
777         *var_len  = sizeof(*c64);
778         c64->low  = (unsigned long long) (0x0ffffffff & ull);
779         ull >>= 32;
780         c64->high = (unsigned long long) (0x0ffffffff & ull);
781 }
782