]>
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) {}
74 pid_t pid
= stap_spawn (s
->verbose
, make_run_command (*s
));
86 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 string localmodule
= s
->tmpdir
+ "/" + s
->module_name
+ ".ko";
224 // Make a remote tempdir.
228 vector
<string
> cmd
= ssh_args
;
230 cmd
.push_back("mktemp -d -t stapXXXXXX");
231 rc
= stap_system_read(s
->verbose
, cmd
, out
);
233 tokenize(out
.str(), vout
, "\r\n");
234 if (vout
.size() != 1)
236 cerr
<< "failed to make a tempdir on " << host
237 << " : rc=" << rc
<< endl
;
241 tmpmodule
= tmpdir
+ "/" + s
->module_name
+ ".ko";
244 // Transfer the module. XXX and uprobes.ko, sigs, etc.
246 vector
<string
> cmd
= scp_args
;
247 cmd
.push_back(localmodule
);
248 cmd
.push_back(host
+ ":" + tmpmodule
);
249 rc
= stap_system(s
->verbose
, cmd
);
251 cerr
<< "failed to copy the module to " << host
252 << " : rc=" << rc
<< endl
;
255 // Run the module on the remote.
257 vector
<string
> cmd
= ssh_args
;
259 cmd
.push_back(cmdstr_join(make_run_command(*s
, tmpmodule
)));
260 pid_t pid
= stap_spawn(s
->verbose
, cmd
);
265 cerr
<< "failed to run the module on " << host
266 << " : ret=" << pid
<< endl
;
280 rc
= stap_waitpid(s
->verbose
, child
);
286 // Remove the tempdir.
287 // XXX need to make sure this runs even with e.g. CTRL-C exits
288 vector
<string
> cmd
= ssh_args
;
290 cmd
.push_back("rm -r " + cmdstr_quoted(tmpdir
));
291 int rc2
= stap_system(s
->verbose
, cmd
);
293 cerr
<< "failed to delete the tempdir on " << host
294 << " : rc=" << rc2
<< endl
;
300 close_control_master();
308 virtual ~ssh_remote()
310 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 remote::run(const vector
<remote
*>& remotes
)
349 // NB: the first failure "wins"
352 for (unsigned i
= 0; i
< remotes
.size() && !pending_interrupts
; ++i
)
354 rc
= remotes
[i
]->start();
359 for (unsigned i
= 0; i
< remotes
.size(); ++i
)
361 rc
= remotes
[i
]->finish();
370 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.053513 seconds and 6 git commands to generate.