4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
27 * This file is part of Lustre, http://www.lustre.org/
28 * Lustre is a trademark of Sun Microsystems, Inc.
30 * snmp/lustre-snmp-util.c
32 * Author: PJ Kirner <pjkirner@clusterfs.com>
36 * include important headers
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>
47 #include <sys/types.h>
55 #include "lustre-snmp-util.h"
57 /*********************************************************************
58 * Function: get_file_list
60 * Description: For the given valid directory path, returns the list
61 * all directories or files in that path.
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
68 * 'count' pointer to number of elements returned in the
71 * Output: List of directories/files in that path.
73 *********************************************************************/
75 char *get_file_list(const char *dirname, int file_type, uint32_t *count)
79 struct dirent *pdirent = NULL;
84 char filename[MAX_PATH_SIZE];
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");
92 report("%s %s:line %d Error in opening the dir %s", __FILE__,
93 __FUNCTION__, __LINE__, dirname);
101 if ((pdirent = readdir(pdir)) == NULL)
104 /* Skip over '.' and '..' directores */
105 if ((pdirent->d_name[0] == '.') ||
106 !strcmp(pdirent->d_name, FILENAME_NUM_REF))
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));
116 /* Calculate the number of bytes for this new entry.*/
117 byte_count += strlen(pdirent->d_name) + 1;
123 if (file_count != 0) {
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);
134 while (file_count != 0) {
135 if ((pdirent = readdir(pdir)) == NULL)
138 if ((pdirent->d_name[0] == '.') ||
139 !strcmp(pdirent->d_name, FILENAME_NUM_REF))
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));
149 strcpy(ret_str + curr_offset, pdirent->d_name);
150 curr_offset = curr_offset + strlen(pdirent->d_name) + 1;
153 /* Put in the finall null terminator*/
154 ret_str[byte_count] = '\0';
161 /*********************************************************************
162 * Function: is_directory
164 * Description: Checks if given filename is a directory or not.
165 * all directories or files in that path.
167 * Input: 'filename' the directory path to be checked.
169 * Output: Returns 1 if its a directory else 0.
171 *********************************************************************/
173 int is_directory(const char *filename)
179 result = stat(filename, &statf);
180 return ((result == SUCCESS) && (statf.st_mode & S_IFDIR));
183 /*********************************************************************
184 * Function: read_string
186 * Description: For the given valid file path, reads the data in
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
196 * Output: Returns SUCCESS if read successfully from file else
198 *********************************************************************/
200 int read_string(const char *filepath, char *lustre_var, size_t var_max_size)
204 int ret_val = SUCCESS;
205 int report_error = 1;
207 if ((filepath == NULL) || (lustre_var == NULL)) {
208 report("%s %s:line %d %s", __FILE__, __FUNCTION__, __LINE__,
209 "Input parameter is NULL");
212 fptr = fopen(filepath, "r");
216 report("%s %s:line %d Unable to open the file %s", __FILE__,
217 __FUNCTION__, __LINE__, filepath);
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);
225 len = strlen(lustre_var);
227 Last char is EOF, before string ends,
228 so '\0' is moved to last but one.
230 lustre_var[len-1] = lustre_var[len];
238 /**************************************************************************
239 * Function: lustrefs_ctrl
241 * Description: Execute /etc/init.d/lustre script for starting,
242 * stopping and restarting Lustre services in child process.
244 * Input: Start/Stop/Restart Command Number.
245 * Output: Returns void
247 **************************************************************************/
249 void lustrefs_ctrl(int command)
253 cmd[0] = LUSTRE_SERVICE;
272 report("failed to execvp(\'%s %s\')",cmd[0],cmd[1]);
276 /*****************************************************************************
277 * Function: get_sysstatus
279 * Description: Read /var/lustre/sysStatus file, and based on file contents
280 * return the status of Lustre services.
283 * Output: Return ONLINE/OFFLINE/ONLINE PENDING/OFFLINE PENDING status
286 ****************************************************************************/
288 int get_sysstatus(void)
290 int ret_val = ERROR ;
291 char sys_status[50] = {0};
293 if(SUCCESS == read_string(FILENAME_SYS_STATUS,sys_status,sizeof(sys_status)))
295 if (memcmp(sys_status, STR_ONLINE_PENDING,strlen(STR_ONLINE_PENDING)) == 0)
296 ret_val = ONLINE_PENDING;
297 else if (memcmp(sys_status, STR_ONLINE, strlen(STR_ONLINE)) == 0)
299 else if (memcmp(sys_status, STR_OFFLINE_PENDING,strlen(STR_OFFLINE_PENDING)) == 0)
300 ret_val = OFFLINE_PENDING;
301 else if (memcmp(sys_status, STR_OFFLINE, strlen(STR_OFFLINE)) == 0)
304 report("%s %s:line %d Bad Contents in file %s \'%s\'", __FILE__,
305 __FUNCTION__, __LINE__, FILENAME_SYS_STATUS,sys_status);
311 /*****************************************************************************
312 * Function: read_ulong
314 * Description: Read long values from lproc and copy to the location
315 * pointed by input parameter.
317 * Input: file path, and pointer for data to be copied
319 * Output: Return ERROR or SUCCESS.
321 ****************************************************************************/
323 int read_ulong(const char *file_path, unsigned long *valuep)
325 char file_data[MAX_LINE_SIZE];
328 if ((ret_val = read_string(file_path, file_data,sizeof(file_data))) == SUCCESS){
329 *valuep = strtoul(file_data,NULL,10);
334 /*****************************************************************************
335 * Function: read_counter64
337 * Description: Read counter64 values from lproc and copy to the location
338 * pointed by input parameter.
340 * Input: file path, and pointer for data to be copied
342 * Output: Return ERROR or SUCCESS.
344 ****************************************************************************/
346 int read_counter64(const char *file_path, counter64 *c64,int factor)
348 char file_data[MAX_LINE_SIZE];
350 unsigned long long tmp = 0;
352 if ((ret_val = read_string(file_path, file_data,sizeof(file_data))) == SUCCESS) {
353 tmp = atoll(file_data) * factor;
354 c64->low = (unsigned long) (0x0FFFFFFFF & tmp);
355 tmp >>= 32; /* Shift right by 4 bytes */
356 c64->high = (unsigned long) (0x0FFFFFFFF & tmp);
361 /*****************************************************************************
362 * Function: get_nth_entry_from_list
364 * Description: Find the n'th entry from a null terminated list of string
366 * Input: dir_list - the list
367 * num - the number of elements in the list
368 * index - the index we are looking for
370 * Output: Return NULL on failure, or the string name on success.
372 ****************************************************************************/
374 const char *get_nth_entry_from_list(const char* dir_list,int num,int index)
381 * if we've reached the end of the list for some reason
382 * because num was wrong then stop processing
384 if( *(dir_list+cur_ptr) == 0)
387 /* If we've found the right one */
389 return dir_list+cur_ptr;
391 /* Move to the next one*/
392 cur_ptr += strlen(dir_list + cur_ptr)+1;
397 /*****************************************************************************
400 * Description: This function used to report error msg to stderr and log into
401 * log file(default file:/var/log/snmpd.log) when agent is started with
402 * debug option -Dlsnmpd
403 * Input: format string and variable arguments.
405 ****************************************************************************/
407 void report(const char *fmt, ...)
412 va_start(arg_list, fmt);
413 vsprintf(buf, fmt, arg_list);
416 DEBUGMSGTL(("lsnmpd", "%s\n", buf));
417 fprintf(stderr, "%s\n", buf);
422 /**************************************************************************
423 * Function: oid_table_ulong_handler
425 * Description: Fetch a unsigned long from the given location.
426 * Setup var_len, and return a pointer to the data.
428 * Input: file_path, and var_len pointer
430 * Output: NULL on failure, or pointer to data
432 **************************************************************************/
435 oid_table_ulong_handler(
436 const char* file_path,
439 static unsigned long ulong_ret;
440 if (SUCCESS != read_ulong(file_path,&ulong_ret))
442 *var_len = sizeof(ulong_ret);
443 return (unsigned char *) &ulong_ret;
446 /**************************************************************************
447 * Function: oid_table_c64_handler
449 * Description: Fetch a counter64 from the given location.
450 * Setup var_len, and return a pointer to the data.
452 * Input: file_path, and var_len pointer
454 * Output: NULL on failure, or pointer to data
456 **************************************************************************/
458 unsigned char* oid_table_c64_handler(const char* file_path,size_t *var_len)
460 static counter64 c64;
461 if (SUCCESS != read_counter64(file_path,&c64,1))
463 *var_len = sizeof(c64);
464 return (unsigned char *) &c64;
467 /**************************************************************************
468 * Function: oid_table_c64_kb_handler
470 * Description: Fetch a counter64 from the given location.
471 * Setup var_len, and return a pointer to the data.
472 * Different than oid_table_c64_handler in that
473 * the original value is multiplied by 1024 before converting
474 * to a counter64. (e.g. turn KB into a Byte scaled value)
476 * Input: file_path, and var_len pointer
478 * Output: NULL on failure, or pointer to data
480 **************************************************************************/
482 unsigned char* oid_table_c64_kb_handler(const char* file_path,size_t *var_len)
484 static counter64 c64;
485 /* scale by factor of 1024*/
486 if (SUCCESS != read_counter64(file_path,&c64,1024))
488 *var_len = sizeof(c64);
489 return (unsigned char *) &c64;
492 /**************************************************************************
493 * Function: oid_table_obj_name_handler
495 * Description: Just copy the file_path and return as the output value.
497 * Input: file_path, and var_len pointer
499 * Output: NULL on failure, or pointer to data
501 **************************************************************************/
504 oid_table_obj_name_handler(
505 const char* file_path,
508 static unsigned char string[SPRINT_MAX_LEN];
509 *var_len = strlen(file_path);
510 *var_len = MIN_LEN(*var_len, sizeof(string));
511 memcpy(string, file_path, *var_len);
512 return (unsigned char *) string;
515 /**************************************************************************
516 * Function: oid_table_string_handler
518 * Description: Fetch a string from the given location.
519 * Setup var_len, and return a pointer to the data.
521 * Input: file_path, and var_len pointer
523 * Output: NULL on failure, or pointer to data
525 **************************************************************************/
528 oid_table_string_handler(
529 const char* file_path,
532 static unsigned char string[SPRINT_MAX_LEN];
533 if( SUCCESS != read_string(file_path, (char *)string,sizeof(string)))
535 *var_len = strlen((char *)string);
536 return (unsigned char *) string;
540 /**************************************************************************
541 * Function: oid_table_is_directory_handler
543 * Description: Determine if the file_path is a directory.
544 * Setup a boolean return value.
545 * Setup var_len, and return a pointer to the data.
547 * Input: file_path, and var_len pointer
549 * Output: NULL on failure, or pointer to data
551 **************************************************************************/
554 oid_table_is_directory_handler(
555 const char* file_path,
558 static long long_ret;
559 long_ret = is_directory(file_path);
560 *var_len = sizeof(long_ret);
561 return (unsigned char *) &long_ret;
564 /**************************************************************************
565 * Function: var_genericTable
567 * Description: Handle Table driven OID processing
569 **************************************************************************/
572 var_genericTable(struct variable *vp,
577 WriteMethod **write_method,
579 struct oid_table *ptable)
584 unsigned char *ret_val = NULL;
586 const char* obj_name;
590 * Get the list of file. If there are no elements
593 if( 0 == (dir_list = get_file_list(path, DIR_TYPE, &num)))
599 if (header_simple_table(vp,name,length,exact,var_len,write_method, num)
601 goto cleanup_and_exit;
604 * The number of the device we're looking at
606 deviceindex = name[*length - 1] - 1;
609 * If we couldn't find this element
610 * something must have recently changed return
613 if(deviceindex >= num){
614 report("deviceindex=%d exceeds number of elements=%d",deviceindex,num);
615 goto cleanup_and_exit;
619 * Fetch the object name from the list
621 obj_name = get_nth_entry_from_list(dir_list,num,deviceindex);
622 if(obj_name == NULL){
624 * Note this should never really happen because we check deviceindex >=num
625 * above. And dir_list should be consitent with num
626 * but just in case...
628 report("object name not found in list",deviceindex,num);
629 goto cleanup_and_exit;
633 * Find the matching magic - or the end of the list
635 while(ptable[i].magic != vp->magic && ptable[i].magic != 0)
639 * If we didn't find a matching entry return
641 if(ptable[i].magic==0)
642 goto cleanup_and_exit;
645 * If the name is NULL is a special case and
646 * just just pass the obj_name as the file_path
647 * otherwise we create a file path from the given components
649 if(ptable[i].name != 0){
650 char file_path[MAX_PATH_SIZE];
651 sprintf(file_path, "%s%s/%s",path,obj_name,ptable[i].name);
652 ret_val = ptable[i].fhandler(file_path,var_len);
655 ret_val = ptable[i].fhandler(obj_name,var_len);
662 /**************************************************************************
663 * Function: stats_values
665 * Description: Setup nb_sample, min, max, sum and sum_square stats values
666 for name_value from filepath.
668 * Input: filepath, name_value,
669 * pointer to nb_sample, min, max, sum, sum_square
671 * Output: SUCCESS or ERROR on failure
673 **************************************************************************/
674 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 char line[MAX_LINE_SIZE];
678 int nbReadValues = 0;
680 if( (statfile=fopen(filepath,"r")) == NULL) {
681 report("stats_value() failed to open %s",filepath);
684 /*find the good line for name_value*/
686 if( fgets(line,MAX_LINE_SIZE,statfile) == NULL ) {
687 report("stats_values() failed to find %s values in %s stat_file",name_value,statfile);
690 } while ( strstr(line,name_value) == NULL );
692 if((nbReadValues=sscanf(line,"%*s %llu %*s %*s %llu %llu %llu %llu",nb_sample,min,max,sum,sum_square)) == 5) {
694 } else if( nbReadValues == 1 && *nb_sample == 0) {
695 *min = *max = *sum = *sum_square = 0;
698 report("stats_values() failed to read stats_values for %s value in %s stat_file",name_value,statfile);
710 /**************************************************************************
711 * Function: mds_stats_values
713 * Description: Setup nb_sample, min, max, sum and sum_square stats values
714 for mds stats name_value .
717 * pointer to nb_sample, min, max, sum, sum_square
719 * Output: SUCCESS or ERROR on failure
721 **************************************************************************/
722 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)
724 unsigned long long tmp_nb_sample=0,tmp_min=0,tmp_max=0,tmp_sum=0,tmp_sum_square=0;
727 /*we parse the three MDS stat files and sum values*/
728 if (cfs_get_param_paths(&path, "mdt/MDS/mds/stats") != 0)
730 if( stats_values(path.gl_pathv[0],name_value,&tmp_nb_sample,&tmp_min,&tmp_max,&tmp_sum,&tmp_sum_square) == ERROR ) {
731 cfs_free_param_data(&path);
734 *nb_sample=tmp_nb_sample;
738 *sum_square=tmp_sum_square;
740 cfs_free_param_data(&path);
742 if (cfs_get_param_paths(&path, "mdt/MDS/mds_readpage/stats") != 0)
744 if( stats_values(path.gl_pathv[0],name_value,&tmp_nb_sample,&tmp_min,&tmp_max,&tmp_sum,&tmp_sum_square) == ERROR ) {
745 cfs_free_param_data(&path);
748 *nb_sample += tmp_nb_sample;
752 *sum_square += tmp_sum_square;
754 cfs_free_param_data(&path);
756 if (cfs_get_param_paths(&path, "mdt/MDS/mds_setattr/stats") != 0)
758 if( stats_values(path.gl_pathv[0],name_value,&tmp_nb_sample,&tmp_min,&tmp_max,&tmp_sum,&tmp_sum_square) == ERROR ) {
759 cfs_free_param_data(&path);
762 *nb_sample += tmp_nb_sample;
766 *sum_square += tmp_sum_square;
768 cfs_free_param_data(&path);
773 void convert_ull(counter64 *c64, unsigned long long ull, size_t *var_len)
775 *var_len = sizeof(*c64);
776 c64->low = (unsigned long long) (0x0ffffffff & ull);
778 c64->high = (unsigned long long) (0x0ffffffff & ull);