]> sourceware.org Git - systemtap.git/blobdiff - main.cxx
the omnibus change act of 2013 for copyright and task_finding excellence
[systemtap.git] / main.cxx
index df997779c2d93f82730c201bf71bf6fd5133598e..efc67ddf01f6aa8b68109e3752d25c07eae56c25 100644 (file)
--- a/main.cxx
+++ b/main.cxx
@@ -23,6 +23,8 @@
 #include "task_finder.h"
 #include "csclient.h"
 #include "remote.h"
+#include "tapsets.h"
+#include "setupdwfl.h"
 
 #include <libintl.h>
 #include <locale.h>
@@ -41,6 +43,7 @@ extern "C" {
 #include <sys/stat.h>
 #include <time.h>
 #include <unistd.h>
+#include <wordexp.h>
 }
 
 using namespace std;
@@ -69,7 +72,7 @@ printscript(systemtap_session& s, ostream& o)
       // Pre-process the probe alias
       for (unsigned i=0; i<s.probes.size(); i++)
         {
-          if (pending_interrupts) return;
+          assert_no_interrupts();
 
           derived_probe* p = s.probes[i];
           // NB: p->basest() is not so interesting;
@@ -106,16 +109,16 @@ printscript(systemtap_session& s, ostream& o)
           }
 
           stringstream tmps;
-          const probe_alias *a = second->get_alias();
+          // XXX PR14297 make this more accurate wrt complex wildcard expansions
+          const probe_point *a = second->get_alias_loc();
           if (a)
             {
-              assert (a->alias_names.size() >= 1);
-              a->alias_names[0]->print(tmps); // XXX: [0] is arbitrary; perhaps print all
+              a->print(tmps);
             }
           else
             {
               assert (second->locations.size() >= 1);
-              second->locations[0]->print(tmps); // XXX: [0] is less arbitrary here, but still ...
+              second->locations[0]->print(tmps); // XXX: choosing only one location is less arbitrary here than in get_alias_loc(), but still ...
             }
           string pp = tmps.str();
 
