Fixed a gcc 2 vs. gcc 3 problem
[gnucomo.git] / src / gcm_input / gcm_input.cpp
1 /**************************************************************************
2 **  (c) Copyright 2002, Andromeda Technology & Automation
3 ** This is free software; you can redistribute it and/or modify it under the
4 ** terms of the GNU General Public License, see the file COPYING.
5 ***************************************************************************
6 ** MODULE INFORMATION *
7 ***********************
8 **      FILE NAME      : gcm_input.cpp
9 **      SYSTEM NAME    : Gnucomo - Gnu Computer Monitoring
10 **      VERSION NUMBER : $Revision: 1.8 $
11 **
12 **  DESCRIPTION      :  Application to store client messages into the database
13 **                      The client message contains a log file from one of the
14 **                      system logs. Gcm_input parses the log file and enters
15 **                      the raw data into the 'log' table of the gnucomo database.
16 **
17 **                      The system log may arrive in one of several forms:
18 **                      1. Log file (archived or not) from a client machine.
19 **                      2. Log file from a client system, arriving in a clear Email.
20 **                      3. Log file from a client machine, arriving in an
21 **                         encrypted Email.
22 **
23 **                      additional information we need that may not be availble in
24 **                      the content of the log is:
25 **                      - FQDN of the client.
26 **                      - Time of arrival of the log
27 **                      - Service that created the log.
28 **
29 **                      If the log arrives in an Email, these items probably are
30 **                      available in the mail header. Otherwise, they have to be
31 **                      provided as command line arguments.
32 **
33 **                      Command line arguments:
34 **                      -c <name>        Configuration name (default = gnucomo).
35 **                      -d <date>        Date and time of log arrival.
36 **                      -h <hostname>    FQDN of the client.
37 **                      -i               Incremental - partial list of parameters.
38 **                      -s <service>     Service that created the log.
39 **                      -T               Test mode. Do not alter the database.
40 **                      -v               Verbose (debug) output.
41 **                      -V               Print version and exit.
42 **
43 **  EXPORTED OBJECTS : 
44 **  LOCAL    OBJECTS : 
45 **  MODULES  USED    :
46 ***************************************************************************
47 **  ADMINISTRATIVE INFORMATION *
48 ********************************
49 **      ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
50 **      CREATION DATE   : Aug 29, 2002
51 **      LAST UPDATE     : Aug 11, 2003
52 **      MODIFICATIONS   : 
53 **************************************************************************/
54
55 /*****************************
56    $Log: gcm_input.cpp,v $
57    Revision 1.8  2003-08-16 15:30:19  arjen
58    Fixed a gcc 2 vs. gcc 3 problem
59
60    Revision 1.7  2003/08/14 10:28:37  arjen
61    Use parameters from a new section 'logging' with three configuration parameters:
62       method       - Output method to use for logging.
63       destination  - Name of the log output destination.
64       level        - Log level: Verbose output if greater than 0.
65
66    Revision 1.6  2003/08/11 16:56:16  arjen
67    Different kinds of log files are parsed by a collection of objects
68    of different classes, derived from the base class line_cooker
69    Depending on the message content or the message_type element in
70    XML, one of these objects is selected.
71
72    Logrunner is integrated with gcm_input. Although its functionality
73    is still limited, a connection between logrunner and gcm_input
74    is beginning to form.
75
76    Revision 1.5  2003/08/05 08:11:06  arjen
77    Added two configuration parameters:
78       logfile   - Log to this file instead of stderr.
79       verbosity - Verbose output if greater than 0.
80    Added '-i' option for incremental parameter updates
81
82    Revision 1.4  2003/03/29 08:42:00  arjen
83    Exit without reading any input if the database connection fails.
84
85    Revision 1.3  2002/11/09 08:04:27  arjen
86    Added a reference to the GPL
87
88    Revision 1.2  2002/11/04 10:13:36  arjen
89    Use proper namespace for iostream classes
90
91    Revision 1.1  2002/10/05 10:25:49  arjen
92    Creation of gcm_input and a first approach to a web interface
93
94 *****************************/
95
96 static const char *RCSID = "$Id: gcm_input.cpp,v 1.8 2003-08-16 15:30:19 arjen Exp $";
97
98 #include <fstream>
99
100 #include <getopt.h>
101
102 #include "message.h"
103 #include "syslog_cooker.h"
104 #include "irix_syslog_cooker.h"
105 #include "access_cooker.h"
106 #include "error_cooker.h"
107
108 bool verbose = false;
109 bool testmode = false;
110 bool incremental = false;
111 std::ostream *log = &std::cerr;
112
113 static char *Version = "gcm_input version 0.0.7 - Jul 24, 2003";
114
115
116 /*=========================================================================
117 **  NAME           : main
118 **  SYNOPSIS       : int main(int argc, char *argv[])
119 **  PARAMETERS     : 
120 **  RETURN VALUE   : 
121 **
122 **  DESCRIPTION    : Parse command line arguments and establish a connection
123 **                   to the database.
124 **                   When we have a database connection, parse the log file
125 **                   from stdin.
126 **
127 **  VARS USED      :
128 **  VARS CHANGED   :
129 **  FUNCTIONS USED :
130 **  SEE ALSO       :
131 **  LAST MODIFIED  : Aug 11, 2003
132 **=========================================================================
133 */
134
135 int main(int argc, char *argv[])
136 {
137    const char *usage = "Usage: gcm_input [-c configname] [-h hostname] [-i] [-d date]"
138                        " [-s service] [-T] [-v] [-V]\n";
139
140    gnucomo_config    cfg;
141    char             *config_name = "gnucomo";
142    std::ofstream    logfile;
143
144
145    /*   Parse command line arguments */
146
147    UTC    arrival = Now();
148    String  hostname(""), service("");
149    int     option;
150
151
152    while ((option = getopt(argc, argv, "c:h:d:s:iTvV")) != -1)
153    {
154       switch (option)
155       {
156       case 'c':
157          config_name = optarg;
158          break;
159
160       case 'h':
161          hostname = optarg;
162          break;
163
164       case 'd':
165          arrival = String(optarg);
166          if (!arrival.proper())
167          {
168             std::cerr << "gcm_input: Invalid date string: " << optarg << ".\n";
169             exit(1);
170          }
171          break;
172
173       case 's':
174          service = optarg;
175          break;
176
177       case 'i':
178          incremental = true;
179          break;
180
181       case 'T':
182          testmode = true;
183          break;
184
185       case 'v':
186          verbose = true;
187          break;
188
189       case 'V':
190          std::cout << Version << "\n";
191          exit(0);
192
193       case '?':
194       case ':':
195          std::cerr << usage;
196          exit(1);
197       }
198    }
199    /*  Get the configuration file */
200
201    if (!cfg.read(config_name))
202    {
203       std::cerr << "Can not read Gnucomo configuration file for " << config_name << ".\n";
204       exit(1);
205    }
206
207    String log_method      = cfg.find_parameter("logging", "method");
208    String log_destination = cfg.find_parameter("logging", "destination");
209    int    level           = cfg.find_parameter("gcm_input", "level");
210
211    if (log_method == "file" && log_destination != "")
212    {
213       std::cerr << "Logging to " << log_destination << ".\n";
214 #if __GNUC__ == 2
215       logfile.open(log_destination, _IO_APPEND); // for gcc 2
216 #else
217       logfile.open(log_destination, std::ios_base::app); // for gcc 3
218 #endif
219       if (!logfile)
220       {
221          std::cerr << "Can't open logfile " << log_destination << " for writing.\n";
222       }
223       else
224       {
225          log = &logfile;
226          verbose = verbose || level > 0;
227       }
228    }
229
230    *log << "Gcm_input starting at " << Now() << ".\n";
231
232    if (verbose)
233    {
234       *log << "Hostname = " << hostname;
235       *log << " Arrival = " << arrival;
236       *log << " Service = " << service << "\n";
237       *log << "Config OK.\n";
238    }
239
240    /*  Try to connect to the database */
241
242    gnucomo_database db(&cfg);
243
244    if (db.is_connected())
245    {
246
247       client_message      msg(&std::cin, db);
248       syslog_cooker       slc;
249       irix_syslog_cooker  islc;
250       access_cooker       alc;
251       error_cooker        elc;
252
253       msg.add_cooker(&slc);
254       msg.add_cooker(&islc);
255       msg.add_cooker(&alc);
256       msg.add_cooker(&elc);
257
258       if (msg.classify(hostname, arrival, service) > 0.9)
259       {
260          msg.enter();
261       }
262       *log << "Gcm_input finished at " << Now() << ".\n";
263       return 0;
264    }
265    else
266    {
267       *log << "gcm_input: Can not connect to database.\n";
268       *log << "Gcm_input finished at " << Now() << ".\n";
269       return 1;
270    }
271 }
272