]>
sourceware.org Git - systemtap.git/blob - remote.cxx
1 // systemtap remote execution
2 // Copyright (C) 2010 Red Hat Inc.
4 // This file is part of systemtap, and is free software. You can
5 // redistribute it and/or modify it under the terms of the GNU General
6 // Public License (GPL); either version 2, or (at your option) any
10 #include <sys/utsname.h>
24 // Decode URIs as per RFC 3986, though not bothering to be strict
28 string scheme
, authority
, path
, query
, fragment
;
29 bool has_authority
, has_query
, has_fragment
;
31 uri_decoder(const string
& uri
):
32 uri(uri
), has_authority(false), has_query(false), has_fragment(false)
35 "^([^:]+):(//[^/?#]*)?([^?#]*)(\\?[^#]*)?(#.*)?$";
37 vector
<string
> matches
;
38 if (regexp_match(uri
, re
, matches
) != 0)
39 throw runtime_error("string doesn't appear to be a URI: " + uri
);
43 if (!matches
[2].empty())
46 authority
= matches
[2].substr(2);
51 if (!matches
[4].empty())
54 query
= matches
[4].substr(1);
57 if (!matches
[5].empty())
60 fragment
= matches
[5].substr(1);
66 // loopback target for running locally
67 class direct
: public remote
{
70 direct(systemtap_session
& s
): remote(s
), child(0) {}
79 pid_t pid
= stap_spawn (s
->verbose
, make_run_command (*s
));
91 int ret
= stap_waitpid(s
->verbose
, child
);
97 class ssh_remote
: public remote
{
98 // NB: ssh commands use a tty (-t) so signals are passed along to the remote
100 vector
<string
> ssh_args
, scp_args
;
105 ssh_remote(systemtap_session
& s
, const string
& host
)
106 : remote(s
), host(host
), child(0)
111 ssh_remote(systemtap_session
& s
, const uri_decoder
& ud
)
112 : remote(s
), child(0)
114 if (!ud
.has_authority
|| ud
.authority
.empty())
115 throw runtime_error("ssh target requires a hostname");
116 if (!ud
.path
.empty() && ud
.path
!= "/")
117 throw runtime_error("ssh target URI doesn't support a /path");
119 throw runtime_error("ssh target URI doesn't support a ?query");
121 throw runtime_error("ssh target URI doesn't support a #fragment");
129 open_control_master();
134 catch (runtime_error
&)
136 close_control_master();
141 void open_control_master()
143 static unsigned index
= 0;
145 if (s
->tmpdir
.empty()) // sanity check, shouldn't happen
146 throw runtime_error("No tmpdir available for ssh control master");
148 ssh_control
= s
->tmpdir
+ "/ssh_remote_control_" + lex_cast(++index
);
151 scp_args
.push_back("scp");
152 scp_args
.push_back("-q");
153 scp_args
.push_back("-o");
154 scp_args
.push_back("ControlPath=" + ssh_control
);
158 ssh_args
.push_back(host
);
160 // NB: ssh -f will stay in the foreground until authentication is
161 // complete and the control socket is created, so we know it's ready to
162 // go when stap_system returns.
163 vector
<string
> cmd
= ssh_args
;
167 int rc
= stap_system(s
->verbose
, cmd
);
171 err
<< "failed to create an ssh control master for " << host
173 throw runtime_error(err
.str());
177 clog
<< "Created ssh control master at "
178 << lex_cast_qstring(ssh_control
) << endl
;
181 void close_control_master()
183 if (ssh_control
.empty())
186 vector
<string
> cmd
= ssh_args
;
188 cmd
.push_back("exit");
189 int rc
= stap_system(s
->verbose
, cmd
, true, true);
191 cerr
<< "failed to stop the ssh control master for " << host
192 << " : rc=" << rc
<< endl
;
202 vector
<string
> uname
;
203 vector
<string
> cmd
= ssh_args
;
205 cmd
.push_back("uname -rm");
206 int rc
= stap_system_read(s
->verbose
, cmd
, out
);
208 tokenize(out
.str(), uname
, " \t\r\n");
209 if (uname
.size() != 2)
210 throw runtime_error("failed to get uname from " + host
211 + " : rc=" + lex_cast(rc
));
212 const string
& release
= uname
[0];
213 const string
& arch
= uname
[1];
214 // XXX need to deal with command-line vs. implied arch/release
215 this->s
= s
->clone(arch
, release
);
221 virtual ~ssh_remote()
223 close_control_master();
229 string localmodule
= s
->tmpdir
+ "/" + s
->module_name
+ ".ko";
232 // Make a remote tempdir.
236 vector
<string
> cmd
= ssh_args
;
238 cmd
.push_back("mktemp -d -t stapXXXXXX");
239 rc
= stap_system_read(s
->verbose
, cmd
, out
);
241 tokenize(out
.str(), vout
, "\r\n");
242 if (vout
.size() != 1)
244 cerr
<< "failed to make a tempdir on " << host
245 << " : rc=" << rc
<< endl
;
249 tmpmodule
= tmpdir
+ "/" + s
->module_name
+ ".ko";
252 // Transfer the module. XXX and uprobes.ko, sigs, etc.
254 vector
<string
> cmd
= scp_args
;
255 cmd
.push_back(localmodule
);
256 cmd
.push_back(host
+ ":" + tmpmodule
);
257 rc
= stap_system(s
->verbose
, cmd
);
259 cerr
<< "failed to copy the module to " << host
260 << " : rc=" << rc
<< endl
;
263 // Run the module on the remote.
265 vector
<string
> cmd
= ssh_args
;
267 cmd
.push_back(cmdstr_join(make_run_command(*s
, tmpmodule
)));
268 pid_t pid
= stap_spawn(s
->verbose
, cmd
);
273 cerr
<< "failed to run the module on " << host
274 << " : ret=" << pid
<< endl
;
288 rc
= stap_waitpid(s
->verbose
, child
);
294 // Remove the tempdir.
295 // XXX need to make sure this runs even with e.g. CTRL-C exits
296 vector
<string
> cmd
= ssh_args
;
298 cmd
.push_back("rm -r " + cmdstr_quoted(tmpdir
));
299 int rc2
= stap_system(s
->verbose
, cmd
);
301 cerr
<< "failed to delete the tempdir on " << host
302 << " : rc=" << rc2
<< endl
;
308 close_control_master();
316 remote::create(systemtap_session
& s
, const string
& uri
)
321 return new direct(s
);
322 else if (uri
.find(':') != string::npos
)
324 const uri_decoder
ud(uri
);
325 if (ud
.scheme
== "ssh")
326 return new ssh_remote(s
, ud
);
330 msg
<< "unrecognized URI scheme '" << ud
.scheme
331 << "' in remote: " << uri
;
332 throw runtime_error(msg
.str());
336 // XXX assuming everything else is ssh for now...
337 return new ssh_remote(s
, uri
);
339 catch (std::runtime_error
& e
)
341 cerr
<< e
.what() << endl
;
347 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.071929 seconds and 6 git commands to generate.