Fix: filesystem report
[gnucomo.git] / src / gcm_input / df_filter.cpp
1
2 /**************************************************************************
3 **  (c) Copyright 2007, Andromeda Technology & Automation
4 ** This is free software; you can redistribute it and/or modify it under the
5 ** terms of the GNU General Public License, see the file COPYING.
6 ***************************************************************************
7 ** MODULE INFORMATION *
8 ***********************
9 **      FILE NAME      : df_filter.cpp
10 **      SYSTEM NAME    : 
11 **      VERSION NUMBER : $Revision: 1.1 $
12 **
13 **  DESCRIPTION      :  Transform output of 'df' into a Gnucomo XML document
14 **
15 **  EXPORTED OBJECTS : 
16 **  LOCAL    OBJECTS : 
17 **  MODULES  USED    :
18 ***************************************************************************
19 **  ADMINISTRATIVE INFORMATION *
20 ********************************
21 **      ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
22 **      CREATION DATE   : Oct 30, 2007
23 **      LAST UPDATE     : Nov 02, 2007
24 **      MODIFICATIONS   : 
25 **************************************************************************/
26
27 /*****************************
28    $Log: df_filter.cpp,v $
29    Revision 1.1  2007-11-03 10:26:13  arjen
30    Added a new filter which can directly read the output
31    of the UNIX df command. A brief description is added in
32    the user manual.
33
34 *****************************/
35
36 #include <ctype.h>
37 #include <vector>
38
39 #include "df_filter.h"
40
41
42 std::vector<String> tokenize(String line)
43 {
44    std::vector<String> words;
45    int    l;           //  letter index in line
46
47    l = 0;
48    while (l < ~line)
49    {
50       int start, length;
51
52       while (l < ~line && isspace(line[l]))
53       {
54          l++;
55       }
56       start = l;
57       length = 0;
58
59       while (l < ~line && !isspace(line[l]))
60       {
61          l++;
62          length++;
63       }
64       String w = line(start, length);
65       words.push_back(w);
66    }
67    return words;
68 }
69
70 //  Find a regular expression in a vector of Strings
71
72 int  findword(const std::vector<String> &tokens, const regex &pattern)
73 {
74    int   i;
75
76    i = 0;
77    while (i < tokens.size() && !(tokens[i] == pattern))
78    {
79       i++;
80    }
81
82    if (i == tokens.size())
83    {
84       std::cerr << "Token not found.\n";
85    }
86
87    return i;
88 }
89
90 /*=========================================================================
91 **  NAME           : constructXML
92 **  SYNOPSIS       : int constructXML(message_buffer &in, strstream &xml)
93 **  PARAMETERS     : 
94 **  RETURN VALUE   : Create an XML document from output of 'df -k'
95 **
96 **  DESCRIPTION    : 
97 **
98 **  VARS USED      :
99 **  VARS CHANGED   :
100 **  FUNCTIONS USED :
101 **  SEE ALSO       :
102 **  LAST MODIFIED  : Nov 02, 2007
103 **=========================================================================
104 */
105
106 static const regex re_df_header("^Filesystem.+[Uu]se.+[Aa]vail.+Mounted");
107 static const regex re_df_i_header("^Filesystem +Inodes.+IUse.+Mounted");
108 static const regex re_df_data(".+ [0-9]+ +[0-9]+ +[0-9]+");
109
110 void df_filter::construct_XML(message_buffer &in, std::strstream &xml)
111 {
112    String line;
113    enum   df_report_detection { NONE, BLOCKS, INODES };
114
115    df_report_detection  report_type = NONE;
116
117    int    field_position[4];  //  Mountpoint, blocks, used, available
118
119    std::vector<String>  tokens;
120
121    scan_email_header(in);
122    construct_header(xml);
123
124    xml << "  <gcmt:data>\n";
125    xml << "    <gcmt:parameters class='filesystem'>\n";
126
127    while (in >> line)
128    { 
129       String  mountpoint;
130       String  device;
131       String  blocks;
132       String  inodes;
133       String  used;
134       String  available;
135
136       switch (report_type)
137       {
138       case NONE:  //  Header.
139          if (line == re_df_header)
140          {
141             report_type = BLOCKS;
142             tokens = tokenize(line);
143             //  Make a map to find the fields we're interested in
144             field_position[0] = findword(tokens, regex("Mounted"));
145             field_position[1] = findword(tokens, regex("kbytes|-blocks"));
146             field_position[2] = findword(tokens, regex("[uU]se"));
147             field_position[3] = findword(tokens, regex("[aA]vail"));
148          }
149          if (line == re_df_i_header)
150          {
151             report_type = INODES;
152             tokens = tokenize(line);
153             //  Make a map to find the fields we're interested in
154             field_position[0] = findword(tokens, regex("Mounted"));
155             field_position[1] = findword(tokens, regex("Inodes"));
156             field_position[2] = findword(tokens, regex("IUsed"));
157             field_position[3] = findword(tokens, regex("IFree"));
158          }
159          break;
160
161       case BLOCKS: // df output lines.
162          tokens = tokenize(line);
163          if (tokens.size() > 4)
164          {
165             mountpoint = tokens[field_position[0]];
166             blocks     = tokens[field_position[1]];
167             used       = tokens[field_position[2]];
168             available  = tokens[field_position[3]];
169             device     = tokens[0];
170             if (mountpoint[0] == '/')
171             {
172
173                //   Create the XML element.
174
175                xml << "    <gcmt:parameter name='" << mountpoint << "'>\n";
176                xml << "      <gcmt:property name='device'>" << device << "</gcmt:property>\n";
177                xml << "      <gcmt:property name='size'>" << blocks << "</gcmt:property>\n";
178                xml << "      <gcmt:property name='used'>"   << used   << "</gcmt:property>\n";
179                xml << "      <gcmt:property name='available'>" << available << "</gcmt:property>\n";
180                xml << "    </gcmt:parameter>\n";
181             }
182          }
183          else
184          {
185             //cerr << "Mismatch on " << line << "\n";
186          }
187          break;
188
189       case INODES: // df output lines.
190          tokens = tokenize(line);
191          if (tokens.size() > 4)
192          {
193             mountpoint = tokens[field_position[0]];
194             inodes     = tokens[field_position[1]];
195             used       = tokens[field_position[2]];
196             available  = tokens[field_position[3]];
197             device     = tokens[0];
198             if (mountpoint[0] == '/')
199             {
200
201                //   Create the XML element.
202
203                xml << "    <gcmt:parameter name='" << mountpoint << "'>\n";
204                xml << "      <gcmt:property name='device'>" << device << "</gcmt:property>\n";
205                xml << "      <gcmt:property name='Inodes'>" << inodes << "</gcmt:property>\n";
206                xml << "      <gcmt:property name='Iused'>"   << used   << "</gcmt:property>\n";
207                xml << "      <gcmt:property name='Ifree'>" << available << "</gcmt:property>\n";
208                xml << "    </gcmt:parameter>\n";
209             }
210          }
211          else
212          {
213             //cerr << "Mismatch on " << line << "\n";
214          }
215          break;
216       }
217    }
218    xml << "    </gcmt:parameters>\n";
219    xml << "  </gcmt:data>\n";
220    xml << "</gcmt:message>\n";
221
222 }
223
224 bool df_cooker::check_pattern(String logline)
225 {
226    if (df_detected)
227    {
228       df_detected = (logline == re_df_data);
229    }
230    else
231    {
232       df_detected = (logline == re_df_header || logline == re_df_i_header);
233    }
234
235    return df_detected;
236 }
237
238 bool df_cooker::cook_this(String logline, UTC arrival)
239 {
240    return true;
241 }