update for powerpc
[lttv.git] / ltt / branches / poly / lttv / modules / gui / tracecontrol / tracecontrol.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2005 Mathieu Desnoyers
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <glib.h>
24 #include <glib/gprintf.h>
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <gdk/gdk.h>
28 #include <gdk/gdkkeysyms.h>
29
30 #include <lttv/lttv.h>
31 #include <lttv/module.h>
32 #include <lttv/hook.h>
33
34 #include <lttvwindow/lttvwindow.h>
35 #include <lttvwindow/lttvwindowtraces.h>
36 #include <lttvwindow/callbacks.h>
37
38 #include "hTraceControlInsert.xpm"
39 #include "TraceControlStart.xpm"
40 #include "TraceControlPause.xpm"
41 #include "TraceControlStop.xpm"
42
43 #include <sys/types.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <pty.h>
47 #include <utmp.h>
48 #include <sys/wait.h>
49 #include <sys/poll.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <sched.h>
53
54 #define MAX_ARGS_LEN PATH_MAX * 10
55
56 GSList *g_control_list = NULL ;
57
58 /*! \file lttv/modules/gui/tracecontrol/tracecontrol.c
59 * \brief Graphic trace start/stop control interface.
60 *
61 * This plugin interacts with lttctl to start/stop tracing. It needs to take the
62 * root password to be able to interact with lttctl.
63 *
64 */
65
66 typedef struct _ControlData ControlData;
67
68 /*
69 * Prototypes
70 */
71 GtkWidget *guicontrol_get_widget(ControlData *tcd);
72 ControlData *gui_control(Tab *tab);
73 void gui_control_destructor(ControlData *tcd);
74 GtkWidget* h_guicontrol(Tab *tab);
75 void control_destroy_walk(gpointer data, gpointer user_data);
76
77 /*
78 * Callback functions
79 */
80
81 static void start_clicked (GtkButton *button, gpointer user_data);
82 static void pause_clicked (GtkButton *button, gpointer user_data);
83 static void unpause_clicked (GtkButton *button, gpointer user_data);
84 static void stop_clicked (GtkButton *button, gpointer user_data);
85
86
87 /**
88 * @struct _ControlData
89 *
90 * @brief Main structure of gui control
91 */
92 struct _ControlData {
93 Tab *tab; /**< current tab of module */
94
95 GtkWidget *window; /**< window */
96
97 GtkWidget *main_box; /**< main container */
98 GtkWidget *start_button;
99 GtkWidget *pause_button;
100 GtkWidget *unpause_button;
101 GtkWidget *stop_button;
102 GtkWidget *username_label;
103 GtkWidget *username_entry;
104 GtkWidget *password_label;
105 GtkWidget *password_entry;
106 GtkWidget *channel_dir_label;
107 GtkWidget *channel_dir_entry;
108 GtkWidget *trace_dir_label;
109 GtkWidget *trace_dir_entry;
110 GtkWidget *trace_name_label;
111 GtkWidget *trace_name_entry;
112 GtkWidget *trace_mode_label;
113 GtkWidget *trace_mode_combo;
114 GtkWidget *start_daemon_label;
115 GtkWidget *start_daemon_check;
116 GtkWidget *append_label;
117 GtkWidget *append_check;
118 GtkWidget *optional_label;
119 GtkWidget *subbuf_size_label;
120 GtkWidget *subbuf_size_entry;
121 GtkWidget *subbuf_num_label;
122 GtkWidget *subbuf_num_entry;
123 GtkWidget *lttd_threads_label;
124 GtkWidget *lttd_threads_entry;
125 GtkWidget *lttctl_path_label;
126 GtkWidget *lttctl_path_entry;
127 GtkWidget *lttd_path_label;
128 GtkWidget *lttd_path_entry;
129 GtkWidget *fac_path_label;
130 GtkWidget *fac_path_entry;
131 };
132
133 /**
134 * @fn GtkWidget* guicontrol_get_widget(ControlData*)
135 *
136 * This function returns the current main widget
137 * used by this module
138 * @param tcd the module struct
139 * @return The main widget
140 */
141 GtkWidget*
142 guicontrol_get_widget(ControlData *tcd)
143 {
144 return tcd->window;
145 }
146
147 /**
148 * @fn ControlData* gui_control(Tab*)
149 *
150 * Constructor is used to create ControlData data structure.
151 * @param tab The tab structure used by the widget
152 * @return The Filter viewer data created.
153 */
154 ControlData*
155 gui_control(Tab *tab)
156 {
157 g_debug("filter::gui_control()");
158
159 unsigned i;
160 GtkCellRenderer *renderer;
161 GtkTreeViewColumn *column;
162
163 ControlData* tcd = g_new(ControlData,1);
164
165 tcd->tab = tab;
166
167 tcd->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
168 gtk_window_set_title(GTK_WINDOW(tcd->window), "LTTng Trace Control");
169 /*
170 * Initiating GtkTable layout
171 * starts with 2 rows and 5 columns and
172 * expands when expressions added
173 */
174 tcd->main_box = gtk_table_new(14,7,FALSE);
175 gtk_table_set_row_spacings(GTK_TABLE(tcd->main_box),5);
176 gtk_table_set_col_spacings(GTK_TABLE(tcd->main_box),5);
177
178 gtk_container_add(GTK_CONTAINER(tcd->window), GTK_WIDGET(tcd->main_box));
179
180 GList *focus_chain = NULL;
181
182 /*
183 * start/pause/stop buttons
184 */
185 GdkPixbuf *pixbuf;
186 GtkWidget *image;
187 pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)TraceControlStart_xpm);
188 image = gtk_image_new_from_pixbuf(pixbuf);
189 tcd->start_button = gtk_button_new_with_label("start");
190 //2.6 gtk_button_set_image(GTK_BUTTON(tcd->start_button), image);
191 g_object_set(G_OBJECT(tcd->start_button), "image", image, NULL);
192 gtk_button_set_alignment(GTK_BUTTON(tcd->start_button), 0.0, 0.0);
193 gtk_widget_show (tcd->start_button);
194 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->start_button,6,7,0,1,GTK_FILL,GTK_FILL,2,2);
195
196 pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)TraceControlPause_xpm);
197 image = gtk_image_new_from_pixbuf(pixbuf);
198 tcd->pause_button = gtk_button_new_with_label("pause");
199 //2.6 gtk_button_set_image(GTK_BUTTON(tcd->pause_button), image);
200 g_object_set(G_OBJECT(tcd->pause_button), "image", image, NULL);
201 gtk_button_set_alignment(GTK_BUTTON(tcd->pause_button), 0.0, 0.0);
202 gtk_widget_show (tcd->pause_button);
203 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->pause_button,6,7,1,2,GTK_FILL,GTK_FILL,2,2);
204
205 pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)TraceControlPause_xpm);
206 image = gtk_image_new_from_pixbuf(pixbuf);
207 tcd->unpause_button = gtk_button_new_with_label("unpause");
208 //2.6 gtk_button_set_image(GTK_BUTTON(tcd->unpause_button), image);
209 g_object_set(G_OBJECT(tcd->unpause_button), "image", image, NULL);
210 gtk_button_set_alignment(GTK_BUTTON(tcd->unpause_button), 0.0, 0.0);
211 gtk_widget_show (tcd->unpause_button);
212 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->unpause_button,6,7,2,3,GTK_FILL,GTK_FILL,2,2);
213
214 pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)TraceControlStop_xpm);
215 image = gtk_image_new_from_pixbuf(pixbuf);
216 tcd->stop_button = gtk_button_new_with_label("stop");
217 //2.6 gtk_button_set_image(GTK_BUTTON(tcd->stop_button), image);
218 g_object_set(G_OBJECT(tcd->stop_button), "image", image, NULL);
219 gtk_button_set_alignment(GTK_BUTTON(tcd->stop_button), 0.0, 0.0);
220 gtk_widget_show (tcd->stop_button);
221 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->stop_button,6,7,3,4,GTK_FILL,GTK_FILL,2,2);
222
223 /*
224 * First half of the filter window
225 * - textual entry of filter expression
226 * - processing button
227 */
228 tcd->username_label = gtk_label_new("Username:");
229 gtk_widget_show (tcd->username_label);
230 tcd->username_entry = gtk_entry_new();
231 gtk_entry_set_text(GTK_ENTRY(tcd->username_entry),"root");
232 gtk_widget_show (tcd->username_entry);
233 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->username_label,0,2,0,1,GTK_FILL,GTK_FILL,2,2);
234 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->username_entry,2,6,0,1,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
235
236
237
238 tcd->password_label = gtk_label_new("Password:");
239 gtk_widget_show (tcd->password_label);
240 tcd->password_entry = gtk_entry_new();
241 gtk_entry_set_visibility(GTK_ENTRY(tcd->password_entry), FALSE);
242 gtk_widget_show (tcd->password_entry);
243 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->password_label,0,2,1,2,GTK_FILL,GTK_FILL,2,2);
244 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->password_entry,2,6,1,2,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
245
246
247 tcd->channel_dir_label = gtk_label_new("Channel directory:");
248 gtk_widget_show (tcd->channel_dir_label);
249 tcd->channel_dir_entry = gtk_entry_new();
250 gtk_entry_set_text(GTK_ENTRY(tcd->channel_dir_entry),"/mnt/relayfs/ltt");
251 gtk_widget_show (tcd->channel_dir_entry);
252 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->channel_dir_label,0,2,2,3,GTK_FILL,GTK_FILL,2,2);
253 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->channel_dir_entry,2,6,2,3,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
254
255 tcd->trace_dir_label = gtk_label_new("Trace directory:");
256 gtk_widget_show (tcd->trace_dir_label);
257 tcd->trace_dir_entry = gtk_entry_new();
258 gtk_entry_set_text(GTK_ENTRY(tcd->trace_dir_entry),"/tmp/trace1");
259 gtk_widget_show (tcd->trace_dir_entry);
260 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->trace_dir_label,0,2,3,4,GTK_FILL,GTK_FILL,2,2);
261 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->trace_dir_entry,2,6,3,4,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
262
263 tcd->trace_name_label = gtk_label_new("Trace name:");
264 gtk_widget_show (tcd->trace_name_label);
265 tcd->trace_name_entry = gtk_entry_new();
266 gtk_entry_set_text(GTK_ENTRY(tcd->trace_name_entry),"trace");
267 gtk_widget_show (tcd->trace_name_entry);
268 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->trace_name_label,0,2,4,5,GTK_FILL,GTK_FILL,2,2);
269 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->trace_name_entry,2,6,4,5,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
270
271 tcd->trace_mode_label = gtk_label_new("Trace mode ");
272 gtk_widget_show (tcd->trace_mode_label);
273 tcd->trace_mode_combo = gtk_combo_box_new_text();
274 gtk_combo_box_append_text(GTK_COMBO_BOX(tcd->trace_mode_combo),
275 "normal");
276 gtk_combo_box_append_text(GTK_COMBO_BOX(tcd->trace_mode_combo),
277 "flight recorder");
278 gtk_combo_box_set_active(GTK_COMBO_BOX(tcd->trace_mode_combo), 0);
279 gtk_widget_show (tcd->trace_mode_combo);
280 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->trace_mode_label,0,2,5,6,GTK_FILL,GTK_FILL,2,2);
281 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->trace_mode_combo,2,6,5,6,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
282
283 tcd->start_daemon_label = gtk_label_new("Start daemon ");
284 gtk_widget_show (tcd->start_daemon_label);
285 tcd->start_daemon_check = gtk_check_button_new();
286 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tcd->start_daemon_check), TRUE);
287 gtk_widget_show (tcd->start_daemon_check);
288 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->start_daemon_label,0,2,6,7,GTK_FILL,GTK_FILL,2,2);
289 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->start_daemon_check,2,6,6,7,GTK_FILL,GTK_FILL,0,0);
290
291 tcd->append_label = gtk_label_new("Append to trace ");
292 gtk_widget_show (tcd->append_label);
293 tcd->append_check = gtk_check_button_new();
294 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tcd->append_check), FALSE);
295 gtk_widget_show (tcd->append_check);
296 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->append_label,0,2,7,8,GTK_FILL,GTK_FILL,2,2);
297 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->append_check,2,6,7,8,GTK_FILL,GTK_FILL,0,0);
298
299
300 tcd->optional_label = gtk_label_new("Optional fields ");
301 gtk_widget_show (tcd->optional_label);
302 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->optional_label,0,6,8,9,GTK_FILL,GTK_FILL,2,2);
303
304 tcd->subbuf_size_label = gtk_label_new("Subbuffer size:");
305 gtk_widget_show (tcd->subbuf_size_label);
306 tcd->subbuf_size_entry = gtk_entry_new();
307 gtk_widget_show (tcd->subbuf_size_entry);
308 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->subbuf_size_label,0,2,9,10,GTK_FILL,GTK_FILL,2,2);
309 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->subbuf_size_entry,2,6,9,10,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
310
311 tcd->subbuf_num_label = gtk_label_new("Number of subbuffers:");
312 gtk_widget_show (tcd->subbuf_num_label);
313 tcd->subbuf_num_entry = gtk_entry_new();
314 gtk_widget_show (tcd->subbuf_num_entry);
315 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->subbuf_num_label,0,2,10,11,GTK_FILL,GTK_FILL,2,2);
316 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->subbuf_num_entry,2,6,10,11,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
317
318 tcd->lttd_threads_label = gtk_label_new("Number of lttd threads:");
319 gtk_widget_show (tcd->lttd_threads_label);
320 tcd->lttd_threads_entry = gtk_entry_new();
321 gtk_entry_set_text(GTK_ENTRY(tcd->lttd_threads_entry), "1");
322 gtk_widget_show (tcd->lttd_threads_entry);
323 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->lttd_threads_label,0,2,11,12,GTK_FILL,GTK_FILL,2,2);
324 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->lttd_threads_entry,2,6,11,12,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
325
326 tcd->lttctl_path_label = gtk_label_new("path to lttctl:");
327 gtk_widget_show (tcd->lttctl_path_label);
328 tcd->lttctl_path_entry = gtk_entry_new();
329 gtk_entry_set_text(GTK_ENTRY(tcd->lttctl_path_entry),PACKAGE_BIN_DIR "/lttctl");
330 gtk_widget_show (tcd->lttctl_path_entry);
331 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->lttctl_path_label,0,2,12,13,GTK_FILL,GTK_FILL,2,2);
332 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->lttctl_path_entry,2,6,12,13,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
333
334
335 tcd->lttd_path_label = gtk_label_new("path to lttd:");
336 gtk_widget_show (tcd->lttd_path_label);
337 tcd->lttd_path_entry = gtk_entry_new();
338 gtk_entry_set_text(GTK_ENTRY(tcd->lttd_path_entry),PACKAGE_BIN_DIR "/lttd");
339 gtk_widget_show (tcd->lttd_path_entry);
340 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->lttd_path_label,0,2,13,14,GTK_FILL,GTK_FILL,2,2);
341 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->lttd_path_entry,2,6,13,14,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
342
343
344 tcd->fac_path_label = gtk_label_new("path to facilities:");
345 gtk_widget_show (tcd->fac_path_label);
346 tcd->fac_path_entry = gtk_entry_new();
347 gtk_entry_set_text(GTK_ENTRY(tcd->fac_path_entry),PACKAGE_DATA_DIR "/" "ltt-control" "/facilities");
348 gtk_widget_set_size_request(tcd->fac_path_entry, 250, -1);
349 gtk_widget_show (tcd->fac_path_entry);
350 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->fac_path_label,0,2,14,15,GTK_FILL,GTK_FILL,2,2);
351 gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->fac_path_entry,2,6,14,15,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0);
352
353 focus_chain = g_list_append (focus_chain, tcd->username_entry);
354 focus_chain = g_list_append (focus_chain, tcd->password_entry);
355 focus_chain = g_list_append (focus_chain, tcd->start_button);
356 focus_chain = g_list_append (focus_chain, tcd->pause_button);
357 focus_chain = g_list_append (focus_chain, tcd->unpause_button);
358 focus_chain = g_list_append (focus_chain, tcd->stop_button);
359 focus_chain = g_list_append (focus_chain, tcd->channel_dir_entry);
360 focus_chain = g_list_append (focus_chain, tcd->trace_dir_entry);
361 focus_chain = g_list_append (focus_chain, tcd->trace_name_entry);
362 focus_chain = g_list_append (focus_chain, tcd->trace_mode_combo);
363 focus_chain = g_list_append (focus_chain, tcd->start_daemon_check);
364 focus_chain = g_list_append (focus_chain, tcd->append_check);
365 focus_chain = g_list_append (focus_chain, tcd->subbuf_size_entry);
366 focus_chain = g_list_append (focus_chain, tcd->subbuf_num_entry);
367 focus_chain = g_list_append (focus_chain, tcd->lttd_threads_entry);
368 focus_chain = g_list_append (focus_chain, tcd->lttctl_path_entry);
369 focus_chain = g_list_append (focus_chain, tcd->lttd_path_entry);
370 focus_chain = g_list_append (focus_chain, tcd->fac_path_entry);
371
372 gtk_container_set_focus_chain(GTK_CONTAINER(tcd->main_box), focus_chain);
373
374 g_list_free(focus_chain);
375
376 g_signal_connect(G_OBJECT(tcd->start_button), "clicked",
377 (GCallback)start_clicked, tcd);
378 g_signal_connect(G_OBJECT(tcd->pause_button), "clicked",
379 (GCallback)pause_clicked, tcd);
380 g_signal_connect(G_OBJECT(tcd->unpause_button), "clicked",
381 (GCallback)unpause_clicked, tcd);
382 g_signal_connect(G_OBJECT(tcd->stop_button), "clicked",
383 (GCallback)stop_clicked, tcd);
384
385 /*
386 * show main container
387 */
388 gtk_widget_show(tcd->main_box);
389 gtk_widget_show(tcd->window);
390
391
392 g_object_set_data_full(
393 G_OBJECT(guicontrol_get_widget(tcd)),
394 "control_viewer_data",
395 tcd,
396 (GDestroyNotify)gui_control_destructor);
397
398 g_control_list = g_slist_append(
399 g_control_list,
400 tcd);
401
402 return tcd;
403 }
404
405
406 /**
407 * @fn void gui_control_destructor(ControlData*)
408 *
409 * Destructor for the filter gui module
410 * @param tcd The module structure
411 */
412 void
413 gui_control_destructor(ControlData *tcd)
414 {
415 Tab *tab = tcd->tab;
416
417 /* May already been done by GTK window closing */
418 if(GTK_IS_WIDGET(guicontrol_get_widget(tcd))){
419 g_info("widget still exists");
420 }
421 // if(tab != NULL) {
422 // lttvwindow_unregister_traceset_notify(tcd->tab,
423 // filter_traceset_changed,
424 // filter_viewer_data);
425 // }
426 lttvwindowtraces_background_notify_remove(tcd);
427
428 g_control_list = g_slist_remove(g_control_list, tcd);
429
430 g_free(tcd);
431 }
432
433 static int execute_command(const gchar *command, const gchar *username,
434 const gchar *password, const gchar *lttd_path, const gchar *fac_path)
435 {
436 pid_t pid;
437 int fdpty;
438 pid = forkpty(&fdpty, NULL, NULL, NULL);
439 int retval = 0;
440
441 if(pid > 0) {
442 /* parent */
443 gchar buf[256];
444 int status;
445 ssize_t count;
446 /* discuss with su */
447 struct timeval timeout;
448 timeout.tv_sec = 1;
449 timeout.tv_usec = 0;
450
451 struct pollfd pollfd;
452 int num_rdy;
453 int num_hup = 0;
454 enum read_state { GET_LINE, GET_SEMI, GET_SPACE } read_state = GET_LINE;
455
456 retval = fcntl(fdpty, F_SETFL, O_WRONLY);
457 if(retval == -1) {
458 perror("Error in fcntl");
459 goto wait_child;
460 }
461
462 /* Read the output from the child terminal before the prompt. If no data in
463 * 200 ms, we stop reading to give the password */
464 g_info("Reading from child console...");
465 while(1) {
466 pollfd.fd = fdpty;
467 pollfd.events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL;
468
469 num_rdy = poll(&pollfd, 1, -1);
470 if(num_rdy == -1) {
471 perror("Poll error");
472 goto wait_child;
473 }
474
475 /* Timeout : Stop waiting for chars */
476 if(num_rdy == 0) goto wait_child;
477
478 switch(pollfd.revents) {
479 case POLLERR:
480 g_warning("Error returned in polling fd\n");
481 num_hup++;
482 break;
483 case POLLHUP:
484 g_info("Polling FD : hung up.");
485 num_hup++;
486 break;
487 case POLLNVAL:
488 g_warning("Polling fd tells it is not open");
489 num_hup++;
490 break;
491 case POLLPRI:
492 case POLLIN:
493 count = read (fdpty, buf, 256);
494 if(count > 0) {
495 unsigned int i;
496 buf[count] = '\0';
497 g_printf("%s", buf);
498 for(i=0; i<count; i++) {
499 switch(read_state) {
500 case GET_LINE:
501 if(buf[i] == '\n') {
502 read_state = GET_SEMI;
503 g_debug("Tracecontrol input line skip\n");
504 }
505 break;
506 case GET_SEMI:
507 if(buf[i] == ':') {
508 g_debug("Tracecontrol input : marker found\n");
509 read_state = GET_SPACE;
510 }
511 break;
512 case GET_SPACE:
513 if(buf[i] == ' ') {
514 g_debug("Tracecontrol input space marker found\n");
515 goto write_password;
516 }
517 break;
518 }
519 }
520 } else if(count == -1) {
521 perror("Error in read");
522 goto wait_child;
523 }
524 break;
525 }
526 if(num_hup > 0) {
527 g_warning("Child hung up too fast");
528 goto wait_child;
529 }
530 }
531 write_password:
532 fsync(fdpty);
533 pollfd.fd = fdpty;
534 pollfd.events = POLLOUT|POLLERR|POLLHUP|POLLNVAL;
535
536 num_rdy = poll(&pollfd, 1, -1);
537 if(num_rdy == -1) {
538 perror("Poll error");
539 goto wait_child;
540 }
541
542 /* Write the password */
543 g_info("Got su prompt, now writing password...");
544 int ret;
545 sleep(1);
546 ret = write(fdpty, password, strlen(password));
547 if(ret < 0) perror("Error in write");
548 ret = write(fdpty, "\n", 1);
549 if(ret < 0) perror("Error in write");
550 fsync(fdpty);
551 /* Take the output from the terminal and show it on the real console */
552 g_info("Getting data from child terminal...");
553 while(1) {
554 int num_hup = 0;
555 pollfd.fd = fdpty;
556 pollfd.events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL;
557
558 num_rdy = poll(&pollfd, 1, -1);
559 if(num_rdy == -1) {
560 perror("Poll error");
561 goto wait_child;
562 }
563 if(num_rdy == 0) break;
564
565 if(pollfd.revents & (POLLERR|POLLNVAL)) {
566 g_warning("Error returned in polling fd\n");
567 num_hup++;
568 }
569
570 if(pollfd.revents & (POLLIN|POLLPRI) ) {
571 count = read (fdpty, buf, 256);
572 if(count > 0) {
573 buf[count] = '\0';
574 printf("%s", buf);
575 } else if(count == -1) {
576 perror("Error in read");
577 goto wait_child;
578 }
579 }
580
581 if(pollfd.revents & POLLHUP) {
582 g_info("Polling FD : hung up.");
583 num_hup++;
584 }
585
586 if(num_hup > 0) goto wait_child;
587 }
588 wait_child:
589 g_info("Waiting for child exit...");
590
591 ret = waitpid(pid, &status, 0);
592
593 if(ret == -1) {
594 g_warning("An error occured in wait : %s",
595 strerror(errno));
596 } else {
597 if(WIFEXITED(status))
598 if(WEXITSTATUS(status) != 0) {
599 retval = WEXITSTATUS(status);
600 g_warning("An error occured in the su command : %s",
601 strerror(retval));
602 }
603 }
604
605 g_info("Child exited.");
606
607 } else if(pid == 0) {
608 /* Setup environment variables */
609 if(strcmp(lttd_path, "") != 0)
610 setenv("LTT_DAEMON", lttd_path, 1);
611 if(strcmp(fac_path, "") != 0)
612 setenv("LTT_FACILITIES", fac_path, 1);
613
614 /* One comment line (must be only one) */
615 g_printf("Executing (as %s) : %s\n", username, command);
616
617 execlp("su", "su", "-p", "-c", command, username, NULL);
618 exit(-1); /* not supposed to happen! */
619
620 //gint ret = execvp();
621
622 } else {
623 /* error */
624 g_warning("Error happened when forking for su");
625 }
626
627 return retval;
628 }
629
630
631 /* Callbacks */
632
633 void start_clicked (GtkButton *button, gpointer user_data)
634 {
635 ControlData *tcd = (ControlData*)user_data;
636
637 const gchar *username = gtk_entry_get_text(GTK_ENTRY(tcd->username_entry));
638 const gchar *password = gtk_entry_get_text(GTK_ENTRY(tcd->password_entry));
639 const gchar *channel_dir =
640 gtk_entry_get_text(GTK_ENTRY(tcd->channel_dir_entry));
641 const gchar *trace_dir = gtk_entry_get_text(GTK_ENTRY(tcd->trace_dir_entry));
642 const gchar *trace_name =
643 gtk_entry_get_text(GTK_ENTRY(tcd->trace_name_entry));
644
645 const gchar *trace_mode_sel;
646 GtkTreeIter iter;
647
648 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(tcd->trace_mode_combo), &iter);
649 gtk_tree_model_get(
650 gtk_combo_box_get_model(GTK_COMBO_BOX(tcd->trace_mode_combo)),
651 &iter, 0, &trace_mode_sel, -1);
652 //const gchar *trace_mode_sel =
653 //2.6+ gtk_combo_box_get_active_text(GTK_COMBO_BOX(tcd->trace_mode_combo));
654 const gchar *trace_mode;
655 if(strcmp(trace_mode_sel, "normal") == 0)
656 trace_mode = "normal";
657 else
658 trace_mode = "flight";
659
660 gboolean start_daemon =
661 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tcd->start_daemon_check));
662
663 gboolean append =
664 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tcd->append_check));
665
666 const gchar *subbuf_size =
667 gtk_entry_get_text(GTK_ENTRY(tcd->subbuf_size_entry));
668 const gchar *subbuf_num =
669 gtk_entry_get_text(GTK_ENTRY(tcd->subbuf_num_entry));
670 const gchar *threads_num =
671 gtk_entry_get_text(GTK_ENTRY(tcd->lttd_threads_entry));
672 const gchar *lttctl_path =
673 gtk_entry_get_text(GTK_ENTRY(tcd->lttctl_path_entry));
674 const gchar *lttd_path = gtk_entry_get_text(GTK_ENTRY(tcd->lttd_path_entry));
675 const gchar *fac_path = gtk_entry_get_text(GTK_ENTRY(tcd->fac_path_entry));
676
677
678 /* Setup arguments to su */
679 /* child */
680 gchar args[MAX_ARGS_LEN];
681 gint args_left = MAX_ARGS_LEN - 1; /* for \0 */
682
683 args[0] = '\0';
684
685 /* Command */
686 strncat(args, "exec", args_left);
687 args_left = MAX_ARGS_LEN - strlen(args) - 1;
688
689 /* space */
690 strncat(args, " ", args_left);
691 args_left = MAX_ARGS_LEN - strlen(args) - 1;
692
693 if(strcmp(lttctl_path, "") == 0)
694 strncat(args, "lttctl", args_left);
695 else
696 strncat(args, lttctl_path, args_left);
697 args_left = MAX_ARGS_LEN - strlen(args) - 1;
698
699 /* space */
700 strncat(args, " ", args_left);
701 args_left = MAX_ARGS_LEN - strlen(args) - 1;
702
703 /* channel dir */
704 strncat(args, "-l ", args_left);
705 args_left = MAX_ARGS_LEN - strlen(args) - 1;
706 strncat(args, channel_dir, args_left);
707 args_left = MAX_ARGS_LEN - strlen(args) - 1;
708
709 /* space */
710 strncat(args, " ", args_left);
711 args_left = MAX_ARGS_LEN - strlen(args) - 1;
712
713 /* trace dir */
714 strncat(args, "-t ", args_left);
715 args_left = MAX_ARGS_LEN - strlen(args) - 1;
716 strncat(args, trace_dir, args_left);
717 args_left = MAX_ARGS_LEN - strlen(args) - 1;
718
719 /* space */
720 strncat(args, " ", args_left);
721 args_left = MAX_ARGS_LEN - strlen(args) - 1;
722
723 /* name */
724 strncat(args, "-n ", args_left);
725 args_left = MAX_ARGS_LEN - strlen(args) - 1;
726 strncat(args, trace_name, args_left);
727 args_left = MAX_ARGS_LEN - strlen(args) - 1;
728
729 /* space */
730 strncat(args, " ", args_left);
731 args_left = MAX_ARGS_LEN - strlen(args) - 1;
732
733 /* trace mode */
734 strncat(args, "-m ", args_left);
735 args_left = MAX_ARGS_LEN - strlen(args) - 1;
736 strncat(args, trace_mode, args_left);
737 args_left = MAX_ARGS_LEN - strlen(args) - 1;
738
739 /* space */
740 strncat(args, " ", args_left);
741 args_left = MAX_ARGS_LEN - strlen(args) - 1;
742
743 /* Start daemon ? */
744 if(start_daemon) {
745 strncat(args, "-d", args_left);
746 args_left = MAX_ARGS_LEN - strlen(args) - 1;
747 } else {
748 /* Simply create the channel and then start tracing */
749 strncat(args, "-b", args_left);
750 args_left = MAX_ARGS_LEN - strlen(args) - 1;
751 }
752
753
754 /* Append to trace ? */
755 if(append) {
756 /* space */
757 strncat(args, " ", args_left);
758 args_left = MAX_ARGS_LEN - strlen(args) - 1;
759 strncat(args, "-a", args_left);
760 args_left = MAX_ARGS_LEN - strlen(args) - 1;
761 }
762
763 /* optional arguments */
764 /* subbuffer size */
765 if(strcmp(subbuf_size, "") != 0) {
766 /* space */
767 strncat(args, " ", args_left);
768 args_left = MAX_ARGS_LEN - strlen(args) - 1;
769
770 strncat(args, "-z ", args_left);
771 args_left = MAX_ARGS_LEN - strlen(args) - 1;
772 strncat(args, subbuf_size, args_left);
773 args_left = MAX_ARGS_LEN - strlen(args) - 1;
774 }
775
776 /* number of subbuffers */
777 if(strcmp(subbuf_num, "") != 0) {
778 /* space */
779 strncat(args, " ", args_left);
780 args_left = MAX_ARGS_LEN - strlen(args) - 1;
781
782 strncat(args, "-x ", args_left);
783 args_left = MAX_ARGS_LEN - strlen(args) - 1;
784 strncat(args, subbuf_num, args_left);
785 args_left = MAX_ARGS_LEN - strlen(args) - 1;
786 }
787
788 /* number of lttd threads */
789 if(strcmp(threads_num, "") != 0) {
790 /* space */
791 strncat(args, " ", args_left);
792 args_left = MAX_ARGS_LEN - strlen(args) - 1;
793
794 strncat(args, "-N ", args_left);
795 args_left = MAX_ARGS_LEN - strlen(args) - 1;
796 strncat(args, threads_num, args_left);
797 args_left = MAX_ARGS_LEN - strlen(args) - 1;
798 }
799
800
801 int retval = execute_command(args, username, password, lttd_path, fac_path);
802
803 if(retval) {
804 gchar msg[256];
805 guint msg_left = 256;
806
807 strcpy(msg, "A problem occured when executing the su command : ");
808 msg_left = 256 - strlen(msg) - 1;
809 strncat(msg, strerror(retval), msg_left);
810 GtkWidget *dialogue =
811 gtk_message_dialog_new(
812 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
813 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
814 GTK_MESSAGE_ERROR,
815 GTK_BUTTONS_OK,
816 msg);
817 gtk_dialog_run(GTK_DIALOG(dialogue));
818 gtk_widget_destroy(dialogue);
819 }
820
821 }
822
823
824 void pause_clicked (GtkButton *button, gpointer user_data)
825 {
826 ControlData *tcd = (ControlData*)user_data;
827
828 const gchar *username = gtk_entry_get_text(GTK_ENTRY(tcd->username_entry));
829 const gchar *password = gtk_entry_get_text(GTK_ENTRY(tcd->password_entry));
830 const gchar *trace_name =
831 gtk_entry_get_text(GTK_ENTRY(tcd->trace_name_entry));
832 const gchar *lttd_path = "";
833 const gchar *fac_path = "";
834
835 const gchar *lttctl_path =
836 gtk_entry_get_text(GTK_ENTRY(tcd->lttctl_path_entry));
837
838 /* Setup arguments to su */
839 /* child */
840 gchar args[MAX_ARGS_LEN];
841 gint args_left = MAX_ARGS_LEN - 1; /* for \0 */
842
843 args[0] = '\0';
844
845 /* Command */
846 strncat(args, "exec", args_left);
847 args_left = MAX_ARGS_LEN - strlen(args) - 1;
848
849 /* space */
850 strncat(args, " ", args_left);
851 args_left = MAX_ARGS_LEN - strlen(args) - 1;
852
853 if(strcmp(lttctl_path, "") == 0)
854 strncat(args, "lttctl", args_left);
855 else
856 strncat(args, lttctl_path, args_left);
857 args_left = MAX_ARGS_LEN - strlen(args) - 1;
858
859 /* space */
860 strncat(args, " ", args_left);
861 args_left = MAX_ARGS_LEN - strlen(args) - 1;
862
863 /* name */
864 strncat(args, "-n ", args_left);
865 args_left = MAX_ARGS_LEN - strlen(args) - 1;
866 strncat(args, trace_name, args_left);
867 args_left = MAX_ARGS_LEN - strlen(args) - 1;
868
869 /* space */
870 strncat(args, " ", args_left);
871 args_left = MAX_ARGS_LEN - strlen(args) - 1;
872
873 /* Simply pause tracing */
874 strncat(args, "-q", args_left);
875 args_left = MAX_ARGS_LEN - strlen(args) - 1;
876
877 int retval = execute_command(args, username, password, lttd_path, fac_path);
878 if(retval) {
879 gchar msg[256];
880 guint msg_left = 256;
881
882 strcpy(msg, "A problem occured when executing the su command : ");
883 msg_left = 256 - strlen(msg) - 1;
884 strncat(msg, strerror(retval), msg_left);
885 GtkWidget *dialogue =
886 gtk_message_dialog_new(
887 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
888 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
889 GTK_MESSAGE_ERROR,
890 GTK_BUTTONS_OK,
891 msg);
892 gtk_dialog_run(GTK_DIALOG(dialogue));
893 gtk_widget_destroy(dialogue);
894 }
895
896 }
897
898 void unpause_clicked (GtkButton *button, gpointer user_data)
899 {
900 ControlData *tcd = (ControlData*)user_data;
901
902 const gchar *username = gtk_entry_get_text(GTK_ENTRY(tcd->username_entry));
903 const gchar *password = gtk_entry_get_text(GTK_ENTRY(tcd->password_entry));
904 const gchar *trace_name =
905 gtk_entry_get_text(GTK_ENTRY(tcd->trace_name_entry));
906 const gchar *lttd_path = "";
907 const gchar *fac_path = "";
908
909 const gchar *lttctl_path =
910 gtk_entry_get_text(GTK_ENTRY(tcd->lttctl_path_entry));
911
912 /* Setup arguments to su */
913 /* child */
914 gchar args[MAX_ARGS_LEN];
915 gint args_left = MAX_ARGS_LEN - 1; /* for \0 */
916
917 args[0] = '\0';
918
919 /* Command */
920 strncat(args, "exec", args_left);
921 args_left = MAX_ARGS_LEN - strlen(args) - 1;
922
923 /* space */
924 strncat(args, " ", args_left);
925 args_left = MAX_ARGS_LEN - strlen(args) - 1;
926
927 if(strcmp(lttctl_path, "") == 0)
928 strncat(args, "lttctl", args_left);
929 else
930 strncat(args, lttctl_path, args_left);
931 args_left = MAX_ARGS_LEN - strlen(args) - 1;
932
933 /* space */
934 strncat(args, " ", args_left);
935 args_left = MAX_ARGS_LEN - strlen(args) - 1;
936
937 /* name */
938 strncat(args, "-n ", args_left);
939 args_left = MAX_ARGS_LEN - strlen(args) - 1;
940 strncat(args, trace_name, args_left);
941 args_left = MAX_ARGS_LEN - strlen(args) - 1;
942
943 /* space */
944 strncat(args, " ", args_left);
945 args_left = MAX_ARGS_LEN - strlen(args) - 1;
946
947 /* Simply unpause tracing */
948 strncat(args, "-s", args_left);
949 args_left = MAX_ARGS_LEN - strlen(args) - 1;
950
951 int retval = execute_command(args, username, password, lttd_path, fac_path);
952 if(retval) {
953 gchar msg[256];
954 guint msg_left = 256;
955
956 strcpy(msg, "A problem occured when executing the su command : ");
957 msg_left = 256 - strlen(msg) - 1;
958 strncat(msg, strerror(retval), msg_left);
959 GtkWidget *dialogue =
960 gtk_message_dialog_new(
961 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
962 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
963 GTK_MESSAGE_ERROR,
964 GTK_BUTTONS_OK,
965 msg);
966 gtk_dialog_run(GTK_DIALOG(dialogue));
967 gtk_widget_destroy(dialogue);
968 }
969
970 }
971
972 void stop_clicked (GtkButton *button, gpointer user_data)
973 {
974 ControlData *tcd = (ControlData*)user_data;
975
976 const gchar *username = gtk_entry_get_text(GTK_ENTRY(tcd->username_entry));
977 const gchar *password = gtk_entry_get_text(GTK_ENTRY(tcd->password_entry));
978 const gchar *trace_name =
979 gtk_entry_get_text(GTK_ENTRY(tcd->trace_name_entry));
980 const gchar *lttd_path = "";
981 const gchar *fac_path = "";
982
983 const gchar *lttctl_path =
984 gtk_entry_get_text(GTK_ENTRY(tcd->lttctl_path_entry));
985 const gchar *trace_dir = gtk_entry_get_text(GTK_ENTRY(tcd->trace_dir_entry));
986
987 /* Setup arguments to su */
988 /* child */
989 gchar args[MAX_ARGS_LEN];
990 gint args_left = MAX_ARGS_LEN - 1; /* for \0 */
991
992 args[0] = '\0';
993
994 /* Command */
995 strncat(args, "exec", args_left);
996 args_left = MAX_ARGS_LEN - strlen(args) - 1;
997
998 /* space */
999 strncat(args, " ", args_left);
1000 args_left = MAX_ARGS_LEN - strlen(args) - 1;
1001
1002 if(strcmp(lttctl_path, "") == 0)
1003 strncat(args, "lttctl", args_left);
1004 else
1005 strncat(args, lttctl_path, args_left);
1006 args_left = MAX_ARGS_LEN - strlen(args) - 1;
1007
1008 /* space */
1009 strncat(args, " ", args_left);
1010 args_left = MAX_ARGS_LEN - strlen(args) - 1;
1011
1012 /* name */
1013 strncat(args, "-n ", args_left);
1014 args_left = MAX_ARGS_LEN - strlen(args) - 1;
1015 strncat(args, trace_name, args_left);
1016 args_left = MAX_ARGS_LEN - strlen(args) - 1;
1017
1018 /* space */
1019 strncat(args, " ", args_left);
1020 args_left = MAX_ARGS_LEN - strlen(args) - 1;
1021
1022 /* Simply stop tracing and destroy channel */
1023 strncat(args, "-R", args_left);
1024 args_left = MAX_ARGS_LEN - strlen(args) - 1;
1025
1026 int retval = execute_command(args, username, password, lttd_path, fac_path);
1027 if(retval) {
1028 gchar msg[256];
1029 guint msg_left = 256;
1030
1031 strcpy(msg, "A problem occured when executing the su command : ");
1032 msg_left = 256 - strlen(msg) - 1;
1033 strncat(msg, strerror(retval), msg_left);
1034 GtkWidget *dialogue =
1035 gtk_message_dialog_new(
1036 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1037 GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
1038 GTK_MESSAGE_ERROR,
1039 GTK_BUTTONS_OK,
1040 msg);
1041 gtk_dialog_run(GTK_DIALOG(dialogue));
1042 gtk_widget_destroy(dialogue);
1043 return;
1044 }
1045
1046
1047 /* Ask to the user if he wants to open the trace in a new window */
1048 GtkWidget *dialogue;
1049 GtkWidget *label;
1050 gint id;
1051
1052 dialogue = gtk_dialog_new_with_buttons("Open trace ?",
1053 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1054 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1055 GTK_STOCK_YES,GTK_RESPONSE_ACCEPT,
1056 GTK_STOCK_NO,GTK_RESPONSE_REJECT,
1057 NULL);
1058 label = gtk_label_new("Do you want to open the trace in LTTV ?");
1059 gtk_widget_show(label);
1060
1061 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialogue)->vbox),
1062 label);
1063
1064 id = gtk_dialog_run(GTK_DIALOG(dialogue));
1065
1066 switch(id){
1067 case GTK_RESPONSE_ACCEPT:
1068 {
1069 create_main_window_with_trace(trace_dir);
1070 }
1071 break;
1072 case GTK_RESPONSE_REJECT:
1073 default:
1074 break;
1075 }
1076 gtk_widget_destroy(dialogue);
1077
1078 }
1079
1080
1081 /**
1082 * @fn GtkWidget* h_guicontrol(Tab*)
1083 *
1084 * Control Module's constructor hook
1085 *
1086 * This constructor is given as a parameter to the menuitem and toolbar button
1087 * registration. It creates the list.
1088 * @param tab A pointer to the parent window.
1089 * @return The widget created.
1090 */
1091 GtkWidget *
1092 h_guicontrol(Tab *tab)
1093 {
1094 ControlData* f = gui_control(tab) ;
1095
1096 return NULL;
1097 }
1098
1099 /**
1100 * @fn static void init()
1101 *
1102 * This function initializes the Filter Viewer functionnality through the
1103 * gtkTraceSet API.
1104 */
1105 static void init() {
1106
1107 lttvwindow_register_constructor("guicontrol",
1108 "/",
1109 "Insert Tracing Control Module",
1110 hTraceControlInsert_xpm,
1111 "Insert Tracing Control Module",
1112 h_guicontrol);
1113 }
1114
1115 /**
1116 * @fn void control_destroy_walk(gpointer,gpointer)
1117 *
1118 * Initiate the destruction of the current gui module
1119 * on the GTK Interface
1120 */
1121 void
1122 control_destroy_walk(gpointer data, gpointer user_data)
1123 {
1124 ControlData *tcd = (ControlData*)data;
1125
1126 g_debug("traceontrol.c : control_destroy_walk, %p", tcd);
1127
1128 /* May already have been done by GTK window closing */
1129 if(GTK_IS_WIDGET(guicontrol_get_widget(tcd)))
1130 gtk_widget_destroy(guicontrol_get_widget(tcd));
1131 }
1132
1133 /**
1134 * @fn static void destroy()
1135 * @brief plugin's destroy function
1136 *
1137 * This function releases the memory reserved by the module and unregisters
1138 * everything that has been registered in the gtkTraceSet API.
1139 */
1140 static void destroy() {
1141
1142 g_slist_foreach(g_control_list, control_destroy_walk, NULL );
1143
1144 lttvwindow_unregister_constructor(h_guicontrol);
1145
1146 }
1147
1148
1149 LTTV_MODULE("guitracecontrol", "Trace Control Window", \
1150 "Graphical module that let user control kernel tracing", \
1151 init, destroy, "lttvwindow")
1152
This page took 0.0576 seconds and 4 git commands to generate.