18d9abf328f8bff19a98c2cf555772816ee28eb4
[oweals/gnunet.git] / src / monkey / gnunet-monkey.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010, 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet 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 for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file monkey/gnunet-monkey.c
23  * @brief Monkey: gnunet automated debugging tool
24  */
25
26 #include <stdio.h>
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_getopt_lib.h"
30 #include "gnunet_program_lib.h"
31 #include "gnunet_monkey_action.h"
32
33 static const char *mode;
34 static const char *dumpFileName;
35 static const char *binaryName;
36 static const char *emailAddress;
37 static const char *edbFilePath;
38 static const char *gdbBinaryPath;
39 static const char *inspectExpression;
40 static const char *inspectFunction;
41 static int ret = 0;
42
43 /**
44  * Main function that will launch the action api.
45  *
46  * @param cls closure
47  * @param args remaining command-line arguments
48  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
49  * @param c configuration
50  */
51 static void
52 run (void *cls,
53      char *const *args,
54      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
55 {
56   int result;
57   struct GNUNET_MONKEY_ACTION_Context *cntxt;
58
59   if (strcasecmp (mode, "email") == 0)
60     {
61       if (NULL == emailAddress)
62         {
63           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
64                       "Working in email mode requires an email address!\n");
65           ret = 1;
66           return;
67         }
68     }
69   else if (strcasecmp (mode, "text") == 0)
70     {
71       if (NULL == dumpFileName)
72         {
73           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
74                       "Working in text mode requires a path for the dump file!\n");
75           ret = 1;
76           return;
77         }
78     }
79
80   /* Initialize context for the Action API */
81   cntxt = GNUNET_malloc (sizeof (struct GNUNET_MONKEY_ACTION_Context));
82   cntxt->binary_name = binaryName;
83   cntxt->expression_database_path = edbFilePath;
84   cntxt->gdb_binary_path = gdbBinaryPath;
85   cntxt->inspect_expression = inspectExpression;
86   cntxt->inspect_function = inspectFunction;
87
88   result = GNUNET_MONKEY_ACTION_rerun_with_gdb (cntxt);
89   switch (result)
90     {
91       int retVal;
92     case GDB_STATE_ERROR:
93       break;
94     case GDB_STATE_EXIT_NORMALLY:
95       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
96                   "Debug with gdb, program exited normally!\n");
97       /*FIXME: Valgrind should be launched here */
98       break;
99     case GDB_STATE_STOPPED:
100       /*FIXME: Expression Database should be inspected here (before writing the report) */
101       retVal = GNUNET_MONKEY_ACTION_inspect_expression_database (cntxt);
102       if (GNUNET_NO == retVal)
103         {
104           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
105                       "Error using Expression Database!\n");
106           ret = 1;
107           break;
108         }
109       else if (GDB_STATE_ERROR == retVal)
110         {
111           /* GDB could not locate a NULL value expression, launch Valgrind */
112           retVal = GNUNET_MONKEY_ACTION_rerun_with_valgrind (cntxt);
113           if (GNUNET_NO == retVal)
114             {
115               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error using Valgrind!\n");
116               ret = 1;
117               break;
118             }
119         }
120       if (GNUNET_OK != GNUNET_MONKEY_ACTION_format_report (cntxt))
121         {
122           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
123                       "Error in generating debug report!\n");
124           ret = 1;
125         }
126       if (strcasecmp (mode, "email") == 0)
127         {
128           if (GNUNET_OK != GNUNET_MONKEY_ACTION_report_email (cntxt))
129             {
130               GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error sending email!\n");
131               ret = 1;
132             }
133         }
134       else
135         {
136           /* text mode */
137           if (GNUNET_OK !=
138               GNUNET_MONKEY_ACTION_report_file (cntxt, dumpFileName))
139             {
140               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
141                           "Error in saving debug file!\n");
142               ret = 1;
143             }
144         }
145       break;
146     default:
147       break;
148     }
149   GNUNET_MONKEY_ACTION_delete_context(cntxt);
150 }
151
152
153 int
154 main (int argc, char *argv[])
155 {
156   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
157     {'m', "mode", NULL,
158      gettext_noop
159      ("monkey's mode of operation: options are \"text\" or \"email\""),
160      GNUNET_YES, &GNUNET_GETOPT_set_string, &mode},
161     {'b', "binary", NULL,
162      gettext_noop ("binary for program to debug with monkey"),
163      GNUNET_YES, &GNUNET_GETOPT_set_string, &binaryName},
164     {'o', "output", NULL,
165      gettext_noop
166      ("path to file to dump monkey's output in case of text mode"),
167      GNUNET_YES, &GNUNET_GETOPT_set_string, &dumpFileName},
168     {'a', "address", NULL,
169      gettext_noop ("address to send email to in case of email mode"),
170      GNUNET_YES, &GNUNET_GETOPT_set_string, &emailAddress},
171     {'d', "database", NULL, gettext_noop ("path to Expression Database file"),
172      GNUNET_YES, &GNUNET_GETOPT_set_string, &edbFilePath},
173     {'g', "gdb", NULL,
174      gettext_noop ("path to gdb binary in use; default is /usr/bin/gdb"),
175      GNUNET_YES, &GNUNET_GETOPT_set_string, &gdbBinaryPath},
176     {'f', "function", NULL, gettext_noop ("Monkey will set a breakpoint on this function"),
177      GNUNET_YES, &GNUNET_GETOPT_set_string, &inspectFunction},
178     {'i', "inspect", NULL, gettext_noop ("An expression to inspect in the function specified after the argument f"),
179      GNUNET_YES, &GNUNET_GETOPT_set_string, &inspectExpression},
180     GNUNET_GETOPT_OPTION_END
181   };
182
183   if (argc < 2)
184     {
185       printf ("%s",
186               "Monkey should take arguments: Use --help to get a list of options.\n");
187       return 1;
188     }
189
190   if (GNUNET_OK == GNUNET_PROGRAM_run (argc,
191                                        argv,
192                                        "gnunet-monkey",
193                                        gettext_noop
194                                        ("Automatically debug a service"),
195                                        options, &run, NULL))
196     {
197       return ret;
198     }
199
200   return 1;
201 }