diff --git a/SOURCES/rhbz1020207.patch b/SOURCES/rhbz1020207.patch new file mode 100644 index 0000000..54489d3 --- /dev/null +++ b/SOURCES/rhbz1020207.patch @@ -0,0 +1,87 @@ +From 9b1d74f9a9d606f1e483690afae0a4a8207c76db Mon Sep 17 00:00:00 2001 +From: David Smith <dsmith@redhat.com> +Date: Fri, 7 Feb 2014 10:27:14 -0600 +Subject: [PATCH] Remove the transport's unused "dropped" file. + +* runtime/transport/relay_v2.c: Unless _STP_USE_DROPPED_FILE is defined, + don't bother creating the unused "dropped" file. +--- + runtime/transport/relay_v2.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c +index 6c9815d..97e02f9 100644 +--- a/runtime/transport/relay_v2.c ++++ b/runtime/transport/relay_v2.c +@@ -43,8 +43,10 @@ + struct _stp_relay_data_type { + struct rchan *rchan; + atomic_t /* enum _stp_transport_state */ transport_state; ++#ifdef _STP_USE_DROPPED_FILE + struct dentry *dropped_file; + atomic_t dropped; ++#endif + atomic_t wakeup; + struct timer_list timer; + int overwrite_flag; +@@ -160,6 +162,7 @@ static void _stp_transport_data_fs_overwrite(int overwrite) + _stp_relay_data.overwrite_flag = overwrite; + } + ++#ifdef _STP_USE_DROPPED_FILE + static int __stp_relay_dropped_open(struct inode *inode, struct file *filp) + { + return 0; +@@ -181,6 +184,7 @@ static struct file_operations __stp_relay_dropped_fops = { + .open = __stp_relay_dropped_open, + .read = __stp_relay_dropped_read, + }; ++#endif + + /* + * Keep track of how many times we encountered a full subbuffer, to aid +@@ -193,7 +197,9 @@ static int __stp_relay_subbuf_start_callback(struct rchan_buf *buf, + if (_stp_relay_data.overwrite_flag || !relay_buf_full(buf)) + return 1; + ++#ifdef _STP_USE_DROPPED_FILE + atomic_inc(&_stp_relay_data.dropped); ++#endif + return 0; + } + +@@ -270,8 +276,10 @@ static void _stp_transport_data_fs_stop(void) + static void _stp_transport_data_fs_close(void) + { + _stp_transport_data_fs_stop(); ++#ifdef _STP_USE_DROPPED_FILE + if (_stp_relay_data.dropped_file) + debugfs_remove(_stp_relay_data.dropped_file); ++#endif + if (_stp_relay_data.rchan) { + relay_close(_stp_relay_data.rchan); + _stp_relay_data.rchan = NULL; +@@ -286,9 +294,11 @@ static int _stp_transport_data_fs_init(void) + + atomic_set(&_stp_relay_data.transport_state, STP_TRANSPORT_STOPPED); + _stp_relay_data.overwrite_flag = 0; ++ _stp_relay_data.rchan = NULL; ++ ++#ifdef _STP_USE_DROPPED_FILE + atomic_set(&_stp_relay_data.dropped, 0); + _stp_relay_data.dropped_file = NULL; +- _stp_relay_data.rchan = NULL; + + /* Create "dropped" file. */ + _stp_relay_data.dropped_file +@@ -306,6 +316,7 @@ static int _stp_transport_data_fs_init(void) + + _stp_relay_data.dropped_file->d_inode->i_uid = KUIDT_INIT(_stp_uid); + _stp_relay_data.dropped_file->d_inode->i_gid = KGIDT_INIT(_stp_gid); ++#endif + + /* Create "trace" file. */ + npages = _stp_subbuf_size * _stp_nsubbufs; +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1035752.patch b/SOURCES/rhbz1035752.patch new file mode 100644 index 0000000..4d06bad --- /dev/null +++ b/SOURCES/rhbz1035752.patch @@ -0,0 +1,108 @@ +From 735972b4c681efeff3c4137816cb913174a839be Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Mon, 2 Dec 2013 11:17:05 -0500 +Subject: [PATCH 1/2] Resolves: #1035752 + +Upstream commit e7d52b3. +--- + csclient.cxx | 2 +- + stap-serverd.cxx | 34 ++++++++++++++++++---------------- + 2 files changed, 19 insertions(+), 17 deletions(-) + +diff --git a/csclient.cxx b/csclient.cxx +index cce5428..4cfeb08 100644 +--- a/csclient.cxx ++++ b/csclient.cxx +@@ -829,7 +829,7 @@ compile_server_client::passes_0_4 () + << TIMESPRINT + << endl; + } +- if (rc) ++ if (rc && !s.listing_mode) + { + clog << _("Passes: via server failed. Try again with another '-v' option.") << endl; + } +diff --git a/stap-serverd.cxx b/stap-serverd.cxx +index 53a8d3a..035d06c 100644 +--- a/stap-serverd.cxx ++++ b/stap-serverd.cxx +@@ -63,7 +63,7 @@ extern "C" { + using namespace std; + + static void cleanup (); +-static PRStatus spawn_and_wait (const vector<string> &argv, ++static PRStatus spawn_and_wait (const vector<string> &argv, int *result, + const char* fd0, const char* fd1, const char* fd2, + const char *pwd, const vector<string>& envVec = vector<string> ()); + +@@ -1234,18 +1234,19 @@ handleRequest (const string &requestDirName, const string &responseDirName, stri + get_stap_locale (staplang, envVec, stapstderr, &client_version); + + /* All ready, let's run the translator! */ +- rc = spawn_and_wait(stapargv, "/dev/null", stapstdout.c_str (), stapstderr.c_str (), +- requestDirName.c_str (), envVec); ++ int staprc; ++ rc = spawn_and_wait(stapargv, &staprc, "/dev/null", stapstdout.c_str (), ++ stapstderr.c_str (), requestDirName.c_str (), envVec); ++ if (rc != PR_SUCCESS) ++ { ++ server_error(_("Failed spawning translator")); ++ return; ++ } + + /* Save the RC */ +- string staprc = responseDirName + "/rc"; +- f = fopen(staprc.c_str (), "w"); +- if (f) +- { +- /* best effort basis */ +- fprintf(f, "%d", rc); +- fclose(f); +- } ++ ofstream ofs((responseDirName + "/rc").c_str()); ++ ofs << staprc; ++ ofs.close(); + + // In unprivileged modes, if we have a module built, we need to sign the sucker. + privilege_t privilege = getRequestedPrivilege (stapargv); +@@ -1316,7 +1317,7 @@ handleRequest (const string &requestDirName, const string &responseDirName, stri + /* A front end for stap_spawn that handles stdin, stdout, stderr, switches to a working + directory and returns overall success or failure. */ + static PRStatus +-spawn_and_wait (const vector<string> &argv, ++spawn_and_wait (const vector<string> &argv, int *spawnrc, + const char* fd0, const char* fd1, const char* fd2, + const char *pwd, const vector<string>& envVec) + { +@@ -1380,8 +1381,8 @@ spawn_and_wait (const vector<string> &argv, + return PR_FAILURE; + } + +- rc = stap_waitpid (0, pid); +- if (rc == -1) ++ *spawnrc = stap_waitpid (0, pid); ++ if (*spawnrc == -1) + { + server_error (_("Error in waitpid")); + return PR_FAILURE; +@@ -1540,14 +1541,15 @@ handle_connection (void *arg) + handleRequest(requestDirName, responseDirName, stapstderr); + + /* Zip the response. */ ++ int ziprc; + argv.clear (); + argv.push_back ("zip"); + argv.push_back ("-q"); + argv.push_back ("-r"); + argv.push_back (responseFileName); + argv.push_back ("."); +- rc = spawn_and_wait (argv, NULL, NULL, NULL, responseDirName); +- if (rc != PR_SUCCESS) ++ rc = spawn_and_wait (argv, &ziprc, NULL, NULL, NULL, responseDirName); ++ if (rc != PR_SUCCESS || ziprc != 0) + { + server_error (_("Unable to compress server response")); + goto cleanup; +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1035850.patch b/SOURCES/rhbz1035850.patch new file mode 100644 index 0000000..a56047a --- /dev/null +++ b/SOURCES/rhbz1035850.patch @@ -0,0 +1,122 @@ +From 10632b637aa12614e36ef83c7762bd44bef80716 Mon Sep 17 00:00:00 2001 +From: David Smith <dsmith@redhat.com> +Date: Tue, 3 Dec 2013 10:52:37 -0600 +Subject: [PATCH 2/2] Resolves: #1035850 + +Upstream commit f112949. +--- + testsuite/systemtap.examples/process/pfiles.stp | 54 +++++++++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/testsuite/systemtap.examples/process/pfiles.stp b/testsuite/systemtap.examples/process/pfiles.stp +index 6f5a834..b2bdbd8 100755 +--- a/testsuite/systemtap.examples/process/pfiles.stp ++++ b/testsuite/systemtap.examples/process/pfiles.stp +@@ -77,6 +77,10 @@ + #include <net/sock.h> + #include <linux/un.h> + #include <linux/tcp.h> ++#ifdef CONFIG_USER_NS ++#include <linux/user_namespace.h> ++#include <linux/uidgid.h> ++#endif + %} + + function task_valid_file_handle:long (task:long, fd:long) %{ /* pure */ +@@ -199,6 +203,9 @@ function task_file_handle_uid:long (task:long, fd:long) %{ /* pure */ + struct task_struct *p = (struct task_struct *)((long)STAP_ARG_task); + struct files_struct *files; + struct file *filp; ++#ifdef CONFIG_USER_NS ++ struct user_namespace *ns = NULL; ++#endif + + rcu_read_lock(); + if ((files = kread(&p->files)) && +@@ -207,7 +214,25 @@ function task_file_handle_uid:long (task:long, fd:long) %{ /* pure */ + /* git commit d76b0d9b */ + const struct cred *cred; + if ((cred = kread(&filp->f_cred))) { ++#ifdef CONFIG_USER_NS ++ ns = get_user_ns(task_cred_xxx(p, user_ns)); ++ if (ns) { ++ // We call kderef_buffer() here to ++ // ensure the memory at the kuid_t ++ // location is valid to read. We can't ++ // use kderef()/kread(), since they ++ // only handle data with a size of 1, ++ // 2, 4, or 8 bytes. ++ kderef_buffer(NULL, &cred->fsuid, ++ sizeof(kuid_t)); ++ STAP_RETVALUE = from_kuid(ns, cred->fsuid); ++ } ++ else ++ STAP_RETVALUE = -1; ++ ++#else /* ! CONFIG_USER_NS */ + STAP_RETVALUE = kread(&cred->fsuid); ++#endif /* ! CONFIG_USER_NS */ + } + #else + STAP_RETVALUE = kread(&filp->f_uid); +@@ -215,6 +240,10 @@ function task_file_handle_uid:long (task:long, fd:long) %{ /* pure */ + } + + CATCH_DEREF_FAULT(); ++#ifdef CONFIG_USER_NS ++ if (ns) ++ put_user_ns(ns); ++#endif + rcu_read_unlock(); + %} + +@@ -222,6 +251,9 @@ function task_file_handle_gid:long (task:long, fd:long) %{ /* pure */ + struct task_struct *p = (struct task_struct *)((long)STAP_ARG_task); + struct files_struct *files; + struct file *filp; ++#ifdef CONFIG_USER_NS ++ struct user_namespace *ns = NULL; ++#endif + + rcu_read_lock(); + if ((files = kread(&p->files)) && +@@ -230,7 +262,25 @@ function task_file_handle_gid:long (task:long, fd:long) %{ /* pure */ + /* git commit d76b0d9b */ + const struct cred *cred; + if ((cred = kread(&filp->f_cred))) { ++#ifdef CONFIG_USER_NS ++ ns = get_user_ns(task_cred_xxx(p, user_ns)); ++ if (ns) { ++ // We call kderef_buffer() here to ++ // ensure the memory at the kgid_t ++ // location is valid to read. We can't ++ // use kderef()/kread(), since they ++ // only handle data with a size of 1, ++ // 2, 4, or 8 bytes. ++ kderef_buffer(NULL, &cred->fsgid, ++ sizeof(kgid_t)); ++ STAP_RETVALUE = from_kgid(ns, cred->fsgid); ++ } ++ else ++ STAP_RETVALUE = -1; ++ ++#else /* ! CONFIG_USER_NS */ + STAP_RETVALUE = kread(&cred->fsgid); ++#endif /* ! CONFIG_USER_NS */ + } + #else + STAP_RETVALUE = kread(&filp->f_gid); +@@ -238,6 +288,10 @@ function task_file_handle_gid:long (task:long, fd:long) %{ /* pure */ + } + + CATCH_DEREF_FAULT(); ++#ifdef CONFIG_USER_NS ++ if (ns) ++ put_user_ns(ns); ++#endif + rcu_read_unlock(); + %} + +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1044429.patch b/SOURCES/rhbz1044429.patch new file mode 100644 index 0000000..910b98d --- /dev/null +++ b/SOURCES/rhbz1044429.patch @@ -0,0 +1,1278 @@ +From 94b9fcc03560b36932405727759a5621966cd212 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Fri, 13 Dec 2013 16:37:57 -0500 +Subject: BZ1044429: fix client.exp and improve client/server + +--- + csclient.cxx | 342 ++++++++++++---------- + csclient.h | 4 +- + nsscommon.cxx | 11 +- + testsuite/lib/systemtap.exp | 1 + + testsuite/systemtap.server/client.exp | 333 ++++++++++----------- + testsuite/systemtap.server/server_args.exp | 17 +- + testsuite/systemtap.server/server_concurrency.exp | 4 +- + 7 files changed, 373 insertions(+), 339 deletions(-) + +diff --git a/csclient.cxx b/csclient.cxx +index cce5428..568cc8f 100644 +--- a/csclient.cxx ++++ b/csclient.cxx +@@ -1,6 +1,6 @@ + /* + Compile server client functions +- Copyright (C) 2010-2013 Red Hat Inc. ++ Copyright (C) 2010-2014 Red Hat Inc. + + This file is part of systemtap, and is free software. You can + redistribute it and/or modify it under the terms of the GNU General +@@ -88,66 +88,71 @@ nsscommon_error (const char *msg, int logit __attribute ((unused))) + // Information about compile servers. + struct compile_server_info + { +- compile_server_info () ++ compile_server_info () : port(0), fully_specified(false) + { + memset (& address, 0, sizeof (address)); + } + + string host_name; + PRNetAddr address; ++ unsigned short port; ++ bool fully_specified; + string version; + string sysinfo; + string certinfo; + + bool empty () const + { +- return this->host_name.empty () && ! this->hasAddress (); ++ return this->host_name.empty () && ! this->hasAddress () && certinfo.empty (); + } + bool hasAddress () const + { + return this->address.raw.family != 0; + } +- unsigned short port () const +- { +- if (this->address.raw.family == PR_AF_INET) +- return ntohs (this->address.inet.port); +- if (this->address.raw.family == PR_AF_INET6) +- return ntohs (this->address.ipv6.port); +- return 0; +- } +- unsigned short setPort (unsigned short port) ++ unsigned short setAddressPort (unsigned short port) + { + if (this->address.raw.family == PR_AF_INET) + return this->address.inet.port = htons (port); + if (this->address.raw.family == PR_AF_INET6) + return this->address.ipv6.port = htons (port); ++ assert (0); + return 0; + } ++ bool isComplete () const ++ { ++ return this->hasAddress () && port != 0; ++ } + + bool operator== (const compile_server_info &that) const + { +- // If both ip addressed are not set, then the host names must match, otherwise +- // the addresses must match. +- if (! this->hasAddress() || ! that.hasAddress()) ++ // If one item or the other has only a name, and possibly a port specified, ++ // then allow a match by name and port only. This is so that the user can specify ++ // names which are returned by avahi, but are not dns resolvable. ++ // Otherwise, we will ignore the host_name. ++ if ((! this->hasAddress() && this->version.empty () && ++ this->sysinfo.empty () && this->certinfo.empty ()) || ++ (! that.hasAddress() && that.version.empty () && ++ that.sysinfo.empty () && that.certinfo.empty ())) + { + if (this->host_name != that.host_name) + return false; + } +- else if (this->address != that.address) +- return false; + + // Compare the other fields only if they have both been set. +- if (this->port() != 0 && that.port() != 0 && +- this->port() != that.port()) ++ if (this->hasAddress() && that.hasAddress() && ++ this->address != that.address) ++ return false; ++ if (this->port != 0 && that.port != 0 && ++ this->port != that.port) + return false; + if (! this->version.empty () && ! that.version.empty () && +- this->version != that.version) ++ this->version != that.version) + return false; + if (! this->sysinfo.empty () && ! that.sysinfo.empty () && +- this->sysinfo != that.sysinfo) ++ this->sysinfo != that.sysinfo) + return false; + if (! this->certinfo.empty () && ! that.certinfo.empty () && +- this->certinfo != that.certinfo) ++ this->certinfo != that.certinfo) + return false; + + return true; // They are equal +@@ -179,6 +184,14 @@ preferred_order (vector<compile_server_info> &servers) + sort (servers.begin (), servers.end ()); + } + ++struct resolved_host ++{ ++ string host_name; ++ PRNetAddr address; ++ resolved_host(string chost_name, PRNetAddr caddress): ++ host_name(chost_name), address(caddress) {} ++}; ++ + struct compile_server_cache + { + vector<compile_server_info> default_servers; +@@ -187,7 +200,7 @@ struct compile_server_cache + vector<compile_server_info> signing_servers; + vector<compile_server_info> online_servers; + vector<compile_server_info> all_servers; +- map<string,vector<compile_server_info> > resolved_servers; ++ map<string,vector<resolved_host> > resolved_hosts; + }; + + // For filtering queries. +@@ -234,7 +247,7 @@ static void resolve_host (systemtap_session& s, compile_server_info &server, vec + // ----------------------------------------------------- + // NSS related code used by the compile server client + // ----------------------------------------------------- +-static void add_server_trust (systemtap_session &s, const string &cert_db_path, const vector<compile_server_info> &server_list); ++static void add_server_trust (systemtap_session &s, const string &cert_db_path, vector<compile_server_info> &server_list); + static void revoke_server_trust (systemtap_session &s, const string &cert_db_path, const vector<compile_server_info> &server_list); + static void get_server_info_from_db (systemtap_session &s, vector<compile_server_info> &servers, const string &cert_db_path); + +@@ -1132,10 +1145,10 @@ compile_server_client::find_and_connect_to_server () + i != specified_servers.end (); + ++i) + { +- // If we have an ip address and port number, then just use the one we've +- // been given. Otherwise, check for matching online servers and try their ++ // If we have an ip address and were given a port number, then just use the one we've ++ // been given. Otherwise, check for matching compatible online servers and try their + // ip addresses and ports. +- if (i->hasAddress() && i->port() != 0) ++ if (i->hasAddress() && i->fully_specified) + add_server_info (*i, server_list); + else + { +@@ -1145,8 +1158,8 @@ compile_server_client::find_and_connect_to_server () + + // If no specific server (port) has been specified, + // then we'll need the servers to be +- // compatible and possible trusted as signers as well. +- if (i->port() == 0) ++ // compatible and possibly trusted as signers as well. ++ if (! i->fully_specified) + { + get_or_keep_compatible_server_info (s, online_servers, true/*keep*/); + if (! pr_contains (s.privilege, pr_stapdev)) +@@ -1227,7 +1240,7 @@ compile_server_client::find_and_connect_to_server () + + int + compile_server_client::compile_using_server ( +- const vector<compile_server_info> &servers ++ vector<compile_server_info> &servers + ) + { + // Make sure NSPR is initialized. Must be done before NSS is initialized +@@ -1275,14 +1288,16 @@ compile_server_client::compile_using_server ( + server_zipfile = s.tmpdir + "/server.zip"; + + // Try each server in turn. +- for (vector<compile_server_info>::const_iterator j = servers.begin (); ++ for (vector<compile_server_info>::iterator j = servers.begin (); + j != servers.end (); + ++j) + { + // At a minimum we need an ip_address along with a port + // number in order to contact the server. +- if (! j->hasAddress() || j->port() == 0) ++ if (! j->hasAddress() || j->port == 0) + continue; ++ // Set the port within the address. ++ j->setAddressPort (j->port); + + if (s.verbose >= 2) + clog << _F("Attempting SSL connection with %s\n" +@@ -1673,7 +1688,7 @@ static void + add_server_trust ( + systemtap_session &s, + const string &cert_db_path, +- const vector<compile_server_info> &server_list ++ vector<compile_server_info> &server_list + ) + { + // Get a list of servers already trusted. This opens the database, so do it +@@ -1716,7 +1731,7 @@ add_server_trust ( + // Iterate over the servers to become trusted. Contact each one and + // add it to the list of trusted servers if it is not already trusted. + // client_connect will issue any error messages. +- for (vector<compile_server_info>::const_iterator server = server_list.begin(); ++ for (vector<compile_server_info>::iterator server = server_list.begin(); + server != server_list.end (); + ++server) + { +@@ -1735,10 +1750,14 @@ add_server_trust ( + trust_already_in_place (*server, server_list, cert_db_path, false/*revoking*/); + continue; + } ++ + // At a minimum we need an ip_address along with a port + // number in order to contact the server. +- if (! server->hasAddress() || server->port() == 0) ++ if (! server->hasAddress() || server->port == 0) + continue; ++ // Set the port within the address. ++ server->setAddressPort (server->port); ++ + int rc = client_connect (*server, NULL, NULL, "permanent"); + if (rc != SUCCESS) + { +@@ -2076,8 +2095,8 @@ ostream &operator<< (ostream &s, const compile_server_info &i) + else + s << "offline"; + s << " port="; +- if (i.port() != 0) +- s << i.port(); ++ if (i.port != 0) ++ s << i.port; + else + s << "unknown"; + s << " sysinfo=\""; +@@ -2586,7 +2605,8 @@ isPort (const char *pstr, compile_server_info &server_info) + clog << _F("Invalid port number specified: %s", pstr) << endl; + return false; + } +- server_info.setPort (p); ++ server_info.port = p; ++ server_info.fully_specified = true; + return true; + } + +@@ -2665,8 +2685,10 @@ isIPv6 (const string &server, compile_server_info &server_info) + if (! empty && components.size() != 8) + return false; // Not a valid IPv6 address + +- // Calls to setPort and isPort need to know that this is an IPv6 address. +- server_info.address.raw.family = PR_AF_INET6; ++ // Try to convert the string to an address. ++ PRStatus prStatus = PR_StringToNetAddr (ip.c_str(), & server_info.address); ++ if (prStatus != PR_SUCCESS) ++ return false; + + // Examine the optional port + if (portIx != string::npos) +@@ -2683,10 +2705,8 @@ isIPv6 (const string &server, compile_server_info &server_info) + } + } + else +- server_info.setPort (0); ++ server_info.port = 0; + +- // Treat the ip address string like a host name. +- server_info.host_name = ip; + return true; // valid IPv6 address. + } + +@@ -2703,20 +2723,20 @@ isIPv4 (const string &server, compile_server_info &server_info) + if (components.size() > 2) + return false; // Not a valid IPv4 address + +- // Separate the host from the port (if any). +- string host; ++ // Separate the address from the port (if any). ++ string addr; + string port; + if (components.size() <= 1) +- host = server; ++ addr = server; + else { +- host = components[0]; ++ addr = components[0]; + port = components[1]; + } + +- // Separate the host components. ++ // Separate the address components. + // There must be exactly 4 components. + components.clear (); +- tokenize (server, components, "."); ++ tokenize (addr, components, "."); + if (components.size() != 4) + return false; // Not a valid IPv4 address + +@@ -2732,8 +2752,10 @@ isIPv4 (const string &server, compile_server_info &server_info) + return false; // Not a valid IPv4 address + } + +- // Calls to setPort and isPort need to know that this is an IPv4 address. +- server_info.address.raw.family = PR_AF_INET; ++ // Try to convert the string to an address. ++ PRStatus prStatus = PR_StringToNetAddr (addr.c_str(), & server_info.address); ++ if (prStatus != PR_SUCCESS) ++ return false; + + // Examine the optional port + if (! port.empty ()) { +@@ -2741,10 +2763,8 @@ isIPv4 (const string &server, compile_server_info &server_info) + return false; // not a valid port + } + else +- server_info.setPort (0); ++ server_info.port = 0; + +- // Treat the ip address string like a host name. +- server_info.host_name = host; + return true; // valid IPv4 address. + } + +@@ -2754,8 +2774,6 @@ isCertSerialNumber (const string &server, compile_server_info &server_info) + // This function assumes that we have already ruled out the server spec being an IPv6 address. + // Certificate serial numbers are 5 fields separated by colons plus an optional 6th decimal + // field specifying a port. +- // Assume IPv4 (for now) when storing the port. +- server_info.address.raw.family = PR_AF_INET; + assert (! server.empty()); + string host = server; + vector<string> components; +@@ -2782,8 +2800,6 @@ isDomain (const string &server, compile_server_info &server_info) + { + // Accept one or two components separated by a colon. The first will be the domain name and + // the second must a port number. +- // Assume IPv4 (for now) when storing the port. +- server_info.address.raw.family = PR_AF_INET; + assert (! server.empty()); + string host = server; + vector<string> components; +@@ -2858,50 +2874,69 @@ get_specified_server_info ( + // Check for IPv6 addresses first. It reduces the amount of checking necessary for + // certificate serial numbers. + compile_server_info server_info; +- vector<compile_server_info> known_servers; ++ vector<compile_server_info> resolved_servers; + if (isIPv6 (server, server_info) || isIPv4 (server, server_info) || +- isDomain (server, server_info)) ++ isCertSerialNumber (server, server_info)) + { +- // Resolve this host and add any information that is discovered. +- // Try to augment the resolved servers with information about known servers. +- // There may be no intersection. +- get_all_server_info (s, known_servers); +- +- vector<compile_server_info> resolved_servers; ++ // An address or cert serial number has been specified. ++ // No resolution is needed. ++ resolved_servers.push_back (server_info); ++ } ++ else if (isDomain (server, server_info)) ++ { ++ // Try to resolve the given name. + resolve_host (s, server_info, resolved_servers); +- +- vector<compile_server_info> common_servers = resolved_servers; +- keep_common_server_info (known_servers, common_servers); +- if (! common_servers.empty ()) +- add_server_info (common_servers, resolved_servers); +- +- if (s.verbose >= 3) +- { +- clog << _F("Servers matching %s: ", server.c_str()) << endl; +- clog << resolved_servers; +- } +- add_server_info (resolved_servers, specified_servers); +- } +- else if (isCertSerialNumber (server, server_info)) +- { +- // The host could not be resolved. Try resolving it as a certificate serial +- // number. Look for all known servers with this serial number and (optional) +- // port number. +- get_all_server_info (s, known_servers); +- keep_server_info_with_cert_and_port (s, server_info, known_servers); +- if (s.verbose >= 3) +- { +- clog << _F("Servers matching %s: ", server.c_str()) << endl; +- clog << known_servers; +- } +- +- add_server_info (known_servers, specified_servers); + } + else + { + clog << _F("Invalid server specification for --use-server: %s", server.c_str()) + << endl; ++ continue; + } ++ ++ // Now examine the server(s) identified and add them to the list of specified ++ // servers. ++ vector<compile_server_info> known_servers; ++ vector<compile_server_info> new_servers; ++ for (vector<compile_server_info>::iterator i = resolved_servers.begin(); ++ i != resolved_servers.end(); ++ ++i) ++ { ++ // If this item was fully specified, then just add it. ++ if (i->fully_specified) ++ add_server_info (*i, new_servers); ++ else { ++ // It was not fully specified, so we need additional info. Try ++ // to get it by matching what we have against other known servers. ++ if (known_servers.empty ()) ++ get_all_server_info (s, known_servers); ++ ++ // See if this server spec matches that of a known server ++ vector<compile_server_info> matched_servers = known_servers; ++ keep_common_server_info (*i, matched_servers); ++ ++ // If this server spec matches one or more known servers, then add the ++ // augmented info to the specified_servers. Otherwise, if this server ++ // spec is complete, then add it directly. Otherwise this server spec ++ // is incomplete. ++ if (! matched_servers.empty()) ++ add_server_info (matched_servers, new_servers); ++ else if (i->isComplete ()) ++ add_server_info (*i, new_servers); ++ else if (s.verbose >= 3) ++ clog << _("Incomplete server spec: ") << *i << endl; ++ } ++ } ++ ++ if (s.verbose >= 3) ++ { ++ clog << _F("Servers matching %s: ", server.c_str()) << endl; ++ clog << new_servers; ++ } ++ ++ // Add the newly identified servers to the list. ++ if (! new_servers.empty()) ++ add_server_info (new_servers, specified_servers); + } // Loop over --use-server options + } // -- use-server specified + +@@ -3087,13 +3122,16 @@ keep_server_info_with_cert_and_port ( + continue; + } + if (servers[i].certinfo == server.certinfo && +- (servers[i].port() == 0 || server.port() == 0 || +- servers[i].port() == server.port())) ++ (servers[i].port == 0 || server.port == 0 || ++ servers[i].port == server.port)) + { + // If the server is not online, then use the specified + // port, if any. +- if (servers[i].port() == 0) +- servers[i].setPort (server.port()); ++ if (servers[i].port == 0) ++ { ++ servers[i].port = server.port; ++ servers[i].fully_specified = server.fully_specified; ++ } + ++i; + continue; + } +@@ -3110,8 +3148,8 @@ resolve_host ( + vector<compile_server_info> &resolved_servers + ) + { +- vector<compile_server_info>& cached_servers = cscache(s)->resolved_servers[server.host_name]; +- if (cached_servers.empty ()) ++ vector<resolved_host>& cached_hosts = cscache(s)->resolved_hosts[server.host_name]; ++ if (cached_hosts.empty ()) + { + // The server's host_name member is a string containing either a host name or an ip address. + // Either is acceptable for lookup. +@@ -3128,10 +3166,8 @@ resolve_host ( + // Failure to resolve will result in an appropriate message later, if other methods fail. + if (rc != 0) + { +- // At a minimum, return the information we were given. + if (s.verbose >= 6) + clog << _F("%s not found: %s", lookup_name, gai_strerror (rc)) << endl; +- add_server_info (server, cached_servers); + } + else + { +@@ -3139,28 +3175,23 @@ resolve_host ( + assert (addr_info); + for (const struct addrinfo *ai = addr_info; ai != NULL; ai = ai->ai_next) + { +- // Start with the info we were given. +- compile_server_info new_server = server; ++ PRNetAddr new_address; + + // We support IPv4 and IPv6, Ignore other protocols, + if (ai->ai_family == AF_INET) + { + // IPv4 Address + struct sockaddr_in *ip = (struct sockaddr_in *)ai->ai_addr; +- new_server.address.inet.family = PR_AF_INET; +- if (ip->sin_port != 0) +- new_server.address.inet.port = ip->sin_port; +- new_server.address.inet.ip = ip->sin_addr.s_addr; ++ new_address.inet.family = PR_AF_INET; ++ new_address.inet.ip = ip->sin_addr.s_addr; + } + else if (ai->ai_family == AF_INET6) + { + // IPv6 Address + struct sockaddr_in6 *ip = (struct sockaddr_in6 *)ai->ai_addr; +- new_server.address.ipv6.family = PR_AF_INET6; +- if (ip->sin6_port != 0) +- new_server.address.ipv6.port = ip->sin6_port; +- new_server.address.ipv6.scope_id = ip->sin6_scope_id; +- copyAddress (new_server.address.ipv6.ip, ip->sin6_addr); ++ new_address.ipv6.family = PR_AF_INET6; ++ new_address.ipv6.scope_id = ip->sin6_scope_id; ++ copyAddress (new_address.ipv6.ip, ip->sin6_addr); + } + else + continue; +@@ -3169,25 +3200,54 @@ resolve_host ( + char hbuf[NI_MAXHOST]; + int status = getnameinfo (ai->ai_addr, ai->ai_addrlen, hbuf, sizeof (hbuf), NULL, 0, + NI_NAMEREQD | NI_IDN); +- if (status == 0) +- new_server.host_name = hbuf; ++ if (status != 0) ++ hbuf[0] = '\0'; + +- // Add the new resolved server to the list. +- add_server_info (new_server, cached_servers); ++ resolved_host *new_host = new resolved_host(hbuf, new_address); ++ cached_hosts.push_back(*new_host); + } + } + if (addr_info) + freeaddrinfo (addr_info); // free the linked list +- +- if (s.verbose >= 6) +- { +- clog << _F("%s resolves to:", lookup_name) << endl; +- clog << cached_servers; +- } + } + +- // Add the information, but not duplicates. +- add_server_info (cached_servers, resolved_servers); ++ // If no addresses were resolved, then return the info we were given. ++ if (cached_hosts.empty()) ++ add_server_info (server, resolved_servers); ++ else { ++ // We will add a new server for each address resolved ++ vector<compile_server_info> new_servers; ++ for (vector<resolved_host>::const_iterator it = cached_hosts.begin(); ++ it != cached_hosts.end(); ++it) ++ { ++ // Start with the info we were given ++ compile_server_info new_server = server; ++ ++ // NB: do not overwrite port info ++ if (it->address.raw.family == AF_INET) ++ { ++ new_server.address.inet.family = PR_AF_INET; ++ new_server.address.inet.ip = it->address.inet.ip; ++ } ++ else // AF_INET6 ++ { ++ new_server.address.ipv6.family = PR_AF_INET6; ++ new_server.address.ipv6.scope_id = it->address.ipv6.scope_id; ++ new_server.address.ipv6.ip = it->address.ipv6.ip; ++ } ++ if (!it->host_name.empty()) ++ new_server.host_name = it->host_name; ++ add_server_info (new_server, new_servers); ++ } ++ ++ if (s.verbose >= 6) ++ { ++ clog << _F("%s resolves to:", server.host_name.c_str()) << endl; ++ clog << new_servers; ++ } ++ ++ add_server_info (new_servers, resolved_servers); ++ } + } + + #if HAVE_AVAHI +@@ -3268,12 +3328,12 @@ void resolve_callback( + // We support both IPv4 and IPv6. Ignore other protocols. + if (protocol == AVAHI_PROTO_INET6) { + info.address.ipv6.family = PR_AF_INET6; +- info.address.ipv6.port = htons (port); + info.address.ipv6.scope_id = interface; ++ info.port = port; + } + else if (protocol == AVAHI_PROTO_INET) { + info.address.inet.family = PR_AF_INET; +- info.address.inet.port = htons (port); ++ info.port = port; + } + else + break; +@@ -3388,7 +3448,6 @@ get_or_keep_online_server_info ( + online_servers.push_back (compile_server_info ()); + #if HAVE_AVAHI + // Must predeclare these due to jumping on error to fail: +- unsigned limit; + vector<compile_server_info> avahi_servers; + + // Initialize. +@@ -3449,25 +3508,6 @@ get_or_keep_online_server_info ( + clog << avahi_servers; + } + +- // Resolve each server discovered, in case there are alternate ways to reach them +- // (e.g. localhost). +- limit = avahi_servers.size (); +- for (unsigned i = 0; i < limit; ++i) +- { +- compile_server_info &avahi_server = avahi_servers[i]; +- +- // Delete the domain, if it is '.local' +- string &host_name = avahi_server.host_name; +- string::size_type dot_index = host_name.find ('.'); +- assert (dot_index != 0); +- string domain = host_name.substr (dot_index + 1); +- if (domain == "local") +- host_name = host_name.substr (0, dot_index); +- +- // Add it to the list of servers, unless it is duplicate. +- resolve_host (s, avahi_server, online_servers); +- } +- + // Merge with the list of servers, as obtained by avahi. + add_server_info (avahi_servers, online_servers); + +@@ -3619,15 +3659,19 @@ merge_server_info ( + compile_server_info &target + ) + { +- if (target.host_name.empty ()) ++ // Copy the host name if the source has one. ++ if (! source.host_name.empty()) + target.host_name = source.host_name; + // Copy the address unconditionally, if the source has an address, even if they are already + // equal. The source address may be an IPv6 address with a scope_id that the target is missing. + assert (! target.hasAddress () || ! source.hasAddress () || source.address == target.address); + if (source.hasAddress ()) + copyNetAddr (target.address, source.address); +- if (target.port() == 0) +- target.setPort (source.port()); ++ if (target.port == 0) ++ { ++ target.port = source.port; ++ target.fully_specified = source.fully_specified; ++ } + if (target.sysinfo.empty ()) + target.sysinfo = source.sysinfo; + if (target.version.empty ()) +diff --git a/csclient.h b/csclient.h +index b7eeda4..e4508ea 100644 +--- a/csclient.h ++++ b/csclient.h +@@ -1,5 +1,5 @@ + // -*- C++ -*- +-// Copyright (C) 2010-2011 Red Hat Inc. ++// Copyright (C) 2010-2014 Red Hat Inc. + // + // This file is part of systemtap, and is free software. You can + // redistribute it and/or modify it under the terms of the GNU General +@@ -35,7 +35,7 @@ private: + ); + int add_package_args (); + int add_package_arg (const std::string &arg); +- int compile_using_server (const std::vector<compile_server_info> &servers); ++ int compile_using_server (std::vector<compile_server_info> &servers); + int add_localization_variables(); + + int read_from_file (const std::string &fname, int &data); +diff --git a/nsscommon.cxx b/nsscommon.cxx +index 70aac54..78e38b0 100644 +--- a/nsscommon.cxx ++++ b/nsscommon.cxx +@@ -1,7 +1,7 @@ + /* + Common functions used by the NSS-aware code in systemtap. + +- Copyright (C) 2009-2013 Red Hat Inc. ++ Copyright (C) 2009-2014 Red Hat Inc. + + This file is part of systemtap, and is free software. You can + redistribute it and/or modify it under the terms of the GNU General Public +@@ -998,12 +998,19 @@ gen_cert_db (const string &db_path, const string &extraDnsNames, bool use_passwo + goto error; + } + +- // Now, generate the cert. We need our host name and the supplied additional dns names (if any). ++ // For the cert, we need our host name. + struct utsname utsname; + uname (& utsname); + dnsNames = utsname.nodename; ++ ++ // Because avahi identifies hosts using a ".local" domain, add one to the list of names. ++ dnsNames += string(",") + dnsNames + ".local"; ++ ++ // Add any extra names that were supplied. + if (! extraDnsNames.empty ()) + dnsNames += "," + extraDnsNames; ++ ++ // Now, generate the cert. + cert = create_cert (cr, dnsNames); + CERT_DestroyCertificateRequest (cr); + if (! cert) +diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp +index d4e4d85..64bbed1 100644 +--- a/testsuite/lib/systemtap.exp ++++ b/testsuite/lib/systemtap.exp +@@ -244,6 +244,7 @@ proc setup_server { args } { + } + + # Make sure that stap can find the server. ++ exec sleep 1 + set use_server --use-server + set res [catch { exec stap --list-servers=online,trusted,compatible >& stap-list-servers.out } looksee] + verbose -log "stap --list-servers returned: res==$res" +diff --git a/testsuite/systemtap.server/client.exp b/testsuite/systemtap.server/client.exp +index f0d0728..41a06cc 100644 +--- a/testsuite/systemtap.server/client.exp ++++ b/testsuite/systemtap.server/client.exp +@@ -1,3 +1,6 @@ ++# In this test, we are using arrays as sets. The key itself does not matter, ++# only the value ++ + # many of these tests use as_root + if {! [installtest_p]} { return } + if {! [nss_p]} { return } +@@ -5,37 +8,111 @@ if {! [nss_p]} { return } + # Let's start with a clean slate in terms of trust. + exec rm -fr $env(SYSTEMTAP_DIR)/ssl + +-# Compare two arrays. If equal, return 1, otherwise 0. +-# (Borrowed from http://wiki.tcl.tk/1032.) +-proc array_compare {array1 array2} { +- upvar 1 $array1 foo $array2 bar ++# arr given as list (e.g. [array_has [array get myarr] elem]) ++proc array_has {arr elem} { + +- if {![array exists foo]} { +- return -code error "$array1 is not an array" +- } +- if {![array exists bar]} { +- return -code error "$array2 is not an array" +- } +- if {[array size foo] != [array size bar]} { +- return 0 +- } ++ array set foo $arr + if {[array size foo] == 0} { ++ return 0 ++ } ++ ++ foreach {key val} [array get foo] { ++ if {[string equal $val $elem]} { ++ return 1 ++ } ++ } ++ ++ return 0 ++} ++ ++# Check if array1 is a subset of array2. Returns 1 if yes, otherwise 0. ++# (Modified from http://wiki.tcl.tk/1032.) ++proc array_in {array1 array2} { ++ upvar 1 $array1 sub $array2 super ++ ++ if {![array exists sub]} { ++ return -code error "$array1 is not an array" ++ } ++ if {![array exists super]} { ++ return -code error "$array2 is not an array" ++ } ++ if {[array size sub] > [array size super]} { ++ return 0 ++ } ++ if {[array size sub] == 0} { + return 1 + } + +- set keys [lsort -unique [concat [array names foo] [array names bar]]] +- if {[llength $keys] != [array size foo]} { +- return 0 +- } +- +- foreach key $keys { +- if {$foo($key) ne $bar($key)} { ++ foreach key [array names sub] { ++ if {![array_has [array get super] $sub($key)]} { + return 0 + } + } + return 1 + } + ++# Check if array1 and array2 have all the same elements ++proc array_equal {array1 array2} { ++ upvar 1 $array1 foo $array2 bar ++ return [array_in foo bar] \ ++ && [array_in bar foo] ++} ++ ++# Returns the union of the three arrays ++proc array_union {array1 array2 array3} { ++ upvar 1 $array1 foo $array2 bar $array3 baz ++ array unset ::union ++ ++ if {![array exists foo]} { ++ return -code error "$array1 is not an array" ++ } ++ if {![array exists bar]} { ++ return -code error "$array2 is not an array" ++ } ++ if {![array exists baz]} { ++ return -code error "$array3 is not an array" ++ } ++ ++ set n 0 ++ foreach key [array names foo] { ++ set ::union($n) $foo($key) ++ incr n ++ } ++ foreach key [array names bar] { ++ if {![array_has [array get ::union] $bar($key)]} { ++ set ::union($n) $bar($key) ++ incr n ++ } ++ } ++ foreach key [array names baz] { ++ if {![array_has [array get ::union] $baz($key)]} { ++ set ::union($n) $baz($key) ++ incr n ++ } ++ } ++} ++ ++# Returns all the elements in array_new not in array_old ++proc array_diff {array_new array_old} { ++ upvar 1 $array_new anew $array_old aold ++ array unset ::diff ++ ++ if {![array exists anew]} { ++ return -code error "$array_new is not an array" ++ } ++ if {![array exists aold]} { ++ return -code error "$array_old is not an array" ++ } ++ ++ set n 0 ++ foreach key [array names anew] { ++ if {![array_has [array get aold] $anew($key)]} { ++ set ::diff($n) $anew($key) ++ incr n ++ } ++ } ++} ++ + # Test the --list-servers option and return an array of the servers found. + proc list_servers { TEST_NAME SERVER_SPEC args } { + set failed 0 +@@ -82,7 +159,6 @@ proc list_servers { TEST_NAME SERVER_SPEC args } { + # Sometimes, we'll see a server running from the last test, if it + # hasn't quite died yet. So, make sure we get the same result twice. + list_servers "List existing online servers" online +-array unset eos1 + array set existing_online_servers [array get servers] + set i 0 + while {1} { +@@ -94,9 +170,9 @@ while {1} { + fail "List existing online servers: never got stable" + return + } +- ++ + verbose -log "verify existing online servers - attempt $i: [array size existing_online_servers] [array size eos2]" +- if {[array_compare existing_online_servers eos2]} { ++ if {[array_equal existing_online_servers eos2]} { + # Arrays are equal, we're done + break + } +@@ -120,37 +196,23 @@ list_servers "List all existing servers" all + array unset all_existing_servers + array set all_existing_servers [array get servers] + +-set test "Verify existing online server list" +-if {[array_compare existing_online_servers all_existing_servers]} { +- pass "$test" +-} else { +- fail "$test" +-} ++# First we create a union ++array_union existing_online_servers \ ++ existing_trusted_servers \ ++ existing_signing_servers ++array set existing_unioned_servers [array get union] + +-set test "Verify existing trusted server list" +-if {[array_compare existing_trusted_servers all_existing_servers]} { +- pass "$test" +-} else { +- fail "$test" +-} +- +-set test "Verify existing signing server list" +-if {[array_compare existing_signing_servers all_existing_servers]} { +- pass "$test" +-} else { +- fail "$test" +-} +- +-set test "Verify all existing server list" +-if {[array_compare existing_online_servers all_existing_servers]} { ++# Now we can compare ++set test "Verify existing server list" ++if {[array_equal existing_unioned_servers all_existing_servers]} { + pass "$test" + } else { + fail "$test" + } + + list_servers "List existing online servers (before start)" online +-array unset existing_online_servers1 +-array set existing_online_servers1 [array get servers] ++array unset existing_online_servers ++array set existing_online_servers [array get servers] + + # Now start our own server and make sure we can work with it. + if {! [setup_server] || $avahi_ok_p != 1} { +@@ -159,31 +221,22 @@ if {! [setup_server] || $avahi_ok_p != 1} { + } + + # Our server should now appear online, separate from the previously discovered +-# online servers. Note that our server could generate serveral listings +-# because it could appear at more than one ip address, ++# online servers. Note that our server could generate serveral listings because ++# it could appear at more than one ip address, + list_servers "List current online servers" online + array unset current_online_servers + array set current_online_servers [array get servers] + ++# array_diff will give us all the servers in current not in existing ++array_diff current_online_servers existing_online_servers ++array unset new_online_servers ++array set new_online_servers [array get diff] ++ + set test "New online servers" +-set n 0 +-foreach idx1 [array names current_online_servers] { +- set found 0 +- foreach idx2 [array names existing_online_servers] { +- if {"$existing_online_servers($idx2)" == "$current_online_servers($idx1)"} { +- set found 1 +- break +- } +- } +- if {$found == 0} { +- set new_online_servers($n) "$current_online_servers($idx1)" +- incr n +- } +-} +-if {$n == 0} { +- fail "$test" +-} else { ++if {[array size new_online_servers] > 0} { + pass "$test" ++} else { ++ fail "$test" + } + + # Our server should now be trusted, separate from the previously discovered +@@ -192,48 +245,27 @@ list_servers "List current trusted servers" online,trusted + array unset current_trusted_servers + array set current_trusted_servers [array get servers] + ++# array_diff will give us all the servers in current not in existing ++array_diff current_trusted_servers existing_trusted_servers ++array unset new_trusted_servers ++array set new_trusted_servers [array get diff] ++ + set test "New trusted servers" +-set n 0 +-foreach idx1 [array names current_trusted_servers] { +- set found 0 +- foreach idx2 [array names existing_trusted_servers] { +- if {"$existing_trusted_servers($idx2)" == "$current_trusted_servers($idx1)"} { +- set found 1 +- break +- } +- } +- if {$found == 0} { +- set new_trusted_servers($n) "$current_trusted_servers($idx1)" +- incr n +- } +-} +-if {$n == 0} { +- fail "$test" +-} else { ++if {[array size new_trusted_servers] > 0} { + pass "$test" ++} else { ++ fail "$test" + } + + # The new servers should automatically be trusted, so the new_trusted_servers +-# array should be a subset of the new_online_servers +-# array, but not necessarilty vice-versa, since new servers may have come +-# online independently of our testing. ++# array should be a subset of the new_online_servers array, but not necessarily ++# vice-versa, since new servers may have come online independently of our ++# testing. + set test "Verify new trusted server list" +-set failed 0 +-foreach idx1 [array names new_trusted_servers] { +- set found 0 +- foreach idx2 [array names new_online_servers] { +- if {"$new_trusted_servers($idx1)" == "$new_online_servers($idx2)"} { +- set found 1 +- break +- } +- } +- if {$found == 0} { +- set failed 1 +- fail "$test $idx1" +- } +-} +-if {$failed == 0} { ++if {[array_in new_trusted_servers new_online_servers]} { + pass "$test" ++} else { ++ fail "$test" + } + + # The newly trusted servers represent the server we just started. +@@ -247,7 +279,7 @@ array unset current_signing_servers + array set current_signing_servers [array get servers] + + set test "No new signing servers" +-if {[array_compare current_signing_servers existing_signing_servers]} { ++if {[array_equal current_signing_servers existing_signing_servers]} { + pass "$test" + } else { + fail "$test" +@@ -287,7 +319,7 @@ array unset current_trusted_servers + array set current_trusted_servers [array get servers] + + set test "No longer trusted after revokation by host name" +-if {[array_compare current_trusted_servers existing_trusted_servers]} { ++if {[array_equal current_trusted_servers existing_trusted_servers]} { + pass "$test" + } else { + fail "$test" +@@ -320,54 +352,24 @@ list_servers "List current trusted servers after reinstatement by ip address" on + array unset current_trusted_servers + array set current_trusted_servers [array get servers] + ++array_diff current_trusted_servers existing_trusted_servers ++array unset new_trusted_servers ++array set new_trusted_servers [array get diff] ++ + set test "New trusted servers after reinstatement by ip address" +-array unset new_trusted_servers +-set n 0 +-foreach idx1 [array names current_trusted_servers] { +- set found 0 +- foreach idx2 [array names existing_trusted_servers] { +- if {"$existing_trusted_servers($idx2)" == "$current_trusted_servers($idx1)"} { +- set found 1 +- break +- } +- } +- if {$found == 0} { +- set new_trusted_servers($n) "$current_trusted_servers($idx1)" +- incr n +- } +-} +-if {$n == 0} { +- fail "$test" +-} else { ++if {[array size new_trusted_servers] > 0} { + pass "$test" ++} else { ++ fail "$test" + } + + # The new_trusted_servers array should now match the our_servers array, since + # the our_servers array is a copy of the original new_trusted_servers array. +-set test "Number of new trusted servers matches after reinstatement by ip address" +-if {[array size new_trusted_servers] == [array size our_servers]} { +- pass "$test" +-} else { +- fail "$test" +-} + set test "New trusted servers matches after reinstatement by ip address" +-set n 0 +-foreach idx1 [array names new_trusted_servers] { +- set found 0 +- foreach idx2 [array names our_servers] { +- if {"$our_servers($idx2)" == "$new_trusted_servers($idx1)"} { +- set found 1 +- break +- } +- } +- if {$found == 1} { +- incr n +- } +-} +-if {$n != [array size new_trusted_servers]} { +- fail "$test" +-} else { ++if {[array_equal new_trusted_servers our_servers]} { + pass "$test" ++} else { ++ fail "$test" + } + + # Trust our server as a module signer. This must be done as root. Specify +@@ -394,28 +396,18 @@ list_servers "List current online signing servers" online,signer + array unset current_signing_servers + array set current_signing_servers [array get servers] + ++array_diff current_signing_servers existing_signing_servers ++array unset new_signing_servers ++array set new_signing_servers [array get diff] ++ + set test "New signing servers" +-set n 0 +-foreach idx1 [array names current_signing_servers] { +- set found 0 +- foreach idx2 [array names existing_signing_servers] { +- if {"$existing_signing_servers($idx2)" == "$current_signing_servers($idx1)"} { +- set found 1 +- break +- } +- } +- if {$found == 0} { +- set new_signing_servers($n) "$current_signing_servers($idx1)" +- incr n +- } +-} + if {$effective_pid == 0} { + setup_xfail *-*-* + } +-if {$n == 0} { +- fail "$test" +-} else { ++if {[array size new_signing_servers] > 0} { + pass "$test" ++} else { ++ fail "$test" + } + + # The new_signing_servers array should now match the our_servers array, since +@@ -428,26 +420,13 @@ if {$effective_pid == 0} { + if {[array size new_signing_servers] == [array size our_servers]} { + pass "$test" + set test "New signing servers matches" +- set n 0 +- foreach idx1 [array names new_signing_servers] { +- set found 0 +- foreach idx2 [array names our_servers] { +- if {"$our_servers($idx2)" == "$new_signing_servers($idx1)"} { +- set found 1 +- break +- } +- } +- if {$found == 1} { +- incr n +- } +- } + if {$effective_pid == 0} { + setup_xfail *-*-* + } +- if {$n != [array size new_signing_servers]} { +- fail "$test" +- } else { ++ if {[array_equal new_signing_servers our_servers]} { + pass "$test" ++ } else { ++ fail "$test" + } + } else { + fail "$test" +@@ -594,7 +573,7 @@ array unset current_signing_servers + array set current_signing_servers [array get servers] + + set test "No longer trusted as a signer after revokation" +-if {[array_compare current_signing_servers existing_signing_servers]} { ++if {[array_in current_signing_servers existing_signing_servers]} { + pass "$test" + } else { + fail "$test" +diff --git a/testsuite/systemtap.server/server_args.exp b/testsuite/systemtap.server/server_args.exp +index 2f5deed..91536a5 100644 +--- a/testsuite/systemtap.server/server_args.exp ++++ b/testsuite/systemtap.server/server_args.exp +@@ -66,20 +66,23 @@ proc stap_direct_and_with_client {stap options} { + verbose -log $res_stap_client + + # Now check the output +- set skip 0 ++ set skip_hostname_mode 0 + set n 0 + set expected [split $res_stap "\n"] + set received [split $res_stap_client "\n"] + foreach line $received { +- # Instructed to skip a line? +- if {$skip} { +- set skip [expr $skip - 1] +- verbose -log "skipping: $line" +- continue ++ # Instructed to skip hostnames? ++ if {$skip_hostname_mode} { ++ if {[regexp {^ \S+$} $line]} { ++ verbose -log "skipping: $line" ++ continue ++ } else { ++ set skip_hostname_mode 0 ++ } + } + # Ignore warnings about the domain name on the certificate not matching + if {[regexp {^WARNING: The domain name, [^,]*, does not match the DNS name\(s\) on the server certificate:} $line]} { +- set skip 1 ++ set skip_hostname_mode 1 + verbose -log "skipping: $line" + continue + } +diff --git a/testsuite/systemtap.server/server_concurrency.exp b/testsuite/systemtap.server/server_concurrency.exp +index dbacb51..a31415b 100644 +--- a/testsuite/systemtap.server/server_concurrency.exp ++++ b/testsuite/systemtap.server/server_concurrency.exp +@@ -26,7 +26,7 @@ if {! [setup_server --max-threads 6]} { + set server_port 0 + set f [open $logfile] + set matched 0 +-verbose -log "Server ouput: " ++verbose -log "Server output: " + while {1} { + set line [gets $f] + if {[eof $f]} { +@@ -34,7 +34,7 @@ while {1} { + break + } + verbose -log "$line" +- if { [regexp {^.*Using network port (\d*)$} $line matched server_port ] } { ++ if { [regexp {^.*Using network address .+:(\d+)$} $line matched server_port ] } { + close $f + break + } +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1051649.2.patch b/SOURCES/rhbz1051649.2.patch new file mode 100644 index 0000000..35bed36 --- /dev/null +++ b/SOURCES/rhbz1051649.2.patch @@ -0,0 +1,63 @@ +commit b728b27964bbded79d0f8c07c0bdbf6acd8fe2db +Author: Jonathan Lebon <jlebon@redhat.com> +Date: Wed Jan 8 16:38:57 2014 -0500 + + autoreconf + +diff --git a/Makefile.in b/Makefile.in +index 2c543f1..e6d03fa 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -120,8 +120,10 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/initscript/config.systemtap.in \ + $(top_srcdir)/initscript/config.stap-server.in \ + $(top_srcdir)/initscript/systemtap.in \ +- $(top_srcdir)/initscript/stap-server.in $(srcdir)/run-stap.in \ +- $(srcdir)/dtrace.in $(top_srcdir)/staprun/guest/stapshd.in \ ++ $(top_srcdir)/initscript/stap-server.in \ ++ $(top_srcdir)/initscript/99stap/module-setup.sh.in \ ++ $(srcdir)/run-stap.in $(srcdir)/dtrace.in \ ++ $(top_srcdir)/staprun/guest/stapshd.in \ + $(top_srcdir)/staprun/guest/stapsh-daemon.in \ + $(top_srcdir)/staprun/guest/stapsh@.service.in depcomp \ + $(am__noinst_HEADERS_DIST) $(oldinclude_HEADERS) +@@ -139,7 +141,8 @@ mkinstalldirs = $(install_sh) -d + CONFIG_HEADER = config.h + CONFIG_CLEAN_FILES = includes/sys/sdt-config.h \ + initscript/config.systemtap initscript/config.stap-server \ +- initscript/systemtap initscript/stap-server run-stap dtrace \ ++ initscript/systemtap initscript/stap-server \ ++ initscript/99stap/module-setup.sh run-stap dtrace \ + staprun/guest/stapshd staprun/guest/stapsh-daemon \ + staprun/guest/stapsh@.service + CONFIG_CLEAN_VPATH_FILES = +@@ -724,6 +727,8 @@ initscript/systemtap: $(top_builddir)/config.status $(top_srcdir)/initscript/sys + cd $(top_builddir) && $(SHELL) ./config.status $@ + initscript/stap-server: $(top_builddir)/config.status $(top_srcdir)/initscript/stap-server.in + cd $(top_builddir) && $(SHELL) ./config.status $@ ++initscript/99stap/module-setup.sh: $(top_builddir)/config.status $(top_srcdir)/initscript/99stap/module-setup.sh.in ++ cd $(top_builddir) && $(SHELL) ./config.status $@ + run-stap: $(top_builddir)/config.status $(srcdir)/run-stap.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + dtrace: $(top_builddir)/config.status $(srcdir)/dtrace.in +diff --git a/configure b/configure +index af7c03a..69231af 100755 +--- a/configure ++++ b/configure +@@ -11420,7 +11420,7 @@ STAP_PREFIX="$stap_prefix" + + ac_config_headers="$ac_config_headers config.h:config.in" + +-ac_config_files="$ac_config_files Makefile doc/Makefile man/Makefile doc/beginners/Makefile doc/SystemTap_Tapset_Reference/Makefile man/stappaths.7 initscript/config.systemtap initscript/config.stap-server initscript/systemtap initscript/stap-server" ++ac_config_files="$ac_config_files Makefile doc/Makefile man/Makefile doc/beginners/Makefile doc/SystemTap_Tapset_Reference/Makefile man/stappaths.7 initscript/config.systemtap initscript/config.stap-server initscript/systemtap initscript/stap-server initscript/99stap/module-setup.sh" + + + +@@ -12296,6 +12296,7 @@ do + "initscript/config.stap-server") CONFIG_FILES="$CONFIG_FILES initscript/config.stap-server" ;; + "initscript/systemtap") CONFIG_FILES="$CONFIG_FILES initscript/systemtap" ;; + "initscript/stap-server") CONFIG_FILES="$CONFIG_FILES initscript/stap-server" ;; ++ "initscript/99stap/module-setup.sh") CONFIG_FILES="$CONFIG_FILES initscript/99stap/module-setup.sh" ;; + "run-stap") CONFIG_FILES="$CONFIG_FILES run-stap" ;; + "dtrace") CONFIG_FILES="$CONFIG_FILES dtrace" ;; + "stapdyn/Makefile") CONFIG_FILES="$CONFIG_FILES stapdyn/Makefile" ;; diff --git a/SOURCES/rhbz1051649.3.patch b/SOURCES/rhbz1051649.3.patch new file mode 100644 index 0000000..47e4fce --- /dev/null +++ b/SOURCES/rhbz1051649.3.patch @@ -0,0 +1,990 @@ +From f19a1ef476349c42861cfecf6dc5afdbedc9191f Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Mon, 10 Feb 2014 10:20:56 -0500 +Subject: [PATCH] man/systemtap.8.in: new man page to replace README + +This man page replaces the README.systemtap text file. The content is +almost the same. A lot of rephrasing, some restructuring, and some +clarifications that weren't present in the original document. + +- man/systemtap.8.in: new man page +- initscript/README.systemtap: remove it +- initscript/systemtap.in: add hint to man page + +- configure.ac: add man/systemtap.8.in in AC_CONFIG_FILES macro +- man/Makefile.am: add systemtap.8 to man_MANS +- systemtap.spec: replace README by man page in systemtap-initscript pkg + $files list +--- + configure.ac | 2 +- + initscript/README.systemtap | 447 -------------------------------------------- + initscript/systemtap.in | 4 +- + man/Makefile.am | 2 +- + man/systemtap.8.in | 439 +++++++++++++++++++++++++++++++++++++++++++ + systemtap.spec | 2 +- + 6 files changed, 445 insertions(+), 451 deletions(-) + delete mode 100644 initscript/README.systemtap + create mode 100644 man/systemtap.8.in + +diff --git a/configure.ac b/configure.ac +index 3f22549..9cc1e50 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -682,7 +682,7 @@ AC_SUBST(STAP_PREFIX, "$stap_prefix") + AC_CONFIG_HEADERS([config.h:config.in]) + AC_CONFIG_FILES([Makefile doc/Makefile man/Makefile \ + doc/beginners/Makefile doc/SystemTap_Tapset_Reference/Makefile \ +-man/stappaths.7 \ ++man/stappaths.7 man/systemtap.8 \ + initscript/config.systemtap initscript/config.stap-server \ + initscript/systemtap initscript/stap-server \ + initscript/99stap/module-setup.sh ]) +diff --git a/initscript/README.systemtap b/initscript/README.systemtap +deleted file mode 100644 +index 9dd1ee6..0000000 +--- a/initscript/README.systemtap ++++ /dev/null +@@ -1,447 +0,0 @@ +-Systemtap initscript +-Version 0.2.1 +-Author: Masami Hiramatsu <mhiramat@redhat.com> +- +-INDEX +-===== +-1. Introduction +-2. Usage +-3. Files +-4. Configuration Format +-5. How to use +- +-1. Introduction +-=============== +-Systemtap initscript aims to provide +-- running systemtap script as a service with dependency. +-- easy way to control(start/stop) those scripts individually. +-The dependency means that which user-defined systemtap script is required by +-other script (Here the scripts don't include tapsets). This dependency +-will be useful for users who use -DRELAY_HOST and -DRELAY_GUEST. +- +-2. Usage +-======== +-2.1 Synopsis +- +-/sbin/service systemtap {start|stop|restart|status|compile|onboot|cleanup} \ +- [-r kernelrelease] [-o path.img] [-b] [-c config] [-R] [-y] [script(s)] +- +-2.2 Commands +- You have to specify one of the below commands. +- +-2.2.1 start +- Run script(s). If the script(s) is already started, the command will be +- ignored. If it fails to start, return FAIL. If AUTOCOMPILE option is 'yes' +- (see 4.1.9), this will try to compile or update the specified script when +- one of the below condition is true. +- - compiled cache file does not exist. +- - mtime (modified time stamp) of original script file is newer than compiled +- script cache. +- - script options which is used when compiling(see 4.2.1) has been changed. +- - result of `uname -a` has been changed. +- If no scripts specified from command line, it starts all scripts in the script +- directory or the scripts specified by DEFAULT_START in config (see 4.1.10). +- +-2.2.2 stop +- Stop script(s). If the script(s) is already stopped, this will be ignored. +- If it fails to stop, return FAIL. +- If no scripts specified from command line, it stops all running scripts. +- +-2.2.3 restart +- Stop and start script(s) again. +- +-2.2.4 status +- Show running script(s) status and dependency. +- +-2.2.5 compile +- Compile script(s) on the specified kernel. This command takes '-r' option +- which specifies the release of the kernel(see 2.3.4) on which you would +- like to compile script(s). This command asks user whether it can overwrite +- existing caches. +- +-2.2.6 onboot +- Make script(s) part of the initramfs so that they are started earlier during +- the boot process. Only works on dracut-based systems. This command also takes +- the '-r' option. If '-r' is omitted, the initramfs is created for the running +- kernel. If '-o path.img' is given, the initramfs is created at 'path.img' (must +- be an absolute path). Otherwise, defaults to '/boot/initramfs-KVER.img', where +- KVER is `uname -r` if the '-r' option is omitted, or the given kernel version +- otherwise. +- +- If the output file already exists, it is overwritten, unless the -b switch is +- given, in which case the file is appended '.bak' rather than overwritten. Note +- however that if a '.bak' version already exists, it will not be overwritten. +- +- If no scripts are specified on the command-line, the initramfs will be created +- without including any scripts at all (i.e. no extra systemtap files added). +- +- Warning: do not use the stap -o option with onboot scripts because the +- script is started before the root filesystem is even mounted. Increase the +- buffer size if more space is needed. +- +-2.2.7 cleanup +- Cleanup compiled script(s) from cache directory(see 3.4). This command also +- takes '-r' option. If '-r' option is omitted, cleanup all caches for running +- kernel. This command asks user whether it can remove caches. +- +-2.3 Options +- Systemtap initscript can have some options. However, since user can't pass +- these options on boot, these options are only for testing or managing scripts +- after booting. +- +-2.3.1 -c config_path +- You can specify configuration path of this initscript. +- +-2.3.2 script(s) +- You can specify individual scripts to the commands. If you omit to specify +- any script, systemtap initscript will execute the command with all scripts +- in the script directory (except 'start', 'stop', and 'onboot' commands, see +- 2.2.1, 2.2.2, and 2.2.6). +- +-2.3.3 -R +- If this option is specified, systemtap initscript will try to solve +- dependency of specified script(s). This option is always set if you don't +- specify any script(s) from command line. +- +-2.3.4 -r kernelrelease +- You can specify release version of the kernel(e.g. 2.6.26.1). This option +- is valid only with compile, onboot, and cleanup commands. +- +-2.3.5 -y +- Answer yes for all questions. +- +-2.3.6 -o path.img +- Specify the path of the initramfs image. Otherwise, the default is +- '/boot/initramfs-KVER.img', where KVER is `uname -r` if the '-r' option is +- omitted, or the given kernel version otherwise. This option is only valid with +- the onboot command. +- +-2.3.7 -b +- If present, will backup an existing initramfs image by renaming it with a +- '.bak' extension. Otherwise, the initramfs is overwritten without backing up. +- This option is only valid with the onboot command. +- +-2.4 Misc +-2.4.1 Service Priority +- Each initscript has execution priority. Since user would like to trace +- other services by using systemtap, systemtap initscript should have the +- highest priority. +- +-3. Files +-======== +-3.1 initscript +- /etc/init.d/systemtap +- +- This file is an executable bash script. +- +-3.2 Configurations +- Configuration files are written in bash script. +- +-3.2.1 Global config file +- /etc/systemtap/config +- +- This config file is for global parameters(see 4.1). +- +-3.2.2 Script config files +- /etc/systemtap/conf.d/*.conf +- +- The config files under this directory are for each scripts or script groups +- (see 4.2). +- +-3.3 Script directory +- /etc/systemtap/script.d/ +- +- Systemtap initscript finds systemtap scripts from this directory. +- +-3.3.1 Scripts in the directory +- /etc/systemtap/script.d/<script-name>.stp +- +- Systemtap scripts stored in the script directory must have ".stp" suffix. +- +-3.4 Cache directory +- /var/cache/systemtap/<kernel-version>/ +- +- Systemtap initscript stores compiled scripts in this directory. +- +-3.4.1 Compiled scripts (or script caches) +- /var/cache/systemtap/<kernel-version>/<script-name>.ko +- /var/cache/systemtap/<kernel-version>/<script-name>.opts +- +- *.ko file is the compiled script, and *.opts is the file which stores +- stap options and uname -a. +- +-3.5 Message Log +- /var/log/systemtap.log +- +- All messages including compilation errors and detailed messages are sent +- to this file. +- Some error and warning messages are also sent to console and syslogd (syslog +- output is optional, because this service will start before syslog). +- +-3.6 Status files +- /var/run/systemtap/<script-name> +- +-3.7 Dracut +- Files related to dracut/initramfs creation +- +-3.7.1 Dracut stap module directory +- /usr/lib/dracut/modules.d/99stap +- +- These files permit SystemTap modules to be included in the initramfs. +- +-4. Configuration Format +-======================= +-Configuration file allows us +-- specifying options for each script +-- supporting flight recorder mode (on file or memory) +- +-4.1 Global Parameters +- +-4.1.1 SCRIPT_PATH +- Specify the absolute path of the script directory. +- (default: /etc/systemtap/script.d) +- +-4.1.2 CONFIG_PATH +- Specify the absolute path of the script config directory. +- (default: /etc/systemtap/conf.d) +- +-4.1.3 CACHE_PATH +- Specify the absolute path of the parent directory of the cache directory. +- (default: /var/cache/systemtap) +- +-4.1.4 TEMP_PATH +- Specify the absolute path of the temporary directory on which systemtap +- initscript make temporary directories to compile scripts. +- (default: /tmp) +- +-4.1.5 STAT_PATH +- Specify the absolute path of the running status directory. +- (default: /var/run/systemtap) +- +-4.1.6 LOG_FILE +- Specify the absolute path of the log file +- (default: /var/log/systemtap.log) +- +-4.1.7 PASSALL +- If this is set 'yes', systemtap initscript will fail when it fails +- to run one of the scripts. If not, systemtap initscript will not +- fail(just warn). +- (default: yes) +- +-4.1.8 RECURSIVE +- If this is set 'yes', systemtap initscript will always follow script +- dependencies. This means, you don't need to specify '-R' option. This flag is +- effective only if you specify script(s) from command line. +- (default: no) +- +-4.1.9 AUTOCOMPILE +- If this is set 'yes', systemtap initscript automatically tries to compile +- specified script if there is no valid cache. Otherwise, it just fails to +- run script(s). +- (default: yes) +- +-4.1.10 DEFAULT_START +- Specify scripts which will be started by default. If omitted (or empty), +- all scripts in the script directory will be started. +- (default: "") +- +-4.1.11 ALLOW_CACHEONLY +- If this is set 'yes', systemtap initscript list up cache-only scripts too. +- *NOTE*: systemtap initscript will load unexpected obsolete caches with this +- option. You should check cache directory before enabling this option. +- (default: no) +- +-4.1.12 LOG_BOOT_ERR +- Because boot-time scripts are run before the root filesystem is mounted, +- staprun's stderr cannot be logged to the LOG_FILE as usual (see 4.1.6). +- However, the log can instead be output to /var/run/systemtap/$script.log (which +- is accessible at boot-time) by setting LOG_BOOT_ERR to 'yes'. If STAT_PATH is +- different from the default, the log files will be moved there upon executing +- any of the initscript commands. +- +-4.2 Script Parameters +- +-4.2.1 <script-name>_OPT +- Specify options passed to stap command for each script. "script-name" is the +- name of the script file without the suffix extension(.stp). +- Some options are just ignored. And even if you don't specify -F option, +- systemtap initscript always add it for flight recorder mode. +- - Below options are ignored when compiling script. +- -p,-m,-r,-c,-x,-e,-s,-o,-h,-V,-k +- - Below options are ignored when starting script. +- -h,-V,-v,-t,-p,-I,-e,-R,-r,-m,-k,-g,-P,-D,-b,-u,-q,-w,-l,-d,-L,-F, and +- other long options. +- +-4.2.2 <script-name>_REQ +- Specify script dependency(which script this script requires). +- For example, "foo.stp" script requires(or run after) "bar.stp" script, set +- +- foo_REQ="bar" +- +- If the script requires many scripts, set all scripts separated by spaces. +- +- foo_REQ="bar baz" +- +-4.3 Configuration Example +- +-4.3.1 Global Config Example +---- +-SCRIPT_PATH=/var/systemtap/script.d/ +-PASSALL=yes +-RECURSIVE=no +---- +- +-4.3.2 Script Config Example +---- +-script1_OPT="-o /var/log/script1.out -DRELAYHOST=group1" +-script2_OPT="-DRELAYGUEST=group1" +-script2_REQ=script1 +---- +- +-5. How to use +-============= +- +-5.1 Package Installation +- After installing systemtap package, install systemtap-initscript package. +- # yum install systemtap-initscript +- This package will include initscript and default configuration file and +- other files. +- +-5.2 Script installation +-5.2.1 Installing script files +- Copy a systemtap script ("script1.stp") into script directory. +- # cp script1.stp /etc/systemtap/script.d/ +- +-5.2.2 Configuration script options +- Add configuration file to specify options. +- # vi /etc/systemtap/conf.d/group1 +- script1_OPT="-o /var/log/group1.log -DRELAYHOST=group1" +- +-5.2.3 Installing script file with dependency +- For example, a script("script2.stp") which shares buffer with another +- script("script1.stp"), there is a dependency. In this case, you just do +- as following. +- +- # cp script2.stp /etc/systemtap/script.d/ +- # vi /etc/systemtap/conf.d/group1 +- script2_OPT="-DRELAYGUEST=group1" +- script2_REQ=script1 +- +- In this case, if stap fails to run script1.stp, systemtap initscript will +- not run script2.stp. +- +-5.3 Testing +- After installing all scripts, please make sure to run service successfully. +- # service systemtap start +- # service systemtap stop +- If there is no error, we are ready to use it. +- +-5.4 Service Enabling +- After all test passed, enable systemtap initscript. +- # chkconfig systemtap on +- +-5.5 Adding script +-5.5.1 Installing and configuring new scripts +- Copy new systemtap script("script3.stp") into script directory. +- # cp script3.stp /etc/systemtap/script.d/ +- and configure it. +- # vi /etc/systemtap/conf.d/group1 +- script3_OPT="-DRELAYGUEST=group1" +- script3_REQ="script1" +- +-5.5.2 Start new script +- If you've already started systemtap initscript, just start new script. +- # service systemtap start script3 +- +-5.6 Deleting script +-5.6.1 Deleting old script +- Remove old script ("script2.stp") and remove configure lines +- # rm /etc/systemtap/script.d/script2.stp +- # vi /etc/systemtap/conf.d/group1 +- (delete script2_OPT and script2_REQ) +- +-5.6.2 Stopping old script and cleanup +- Stop old script. +- # service systemtap stop script2 +- And cleanup the script caches. +- # service systemtap cleanup script2 +- +-5.7 Updating kernel +- Usually, you don't need to do anything. Systemtap initscript checks the +- kernel version when starting the service, and compile scripts. +- (If you would like to use compiled scripts due to lack of compiler or +- debuginfo on the system, see 5.8) +- However, if you want to avoid compiling when booting system, you can prepare +- script caches for new kernel. +- # service systemtap compile -r <new kernel version> +- +-5.8 Using with compiled scripts +- Sometimes, production systems don't have any compilation environment. Even +- though, you can use systemtap initscript with compiled scripts as script +- caches, which are compiled on other machine (but same software environment). +- +-5.8.1 Preparing compiled scripts +- As described in 5.2, installing scripts and configure it on the compiling +- machine (which has compilation environment). +- After that, compile those scripts. +- # service systemtap compile -r <kernel-version> +- And package the compiled scripts and configuration file. +- # tar czf stap-scripts-<kernel-version>.tar.gz \ +- /var/cache/systemtap/<kernel-version> /etc/systemtap/conf.d/<config> +- And copy this package to the target machine. +- +-5.8.2 Installing pre-compiled scripts +- On the target machine, unpackage the compiled scripts into cache +- directory. +- # tar xzf stap-scripts-<kernel-version>.tar.gz -C /var/cache/systemtap/ +- # mv /var/cache/systemtap/<config> /etc/systemtap/conf.d/ +- At last, set AUTOCOMPILE=no and ALLOW_CACHEONLY=yes in config file. +- # vi /etc/systemtap/config +- AUTOCOMPILE=no +- ALLOW_CACHEONLY=yes +- +-5.9 Starting scripts during early-boot +- The initscript also allows you to start scripts earlier during the boot +- process by creating an initramfs containing the script's module. Your system +- must be dracut-based for this to work. Starting at this stage gives access to +- information otherwise very hard to obtain. +- +-5.9.1 Preparing the script +- As usual, place the script in /etc/systemtap/script.d and any configuration +- settings in /etc/systemtap/conf.d. (Note however that -o and -c are not +- supported). +- +-5.9.2 Adding to initramfs +- Simply run the command: +- # service systemtap onboot my_script +- If the script is not already compiled and cached, it will be done at this +- point. A new initramfs will then be created at the default location. You can +- specify the '-b' option to make sure that your current initramfs is backed up. +- You can then restart your system. See 2.2.6 for more information regarding the +- onboot command. +- +-5.9.3 Adding to a different initramfs +- Rather than taking the spot of the default initramfs, you may want to create a +- different initramfs for a one-time boot. You can do this using the -o option: +- # service systemtap onboot -o /boot/special_initramfs.img +- Once the initramfs is created, you can change the command-line options at +- boot-time so that the new image is used rather than the usual one. +- +-5.9.4 Creating an initramfs for a different kernel +- Just like the compile command, you can use the -r option to specify the kernel +- for which you would like to create the initramfs. This is useful when you are +- about to upgrade and would like to prepare in advance. For example: +- # service systemtap onboot -r 3.12.6-200.fc19.x86_64 my_script +- +-5.9.5 Removing from initramfs +- To remove all scripts from the initramfs, you can run: +- # service systemtap onboot +- (That is, without any scripts explicitly mentioned). This will simply create +- a standard initramfs without any SystemTap modules inserted. +- +-5.9.6 Troubleshooting +- There can be many reasons for which the module didn't insert or did not work as +- expected. It may be useful to turn on dracut debugging by adding 'rdinitdebug' to +- the kernel command-line and checking dmesg/journalctl -ae. Also, you can +- capture the stderr output of staprun by setting LOG_BOOT_ERR to 'yes' (see +- 4.1.12). +diff --git a/initscript/systemtap.in b/initscript/systemtap.in +index 5290f56..21f9018 100755 +--- a/initscript/systemtap.in ++++ b/initscript/systemtap.in +@@ -83,7 +83,7 @@ INITRAMFS= + BACKUP_INITRAMFS= + + echo_usage () { +- echo $"Usage: $prog {start|stop|status|restart|compile|onboot|cleanup|condrestart|try-restart|reload|force-reload} [option]" ++ echo $"Usage: $prog {start|stop|status|restart|compile|onboot|cleanup|condrestart|try-restart|reload|force-reload} [OPTIONS] [SCRIPTS]" + echo $"Options:" + echo $" -b : backup initramfs before overwriting" + echo $" -c configfile : specify config file" +@@ -92,6 +92,8 @@ echo_usage () { + echo $" -R : recursively dependency checking" + echo $" -y : answer yes for all questions" + echo $" script(s) : specify systemtap scripts" ++ echo $"" ++ echo $"See systemtap(8) for full documentation" + } + + #----------------------------------------------------------------- +diff --git a/man/Makefile.am b/man/Makefile.am +index b626481..ef0892e 100644 +--- a/man/Makefile.am ++++ b/man/Makefile.am +@@ -4,7 +4,7 @@ + AUTOMAKE_OPTIONS = no-dist foreign + + man_MANS = stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap \ +- dtrace.1 stap-merge.1 stappaths.7 stapsh.8 ++ dtrace.1 stap-merge.1 stappaths.7 stapsh.8 systemtap.8 + + # NB: this doesn't work, apparently because make doesn't like + # file names with :: in them, misinterpreting them as some kind +diff --git a/man/systemtap.8.in b/man/systemtap.8.in +new file mode 100644 +index 0000000..cea3868 +--- /dev/null ++++ b/man/systemtap.8.in +@@ -0,0 +1,439 @@ ++.\" -*- nroff -*- ++.TH SYSTEMTAP 8 ++.SH NAME ++systemtap \- SystemTap initscript service ++ ++.\" macros ++.de SAMPLE ++ ++.nr oldin \\n(.i ++.br ++.RS ++.nf ++.nh ++.. ++.de ESAMPLE ++.hy ++.fi ++.RE ++.in \\n[oldin]u ++ ++.. ++ ++.SH SYNOPSIS ++.B service systemtap ++.IR COMMAND " [" OPTIONS "] [" SCRIPT ...] ++ ++.SH DESCRIPTION ++The SystemTap initscript aims to provide a way to run scripts as a service and ++easily control them individually. Scripts can be configured to start upon manual ++request, or during system startup. On dracut-based systems, it is also possible ++to integrate scripts in the initramfs and have them start during early-boot. ++ ++There are various parameters and options available to modify global behaviour, ++as well as script behaviour. Dependencies between scripts can be established so ++that starting one starts others (especially convenient when using the ++-DRELAY_HOST and -DRELAY_GUEST options of \fIstap\fR(1)). ++ ++The configuration file of the initscript is located at ++\fB@sysconfdir@/systemtap/config\fR. Acceptable parameters are detailed in the ++GLOBAL PARAMETERS section. ++ ++Scripts must be placed in the \fB@sysconfdir@/systemtap/script.d\fR directory ++and must have a \fB.stp\fR extension. When referring to them on the command-line ++however, there in no need to include the \fB.stp\fR extension. The scripts ++directory may be changed by setting the SCRIPT_PATH parameter in the ++configuration file. ++ ++.SH COMMANDS ++One of the commands below must be specified: ++ ++.TP ++.B start ++Start \fISCRIPT\fRs. If no scripts are specified, start the scripts specified by ++the DEFAULT_START configuration. If DEFAULT_START is not set, start all scripts ++in the script directory. For scripts already started, the command is ignored. ++The command will fail if the scripts fail to start (see also the PASSALL ++configuration). ++ ++If the AUTOCOMPILE configuration is on, the command will try to compile or ++update the specified scripts when one of the below conditions is true: ++.RS ++.IP - 2 ++The compiled cache file does not exist. ++.IP - ++The mtime (modified timestamp) of the original script file is newer than the ++time of the compiled script cache. ++.IP - ++The specified stap options used to compile the script has been changed (see ++also the SCRIPT PARAMETERS section). ++.IP - ++The result of `uname -a` has been changed. ++.RE ++ ++.TP ++.B stop ++Stop \fISCRIPT\fRs. If no scripts are specified, stop all running scripts. For ++scripts already stopped, the command is ignored. The command will fail if the ++scripts fail to stop (see also the PASSALL configuration). ++ ++.TP ++.B restart ++Stop and start \fISCRIPT\fRs. ++ ++.TP ++.B status ++Show the state of \fISCRIPT\fRs and their dependencies. ++ ++.TP ++.B compile ++Compile \fISCRIPT\fRs but do not start them. If the scripts have already been ++compiled, prompt for confirmation before overwriting cache. Compile for the ++current kernel, or the kernel release specified by the \fB-r\fR option. ++ ++.TP ++.B onboot ++Make \fISCRIPT\fRs part of the initramfs so that they are started earlier during ++the boot process. This command is only available on dracut-based systems. If no ++scripts are specified, create a normal initramfs devoid of any SystemTap files. ++ ++The initramfs is created for the current kernel, or the kernel release specified ++by the \fB-r\fR option. The path of the created initramfs defaults ++to \fB/boot/initramfs-KVER.img\fR, where KVER is the output of `uname -r`. Use ++the \fB-o\fR option to specify a different path. ++ ++If the output file already exists, it is overwritten, unless the \fB-b\fR switch ++is given, in which case the file is appended \fB.bak\fR rather than overwritten. ++However, if there is already a \fB.bak\fR version of the file, the backup will ++not be overwritten. ++ ++WARNING: do not use the \fB-o\fR option of \fIstap\fR(1) with onboot scripts ++because the script is started before the root filesystem is even mounted. ++Increase the buffer size if more space is needed. ++ ++.TP ++.B cleanup ++Delete the compiled \fISCRIPT\fRs from cache. If no scripts are specified, then ++all compiled scripts are deleted. Only the cache for the current kernel is ++deleted, or the kernel release specified by the \fB-r\fR option. Prompt for ++confirmation before deleting. ++ ++.SH OPTIONS ++Many of the commands can also take options. However, since users can't pass ++these options on boot, they are only meant for managing scripts after boot and ++for testing. Available options are: ++ ++.TP ++.BI "-c " CONFIG_FILE ++Specify a different configuration file in place of the default one. ++ ++.TP ++.B -R ++When using the \fBstart\fR and \fBstop\fR commands, also include the scripts' ++dependencies (recursively). ++ ++.TP ++.BI "-r " KERNEL_RELEASE ++When using the \fBcompile\fR, \fBonboot\fR, and \fBcleanup\fR commands, specify ++the target kernel version rather than using the current one. Must be in the same ++format as `uname -r`. ++ ++.TP ++.B -y ++Answer yes for all prompts. ++ ++.TP ++.BI "-o " PATH.IMG ++When using the \fBonboot\fR command, specify the output path of the created ++initramfs. ++ ++.TP ++.B -b ++When using the \fBonboot\fR command, backup an existing initramfs image by ++adding a \fB.bak\fR extension rather than overwriting it. Without this option, ++the initramfs is overwritten. ++ ++.SH GLOBAL PARAMETERS ++These parameters affect the general behaviour of the SystemTap initscript ++service. They can be specified in the configuration file. ++ ++.TP ++.B SCRIPT_PATH ++Specify the absolute path of the script directory. These are the scripts on ++which the initscript can operate. Scripts must have the \fB.stp\fR extension. ++The default path is \fB@sysconfdir@/systemtap/script.d\fR. ++ ++.TP ++.B CONFIG_PATH ++Specify the absolute path of the script configuration directory. These ++configuration files contain options for specific scripts. They must have the ++\fB.conf\fR extension. The default path is \fB@sysconfdir@/systemtap/conf.d\fR. ++ ++.TP ++.B CACHE_PATH ++Specify the absolute path of the cache directory. The default path is ++\fB@localstatedir@/cache/systemtap\fR. ++ ++.TP ++.B TEMP_PATH ++Specify the absolute path of the temporary directory in which SystemTap ++makes temporary directories to compile scripts. The default path is \fB/tmp\fR. ++ ++.TP ++.B STAT_PATH ++Specify the absolute path of the directory containing PID files used to track ++the status of SystemTap scripts. The default path is ++\fB@localstatedir@/run/systemtap\fR. ++ ++.TP ++.B LOG_FILE ++Specify the absolute path of the log file. All messages are sent to this file, ++including compilation and runtime errors. The default path is ++\fB@localstatedir@/log/systemtap.log\fR. ++ ++.TP ++.B PASSALL ++If this is set \fByes\fR, initscript commands that operate on multiple scripts ++will report as failed when the action could not be performed on at least one ++script. If set to \fBno\fR, only a warning is emitted. The default is \fByes\fR. ++ ++.TP ++.B RECURSIVE ++If this is set \fByes\fR, the initscript will always follow script dependencies ++recursively. This means that there is no need to specify the \fB-R\fR option. ++This flag is effective only if you specify script(s) from the command-line. The ++default is \fBno\fR. ++ ++.TP ++.B AUTOCOMPILE ++If this is set \fByes\fR, the initscript automatically tries to compile ++specified scripts when needed if there is no valid cache. Otherwise, the related ++command simply fails. The default is \fByes\fR. ++ ++.TP ++.B DEFAULT_START ++Specify scripts which will be started by default. If omitted (or empty), all ++scripts in the script directory will be started. The default is \fB""\fR. ++ ++.TP ++.B ALLOW_CACHEONLY ++If this is set \fByes\fR, the initscript will also allow operating on scripts ++that are located in the cache directory, but not in the script directory. The ++default is \fBno\fR. ++ ++WARNING: the initscript may load unexpected obsolete caches with this option. ++The cache directory should be checked before enabling this option. ++ ++.TP ++.B LOG_BOOT_ERR ++Because boot-time scripts are run before the root filesystem is mounted, ++staprun's stderr cannot be logged to the LOG_FILE as usual. However, the log ++can instead be output to /var/run/systemtap/$script.log by setting LOG_BOOT_ERR ++to \fByes\fR. If STAT_PATH is different from the default, the log files will be ++moved there upon executing any of the initscript commands. The default is ++\fBno\fR. ++ ++.PP ++Here is a global configuration file example: ++.SAMPLE ++SCRIPT_PATH=/var/systemtap/script.d/ ++PASSALL=yes ++RECURSIVE=no ++.ESAMPLE ++ ++.SH SCRIPT PARAMETERS ++These parameters affect the compilation or runtime behaviour of specific ++SystemTap scripts. They must be placed in config files located in the ++CONFIG_PATH directory. ++ ++.TP ++.B <SCRIPT>_OPT ++Specify options passed to the \fIstap\fR(1) command for the SCRIPT. Here, SCRIPT ++is the name of the script file without the \fB.stp\fR extension. Note that the ++\fB-F\fR option is always added. ++ ++The following options are ignored when compiling scripts: -p, -m, -r, -c, -x, ++-e, -s, -o, -h, -V, -k. ++ ++The following options are ignored when running starting scripts: -h, -V, -v, -t, ++-p, -I, -e, -R, -r, -m, -k, -g, -P, -D, -b, -u, -q, -w, -l, -d, -L, -F, and all ++long options. ++ ++.TP ++.B <SCRIPT>_REQ ++Specify script dependencies (i.e. which script this script requires). For ++example, if foo.stp requires (or needs to run after) bar.stp, set ++.SAMPLE ++foo_REQ="bar" ++.ESAMPLE ++Specify multiple scripts by separating their names by spaces. ++ ++.PP ++Here is a script configuration file example: ++.SAMPLE ++script1_OPT="-o /var/log/script1.out -DRELAY_HOST=group1" ++script2_OPT="-DRELAY_GUEST=group1" ++script2_REQ="script1" ++.ESAMPLE ++ ++.SH EXAMPLES ++ ++.TP ++.B INSTALLING SCRIPTS ++We first copy a SystemTap script (e.g. "script1.stp") into the script directory: ++.SAMPLE ++\fB#\fR cp script1.stp /etc/systemtap/script.d/ ++.ESAMPLE ++We can then set any script options, for example: ++.SAMPLE ++\fB#\fR vi /etc/systemtap/conf.d/group1 ++script1_OPT="-o /var/log/group1.out -DRELAY_HOST=group1" ++.ESAMPLE ++If we then install a script (e.g. "script2.stp") which shares a buffer with ++script1, there is a dependency. In this case, we can do the following: ++.SAMPLE ++\fB#\fR cp script2.stp /etc/systemtap/script.d/ ++\fB#\fR vi /etc/systemtap/conf.d/group1 ++script2_OPT="-DRELAY_GUEST=group1" ++script2_REQ="script1" ++.ESAMPLE ++This way, if \fIstap\fR(1) fails to run script1, the initscript will not even ++try to run script2. ++ ++.TP ++.B TESTING ++After installing scripts, we can test that they work by simply doing: ++.SAMPLE ++\fB#\fR service systemtap start ++\fB#\fR service systemtap stop ++.ESAMPLE ++We could be more specific as well, for example: ++.SAMPLE ++\fB#\fR service systemtap start script1 ++\fB#\fR service systemtap stop script1 ++.ESAMPLE ++If there were no errors, we are ready to use it. ++ ++.TP ++.B ENABLING SERVICE ++After we're satisfied with the scripts and their tests, we can enable the ++SystemTap initscript service: ++.SAMPLE ++\fB#\fR chkconfig systemtap on ++.ESAMPLE ++ ++.TP ++.B DELETING SCRIPTS ++Scripts are deleted by simply removing them from the script directory and ++removing any configuration lines specific to them: ++.SAMPLE ++\fB#\fR rm /etc/systemtap/script.d/script2.stp ++\fB#\fR vi /etc/systemtap/conf.d/group1 ++.ESAMPLE ++If the script is still running, we also need to stop it: ++.SAMPLE ++\fB#\fR service systemtap stop script2 ++.ESAMPLE ++We can then also remove the cache associated with the script: ++.SAMPLE ++\fB#\fR service systemtap cleanup script2 ++.ESAMPLE ++ ++.TP ++.B PREPARING FOR KERNEL UPDATES ++Usually, there is nothing to do when booting into a new kernel. The initscript ++will see that the kernel version is different and will compile the scripts. The ++compilation can be done beforehand as well to avoid having to compile during ++boot by using the \fB-r\fR option: ++.SAMPLE ++\fB#\fR service systemtap compile myscript -r <NEW_KERNEL_VERSION> ++.ESAMPLE ++ ++.TP ++.B IMPORTING COMPILED SCRIPTS ++For environments which lack compilation infrastructure (e.g. no compilers or ++debuginfo), such as a production system, the scripts can be compiled on another ++(development) machine and then transferred over to the production system: ++.SAMPLE ++\fB#\fR service systemtap compile myscript -r \\ ++.br ++> <KERNEL_VERSION_OF_TARGET_MACHINE> ++\fB#\fR tar czf stap-scripts-<kernel-version>.tar.gz \\ ++.br ++> /var/cache/systemtap/<kernel-version> \\ ++.br ++> /etc/systemtap/conf.d/<configfile> ++.ESAMPLE ++And then copy this package to the target machine and extract it. ++ ++.TP ++.B STARTING SCRIPTS DURING EARLY-BOOT ++The initscript also allows us to start scripts earlier during the boot process ++by creating an initramfs containing the script's module. The system must be ++dracut-based for this to work. Starting a script at this stage gives access to ++information otherwise very hard to obtain. ++ ++We first install the script by copying it into the script directory as usual and ++setting whatever options we'd like: ++.SAMPLE ++\fB#\fR cp myscript.stp /etc/systemtap/script.d ++\fB#\fR vi /etc/systemtap/conf.d/myscript.conf ++.ESAMPLE ++To add the script to the initramfs, we use the \fBonboot\fR command: ++.SAMPLE ++\fB#\fR service systemtap onboot myscript ++.ESAMPLE ++If the script is not already compiled and cached, it will be done at this point. ++A new initramfs will then be created at the default location. We can use the ++\fB-b\fR option to ensure that the existing initramfs is backed up. We can then ++restart the system. ++ ++.TP ++.B USING A DIFFERENT INITRAMFS ++If we would prefer to only start the script for one boot and not others, it ++might be easier to instead use the \fB-o\fR option to specify a different ++initramfs output file: ++.SAMPLE ++\fB#\fR service systemtap onboot myscript \\ ++> -o /boot/special_initramfs.img ++.ESAMPLE ++Once the initramfs is created, it's simply a matter of changing the command-line ++options at boot-time so that the new image is used rather than the usual one. ++ ++.TP ++.B CREATING AN INITRAMFS FOR A DIFFERENT KERNEL ++Just like the compile command, we can use the \fB-r\fR option to specify the ++kernel for which we want to create the initramfs. This is useful when we are ++about to upgrade and would like to prepare in advance. For example: ++.SAMPLE ++\fB#\fR service systemtap onboot myscript \\ ++> -r 3.12.6-200.fc19.x86_64 ++.ESAMPLE ++ ++.TP ++.B REMOVING SCRIPTS FROM THE INITRAMFS ++Finally, to remove all script from the initramfs, we simple run the \fBonboot\fR ++command without specifying any scripts: ++.SAMPLE ++\fB#\fR service systemtap onboot ++.ESAMPLE ++This will simply create a standard initramfs without any SystemTap modules ++inserted. ++ ++.TP ++.B TROUBLESHOOTING EARLY-BOOT ISSUES ++There can be many reasons for which the module didn't insert or did not work as ++expected. It may be useful to turn on dracut debugging by adding 'rdinitdebug' ++to the kernel command-line and checking dmesg/journalctl -ae. Also, the stderr ++output of staprun can be captured by setting the LOG_BOOT_ERR option to ++\fByes\fR. ++ ++.SH SEE ALSO ++.IR stap (1) ++ ++.SH BUGS ++Use the Bugzilla link of the project web page or our mailing list. ++.nh ++.BR http://sourceware.org/systemtap/ ", " <systemtap@sourceware.org> . ++.hy ++ +diff --git a/systemtap.spec b/systemtap.spec +index 41945bd..41c746d 100644 +--- a/systemtap.spec ++++ b/systemtap.spec +@@ -940,7 +940,7 @@ done + %config(noreplace) %{_sysconfdir}/systemtap/config + %dir %{_localstatedir}/cache/systemtap + %ghost %{_localstatedir}/run/systemtap +-%doc initscript/README.systemtap ++%{_mandir}/man8/systemtap.8* + %if %{with_dracut} + %dir %{dracutstap} + %{dracutstap}/* +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1051649.4.patch b/SOURCES/rhbz1051649.4.patch new file mode 100644 index 0000000..4c3932b --- /dev/null +++ b/SOURCES/rhbz1051649.4.patch @@ -0,0 +1,74 @@ +From b5c84307cd507c5fa8d7991e1b533d6983b07a73 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Mon, 10 Feb 2014 10:21:26 -0500 +Subject: [PATCH] autoreconf + +--- + configure | 3 ++- + man/Makefile.in | 8 +++++--- + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/configure b/configure +index 69231af..2a964c1 100755 +--- a/configure ++++ b/configure +@@ -11420,7 +11420,7 @@ STAP_PREFIX="$stap_prefix" + + ac_config_headers="$ac_config_headers config.h:config.in" + +-ac_config_files="$ac_config_files Makefile doc/Makefile man/Makefile doc/beginners/Makefile doc/SystemTap_Tapset_Reference/Makefile man/stappaths.7 initscript/config.systemtap initscript/config.stap-server initscript/systemtap initscript/stap-server initscript/99stap/module-setup.sh" ++ac_config_files="$ac_config_files Makefile doc/Makefile man/Makefile doc/beginners/Makefile doc/SystemTap_Tapset_Reference/Makefile man/stappaths.7 man/systemtap.8 initscript/config.systemtap initscript/config.stap-server initscript/systemtap initscript/stap-server initscript/99stap/module-setup.sh" + + + +@@ -12292,6 +12292,7 @@ do + "doc/beginners/Makefile") CONFIG_FILES="$CONFIG_FILES doc/beginners/Makefile" ;; + "doc/SystemTap_Tapset_Reference/Makefile") CONFIG_FILES="$CONFIG_FILES doc/SystemTap_Tapset_Reference/Makefile" ;; + "man/stappaths.7") CONFIG_FILES="$CONFIG_FILES man/stappaths.7" ;; ++ "man/systemtap.8") CONFIG_FILES="$CONFIG_FILES man/systemtap.8" ;; + "initscript/config.systemtap") CONFIG_FILES="$CONFIG_FILES initscript/config.systemtap" ;; + "initscript/config.stap-server") CONFIG_FILES="$CONFIG_FILES initscript/config.stap-server" ;; + "initscript/systemtap") CONFIG_FILES="$CONFIG_FILES initscript/systemtap" ;; +diff --git a/man/Makefile.in b/man/Makefile.in +index 42c56be..ae68814 100644 +--- a/man/Makefile.in ++++ b/man/Makefile.in +@@ -85,7 +85,7 @@ target_triplet = @target@ + @HAVE_LIBVIRT_TRUE@@HAVE_LIBXML2_TRUE@am__append_3 = stapvirt.1 + subdir = man + DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ +- $(srcdir)/stappaths.7.in ++ $(srcdir)/stappaths.7.in $(srcdir)/systemtap.8.in + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ +@@ -96,7 +96,7 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) + mkinstalldirs = $(install_sh) -d + CONFIG_HEADER = $(top_builddir)/config.h +-CONFIG_CLEAN_FILES = stappaths.7 ++CONFIG_CLEAN_FILES = stappaths.7 systemtap.8 + CONFIG_CLEAN_VPATH_FILES = + AM_V_P = $(am__v_P_@AM_V@) + am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +@@ -321,7 +321,7 @@ top_srcdir = @top_srcdir@ + AUTOMAKE_OPTIONS = no-dist foreign + man_MANS = stapprobes.3stap stapfuncs.3stap stapvars.3stap \ + stapex.3stap dtrace.1 stap-merge.1 stappaths.7 stapsh.8 \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ systemtap.8 $(am__append_1) $(am__append_2) $(am__append_3) + all: all-am + + .SUFFIXES: +@@ -357,6 +357,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__aclocal_m4_deps): + stappaths.7: $(top_builddir)/config.status $(srcdir)/stappaths.7.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ ++systemtap.8: $(top_builddir)/config.status $(srcdir)/systemtap.8.in ++ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + install-man1: $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1051649.5.patch b/SOURCES/rhbz1051649.5.patch new file mode 100644 index 0000000..db69d99 --- /dev/null +++ b/SOURCES/rhbz1051649.5.patch @@ -0,0 +1,147 @@ +From bb241c250cf74865382bfe099b550118d4badba0 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Wed, 26 Mar 2014 11:39:11 -0400 +Subject: [PATCH] initscript: use new-kernel-pkg after dracut + +With this patch, we now also call new-kernel-pkg --update after creating +the new image so that the bootloader is updated if need be (see also +BZ1051649#c9). + +This patch also includes some polishing re. console log output. +--- + initscript/systemtap.in | 54 ++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 45 insertions(+), 9 deletions(-) + +diff --git a/initscript/systemtap.in b/initscript/systemtap.in +index 21f9018..075226e 100755 +--- a/initscript/systemtap.in ++++ b/initscript/systemtap.in +@@ -37,6 +37,7 @@ STAPRUN=@bindir@/staprun + UNAME=/bin/uname + LSMOD=/sbin/lsmod + DRACUT=/sbin/dracut ++NEWKERNELPKG=/usr/sbin/new-kernel-pkg + + # Not actually used directly, but needed by + # stap dracut module for inclusion in initramfs +@@ -81,6 +82,7 @@ OPTS= + OPT_ASSUMEYES= + INITRAMFS= + BACKUP_INITRAMFS= ++EXPLICIT_INITRAMFS= + + echo_usage () { + echo $"Usage: $prog {start|stop|status|restart|compile|onboot|cleanup|condrestart|try-restart|reload|force-reload} [OPTIONS] [SCRIPTS]" +@@ -202,6 +204,9 @@ parse_args $OPTS + # Set default output file if not given as an option + if [ ! "$INITRAMFS" ]; then + INITRAMFS=/boot/initramfs-$KRELEASE.img ++else ++ # User explicitly specified an img file to output to ++ EXPLICIT_INITRAMFS=1 + fi + + # Include configs +@@ -738,9 +743,9 @@ compile () { + return 0 + } + +-# Writes info to $DRACUT_SRC, which the stap dracut module will source ++# Writes info to $DRACUT_SRC, which the stap dracut module will source. + # Includes all needed info such as location of stap/staprun, which +-# scripts to insert, and their options ++# scripts to insert, and their options. + update_dracut() { # scripts + local s opts + +@@ -773,20 +778,29 @@ update_dracut() { # scripts + backup_initramfs() { + # does target file exist? + if [ -f "$INITRAMFS" ]; then ++ clog + # don't overwrite an existing backup + if [ ! -f "$INITRAMFS.bak" ]; then + mv "$INITRAMFS" "$INITRAMFS.bak" +- clog "Renamed $INITRAMFS" +- clog " to $INITRAMFS.bak" ++ clog " Renamed $INITRAMFS" ++ clog " to $INITRAMFS.bak ... " -n + RESTORE_INITRAMFS_ON_FAIL=1 + else +- clog "Backup already exists: $INITRAMFS.bak" ++ clog " Backup already exists: $INITRAMFS.bak ... " -n + fi + fi + } + + onboot () { + local s ret ss ++ if [ ! -f "$NEWKERNELPKG" ]; then ++ clog "Could not find $NEWKERNELPKG" -n ++ do_failure "$NEWKERNELPKG not found" ++ clog ++ clog "This feature requires $NEWKERNELPKG." ++ clog "If it is located elsewhere, modify the \$NEWKERNELPKG parameter" -n ++ return 1 ++ fi + if [ ! -f "$DRACUT" ]; then + clog "Could not find $DRACUT" -n + do_failure "$DRACUT not found" +@@ -845,6 +859,9 @@ onboot () { + do_failure "Failed to make temporary file in $dir" + return 1 + fi ++ # Create the initramfs image. We could have combined this with the ++ # new-kernel-pkg call below using --dracut, but then we would have ++ # lost error-checking and our backing up facilities. + out=$($DRACUT --force $TMPINITRAMFS $KRELEASE 2>&1) + # dracut will report success even if some modules (e.g. stap) failed + # to install some files, so we need to be a bit more involved in +@@ -856,7 +873,7 @@ onboot () { + else + do_failure "See dracut log for more info" + fi +- echo # We need a new line ++ clog + if [ -f "$TMPINITRAMFS" ]; then + rm "$TMPINITRAMFS" + fi +@@ -864,13 +881,32 @@ onboot () { + # whatever initramfs they used to boot in is still there) + if [ "$RESTORE_INITRAMFS_ON_FAIL" ]; then + mv "$INITRAMFS.bak" "$INITRAMFS" +- clog "Renamed $INITRAMFS.bak" +- clog " to $INITRAMFS" ++ clog " Renamed $INITRAMFS.bak" ++ clog " to $INITRAMFS" + fi + return 1 + fi + mv "$TMPINITRAMFS" "$INITRAMFS" +- might_success "initramfs created" ++ # The initramfs is in place. If the user explicitly specified an ++ # output file using -o, then we should skip updating the bootloader ++ # (the output file may not even be in /boot/). ++ if [ "$EXPLICIT_INITRAMFS" ]; then ++ might_success "initramfs created" ++ clog ++ clog "NB: bootloader was not updated" -n ++ return 0 ++ fi ++ clog "done" ++ # We're installing the initramfs in the default location, so user ++ # expects the next boot to use it. Let's also update the bootloader. ++ clog " Updating bootloader ... " -n ++ logex $NEWKERNELPKG --initrdfile="$INITRAMFS" \ ++ --update $KRELEASE ++ if [ $? -ne 0 ]; then ++ do_failure "$NEWKERNELPKG exited with nonzero status" ++ return 1 ++ fi ++ might_success "initramfs created and bootloader updated" + return 0 + } + +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1051649.6.patch b/SOURCES/rhbz1051649.6.patch new file mode 100644 index 0000000..30aaa33 --- /dev/null +++ b/SOURCES/rhbz1051649.6.patch @@ -0,0 +1,57 @@ +From 65dc00af707a48948d08dd4fec97ecb22459dd0c Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Wed, 26 Mar 2014 13:56:20 -0400 +Subject: [PATCH] initscript: skip dracut stap module by default + +We previously always enabled the dracut stap module as long as there +were scripts to include. This can lead to issues since the params.conf +file may be obsolete/not in sync e.g. during a kernel update. We now +make the module an opt-in feature, and make the initscript explicit +specify its inclusion. +--- + initscript/99stap/module-setup.sh.in | 10 +++++++--- + initscript/systemtap.in | 6 ++---- + 2 files changed, 9 insertions(+), 7 deletions(-) + +diff --git a/initscript/99stap/module-setup.sh.in b/initscript/99stap/module-setup.sh.in +index 4f4583d..7b2b401 100644 +--- a/initscript/99stap/module-setup.sh.in ++++ b/initscript/99stap/module-setup.sh.in +@@ -5,10 +5,14 @@ + + # Return 0 --> install stap module + # Return 1 --> skip stap module ++# Return 255 --> install stap module only if explicitly requested + check() { +- # Install it if we have early-boot scripts +- [ "$ONBOOT_SCRIPTS" ] && return 0 +- return 1 ++ # Do not include stap module if there are no scripts to include ++ [ "$ONBOOT_SCRIPTS" ] || return 1 ++ # We're disabled by default: the initscript explicitly uses dracut's ++ # '--add stap' when creating the initramfs. Otherwise, we might be ++ # mistakenly included during e.g. kernel updates. ++ return 255 + } + + # We don't depend on anything +diff --git a/initscript/systemtap.in b/initscript/systemtap.in +index 075226e..ab882e9 100755 +--- a/initscript/systemtap.in ++++ b/initscript/systemtap.in +@@ -859,10 +859,8 @@ onboot () { + do_failure "Failed to make temporary file in $dir" + return 1 + fi +- # Create the initramfs image. We could have combined this with the +- # new-kernel-pkg call below using --dracut, but then we would have +- # lost error-checking and our backing up facilities. +- out=$($DRACUT --force $TMPINITRAMFS $KRELEASE 2>&1) ++ # Create the initramfs image with stap module enabled. ++ out=$($DRACUT --add stap --force $TMPINITRAMFS $KRELEASE 2>&1) + # dracut will report success even if some modules (e.g. stap) failed + # to install some files, so we need to be a bit more involved in + # checking for errors +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1051649.7.patch b/SOURCES/rhbz1051649.7.patch new file mode 100644 index 0000000..3f5bb16 --- /dev/null +++ b/SOURCES/rhbz1051649.7.patch @@ -0,0 +1,49 @@ +From bfb256e83ba00cbb44f7d115ebfcdd100821114d Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Wed, 26 Mar 2014 14:17:02 -0400 +Subject: [PATCH] systemtap.8: clarify docs regarding new-kernel-pkg + +--- + man/systemtap.8.in | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/man/systemtap.8.in b/man/systemtap.8.in +index cea3868..798a278 100644 +--- a/man/systemtap.8.in ++++ b/man/systemtap.8.in +@@ -98,9 +98,11 @@ the boot process. This command is only available on dracut-based systems. If no + scripts are specified, create a normal initramfs devoid of any SystemTap files. + + The initramfs is created for the current kernel, or the kernel release specified +-by the \fB-r\fR option. The path of the created initramfs defaults +-to \fB/boot/initramfs-KVER.img\fR, where KVER is the output of `uname -r`. Use +-the \fB-o\fR option to specify a different path. ++by the \fB-r\fR option. The path of the created initramfs defaults to ++\fB/boot/initramfs-KVER.img\fR, where KVER is the output of `uname -r`. The ++bootloader is also updated (using \fInew-kernel-pkg\fR(8)) to make the kernel ++entry use the new initramfs file. Use the \fB-o\fR option to specify a different ++path (the bootloader will not be updated). + + If the output file already exists, it is overwritten, unless the \fB-b\fR switch + is given, in which case the file is appended \fB.bak\fR rather than overwritten. +@@ -145,7 +147,7 @@ Answer yes for all prompts. + .TP + .BI "-o " PATH.IMG + When using the \fBonboot\fR command, specify the output path of the created +-initramfs. ++initramfs. When specified, the bootloader configuration is not updated. + + .TP + .B -b +@@ -430,6 +432,8 @@ output of staprun can be captured by setting the LOG_BOOT_ERR option to + + .SH SEE ALSO + .IR stap (1) ++.IR dracut (8) ++.IR new-kernel-pkg (8) + + .SH BUGS + Use the Bugzilla link of the project web page or our mailing list. +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1051649.8.patch b/SOURCES/rhbz1051649.8.patch new file mode 100644 index 0000000..8036866 --- /dev/null +++ b/SOURCES/rhbz1051649.8.patch @@ -0,0 +1,79 @@ +From ae91e3d552aff4f0e74662d055dae06ea55eb6bc Mon Sep 17 00:00:00 2001 +From: "Frank Ch. Eigler" <fche@redhat.com> +Date: Thu, 27 Mar 2014 21:29:04 -0400 +Subject: [PATCH] PR16766: kernel crash for failed-init module-notification + +Suppress the module_notifier callback for cases of failure of the +main generated systemtap module-initialization code, which checks +build-ids, privileges, etc. etc.; we don't want any module-notifier +callbacks after an error. + +* runtime/transport/transport.c: Don't call module-notifier stuff + if initialization failed. +* translate.cxx (emit_module_refresh): Emit code to suppress callback + payload if somehow the notifier got activated anyway. +--- + runtime/transport/transport.c | 20 ++++++++++++-------- + translate.cxx | 11 +++++++++++ + 2 files changed, 23 insertions(+), 8 deletions(-) + +diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c +index 1800764..e4d4d8e 100644 +--- a/runtime/transport/transport.c ++++ b/runtime/transport/transport.c +@@ -135,16 +135,20 @@ static void _stp_handle_start(struct _stp_msg_start *st) + + _stp_target = st->target; + st->res = systemtap_module_init(); +- if (st->res == 0) ++ if (st->res == 0) { + _stp_probes_started = 1; + +- /* Register the module notifier. */ +- if (!_stp_module_notifier_active) { +- int rc = register_module_notifier(& _stp_module_notifier_nb); +- if (rc == 0) +- _stp_module_notifier_active = 1; +- else +- _stp_warn ("Cannot register module notifier (%d)\n", rc); ++ /* Register the module notifier ... */ ++ /* NB: but not if the module_init stuff ++ failed: something nasty has happened, and ++ we want no further probing started. PR16766 */ ++ if (!_stp_module_notifier_active) { ++ int rc = register_module_notifier(& _stp_module_notifier_nb); ++ if (rc == 0) ++ _stp_module_notifier_active = 1; ++ else ++ _stp_warn ("Cannot register module notifier (%d)\n", rc); ++ } + } + + /* Called from the user context in response to a proc +diff --git a/translate.cxx b/translate.cxx +index 9903751..17dedd4 100644 +--- a/translate.cxx ++++ b/translate.cxx +@@ -1881,8 +1881,19 @@ c_unparser::emit_module_refresh () + { + o->newline() << "static void systemtap_module_refresh (void) {"; + o->newline(1) << "int i=0, j=0;"; // for derived_probe_group use ++ ++ /* If we're not in STARTING/RUNNING state, don't try doing any work. ++ PR16766 */ ++ o->newline() << "int state = atomic_read (session_state());"; ++ o->newline() << "if (state != STAP_SESSION_RUNNING && state != STAP_SESSION_STARTING) {"; ++ // cannot _stp_warn etc. since we're not in probe context ++ o->newline(1) << "printk (KERN_ERR \"stap module notifier triggered in unexpected state %d\", state);"; ++ o->newline() << "return;"; ++ o->newline(-1) << "}"; ++ + o->newline() << "(void) i;"; + o->newline() << "(void) j;"; ++ + vector<derived_probe_group*> g = all_session_groups (*session); + for (unsigned i=0; i<g.size(); i++) + { +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1051649.9.patch b/SOURCES/rhbz1051649.9.patch new file mode 100644 index 0000000..9d61928 --- /dev/null +++ b/SOURCES/rhbz1051649.9.patch @@ -0,0 +1,29 @@ +From 53d72bca75a2bfc75bceea0d094131c9d53bd942 Mon Sep 17 00:00:00 2001 +From: "Frank Ch. Eigler" <fche@redhat.com> +Date: Fri, 28 Mar 2014 15:24:19 -0400 +Subject: [PATCH] PR16766 cont'd: unbreak --runtime=dyninst + +* translate.cxx: While emitting systemtap_module_refresh(), protect + the printk diagnostics with #if defined(__KERNEL__). +--- + translate.cxx | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/translate.cxx b/translate.cxx +index 17dedd4..90b04d8 100644 +--- a/translate.cxx ++++ b/translate.cxx +@@ -1887,7 +1887,9 @@ c_unparser::emit_module_refresh () + o->newline() << "int state = atomic_read (session_state());"; + o->newline() << "if (state != STAP_SESSION_RUNNING && state != STAP_SESSION_STARTING) {"; + // cannot _stp_warn etc. since we're not in probe context +- o->newline(1) << "printk (KERN_ERR \"stap module notifier triggered in unexpected state %d\", state);"; ++ o->newline(1) << "#if defined(__KERNEL__)"; ++ o->newline() << "printk (KERN_ERR \"stap module notifier triggered in unexpected state %d\", state);"; ++ o->newline() << "#endif"; + o->newline() << "return;"; + o->newline(-1) << "}"; + +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1051649.patch b/SOURCES/rhbz1051649.patch new file mode 100644 index 0000000..326106a --- /dev/null +++ b/SOURCES/rhbz1051649.patch @@ -0,0 +1,803 @@ +From 2512f77547e7a4b9bbfd46c01c5b2ded2c171cf3 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Wed, 27 Nov 2013 11:21:02 -0500 +Subject: BZ1051649: backport boot-time probing feature + +--- + configure.ac | 3 +- + initscript/99stap/module-setup.sh.in | 36 ++++++ + initscript/99stap/start-staprun.sh | 26 ++++ + initscript/README.systemtap | 108 ++++++++++++++-- + initscript/config.systemtap.in | 3 + + initscript/systemtap.in | 230 +++++++++++++++++++++++++++++++++-- + systemtap.spec | 39 ++++-- + tapset-utrace.cxx | 9 -- + 8 files changed, 413 insertions(+), 41 deletions(-) + create mode 100644 initscript/99stap/module-setup.sh.in + create mode 100644 initscript/99stap/start-staprun.sh + mode change 100644 => 100755 initscript/systemtap.in + +diff --git a/configure.ac b/configure.ac +index 56c3b88..3d6b50b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -681,7 +681,8 @@ AC_CONFIG_FILES([Makefile doc/Makefile man/Makefile \ + doc/beginners/Makefile doc/SystemTap_Tapset_Reference/Makefile \ + man/stappaths.7 \ + initscript/config.systemtap initscript/config.stap-server \ +-initscript/systemtap initscript/stap-server ]) ++initscript/systemtap initscript/stap-server \ ++initscript/99stap/module-setup.sh ]) + AC_CONFIG_SUBDIRS(testsuite) + if test $enable_translator == "yes"; then + AC_CONFIG_FILES([run-stap], [chmod +x run-stap]) +diff --git a/initscript/99stap/module-setup.sh.in b/initscript/99stap/module-setup.sh.in +new file mode 100644 +index 0000000..4f4583d +--- /dev/null ++++ b/initscript/99stap/module-setup.sh.in +@@ -0,0 +1,36 @@ ++#!/bin/bash ++ ++# NB: $moddir only works in install() ++. @prefix@/lib/dracut/modules.d/99stap/params.conf ++ ++# Return 0 --> install stap module ++# Return 1 --> skip stap module ++check() { ++ # Install it if we have early-boot scripts ++ [ "$ONBOOT_SCRIPTS" ] && return 0 ++ return 1 ++} ++ ++# We don't depend on anything ++depends() { ++ echo "" ++} ++ ++install() { ++ ++ # These programs are very likely to already be included by other ++ # dracut modules so we're really not adding any weight ++ dracut_install bash mkdir ++ ++ # The real payload... ++ inst "$STAPRUN" ++ inst "$STAPIO" ++ for script in $ONBOOT_SCRIPTS; do ++ inst "$CACHE_PATH/$script.ko" ++ done ++ ++ # start-staprun.sh will need a copy of params.conf ++ inst_simple "$moddir/params.conf" "/etc/systemtap-params.conf" ++ inst_hook cmdline 01 "$moddir/start-staprun.sh" ++} ++ +diff --git a/initscript/99stap/start-staprun.sh b/initscript/99stap/start-staprun.sh +new file mode 100644 +index 0000000..efb4d2f +--- /dev/null ++++ b/initscript/99stap/start-staprun.sh +@@ -0,0 +1,26 @@ ++#!/bin/bash ++ ++# Inserts the SystemTap modules using staprun. ++ ++. /etc/systemtap-params.conf ++ ++# From here, we can access /var/run (or rather what it will link to), ++# but because $STAT_PATH is user-configurable, we're not guaranteed that ++# it will be /var/run. Regardless, we can't have access to the final ++# root so we make do and write to /var/run/systemtap anyway. The init ++# script will take care of moving the PID files to the real directory if ++# necessary. ++PIDDIR=/run/systemtap ++mkdir -p $PIDDIR ++ ++for script in $ONBOOT_SCRIPTS; do ++ pid=$PIDDIR/$script ++ eval opts=\$${script}_OPT ++ if [ $LOG_BOOT_ERR -eq 1 ]; then ++ $STAPRUN $opts $CACHE_PATH/$script.ko 2> $PIDDIR/$script.log ++ else ++ $STAPRUN $opts $CACHE_PATH/$script.ko ++ fi ++ echo 0 > $pid ++done ++ +diff --git a/initscript/README.systemtap b/initscript/README.systemtap +index d583d72..9dd1ee6 100644 +--- a/initscript/README.systemtap ++++ b/initscript/README.systemtap +@@ -23,8 +23,8 @@ will be useful for users who use -DRELAY_HOST and -DRELAY_GUEST. + ======== + 2.1 Synopsis + +-/sbin/service systemtap {start|stop|restart|status|compile|cleanup} \ +- [-r kernelrelease] [-c config] [-R] [-y] [script(s)] ++/sbin/service systemtap {start|stop|restart|status|compile|onboot|cleanup} \ ++ [-r kernelrelease] [-o path.img] [-b] [-c config] [-R] [-y] [script(s)] + + 2.2 Commands + You have to specify one of the below commands. +@@ -57,9 +57,29 @@ will be useful for users who use -DRELAY_HOST and -DRELAY_GUEST. + Compile script(s) on the specified kernel. This command takes '-r' option + which specifies the release of the kernel(see 2.3.4) on which you would + like to compile script(s). This command asks user whether it can overwrite +-existing caches. ++ existing caches. + +-2.2.6 cleanup ++2.2.6 onboot ++ Make script(s) part of the initramfs so that they are started earlier during ++ the boot process. Only works on dracut-based systems. This command also takes ++ the '-r' option. If '-r' is omitted, the initramfs is created for the running ++ kernel. If '-o path.img' is given, the initramfs is created at 'path.img' (must ++ be an absolute path). Otherwise, defaults to '/boot/initramfs-KVER.img', where ++ KVER is `uname -r` if the '-r' option is omitted, or the given kernel version ++ otherwise. ++ ++ If the output file already exists, it is overwritten, unless the -b switch is ++ given, in which case the file is appended '.bak' rather than overwritten. Note ++ however that if a '.bak' version already exists, it will not be overwritten. ++ ++ If no scripts are specified on the command-line, the initramfs will be created ++ without including any scripts at all (i.e. no extra systemtap files added). ++ ++ Warning: do not use the stap -o option with onboot scripts because the ++ script is started before the root filesystem is even mounted. Increase the ++ buffer size if more space is needed. ++ ++2.2.7 cleanup + Cleanup compiled script(s) from cache directory(see 3.4). This command also + takes '-r' option. If '-r' option is omitted, cleanup all caches for running + kernel. This command asks user whether it can remove caches. +@@ -75,8 +95,8 @@ existing caches. + 2.3.2 script(s) + You can specify individual scripts to the commands. If you omit to specify + any script, systemtap initscript will execute the command with all scripts +- in the script directory(except 'start' and 'stop' command, see 2.2.1 and +- 2.2.2). ++ in the script directory (except 'start', 'stop', and 'onboot' commands, see ++ 2.2.1, 2.2.2, and 2.2.6). + + 2.3.3 -R + If this option is specified, systemtap initscript will try to solve +@@ -85,11 +105,22 @@ existing caches. + + 2.3.4 -r kernelrelease + You can specify release version of the kernel(e.g. 2.6.26.1). This option +- is valid only with compile and cleanup commands. ++ is valid only with compile, onboot, and cleanup commands. + + 2.3.5 -y + Answer yes for all questions. + ++2.3.6 -o path.img ++ Specify the path of the initramfs image. Otherwise, the default is ++ '/boot/initramfs-KVER.img', where KVER is `uname -r` if the '-r' option is ++ omitted, or the given kernel version otherwise. This option is only valid with ++ the onboot command. ++ ++2.3.7 -b ++ If present, will backup an existing initramfs image by renaming it with a ++ '.bak' extension. Otherwise, the initramfs is overwritten without backing up. ++ This option is only valid with the onboot command. ++ + 2.4 Misc + 2.4.1 Service Priority + Each initscript has execution priority. Since user would like to trace +@@ -147,9 +178,16 @@ existing caches. + Some error and warning messages are also sent to console and syslogd (syslog + output is optional, because this service will start before syslog). + +-3.7 Status files ++3.6 Status files + /var/run/systemtap/<script-name> + ++3.7 Dracut ++ Files related to dracut/initramfs creation ++ ++3.7.1 Dracut stap module directory ++ /usr/lib/dracut/modules.d/99stap ++ ++ These files permit SystemTap modules to be included in the initramfs. + + 4. Configuration Format + ======================= +@@ -213,6 +251,14 @@ Configuration file allows us + option. You should check cache directory before enabling this option. + (default: no) + ++4.1.12 LOG_BOOT_ERR ++ Because boot-time scripts are run before the root filesystem is mounted, ++ staprun's stderr cannot be logged to the LOG_FILE as usual (see 4.1.6). ++ However, the log can instead be output to /var/run/systemtap/$script.log (which ++ is accessible at boot-time) by setting LOG_BOOT_ERR to 'yes'. If STAT_PATH is ++ different from the default, the log files will be moved there upon executing ++ any of the initscript commands. ++ + 4.2 Script Parameters + + 4.2.1 <script-name>_OPT +@@ -353,3 +399,49 @@ script2_REQ=script1 + # vi /etc/systemtap/config + AUTOCOMPILE=no + ALLOW_CACHEONLY=yes ++ ++5.9 Starting scripts during early-boot ++ The initscript also allows you to start scripts earlier during the boot ++ process by creating an initramfs containing the script's module. Your system ++ must be dracut-based for this to work. Starting at this stage gives access to ++ information otherwise very hard to obtain. ++ ++5.9.1 Preparing the script ++ As usual, place the script in /etc/systemtap/script.d and any configuration ++ settings in /etc/systemtap/conf.d. (Note however that -o and -c are not ++ supported). ++ ++5.9.2 Adding to initramfs ++ Simply run the command: ++ # service systemtap onboot my_script ++ If the script is not already compiled and cached, it will be done at this ++ point. A new initramfs will then be created at the default location. You can ++ specify the '-b' option to make sure that your current initramfs is backed up. ++ You can then restart your system. See 2.2.6 for more information regarding the ++ onboot command. ++ ++5.9.3 Adding to a different initramfs ++ Rather than taking the spot of the default initramfs, you may want to create a ++ different initramfs for a one-time boot. You can do this using the -o option: ++ # service systemtap onboot -o /boot/special_initramfs.img ++ Once the initramfs is created, you can change the command-line options at ++ boot-time so that the new image is used rather than the usual one. ++ ++5.9.4 Creating an initramfs for a different kernel ++ Just like the compile command, you can use the -r option to specify the kernel ++ for which you would like to create the initramfs. This is useful when you are ++ about to upgrade and would like to prepare in advance. For example: ++ # service systemtap onboot -r 3.12.6-200.fc19.x86_64 my_script ++ ++5.9.5 Removing from initramfs ++ To remove all scripts from the initramfs, you can run: ++ # service systemtap onboot ++ (That is, without any scripts explicitly mentioned). This will simply create ++ a standard initramfs without any SystemTap modules inserted. ++ ++5.9.6 Troubleshooting ++ There can be many reasons for which the module didn't insert or did not work as ++ expected. It may be useful to turn on dracut debugging by adding 'rdinitdebug' to ++ the kernel command-line and checking dmesg/journalctl -ae. Also, you can ++ capture the stderr output of staprun by setting LOG_BOOT_ERR to 'yes' (see ++ 4.1.12). +diff --git a/initscript/config.systemtap.in b/initscript/config.systemtap.in +index 23068e1..9237b3b 100644 +--- a/initscript/config.systemtap.in ++++ b/initscript/config.systemtap.in +@@ -18,3 +18,6 @@ + # Start these scripts by default. If omitted, all scripts are started. + # DEFAULT_START= + ++# Log boot-time staprun stderr to /var/run/systemtap/$script.log ++# LOG_BOOT_ERR=no ++ +diff --git a/initscript/systemtap.in b/initscript/systemtap.in +old mode 100644 +new mode 100755 +index c1c8854..5290f56 +--- a/initscript/systemtap.in ++++ b/initscript/systemtap.in +@@ -36,6 +36,11 @@ STAP=@bindir@/stap + STAPRUN=@bindir@/staprun + UNAME=/bin/uname + LSMOD=/sbin/lsmod ++DRACUT=/sbin/dracut ++ ++# Not actually used directly, but needed by ++# stap dracut module for inclusion in initramfs ++STAPIO=@libexecdir@/systemtap/stapio + + # Path setup + SCRIPT_PATH=@sysconfdir@/systemtap/script.d +@@ -45,6 +50,9 @@ STAT_PATH=@localstatedir@/run/systemtap + TEMP_PATH=/tmp + LOG_FILE=@localstatedir@/log/systemtap.log + ++# NB: this path is also used in 99stap/module-setup.sh ++DRACUT_SRC=@prefix@/lib/dracut/modules.d/99stap/params.conf ++ + # FAIL unless all scripts succeeded to run + PASSALL=yes + +@@ -60,6 +68,9 @@ DEFAULT_START= + # Allow cache only scripts + ALLOW_CACHEONLY=no + ++# Log boot-time staprun stderr to /var/run/systemtap/$script.log ++LOG_BOOT_ERR=no ++ + # Optional settings + CONFIG=@sysconfdir@/systemtap/config + SCRIPTS= +@@ -68,14 +79,18 @@ OPT_RECURSIVE= + OPT_SCRIPTS= + OPTS= + OPT_ASSUMEYES= ++INITRAMFS= ++BACKUP_INITRAMFS= + + echo_usage () { +- echo $"Usage: $prog {start|stop|status|restart|compile|cleanup|condrestart|try-restart|reload|force-reload} [option]" ++ echo $"Usage: $prog {start|stop|status|restart|compile|onboot|cleanup|condrestart|try-restart|reload|force-reload} [option]" + echo $"Options:" ++ echo $" -b : backup initramfs before overwriting" + echo $" -c configfile : specify config file" ++ echo $" -o path.img : specify initramfs output file" + echo $" -r kernelrelease: specify kernel release version" + echo $" -R : recursively dependency checking" +- echo $" -y : answer yes for all questions." ++ echo $" -y : answer yes for all questions" + echo $" script(s) : specify systemtap scripts" + } + +@@ -154,6 +169,13 @@ parse_args () { # arguments + -y) + OPT_ASSUMEYES=1 + ;; ++ -o) ++ INITRAMFS=$2 ++ shift 1 ++ ;; ++ -b) ++ BACKUP_INITRAMFS=1 ++ ;; + --) + ;; + *) +@@ -166,7 +188,7 @@ parse_args () { # arguments + + CMD=$1 + shift 1 +-OPTS=`getopt -s bash -u -o 'r:c:Ry' -- $@` ++OPTS=`getopt -s bash -u -o 'r:c:Ryo:b' -- $@` + if [ $? -ne 0 ]; then + slog "Error: Argument parse error: $@" + failure $"parse error" +@@ -175,6 +197,11 @@ if [ $? -ne 0 ]; then + fi + parse_args $OPTS + ++# Set default output file if not given as an option ++if [ ! "$INITRAMFS" ]; then ++ INITRAMFS=/boot/initramfs-$KRELEASE.img ++fi ++ + # Include configs + . "$CONFIG" + +@@ -188,7 +215,7 @@ check_bool $PASSALL + PASSALL=$? + check_bool $RECURSIVE + RECURSIVE=$? +-if [ "$OPT_RECURSIVE" ]; then # -r option overrides RECURSIVE. ++if [ "$OPT_RECURSIVE" ]; then # -R option overrides RECURSIVE. + RECURSIVE=1 + fi + check_bool $AUTOCOMPILE +@@ -198,6 +225,9 @@ CACHE_PATH="$CACHE_PATH/$KRELEASE" + check_bool $ALLOW_CACHEONLY + ALLOW_CACHEONLY=$? + ++check_bool $LOG_BOOT_ERR ++LOG_BOOT_ERR=$? ++ + __get_all_scripts () { + local s + if [ $ALLOW_CACHEONLY -eq 1 ]; then +@@ -225,6 +255,29 @@ else + SCRIPTS="$OPT_SCRIPTS" + fi + ++# Move over any pid files in /var/run/systemtap (from boot-time scripts) ++# to the user-defined $STAT_PATH if it's different. ++if [ "$STAT_PATH" != /var/run/systemtap ] && # XXX: use inodes instead? ++ [ -d /var/run/systemtap ]; then ++ ++ # Check if there's stuff to copy ++ if [ "$(ls -A /var/run/systemtap)" ]; then ++ ++ # Create target dir if it does not exist ++ if [ ! -d "$STAT_PATH" ]; then ++ logex mkdir -p "$STAT_PATH" ++ if [ $? -ne 0 ]; then ++ do_failure $"Failed to make stat directory ($STAT_PATH)" ++ exit 1 ++ fi ++ fi ++ ++ cp /var/run/systemtap/* "$STAT_PATH" ++ fi ++ ++ rm -rf /var/run/systemtap ++fi ++ + #------------------------------------------------------------------ + # Main routine + #------------------------------------------------------------------ +@@ -328,10 +381,13 @@ get_compile_opts () { # opts + done + } + ++# Returns 0 if something went wrong ++# Returns 1 if in -L mode ++# Returns 2 if in -D (daemon) mode + get_run_opts () { # normalized_opts + local opts o show mode + opts=`stap_getopt $*` +- [ $? -ne 0 ] && return 1 ++ [ $? -ne 0 ] && return 0 + mode='-L' + show=0 + for o in $opts; do +@@ -351,6 +407,9 @@ get_run_opts () { # normalized_opts + esac + done + echo -n $mode ++ [ "$mode" == "-L" ] && return 1 ++ [ "$mode" == "-D" ] && return 2 ++ return 0 + } + + prepare_cache_dir () { +@@ -457,7 +516,7 @@ sort_dependency () { # scripts + } + + start_script () { # script +- local tmpdir s=$1 ret count=0 ++ local tmpdir s=$1 ret count=0 mode + check_running $s + ret=$? + [ $ret -eq 0 ] && return 0 # already running +@@ -472,7 +531,8 @@ start_script () { # script + + eval opts=\$${s}_OPT + opts=`get_run_opts $opts` +- [ $? -ne 0 ] && return 2 ++ mode=$? ++ [ $mode -eq 0 ] && return 2 + + clog " Starting $1 ... " -n + tmpdir=`mktemp -d -p "$TEMP_PATH" cache.XXXXXXXX` # bz7097 +@@ -489,12 +549,14 @@ start_script () { # script + # used, staprun detaches from the terminal and *then* prints the new + # pid. So, it is possible to check the ./pid file before it has + # been written. To avoid this, wait a bit (if necessary). +- while [ $count -lt 10 ]; do +- # when the file exists and has a size > 0, quit +- [ -s ./pid ] && break +- sleep 1 +- count=`expr $count + 1` +- done ++ if [ $mode -eq 2 ]; then ++ while [ $count -lt 10 ]; do ++ # when the file exists and has a size > 0, quit ++ [ -s ./pid ] && break ++ sleep 1 ++ count=`expr $count + 1` ++ done ++ fi + + [ x`cat ./pid` = x ] && echo 0 > ./pid + if [ $ret -eq 0 ]; then +@@ -674,6 +736,142 @@ compile () { + return 0 + } + ++# Writes info to $DRACUT_SRC, which the stap dracut module will source ++# Includes all needed info such as location of stap/staprun, which ++# scripts to insert, and their options ++update_dracut() { # scripts ++ local s opts ++ ++ if [ -f "$DRACUT_SRC" ]; then ++ rm -f "$DRACUT_SRC" ++ fi ++ ++ echo "STAPRUN=\"$STAPRUN\"" >> "$DRACUT_SRC" ++ echo "STAPIO=\"$STAPIO\"" >> "$DRACUT_SRC" ++ echo "CACHE_PATH=\"$CACHE_PATH\"" >> "$DRACUT_SRC" ++ echo "STAT_PATH=\"$STAT_PATH\"" >> "$DRACUT_SRC" ++ echo "KRELEASE=\"$KRELEASE\"" >> "$DRACUT_SRC" ++ echo "LOG_BOOT_ERR=\"$LOG_BOOT_ERR\"" >> "$DRACUT_SRC" ++ ++ echo -n "ONBOOT_SCRIPTS=\"" >> "$DRACUT_SRC" ++ for s in $*; do ++ echo -n "$s " >> "$DRACUT_SRC" ++ done ++ echo "\"" >> "$DRACUT_SRC" ++ ++ for s in $*; do ++ eval opts=\$${s}_OPT ++ opts=`get_run_opts $opts` ++ [ $? -eq 0 ] && return 1 ++ echo -n "$s" >> "$DRACUT_SRC" ++ echo "_OPT=\"$opts\"" >> "$DRACUT_SRC" ++ done ++} ++ ++backup_initramfs() { ++ # does target file exist? ++ if [ -f "$INITRAMFS" ]; then ++ # don't overwrite an existing backup ++ if [ ! -f "$INITRAMFS.bak" ]; then ++ mv "$INITRAMFS" "$INITRAMFS.bak" ++ clog "Renamed $INITRAMFS" ++ clog " to $INITRAMFS.bak" ++ RESTORE_INITRAMFS_ON_FAIL=1 ++ else ++ clog "Backup already exists: $INITRAMFS.bak" ++ fi ++ fi ++} ++ ++onboot () { ++ local s ret ss ++ if [ ! -f "$DRACUT" ]; then ++ clog "Could not find $DRACUT" -n ++ do_failure "$DRACUT not found" ++ clog ++ clog "The system must be dracut-based to use this feature" ++ clog "If it is located elsewhere, modify the \$DRACUT parameter" -n ++ return 1 ++ fi ++ if [ ! -d "$(dirname $DRACUT_SRC)" ]; then ++ clog "Could not find dracut module" -n ++ do_failure "SystemTap dracut module $(dirname $DRACUT_SRC) not found" ++ return 1 ++ fi ++ prepare_cache_dir ++ if [ $? -ne 0 ]; then ++ do_failure "Failed to make cache directory ($CACHE_PATH)" ++ return 1 ++ fi ++ # NB: we use OPT_SCRIPTS, not SCRIPTS because we want ++ # no scripts passed to mean building a virgin initramfs ++ for s in $OPT_SCRIPTS; do ++ compile_script $s check ++ ret=$? ++ [ $ret -ne 0 ] && might_fail "Could not compile $s ($ret)" ++ eval opts=\$${s}_OPT ++ opts=`get_run_opts $opts` ++ mode=$? ++ clog " Checking options $s ... " -n ++ [ $mode -eq 0 ] && might_fail "Bad runtime options for script $s" ++ [ $mode -eq 2 ] && might_fail "Unsupported option -o in script $s" ++ if [ $ret -eq 0 ] && [ $mode -eq 1 ]; then ++ ss="$ss$s " ++ clog "done" ++ fi ++ done ++ # User specified script(s) but they were all skipped ++ if [ -n "$OPT_SCRIPTS" ] && [ -z "$ss" ]; then ++ do_failure "No scripts left to operate on" ++ return 1 ++ fi ++ if [ ! "$ss" ]; then ++ clog " Creating initramfs without scripts ... " -n ++ else ++ clog " Creating initramfs with $ss... " -n ++ fi ++ update_dracut $ss ++ if [ $? -ne 0 ]; then ++ do_failure "Call to update_dracut failed. Bad opts?" ++ return 1 ++ fi ++ if [ "$BACKUP_INITRAMFS" ]; then ++ backup_initramfs ++ fi ++ dir=`dirname $INITRAMFS` && TMPINITRAMFS=`mktemp --tmpdir=$dir` ++ if [ $? -ne 0 ]; then ++ do_failure "Failed to make temporary file in $dir" ++ return 1 ++ fi ++ out=$($DRACUT --force $TMPINITRAMFS $KRELEASE 2>&1) ++ # dracut will report success even if some modules (e.g. stap) failed ++ # to install some files, so we need to be a bit more involved in ++ # checking for errors ++ if [ $? -ne 0 ] || [[ "$out" == *ERROR* ]]; then ++ do_failure "The initramfs creation is unsuccessful" ++ if [ -f /var/log/dracut.log ]; then ++ do_failure "See /var/log/dracut.log for more info" ++ else ++ do_failure "See dracut log for more info" ++ fi ++ echo # We need a new line ++ if [ -f "$TMPINITRAMFS" ]; then ++ rm "$TMPINITRAMFS" ++ fi ++ # Put back the initramfs if we moved it (if we didn't move it, then ++ # whatever initramfs they used to boot in is still there) ++ if [ "$RESTORE_INITRAMFS_ON_FAIL" ]; then ++ mv "$INITRAMFS.bak" "$INITRAMFS" ++ clog "Renamed $INITRAMFS.bak" ++ clog " to $INITRAMFS" ++ fi ++ return 1 ++ fi ++ mv "$TMPINITRAMFS" "$INITRAMFS" ++ might_success "initramfs created" ++ return 0 ++} ++ + # Cleanup caches + cleanup () { + local s ss ret +@@ -731,6 +929,10 @@ case $CMD in + compile + RETVAL=$? + ;; ++ onboot) ++ onboot ++ RETVAL=$? ++ ;; + cleanup) + cleanup + RETVAL=$? +@@ -748,3 +950,5 @@ esac + + echo + exit $RETVAL ++ ++# vim: sw=2 ts=8 +diff --git a/systemtap.spec b/systemtap.spec +index 39d22ca..6cd5853 100644 +--- a/systemtap.spec ++++ b/systemtap.spec +@@ -32,6 +32,7 @@ + # don't want to build runtime-virthost for f18 or RHEL5/6 + %{!?with_virthost: %global with_virthost 0%{?fedora} >= 19 || 0%{?rhel} >= 7} + %{!?with_virtguest: %global with_virtguest 1} ++%{!?with_dracut: %global with_dracut 0%{?fedora} >= 19 || 0%{?rhel} >= 7} + + %if 0%{?fedora} >= 18 || 0%{?rhel} >= 6 + %define initdir %{_initddir} +@@ -47,6 +48,9 @@ + %endif + %endif + ++%define dracutlibdir %{_prefix}/lib/dracut ++%define dracutstap %{dracutlibdir}/modules.d/99stap ++ + Name: systemtap + Version: 2.4 + Release: 1%{?dist} +@@ -60,7 +64,7 @@ Release: 1%{?dist} + # systemtap-devel /usr/bin/stap, runtime, tapset, req:kernel-devel + # systemtap-runtime /usr/bin/staprun, /usr/bin/stapsh, /usr/bin/stapdyn + # systemtap-client /usr/bin/stap, samples, docs, tapset(bonus), req:-runtime +-# systemtap-initscript /etc/init.d/systemtap, req:systemtap ++# systemtap-initscript /etc/init.d/systemtap, dracut module, req:systemtap + # systemtap-sdt-devel /usr/include/sys/sdt.h /usr/bin/dtrace + # systemtap-testsuite /usr/share/systemtap/testsuite*, req:systemtap, req:sdt-devel + # systemtap-runtime-java libHelperSDT.so, HelperSDT.jar, stapbm, req:-runtime +@@ -245,7 +249,9 @@ Requires(preun): initscripts + Requires(postun): initscripts + + %description initscript +-Sysvinit scripts to launch selected systemtap scripts at system startup. ++This package includes a SysVinit script to launch selected systemtap ++scripts at system startup, along with a dracut module for early ++boot-time probing if supported. + + + %package sdt-devel +@@ -545,6 +551,13 @@ done + %endif + %endif + ++%if %{with_dracut} ++ mkdir -p $RPM_BUILD_ROOT%{dracutstap} ++ install -p -m 755 initscript/99stap/module-setup.sh $RPM_BUILD_ROOT%{dracutstap} ++ install -p -m 755 initscript/99stap/start-staprun.sh $RPM_BUILD_ROOT%{dracutstap} ++ touch $RPM_BUILD_ROOT%{dracutstap}/params.conf ++%endif ++ + %clean + rm -rf ${RPM_BUILD_ROOT} + +@@ -615,7 +628,7 @@ if [ $1 = 0 ] ; then + /bin/systemctl stop stap-server.service >/dev/null 2>&1 || : + %else + /sbin/service stap-server stop >/dev/null 2>&1 +- /sbin/chkconfig --del stap-server ++ /sbin/chkconfig --del stap-server + %endif + fi + exit 0 +@@ -625,7 +638,7 @@ exit 0 + # If so, restart the service if it's running + if [ "$1" -ge "1" ] ; then + %if %{with_systemd} +- /bin/systemctl restart stap-server.service >/dev/null 2>&1 || : ++ /bin/systemctl restart stap-server.service >/dev/null 2>&1 || : + %else + /sbin/service stap-server condrestart >/dev/null 2>&1 || : + %endif +@@ -634,8 +647,7 @@ exit 0 + + %post initscript + %if %{with_systemd} +- /bin/systemctl enable stap-server.service >/dev/null 2>&1 || : +- /bin/systemd-tmpfiles --create >/dev/null 2>&1 || : ++ /bin/systemctl enable systemtap.service >/dev/null 2>&1 || : + %else + /sbin/chkconfig --add systemtap + %endif +@@ -646,11 +658,11 @@ exit 0 + # just removing the old package on upgrade. + if [ $1 = 0 ] ; then + %if %{with_systemd} +- /bin/systemctl --no-reload disable stap-server.service >/dev/null 2>&1 || : +- /bin/systemctl stop stap-server.service >/dev/null 2>&1 || : ++ /bin/systemctl --no-reload disable systemtap.service >/dev/null 2>&1 || : ++ /bin/systemctl stop systemtap.service >/dev/null 2>&1 || : + %else + /sbin/service systemtap stop >/dev/null 2>&1 +- /sbin/chkconfig --del systemtap ++ /sbin/chkconfig --del systemtap + %endif + fi + exit 0 +@@ -660,7 +672,7 @@ exit 0 + # If so, restart the service if it's running + if [ "$1" -ge "1" ] ; then + %if %{with_systemd} +- /bin/systemctl restart stap-server.service >/dev/null 2>&1 || : ++ /bin/systemctl condrestart systemtap.service >/dev/null 2>&1 || : + %else + /sbin/service systemtap condrestart >/dev/null 2>&1 || : + %endif +@@ -917,6 +929,10 @@ done + %dir %{_localstatedir}/cache/systemtap + %ghost %{_localstatedir}/run/systemtap + %doc initscript/README.systemtap ++%if %{with_dracut} ++ %dir %{dracutstap} ++ %{dracutstap}/* ++%endif + + + %files sdt-devel +@@ -970,6 +986,9 @@ done + # http://sourceware.org/systemtap/wiki/SystemTapReleases + + %changelog ++* Mon Jan 06 2014 Jonathan Lebon <jlebon@redhat.com> ++- Added dracut module to initscript package ++ + * Wed Nov 06 2013 Frank Ch. Eigler <fche@redhat.com> - 2.4-1 + - Upstream release. + +diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx +index 05491f3..d0f90ea 100644 +--- a/tapset-utrace.cxx ++++ b/tapset-utrace.cxx +@@ -700,15 +700,6 @@ struct utrace_builder: public derived_probe_builder + sess.unwindsym_modules.insert (path); + path_tgt = path_remove_sysroot(sess, path); + } +- else if (has_pid) +- { +- // We can't probe 'init' (pid 1). XXX: where does this limitation come from? +- if (pid < 2) +- throw SEMANTIC_ERROR (_("process pid must be greater than 1"), +- location->components.front()->tok); +- +- // XXX: could we use /proc/$pid/exe in unwindsym_modules and elsewhere? +- } + + finished_results.push_back(new utrace_derived_probe(sess, base, location, + has_path, path_tgt, pid, +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1054954.patch b/SOURCES/rhbz1054954.patch new file mode 100644 index 0000000..e3df1cf --- /dev/null +++ b/SOURCES/rhbz1054954.patch @@ -0,0 +1,24 @@ +From f551ef1599fa4ff5d244285eef731928a5d9820e Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Tue, 10 Dec 2013 11:38:39 -0500 +Subject: BZ1054954: PR16309: spawn stap-serverd with / cwd + +--- + stap-start-server | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/stap-start-server b/stap-start-server +index b6ec943..4221631 100755 +--- a/stap-start-server ++++ b/stap-start-server +@@ -18,6 +18,7 @@ + startup_timeout=10 + + # start the server ++cd / # change to a dir we're 100% sure we have RD_ONLY access to + ${stap_pkglibexecdir}stap-serverd "$@" </dev/null >/dev/null 2>/dev/null & + server_pid=$! + +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1054956.patch b/SOURCES/rhbz1054956.patch new file mode 100644 index 0000000..6f65b6e --- /dev/null +++ b/SOURCES/rhbz1054956.patch @@ -0,0 +1,84 @@ +From b48894ebfc1e123ec9030bb7a31a269d13995ce0 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Sat, 30 Nov 2013 11:14:25 -0500 +Subject: BZ1054956: stapsh.c: fix handling of POLLIN to indicate EOF + +We previously relied on POLLHUP to indicate EOF. However, it is also +possible to receive POLLIN when EOF is reached. With this patch, upon +receiving POLLIN and reading from the associated fd, if EOF is found, we +modify the polling array to indicate we're no longer interested. +--- + staprun/stapsh.c | 27 ++++++++++++++++++++------- + 1 file changed, 20 insertions(+), 7 deletions(-) + +diff --git a/staprun/stapsh.c b/staprun/stapsh.c +index 3d88537..5c3229b 100644 +--- a/staprun/stapsh.c ++++ b/staprun/stapsh.c +@@ -638,7 +638,11 @@ process_command(void) + // stap commands are short and always end in \n. Even if we do block it's not + // so bad a thing. + if (fgets(command, sizeof(command), stapsh_in) == NULL) +- return; ++ { ++ if (feof(stapsh_in)) // no more stap commands coming ++ pfds[PFD_STAP_OUT].events = 0; ++ return; ++ } + + dbug(1, "command: %s", command); + const char* arg = strtok(command, STAPSH_TOK_DELIM) ?: "(null)"; +@@ -665,10 +669,10 @@ process_command(void) + } + + static void +-prefix_staprun(int fdin, FILE *out, const char *stream) ++prefix_staprun(int i, FILE *out, const char *stream) + { + char buf[4096]; +- ssize_t n = read(fdin, buf, sizeof buf); ++ ssize_t n = read(pfds[i].fd, buf, sizeof buf); + if (n > 0) + { + // actually check if we need to prefix data (we could also be piping for +@@ -679,6 +683,8 @@ prefix_staprun(int fdin, FILE *out, const char *stream) + dbug(2, "failed fwrite\n"); // appease older gccs (don't ignore fwrite rc) + fflush(out); + } ++ else if (n == 0) // eof ++ pfds[i].events = 0; + } + + int +@@ -751,17 +757,24 @@ main(int argc, char* const argv[]) + sleep(2); // Once we support only platforms with guaranteed SIGIO support, + // we could replace this with a pause(). + +- for (;;) ++ // keep polling as long as we're listening for stap commands ++ while (pfds[PFD_STAP_OUT].events) + { +- poll(pfds, staprun_pid > 0 ? 3 : 1, -1); ++ if (poll(pfds, 3, -1) < 0) ++ { ++ if (errno == EINTR) ++ continue; // go back to poll() ++ else ++ die ("poll() failed with critical error"); ++ } + if (pfds[PFD_STAP_OUT].revents & POLLHUP) + break; + if (pfds[PFD_STAP_OUT].revents & POLLIN) + process_command(); + if (pfds[PFD_STAPRUN_OUT].revents & POLLIN) +- prefix_staprun(pfds[PFD_STAPRUN_OUT].fd, stapsh_out, "stdout"); ++ prefix_staprun(PFD_STAPRUN_OUT, stapsh_out, "stdout"); + if (pfds[PFD_STAPRUN_ERR].revents & POLLIN) +- prefix_staprun(pfds[PFD_STAPRUN_ERR].fd, stapsh_err, "stderr"); ++ prefix_staprun(PFD_STAPRUN_ERR, stapsh_err, "stderr"); + } + + cleanup(0); +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1054962.patch b/SOURCES/rhbz1054962.patch new file mode 100644 index 0000000..3a89259 --- /dev/null +++ b/SOURCES/rhbz1054962.patch @@ -0,0 +1,93 @@ +From a94b495c5b48324cecff42afce15a4d843577741 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Wed, 13 Nov 2013 12:29:49 -0500 +Subject: BZ1054962 + +BZ1054962: PR16166: assign token to new block + +BZ1054962: stap translator: tolerate NULLs coming from some elfutils string lookups + +It was reported on the mailing list, and privately experienced, that +stap pass-2 crashes could occur due to NULL dwarf_diename or +dwarf_decl_file's being propagated rather far within stap. This +commit adds protections (of the form ?: "foo") to eliminate the +problem in a few spots. There may be others; we should not store +so many raw char*'s. +--- + dwflpp.cxx | 4 ++-- + tapsets.cxx | 16 +++++++++++----- + 2 files changed, 13 insertions(+), 7 deletions(-) + +diff --git a/dwflpp.cxx b/dwflpp.cxx +index f8b1517..93713d0 100644 +--- a/dwflpp.cxx ++++ b/dwflpp.cxx +@@ -1742,7 +1742,7 @@ dwflpp::iterate_over_labels (Dwarf_Die *begin_die, + { + // Get the file/line number for this label + int dline; +- const char *file = dwarf_decl_file (&die); ++ const char *file = dwarf_decl_file (&die) ?: "<unknown source>"; + dwarf_decl_line (&die, &dline); + + vector<Dwarf_Die> scopes = getscopes_die(&die); +@@ -2045,7 +2045,7 @@ dwflpp::function_file (char const ** c) + { + assert (function); + assert (c); +- *c = dwarf_decl_file (function); ++ *c = dwarf_decl_file (function) ?: "<unknown source>"; + } + + +diff --git a/tapsets.cxx b/tapsets.cxx +index 6dea4d2..205de34 100644 +--- a/tapsets.cxx ++++ b/tapsets.cxx +@@ -1683,8 +1683,14 @@ inline_instance_info::operator<(const inline_instance_info& other) const + return decl_line < other.decl_line; + + int cmp = name.compare(other.name); +- if (!cmp) +- cmp = strcmp(decl_file, other.decl_file); ++ ++ if (!cmp) ++ { ++ assert (decl_file); ++ assert (other.decl_file); ++ cmp = strcmp(decl_file, other.decl_file); ++ } ++ + return cmp < 0; + } + +@@ -3874,6 +3880,7 @@ dwarf_var_expanding_visitor::visit_perf_op (perf_op *e) + t->content = e_lit_val; + + add_block = new block; ++ add_block->tok = e->tok; + + systemtap_session &s = this->q.sess; + map<string, pair<string,derived_probe*> >::iterator it; +@@ -4187,8 +4194,7 @@ dwarf_atvar_query::atvar_query_cu (Dwarf_Die * cudie, void * data) + + if (! q->e.cu_name.empty()) + { +- const char *die_name = dwarf_diename(cudie); +- ++ const char *die_name = dwarf_diename(cudie) ?: ""; + if (strcmp(die_name, q->e.cu_name.c_str()) != 0 // Perfect match + && fnmatch(q->cu_name_pattern.c_str(), die_name, 0) != 0) + { +@@ -9714,7 +9720,7 @@ tracepoint_derived_probe::build_args(dwflpp&, Dwarf_Die& func_die) + { + // build a tracepoint_arg for this parameter + tracepoint_arg tparg; +- tparg.name = dwarf_diename(&arg); ++ tparg.name = dwarf_diename(&arg) ?: ""; + + // read the type of this parameter + if (!dwarf_attr_die (&arg, DW_AT_type, &tparg.type_die) +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1055778.patch b/SOURCES/rhbz1055778.patch new file mode 100644 index 0000000..169f8a6 --- /dev/null +++ b/SOURCES/rhbz1055778.patch @@ -0,0 +1,91 @@ +diff --git a/buildrun.cxx b/buildrun.cxx +index 3c26d50..cfb3ae0 100644 +--- a/buildrun.cxx ++++ b/buildrun.cxx +@@ -1,5 +1,5 @@ + // build/run probes +-// Copyright (C) 2005-2013 Red Hat Inc. ++// Copyright (C) 2005-2014 Red Hat Inc. + // + // This file is part of systemtap, and is free software. You can + // redistribute it and/or modify it under the terms of the GNU General +@@ -378,6 +378,7 @@ compile_pass (systemtap_session& s) + output_autoconf(s, o, "autoconf-relay-umode_t.c", "STAPCONF_RELAY_UMODE_T", NULL); + output_autoconf(s, o, "autoconf-fs_supers-hlist.c", "STAPCONF_FS_SUPERS_HLIST", NULL); + output_autoconf(s, o, "autoconf-compat_sigaction.c", "STAPCONF_COMPAT_SIGACTION", NULL); ++ output_autoconf(s, o, "autoconf-netfilter.c", "STAPCONF_NETFILTER_V313", NULL); + + // used by tapset/timestamp_monotonic.stp + output_exportconf(s, o, "cpu_clock", "STAPCONF_CPU_CLOCK"); +diff --git a/man/stapprobes.3stap b/man/stapprobes.3stap +index 4bc99fc..2229c9c 100644 +--- a/man/stapprobes.3stap ++++ b/man/stapprobes.3stap +@@ -1043,6 +1043,9 @@ the C code generated by systemtap. + + The netfilter probe points define the following context variables: + .TP ++.IR $hooknum ++The hook number. ++.TP + .IR $skb + The address of the sk_buff struct representing the packet. See + <linux/skbuff.h> for details on how to use this struct, or +diff --git a/runtime/linux/autoconf-netfilter.c b/runtime/linux/autoconf-netfilter.c +new file mode 100644 +index 0000000..f122664 +--- /dev/null ++++ b/runtime/linux/autoconf-netfilter.c +@@ -0,0 +1,16 @@ ++#include <linux/netfilter.h> ++ ++unsigned int ++new_style_hook(const struct nf_hook_ops *ops, /* not: unsigned int hook; */ ++ struct sk_buff *skb, ++ const struct net_device *in, const struct net_device *out, ++ int (*okfn)(struct sk_buff *)) ++{ ++ (void) ops; (void) skb; (void) in; (void) out; (void) okfn; ++ return 0; ++} ++ ++struct nf_hook_ops netfilter_ops = { ++ .hook = new_style_hook ++}; ++ +diff --git a/tapset-netfilter.cxx b/tapset-netfilter.cxx +index f20b569..eec7e31 100644 +--- a/tapset-netfilter.cxx ++++ b/tapset-netfilter.cxx +@@ -1,5 +1,5 @@ + // tapset for netfilter hooks +-// Copyright (C) 2012 Red Hat Inc. ++// Copyright (C) 2012-2014 Red Hat Inc. + // + // This file is part of systemtap, and is free software. You can + // redistribute it and/or modify it under the terms of the GNU General +@@ -267,7 +267,13 @@ netfilter_derived_probe_group::emit_module_decls (systemtap_session& s) + // Previous to kernel 2.6.22, the hookfunction definition takes a struct sk_buff **skb, + // whereas currently it uses a *skb. We need emit the right version so this will + // compile on RHEL5, for example. +- s.op->newline() << "#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)"; ++ s.op->newline() << "#ifdef STAPCONF_NETFILTER_V313"; ++ ++ s.op->newline() << "(const struct nf_hook_ops *nf_ops, struct sk_buff *nf_skb, const struct net_device *nf_in, const struct net_device *nf_out, int (*nf_okfn)(struct sk_buff *))"; ++ s.op->newline() << "{"; ++ ++ s.op->newline() << "#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)"; ++ + s.op->newline() << "(unsigned int nf_hooknum, struct sk_buff *nf_skb, const struct net_device *nf_in, const struct net_device *nf_out, int (*nf_okfn)(struct sk_buff *))"; + s.op->newline() << "{"; + +@@ -280,6 +286,9 @@ netfilter_derived_probe_group::emit_module_decls (systemtap_session& s) + s.op->newline(-1) << "#endif"; + s.op->newline(1) << "const struct stap_probe * const stp = & stap_probes[" << np->session_index << "];"; + s.op->newline() << "int nf_verdict = NF_ACCEPT;"; // default NF_ACCEPT, to be used by $verdict context var ++ s.op->newline() << "#ifdef STAPCONF_NETFILTER_V313"; ++ s.op->newline() << "unsigned int nf_hooknum = nf_ops->hooknum;"; ++ s.op->newline() << "#endif"; + common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp", + "stp_probe_type_netfilter", + false); diff --git a/SOURCES/rhbz1056687.patch b/SOURCES/rhbz1056687.patch new file mode 100644 index 0000000..f936c9e --- /dev/null +++ b/SOURCES/rhbz1056687.patch @@ -0,0 +1,35 @@ +commit fb3db0ca1cf6bed4bb4beabbf9bf91d09759cae6 +Author: Martin Cermak <mcermak@redhat.com> +Date: Wed Jan 22 17:01:36 2014 +0100 + + PR16448: adapt stap-prep for el7 + + * stap-prep: use yum to install needed kernel information RPMs + should work across all yum-based rhel releases + +diff --git a/stap-prep b/stap-prep +index 541316a..dc997ab 100755 +--- a/stap-prep ++++ b/stap-prep +@@ -30,18 +30,10 @@ NEEDED=`rpm --qf "%{name}-%{version}-%{release}.%{arch}\n" \ + -q $CANDIDATES | grep "is not installed" | awk '{print $2}'` + if [ "$NEEDED" != "" ]; then + echo -e "Need to install the following packages:\n$NEEDED" +- if [ `id -u` = "0" ]; then #attempt download and install +- DIR=`mktemp -d` || exit 1 +- if [ ! -x /usr/bin/yumdownloader ]; then +- echo "Need to first install yum-utils for yumdownloader" +- yum install -y yum-utils +- fi +- yumdownloader --enablerepo="*debuginfo*" $NEEDED --destdir=$DIR \ +- --resolve +- check_error $? "problem downloading rpm(s) $NEEDED" +- rpm --force -ivh $DIR/*.rpm ++ if [ `id -u` = "0" ]; then #attempt to install ++ yum install -y --enablerepo=\* $NEEDED ++ rpm -q $NEEDED + check_error $? "problem installing rpm(s) $NEEDED" +- rm -r $DIR #cleanup + fi + fi + } diff --git a/SOURCES/rhbz1057773.patch b/SOURCES/rhbz1057773.patch new file mode 100644 index 0000000..72502b2 --- /dev/null +++ b/SOURCES/rhbz1057773.patch @@ -0,0 +1,40 @@ +From 95ac9a456e725b2f508c03322b5f13245e6027de Mon Sep 17 00:00:00 2001 +From: Josh Stone <jistone@redhat.com> +Date: Fri, 24 Jan 2014 09:53:53 -0800 +Subject: [PATCH] Resolves: rhbz1057773 + +--- + systemtap.spec | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/systemtap.spec b/systemtap.spec +index c8daaeb..09baff1 100644 +--- a/systemtap.spec ++++ b/systemtap.spec +@@ -599,10 +599,11 @@ test -e %{_localstatedir}/log/stap-server/log || { + if test ! -e ~stap-server/.systemtap/ssl/server/stap.cert; then + runuser -s /bin/sh - stap-server -c %{_libexecdir}/systemtap/stap-gen-cert >/dev/null + fi +-# Activate the service ++# Prepare the service + %if %{with_systemd} +- /bin/systemctl enable stap-server.service >/dev/null 2>&1 || : +- /bin/systemd-tmpfiles --create >/dev/null 2>&1 || : ++ # Note, Fedora policy doesn't allow network services enabled by default ++ # /bin/systemctl enable stap-server.service >/dev/null 2>&1 || : ++ /bin/systemd-tmpfiles --create %{_tmpfilesdir}/stap-server.conf >/dev/null 2>&1 || : + %else + /sbin/chkconfig --add stap-server + %endif +@@ -636,7 +637,7 @@ exit 0 + # If so, restart the service if it's running + if [ "$1" -ge "1" ] ; then + %if %{with_systemd} +- /bin/systemctl restart stap-server.service >/dev/null 2>&1 || : ++ /bin/systemctl condrestart stap-server.service >/dev/null 2>&1 || : + %else + /sbin/service stap-server condrestart >/dev/null 2>&1 || : + %endif +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1062076.patch b/SOURCES/rhbz1062076.patch new file mode 100644 index 0000000..9d5919e --- /dev/null +++ b/SOURCES/rhbz1062076.patch @@ -0,0 +1,391 @@ +From ba7071cd1ca2ed84d351e6cfbe1db5c0bf1a5a09 Mon Sep 17 00:00:00 2001 +From: David Smith <dsmith@redhat.com> +Date: Mon, 10 Feb 2014 09:59:21 -0600 +Subject: [PATCH] rhbz1062076 + +--- + tapset/linux/nfsd.stp | 130 +++++++++++++++++++++++++++++++++----------------- + tapset/linux/rpc.stp | 15 ++++-- + tapset/linux/scsi.stp | 16 ++++--- + 3 files changed, 106 insertions(+), 55 deletions(-) + +diff --git a/tapset/linux/nfsd.stp b/tapset/linux/nfsd.stp +index 092f55d..83765a3 100644 +--- a/tapset/linux/nfsd.stp ++++ b/tapset/linux/nfsd.stp +@@ -146,6 +146,34 @@ function ftype:string(type:long) %{ /* pure */ + } + %} + ++function __rqstp_uid:long(rqstp:long) ++{ ++%( CONFIG_USER_NS == "y" %? ++ # Notice we're using the 'init_user_ns' here, not ++ # 'current_user_ns()'. This matches up with the use in ++ # net/sunrpc/auth_generic.c. ++ return %{ /* pure */ ++ from_kuid_munged(&init_user_ns, ++ ((struct svc_rqst *)STAP_ARG_rqstp)->rq_cred.cr_uid) %} ++%: ++ return @cast(rqstp, "svc_rqst", "kernel:nfsd")->rq_cred->cr_uid ++%) ++} ++ ++function __rqstp_gid:long(rqstp:long) ++{ ++%( CONFIG_USER_NS == "y" %? ++ # Notice we're using the 'init_user_ns' here, not ++ # 'current_user_ns()'. This matches up with the use in ++ # net/sunrpc/auth_generic.c. ++ return %{ /* pure */ ++ from_kgid_munged(&init_user_ns, ++ ((struct svc_rqst *)STAP_ARG_rqstp)->rq_cred.cr_gid) %} ++%: ++ return @cast(rqstp, "svc_rqst", "kernel:nfsd")->rq_cred->cr_gid ++%) ++} ++ + /** + * probe nfsd.dispatch - NFS server receives an operation from client + * +@@ -230,8 +258,8 @@ probe nfsd.proc2.lookup = kernel.function("nfsd_proc_lookup") !, + filelen = $argp->len + filename = kernel_string_n($argp->name, $argp->len) + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc2.lookup" + argstr = sprintf("%s", kernel_string_n($argp->name, $argp->len)) +@@ -259,8 +287,8 @@ probe nfsd.proc3.lookup = kernel.function("nfsd3_proc_lookup") !, + filelen = $argp->len + filename = kernel_string_n($argp->name, $argp->len) + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc3.lookup" + argstr = sprintf("%s", kernel_string_n($argp->name, $argp->len)) +@@ -306,8 +334,8 @@ probe nfsd.proc4.lookup = kernel.function("nfsd4_lookup").call !, + filelen = $lookup->lo_len + filename = kernel_string_n($lookup->lo_name, $lookup->lo_len) + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc4.lookup" + argstr = sprintf("%s", kernel_string_n($lookup->lo_name, $lookup->lo_len)) +@@ -364,8 +392,8 @@ probe nfsd.proc2.read = kernel.function("nfsd_proc_read") !, + vec = @choose_defined($rqstp->rq_vec, $argp->vec) + vlen = $argp->vlen + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc2.read" + argstr = sprintf("%d,%d",count,offset) +@@ -398,8 +426,8 @@ probe nfsd.proc3.read = kernel.function("nfsd3_proc_read") !, + vec = @choose_defined($rqstp->rq_vec, $argp->vec) + vlen = $argp->vlen + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc3.read" + argstr = sprintf("%d,%d",count,offset) +@@ -432,8 +460,8 @@ probe nfsd.proc4.read = kernel.function("nfsd4_read").call !, + vec = $rqstp->rq_vec + vlen = $read->rd_vlen + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc4.read" + argstr = sprintf("%d,%d",count,offset) +@@ -494,8 +522,8 @@ probe nfsd.proc2.write = kernel.function("nfsd_proc_write") !, + vlen = $argp->vlen + stable = 1 # hardcoded in nfsd_proc_write() + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc2.write" + argstr = sprintf("%d,%d",count,offset) +@@ -531,8 +559,8 @@ probe nfsd.proc3.write = kernel.function("nfsd3_proc_write") !, + vlen = $argp->vlen + stable = $argp->stable + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc3.write" + argstr = sprintf("%d,%d",count,offset) +@@ -567,8 +595,8 @@ probe nfsd.proc4.write = kernel.function("nfsd4_write").call !, + vlen = @choose_defined($write->wr_vlen, 0) + stable = $write->wr_stable_how + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc4.write" + argstr = sprintf("%d,%d",count,offset) +@@ -625,8 +653,8 @@ probe nfsd.proc3.commit = kernel.function("nfsd3_proc_commit") !, + count = $argp->count + offset = $argp->offset + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc3.commit" + argstr = sprintf("%d,%d",count,offset) +@@ -656,8 +684,8 @@ probe nfsd.proc4.commit = kernel.function("nfsd4_commit").call !, + count = $commit->co_count + offset = $commit->co_offset + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc4.commit" + argstr = sprintf("%d,%d",count,offset) +@@ -712,8 +740,8 @@ probe nfsd.proc2.create = kernel.function("nfsd_proc_create") !, + filename = kernel_string_n($argp->name, $argp->len) + createmode = 0 # gets computed by nfsd_proc_create + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc2.create" + argstr = sprintf("%s", kernel_string_n($argp->name, $argp->len)) +@@ -742,8 +770,8 @@ probe nfsd.proc3.create = kernel.function("nfsd3_proc_create") !, + filename = kernel_string_n($argp->name, $argp->len) + createmode = $argp->createmode + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc3.create" + argstr = sprintf("%s (mode=%s)", +@@ -775,8 +803,8 @@ probe nfsd.proc4.create = kernel.function("nfsd4_create").call !, + filename = kernel_string_n($create->cr_name, $create->cr_namelen) + createmode = $create->cr_type + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc4.create" + argstr = sprintf("%s (type=%s)", +@@ -830,8 +858,8 @@ probe nfsd.proc2.remove = kernel.function("nfsd_proc_remove") !, + filelen = $argp->len + filename = kernel_string_n($argp->name, $argp->len) + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc2.remove" + argstr = sprintf("%s", kernel_string_n($argp->name, $argp->len)) +@@ -859,8 +887,8 @@ probe nfsd.proc3.remove = kernel.function("nfsd3_proc_remove") !, + filelen = $argp->len + filename = kernel_string_n($argp->name, $argp->len) + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc3.remove" + argstr = sprintf("%s", kernel_string_n($argp->name, $argp->len)) +@@ -887,8 +915,8 @@ probe nfsd.proc4.remove = kernel.function("nfsd4_remove").call !, + filelen = $remove->rm_namelen + filename = kernel_string_n($remove->rm_name, $remove->rm_namelen) + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc4.remove" + argstr = sprintf("%s", +@@ -946,8 +974,8 @@ probe nfsd.proc2.rename = kernel.function("nfsd_proc_rename") !, + tlen = $argp->tlen + tname = kernel_string_n($argp->tname, $argp->tlen) + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc2.rename" + argstr = sprintf("%s to %s", +@@ -980,8 +1008,8 @@ probe nfsd.proc3.rename = kernel.function("nfsd3_proc_rename") !, + tlen = $argp->tlen + tname = kernel_string_n($argp->tname, $argp->tlen) + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc3.rename" + argstr = sprintf("%s to %s", +@@ -1014,8 +1042,8 @@ probe nfsd.proc4.rename = kernel.function("nfsd4_rename").call !, + tlen = $rename->rn_tnamelen + tname = kernel_string_n($rename->rn_tname, $rename->rn_tnamelen) + +- uid = $rqstp->rq_cred->cr_uid +- gid = $rqstp->rq_cred->cr_gid ++ uid = __rqstp_uid($rqstp) ++ gid = __rqstp_gid($rqstp) + + name = "nfsd.proc4.rename" + argstr = sprintf("%s to %s", +@@ -1093,15 +1121,29 @@ probe nfsd.open.return = kernel.function("nfsd_open").return !, + * + * @filename: file name + */ +-probe nfsd.close = kernel.function("nfsd_close") !, +- module("nfsd").function("nfsd_close") ? ++probe nfsd.close = __nfsd.call_close ?, __nfsd.inlined_close ? + { + client_ip ="N/A" +- filename = __file_filename($filp) +- + name = "nfsd.close" + argstr = sprintf("%s",filename) + } ++/* ++ * Why split nfsd.close up into '__nfsd.call_close' and ++ * '__nfds.inlined_close'? We need the '@choose_defined()' since ++ * SystemTap has trouble accessing the arguments of inlined functions ++ * (PR 1155). But, if we only used '@choose_defined()', we wouldn't ++ * automatically notice a change in the argument name. ++ */ ++probe __nfsd.call_close = kernel.function("nfsd_close").call !, ++ module("nfsd").function("nfsd_close").call ? ++{ ++ filename = __file_filename($filp) ++} ++probe __nfsd.inlined_close = kernel.function("nfsd_close").inline !, ++ module("nfsd").function("nfsd_close").inline ? ++{ ++ filename = __file_filename(@choose_defined($filp, 0)) ++} + + probe nfsd.close.return = kernel.function("nfsd_close").return !, + module("nfsd").function("nfsd_close").return ? +diff --git a/tapset/linux/rpc.stp b/tapset/linux/rpc.stp +index 0b8d957..10c9d74 100644 +--- a/tapset/linux/rpc.stp ++++ b/tapset/linux/rpc.stp +@@ -289,7 +289,8 @@ probe sunrpc.clnt.clone_client = kernel.function("rpc_clone_client") !, + servername = kernel_string(@choose_defined($clnt->cl_server, + @cast(rcu_dereference($clnt->cl_xprt), + "struct rpc_xprt")->servername)) +- progname = kernel_string($clnt->cl_protname) ++ progname = kernel_string(@choose_defined($clnt->cl_program->name, ++ $clnt->cl_protname)) + prog = prog_from_clnt($clnt) + vers = vers_from_clnt($clnt) + prot = prot_from_clnt($clnt) +@@ -337,7 +338,8 @@ probe sunrpc.clnt.shutdown_client = kernel.function("rpc_shutdown_client") !, + servername = kernel_string(@choose_defined($clnt->cl_server, + @cast(rcu_dereference($clnt->cl_xprt), + "struct rpc_xprt")->servername)) +- progname = kernel_string($clnt->cl_protname) ++ progname = kernel_string(@choose_defined($clnt->cl_program->name, ++ $clnt->cl_protname)) + prog = prog_from_clnt($clnt) + vers = vers_from_clnt($clnt) + prot = prot_from_clnt($clnt) +@@ -409,7 +411,8 @@ probe sunrpc.clnt.bind_new_program = + servername = kernel_string(@choose_defined($old->cl_server, + @cast(rcu_dereference($old->cl_xprt), + "struct rpc_xprt")->servername)) +- old_progname = kernel_string($old->cl_protname) ++ old_progname = kernel_string(@choose_defined($old->cl_program->name, ++ $old->cl_protname)) + old_prog = prog_from_clnt($old) + old_vers = vers_from_clnt($old) + progname = kernel_string($program->name) +@@ -450,7 +453,8 @@ probe sunrpc.clnt.call_sync = kernel.function("rpc_call_sync") !, + servername = kernel_string(@choose_defined($clnt->cl_server, + @cast(rcu_dereference($clnt->cl_xprt), + "struct rpc_xprt")->servername)) +- progname = kernel_string($clnt->cl_protname) ++ progname = kernel_string(@choose_defined($clnt->cl_program->name, ++ $clnt->cl_protname)) + prog = prog_from_clnt($clnt) + vers = vers_from_clnt($clnt) + prot = prot_from_clnt($clnt) +@@ -497,7 +501,8 @@ probe sunrpc.clnt.call_async = kernel.function("rpc_call_async") !, + servername = kernel_string(@choose_defined($clnt->cl_server, + @cast(rcu_dereference($clnt->cl_xprt), + "struct rpc_xprt")->servername)) +- progname = kernel_string($clnt->cl_protname) ++ progname = kernel_string(@choose_defined($clnt->cl_program->name, ++ $clnt->cl_protname)) + prog = prog_from_clnt($clnt) + vers = vers_from_clnt($clnt) + prot = prot_from_clnt($clnt) +diff --git a/tapset/linux/scsi.stp b/tapset/linux/scsi.stp +index b8f0c2c..d54e83e 100644 +--- a/tapset/linux/scsi.stp ++++ b/tapset/linux/scsi.stp +@@ -126,15 +126,19 @@ probe scsi.iodispatching + * @scsi_timer_pending: 1 if a timer is pending on this request + */ + probe scsi.iodone +- = module("scsi_mod").function("scsi_done@drivers/scsi/scsi.c")!, ++ = kernel.trace("scsi_dispatch_cmd_done")!, ++ module("scsi_mod").function("scsi_done@drivers/scsi/scsi.c")!, + kernel.function("scsi_done@drivers/scsi/scsi.c")? + + { +- host_no = $cmd->device->host->host_no +- channel = $cmd->device->channel +- lun = $cmd->device->lun +- dev_id = $cmd->device->id +- device_state = $cmd->device->sdev_state ++ # Why is the @cast() needed here? When the probe alias uses ++ # the "scsi_dispatch_cmd_done" tracepoint, the type info isn't ++ # in scope. ++ host_no = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->host->host_no ++ channel = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->channel ++ lun = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->lun ++ dev_id = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->id ++ device_state = @cast($cmd->device, "scsi_device", "kernel:scsi_mod")->sdev_state + device_state_str = describe_device_state(device_state) + data_direction = $cmd->sc_data_direction + data_direction_str = describe_data_direction(data_direction) +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1073640.1.patch b/SOURCES/rhbz1073640.1.patch new file mode 100644 index 0000000..42c9439 --- /dev/null +++ b/SOURCES/rhbz1073640.1.patch @@ -0,0 +1,354 @@ +From f4faaf86acd0fe9d410c16c8ec44664ef92559ef Mon Sep 17 00:00:00 2001 +From: Josh Stone <jistone@redhat.com> +Date: Wed, 13 Nov 2013 17:04:19 -0800 +Subject: [PATCH] PR16162: Support .plt probes on prelinked libraries + +There were a few bias issues in how plt addresses were handled, which +broke in the face of prelink offsets. This patch tries to standardize +how these addresses are handled. + +* tapsets.cxx (query_plt_statement): New function to fix plt addresses, + both adding dwfl's elf bias and subtracting the dw bias, so it will + work with dwflpp::relocate_address like everything else. + (base_query::base_query): Leave session::consult_symtab alone! + (dwarf_query::query_module_symtab): PLT doesn't fake a path through + the symbol table anymore. + (dwarf_query::handle_query_module): Direct PLT to query_plt_statement. + (dwarf_query::add_probe_point): Remove the relocate exemption for plt. +* testsuite/systemtap.base/plt.exp: Update with a prelink test, and + refactor a lot of the test on the way. +--- + tapsets.cxx | 52 ++++++++----- + testsuite/systemtap.base/plt.exp | 163 ++++++++++++++++----------------------- + testsuite/systemtap.base/plt.stp | 9 +++ + 3 files changed, 109 insertions(+), 115 deletions(-) + create mode 100644 testsuite/systemtap.base/plt.stp + +diff --git a/tapsets.cxx b/tapsets.cxx +index 49740b0..f7947ca 100644 +--- a/tapsets.cxx ++++ b/tapsets.cxx +@@ -405,6 +405,7 @@ static const string TOK_CLASS("class");; + + static int query_cu (Dwarf_Die * cudie, void * arg); + static void query_addr(Dwarf_Addr addr, dwarf_query *q); ++static void query_plt_statement(dwarf_query *q); + + // Can we handle this query with just symbol-table info? + enum dbinfo_reqt +@@ -665,8 +666,6 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params): + if ((has_plt = has_null_param (params, TOK_PLT))) + plt_val = "*"; + else has_plt = get_string_param (params, TOK_PLT, plt_val); +- if (has_plt) +- sess.consult_symtab = true; + has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val); + + if (has_process) +@@ -1049,14 +1048,7 @@ dwarf_query::query_module_symtab() + // Find the "function" in which the indicated address resides. + Dwarf_Addr addr = + (has_function_num ? function_num_val : statement_num_val); +- if (has_plt) +- { +- // Use the raw address from the .plt +- fi = sym_table->get_first_func(); +- fi->addr = addr; +- } +- else +- fi = sym_table->get_func_containing_address(addr); ++ fi = sym_table->get_func_containing_address(addr); + + if (!fi) + { +@@ -1081,6 +1073,12 @@ dwarf_query::query_module_symtab() + void + dwarf_query::handle_query_module() + { ++ if (has_plt && has_statement_num) ++ { ++ query_plt_statement (this); ++ return; ++ } ++ + bool report = dbinfo_reqt == dbr_need_dwarf || !sess.consult_symtab; + dw.get_module_dwarf(false, report); + +@@ -1250,14 +1248,7 @@ dwarf_query::add_probe_point(const string& dw_funcname, + + assert (! has_absolute); // already handled in dwarf_builder::build() + +- if (!has_plt) +- reloc_addr = dw.relocate_address(addr, reloc_section); +- else +- { +- // Set the reloc_section but use the plt entry for reloc_addr +- dw.relocate_address(addr, reloc_section); +- reloc_addr = addr; +- } ++ reloc_addr = dw.relocate_address(addr, reloc_section); + + // If we originally used the linkage name, then let's call it that way + const char* linkage_name; +@@ -1515,6 +1506,29 @@ query_addr(Dwarf_Addr addr, dwarf_query *q) + } + + static void ++query_plt_statement(dwarf_query *q) ++{ ++ assert (q->has_plt && q->has_statement_num); ++ ++ Dwarf_Addr addr = q->statement_num_val; ++ if (q->sess.verbose > 2) ++ clog << "query_plt_statement 0x" << hex << addr << dec << endl; ++ ++ // First adjust the raw address to dwfl's elf bias. ++ Dwarf_Addr elf_bias; ++ Elf *elf = dwfl_module_getelf (q->dw.module, &elf_bias); ++ assert(elf); ++ addr += elf_bias; ++ ++ // Now compensate for the dw bias ++ q->dw.get_module_dwarf(false, false); ++ addr -= q->dw.module_bias; ++ ++ // Build a probe at this point ++ query_statement(q->plt_val, NULL, -1, NULL, addr, q); ++} ++ ++static void + query_label (string const & func, + char const * label, + char const * file, +@@ -2233,8 +2247,6 @@ query_one_plt (const char *entry, long addr, dwflpp & dw, + if (dw.sess.verbose > 2) + clog << _F("plt entry=%s\n", entry); + +- // query_module_symtab requires .plt to recognize that it can set the probe at +- // a plt entry so we convert process.plt to process.plt.statement + vector<probe_point::component*>::iterator it; + for (it = specific_loc->components.begin(); + it != specific_loc->components.end(); ++it) +diff --git a/testsuite/systemtap.base/plt.exp b/testsuite/systemtap.base/plt.exp +index 71b7987..a6d2a86 100644 +--- a/testsuite/systemtap.base/plt.exp ++++ b/testsuite/systemtap.base/plt.exp +@@ -1,4 +1,5 @@ + set test "plt" ++set script "$srcdir/$subdir/$test.stp" + + proc cleanup_handler { verbose } { + if { $verbose == 0 } { +@@ -20,127 +21,99 @@ proc error_handler { res test message } { + } + } + ++set ::result_string \ ++{__cxa_finalize 2 ++__libc_start_main 1 ++__xpg_basename 1 ++asctime 1 ++asprintf 3 ++basename2 1 ++bsearch 3 ++critters 1 ++datetime 1 ++find_critter 3 ++fprintf 3 ++fputs 3 ++free 4 ++localtime 1 ++malloc 3 ++memcpy 1 ++open 2 ++open2 1 ++open3 1 ++print_critter 32 ++printf 38 ++qsort 1 ++register_printf_function 1 ++savestring 1 ++stpcpy 4 ++strcmp 51 ++strftime 2 ++strlen 4 ++time 1 ++widgets 1 ++xmalloc 2 ++zenme 1} ++ + if {![installtest_p]} { untested $test; return } + if {![plt_probes_p]} { untested $test; return } + +-set stap_path $env(SYSTEMTAP_PATH)/stap +- + set exepath "./plt.x" + ++ + set F additional_flags +-set flags "$F=-I. $F=-shared $F=-fPIC $F=-DLIBPLT1 $F=-g $F=-Wno-deprecated-declarations $F=-Wno-format" ++set common_flags "$F=-g $F=-Wno-deprecated-declarations $F=-Wno-format $F=-fno-builtin" ++set flags "$F=-I. $F=-shared $F=-fPIC $F=-DLIBPLT1 $common_flags" + set res [target_compile $srcdir/$subdir/plt.c ./libplt1.so executable $flags ] + if { [error_handler [expr {$res == ""}] "target_compile libplt1.so" ""] } { return } + +-set flags "$F=-I. $F=-shared $F=-fPIC $F=-DLIBPLT2 $F=-g $F=-Wno-deprecated-declarations $F=-Wno-format" ++set flags "$F=-I. $F=-shared $F=-fPIC $F=-DLIBPLT2 $common_flags" + set res [target_compile $srcdir/$subdir/plt.c ./libplt2.so executable $flags ] + if { [error_handler [expr {$res == ""}] "target_compile libplt2.so" ""] } { return } + +-set flags "$F=-Wl,-rpath,[pwd] $F=-L[pwd] $F=-lplt1 $F=-lplt2 $F=-DONLY_MAIN $F=-g $F=-Wno-deprecated-declarations $F=-Wno-format" ++set flags "$F=-Wl,-rpath,[pwd] $F=-L[pwd] $F=-lplt1 $F=-lplt2 $F=-DONLY_MAIN $common_flags" + set res [target_compile $srcdir/$subdir/plt.c $exepath executable $flags ] + if { [error_handler [expr {$res == ""}] "target_compile plt.x" ""] } { return } + + # test process.plt + +-set ok 0 +-spawn $stap_path -c $exepath -e "global calls probe process(\"./plt.x\").plt {calls\[\$\$name\] += 1} probe process(\"./libplt1.so\").plt {calls\[\$\$name\] += 1} probe process(\"./libplt2.so\").plt {calls\[\$\$name\] += 1} probe end {foreach (x in calls) printf (\"%s %d\\n\", x, calls\[x\])}" +- +-expect { +- -timeout 180 +- -re {__libc_start_main 1\r\n} { incr ok; exp_continue } +- -re {xmalloc 2\r\n} { incr ok; exp_continue } +- -re {savestring 1\r\n} { incr ok; exp_continue } +- -re {memcpy 1\r\n} { incr ok; exp_continue } +- -re {open2 1\r\n} { incr ok; exp_continue } +- -re {stpcpy 4\r\n} { incr ok; exp_continue } +- -re {open 2\r\n} { incr ok; exp_continue } +- -re {open3 1\r\n} { incr ok; exp_continue } +- -re {basename2 1\r\n} { incr ok; exp_continue } +- -re {__xpg_basename 1\r\n} { incr ok; exp_continue } +- -re {critters 1\r\n} { incr ok; exp_continue } +- -re {print_critter 32\r\n} { incr ok; exp_continue } +- -re {printf 36\r\n} { incr ok; exp_continue } +- -re {putchar 2\r\n} { incr ok; exp_continue } +- -re {qsort 1\r\n} { incr ok; exp_continue } +- -re {strcmp 51\r\n} { incr ok; exp_continue } +- -re {find_critter 3\r\n} { incr ok; exp_continue } +- -re {bsearch 3\r\n} { incr ok; exp_continue } +- -re {widgets 1\r\n} { incr ok; exp_continue } +- -re {register_printf_function 1\r\n} { incr ok; exp_continue } +- -re {asprintf 3\r\n} { incr ok; exp_continue } +- -re {fprintf 3\r\n} { incr ok; exp_continue } +- -re {datetime 1\r\n} { incr ok; exp_continue } +- -re {time 1\r\n} { incr ok; exp_continue } +- -re {localtime 1\r\n} { incr ok; exp_continue } +- -re {asctime 1\r\n} { incr ok; exp_continue } +- -re {fputs 3\r\n} { incr ok; exp_continue } +- -re {strftime 2\r\n} { incr ok; exp_continue } +- timeout { fail "$test (timeout)" } +- eof { } +-} +- +-catch { close}; catch { wait} +- +-error_handler [expr {$ok == 28}] "plt" "($ok != 28)" ++set pp {process("./plt.x").plt, process("./libplt1.so").plt, process("./libplt2.so").plt} ++stap_run3 "plt" "$script" "$pp" -c "$exepath >/dev/null" + + # test process.library.plt + +-set ok 0 +-spawn $stap_path -c $exepath -e "global calls probe process(\"./plt.x\").plt {calls\[\$\$name\] += 1} probe process(\"./plt.x\").library(\"*\").plt {calls\[\$\$name\] += 1} probe end {foreach (x in calls) printf (\"%s %d\\n\", x, calls\[x\])}" ++set pp {process("./plt.x").plt, process("./plt.x").library("libplt*").plt} ++stap_run3 "plt library" "$script" "$pp" -c "$exepath >/dev/null" + +-expect { +- -timeout 180 +- -re {__libc_start_main 1\r\n} { incr ok; exp_continue } +- -re {xmalloc 2\r\n} { incr ok; exp_continue } +- -re {savestring 1\r\n} { incr ok; exp_continue } +- -re {memcpy 1\r\n} { incr ok; exp_continue } +- -re {open2 1\r\n} { incr ok; exp_continue } +- -re {stpcpy 4\r\n} { incr ok; exp_continue } +- -re {open 2\r\n} { incr ok; exp_continue } +- -re {open3 1\r\n} { incr ok; exp_continue } +- -re {basename2 1\r\n} { incr ok; exp_continue } +- -re {__xpg_basename 1\r\n} { incr ok; exp_continue } +- -re {critters 1\r\n} { incr ok; exp_continue } +- -re {print_critter 32\r\n} { incr ok; exp_continue } +- -re {printf 36\r\n} { incr ok; exp_continue } +- -re {putchar 2\r\n} { incr ok; exp_continue } +- -re {qsort 1\r\n} { incr ok; exp_continue } +- -re {strcmp 51\r\n} { incr ok; exp_continue } +- -re {find_critter 3\r\n} { incr ok; exp_continue } +- -re {bsearch 3\r\n} { incr ok; exp_continue } +- -re {widgets 1\r\n} { incr ok; exp_continue } +- -re {register_printf_function 1\r\n} { incr ok; exp_continue } +- -re {asprintf 3\r\n} { incr ok; exp_continue } +- -re {fprintf 3\r\n} { incr ok; exp_continue } +- -re {datetime 1\r\n} { incr ok; exp_continue } +- -re {time 1\r\n} { incr ok; exp_continue } +- -re {localtime 1\r\n} { incr ok; exp_continue } +- -re {asctime 1\r\n} { incr ok; exp_continue } +- -re {fputs 3\r\n} { incr ok; exp_continue } +- -re {strftime 2\r\n} { incr ok; exp_continue } +- timeout { fail "$test (timeout)" } +- eof { } ++# test process.library.plt prelinked ++ ++set prelink_bin "/usr/sbin/prelink" ++if {[file exists $prelink_bin]} { ++ set addr "-r 0x6400000" ++ set prelink_cmd [concat $prelink_bin -vfNR $addr libplt1.so] ++ send_log "Executing: $prelink_cmd\n" ++ catch {eval exec $prelink_cmd} result ++ if { $result != "" } { ++ verbose -log "prelink failed: $result" ++ fail "plt prelink libplt1.so" ++ untested "plt prelinked library" ++ } else { ++ pass "plt prelink libplt1.so" ++ ++ set pp {process("./plt.x").plt, process("./plt.x").library("libplt*").plt} ++ stap_run3 "plt prelinked library" "$script" "$pp" -c "$exepath >/dev/null" ++ } ++} else { ++ untested "plt prelink libplt1.so" ++ untested "plt prelinked library" + } + +-catch { close}; catch { wait} +- +-error_handler [expr {$ok == 28}] "plt library" "($ok != 28)" +- + # test process.plt("glob") + + set ok 0 +-spawn $stap_path -c $exepath -e "global calls probe process(\"./libplt2.so\").plt(\"strcmp\") {calls\[\$\$name\] += 1} probe end {foreach (x in calls) printf (\"%s %d\\n\", x, calls\[x\])}" ++set ::result_string {strcmp 51} ++set pp {process("./libplt2.so").plt("strcmp")} ++stap_run3 "plt glob" "$script" "$pp" -c "$exepath >/dev/null" + +-expect { +- -timeout 180 +- -re {strcmp 51\r\n} { incr ok; exp_continue } +- -re {printf 36\r\n} { incr ok; exp_continue } +- timeout { fail "$test (timeout)" } +- eof { } +-} +- +-catch { close}; catch { wait} +- +-error_handler [expr {$ok == 1}] "plt glob" "($ok != 1)" + + cleanup_handler $verbose +diff --git a/testsuite/systemtap.base/plt.stp b/testsuite/systemtap.base/plt.stp +new file mode 100644 +index 0000000..286c4e9 +--- /dev/null ++++ b/testsuite/systemtap.base/plt.stp +@@ -0,0 +1,9 @@ ++global calls ++probe $1 { ++ calls[$$name] += 1 ++} ++probe end { ++ foreach (x+ in calls) ++ printf ("%s %d\n", x, calls[x]) ++} ++ +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1073640.2.patch b/SOURCES/rhbz1073640.2.patch new file mode 100644 index 0000000..31d870e --- /dev/null +++ b/SOURCES/rhbz1073640.2.patch @@ -0,0 +1,247 @@ +From 91bb9081f0f2342d2e7df985d448ea9c9ebd34b5 Mon Sep 17 00:00:00 2001 +From: Lukas Berk <lberk@redhat.com> +Date: Fri, 29 Nov 2013 16:34:11 -0500 +Subject: [PATCH] PR10208 Support probing weak symbols + +*tapsets.cxx - Now always query the symtab (unless there is a pending interrupt + or dwarf callback error) on a function probe. We need to be careful + to check probe point's we've already resolved which will already + have full debug information and to not place another probe there. + We've removed the case of probing the symbol table on a statement probe, + as that code was written specifically for the kernel without userspace + in mind and was resolving the function the statement resided in (causing + errors in some cases). + +*list.exp - Added testcase for weak symbols +*last_100_frees.stp - we use @defined($mem) here because on 64 bit systems, the + wildcard search takes us through both 64 bit and 32 bit libc + (which doesn't have debuginfo), this means the probe point + resolved from the 32 bit library has no context info +*mutex-contention.stp - ditto but for @defined($mutex) and @defined($rwlock) +--- + tapsets.cxx | 94 ++++++++++++---------- + testsuite/systemtap.base/list.exp | 4 + + .../systemtap.examples/memory/last_100_frees.stp | 12 ++- + .../process/mutex-contention.stp | 14 +++- + 4 files changed, 74 insertions(+), 50 deletions(-) + +diff --git a/tapsets.cxx b/tapsets.cxx +index 7927106..4e05d4a 100644 +--- a/tapsets.cxx ++++ b/tapsets.cxx +@@ -989,6 +989,40 @@ dwarf_query::query_module_dwarf() + static void query_func_info (Dwarf_Addr entrypc, func_info & fi, + dwarf_query * q); + ++static void ++query_symtab_func_info (func_info & fi, dwarf_query * q) ++{ ++ assert(null_die(&fi.die)); ++ ++ Dwarf_Addr addr = fi.addr; ++ ++ // Now compensate for the dw bias because the addresses come ++ // from dwfl_module_symtab, so fi->addr is NOT a normal dw address. ++ q->dw.get_module_dwarf(false, false); ++ addr -= q->dw.module_bias; ++ ++ // If there are already probes in this module, lets not duplicate. ++ // This can come from other weak symbols/aliases or existing ++ // matches from Dwarf DIE functions. ++ if (q->alias_dupes.size() > 0) ++ { ++ for (set<Dwarf_Addr>::iterator it=q->alias_dupes.begin(); it!=q->alias_dupes.end(); ++it) ++ { ++ // If we've already got a probe at that pc, skip it ++ if (*it == addr) ++ return; ++ if (*it != addr && ++it==q->alias_dupes.end()) ++ { ++ // Build a probe at this point ++ query_func_info(addr, fi, q); ++ return; ++ } ++ } ++ } ++ else ++ query_func_info(addr,fi,q); ++} ++ + void + dwarf_query::query_module_symtab() + { +@@ -1014,15 +1048,6 @@ dwarf_query::query_module_symtab() + assert(spec_type == function_alone); + if (dw.name_has_wildcard(function_str_val)) + { +- // Until we augment the blacklist sufficently... +- if ((function_str_val.find_first_not_of("*?") == string::npos) && !dw.has_gnu_debugdata()) +- { +- // e.g., kernel.function("*") +- cerr << _F("Error: Pattern '%s' matches every single " +- "instruction address in the symbol table,\n" +- "some of which aren't even functions.\n", function_str_val.c_str()) << endl; +- return; +- } + symbol_table::iterator_t iter; + for (iter = sym_table->map_by_addr.begin(); + iter != sym_table->map_by_addr.end(); +@@ -1032,42 +1057,16 @@ dwarf_query::query_module_symtab() + if (!null_die(&fi->die)) + continue; // already handled in query_module_dwarf() + if (dw.function_name_matches_pattern(fi->name, function_str_val)) +- query_func_info(fi->addr, *fi, this); ++ query_symtab_func_info(*fi, this); + } + } + else + { + fi = sym_table->lookup_symbol(function_str_val); + if (fi && !fi->descriptor && null_die(&fi->die)) +- query_func_info(fi->addr, *fi, this); ++ query_symtab_func_info(*fi, this); + } + } +- else +- { +- assert(has_function_num || has_statement_num); +- // Find the "function" in which the indicated address resides. +- Dwarf_Addr addr = +- (has_function_num ? function_num_val : statement_num_val); +- fi = sym_table->get_func_containing_address(addr); +- +- if (!fi) +- { +- sess.print_warning(_F("address %#" PRIx64 " out of range for module %s", +- addr, dw.module_name.c_str())); +- return; +- } +- if (!null_die(&fi->die)) +- { +- // addr looks like it's in the compilation unit containing +- // the indicated function, but query_module_dwarf() didn't +- // match addr to any compilation unit, so addr must be +- // above that cu's address range. +- sess.print_warning(_F("address %#" PRIx64 " maps to no known compilation unit in module %s", +- addr, dw.module_name.c_str())); +- return; +- } +- query_func_info(fi->addr, *fi, this); +- } + } + + void +@@ -1092,10 +1091,11 @@ dwarf_query::handle_query_module() + if (dw.mod_info->dwarf_status == info_present) + query_module_dwarf(); + +- // Consult the symbol table if we haven't found all we're looking for. +- // asm functions can show up in the symbol table but not in dwarf, +- // or if we want to check the .gnu_debugdata section +- if ((sess.consult_symtab || dw.has_gnu_debugdata()) && !query_done) ++ // Consult the symbol table, asm and weak functions can show up ++ // in the symbol table but not in dwarf and minidebuginfo is ++ // located in the gnu_debugdata section, alias_dupes checking ++ // is done before adding any probe points ++ if (!query_done && !pending_interrupts) + query_module_symtab(); + } + +@@ -1252,7 +1252,7 @@ dwarf_query::add_probe_point(const string& dw_funcname, + + // If we originally used the linkage name, then let's call it that way + const char* linkage_name; +- if (scope_die && startswith (this->function, "_Z") ++ if (!null_die(scope_die) && startswith (this->function, "_Z") + && (linkage_name = dwarf_linkage_name (scope_die))) + funcname = linkage_name; + +@@ -1954,8 +1954,14 @@ dwarf_query::query_module_functions () + inline_dupes.clear(); + + // Run the query again on the individual CUs +- for (vector<Dwarf_Die>::iterator i = cus.begin(); i != cus.end(); ++i) +- query_cu(&*i, this); ++ for (vector<Dwarf_Die>::iterator i = cus.begin(); i != cus.end(); ++i){ ++ rc = query_cu(&*i, this); ++ if (rc != DWARF_CB_OK) ++ { ++ query_done = true; ++ return; ++ } ++ } + } + catch (const semantic_error& e) + { +diff --git a/testsuite/systemtap.base/list.exp b/testsuite/systemtap.base/list.exp +index 1aa97f8..bae7e0e 100644 +--- a/testsuite/systemtap.base/list.exp ++++ b/testsuite/systemtap.base/list.exp +@@ -81,3 +81,7 @@ test_list copy_flags-inline {kernel.function("copy_flags@kernel/fork.c").inline} + # PR15587: make sure we have line numbers on statements of an inline function + test_list copy_flags-statement {kernel.statement("copy_flags@kernel/fork.c:*")} \ + {kernel.statement."copy_flags@kernel/fork.c:\d+".\r\n} ++ ++# PR10208: ensure we can probe weak symbols ++test_uprobes_list function-weak {process("/lib*/libc.so.*").function("chmod")} \ ++ {process.*.function."chmod".\r\n} +diff --git a/testsuite/systemtap.examples/memory/last_100_frees.stp b/testsuite/systemtap.examples/memory/last_100_frees.stp +index 06d7acf..4ca43b5 100755 +--- a/testsuite/systemtap.examples/memory/last_100_frees.stp ++++ b/testsuite/systemtap.examples/memory/last_100_frees.stp +@@ -1,10 +1,16 @@ +-#! /usr/bin/env stap ++#! /usr/bin/env stap + + global bt%[100] + + probe process("/lib*/libc.so.*").function("free") { +- bt[execname(),tid(),$mem,sprint_ubacktrace()] +- <<< local_clock_ns() ++ // we use @defined($mem) here because on 64 bit systems, the ++ // wildcard search takes us through both 64 bit and 32 bit ++ // libc (which doesn't have debuginfo), this means the probe ++ // point resolved from the 32 bit library has no context info ++ if (@defined($mem)) { ++ bt[execname(),tid(),$mem,sprint_ubacktrace()] ++ <<< local_clock_ns() ++ } + // Any monotonically increasing expression would do. + // With some arbitrary expression or constant instead, + // at worst we get the last 100ish results out of order. +diff --git a/testsuite/systemtap.examples/process/mutex-contention.stp b/testsuite/systemtap.examples/process/mutex-contention.stp +index 669618e..f418754 100755 +--- a/testsuite/systemtap.examples/process/mutex-contention.stp ++++ b/testsuite/systemtap.examples/process/mutex-contention.stp +@@ -71,17 +71,25 @@ function show_contention(mutex, stack, type) + } + } + ++// we use @defined($muex) and @defined($rwlock) here because ++// on 64 bit systems, the wildcard search takes us through ++// both 64 bit and 32 bit libc (which doesn't have debuginfo), ++// this means the probe point resolved from the 32 bit library ++// has no context info + probe process("/lib*/libc.so*").function("pthread_mutex_init") + { +- process_mutex_init($mutex, probefunc()) ++ if(@defined($mutex)) ++ process_mutex_init($mutex, probefunc()) + } + probe process("/lib*/libpthread.so*").function("__pthread_mutex_init") + { +- process_mutex_init($mutex, probefunc()) ++ if(@defined($mutex)) ++ process_mutex_init($mutex, probefunc()) + } + probe process("/lib*/libpthread.so*").function("__pthread_rwlock_init") + { +- process_mutex_init($rwlock, probefunc()) ++ if(@defined($rwlock)) ++ process_mutex_init($rwlock, probefunc()) + } + + probe syscall.futex.return +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1073640.3.patch b/SOURCES/rhbz1073640.3.patch new file mode 100644 index 0000000..1ed495d --- /dev/null +++ b/SOURCES/rhbz1073640.3.patch @@ -0,0 +1,52 @@ +From a41f2ad77a642e70f46caa8261746c651f5dc2ad Mon Sep 17 00:00:00 2001 +From: Josh Stone <jistone@redhat.com> +Date: Mon, 2 Dec 2013 14:34:07 -0800 +Subject: [PATCH] Use proper set operations for symtab dupe checks + +In query_symtab_func_info, rather than full set iteration to check an +address in alias_dupes, just use set::insert().second as a test. This +is what sets are designed to be algorithmically good at. + +This also has the benefit of adding to alias_dupes, so duplicates within +the symbol table itself will still only be probed once. (If we didn't +want that effect, we would just use set::count() to test membership.) +--- + tapsets.cxx | 22 ++++------------------ + 1 file changed, 4 insertions(+), 18 deletions(-) + +diff --git a/tapsets.cxx b/tapsets.cxx +index f1a5843..b3cfa0e 100644 +--- a/tapsets.cxx ++++ b/tapsets.cxx +@@ -1003,24 +1003,10 @@ query_symtab_func_info (func_info & fi, dwarf_query * q) + + // If there are already probes in this module, lets not duplicate. + // This can come from other weak symbols/aliases or existing +- // matches from Dwarf DIE functions. +- if (q->alias_dupes.size() > 0) +- { +- for (set<Dwarf_Addr>::iterator it=q->alias_dupes.begin(); it!=q->alias_dupes.end(); ++it) +- { +- // If we've already got a probe at that pc, skip it +- if (*it == addr) +- return; +- if (*it != addr && ++it==q->alias_dupes.end()) +- { +- // Build a probe at this point +- query_func_info(addr, fi, q); +- return; +- } +- } +- } +- else +- query_func_info(addr,fi,q); ++ // matches from Dwarf DIE functions. Try to add this addr to the ++ // collection, and only continue if it was new. ++ if (q->alias_dupes.insert(addr).second) ++ query_func_info(addr, fi, q); + } + + void +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1073640.4.patch b/SOURCES/rhbz1073640.4.patch new file mode 100644 index 0000000..3c58c59 --- /dev/null +++ b/SOURCES/rhbz1073640.4.patch @@ -0,0 +1,27 @@ +From 3449dd58cbbb28d6d0b89740b68ae158b08d0b1c Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Tue, 21 Jan 2014 16:14:21 -0500 +Subject: [PATCH] PR16478: always use dwarf for labels + +Now that the symtab is queried more often for function probes, we need +to explicitly make .label queries use dwarf or they won't work properly. +--- + tapsets.cxx | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tapsets.cxx b/tapsets.cxx +index d8e8cf7..5bae070 100644 +--- a/tapsets.cxx ++++ b/tapsets.cxx +@@ -1296,7 +1296,7 @@ dwarf_query::assess_dbinfo_reqt() + // kernel.statement(NUM).absolute + return dbr_none; + } +- if (has_inline) ++ if (has_inline || has_label) + { + // kernel.function("f").inline or module("m").function("f").inline + return dbr_need_dwarf; +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1073640.5.patch b/SOURCES/rhbz1073640.5.patch new file mode 100644 index 0000000..53565e1 --- /dev/null +++ b/SOURCES/rhbz1073640.5.patch @@ -0,0 +1,115 @@ +From b2c99fdcc379ae65a83e25a6b6a8bc2b77a5b03c Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon <jlebon@redhat.com> +Date: Tue, 21 Jan 2014 16:21:31 -0500 +Subject: [PATCH] testsuite: adjust tests for new probing powers + +Since we can now probe more functions (such as _start, +register_tm_clones), a few tests need to be adjusted. + +* rep_ret.exp + + Get rid of 'bad' var and handle the case where main is not the first + line printed out (which is now _start). + +* process_by_cmd.exp + + Change wildcard probe (which now picks up too many functions) for + multiple probe points targetting only the functions we want. + +* exelib.exp + + Same as process_by_cmd.exp +--- + testsuite/systemtap.base/process_by_cmd.stp | 5 ++++- + testsuite/systemtap.base/rep_ret.exp | 9 ++++++--- + testsuite/systemtap.exelib/libmarkunamestack.stp | 6 ++++-- + testsuite/systemtap.exelib/uname.stp | 6 ++++-- + 4 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/testsuite/systemtap.base/process_by_cmd.stp b/testsuite/systemtap.base/process_by_cmd.stp +index 8f744e0..5fe1dec 100644 +--- a/testsuite/systemtap.base/process_by_cmd.stp ++++ b/testsuite/systemtap.base/process_by_cmd.stp +@@ -1,3 +1,6 @@ + probe process.function("main") { printf("func end\n") } +-probe process.function("*").return { printf("func return end\n") } ++probe process.function("main").return, ++ process.function("first").return, ++ process.function("second").return, ++ process.function("third") { printf("func return end\n") } + probe process.mark("*") { printf("mark end\n") } +diff --git a/testsuite/systemtap.base/rep_ret.exp b/testsuite/systemtap.base/rep_ret.exp +index 959050e..75b64df 100644 +--- a/testsuite/systemtap.base/rep_ret.exp ++++ b/testsuite/systemtap.base/rep_ret.exp +@@ -32,11 +32,14 @@ foreach arch $arches { + + if {[installtest_p] && [uprobes_p]} { + set ok 0 +- set bad 0 + set warn 0 + + spawn stap -e {probe process(@1).function("*") { println(probefunc()) }} ./$exe -c ./$exe ++ # We have two cases for main below to handle the possibility of main not being the first ++ # line being printed out (but only one of the two will ever fire, so the count is still 3) ++ # The test however does still ensure that main is followed by rep_ret then by repnz_ret. + expect { ++ -re {\r\nmain\r\n} { incr ok; exp_continue } + -re {^main\r\n} { incr ok; exp_continue } + -re {^rep_ret\r\n} { incr ok; exp_continue } + -re {^repnz_ret\r\n} { incr ok; exp_continue } +@@ -46,10 +49,10 @@ foreach arch $arches { + } + wait + +- if {$ok == 3 && $bad == 0 && $warn == 0} { ++ if {$ok == 3 && $warn == 0} { + pass "$exe" + } else { +- fail "$exe ($ok, $bad, $warn)" ++ fail "$exe ($ok, $warn)" + } + } else { + untested "$exe" +diff --git a/testsuite/systemtap.exelib/libmarkunamestack.stp b/testsuite/systemtap.exelib/libmarkunamestack.stp +index 3ad1aa5..7894ef4 100644 +--- a/testsuite/systemtap.exelib/libmarkunamestack.stp ++++ b/testsuite/systemtap.exelib/libmarkunamestack.stp +@@ -28,11 +28,13 @@ probe process(@2).mark("func_count") { + } + + #uname +-probe process(@1).function("*") { ++probe process(@1).function("main"), ++ process(@1).function("main_func") { + printf("exe: %s=%s\n",probefunc(), usymname(uaddr())); + } + +-probe process(@2).function("*") { ++probe process(@2).function("lib_main"), ++ process(@2).function("lib_func") { + printf("lib: %s=%s\n",probefunc(), usymname(uaddr())); + } + +diff --git a/testsuite/systemtap.exelib/uname.stp b/testsuite/systemtap.exelib/uname.stp +index aaf7ef1..25e6f8d 100644 +--- a/testsuite/systemtap.exelib/uname.stp ++++ b/testsuite/systemtap.exelib/uname.stp +@@ -1,10 +1,12 @@ + // Prints probefunc() and usymname(uaddr()) to check they are similar. + // Arguments: @1 uprobes_exe, @2 libuprobes_lib.so + +-probe process(@1).function("*") { ++probe process(@1).function("main"), ++ process(@1).function("main_func") { + printf("exe: %s=%s\n",probefunc(), usymname(uaddr())); + } + +-probe process(@2).function("*") { ++probe process(@2).function("lib_main"), ++ process(@2).function("lib_func") { + printf("lib: %s=%s\n",probefunc(), usymname(uaddr())); + } +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1073640.6.patch b/SOURCES/rhbz1073640.6.patch new file mode 100644 index 0000000..cb7352b --- /dev/null +++ b/SOURCES/rhbz1073640.6.patch @@ -0,0 +1,32 @@ +From e695d462f82f64f567aadbdbe9d4c2389a406321 Mon Sep 17 00:00:00 2001 +From: Torsten Polle <Torsten.Polle@gmx.de> +Date: Fri, 7 Mar 2014 14:37:11 -0600 +Subject: [PATCH 6/8] Fix: Crash when canceling task work. + +As the elements of the list __stp_tf_task_work_list are removed from +the list, a safe iteration has to be used in __stp_tf_cancel_task_work(). +--- + runtime/linux/task_finder2.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/runtime/linux/task_finder2.c b/runtime/linux/task_finder2.c +index 16fda87..e8f33a3 100644 +--- a/runtime/linux/task_finder2.c ++++ b/runtime/linux/task_finder2.c +@@ -169,11 +169,12 @@ static void __stp_tf_free_task_work(struct task_work *work) + static void __stp_tf_cancel_task_work(void) + { + struct __stp_tf_task_work *node; ++ struct __stp_tf_task_work *tmp; + unsigned long flags; + + // Cancel all remaining requests. + spin_lock_irqsave(&__stp_tf_task_work_list_lock, flags); +- list_for_each_entry(node, &__stp_tf_task_work_list, list) { ++ list_for_each_entry_safe(node, tmp, &__stp_tf_task_work_list, list) { + // Remove the item from the list, cancel it, then free it. + list_del(&node->list); + stp_task_work_cancel(node->task, node->work.func); +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1073640.7.patch b/SOURCES/rhbz1073640.7.patch new file mode 100644 index 0000000..b0afc73 --- /dev/null +++ b/SOURCES/rhbz1073640.7.patch @@ -0,0 +1,33 @@ +From 9ee1bfe9ac1c92a0640e64a463efd43c9c5a57ac Mon Sep 17 00:00:00 2001 +From: Torsten Polle <Torsten.Polle@gmx.de> +Date: Fri, 7 Mar 2014 14:39:31 -0600 +Subject: [PATCH 7/8] Fix: stap/staprun deadlocks when probing ends. + +stap_stop_task_finder() exits utrace through utrace_exit(). At that +time, there might be outstanding task workers. Hence, waiting for +exiting the task work waits forever. Therefore exiting the task work +is done after canceling all task workers. +--- + runtime/linux/task_finder2.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/runtime/linux/task_finder2.c b/runtime/linux/task_finder2.c +index e8f33a3..a3abc16 100644 +--- a/runtime/linux/task_finder2.c ++++ b/runtime/linux/task_finder2.c +@@ -1875,10 +1875,10 @@ stap_stop_task_finder(void) + debug_task_finder_report(); + #endif + +- utrace_exit(); +- + /* Make sure all outstanding task work requests are canceled. */ + __stp_tf_cancel_task_work(); ++ ++ utrace_exit(); + } + + #endif /* TASK_FINDER2_C */ +-- +1.8.3.1 + diff --git a/SOURCES/rhbz1073640.8.patch b/SOURCES/rhbz1073640.8.patch new file mode 100644 index 0000000..2eb26fc --- /dev/null +++ b/SOURCES/rhbz1073640.8.patch @@ -0,0 +1,119 @@ +From 66283521fac33ac5716b71a6d2662093aec409c1 Mon Sep 17 00:00:00 2001 +From: David Smith <dsmith@redhat.com> +Date: Wed, 12 Mar 2014 09:07:58 -0500 +Subject: [PATCH] Improve task_finder/utrace shutdown. + +* runtime/stp_utrace.c (utrace_exit): Move the call to + stp_task_work_exit() up above the calls to free the kmem caches. This + make sure any running task work items don't have the memory freed out + from under them. +* runtime/linux/task_finder2.c (__stp_task_finder_cleanup): Move + utrace_shutdown() call into stap_stop_task_finder(). + (stap_stop_task_finder): Call utrace_shutdown() directly. Wait to make + sure all tracepoint probes are finished. +--- + runtime/linux/task_finder2.c | 24 +++++++----------------- + runtime/stp_utrace.c | 27 +++++++++++++++++++-------- + 2 files changed, 26 insertions(+), 25 deletions(-) + +diff --git a/runtime/linux/task_finder2.c b/runtime/linux/task_finder2.c +index a3abc16..ef074c5 100644 +--- a/runtime/linux/task_finder2.c ++++ b/runtime/linux/task_finder2.c +@@ -418,15 +418,6 @@ stap_utrace_detach_ops(struct utrace_engine_ops *ops) + debug_task_finder_report(); + } + +-static void +-__stp_task_finder_cleanup(void) +-{ +- // The utrace_shutdown() function detaches and deletes +- // everything for us - we don't have to go through each +- // engine. +- utrace_shutdown(); +-} +- + static char * + __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen) + { +@@ -1849,16 +1840,16 @@ stap_stop_task_finder(void) + atomic_set(&__stp_task_finder_state, __STP_TF_STOPPING); + + debug_task_finder_report(); +-#if 0 +- /* We don't need this since __stp_task_finder_cleanup() +- * removes everything by calling utrace_shutdown(). */ +- stap_utrace_detach_ops(&__stp_utrace_task_finder_ops); +-#endif +- __stp_task_finder_cleanup(); ++ ++ // The utrace_shutdown() function detaches and cleans up ++ // everything for us - we don't have to go through each ++ // engine. This also means that the attach_count could end up ++ // > 0 (since we don't got through each engine individually). ++ utrace_shutdown(); ++ + debug_task_finder_report(); + atomic_set(&__stp_task_finder_state, __STP_TF_STOPPED); + +-#if 0 + /* Now that all the engines are detached, make sure + * all the callbacks are finished. If they aren't, we'll + * crash the kernel when the module is removed. */ +@@ -1873,7 +1864,6 @@ stap_stop_task_finder(void) + printk(KERN_ERR "it took %d polling loops to quit.\n", i); + #endif + debug_task_finder_report(); +-#endif + + /* Make sure all outstanding task work requests are canceled. */ + __stp_tf_cancel_task_work(); +diff --git a/runtime/stp_utrace.c b/runtime/stp_utrace.c +index 89ea0e4..a6f363d 100644 +--- a/runtime/stp_utrace.c ++++ b/runtime/stp_utrace.c +@@ -286,12 +286,18 @@ static int utrace_exit(void) + { + utrace_shutdown(); + +- if (utrace_cachep) +- kmem_cache_destroy(utrace_cachep); +- if (utrace_engine_cachep) +- kmem_cache_destroy(utrace_engine_cachep); +- + stp_task_work_exit(); ++ ++ /* After utrace_shutdown() and stp_task_work_exit() (and the ++ * code in stap_stop_task_finder()), we're *sure* there are no ++ * tracepoint probes or task work items running or scheduled ++ * to be run. So, now would be a great time to actually free ++ * everything. */ ++ ++ if (utrace_cachep) ++ kmem_cache_destroy(utrace_cachep); ++ if (utrace_engine_cachep) ++ kmem_cache_destroy(utrace_engine_cachep); + return 0; + } + +@@ -373,9 +379,14 @@ static void utrace_shutdown(void) + unregister_trace_sys_exit(utrace_report_syscall_exit, NULL); + tracepoint_synchronize_unregister(); + +- /* After calling tracepoint_synchronize_unregister(), we're +- * sure there are no outstanding tracepoint probes being +- * called. So, now would be a great time to free everything. */ ++ /* After tracepoint_synchronize_unregister(), we're *sure* ++ * there will be no new tracepoint probes running. There could ++ * be currently running tracepoint probes or task work ++ * items. So, now would be a great time to cleanup. ++ * ++ * Currently running items should be OK, since ++ * utrace_cleanup() just puts the memory back into the utrace ++ * kmem caches. */ + + #ifdef STP_TF_DEBUG + printk(KERN_ERR "%s:%d - freeing task-specific\n", __FUNCTION__, __LINE__); +-- +1.8.3.1 + diff --git a/SOURCES/rhbz847285.patch b/SOURCES/rhbz847285.patch new file mode 100644 index 0000000..f6418d8 --- /dev/null +++ b/SOURCES/rhbz847285.patch @@ -0,0 +1,32 @@ +From 1436fd6092bf724e8bc80c53c7bc3c71ff9835cc Mon Sep 17 00:00:00 2001 +From: Dave Brolley <brolley@redhat.com> +Date: Wed, 12 Feb 2014 16:03:51 -0500 +Subject: [PATCH] RHBZ 847285: Don't allow 'systemctl reload'. + +'reload' is not supported by the stap-server script. The +ExecReload line in stap-server.service was calling +'stap-server restart' which stops the server and starts a +new one. This behavior is not expected or tolerated by systemd +which promptly sends SIGKILL to the new server. + +We cannot supported 'reload' in systemctl. Note that 'restart' +is supported and works properly. +--- + stap-server.service | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/stap-server.service b/stap-server.service +index 000ee74..76e2196 100644 +--- a/stap-server.service ++++ b/stap-server.service +@@ -8,7 +8,6 @@ After=network.target avahi-daemon.service + Type=oneshot + User=stap-server + ExecStart=/usr/bin/stap-server start +-ExecReload=/usr/bin/stap-server restart + ExecStop=/usr/bin/stap-server stop + RemainAfterExit=yes + +-- +1.8.3.1 + diff --git a/SPECS/systemtap.spec b/SPECS/systemtap.spec index c639ea2..c63d1d0 100644 --- a/SPECS/systemtap.spec +++ b/SPECS/systemtap.spec @@ -32,6 +32,7 @@ # don't want to build runtime-virthost for f18 or RHEL5/6 %{!?with_virthost: %global with_virthost 0%{?fedora} >= 19 || 0%{?rhel} >= 7} %{!?with_virtguest: %global with_virtguest 1} +%{!?with_dracut: %global with_dracut 0%{?fedora} >= 19 || 0%{?rhel} >= 7} %if 0%{?fedora} >= 18 || 0%{?rhel} >= 6 %define initdir %{_initddir} @@ -47,11 +48,44 @@ %endif %endif +%define dracutlibdir %{_prefix}/lib/dracut +%define dracutstap %{dracutlibdir}/modules.d/99stap + Name: systemtap Version: 2.4 -Release: 1%{?dist} +Release: 14%{?dist} # for version, see also configure.ac +#Patch1: reserved for elfutils (see below) +Patch2: rhbz1054962.patch +Patch3: rhbz1054956.patch +Patch4: rhbz1054954.patch +Patch5: rhbz1051649.patch +Patch6: rhbz1044429.patch +Patch7: rhbz1055778.patch +Patch8: rhbz1035752.patch +Patch9: rhbz1035850.patch +Patch10: rhbz1056687.patch +Patch11: rhbz1057773.patch +Patch12: rhbz1020207.patch +Patch13: rhbz1062076.patch +Patch14: rhbz1051649.2.patch +Patch15: rhbz847285.patch +Patch16: rhbz1073640.1.patch +Patch17: rhbz1073640.2.patch +Patch18: rhbz1073640.3.patch +Patch19: rhbz1073640.4.patch +Patch20: rhbz1073640.5.patch +Patch21: rhbz1073640.6.patch +Patch22: rhbz1073640.7.patch +Patch23: rhbz1073640.8.patch +Patch24: rhbz1051649.3.patch +Patch25: rhbz1051649.4.patch +Patch26: rhbz1051649.5.patch +Patch27: rhbz1051649.6.patch +Patch28: rhbz1051649.7.patch +Patch29: rhbz1051649.8.patch +Patch30: rhbz1051649.9.patch # Packaging abstract: # @@ -60,7 +94,7 @@ Release: 1%{?dist} # systemtap-devel /usr/bin/stap, runtime, tapset, req:kernel-devel # systemtap-runtime /usr/bin/staprun, /usr/bin/stapsh, /usr/bin/stapdyn # systemtap-client /usr/bin/stap, samples, docs, tapset(bonus), req:-runtime -# systemtap-initscript /etc/init.d/systemtap, req:systemtap +# systemtap-initscript /etc/init.d/systemtap, dracut module, req:systemtap # systemtap-sdt-devel /usr/include/sys/sdt.h /usr/bin/dtrace # systemtap-testsuite /usr/share/systemtap/testsuite*, req:systemtap, req:sdt-devel # systemtap-runtime-java libHelperSDT.so, HelperSDT.jar, stapbm, req:-runtime @@ -245,7 +279,9 @@ Requires(preun): initscripts Requires(postun): initscripts %description initscript -Sysvinit scripts to launch selected systemtap scripts at system startup. +This package includes a SysVinit script to launch selected systemtap +scripts at system startup, along with a dracut module for early +boot-time probing if supported. %package sdt-devel @@ -368,6 +404,36 @@ find . \( -name configure -o -name config.h.in \) -print | xargs touch cd .. %endif +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 + %build %if %{with_bundled_elfutils} @@ -545,6 +611,13 @@ done %endif %endif +%if %{with_dracut} + mkdir -p $RPM_BUILD_ROOT%{dracutstap} + install -p -m 755 initscript/99stap/module-setup.sh $RPM_BUILD_ROOT%{dracutstap} + install -p -m 755 initscript/99stap/start-staprun.sh $RPM_BUILD_ROOT%{dracutstap} + touch $RPM_BUILD_ROOT%{dracutstap}/params.conf +%endif + %clean rm -rf ${RPM_BUILD_ROOT} @@ -588,10 +661,11 @@ test -e %{_localstatedir}/log/stap-server/log || { if test ! -e ~stap-server/.systemtap/ssl/server/stap.cert; then runuser -s /bin/sh - stap-server -c %{_libexecdir}/systemtap/stap-gen-cert >/dev/null fi -# Activate the service +# Prepare the service %if %{with_systemd} - /bin/systemctl enable stap-server.service >/dev/null 2>&1 || : - /bin/systemd-tmpfiles --create >/dev/null 2>&1 || : + # Note, Fedora policy doesn't allow network services enabled by default + # /bin/systemctl enable stap-server.service >/dev/null 2>&1 || : + /bin/systemd-tmpfiles --create %{_tmpfilesdir}/stap-server.conf >/dev/null 2>&1 || : %else /sbin/chkconfig --add stap-server %endif @@ -615,7 +689,7 @@ if [ $1 = 0 ] ; then /bin/systemctl stop stap-server.service >/dev/null 2>&1 || : %else /sbin/service stap-server stop >/dev/null 2>&1 - /sbin/chkconfig --del stap-server + /sbin/chkconfig --del stap-server %endif fi exit 0 @@ -625,7 +699,7 @@ exit 0 # If so, restart the service if it's running if [ "$1" -ge "1" ] ; then %if %{with_systemd} - /bin/systemctl restart stap-server.service >/dev/null 2>&1 || : + /bin/systemctl condrestart stap-server.service >/dev/null 2>&1 || : %else /sbin/service stap-server condrestart >/dev/null 2>&1 || : %endif @@ -634,8 +708,7 @@ exit 0 %post initscript %if %{with_systemd} - /bin/systemctl enable stap-server.service >/dev/null 2>&1 || : - /bin/systemd-tmpfiles --create >/dev/null 2>&1 || : + /bin/systemctl enable systemtap.service >/dev/null 2>&1 || : %else /sbin/chkconfig --add systemtap %endif @@ -646,11 +719,11 @@ exit 0 # just removing the old package on upgrade. if [ $1 = 0 ] ; then %if %{with_systemd} - /bin/systemctl --no-reload disable stap-server.service >/dev/null 2>&1 || : - /bin/systemctl stop stap-server.service >/dev/null 2>&1 || : + /bin/systemctl --no-reload disable systemtap.service >/dev/null 2>&1 || : + /bin/systemctl stop systemtap.service >/dev/null 2>&1 || : %else /sbin/service systemtap stop >/dev/null 2>&1 - /sbin/chkconfig --del systemtap + /sbin/chkconfig --del systemtap %endif fi exit 0 @@ -660,7 +733,7 @@ exit 0 # If so, restart the service if it's running if [ "$1" -ge "1" ] ; then %if %{with_systemd} - /bin/systemctl restart stap-server.service >/dev/null 2>&1 || : + /bin/systemctl condrestart systemtap.service >/dev/null 2>&1 || : %else /sbin/service systemtap condrestart >/dev/null 2>&1 || : %endif @@ -916,7 +989,11 @@ done %config(noreplace) %{_sysconfdir}/systemtap/config %dir %{_localstatedir}/cache/systemtap %ghost %{_localstatedir}/run/systemtap -%doc initscript/README.systemtap +%{_mandir}/man8/systemtap.8* +%if %{with_dracut} + %dir %{dracutstap} + %{dracutstap}/* +%endif %files sdt-devel @@ -970,6 +1047,47 @@ done # http://sourceware.org/systemtap/wiki/SystemTapReleases %changelog +* Fri Mar 28 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-14 +- Small fix on latest backport fix for dyninst runtime + +* Fri Mar 28 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-13 +- Backport fixes for 1051649 (see comments 4 and 5) + +* Thu Mar 06 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-12 +- Backport fix for 1073640 + +* Wed Feb 12 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-11 +- Backport fix for 847285 + +* Wed Feb 12 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-10 +- Apply spec file patches to this one, not the tarred one +- Add missing autoreconf patch for backport feature (1051649) + +* Tue Feb 11 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-9 +- Backport fixes for: 1062076, 1020207 + +* Tue Jan 28 2014 Daniel Mach <dmach@redhat.com> - 2.4-8 +- Mass rebuild 2014-01-24 + +* Fri Jan 24 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-7 +- Backport fix for 1057773 + +* Wed Jan 22 2014 Frank Ch. Subbackportmeister Eigler <fche@redhat.com> - 2.4-6 +- Backport fixes for: 1056687 + +* Wed Jan 22 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-5 +- Backport fixes for: 1035752, 1035850 + +* Tue Jan 21 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-4 +- Backport fix for 1055778 + +* Fri Jan 17 2014 Jonathan Lebon <jlebon@redhat.com> - 2.4-3 +- Backport fixes for: 1054962, 1054956, 1054954, 1044429 +- Backport boot-time probing feature (1051649) + +* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 2.4-2 +- Mass rebuild 2013-12-27 + * Wed Nov 06 2013 Frank Ch. Eigler <fche@redhat.com> - 2.4-1 - Upstream release.