]> sourceware.org Git - systemtap.git/blob - main.cxx
Improve the way a script is read from standard input.
[systemtap.git] / main.cxx
1 // systemtap translator/driver
2 // Copyright (C) 2005-2016 Red Hat Inc.
3 // Copyright (C) 2005 IBM Corp.
4 // Copyright (C) 2006 Intel Corporation.
5 //
6 // This file is part of systemtap, and is free software. You can
7 // redistribute it and/or modify it under the terms of the GNU General
8 // Public License (GPL); either version 2, or (at your option) any
9 // later version.
10
11 #include "config.h"
12 #include "staptree.h"
13 #include "parse.h"
14 #include "elaborate.h"
15 #include "translate.h"
16 #include "buildrun.h"
17 #include "session.h"
18 #include "hash.h"
19 #include "cache.h"
20 #include "util.h"
21 #include "coveragedb.h"
22 #include "rpm_finder.h"
23 #include "task_finder.h"
24 #include "csclient.h"
25 #include "client-nss.h"
26 #include "remote.h"
27 #include "tapsets.h"
28 #include "setupdwfl.h"
29 #ifdef HAVE_LIBREADLINE
30 #include "interactive.h"
31 #endif
32 #include "bpf.h"
33
34 #if ENABLE_NLS
35 #include <libintl.h>
36 #include <locale.h>
37 #endif
38
39 #include "stap-probe.h"
40
41 #include <cstdlib>
42 #include <thread>
43 #include <algorithm>
44
45 extern "C" {
46 #include <glob.h>
47 #include <unistd.h>
48 #include <signal.h>
49 #include <sys/utsname.h>
50 #include <sys/times.h>
51 #include <sys/time.h>
52 #include <sys/stat.h>
53 #include <time.h>
54 #include <unistd.h>
55 #include <wordexp.h>
56 #include <ftw.h>
57 }
58
59 using namespace std;
60
61 static void
62 uniq_list(list<string>& l)
63 {
64 set<string> s;
65 list<string>::iterator i = l.begin();
66 while (i != l.end())
67 if (s.insert(*i).second)
68 ++i;
69 else
70 i = l.erase(i);
71 }
72
73 static void
74 printscript(systemtap_session& s, ostream& o)
75 {
76 if (s.dump_mode == systemtap_session::dump_matched_probes ||
77 s.dump_mode == systemtap_session::dump_matched_probes_vars)
78 {
79 // We go through some heroic measures to produce clean output.
80 // Record the alias and probe pointer as <name, set<derived_probe *> >
81 map<string,set<derived_probe *> > probe_list;
82
83 // Pre-process the probe alias
84 for (unsigned i=0; i<s.probes.size(); i++)
85 {
86 assert_no_interrupts();
87
88 derived_probe* p = s.probes[i];
89 vector<probe*> chain;
90 p->collect_derivation_chain (chain);
91
92 if (s.verbose > 2) {
93 p->printsig(cerr); cerr << endl;
94 cerr << "chain[" << chain.size() << "]:" << endl;
95 for (unsigned j=0; j<chain.size(); j++)
96 {
97 cerr << " [" << j << "]: " << endl;
98 cerr << "\tlocations[" << chain[j]->locations.size() << "]:" << endl;
99 for (unsigned k=0; k<chain[j]->locations.size(); k++)
100 {
101 cerr << "\t [" << k << "]: ";
102 chain[j]->locations[k]->print(cerr);
103 cerr << endl;
104 }
105 const probe_alias *a = chain[j]->get_alias();
106 if (a)
107 {
108 cerr << "\taliases[" << a->alias_names.size() << "]:" << endl;
109 for (unsigned k=0; k<a->alias_names.size(); k++)
110 {
111 cerr << "\t [" << k << "]: ";
112 a->alias_names[k]->print(cerr);
113 cerr << endl;
114 }
115 }
116 }
117 }
118
119 const string& pp = lex_cast(*p->script_location());
120
121 // PR16730: We should only list probes that can be traced back to the
122 // user's spec, not any auxiliary probes in the tapsets.
123 // Also, do not want to the probes that are from the additional
124 // scripts (-E SCRIPT) to be listed.
125 if (!s.is_primary_probe(p))
126 continue;
127
128 // Now duplicate-eliminate. An alias may have expanded to
129 // several actual derived probe points, but we only want to
130 // print the alias head name once.
131 probe_list[pp].insert(p);
132 }
133
134 // print probe name and variables if there
135 for (map<string, set<derived_probe *> >::iterator it=probe_list.begin(); it!=probe_list.end(); ++it)
136 {
137 // probe name or alias
138 if (s.dump_mode == systemtap_session::dump_matched_probes_vars && isatty(STDOUT_FILENO))
139 o << s.colorize(it->first, "source");
140 else
141 o << it->first;
142
143 // Print the locals and arguments for -L mode only
144 if (s.dump_mode == systemtap_session::dump_matched_probes_vars)
145 {
146 map<string,unsigned> var_count; // format <"name:type",count>
147 map<string,unsigned> arg_count;
148 list<string> var_list;
149 list<string> arg_list;
150 // traverse set<derived_probe *> to collect all locals and arguments
151 for (set<derived_probe *>::iterator ix=it->second.begin(); ix!=it->second.end(); ++ix)
152 {
153 derived_probe* p = *ix;
154 // collect available locals of the probe
155 for (unsigned j=0; j<p->locals.size(); j++)
156 {
157 stringstream tmps;
158 vardecl* v = p->locals[j];
159 v->printsig (tmps);
160 var_count[tmps.str()]++;
161 var_list.push_back(tmps.str());
162 }
163 // collect arguments of the probe if there
164 list<string> arg_set;
165 p->getargs(arg_set);
166 for (list<string>::iterator ia=arg_set.begin(); ia!=arg_set.end(); ++ia) {
167 arg_count[*ia]++;
168 arg_list.push_back(*ia);
169 }
170 }
171
172 uniq_list(arg_list);
173 uniq_list(var_list);
174
175 // print the set-intersection only
176 for (list<string>::iterator ir=var_list.begin(); ir!=var_list.end(); ++ir)
177 if (var_count.find(*ir)->second == it->second.size()) // print locals
178 o << " " << *ir;
179 for (list<string>::iterator ir=arg_list.begin(); ir!=arg_list.end(); ++ir)
180 if (arg_count.find(*ir)->second == it->second.size()) // print arguments
181 o << " " << *ir;
182 }
183 o << endl;
184 }
185 }
186 else
187 {
188 if (s.embeds.size() > 0)
189 o << _("# global embedded code") << endl;
190 for (unsigned i=0; i<s.embeds.size(); i++)
191 {
192 assert_no_interrupts();
193 embeddedcode* ec = s.embeds[i];
194 ec->print (o);
195 o << endl;
196 }
197
198 if (s.globals.size() > 0)
199 o << _("# globals") << endl;
200 for (unsigned i=0; i<s.globals.size(); i++)
201 {
202 assert_no_interrupts();
203 vardecl* v = s.globals[i];
204 v->printsig (o);
205 if (s.verbose && v->init)
206 {
207 o << " = ";
208 v->init->print(o);
209 }
210 o << endl;
211 }
212
213 if (s.functions.size() > 0)
214 o << _("# functions") << endl;
215 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
216 {
217 assert_no_interrupts();
218 functiondecl* f = it->second;
219 f->printsig (o);
220 o << endl;
221 if (f->locals.size() > 0)
222 o << _(" # locals") << endl;
223 for (unsigned j=0; j<f->locals.size(); j++)
224 {
225 vardecl* v = f->locals[j];
226 o << " ";
227 v->printsig (o);
228 o << endl;
229 }
230 if (s.verbose)
231 {
232 f->body->print (o);
233 o << endl;
234 }
235 }
236
237 if (s.probes.size() > 0)
238 o << _("# probes") << endl;
239 for (unsigned i=0; i<s.probes.size(); i++)
240 {
241 assert_no_interrupts();
242 derived_probe* p = s.probes[i];
243 p->printsig (o);
244 o << endl;
245 if (p->locals.size() > 0)
246 o << _(" # locals") << endl;
247 for (unsigned j=0; j<p->locals.size(); j++)
248 {
249 vardecl* v = p->locals[j];
250 o << " ";
251 v->printsig (o);
252 o << endl;
253 }
254 if (s.verbose)
255 {
256 p->body->print (o);
257 o << endl;
258 }
259 }
260 }
261 }
262
263
264 int pending_interrupts;
265
266 extern "C"
267 void handle_interrupt (int)
268 {
269 // This might be nice, but we don't know our current verbosity...
270 // clog << _F("Received signal %d", sig) << endl << flush;
271 kill_stap_spawn(SIGTERM);
272
273 pending_interrupts ++;
274 // Absorb the first two signals. This used to be one, but when
275 // stap is run under sudo, and then interrupted, sudo relays a
276 // redundant copy of the signal to stap, leading to an unclean shutdown.
277 if (pending_interrupts > 2) // XXX: should be configurable? time-based?
278 {
279 char msg[] = "Too many interrupts received, exiting.\n";
280 int rc = write (2, msg, sizeof(msg)-1);
281 if (rc) {/* Do nothing; we don't care if our last gasp went out. */ ;}
282 _exit (1);
283 }
284 }
285
286
287 void
288 setup_signals (sighandler_t handler)
289 {
290 struct sigaction sa;
291
292 memset(&sa, 0, sizeof(sa));
293 sa.sa_handler = handler;
294 sigemptyset (&sa.sa_mask);
295 if (handler != SIG_IGN)
296 {
297 sigaddset (&sa.sa_mask, SIGHUP);
298 sigaddset (&sa.sa_mask, SIGPIPE);
299 sigaddset (&sa.sa_mask, SIGINT);
300 sigaddset (&sa.sa_mask, SIGTERM);
301 sigaddset (&sa.sa_mask, SIGXFSZ);
302 sigaddset (&sa.sa_mask, SIGXCPU);
303 }
304 sa.sa_flags = SA_RESTART;
305
306 sigaction (SIGHUP, &sa, NULL);
307 sigaction (SIGPIPE, &sa, NULL);
308 sigaction (SIGINT, &sa, NULL);
309 sigaction (SIGTERM, &sa, NULL);
310 sigaction (SIGXFSZ, &sa, NULL);
311 sigaction (SIGXCPU, &sa, NULL);
312 }
313
314
315 static void
316 sdt_benchmark_thread(unsigned long i)
317 {
318 PROBE(stap, benchmark__thread__start);
319 while (i--)
320 PROBE1(stap, benchmark, i);
321 PROBE(stap, benchmark__thread__end);
322 }
323
324
325 static int
326 run_sdt_benchmark(systemtap_session& s)
327 {
328 unsigned long loops = s.benchmark_sdt_loops ?: 10000000;
329 unsigned long threads = s.benchmark_sdt_threads ?: 1;
330
331 if (s.verbose > 0)
332 clog << _F("Beginning SDT benchmark with %lu loops in %lu threads.",
333 loops, threads) << endl;
334
335 struct tms tms_before, tms_after;
336 struct timeval tv_before, tv_after;
337 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
338 times (& tms_before);
339 gettimeofday (&tv_before, NULL);
340
341 PROBE(stap, benchmark__start);
342 {
343 vector<thread> handles;
344 for (unsigned long i = 0; i < threads; ++i)
345 handles.push_back(thread(sdt_benchmark_thread, loops));
346 for (unsigned long i = 0; i < threads; ++i)
347 handles[i].join();
348 }
349 PROBE(stap, benchmark__end);
350
351 times (& tms_after);
352 gettimeofday (&tv_after, NULL);
353 if (s.verbose > 0)
354 clog << _F("Completed SDT benchmark in %ldusr/%ldsys/%ldreal ms.",
355 (long)(tms_after.tms_utime - tms_before.tms_utime) * 1000 / _sc_clk_tck,
356 (long)(tms_after.tms_stime - tms_before.tms_stime) * 1000 / _sc_clk_tck,
357 (long)((tv_after.tv_sec - tv_before.tv_sec) * 1000 +
358 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000))
359 << endl;
360
361 return EXIT_SUCCESS;
362 }
363
364 static set<string> files;
365 static string path_dir;
366
367 static int collect_stp(const char* fpath, const struct stat*,
368 int typeflag, struct FTW* ftwbuf)
369 {
370 if (typeflag == FTW_F)
371 {
372 const char* ext = strrchr(fpath, '.');
373 if (ext && (strcmp(".stp", ext) == 0))
374 files.insert(fpath);
375 }
376 else if (typeflag == FTW_D && ftwbuf->level > 0)
377 {
378 // Only recurse for PATH root directory
379 if (strncmp(path_dir.c_str(), fpath, path_dir.size()) != 0 ||
380 (fpath[path_dir.size()] != '/' && fpath[path_dir.size()] != '\0'))
381 return FTW_SKIP_SUBTREE;
382 }
383 return FTW_CONTINUE;
384 }
385
386 static int collect_stpm(const char* fpath, const struct stat*,
387 int typeflag, struct FTW* ftwbuf)
388 {
389 if (typeflag == FTW_F)
390 {
391 const char* ext = strrchr(fpath, '.');
392 if (ext && (strcmp(".stpm", ext) == 0))
393 files.insert(fpath);
394 }
395 else if (typeflag == FTW_D && ftwbuf->level > 0)
396 {
397 // Only recurse for PATH root directory
398 if (strncmp(path_dir.c_str(), fpath, path_dir.size()) != 0 ||
399 (fpath[path_dir.size()] != '/' && fpath[path_dir.size()] != '\0'))
400 return FTW_SKIP_SUBTREE;
401 }
402 return FTW_CONTINUE;
403 }
404
405 #ifndef HAVE_LINUX_BPF_H
406 int
407 translate_bpf_pass (systemtap_session &)
408 {
409 return 1;
410 }
411 #endif
412
413 // Compilation passes 0 through 4
414 int
415 passes_0_4 (systemtap_session &s)
416 {
417 int rc = 0;
418
419 // If we don't know the release, there's no hope either locally or on a server.
420 if (s.kernel_release.empty())
421 {
422 if (s.kernel_build_tree.empty())
423 cerr << _("ERROR: kernel release isn't specified") << endl;
424 else
425 cerr << _F("ERROR: kernel release isn't found in \"%s\"",
426 s.kernel_build_tree.c_str()) << endl;
427 return 1;
428 }
429
430 // Perform passes 0 through 4 using a compile server?
431 if (! s.specified_servers.empty ())
432 {
433 #if NEED_BASE_CLIENT_CODE
434 compile_server_client client (s);
435 return client.passes_0_4 ();
436 #else
437 s.print_warning(_("Without NSS or HTTP client support, using a compile-server is not supported by this version of systemtap"));
438
439 // This cannot be an attempt to use a server after a local compile failed
440 // since --use-server-on-error is locked to 'no' if we don't have
441 // NSS.
442 assert (! s.try_server ());
443 s.print_warning(_("Ignoring --use-server"));
444 #endif
445 }
446
447 // PASS 0: setting up
448 s.verbose = s.perpass_verbose[0];
449 PROBE1(stap, pass0__start, &s);
450
451 // For PR1477, we used to override $PATH and $LC_ALL and other stuff
452 // here. We seem to use complete pathnames in
453 // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further,
454 // it interferes with util.cxx:find_executable(), used for $PATH
455 // resolution.
456
457 s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
458
459 // Update various paths to include the sysroot, if provided.
460 if (!s.sysroot.empty())
461 {
462 if (s.update_release_sysroot && !s.sysroot.empty())
463 s.kernel_build_tree = s.sysroot + s.kernel_build_tree;
464 debuginfo_path_insert_sysroot(s.sysroot);
465 }
466
467 // Now that no further changes to s.kernel_build_tree can occur, let's use it.
468 if (!s.runtime_usermode_p())
469 {
470 if ((rc = s.parse_kernel_config ()) != 0
471 || (rc = s.parse_kernel_exports ()) != 0
472 || (rc = s.parse_kernel_functions ()) != 0)
473 {
474 // Try again with a server
475 s.set_try_server ();
476 return rc;
477 }
478 }
479
480 // Create the name of the C source file within the temporary
481 // directory. Note the _src prefix, explained in
482 // buildrun.cxx:compile_pass()
483 s.translated_source = string(s.tmpdir) + "/" + s.module_name + "_src.c";
484
485 PROBE1(stap, pass0__end, &s);
486
487 struct tms tms_before;
488 times (& tms_before);
489 struct timeval tv_before;
490 gettimeofday (&tv_before, NULL);
491
492 // PASS 1a: PARSING LIBRARY SCRIPTS
493 PROBE1(stap, pass1a__start, &s);
494
495 // prep this array for tapset $n use too ... although we will reset once again for user scripts
496 s.used_args.resize(s.args.size(), false);
497
498 if (! s.pass_1a_complete)
499 {
500 // We need to handle the library scripts first because this pass
501 // gathers information on .stpm files that might be needed to
502 // parse the user script.
503
504 // We need to first ascertain the status of the user script, though.
505 struct stat user_file_stat;
506 int user_file_stat_rc = -1;
507
508 if (s.script_file == "-")
509 {
510 user_file_stat_rc = fstat (STDIN_FILENO, & user_file_stat);
511 }
512 else if (s.script_file != "")
513 {
514 user_file_stat_rc = stat (s.script_file.c_str(), & user_file_stat);
515 }
516 // otherwise, rc is 0 for a command line script
517
518 vector<string> version_suffixes;
519 if (!s.runtime_usermode_p())
520 {
521 // Construct kernel-versioning search path
522 string kvr = s.kernel_release;
523
524 // add full kernel-version-release (2.6.NN-FOOBAR)
525 version_suffixes.push_back ("/" + kvr);
526
527 // add kernel version (2.6.NN)
528 if (kvr != s.kernel_base_release)
529 {
530 kvr = s.kernel_base_release;
531 version_suffixes.push_back ("/" + kvr);
532 }
533
534 // add kernel family (2.6)
535 string::size_type dot1_index = kvr.find ('.');
536 string::size_type dot2_index = kvr.rfind ('.');
537 while (dot2_index > dot1_index && dot2_index != string::npos)
538 {
539 kvr.erase(dot2_index);
540 version_suffixes.push_back ("/" + kvr);
541 dot2_index = kvr.rfind ('.');
542 }
543 }
544
545 // add empty string as last element
546 version_suffixes.push_back ("");
547
548 // Add arch variants of every path, just before each
549 const string& arch = s.architecture;
550 for (unsigned i=0; i<version_suffixes.size(); i+=2)
551 version_suffixes.insert(version_suffixes.begin() + i,
552 version_suffixes[i] + "/" + arch);
553
554 // Add runtime variants of every path, before everything else
555 string runtime_prefix;
556 if (s.runtime_mode == systemtap_session::kernel_runtime)
557 runtime_prefix = "/linux";
558 else if (s.runtime_mode == systemtap_session::dyninst_runtime)
559 runtime_prefix = "/dyninst";
560 else if (s.runtime_mode == systemtap_session::bpf_runtime)
561 runtime_prefix = "/bpf";
562 if (!runtime_prefix.empty())
563 for (unsigned i=0; i<version_suffixes.size(); i+=2)
564 version_suffixes.insert(version_suffixes.begin() + i/2,
565 runtime_prefix + version_suffixes[i]);
566
567 // First, parse .stpm files on the include path. We need to have the
568 // resulting macro definitions available for parsing library files,
569 // but since .stpm files can consist only of '@define' constructs,
570 // we can parse each one without reference to the others.
571 set<pair<dev_t, ino_t> > seen_library_macro_files;
572 set<string> seen_library_macro_files_names;
573
574 for (unsigned i=0; i<s.include_path.size(); i++)
575 {
576 // now iterate upon it
577 for (unsigned k=0; k<version_suffixes.size(); k++)
578 {
579 int flags = FTW_ACTIONRETVAL;
580 string dir = s.include_path[i] + version_suffixes[k];
581 files.clear();
582 // we need to set this for the nftw() callback
583 path_dir = s.include_path[i] + "/PATH";
584 (void) nftw(dir.c_str(), collect_stpm, 1, flags);
585
586 unsigned prev_s_library_files = s.library_files.size();
587
588 for (auto it = files.begin(); it != files.end(); ++it)
589 {
590 assert_no_interrupts();
591
592 struct stat tapset_file_stat;
593 int stat_rc = stat (it->c_str(), & tapset_file_stat);
594 if (stat_rc == 0 && user_file_stat_rc == 0 &&
595 user_file_stat.st_dev == tapset_file_stat.st_dev &&
596 user_file_stat.st_ino == tapset_file_stat.st_ino)
597 {
598 cerr
599 << _F("usage error: macro tapset file '%s' cannot be run directly as a session script.",
600 it->c_str()) << endl;
601 rc ++;
602 }
603
604 // PR11949: duplicate-eliminate tapset files
605 if (stat_rc == 0)
606 {
607 pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
608 tapset_file_stat.st_ino);
609 if (seen_library_macro_files.find(here) != seen_library_macro_files.end())
610 {
611 if (s.verbose>2)
612 clog << _F("Skipping tapset \"%s\", duplicate inode.", it->c_str()) << endl;
613 continue;
614 }
615 seen_library_macro_files.insert (here);
616 }
617
618 // PR12443: duplicate-eliminate harder
619 string full_path = *it;
620 string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too
621 if (full_path.size() > tapset_base.size())
622 {
623 string tail_part = full_path.substr(tapset_base.size());
624 if (seen_library_macro_files_names.find (tail_part) != seen_library_macro_files_names.end())
625 {
626 if (s.verbose>2)
627 clog << _F("Skipping tapset \"%s\", duplicate name.", it->c_str()) << endl;
628 continue;
629 }
630 seen_library_macro_files_names.insert (tail_part);
631 }
632
633 if (s.verbose>2)
634 clog << _F("Processing tapset \"%s\"", it->c_str()) << endl;
635
636 stapfile* f = parse_library_macros (s, *it);
637 if (f == 0)
638 s.print_warning(_F("macro tapset \"%s\" has errors, and will be skipped.", it->c_str()));
639 else
640 s.library_files.push_back (f);
641 }
642
643 unsigned next_s_library_files = s.library_files.size();
644 if (s.verbose>1 && !files.empty())
645 //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
646 clog << _F("Searched for library macro files: \"%s\", found: %zu, processed: %u",
647 dir.c_str(), files.size(),
648 (next_s_library_files-prev_s_library_files)) << endl;
649 }
650 }
651
652 // Next, gather and parse the library files.
653 set<pair<dev_t, ino_t> > seen_library_files;
654 set<string> seen_library_files_names;
655
656 for (unsigned i=0; i<s.include_path.size(); i++)
657 {
658 // now iterate upon it
659 for (unsigned k=0; k<version_suffixes.size(); k++)
660 {
661 int flags = FTW_ACTIONRETVAL;
662 string dir = s.include_path[i] + version_suffixes[k];
663 files.clear();
664 // we need to set this for the nftw() callback
665 path_dir = s.include_path[i] + "/PATH";
666 (void) nftw(dir.c_str(), collect_stp, 1, flags);
667
668 unsigned prev_s_library_files = s.library_files.size();
669
670 for (auto it = files.begin(); it != files.end(); ++it)
671 {
672 unsigned tapset_flags = pf_guru | pf_squash_errors;
673
674 // The first path is special, as it's the builtin tapset.
675 // Allow all features no matter what s.compatible says.
676 if (i == 0)
677 tapset_flags |= pf_no_compatible;
678
679 if (it->find("/PATH/") != string::npos)
680 tapset_flags |= pf_auto_path;
681
682 assert_no_interrupts();
683
684 struct stat tapset_file_stat;
685 int stat_rc = stat (it->c_str(), & tapset_file_stat);
686 if (stat_rc == 0 && user_file_stat_rc == 0 &&
687 user_file_stat.st_dev == tapset_file_stat.st_dev &&
688 user_file_stat.st_ino == tapset_file_stat.st_ino)
689 {
690 cerr
691 << _F("usage error: tapset file '%s' cannot be run directly as a session script.",
692 it->c_str()) << endl;
693 rc ++;
694 }
695
696 // PR11949: duplicate-eliminate tapset files
697 if (stat_rc == 0)
698 {
699 pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
700 tapset_file_stat.st_ino);
701 if (seen_library_files.find(here) != seen_library_files.end())
702 {
703 if (s.verbose>2)
704 clog << _F("Skipping tapset \"%s\", duplicate inode.", it->c_str()) << endl;
705 continue;
706 }
707 seen_library_files.insert (here);
708 }
709
710 // PR12443: duplicate-eliminate harder
711 string full_path = *it;
712 string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too
713 if (full_path.size() > tapset_base.size())
714 {
715 string tail_part = full_path.substr(tapset_base.size());
716 if (seen_library_files_names.find (tail_part) != seen_library_files_names.end())
717 {
718 if (s.verbose>2)
719 clog << _F("Skipping tapset \"%s\", duplicate name.", it->c_str()) << endl;
720 continue;
721 }
722 seen_library_files_names.insert (tail_part);
723 }
724
725 if (s.verbose>2)
726 clog << _F("Processing tapset \"%s\"", it->c_str()) << endl;
727
728 // NB: we don't need to restrict privilege only for
729 // /usr/share/systemtap, i.e., excluding
730 // user-specified $XDG_DATA_DIRS. That's because
731 // stapdev gets root-equivalent privileges anyway;
732 // stapsys and stapusr use a remote compilation with
733 // a trusted environment, where client-side
734 // $XDG_DATA_DIRS are not passed.
735
736 stapfile* f = parse (s, *it, tapset_flags);
737 if (f == 0)
738 s.print_warning(_F("tapset \"%s\" has errors, and will be skipped", it->c_str()));
739 else
740 s.library_files.push_back (f);
741 }
742
743 unsigned next_s_library_files = s.library_files.size();
744 if (s.verbose>1 && !files.empty())
745 //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
746 clog << _F("Searched: \"%s\", found: %zu, processed: %u",
747 dir.c_str(), files.size(),
748 (next_s_library_files-prev_s_library_files)) << endl;
749 }
750 }
751
752 if (s.num_errors())
753 rc ++;
754
755 // Now that we've made it through pass 1a, remember this so we
756 // don't have to do this again in interactive mode. This doesn't
757 // effect non-interactive mode.
758 s.pass_1a_complete = true;
759 }
760
761 // PASS 1b: PARSING USER SCRIPT
762 PROBE1(stap, pass1b__start, &s);
763
764 // reset for user scripts -- it's their use of $* we care about
765 // except that tapsets like argv.stp can consume $parms
766 fill(s.used_args.begin(), s.used_args.end(), false);
767
768 // Only try to parse a user script if the user provided one, or if we have to
769 // make one (as is the case for listing mode). Otherwise, s.user_script
770 // remains NULL.
771 if (!s.script_file.empty() ||
772 !s.cmdline_script.empty() ||
773 s.dump_mode == systemtap_session::dump_matched_probes ||
774 s.dump_mode == systemtap_session::dump_matched_probes_vars)
775 {
776 unsigned user_flags = s.guru_mode ? pf_guru : 0;
777 user_flags |= pf_user_file;
778 if (s.script_file == "-")
779 {
780 if (s.stdin_script.str().empty())
781 s.stdin_script << cin.rdbuf();
782 s.user_files.push_back (parse (s, "<input>", s.stdin_script,
783 user_flags));
784 }
785 else if (s.script_file != "")
786 {
787 s.user_files.push_back (parse (s, s.script_file, user_flags));
788 }
789 else if (s.cmdline_script != "")
790 {
791 istringstream ii (s.cmdline_script);
792 s.user_files.push_back(parse (s, "<input>", ii, user_flags));
793 }
794 else // listing mode
795 {
796 istringstream ii ("probe " + s.dump_matched_pattern + " {}");
797 s.user_files.push_back (parse (s, "<input>", ii, user_flags));
798 }
799
800 // parses the additional script(s) (-E script). does so even if in listing
801 // mode, incase there is something special in the additional script(s),
802 // like a macro or alias. give them a unique name to differentiate the
803 // scripts that were inputted.
804 unsigned count = 1;
805 for (vector<string>::iterator script = s.additional_scripts.begin(); script != s.additional_scripts.end(); script++)
806 {
807 string input_name = "<input" + lex_cast(count) + ">";
808 istringstream ii (*script);
809 s.user_files.push_back(parse (s, input_name, ii, user_flags));
810 count ++;
811 }
812
813 for(vector<stapfile*>::iterator it = s.user_files.begin(); it != s.user_files.end(); it++)
814 {
815 if (!(*it))
816 {
817 // Syntax errors already printed.
818 rc ++;
819 }
820 }
821 }
822 else if (s.cmdline_script.empty() &&
823 s.dump_mode == systemtap_session::dump_none) // -e ''
824 {
825 cerr << _("Input file '<input>' is empty.") << endl;
826 rc++;
827 }
828
829 // Dump a list of probe aliases picked up, if requested
830 if (s.dump_mode == systemtap_session::dump_probe_aliases)
831 {
832 set<string> aliases;
833 vector<stapfile*>::const_iterator file;
834 for (file = s.library_files.begin();
835 file != s.library_files.end(); ++file)
836 {
837 vector<probe_alias*>::const_iterator alias;
838 for (alias = (*file)->aliases.begin();
839 alias != (*file)->aliases.end(); ++alias)
840 {
841 stringstream ss;
842 (*alias)->printsig(ss);
843 string str = ss.str();
844 if (!s.verbose && startswith(str, "_"))
845 continue;
846 aliases.insert(str);
847 }
848 }
849
850 set<string>::iterator alias;
851 for (alias = aliases.begin();
852 alias != aliases.end(); ++alias)
853 {
854 cout << *alias << endl;
855 }
856 }
857 // Dump the parse tree if this is the last pass
858 else if (rc == 0 && s.last_pass == 1)
859 {
860 cout << _("# parse tree dump") << endl;
861 for (vector<stapfile*>::iterator it = s.user_files.begin(); it != s.user_files.end(); it++)
862 (*it)->print (cout);
863 cout << endl;
864 if (s.verbose)
865 for (unsigned i=0; i<s.library_files.size(); i++)
866 {
867 s.library_files[i]->print (cout);
868 cout << endl;
869 }
870 }
871
872 struct tms tms_after;
873 times (& tms_after);
874 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
875 struct timeval tv_after;
876 gettimeofday (&tv_after, NULL);
877
878 #define TIMESPRINT _("in ") << \
879 (tms_after.tms_cutime + tms_after.tms_utime \
880 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
881 << (tms_after.tms_cstime + tms_after.tms_stime \
882 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
883 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
884 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
885
886 // syntax errors, if any, are already printed
887 if (s.verbose)
888 {
889 // XXX also include a count of helper macro files loaded (.stpm)?
890 int n = int(s.library_files.size());
891 clog << _("Pass 1: parsed user script and ")
892 << _NF("%d library script ", "%d library scripts ", n, n)
893 << getmemusage()
894 << TIMESPRINT
895 << endl;
896 }
897
898 if (rc && !s.dump_mode)
899 cerr << _("Pass 1: parse failed. [man error::pass1]") << endl;
900
901 PROBE1(stap, pass1__end, &s);
902
903 assert_no_interrupts();
904 if (rc || s.last_pass == 1 ||
905 s.dump_mode == systemtap_session::dump_probe_aliases)
906 return rc;
907
908 times (& tms_before);
909 gettimeofday (&tv_before, NULL);
910
911 // PASS 2: ELABORATION
912 s.verbose = s.perpass_verbose[1];
913 PROBE1(stap, pass2__start, &s);
914 rc = semantic_pass (s);
915
916 // http handled probes need probe information from pass 2
917 if (! s.http_servers.empty ())
918 {
919 #if NEED_BASE_CLIENT_CODE
920 compile_server_client client (s);
921 return client.passes_0_4 ();
922 #else
923 s.print_warning(_("Without NSS or HTTP client support, using a compile-server is not supported by this version of systemtap"));
924
925 // This cannot be an attempt to use a server after a local compile failed
926 // since --use-server-on-error is locked to 'no' if we don't have
927 // NSS.
928 assert (! s.try_server ());
929 s.print_warning(_("Ignoring --use-server"));
930 #endif
931 }
932
933 // Dump a list of known probe point types, if requested.
934 if (s.dump_mode == systemtap_session::dump_probe_types)
935 s.pattern_root->dump (s);
936 // Dump a list of functions we picked up, if requested.
937 else if (s.dump_mode == systemtap_session::dump_functions)
938 {
939 map<string,functiondecl*>::const_iterator func;
940 for (func = s.functions.begin();
941 func != s.functions.end(); ++func)
942 {
943 functiondecl& curfunc = *func->second;
944 if (curfunc.synthetic)
945 continue;
946 if (!startswith(curfunc.name, "__global_"))
947 continue;
948 if (!s.verbose && startswith(curfunc.name, "__global__"))
949 continue;
950 curfunc.printsigtags(cout, s.verbose>0 /* all_tags */ );
951 cout << endl;
952 }
953 }
954 // Dump the whole script if requested, or if we stop at 2
955 else if (s.dump_mode == systemtap_session::dump_matched_probes ||
956 s.dump_mode == systemtap_session::dump_matched_probes_vars ||
957 (rc == 0 && s.last_pass == 2) ||
958 (rc != 0 && s.verbose > 2))
959 printscript(s, cout);
960
961 times (& tms_after);
962 gettimeofday (&tv_after, NULL);
963
964 if (s.verbose) {
965 int np = s.probes.size();
966 int nf = s.functions.size();
967 int ne = s.embeds.size();
968 int ng = s.globals.size();
969 clog << _("Pass 2: analyzed script: ")
970 << _NF("%d probe, ", "%d probes, ", np, np)
971 << _NF("%d function, ", "%d functions, ", nf, nf)
972 << _NF("%d embed, ", "%d embeds, ", ne, ne)
973 << _NF("%d global ", "%d globals ", ng, ng)
974 << getmemusage()
975 << TIMESPRINT
976 << endl;
977 }
978
979 missing_rpm_list_print(s, "-debuginfo");
980
981 // Check for unused command line parameters. But - if the argv
982 // tapset was selected for inclusion, then the user-script need not
983 // use $* directly, so we want to suppress the warning in this case.
984 // This is hacky, but we don't have a formal way of tracking tokens
985 // that came from command line arguments so as to do set-subtraction
986 // at this point.
987 //
988 bool argc_found=false, argv_found=false;
989 for (unsigned i = 0; i<s.globals.size(); i++) {
990 if (s.globals[i]->unmangled_name == "argc") argc_found = true;
991 if (s.globals[i]->unmangled_name == "argv") argv_found = true;
992 }
993 if (!argc_found && !argv_found)
994 for (unsigned i = 0; i<s.used_args.size(); i++)
995 if (! s.used_args[i])
996 s.print_warning (_F("unused command line option $%u/@%u", i+1, i+1));
997
998 if (rc && !s.dump_mode && !s.try_server ())
999 cerr << _("Pass 2: analysis failed. [man error::pass2]") << endl;
1000
1001 PROBE1(stap, pass2__end, &s);
1002
1003 assert_no_interrupts();
1004 // NB: none of the dump modes need to go beyond pass-2. If this changes, break
1005 // into individual modes here.
1006 if (rc || s.last_pass == 2 || s.dump_mode)
1007 return rc;
1008
1009 rc = prepare_translate_pass (s);
1010 assert_no_interrupts();
1011 if (rc) return rc;
1012
1013 // Generate hash. There isn't any point in generating the hash
1014 // if last_pass is 2, since we'll quit before using it.
1015 if (s.use_script_cache)
1016 {
1017 ostringstream o;
1018 unsigned saved_verbose;
1019
1020 {
1021 // Make sure we're in verbose mode, so that printscript()
1022 // will output function/probe bodies.
1023 saved_verbose = s.verbose;
1024 s.verbose = 3;
1025 printscript(s, o); // Print script to 'o'
1026 s.verbose = saved_verbose;
1027 }
1028
1029 // Generate hash
1030 find_script_hash (s, o.str());
1031
1032 // See if we can use cached source/module.
1033 if (get_script_from_cache(s))
1034 {
1035 // We may still need to build uprobes, if it's not also cached.
1036 if (s.need_uprobes)
1037 rc = uprobes_pass(s);
1038
1039 // If our last pass isn't 5, we're done (since passes 3 and
1040 // 4 just generate what we just pulled out of the cache).
1041 assert_no_interrupts();
1042 if (rc || s.last_pass < 5) return rc;
1043
1044 // Short-circuit to pass 5.
1045 return 0;
1046 }
1047 }
1048
1049 // PASS 3: TRANSLATION
1050 // (BPF does translation and compilation at once in pass 4.)
1051 if (s.runtime_mode != systemtap_session::bpf_runtime)
1052 {
1053 s.verbose = s.perpass_verbose[2];
1054 times (& tms_before);
1055 gettimeofday (&tv_before, NULL);
1056 PROBE1(stap, pass3__start, &s);
1057
1058 rc = translate_pass (s);
1059
1060 if (! rc && s.last_pass == 3)
1061 {
1062 ifstream i (s.translated_source.c_str());
1063 cout << i.rdbuf();
1064 }
1065
1066 times (& tms_after);
1067 gettimeofday (&tv_after, NULL);
1068
1069 if (s.verbose)
1070 clog << _("Pass 3: translated to C into \"")
1071 << s.translated_source
1072 << "\" "
1073 << getmemusage()
1074 << TIMESPRINT
1075 << endl;
1076
1077 if (rc && ! s.try_server ())
1078 cerr << _("Pass 3: translation failed. [man error::pass3]") << endl;
1079
1080 PROBE1(stap, pass3__end, &s);
1081
1082 assert_no_interrupts();
1083 if (rc || s.last_pass == 3)
1084 return rc;
1085 }
1086
1087 // PASS 4: COMPILATION
1088 s.verbose = s.perpass_verbose[3];
1089 times (& tms_before);
1090 gettimeofday (&tv_before, NULL);
1091 PROBE1(stap, pass4__start, &s);
1092
1093 if (s.runtime_mode == systemtap_session::bpf_runtime)
1094 rc = translate_bpf_pass (s);
1095 else
1096 {
1097 if (s.use_cache)
1098 {
1099 find_stapconf_hash(s);
1100 get_stapconf_from_cache(s);
1101 }
1102 rc = compile_pass (s);
1103 }
1104
1105 if (! rc && s.last_pass <= 4)
1106 {
1107 cout << ((s.hash_path == "") ? s.module_filename() : s.hash_path);
1108 cout << endl;
1109 }
1110
1111 times (& tms_after);
1112 gettimeofday (&tv_after, NULL);
1113
1114 if (s.verbose)
1115 {
1116 if (s.runtime_mode == systemtap_session::bpf_runtime)
1117 clog << _("Pass 4: compiled BPF into \"");
1118 else
1119 clog << _("Pass 4: compiled C into \"");
1120 clog << s.module_filename() << "\" " << TIMESPRINT << endl;
1121 }
1122
1123 if (rc && ! s.try_server ())
1124 cerr << _("Pass 4: compilation failed. [man error::pass4]") << endl;
1125 else
1126 {
1127 // Update cache. Cache cleaning is kicked off at the
1128 // beginning of this function.
1129 if (s.use_script_cache)
1130 add_script_to_cache(s);
1131 if (s.use_cache && !s.runtime_usermode_p())
1132 add_stapconf_to_cache(s);
1133
1134 // We may need to save the module in $CWD if the cache was
1135 // inaccessible for some reason.
1136 if (! s.use_script_cache && s.last_pass <= 4)
1137 s.save_module = true;
1138
1139 // Copy module to the current directory.
1140 if (s.save_module && !pending_interrupts)
1141 {
1142 string module_src_path = s.tmpdir + "/" + s.module_filename();
1143 string module_dest_path = s.module_filename();
1144 copy_file(module_src_path, module_dest_path, s.verbose > 1);
1145 }
1146
1147 // Copy uprobes module to the current directory.
1148 if (s.save_uprobes && !s.uprobes_path.empty() && !pending_interrupts)
1149 {
1150 rc = create_dir("uprobes");
1151 if (! rc)
1152 copy_file(s.uprobes_path, "uprobes/uprobes.ko", s.verbose > 1);
1153 }
1154 }
1155
1156 PROBE1(stap, pass4__end, &s);
1157
1158 return rc;
1159 }
1160
1161 int
1162 pass_5 (systemtap_session &s, vector<remote*> targets)
1163 {
1164 // PASS 5: RUN
1165 s.verbose = s.perpass_verbose[4];
1166 struct tms tms_before;
1167 times (& tms_before);
1168 struct timeval tv_before;
1169 gettimeofday (&tv_before, NULL);
1170 // NB: this message is a judgement call. The other passes don't emit
1171 // a "hello, I'm starting" message, but then the others aren't interactive
1172 // and don't take an indefinite amount of time.
1173 PROBE1(stap, pass5__start, &s);
1174 if (s.verbose) clog << _("Pass 5: starting run.") << endl;
1175 int rc = remote::run(targets);
1176 struct tms tms_after;
1177 times (& tms_after);
1178 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
1179 struct timeval tv_after;
1180 gettimeofday (&tv_after, NULL);
1181 if (s.verbose) clog << _("Pass 5: run completed ")
1182 << TIMESPRINT
1183 << endl;
1184
1185 if (rc)
1186 cerr << _("Pass 5: run failed. [man error::pass5]") << endl;
1187 else
1188 // Interrupting pass-5 to quit is normal, so we want an EXIT_SUCCESS below.
1189 pending_interrupts = 0;
1190
1191 PROBE1(stap, pass5__end, &s);
1192
1193 return rc;
1194 }
1195
1196 static void
1197 cleanup (systemtap_session &s, int rc)
1198 {
1199 // PASS 6: cleaning up
1200 PROBE1(stap, pass6__start, &s);
1201
1202 for (systemtap_session::session_map_t::iterator it = s.subsessions.begin();
1203 it != s.subsessions.end(); ++it)
1204 cleanup (*it->second, rc);
1205
1206 // update the database information
1207 if (!rc && s.tapset_compile_coverage && !pending_interrupts) {
1208 #ifdef HAVE_LIBSQLITE3
1209 update_coverage_db(s);
1210 #else
1211 cerr << _("Coverage database not available without libsqlite3") << endl;
1212 #endif
1213 }
1214
1215 s.report_suppression();
1216
1217 PROBE1(stap, pass6__end, &s);
1218 }
1219
1220 static int
1221 passes_0_4_again_with_server (systemtap_session &s)
1222 {
1223 // Not a server and not already using a server.
1224 assert (! s.client_options);
1225 assert (s.specified_servers.empty ());
1226
1227 // Specify default server(s).
1228 s.specified_servers.push_back ("");
1229
1230 // Reset the previous temporary directory and start fresh
1231 s.reset_tmp_dir();
1232
1233 // Try to compile again, using the server
1234 clog << _("Attempting compilation using a compile server")
1235 << endl;
1236
1237 int rc = passes_0_4 (s);
1238 return rc;
1239 }
1240
1241 int
1242 main (int argc, char * const argv [])
1243 {
1244 // Initialize defaults.
1245 try {
1246 systemtap_session s;
1247 #if ENABLE_NLS
1248 setlocale (LC_ALL, "");
1249 bindtextdomain (PACKAGE, LOCALEDIR);
1250 textdomain (PACKAGE);
1251 #endif
1252
1253 // Set up our handler to catch routine signals, to allow clean
1254 // and reasonably timely exit.
1255 setup_signals(&handle_interrupt);
1256
1257 // PR13520: Parse $SYSTEMTAP_DIR/rc for extra options
1258 string rc_file = s.data_path + "/rc";
1259 ifstream rcf (rc_file.c_str());
1260 string rcline;
1261 wordexp_t words;
1262 memset (& words, 0, sizeof(words));
1263 int rc = 0;
1264 int linecount = 0;
1265 while (getline (rcf, rcline))
1266 {
1267 rc = wordexp (rcline.c_str(), & words, WRDE_NOCMD|WRDE_UNDEF|
1268 (linecount > 0 ? WRDE_APPEND : 0));
1269 // NB: WRDE_APPEND automagically reallocates words.* as more options are added.
1270 linecount ++;
1271 if (rc) break;
1272 }
1273 rcf.close();
1274
1275 int extended_argc = words.we_wordc + argc;
1276 char **extended_argv = (char**) calloc (extended_argc + 1, sizeof(char*));
1277 if (rc || !extended_argv)
1278 {
1279 clog << _F("Error processing extra options in %s", rc_file.c_str());
1280 return EXIT_FAILURE;
1281 }
1282 // Copy over the arguments *by reference*, first the ones from the rc file.
1283 char **p = & extended_argv[0];
1284 *p++ = argv[0];
1285 for (unsigned i=0; i<words.we_wordc; i++) *p++ = words.we_wordv[i];
1286 for (int j=1; j<argc; j++) *p++ = argv[j];
1287 *p++ = NULL;
1288
1289 // Process the command line.
1290 rc = s.parse_cmdline (extended_argc, extended_argv);
1291 if (rc != 0)
1292 return rc;
1293
1294 // Create the temp dir.
1295 s.create_tmp_dir();
1296
1297 if (words.we_wordc > 0 && s.verbose > 1)
1298 clog << _F("Extra options in %s: %d\n", rc_file.c_str(), (int)words.we_wordc);
1299
1300 // Check for options conflicts. Exits if errors are detected.
1301 s.check_options (extended_argc, extended_argv);
1302
1303 // We don't need these strings any more.
1304 wordfree (& words);
1305 free (extended_argv);
1306
1307 // arguments parsed; get down to business
1308 if (s.verbose > 1)
1309 s.version ();
1310
1311 // Need to send the verbose message here, rather than in the session ctor, since
1312 // we didn't know if verbose was set.
1313 if (rc == 0 && s.verbose>1)
1314 clog << _F("Created temporary directory \"%s\"", s.tmpdir.c_str()) << endl;
1315
1316 // Run the benchmark and quit right away.
1317 if (s.benchmark_sdt_loops || s.benchmark_sdt_threads)
1318 return run_sdt_benchmark(s);
1319
1320 // Prepare connections for each specified remote target.
1321 vector<remote*> targets;
1322 bool fake_remote=false;
1323 if (s.remote_uris.empty())
1324 {
1325 fake_remote=true;
1326 s.remote_uris.push_back("direct:");
1327 }
1328 for (unsigned i = 0; rc == 0 && i < s.remote_uris.size(); ++i)
1329 {
1330 // PR13354: pass remote id#/url only in non --remote=HOST cases
1331 remote *target = remote::create(s, s.remote_uris[i],
1332 fake_remote ? -1 : (int)i);
1333 if (target)
1334 targets.push_back(target);
1335 else
1336 rc = 1;
1337 }
1338
1339 // Discover and loop over each unique session created by the remote targets.
1340 set<systemtap_session*> sessions;
1341 for (unsigned i = 0; i < targets.size(); ++i)
1342 sessions.insert(targets[i]->get_session());
1343
1344 // FIXME: For now, only attempt local interactive use.
1345 if (s.interactive_mode && fake_remote)
1346 {
1347 #ifdef HAVE_LIBREADLINE
1348 rc = interactive_mode (s, targets);
1349 #endif
1350 }
1351 else
1352 {
1353 for (set<systemtap_session*>::iterator it = sessions.begin();
1354 rc == 0 && !pending_interrupts && it != sessions.end(); ++it)
1355 {
1356 systemtap_session& ss = **it;
1357 if (ss.verbose > 1)
1358 clog << _F("Session arch: %s release: %s",
1359 ss.architecture.c_str(), ss.kernel_release.c_str())
1360 << endl;
1361
1362 #if HAVE_NSS
1363 // If requested, query server status. This is independent
1364 // of other tasks.
1365 nss_client_query_server_status (ss);
1366
1367 // If requested, manage trust of servers. This is
1368 // independent of other tasks.
1369 nss_client_manage_server_trust (ss);
1370 #endif
1371
1372 // Run the passes only if a script has been specified or
1373 // if we're dumping something. The requirement for a
1374 // script has already been checked in
1375 // systemtap_session::check_options.
1376 if (ss.have_script || ss.dump_mode)
1377 {
1378 // Run passes 0-4 for each unique session, either
1379 // locally or using a compile-server.
1380 ss.init_try_server ();
1381 if ((rc = passes_0_4 (ss)))
1382 {
1383 // Compilation failed.
1384 // Try again using a server if appropriate.
1385 if (ss.try_server ())
1386 rc = passes_0_4_again_with_server (ss);
1387 }
1388 if (rc || s.perpass_verbose[0] >= 1)
1389 s.explain_auto_options ();
1390 }
1391 }
1392
1393 // Run pass 5, if requested
1394 if (rc == 0 && s.have_script && s.last_pass >= 5 && ! pending_interrupts)
1395 rc = pass_5 (s, targets);
1396 }
1397
1398 // Pass 6. Cleanup
1399 for (unsigned i = 0; i < targets.size(); ++i)
1400 delete targets[i];
1401 cleanup (s, rc);
1402
1403 assert_no_interrupts();
1404 return (rc) ? EXIT_FAILURE : EXIT_SUCCESS;
1405 }
1406 catch (const interrupt_exception& e) {
1407 // User entered ctrl-c, exit quietly.
1408 return EXIT_FAILURE;
1409 }
1410 catch (const exit_exception& e) {
1411 // Exiting for any quiet reason.
1412 return e.rc;
1413 }
1414 catch (const exception &e) {
1415 // Some other uncaught exception.
1416 cerr << e.what() << endl;
1417 return EXIT_FAILURE;
1418 }
1419 catch (...) {
1420 // Catch all other unknown exceptions.
1421 cerr << _("ERROR: caught unknown exception!") << endl;
1422 return EXIT_FAILURE;
1423 }
1424 }
1425
1426 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.116378 seconds and 6 git commands to generate.