1 |
#!/usr/bin/perl |
2 |
|
3 |
# Drak Bug Report |
4 |
# Copyright (C) 2002-2008 Mandriva (daouda at mandriva dot com) |
5 |
# Stew Benedict (sbenedict at mandriva dot com) |
6 |
# |
7 |
# This program is free software; you can redistribute it and/or modify |
8 |
# it under the terms of the GNU General Public License as published by |
9 |
# the Free Software Foundation; either version 2, or (at your option) |
10 |
# any later version. |
11 |
# |
12 |
# This program is distributed in the hope that it will be useful, |
13 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
# GNU General Public License for more details. |
16 |
# |
17 |
# You should have received a copy of the GNU General Public License |
18 |
# along with this program; if not, write to the Free Software |
19 |
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
20 |
|
21 |
use strict; |
22 |
use diagnostics; |
23 |
use lib qw(/usr/lib/libDrakX); |
24 |
use any; |
25 |
use standalone; |
26 |
use MDK::Common; |
27 |
use common; |
28 |
BEGIN { $::no_ugtk_init = 1 } |
29 |
use mygtk2 qw(gtknew); |
30 |
use ugtk2 qw(:all); |
31 |
use Config; |
32 |
use URI::Escape; |
33 |
use run_program; |
34 |
|
35 |
my $prog; |
36 |
my $incident = 0; |
37 |
my ($table, $comb_app, $com_app, $button_pkg, $button_browse, $package, $distrocode, $error, $gdb_trace, $user_descr); |
38 |
|
39 |
my $i; |
40 |
foreach (@ARGV) { |
41 |
next unless defined $_; |
42 |
$i++; |
43 |
/^--error$/ and do { $error = splice(@ARGV, $i, 1) }; |
44 |
/^--report$/ and $prog = splice(@ARGV, $i, 1); |
45 |
/^--incident$/ and do { $incident = 1; $prog = splice(@ARGV, $i, 1) }; |
46 |
} |
47 |
|
48 |
my $segfaulted = $error =~ /SEGV/; |
49 |
if ($segfaulted && -x '/usr/bin/gdb') { |
50 |
local $ENV{TMP} = $ENV{TMP} || '/tmp'; |
51 |
my $file = chomp_(`mktemp $ENV{TMP}/drakbug.XXXXXXXX`); |
52 |
my $_guard = before_leaving { rm_rf $file }; |
53 |
if (-e $file) { |
54 |
output($file, qq(bt |
55 |
quit)); |
56 |
local $ENV{LANGUAGE} = 'C'; |
57 |
my $temp = run_program::get_stdout('gdb', '-q', 'perl', $$, '-x', $file); |
58 |
$gdb_trace = join "\n", grep { !/^done\.$/ && !/Reading symbols from/ |
59 |
&& !/Loaded symbols/ && !/The program is run/ } split(/\n/, $temp); |
60 |
} |
61 |
} |
62 |
if (!check_for_xserver()) { |
63 |
print("Cannot be run in console mode.\n"); |
64 |
print join("\n", |
65 |
N("The \"%s\" program has crashed with the following error:", $prog), |
66 |
$error, |
67 |
$gdb_trace, |
68 |
'') |
69 |
if $error; |
70 |
c::_exit(0); |
71 |
} |
72 |
|
73 |
mygtk2::init(); |
74 |
|
75 |
$ugtk2::wm_icon = 'drakbug-16'; |
76 |
my $window = ugtk2->new(N("%s Bug Report Tool"), center => 1); |
77 |
$window->{rwindow}->set_border_width(5); |
78 |
$window->{window}->signal_connect("delete_event", sub { ugtk2->exit(0) }); |
79 |
|
80 |
my $mdk_app = { |
81 |
N("%s Control Center") => 'drakconf', |
82 |
N("First Time Wizard") => 'drakfw', |
83 |
N("Synchronization tool") => 'draksync', |
84 |
N("Standalone Tools") => 'drakxtools', |
85 |
"harddrake" => 'harddrake2', |
86 |
N("%s Online") => 'mdkonline', |
87 |
N("%s Online") => 'mdkapplet', |
88 |
N("Remote Control") => 'rfbdrake', |
89 |
N("Software Manager") => 'rpmdrake', |
90 |
N("Windows Migration tool") => 'transfugdrake', |
91 |
N("Configuration Wizards") => 'wizdrake', |
92 |
}; |
93 |
|
94 |
my @generic_tool = keys %$mdk_app; |
95 |
my @all_drakxtools = qw(adduserdrake diskdrake drakautoinst drakboot drakbug drakclock drakfloppy drakfont draksec drakxservices drakxtools drakxtv logdrake scannerdrake); |
96 |
push @generic_tool, @all_drakxtools, qw(MageiaUpdate drakbackup drakconnect drakfirewall drakhosts drakmenustyle draknfs draksambashare drakgw drakroam drakvpn keyboarddrake msec mousedrake net_monitor urpmi userdrake XFdrake); |
97 |
|
98 |
my $kernel_release = chomp_(`uname -r`); |
99 |
my $mageia_release = chomp_(cat_('/etc/release')); |
100 |
#- unused for now |
101 |
#- (my $mageia_version) = $mageia_release =~ /(\d+\.\d+)/; |
102 |
|
103 |
if ($mageia_release =~ /(official|community)/i) { |
104 |
$distrocode = $mageia_release; |
105 |
$distrocode =~ s/^.*?(\d+\.\d+) \((\w+)\).*$/$1-\l$2/; |
106 |
} else { |
107 |
$distrocode = "cooker"; |
108 |
} |
109 |
my $bugzilla_url = 'http://bugs.mageia.org/enter_bug.cgi'; |
110 |
my $wizard_name = "Bugzilla"; |
111 |
|
112 |
$table = create_packtable({ col_spacings => 5, row_spacings => 10 }, |
113 |
[ gtknew('Label_Left', text => N("Select %s Tool:")), $comb_app = Gtk2::ComboBox->new_text, $comb_app->set_wrap_width(3) ], |
114 |
[ gtknew('Label_Left', text => N("or Application Name\n(or Full Path):")), |
115 |
gtkpack_(Gtk2::HBox->new(0, 5), |
116 |
1, $com_app = gtkset_editable(Gtk2::Entry->new, 1), |
117 |
0, $button_pkg = Gtk2::Button->new(N("Find Package")), |
118 |
0, $button_browse = Gtk2::FileChooserButton->new(N("Browse"), 'GTK_FILE_CHOOSER_ACTION_OPEN'), |
119 |
) ], |
120 |
[ gtknew('Label_Left', text => N("Package: ")), $package = Gtk2::Entry->new_with_text("...") ], # complain on gtk-perl@ml |
121 |
[ gtknew('Label_Left', text => N("Kernel:")), gtkset_editable(Gtk2::Entry->new_with_text($kernel_release), 0) ] |
122 |
); |
123 |
$comb_app->set_popdown_strings("", uniq(sort(@generic_tool), if_($prog, $prog))); |
124 |
$comb_app->set_text(""); |
125 |
|
126 |
sub is_a_boot_issue() { |
127 |
$prog =~ /boot|mkinitrd/; |
128 |
} |
129 |
|
130 |
sub format_trace_with_message { |
131 |
my ($message, $trace) = @_; |
132 |
([ $message ], [ "\n\n " . join("\n ", split("\n", $trace)) . "\n\n", { family => 'monospace' }]); |
133 |
} |
134 |
|
135 |
my @commands = 'lspcidrake -v'; |
136 |
|
137 |
push @commands, 'blkid' if is_a_boot_issue(); |
138 |
|
139 |
my $parent_uid = get_parent_uid(); |
140 |
|
141 |
my $width = 600; |
142 |
gtkadd($window->{window}, |
143 |
gtkpack_(Gtk2::VBox->new(0, 5), |
144 |
0, gtknew('Title1', label => $mageia_release, width => $width), |
145 |
1, create_scrolled_window( |
146 |
gtknew('TextView', editable => 0, height => 150, |
147 |
text => [ |
148 |
if_($prog, |
149 |
if_($error, |
150 |
format_trace_with_message( |
151 |
($gdb_trace ? |
152 |
N("The \"%s\" program has segfaulted with the following error:", $prog) |
153 |
: N("The \"%s\" program has crashed with the following error:", $prog)), |
154 |
$error) |
155 |
), |
156 |
if_($gdb_trace, format_trace_with_message(N("Its GDB trace is:"), $gdb_trace)), |
157 |
), |
158 |
[ |
159 |
N("To submit a bug report, click on the report button. \nThis will open a web browser window on %s where you'll find a form to fill in. The information displayed above will be transferred to that server", |
160 |
$wizard_name). "\n" . |
161 |
P("It would be very useful to attach to your report the output of the following command: %s.", |
162 |
"Things useful to attach to your report are the output of the following commands: %s.", |
163 |
scalar(@commands), |
164 |
join(", ", map { N("'%s'", $_) } @commands)) . |
165 |
if_(is_a_boot_issue(), |
166 |
"\n" . |
167 |
N("You should also attach the following files: %s as well as %s.", |
168 |
'/etc/modprobe.conf, /etc/fstab, /boot/grub/menu.lst, /boot/grub/devices.map', |
169 |
'/etc/lilo.conf', |
170 |
) |
171 |
) |
172 |
] |
173 |
])), |
174 |
0, gtknew('Title2', label => N("Please describe what you were doing when it crashed:"), width => $width), |
175 |
if_($incident, |
176 |
1, create_scrolled_window( |
177 |
$user_descr = gtknew('TextView', editable => 1, height => 200) |
178 |
), |
179 |
), |
180 |
if_(!$error, |
181 |
0, gtkadd($table), |
182 |
), |
183 |
0, gtkpack(Gtk2::HSeparator->new), |
184 |
0, gtkpack(create_hbox('edge'), |
185 |
gtksignal_connect( |
186 |
Gtk2::Button->new(N("Help")), clicked => sub { |
187 |
run_program::raw({ detach => 1, setuid => $parent_uid }, 'drakhelp', '--id', 'drakbug'); |
188 |
}), |
189 |
gtkpack(create_hbox('end'), |
190 |
gtksignal_connect(Gtk2::Button->new(N("Report")), clicked => \&report_bug_to_bugzilla), |
191 |
gtksignal_connect(Gtk2::Button->new(N("Close")), clicked => sub { ugtk2->exit(0) }), |
192 |
)))); |
193 |
|
194 |
if (defined $prog) { |
195 |
update_app($prog); |
196 |
$comb_app->set_text($prog); |
197 |
} |
198 |
$comb_app->entry->signal_connect('changed', sub { |
199 |
my $text = $comb_app->entry->get_text; |
200 |
$text and update_app($text); |
201 |
}); |
202 |
|
203 |
$button_pkg->signal_connect('clicked', sub { |
204 |
$comb_app->set_text(""); |
205 |
my $pkg_name = get_package($com_app->get_text); |
206 |
$package->set_text($pkg_name); |
207 |
}); |
208 |
|
209 |
$button_browse->signal_connect('file-set', sub { $com_app->set_text($button_browse->get_filename()) }); |
210 |
|
211 |
$window->{window}->show_all; |
212 |
$window->main; |
213 |
ugtk2->exit(0); |
214 |
|
215 |
sub update_app { |
216 |
my ($text) = @_; |
217 |
my $app_choice; |
218 |
$ENV{PATH} = "/sbin:/usr/sbin:$ENV{PATH}"; |
219 |
if (member($text, @all_drakxtools) || $text eq N("Standalone Tools")) { |
220 |
$app_choice = chomp_(`rpm -q drakxtools`); |
221 |
} elsif (exists($mdk_app->{$text})) { |
222 |
$app_choice = get_package($mdk_app->{$text}); |
223 |
} else { |
224 |
$app_choice = get_package($text); |
225 |
} |
226 |
$app_choice ? $package->set_text($app_choice) : $package->set_text(N("Not installed")); |
227 |
} |
228 |
|
229 |
my %packages; |
230 |
|
231 |
sub get_package { |
232 |
my ($executable) = @_; |
233 |
my ($rpm_package, $which_app); |
234 |
$rpm_package = $packages{$executable}; |
235 |
if (!defined $rpm_package) { |
236 |
local $ENV{PATH} = "$ENV{PATH}:/sbin:/usr/sbin"; |
237 |
$which_app = chomp_(`which '$executable' 2> /dev/null`); |
238 |
# deush, rpm can takes some time aka it'll sleeps if something has opened rpm db ! |
239 |
$rpm_package = $which_app eq "" ? N("Package not installed") : common::to_utf8(chomp_(`rpm -qf '$which_app' 2>&1`)); |
240 |
$packages{$executable} = $rpm_package; |
241 |
} |
242 |
$rpm_package; |
243 |
} |
244 |
|
245 |
sub get_top_of_trace { |
246 |
my ($error) = @_; |
247 |
return if !$error; |
248 |
sprintf(" (%s)", first(split(/\n/, $error))); |
249 |
} |
250 |
|
251 |
sub report_bug_to_bugzilla() { |
252 |
my $p = $package->get_text; |
253 |
my ($product, $version) = $p =~ /^(.*)-([^-]+-[^-]+(mga.*))$/; # FIXME: fragile! |
254 |
my $app = $comb_app->entry->get_text; |
255 |
my $_component = $app ? |
256 |
if_(member($app, @all_drakxtools), $app) || $mdk_app->{$app} : |
257 |
$product; |
258 |
my $text; |
259 |
if ($incident) { |
260 |
my $buffer = $user_descr->get_buffer; |
261 |
$text = $buffer->get_text($buffer->get_start_iter, $buffer->get_end_iter, 0); |
262 |
if (!$text) { |
263 |
err_dialog(N("Warning"), |
264 |
N("You must type in what you were doing when this bug happened in order to enable us to reproduce this bug and to increase the odds of fixing it") |
265 |
. "\n\n" . N("Thanks.")); |
266 |
return; |
267 |
} |
268 |
} |
269 |
my $rel_data = mageia_release_info(); |
270 |
my $rel = standalone::real_version(); |
271 |
my $cpuinfo; |
272 |
if (cat_('/proc/cpuinfo') =~ /model name\s*:\s*(.*)$/m) { |
273 |
$cpuinfo = $1; |
274 |
} |
275 |
my $arch = arch(); |
276 |
$arch = 'i586' if arch =~ /^i.86/; |
277 |
my $options = join('&', |
278 |
($product || $version ? 'cf_rpmpkg=' . join('-', $product, $version) : ()), |
279 |
'version=' . ($rel_data->{branch} eq 'Devel' ? 'Cauldron' : $rel_data->{version}), |
280 |
'component=Core%20Packages', |
281 |
'product=Mageia', |
282 |
"rep_platform=$arch", |
283 |
if_($incident, |
284 |
join('', "short_desc=$prog%20", |
285 |
($segfaulted ? 'segfaulted' : 'crashed'), |
286 |
if_(!$gdb_trace, get_top_of_trace($error)), |
287 |
), |
288 |
), |
289 |
'comment=' . uri_escape( |
290 |
if_($incident, |
291 |
qq(The "$prog" program crashed. Drakbug-$rel caught it. |
292 |
|
293 |
) . ($text || "Please describe what you were doing when it crashed.") . "\n\n" |
294 |
. ($error ? qq(Backtrace was: |
295 |
$error) : |
296 |
qq(If you can, try to run the "$prog" program from a terminal and copy and paste here any error messages and/or backtrace)) |
297 |
. if_($gdb_trace, qq( |
298 |
GDB backtrace was (its interesting part is below Perl_pp_fork() or Perl_pp_waitpid()): |
299 |
$gdb_trace)), |
300 |
) |
301 |
. qq( |
302 |
Kernel version = $kernel_release |
303 |
Distribution=) . cat_('/etc/release') |
304 |
. if_($cpuinfo, "CPU=$cpuinfo") |
305 |
), |
306 |
); |
307 |
print($bugzilla_url . "?" . $options . "\n"); |
308 |
run_program::raw({ detach => 1, setuid => $parent_uid }, '/usr/bin/www-browser', "$bugzilla_url?$options"); |
309 |
} |
310 |
|