1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (c) 2005 Cluster File Systems, Inc.
5 * Author: PJ Kirner <pjkirner@clusterfs.com>
7 * This file is part of Lustre, http://www.lustre.org.
9 * Lustre is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU General Public
11 * License as published by the Free Software Foundation.
13 * Lustre is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Lustre; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * include important headers
27 #include <net-snmp/net-snmp-config.h>
28 #include <net-snmp/net-snmp-includes.h>
29 #include <net-snmp/agent/net-snmp-agent-includes.h>
35 #include <sys/types.h>
42 #include "lustre-snmp-util.h"
44 /*********************************************************************
45 * Function: get_file_list
47 * Description: For the given valid directory path, returns the list
48 * all directories or files in that path.
50 * Input: 'dirname' the directory path.
51 * 'file_type' if this takes the value DIR_TYPE then
52 * returns the list of directories in that path.
53 * If its of type FILE_TYPE then returns the list of files
55 * 'count' pointer to number of elements returned in the
58 * Output: List of directories/files in that path.
60 *********************************************************************/
62 char *get_file_list(const char *dirname, int file_type, uint32_t *count)
66 struct dirent *pdirent = NULL;
71 char filename[MAX_PATH_SIZE];
74 if ((dirname == NULL) || ((pdir = opendir(dirname)) == NULL )) {
75 if (dirname == NULL) {
76 report("%s %s:line %d %s", __FILE__, __FUNCTION__, __LINE__,
77 "NULL directory is passed as parameter to funtion");
79 report("%s %s:line %d Error in opening the dir %s", __FILE__,
80 __FUNCTION__, __LINE__, dirname);
88 if ((pdirent = readdir(pdir)) == NULL)
91 /* Skip over '.' and '..' directores */
92 if ((pdirent->d_name[0] == '.') ||
93 !strcmp(pdirent->d_name, FILENAME_NUM_REF))
96 sprintf(filename, "%s/%s", dirname, pdirent->d_name);
97 cond1 = (file_type == FILE_TYPE) && is_directory(filename);
98 cond2 = (file_type == DIR_TYPE) && (!is_directory(filename));
103 /* Calculate the number of bytes for this new entry.*/
104 byte_count += strlen(pdirent->d_name) + 1;
110 if (file_count != 0) {
112 /* need one extra one for the finall NULL terminator*/
113 if ((ret_str = (char *) malloc(byte_count + 1)) == NULL) {
114 report("get_file_list() failed to malloc(%d)",byte_count+1);
121 while (file_count != 0) {
122 if ((pdirent = readdir(pdir)) == NULL)
125 if ((pdirent->d_name[0] == '.') ||
126 !strcmp(pdirent->d_name, FILENAME_NUM_REF))
129 sprintf(filename, "%s/%s", dirname, pdirent->d_name);
130 cond1 = (file_type == FILE_TYPE) && is_directory(filename);
131 cond2 = (file_type == DIR_TYPE) && (!is_directory(filename));
136 strcpy(ret_str + curr_offset, pdirent->d_name);
137 curr_offset = curr_offset + strlen(pdirent->d_name) + 1;
140 /* Put in the finall null terminator*/
141 ret_str[byte_count] = '\0';
148 /*********************************************************************
149 * Function: is_directory
151 * Description: Checks if given filename is a directory or not.
152 * all directories or files in that path.
154 * Input: 'filename' the directory path to be checked.
156 * Output: Returns 1 if its a directory else 0.
158 *********************************************************************/
160 int is_directory(const char *filename)
166 result = stat(filename, &statf);
167 return ((result == SUCCESS) && (statf.st_mode & S_IFDIR));
170 /*********************************************************************
171 * Function: read_string
173 * Description: For the given valid file path, reads the data in
176 * Input: 'filepath' the file whose data is to be accessed.
177 * 'lustre_var' the data from the file is read into
178 * this variable, returned to the requestor.
179 * 'var_max_size' the max size of the string
180 * 'report_error' boolean if error should be reported on
183 * Output: Returns SUCCESS if read successfully from file else
185 *********************************************************************/
187 int read_string(const char *filepath, char *lustre_var, size_t var_max_size)
191 int ret_val = SUCCESS;
192 int report_error = 1;
194 if ((filepath == NULL) || (lustre_var == NULL)) {
195 report("%s %s:line %d %s", __FILE__, __FUNCTION__, __LINE__,
196 "Input parameter is NULL");
199 fptr = fopen(filepath, "r");
203 report("%s %s:line %d Unable to open the file %s", __FILE__,
204 __FUNCTION__, __LINE__, filepath);
207 if (fgets(lustre_var, var_max_size, fptr) == NULL) {
208 report("%s %s:line %d read failed for file %s", __FILE__,
209 __FUNCTION__, __LINE__, filepath);
212 len = strlen(lustre_var);
214 Last char is EOF, before string ends,
215 so '\0' is moved to last but one.
217 lustre_var[len-1] = lustre_var[len];
225 /**************************************************************************
226 * Function: lustrefs_ctrl
228 * Description: Execute /etc/init.d/lustre script for starting,
229 * stopping and restarting Lustre services in child process.
231 * Input: Start/Stop/Restart Command Number.
232 * Output: Returns void
234 **************************************************************************/
236 void lustrefs_ctrl(int command)
240 cmd[0] = LUSTRE_SERVICE;
259 report("failed to execvp(\'%s %s\')",cmd[0],cmd[1]);
264 /*****************************************************************************
265 * Function: get_sysstatus
267 * Description: Read /var/lustre/sysStatus file, and based on file contents
268 * return the status of Lustre services.
271 * Output: Return ONLINE/OFFLINE/ONLINE PENDING/OFFLINE PENDING status
274 ****************************************************************************/
276 int get_sysstatus(void)
280 int ret_val = ERROR ;
281 char sys_status[50] = {0};
283 if(SUCCESS == read_string(FILENAME_SYS_STATUS,sys_status,sizeof(sys_status)))
285 if (memcmp(sys_status, STR_ONLINE_PENDING,strlen(STR_ONLINE_PENDING)) == 0)
286 ret_val = ONLINE_PENDING;
287 else if (memcmp(sys_status, STR_ONLINE, strlen(STR_ONLINE)) == 0)
289 else if (memcmp(sys_status, STR_OFFLINE_PENDING,strlen(STR_OFFLINE_PENDING)) == 0)
290 ret_val = OFFLINE_PENDING;
291 else if (memcmp(sys_status, STR_OFFLINE, strlen(STR_OFFLINE)) == 0)
294 report("%s %s:line %d Bad Contents in file %s \'%s\'", __FILE__,
295 __FUNCTION__, __LINE__, FILENAME_SYS_STATUS,sys_status);
301 /*****************************************************************************
302 * Function: read_ulong
304 * Description: Read long values from lproc and copy to the location
305 * pointed by input parameter.
307 * Input: file path, and pointer for data to be copied
309 * Output: Return ERROR or SUCCESS.
311 ****************************************************************************/
313 int read_ulong(const char *file_path, unsigned long *valuep)
315 char file_data[MAX_LINE_SIZE];
318 if ((ret_val = read_string(file_path, file_data,sizeof(file_data))) == SUCCESS){
319 *valuep = strtoul(file_data,NULL,10);
324 /*****************************************************************************
325 * Function: read_counter64
327 * Description: Read counter64 values from lproc and copy to the location
328 * pointed by input parameter.
330 * Input: file path, and pointer for data to be copied
332 * Output: Return ERROR or SUCCESS.
334 ****************************************************************************/
336 int read_counter64(const char *file_path, counter64 *c64,int factor)
338 char file_data[MAX_LINE_SIZE];
340 unsigned long long tmp = 0;
342 if ((ret_val = read_string(file_path, file_data,sizeof(file_data))) == SUCCESS) {
343 tmp = atoll(file_data) * factor;
344 c64->low = (ulong) (0x0FFFFFFFF & tmp);
345 tmp >>= 32; /* Shift right by 4 bytes */
346 c64->high = (ulong) (0x0FFFFFFFF & tmp);
351 /*****************************************************************************
352 * Function: get_nth_entry_from_list
354 * Description: Find the n'th entry from a null terminated list of string
356 * Input: dir_list - the list
357 * num - the number of elements in the list
358 * index - the index we are looking for
360 * Output: Return NULL on failure, or the string name on success.
362 ****************************************************************************/
364 const char *get_nth_entry_from_list(const char* dir_list,int num,int index)
371 * if we've reached the end of the list for some reason
372 * because num was wrong then stop processing
374 if( *(dir_list+cur_ptr) == 0)
377 /* If we've found the right one */
379 return dir_list+cur_ptr;
381 /* Move to the next one*/
382 cur_ptr += strlen(dir_list + cur_ptr)+1;
387 /*****************************************************************************
390 * Description: This function used to report error msg to stderr and log into
391 * log file(default file:/var/log/snmpd.log) when agent is started with
392 * debug option -Dlsnmpd
393 * Input: format string and variable arguments.
395 ****************************************************************************/
397 void report(const char *fmt, ...)
402 va_start(arg_list, fmt);
403 vsprintf(buf, fmt, arg_list);
406 DEBUGMSGTL(("lsnmpd", "%s\n", buf));
407 fprintf(stderr, "%s\n", buf);
413 /**************************************************************************
414 * Function: oid_table_ulong_handler
416 * Description: Fetch a unsigned long from the given location.
417 * Setup var_len, and return a pointer to the data.
419 * Input: file_path, and var_len pointer
421 * Output: NULL on failure, or pointer to data
423 **************************************************************************/
426 oid_table_ulong_handler(
427 const char* file_path,
430 static unsigned long ulong_ret;
431 if (SUCCESS != read_ulong(file_path,&ulong_ret))
433 *var_len = sizeof(ulong_ret);
434 return (unsigned char *) &ulong_ret;
437 /**************************************************************************
438 * Function: oid_table_c64_handler
440 * Description: Fetch a counter64 from the given location.
441 * Setup var_len, and return a pointer to the data.
443 * Input: file_path, and var_len pointer
445 * Output: NULL on failure, or pointer to data
447 **************************************************************************/
449 unsigned char* oid_table_c64_handler(const char* file_path,size_t *var_len)
451 static counter64 c64;
452 if (SUCCESS != read_counter64(file_path,&c64,1))
454 *var_len = sizeof(c64);
455 return (unsigned char *) &c64;
458 /**************************************************************************
459 * Function: oid_table_c64_kb_handler
461 * Description: Fetch a counter64 from the given location.
462 * Setup var_len, and return a pointer to the data.
463 * Different than oid_table_c64_handler in that
464 * the original value is multiplied by 1024 before converting
465 * to a counter64. (e.g. turn KB into a Byte scaled value)
467 * Input: file_path, and var_len pointer
469 * Output: NULL on failure, or pointer to data
471 **************************************************************************/
473 unsigned char* oid_table_c64_kb_handler(const char* file_path,size_t *var_len)
475 static counter64 c64;
476 /* scale by factor of 1024*/
477 if (SUCCESS != read_counter64(file_path,&c64,1024))
479 *var_len = sizeof(c64);
480 return (unsigned char *) &c64;
483 /**************************************************************************
484 * Function: oid_table_obj_name_handler
486 * Description: Just copy the file_path and return as the output value.
488 * Input: file_path, and var_len pointer
490 * Output: NULL on failure, or pointer to data
492 **************************************************************************/
495 oid_table_obj_name_handler(
496 const char* file_path,
499 static unsigned char string[SPRINT_MAX_LEN];
500 *var_len = strlen(file_path);
501 *var_len = MIN_LEN(*var_len, sizeof(string));
502 memcpy(string, file_path, *var_len);
503 return (unsigned char *) string;
506 /**************************************************************************
507 * Function: oid_table_string_handler
509 * Description: Fetch a string from the given location.
510 * Setup var_len, and return a pointer to the data.
512 * Input: file_path, and var_len pointer
514 * Output: NULL on failure, or pointer to data
516 **************************************************************************/
519 oid_table_string_handler(
520 const char* file_path,
523 static unsigned char string[SPRINT_MAX_LEN];
524 if( SUCCESS != read_string(file_path, string,sizeof(string)))
526 *var_len = strlen(string);
527 return (unsigned char *) string;
531 /**************************************************************************
532 * Function: oid_table_is_directory_handler
534 * Description: Determine if the file_path is a directory.
535 * Setup a boolean return value.
536 * Setup var_len, and return a pointer to the data.
538 * Input: file_path, and var_len pointer
540 * Output: NULL on failure, or pointer to data
542 **************************************************************************/
545 oid_table_is_directory_handler(
546 const char* file_path,
549 static long long_ret;
550 long_ret = is_directory(file_path);
551 *var_len = sizeof(long_ret);
552 return (unsigned char *) &long_ret;
555 /**************************************************************************
556 * Function: var_genericTable
558 * Description: Handle Table driven OID processing
560 **************************************************************************/
563 var_genericTable(struct variable *vp,
568 WriteMethod **write_method,
570 struct oid_table *ptable)
575 unsigned char *ret_val = NULL;
577 const char* obj_name;
581 * Get the list of file. If there are no elements
584 if( 0 == (dir_list = get_file_list(path, DIR_TYPE, &num)))
590 if (header_simple_table(vp,name,length,exact,var_len,write_method, num)
592 goto cleanup_and_exit;
595 * The number of the device we're looking at
597 deviceindex = name[*length - 1] - 1;
600 * If we couldn't find this element
601 * something must have recently changed return
604 if(deviceindex >= num){
605 report("deviceindex=%d exceeds number of elements=%d",deviceindex,num);
606 goto cleanup_and_exit;
610 * Fetch the object name from the list
612 obj_name = get_nth_entry_from_list(dir_list,num,deviceindex);
613 if(obj_name == NULL){
615 * Note this should never really happen because we check deviceindex >=num
616 * above. And dir_list should be consitent with num
617 * but just in case...
619 report("object name not found in list",deviceindex,num);
620 goto cleanup_and_exit;
624 * Find the matching magic - or the end of the list
626 while(ptable[i].magic != vp->magic && ptable[i].magic != 0)
630 * If we didn't find a matching entry return
632 if(ptable[i].magic==0)
633 goto cleanup_and_exit;
636 * If the name is NULL is a special case and
637 * just just pass the obj_name as the file_path
638 * otherwise we create a file path from the given components
640 if(ptable[i].name != 0){
641 char file_path[MAX_PATH_SIZE];
642 sprintf(file_path, "%s%s/%s",path,obj_name,ptable[i].name);
643 ret_val = ptable[i].fhandler(file_path,var_len);
646 ret_val = ptable[i].fhandler(obj_name,var_len);