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