Whamcloud - gitweb
src needs to be in the options list if it is going to be available for use.
[fs/lustre-release.git] / snmp / lustre-snmp-util.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2005 Cluster File Systems, Inc.
5  *   Author: PJ Kirner <pjkirner@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
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.
12  *
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.
17  *
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.
21  */
22
23 /*
24  *   include important headers
25  */
26
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>
30
31 /*
32  *  include our .h file
33  */ 
34
35 #include <sys/types.h>
36 #include <sys/vfs.h>
37 #include <dirent.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #include <stdio.h>
41 #include <stdarg.h>
42 #include "lustre-snmp-util.h"
43
44 /*********************************************************************
45  * Function:    get_file_list
46  *
47  * Description: For the given valid directory  path, returns the list
48  *              all directories or files in that path.
49  *
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
54  *          in that path.
55  *          'count' pointer to number of elements returned in the
56  *          return string. 
57  *
58  * Output:  List of  directories/files in that path.
59  *
60  *********************************************************************/
61
62 char *get_file_list(const char *dirname, int file_type, uint32_t *count)
63 {
64
65     DIR           *pdir = NULL;
66     struct dirent *pdirent = NULL;
67     int           curr_offset = 0;
68     int           byte_count = 0;
69     int           file_count = 0;
70     char          *ret_str = NULL;
71     char          filename[MAX_PATH_SIZE];
72     int           cond1, cond2;
73
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");
78         } else {
79             report("%s %s:line %d Error in opening the dir %s", __FILE__,
80                    __FUNCTION__, __LINE__, dirname);
81         }
82         if (count)
83             *count = 0;
84         return NULL;
85     }
86
87     while (1) {
88         if ((pdirent = readdir(pdir)) == NULL)
89             break;
90
91         /* Skip over '.' and '..' directores */
92         if ((pdirent->d_name[0] == '.') ||
93             !strcmp(pdirent->d_name, FILENAME_NUM_REF))
94             continue;
95         
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));
99
100         if (cond1 || cond2)
101             continue;
102
103         /* Calculate the number of bytes for this new entry.*/                    
104         byte_count += strlen(pdirent->d_name) + 1;
105         file_count++;
106     }
107     if (count)
108         *count = file_count;
109     
110     if (file_count != 0) {
111         
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);
115             closedir(pdir);
116             return NULL;
117         }    
118         
119         rewinddir(pdir);
120         
121         while (file_count != 0) {
122             if ((pdirent = readdir(pdir)) == NULL)
123                 break;
124
125             if ((pdirent->d_name[0] == '.') ||
126                 !strcmp(pdirent->d_name, FILENAME_NUM_REF))
127                 continue;
128             
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));
132
133             if (cond1 || cond2)
134                 continue;
135
136             strcpy(ret_str + curr_offset, pdirent->d_name);
137             curr_offset = curr_offset + strlen(pdirent->d_name) + 1;
138             file_count--;
139         }
140         /* Put in the finall null terminator*/
141         ret_str[byte_count] = '\0';
142     }
143     closedir(pdir);
144     return ret_str;
145 }
146
147
148 /*********************************************************************
149  * Function:    is_directory
150  *
151  * Description: Checks if given filename is a directory or not.
152  *              all directories or files in that path.
153  *
154  * Input:   'filename' the directory path to be checked.
155  *
156  * Output:  Returns 1 if its a directory else 0.
157  *
158  *********************************************************************/
159
160 int is_directory(const char *filename)
161 {
162
163     struct stat statf;
164     int result;
165
166     result = stat(filename, &statf);
167     return ((result == SUCCESS) && (statf.st_mode & S_IFDIR));
168 }
169
170 /*********************************************************************
171  * Function:    read_string
172  *
173  * Description: For the given valid file path, reads the data in
174  *              that file.
175  *
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 
181  *           missing filepath
182  *
183  * Output:  Returns SUCCESS if read successfully from file else
184  *          returns ERROR.
185  *********************************************************************/
186  
187 int  read_string(const char *filepath, char *lustre_var, size_t var_max_size)
188 {
189     FILE    *fptr = NULL;
190     int     len = 0;
191     int     ret_val = SUCCESS;
192     int     report_error = 1;
193
194     if ((filepath == NULL) || (lustre_var == NULL)) {
195         report("%s %s:line %d %s", __FILE__, __FUNCTION__, __LINE__,
196                "Input parameter is NULL");
197         ret_val = ERROR;
198     } else {
199         fptr = fopen(filepath, "r");
200
201         if (fptr == NULL) {
202             if(report_error)
203                 report("%s %s:line %d Unable to open the file %s", __FILE__,
204                        __FUNCTION__, __LINE__, filepath);
205             ret_val = ERROR;
206         } else {
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);
210                  ret_val = ERROR;
211             } else {
212                 len = strlen(lustre_var);
213                 /*
214                     Last char is EOF, before string ends,
215                     so '\0' is moved to last but one.
216                 */
217                 lustre_var[len-1] = lustre_var[len];
218             }
219             fclose(fptr);
220         }
221     }
222     return ret_val;
223 }
224
225 /**************************************************************************
226  * Function:   lustrefs_ctrl
227  *
228  * Description: Execute /etc/init.d/lustre script for starting,
229  *              stopping and restarting Lustre services in child process.
230  *
231  * Input:  Start/Stop/Restart Command Number.
232  * Output: Returns  void
233  *
234  **************************************************************************/
235
236 void lustrefs_ctrl(int command)
237 {
238     char *cmd[3];
239
240     cmd[0] = LUSTRE_SERVICE;
241     switch (command) {
242     case ONLINE:
243         cmd[1] = "start";
244         break;
245     case OFFLINE:
246         cmd[1] = "stop";
247         break;
248     case RESTART:
249         cmd[1] = "restart";
250         break;
251     default:
252         return;
253     }
254
255     cmd[2] = (char *)0;
256
257     if (fork() == 0) {
258         execvp(cmd[0], cmd);
259         report("failed to execvp(\'%s %s\')",cmd[0],cmd[1]);
260     }
261     return;
262 }
263
264 /*****************************************************************************
265  * Function:     get_sysstatus
266  *
267  * Description:  Read /var/lustre/sysStatus file, and based on file contents
268  *               return the status of Lustre services.
269  *
270  * Input:   void
271  * Output:  Return ONLINE/OFFLINE/ONLINE PENDING/OFFLINE PENDING status
272  *          values.
273  *
274  ****************************************************************************/
275
276 int get_sysstatus(void)
277 {
278     FILE    *fptr = NULL;
279     int     len = 0;
280     int     ret_val = ERROR ;
281     char    sys_status[50] = {0};
282     
283     if(SUCCESS == read_string(FILENAME_SYS_STATUS,sys_status,sizeof(sys_status)))
284     {
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)
288             ret_val = ONLINE;
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)
292             ret_val = OFFLINE;
293         else
294             report("%s %s:line %d Bad Contents in file %s \'%s\'", __FILE__,
295                 __FUNCTION__, __LINE__, FILENAME_SYS_STATUS,sys_status);
296     }
297     return ret_val;
298 }
299
300
301 /*****************************************************************************
302  * Function:     read_ulong
303  *
304  * Description:  Read long values from lproc and copy to the location
305  *               pointed by input parameter.
306  *
307  * Input:   file path, and pointer for data to be copied
308  *
309  * Output:  Return ERROR or SUCCESS.
310  *
311  ****************************************************************************/
312
313 int read_ulong(const char *file_path, unsigned long *valuep)
314 {
315     char    file_data[MAX_LINE_SIZE];
316     int     ret_val;
317
318     if ((ret_val = read_string(file_path, file_data,sizeof(file_data))) == SUCCESS){
319         *valuep = strtoul(file_data,NULL,10);
320     }
321     return ret_val;
322 }
323
324 /*****************************************************************************
325  * Function:     read_counter64
326  *
327  * Description:  Read counter64 values from lproc and copy to the location
328  *               pointed by input parameter.
329  *
330  * Input:   file path, and pointer for data to be copied
331  *
332  * Output:  Return ERROR or SUCCESS.
333  *
334  ****************************************************************************/
335
336 int read_counter64(const char *file_path, counter64 *c64,int factor)
337 {
338     char    file_data[MAX_LINE_SIZE];
339     int     ret_val;
340     unsigned long long tmp = 0;
341
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);
347     }
348     return ret_val;
349 }
350
351 /*****************************************************************************
352  * Function:     get_nth_entry_from_list
353  *
354  * Description:  Find the n'th entry from a null terminated list of string
355  *
356  * Input:   dir_list - the list
357  *          num - the number of elements in the list
358  *          index - the index we are looking for
359  *
360  * Output:  Return NULL on failure, or the string name on success.
361  *
362  ****************************************************************************/
363
364 const char *get_nth_entry_from_list(const char* dir_list,int num,int index)
365 {
366     int i;
367     int cur_ptr = 0;
368     for(i=0;i<num;i++){
369         
370         /* 
371          * if we've reached the end of the list for some reason
372          * because num was wrong then stop processing
373          */
374         if( *(dir_list+cur_ptr) == 0)
375             break;
376             
377         /* If we've found the right one */    
378         if( i == index )
379             return dir_list+cur_ptr;
380             
381         /* Move to the next one*/            
382         cur_ptr += strlen(dir_list + cur_ptr)+1;
383     }
384     return NULL;
385 }
386
387 /*****************************************************************************
388  * Function:    report
389  *
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.
394  * Output:  void
395  ****************************************************************************/
396
397 void report(const char *fmt, ...)
398 {
399     char buf[1024];
400
401     va_list arg_list;
402     va_start(arg_list, fmt);
403     vsprintf(buf, fmt, arg_list);
404     va_end(arg_list);
405
406     DEBUGMSGTL(("lsnmpd", "%s\n", buf));
407     fprintf(stderr, "%s\n", buf);
408     return;
409 }
410
411
412
413 /**************************************************************************
414  * Function:   oid_table_ulong_handler
415  *
416  * Description: Fetch a unsigned long from the given location.
417  *              Setup var_len, and return a pointer to the data.
418  *
419  * Input:  file_path, and var_len pointer
420  *
421  * Output: NULL on failure, or pointer to data
422  *
423  **************************************************************************/
424
425 unsigned char* 
426     oid_table_ulong_handler(
427         const char* file_path,
428         size_t  *var_len)
429 {
430     static unsigned long ulong_ret;
431     if (SUCCESS != read_ulong(file_path,&ulong_ret))
432         return NULL;
433     *var_len = sizeof(ulong_ret);
434     return  (unsigned char *) &ulong_ret;
435 }
436
437 /**************************************************************************
438  * Function:   oid_table_c64_handler
439  *
440  * Description: Fetch a counter64 from the given location.
441  *              Setup var_len, and return a pointer to the data.
442  *
443  * Input:  file_path, and var_len pointer
444  *
445  * Output: NULL on failure, or pointer to data
446  *
447  **************************************************************************/
448
449 unsigned char* oid_table_c64_handler(const char* file_path,size_t  *var_len)
450 {
451     static counter64 c64;
452     if (SUCCESS != read_counter64(file_path,&c64,1))
453         return NULL;
454     *var_len = sizeof(c64);
455     return (unsigned char *) &c64;
456 }
457
458 /**************************************************************************
459  * Function:   oid_table_c64_kb_handler
460  *
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)
466  *
467  * Input:  file_path, and var_len pointer
468  *
469  * Output: NULL on failure, or pointer to data
470  *
471  **************************************************************************/
472
473 unsigned char* oid_table_c64_kb_handler(const char* file_path,size_t  *var_len)
474 {
475     static counter64 c64;
476     /* scale by factor of 1024*/
477     if (SUCCESS != read_counter64(file_path,&c64,1024))
478         return NULL;
479     *var_len = sizeof(c64);
480     return (unsigned char *) &c64;
481 }
482
483 /**************************************************************************
484  * Function:   oid_table_obj_name_handler
485  *
486  * Description: Just copy the file_path and return as the output value.
487  *
488  * Input:  file_path, and var_len pointer
489  *
490  * Output: NULL on failure, or pointer to data
491  *
492  **************************************************************************/
493
494 unsigned char* 
495     oid_table_obj_name_handler(
496         const char* file_path,
497         size_t  *var_len)
498 {
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;
504 }
505
506 /**************************************************************************
507  * Function:   oid_table_string_handler
508  *
509  * Description: Fetch a string from the given location.
510  *              Setup var_len, and return a pointer to the data.
511  *
512  * Input:  file_path, and var_len pointer
513  *
514  * Output: NULL on failure, or pointer to data
515  *
516  **************************************************************************/
517
518 unsigned char* 
519     oid_table_string_handler(
520         const char* file_path,
521         size_t  *var_len)
522 {
523     static unsigned char string[SPRINT_MAX_LEN];
524     if( SUCCESS != read_string(file_path, string,sizeof(string)))
525         return NULL;
526     *var_len = strlen(string);
527     return (unsigned char *) string;
528 }
529
530
531 /**************************************************************************
532  * Function:   oid_table_is_directory_handler
533  *
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.
537  *
538  * Input:  file_path, and var_len pointer
539  *
540  * Output: NULL on failure, or pointer to data
541  *
542  **************************************************************************/
543
544 unsigned char* 
545     oid_table_is_directory_handler(
546         const char* file_path,
547         size_t *var_len)
548 {
549     static long long_ret;
550     long_ret =  is_directory(file_path);
551     *var_len = sizeof(long_ret);
552     return (unsigned char *) &long_ret;
553 }
554
555 /**************************************************************************
556  * Function:   var_genericTable
557  *
558  * Description: Handle Table driven OID processing
559  *
560  **************************************************************************/
561
562 unsigned char *
563 var_genericTable(struct variable *vp,
564             oid     *name,
565             size_t  *length,
566             int     exact,
567             size_t  *var_len,
568             WriteMethod **write_method,
569             const char *path,
570             struct oid_table *ptable)
571 {
572     char *dir_list;
573     uint32_t num;
574     int  deviceindex;
575     unsigned char *ret_val = NULL;
576     int i=0;
577     const char* obj_name;
578     
579     
580     /*
581      * Get the list of file.  If there are no elements
582      * return nothing
583      */
584     if( 0 == (dir_list = get_file_list(path, DIR_TYPE, &num)))
585         return NULL;
586
587     /*
588      * Setup the table
589      */
590     if (header_simple_table(vp,name,length,exact,var_len,write_method, num)
591                                                 == MATCH_FAILED )
592         goto cleanup_and_exit;
593
594     /*
595      * The number of the device we're looking at
596      */
597     deviceindex = name[*length - 1] - 1;
598
599     /*
600      * If we couldn't find this element
601      * something must have recently changed return
602      * nothing
603      */
604     if(deviceindex >= num){
605         report("deviceindex=%d exceeds number of elements=%d",deviceindex,num);
606         goto cleanup_and_exit;
607     }
608
609     /*
610      * Fetch the object name from the list
611      */
612     obj_name = get_nth_entry_from_list(dir_list,num,deviceindex);
613     if(obj_name == NULL){
614         /*
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...
618          */
619         report("object name not found in list",deviceindex,num);
620         goto cleanup_and_exit;
621     }
622
623     /*
624      * Find the matching magic - or the end of the list
625      */
626     while(ptable[i].magic != vp->magic && ptable[i].magic != 0)
627         i++;
628
629     /*
630      * If we didn't find a matching entry return
631      */
632     if(ptable[i].magic==0)
633         goto cleanup_and_exit;
634
635     /*
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
639      */
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);
644     }
645     else
646         ret_val =  ptable[i].fhandler(obj_name,var_len);
647
648 cleanup_and_exit:
649     free(dir_list);
650     return ret_val;
651 };
652