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