@@ -179,7 +182,7 @@ printscript(systemtap_session& s, ostream& o)
         o << _("# global embedded code") << endl;
       for (unsigned i=0; i<s.embeds.size(); i++)
         {
-          if (pending_interrupts) return;
+          assert_no_interrupts();
           embeddedcode* ec = s.embeds[i];
           ec->print (o);
           o << endl;
@@ -189,7 +192,7 @@ printscript(systemtap_session& s, ostream& o)
         o << _("# globals") << endl;
       for (unsigned i=0; i<s.globals.size(); i++)
         {
-          if (pending_interrupts) return;
+          assert_no_interrupts();
           vardecl* v = s.globals[i];
           v->printsig (o);
           if (s.verbose && v->init)
@@ -204,7 +207,7 @@ printscript(systemtap_session& s, ostream& o)
         o << _("# functions") << endl;
       for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
         {
-          if (pending_interrupts) return;
+          assert_no_interrupts();
           functiondecl* f = it->second;
           f->printsig (o);
           o << endl;
@@ -228,7 +231,7 @@ printscript(systemtap_session& s, ostream& o)
         o << _("# probes") << endl;
       for (unsigned i=0; i<s.probes.size(); i++)
         {
-          if (pending_interrupts) return;
+          assert_no_interrupts();
           derived_probe* p = s.probes[i];
           p->printsig (o);
           o << endl;
@@ -258,7 +261,8 @@ void handle_interrupt (int sig)
 {
   // This might be nice, but we don't know our current verbosity...
   // clog << _F("Received signal %d", sig) << endl << flush;
-  kill_stap_spawn(sig);
+  kill_stap_spawn(SIGTERM);
+
   pending_interrupts ++;
   // Absorb the first two signals.   This used to be one, but when
   // stap is run under sudo, and then interrupted, sudo relays a
@@ -300,133 +304,6 @@ setup_signals (sighandler_t handler)
   sigaction (SIGXCPU, &sa, NULL);
 }
 
-int parse_kernel_config (systemtap_session &s)
-{
-  // PR10702: pull config options
-  string kernel_config_file = s.kernel_build_tree + "/.config";
-  struct stat st;
-  int rc = stat(kernel_config_file.c_str(), &st);
-  if (rc != 0)
-    {
-        clog << _F("Checking \"%s\" failed with error: %s",
-                   kernel_config_file.c_str(), strerror(errno)) << endl;
-       find_devel_rpms(s, s.kernel_build_tree.c_str());
-       missing_rpm_list_print(s,"-devel");
-       return rc;
-    }
-
-  ifstream kcf (kernel_config_file.c_str());
-  string line;
-  while (getline (kcf, line))
-    {
-      if (!startswith(line, "CONFIG_")) continue;
-      size_t off = line.find('=');
-      if (off == string::npos) continue;
-      string key = line.substr(0, off);
-      string value = line.substr(off+1, string::npos);
-      s.kernel_config[key] = value;
-    }
-  if (s.verbose > 2)
-    clog << _F("Parsed kernel \"%s\", ", kernel_config_file.c_str())
-         << _F(ngettext("containing %zu tuple", "containing %zu tuples",
-                s.kernel_config.size()), s.kernel_config.size()) << endl;
-
-  kcf.close();
-  return 0;
-}
-
-
-int parse_kernel_exports (systemtap_session &s)
-{
-  string kernel_exports_file = s.kernel_build_tree + "/Module.symvers";
-  struct stat st;
-  int rc = stat(kernel_exports_file.c_str(), &st);
-  if (rc != 0)
-    {
-        clog << _F("Checking \"%s\" failed with error: %s\nEnsure kernel development headers & makefiles are installed",
-                   kernel_exports_file.c_str(), strerror(errno)) << endl;
-       return rc;
-    }
-
-  ifstream kef (kernel_exports_file.c_str());
-  string line;
-  while (getline (kef, line))
-    {
-      vector<string> tokens;
-      tokenize (line, tokens, "\t");
-      if (tokens.size() == 4 &&
-          tokens[2] == "vmlinux" &&
-          tokens[3].substr(0,13) == string("EXPORT_SYMBOL"))
-        s.kernel_exports.insert (tokens[1]);
-    }
-  if (s.verbose > 2)
-    clog << _F(ngettext("Parsed kernel %s, which contained one vmlinux export",
-                        "Parsed kernel %s, which contained %zu vmlinux exports",
-                         s.kernel_exports.size()), kernel_exports_file.c_str(),
-                         s.kernel_exports.size()) << endl;
-
-  kef.close();
-  return 0;
-}
-
-
-static int
-create_temp_dir (systemtap_session &s)
-{
-  if (!s.tmpdir.empty())
-    return 0;
-
-  // Create a temporary directory to build within.
-  // Be careful with this, as "tmpdir" is "rm -rf"'d at the end.
-  const char* tmpdir_env = getenv("TMPDIR");
-  if (! tmpdir_env)
-    tmpdir_env = "/tmp";
-
-  string stapdir = "/stapXXXXXX";
-  string tmpdirt = tmpdir_env + stapdir;
-  mode_t mask = umask(0);
-  const char *tmpdir_name = mkdtemp((char *)tmpdirt.c_str());
-  umask(mask);
-  if (! tmpdir_name)
-    {
-      const char* e = strerror (errno);
-      //TRANSLATORS: we can't make the directory due to the error
-      cerr << _F("ERROR: cannot create temporary directory (\" %s \"): %s", tmpdirt.c_str(), e) << endl;
-      return 1;
-    }
-  else
-    s.tmpdir = tmpdir_name;
-
-  if (s.verbose>1)
-    clog << _F("Created temporary directory \"%s\"", s.tmpdir.c_str()) << endl;
-  return 0;
-}
-
-static void
-remove_temp_dir (systemtap_session &s)
-{
-  if (!s.tmpdir.empty())
-    {
-      if (s.keep_tmpdir)
-        // NB: the format of this message needs to match the expectations
-        // of stap-serverd.cxx.
-        clog << _F("Keeping temporary directory \"%s\"", s.tmpdir.c_str()) << endl;
-      else
-        {
-         // Mask signals while we're deleting the temporary directory.
-         stap_sigmasker masked;
-
-         // Remove the temporary directory.
-         vector<string> cleanupcmd;
-         cleanupcmd.push_back("rm");
-         cleanupcmd.push_back("-rf");
-         cleanupcmd.push_back(s.tmpdir);
-
-         (void) stap_system (s.verbose, cleanupcmd);
-          s.tmpdir.clear();
-        }
-    }
-}
 
 // Compilation passes 0 through 4
 static int
@@ -445,20 +322,20 @@ passes_0_4 (systemtap_session &s)
       return 1;
     }
 
-  // Create a temporary directory to build within.
-  // Be careful with this, as "s.tmpdir" is "rm -rf"'d at the end.
-  rc = create_temp_dir (s);
-  if (rc)
-    return rc;
-
   // Perform passes 0 through 4 using a compile server?
   if (! s.specified_servers.empty ())
     {
 #if HAVE_NSS
       compile_server_client client (s);
-      return client.passes_0_4 ();
+      int rc = client.passes_0_4 ();
+      // Need to give a user a better diagnostic, if she didn't
+      // even ask for a server
+      if (rc && s.automatic_server_mode) {
+        cerr << _("Note: --use-server --unprivileged was selected because of stapusr membership.") << endl;
+      }
+      return rc;
 #else
-      cerr << _("WARNING: Without NSS, using a compile-server is not supported by this version of systemtap") << endl;
+      s.print_warning("Without NSS, using a compile-server is not supported by this version of systemtap");
       // This cannot be an attempt to use a server after a local compile failed
       // since --use-server-on-error is locked to 'no' if we don't have
       // NSS.
@@ -478,15 +355,18 @@ passes_0_4 (systemtap_session &s)
 
   s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
 
-  // Now that no further changes to s.kernel_build_tree can occur, let's use it.
-  if ((rc = parse_kernel_config (s)) != 0)
+  // Update various paths to include the sysroot, if provided.
+  if (!s.sysroot.empty())
     {
-      // Try again with a server
-      s.set_try_server ();
-      return rc;
+      if (s.update_release_sysroot && !s.sysroot.empty())
+        s.kernel_build_tree = s.sysroot + s.kernel_build_tree;
+      debuginfo_path_insert_sysroot(s.sysroot);
     }
 
-  if ((rc = parse_kernel_exports (s)) != 0)
+  // Now that no further changes to s.kernel_build_tree can occur, let's use it.
+  if ((rc = s.parse_kernel_config ()) != 0
+      || (rc = s.parse_kernel_exports ()) != 0
+      || (rc = s.parse_kernel_functions ()) != 0)
     {
       // Try again with a server
       s.set_try_server ();
@@ -494,8 +374,9 @@ passes_0_4 (systemtap_session &s)
     }
 
   // Create the name of the C source file within the temporary
-  // directory.
-  s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
+  // directory.  Note the _src prefix, explained in
+  // buildrun.cxx:compile_pass()
+  s.translated_source = string(s.tmpdir) + "/" + s.module_name + "_src.c";
 
   PROBE1(stap, pass0__end, &s);
 
@@ -504,64 +385,162 @@ passes_0_4 (systemtap_session &s)
   struct timeval tv_before;
   gettimeofday (&tv_before, NULL);
 
-  // PASS 1a: PARSING USER SCRIPT
+  // PASS 1a: PARSING LIBRARY SCRIPTS
   PROBE1(stap, pass1a__start, &s);
 
+  // We need to handle the library scripts first because this pass
+  // gathers information on .stpm files that might be needed to
+  // parse the user script.
+
+  // We need to first ascertain the status of the user script, though.
   struct stat user_file_stat;
   int user_file_stat_rc = -1;
 
   if (s.script_file == "-")
     {
-      s.user_file = parse (s, cin, s.guru_mode);
       user_file_stat_rc = fstat (STDIN_FILENO, & user_file_stat);
     }
   else if (s.script_file != "")
     {
-      s.user_file = parse (s, s.script_file, s.guru_mode);
       user_file_stat_rc = stat (s.script_file.c_str(), & user_file_stat);
     }
-  else
-    {
-      istringstream ii (s.cmdline_script);
-      s.user_file = parse (s, ii, s.guru_mode);
-    }
-  if (s.user_file == 0)
+  // otherwise, rc is 0 for a command line script
+
+  vector<string> version_suffixes;
+  if (s.runtime_mode == systemtap_session::kernel_runtime)
     {
-      // Syntax errors already printed.
-      rc ++;
+      // Construct kernel-versioning search path
+      string kvr = s.kernel_release;
+
+      // add full kernel-version-release (2.6.NN-FOOBAR)
+      version_suffixes.push_back ("/" + kvr);
+
+      // add kernel version (2.6.NN)
+      if (kvr != s.kernel_base_release)
+        {
+          kvr = s.kernel_base_release;
+          version_suffixes.push_back ("/" + kvr);
+        }
+
+      // add kernel family (2.6)
+      string::size_type dot1_index = kvr.find ('.');
+      string::size_type dot2_index = kvr.rfind ('.');
+      while (dot2_index > dot1_index && dot2_index != string::npos)
+        {
+          kvr.erase(dot2_index);
+          version_suffixes.push_back ("/" + kvr);
+          dot2_index = kvr.rfind ('.');
+        }
     }
 
-  // Construct arch / kernel-versioning search path
-  vector<string> version_suffixes;
-  string kvr = s.kernel_release;
-  const string& arch = s.architecture;
-  // add full kernel-version-release (2.6.NN-FOOBAR) + arch
-  version_suffixes.push_back ("/" + kvr + "/" + arch);
-  version_suffixes.push_back ("/" + kvr);
-  // add kernel version (2.6.NN) + arch
-  if (kvr != s.kernel_base_release) {
-    kvr = s.kernel_base_release;
-    version_suffixes.push_back ("/" + kvr + "/" + arch);
-    version_suffixes.push_back ("/" + kvr);
-  }
-  // add kernel family (2.6) + arch
-  string::size_type dot1_index = kvr.find ('.');
-  string::size_type dot2_index = kvr.rfind ('.');
-  while (dot2_index > dot1_index && dot2_index != string::npos) {
-    kvr.erase(dot2_index);
-    version_suffixes.push_back ("/" + kvr + "/" + arch);
-    version_suffixes.push_back ("/" + kvr);
-    dot2_index = kvr.rfind ('.');
-  }
-  // add architecture search path
-  version_suffixes.push_back("/" + arch);
   // add empty string as last element
   version_suffixes.push_back ("");
 
-  // PASS 1b: PARSING LIBRARY SCRIPTS
-  PROBE1(stap, pass1b__start, &s);
+  // Add arch variants of every path, just before each
+  const string& arch = s.architecture;
+  for (unsigned i=0; i<version_suffixes.size(); i+=2)
+    version_suffixes.insert(version_suffixes.begin() + i,
+                            version_suffixes[i] + "/" + arch);
+
+  // Add runtime variants of every path, before everything else
+  string runtime_prefix;
+  if (s.runtime_mode == systemtap_session::kernel_runtime)
+    runtime_prefix = "/linux";
+  else if (s.runtime_mode == systemtap_session::dyninst_runtime)
+    runtime_prefix = "/dyninst";
+  if (!runtime_prefix.empty())
+    for (unsigned i=0; i<version_suffixes.size(); i+=2)
+      version_suffixes.insert(version_suffixes.begin() + i/2,
+                              runtime_prefix + version_suffixes[i]);
+
+  // First, parse .stpm files on the include path. We need to have the
+  // resulting macro definitions available for parsing library files,
+  // but since .stpm files can consist only of '@define' constructs,
+  // we can parse each one without reference to the others.
+  set<pair<dev_t, ino_t> > seen_library_macro_files;
+  set<string> seen_library_macro_files_names;
+
+  for (unsigned i=0; i<s.include_path.size(); i++)
+    {
+      // now iterate upon it
+      for (unsigned k=0; k<version_suffixes.size(); k++)
+        {
+          glob_t globbuf;
+          string dir = s.include_path[i] + version_suffixes[k] + "/*.stpm";
+          int r = glob(dir.c_str (), 0, NULL, & globbuf);
+          if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
+            rc ++;
+          // GLOB_NOMATCH is acceptable
+
+          unsigned prev_s_library_files = s.library_files.size();
+
+          for (unsigned j=0; j<globbuf.gl_pathc; j++)
+            {
+              assert_no_interrupts();
+
+              struct stat tapset_file_stat;
+              int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
+              if (stat_rc == 0 && user_file_stat_rc == 0 &&
+                  user_file_stat.st_dev == tapset_file_stat.st_dev &&
+                  user_file_stat.st_ino == tapset_file_stat.st_ino)
+                {
+                  cerr
+                  << _F("usage error: macro tapset file '%s' cannot be run directly as a session script.",
+                        globbuf.gl_pathv[j]) << endl;
+                  rc ++;
+                }
+
+              // PR11949: duplicate-eliminate tapset files
+              if (stat_rc == 0)
+                {
+                  pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
+                                                     tapset_file_stat.st_ino);
+                  if (seen_library_macro_files.find(here) != seen_library_macro_files.end()) {
+                    if (s.verbose>2)
+                      clog << _F("Skipping tapset \"%s\", duplicate inode.", globbuf.gl_pathv[j]) << endl;
+                    continue; 
+                  }
+                  seen_library_macro_files.insert (here);
+                }
+
+              // PR12443: duplicate-eliminate harder
+              string full_path = globbuf.gl_pathv[j];
+              string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too
+              if (full_path.size() > tapset_base.size()) {
+                string tail_part = full_path.substr(tapset_base.size());
+                if (seen_library_macro_files_names.find (tail_part) != seen_library_macro_files_names.end()) {
+                  if (s.verbose>2)
+                      clog << _F("Skipping tapset \"%s\", duplicate name.", globbuf.gl_pathv[j]) << endl;
+                  continue;
+                }
+                seen_library_macro_files_names.insert (tail_part);
+              }
+
+              if (s.verbose>2)
+                clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl;
+
+              stapfile* f = parse_library_macros (s, globbuf.gl_pathv[j]);
+              if (f == 0)
+                s.print_warning("macro tapset '" + string(globbuf.gl_pathv[j])
+                                + "' has errors, and will be skipped."); // TODOXXX internationalization?
+              else
+                s.library_files.push_back (f);
+            }
+
+          unsigned next_s_library_files = s.library_files.size();
+          if (s.verbose>1 && globbuf.gl_pathc > 0)
+            //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
+            clog << _F("Searched for library macro files: \"%s\", found: %zu, processed: %u",
+                       dir.c_str(), globbuf.gl_pathc,
+                       (next_s_library_files-prev_s_library_files)) << endl;
+
+          globfree (&globbuf);
+        }
+    }
 
+  // Next, gather and parse the library files.
   set<pair<dev_t, ino_t> > seen_library_files;
+  set<string> seen_library_files_names;
 
   for (unsigned i=0; i<s.include_path.size(); i++)
     {
@@ -579,8 +558,7 @@ passes_0_4 (systemtap_session &s)
 
           for (unsigned j=0; j<globbuf.gl_pathc; j++)
             {
-              if (pending_interrupts)
-                break;
+              assert_no_interrupts();
 
               struct stat tapset_file_stat;
               int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
@@ -599,16 +577,39 @@ passes_0_4 (systemtap_session &s)
                 {
                   pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
                                                      tapset_file_stat.st_ino);
-                  if (seen_library_files.find(here) != seen_library_files.end())
-                    continue;
+                  if (seen_library_files.find(here) != seen_library_files.end()) {
+                    if (s.verbose>2)
+                      clog << _F("Skipping tapset \"%s\", duplicate inode.", globbuf.gl_pathv[j]) << endl;
+                    continue; 
+                  }
                   seen_library_files.insert (here);
                 }
 
-              // XXX: privilege only for /usr/share/systemtap?
-              stapfile* f = parse (s, globbuf.gl_pathv[j], true);
-              if (f == 0 && !s.suppress_warnings)
+              // PR12443: duplicate-eliminate harder
+              string full_path = globbuf.gl_pathv[j];
+              string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too
+              if (full_path.size() > tapset_base.size()) {
+                string tail_part = full_path.substr(tapset_base.size());
+                if (seen_library_files_names.find (tail_part) != seen_library_files_names.end()) {
+                  if (s.verbose>2)
+                      clog << _F("Skipping tapset \"%s\", duplicate name.", globbuf.gl_pathv[j]) << endl;
+                  continue;
+                }
+                seen_library_files_names.insert (tail_part);
+              }
+
+              if (s.verbose>2)
+                clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl;
+
+              // NB: we don't need to restrict privilege only for /usr/share/systemtap, i.e., 
+              // excluding user-specified $XDG_DATA_DIRS.  That's because stapdev gets
+              // root-equivalent privileges anyway; stapsys and stapusr use a remote compilation
+              // with a trusted environment, where client-side $XDG_DATA_DIRS are not passed.
+
+              stapfile* f = parse (s, globbuf.gl_pathv[j], true /* privileged */);
+              if (f == 0)
                 s.print_warning("tapset '" + string(globbuf.gl_pathv[j])
-                                + "' has errors, and will be skipped.");
+                                + "' has errors, and will be skipped."); // TODOXXX internationalization?
               else
                 s.library_files.push_back (f);
             }
@@ -616,7 +617,7 @@ passes_0_4 (systemtap_session &s)
           unsigned next_s_library_files = s.library_files.size();
           if (s.verbose>1 && globbuf.gl_pathc > 0)
             //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
-            clog << _F("Searched: \" %s \", found: %zu, processed: %u",
+            clog << _F("Searched: \"%s\", found: %zu, processed: %u",
                        dir.c_str(), globbuf.gl_pathc,
                        (next_s_library_files-prev_s_library_files)) << endl;
 
@@ -626,6 +627,28 @@ passes_0_4 (systemtap_session &s)
   if (s.num_errors())
     rc ++;
 
+  // PASS 1b: PARSING USER SCRIPT
+  PROBE1(stap, pass1b__start, &s);
+
+  if (s.script_file == "-")
+    {
+      s.user_file = parse (s, cin, s.guru_mode);
+    }
+  else if (s.script_file != "")
+    {
+      s.user_file = parse (s, s.script_file, s.guru_mode);
+    }
+  else
+    {
+      istringstream ii (s.cmdline_script);
+      s.user_file = parse (s, ii, s.guru_mode);
+    }
+  if (s.user_file == 0)
+    {
+      // Syntax errors already printed.
+      rc ++;
+    }
+
   if (rc == 0 && s.last_pass == 1)
     {
       cout << _("# parse tree dump") << endl;
@@ -656,6 +679,7 @@ passes_0_4 (systemtap_session &s)
   // syntax errors, if any, are already printed
   if (s.verbose)
     {
+      // XXX also include a count of helper macro files loaded (.stpm)?
       clog << "Pass 1: parsed user script and "
            << s.library_files.size()
            << " library script(s) "
@@ -672,7 +696,8 @@ passes_0_4 (systemtap_session &s)
 
   PROBE1(stap, pass1__end, &s);
 
-  if (rc || s.last_pass == 1 || pending_interrupts) return rc;
+  assert_no_interrupts();
+  if (rc || s.last_pass == 1) return rc;
 
   times (& tms_before);
   gettimeofday (&tv_before, NULL);
@@ -682,6 +707,10 @@ passes_0_4 (systemtap_session &s)
   PROBE1(stap, pass2__start, &s);
   rc = semantic_pass (s);
 
+  // Dump a list of known probe point types, if requested.
+  if (s.dump_probe_types)
+    s.pattern_root->dump (s);
+
   if (s.listing_mode || (rc == 0 && s.last_pass == 2))
     printscript(s, cout);
 
@@ -708,10 +737,12 @@ passes_0_4 (systemtap_session &s)
 
   PROBE1(stap, pass2__end, &s);
 
-  if (rc || s.listing_mode || s.last_pass == 2 || pending_interrupts) return rc;
+  assert_no_interrupts();
+  if (rc || s.listing_mode || s.last_pass == 2) return rc;
 
   rc = prepare_translate_pass (s);
-  if (rc || pending_interrupts) return rc;
+  assert_no_interrupts();
+  if (rc) return rc;
 
   // Generate hash.  There isn't any point in generating the hash
   // if last_pass is 2, since we'll quit before using it.
@@ -735,9 +766,14 @@ passes_0_4 (systemtap_session &s)
       // See if we can use cached source/module.
       if (get_script_from_cache(s))
         {
+         // We may still need to build uprobes, if it's not also cached.
+         if (s.need_uprobes)
+           rc = uprobes_pass(s);
+
          // If our last pass isn't 5, we're done (since passes 3 and
          // 4 just generate what we just pulled out of the cache).
-         if (s.last_pass < 5 || pending_interrupts) return rc;
+         assert_no_interrupts();
+         if (rc || s.last_pass < 5) return rc;
 
          // Short-circuit to pass 5.
          return 0;
@@ -776,7 +812,8 @@ passes_0_4 (systemtap_session &s)
 
   PROBE1(stap, pass3__end, &s);
 
-  if (rc || s.last_pass == 3 || pending_interrupts) return rc;
+  assert_no_interrupts();
+  if (rc || s.last_pass == 3) return rc;
 
   // PASS 4: COMPILATION
   s.verbose = s.perpass_verbose[3];
@@ -792,7 +829,7 @@ passes_0_4 (systemtap_session &s)
   rc = compile_pass (s);
   if (! rc && s.last_pass == 4)
     {
-      cout << ((s.hash_path == "") ? (s.module_name + string(".ko")) : s.hash_path);
+      cout << ((s.hash_path == "") ? s.module_filename() : s.hash_path);
       cout << endl;
     }
 
@@ -800,22 +837,20 @@ passes_0_4 (systemtap_session &s)
   gettimeofday (&tv_after, NULL);
 
   if (s.verbose) clog << "Pass 4: compiled C into \""
-                      << s.module_name << ".ko"
+                      << s.module_filename()
                       << "\" "
                       << TIMESPRINT
                       << endl;
 
   if (rc && ! s.try_server ())
-    cerr << _("Pass 4: compilation failed.  Try again with another '--vp 0001' option.") << endl;
-    //cerr << "Pass 4: compilation failed.  "
-    //     << "Try again with another '--vp 0001' option."
-    //     << endl;
+    cerr << _("Pass 4: compilation failed. [man error::pass4]") << endl;
+
   else
     {
       // Update cache. Cache cleaning is kicked off at the beginning of this function.
       if (s.use_script_cache)
         add_script_to_cache(s);
-      if (s.use_cache)
+      if (s.use_cache && !s.runtime_usermode_p())
         add_stapconf_to_cache(s);
 
       // We may need to save the module in $CWD if the cache was
@@ -826,8 +861,8 @@ passes_0_4 (systemtap_session &s)
       // Copy module to the current directory.
       if (s.save_module && !pending_interrupts)
         {
-         string module_src_path = s.tmpdir + "/" + s.module_name + ".ko";
-         string module_dest_path = s.module_name + ".ko";
+         string module_src_path = s.tmpdir + "/" + s.module_filename();
+         string module_dest_path = s.module_filename();
          copy_file(module_src_path, module_dest_path, s.verbose > 1);
        }
     }
@@ -894,9 +929,6 @@ cleanup (systemtap_session &s, int rc)
 #endif
   }
 
-  // Clean up temporary directory.  Obviously, be careful with this.
-  remove_temp_dir (s);
-
   PROBE1(stap, pass6__end, &s);
 }
 
@@ -910,12 +942,13 @@ passes_0_4_again_with_server (systemtap_session &s)
   // Specify default server(s).
   s.specified_servers.push_back ("");
 
-  // Remove the previous temporary directory and start fresh.
-  remove_temp_dir (s);
+  // Reset the previous temporary directory and start fresh
+  s.reset_tmp_dir();
 
   // Try to compile again, using the server
   clog << _("Attempting compilation using a compile server")
        << endl;
+
   int rc = passes_0_4 (s);
   return rc;
 }
@@ -924,90 +957,164 @@ int
 main (int argc, char * const argv [])
 {
   // Initialize defaults.
-  systemtap_session s;
-
-  setlocale (LC_ALL, "");
-  bindtextdomain (PACKAGE, LOCALEDIR);
-  textdomain (PACKAGE);
+  try {
+    systemtap_session s;
+
+    setlocale (LC_ALL, "");
+    bindtextdomain (PACKAGE, LOCALEDIR);
+    textdomain (PACKAGE);
+
+    // Set up our handler to catch routine signals, to allow clean
+    // and reasonably timely exit.
+    setup_signals(&handle_interrupt);
+
+    // PR13520: Parse $SYSTEMTAP_DIR/rc for extra options
+    string rc_file = s.data_path + "/rc";
+    ifstream rcf (rc_file.c_str());
+    string rcline;
+    wordexp_t words;
+    memset (& words, 0, sizeof(words));
+    int rc = 0;
+    int linecount = 0;
+    while (getline (rcf, rcline))
+      {
+        rc = wordexp (rcline.c_str(), & words, WRDE_NOCMD|WRDE_UNDEF|
+                      (linecount > 0 ? WRDE_APPEND : 0)); 
+        // NB: WRDE_APPEND automagically reallocates words.* as more options are added.
+        linecount ++;
+        if (rc) break;
+      }
+    int extended_argc = words.we_wordc + argc;
+    char **extended_argv = (char**) calloc (extended_argc + 1, sizeof(char*));
+    if (rc || !extended_argv)
+      {
+        clog << _F("Error processing extra options in %s", rc_file.c_str());
+        return EXIT_FAILURE;
+      }
+    // Copy over the arguments *by reference*, first the ones from the rc file.
+    char **p = & extended_argv[0];
+    *p++ = argv[0];
+    for (unsigned i=0; i<words.we_wordc; i++) *p++ = words.we_wordv[i];
+    for (int j=1; j<argc; j++) *p++ = argv[j];
+    *p++ = NULL;
+
+    // Process the command line.
+    rc = s.parse_cmdline (extended_argc, extended_argv);
+    if (rc != 0)
+      return rc;
 
-  // Set up our handler to catch routine signals, to allow clean
-  // and reasonably timely exit.
-  setup_signals(&handle_interrupt);
+    if (words.we_wordc > 0 && s.verbose > 1)
+      clog << _F("Extra options in %s: %d\n", rc_file.c_str(), (int)words.we_wordc);
 
-  // Process the command line.
-  int rc = s.parse_cmdline (argc, argv);
-  if (rc != 0)
-    exit (rc);
+    // Check for options conflicts. Exits if errors are detected.
+    s.check_options (extended_argc, extended_argv);
 
-  // Check for options conflicts. Exits if errors are detected.
-  s.check_options (argc, argv);
+    // We don't need these strings any more.
+    wordfree (& words);
+    free (extended_argv);
 
-  // arguments parsed; get down to business
-  if (s.verbose > 1)
-    s.version ();
+    // arguments parsed; get down to business
+    if (s.verbose > 1)
+      s.version ();
 
-  // Some of the remote methods need to write temporary data, so go ahead
-  // and create the main tempdir now.
-  rc = create_temp_dir (s);
+    // Need to send the verbose message here, rather than in the session ctor, since
+    // we didn't know if verbose was set.
+    if (rc == 0 && s.verbose>1)
+      clog << _F("Created temporary directory \"%s\"", s.tmpdir.c_str()) << endl;
 
-  // Prepare connections for each specified remote target.
-  vector<remote*> targets;
-  if (s.remote_uris.empty())
-    s.remote_uris.push_back("direct:");
-  for (unsigned i = 0; rc == 0 && i < s.remote_uris.size(); ++i)
-    {
-      remote *target = remote::create(s, s.remote_uris[i]);
-      if (target)
-        targets.push_back(target);
-      else
-        rc = 1;
-    }
+    // Prepare connections for each specified remote target.
+    vector<remote*> targets;
+    bool fake_remote=false;
+    if (s.remote_uris.empty())
+      {
+        fake_remote=true;
+        s.remote_uris.push_back("direct:");
+      }
+    for (unsigned i = 0; rc == 0 && i < s.remote_uris.size(); ++i)
+      {
+        // PR13354: pass remote id#/url only in non --remote=HOST cases
+        remote *target = remote::create(s, s.remote_uris[i],
+                                        fake_remote ? -1 : (int)i);
+        if (target)
+          targets.push_back(target);
+        else
+          rc = 1;
+      }
 
-  // Discover and loop over each unique session created by the remote targets.
-  set<systemtap_session*> sessions;
-  for (unsigned i = 0; i < targets.size(); ++i)
-    sessions.insert(targets[i]->get_session());
-  for (set<systemtap_session*>::iterator it = sessions.begin();
-       rc == 0 && !pending_interrupts && it != sessions.end(); ++it)
-    {
-      systemtap_session& ss = **it;
-      if (ss.verbose > 1)
-        clog << _F("Session arch: %s release: %s",
-                   ss.architecture.c_str(), ss.kernel_release.c_str()) << endl;
+    // Discover and loop over each unique session created by the remote targets.
+    set<systemtap_session*> sessions;
+    for (unsigned i = 0; i < targets.size(); ++i)
+      sessions.insert(targets[i]->get_session());
+    for (set<systemtap_session*>::iterator it = sessions.begin();
+         rc == 0 && !pending_interrupts && it != sessions.end(); ++it)
+      {
+        systemtap_session& ss = **it;
+        if (ss.verbose > 1)
+          clog << _F("Session arch: %s release: %s",
+                     ss.architecture.c_str(), ss.kernel_release.c_str()) << endl;
 
-      // If requested, query server status. This is independent of other tasks.
-      query_server_status (ss);
+#if HAVE_NSS
+        // If requested, query server status. This is independent of other tasks.
+        query_server_status (ss);
 
-      // If requested, manage trust of servers. This is independent of other tasks.
-      manage_server_trust (ss);
+        // If requested, manage trust of servers. This is independent of other tasks.
+        manage_server_trust (ss);
+#endif
 
-      // Run the passes only if a script has been specified. The requirement for
-      // a script has already been checked in systemtap_session::check_options.
-      if (ss.have_script)
-        {
-          // Run passes 0-4 for each unique session,
-          // either locally or using a compile-server.
-          ss.init_try_server ();
-          if ((rc = passes_0_4 (ss)))
-            {
-              // Compilation failed.
-              // Try again using a server if appropriate.
-              if (ss.try_server ())
-                rc = passes_0_4_again_with_server (ss);
-            }
-        }
-    }
+        // Run the passes only if a script has been specified. The requirement for
+        // a script has already been checked in systemtap_session::check_options.
+        // Run the passes also if a dump of supported probe types has been requested via a server.
+        if (ss.have_script || (ss.dump_probe_types && ! s.specified_servers.empty ()))
+          {
+            // Run passes 0-4 for each unique session,
+            // either locally or using a compile-server.
+            ss.init_try_server ();
+            if ((rc = passes_0_4 (ss)))
+              {
+                // Compilation failed.
+                // Try again using a server if appropriate.
+                if (ss.try_server ())
+                  rc = passes_0_4_again_with_server (ss);
+              }
+          }
+        else if (ss.dump_probe_types)
+          {
+            // Dump a list of known probe point types, if requested.
+            register_standard_tapsets(ss);
+            ss.pattern_root->dump (ss);
+          }
+      }
 
-  // Run pass 5, if requested
-  if (rc == 0 && s.have_script && s.last_pass >= 5 && ! pending_interrupts)
-    rc = pass_5 (s, targets);
+    // Run pass 5, if requested
+    if (rc == 0 && s.have_script && s.last_pass >= 5 && ! pending_interrupts)
+      rc = pass_5 (s, targets);
 
-  // Pass 6. Cleanup
-  for (unsigned i = 0; i < targets.size(); ++i)
-    delete targets[i];
-  cleanup (s, rc);
+    // Pass 6. Cleanup
+    for (unsigned i = 0; i < targets.size(); ++i)
+      delete targets[i];
+    cleanup (s, rc);
 
-  return (rc||pending_interrupts) ? EXIT_FAILURE : EXIT_SUCCESS;
+    assert_no_interrupts();
+    return (rc) ? EXIT_FAILURE : EXIT_SUCCESS;
+  }
+  catch (const interrupt_exception& e) {
+      // User entered ctrl-c, exit quietly.
+      return EXIT_FAILURE;
+  }
+  catch (const exit_exception& e) {
+      // Exiting for any quiet reason.
+      return e.rc;
+  }
+  catch (const runtime_error &e) {
+      // Some other uncaught runtime_error exception.
+      cerr << e.what() << endl;
+      return EXIT_FAILURE;
+  }
+  catch (...) {
+      // Catch all other unknown exceptions.
+      cerr << _("ERROR: caught unknown exception!") << endl;
+      return EXIT_FAILURE;
+  }
 }
 
 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.048443 seconds and 5 git commands to generate.