]>
Commit | Line | Data |
---|---|---|
2dce8c42 DB |
1 | /* |
2 | Compile server client functions | |
01fb72a0 | 3 | Copyright (C) 2010-2017 Red Hat Inc. |
2dce8c42 DB |
4 | |
5 | This file is part of systemtap, and is free software. You can | |
6 | redistribute it and/or modify it under the terms of the GNU General | |
7 | Public License (GPL); either version 2, or (at your option) any | |
8 | later version. | |
9 | */ | |
c4fd15b4 DB |
10 | |
11 | // Completely disable the client if NSS is not available. | |
2dce8c42 DB |
12 | #include "config.h" |
13 | #include "session.h" | |
005df4e5 | 14 | #include "cscommon.h" |
aa4d21c0 | 15 | #include "csclient.h" |
01fb72a0 DS |
16 | #include "client-nss.h" |
17 | #include "client-http.h" | |
2fad97fd | 18 | #include "util.h" |
0f5d597d | 19 | #include "stap-probe.h" |
2dce8c42 | 20 | |
6b314d31 | 21 | #include <unistd.h> |
01fb72a0 | 22 | #include <iostream> |
79efe7f8 FCE |
23 | |
24 | extern "C" { | |
01fb72a0 | 25 | #include <sys/times.h> |
3eee0879 | 26 | #include <sys/time.h> |
586c8666 | 27 | #include <glob.h> |
aeb9cc10 | 28 | } |
2fad97fd | 29 | |
aeb9cc10 DB |
30 | using namespace std; |
31 | ||
01fb72a0 DS |
32 | int |
33 | compile_server_client::passes_0_4 () | |
840e5073 | 34 | { |
01fb72a0 DS |
35 | // Use the correct backend. |
36 | #ifdef HAVE_HTTP_SUPPORT | |
37 | if (! s.http_servers.empty()) | |
38 | backend = new http_client_backend (s); | |
840e5073 | 39 | #endif |
01fb72a0 DS |
40 | #if HAVE_NSS |
41 | if (backend == NULL) | |
42 | backend = new nss_client_backend (s); | |
840e5073 | 43 | #endif |
01fb72a0 | 44 | if (backend == NULL) |
840e5073 | 45 | { |
01fb72a0 DS |
46 | clog << _("Using a compile server backend failed.") << endl; |
47 | return 1; | |
840e5073 DB |
48 | } |
49 | ||
0f5d597d | 50 | PROBE1(stap, client__start, &s); |
2fad97fd | 51 | |
aa4d21c0 | 52 | // arguments parsed; get down to business |
4e78c716 | 53 | if (s.verbose || ! s.auto_server_msgs.empty ()) |
a46f9abe | 54 | clog << _("Using a compile server.") << endl; |
aa4d21c0 | 55 | |
aa4d21c0 DB |
56 | struct tms tms_before; |
57 | times (& tms_before); | |
58 | struct timeval tv_before; | |
59 | gettimeofday (&tv_before, NULL); | |
60 | ||
2fad97fd DB |
61 | // Create the request package. |
62 | int rc = initialize (); | |
e19ebcf7 | 63 | assert_no_interrupts(); |
985892de | 64 | if (rc != 0) goto done; |
2fad97fd | 65 | rc = create_request (); |
e19ebcf7 | 66 | assert_no_interrupts(); |
985892de | 67 | if (rc != 0) goto done; |
01fb72a0 | 68 | rc = backend->package_request (); |
e19ebcf7 | 69 | assert_no_interrupts(); |
985892de | 70 | if (rc != 0) goto done; |
2fad97fd DB |
71 | |
72 | // Submit it to the server. | |
01fb72a0 | 73 | rc = backend->find_and_connect_to_server (); |
e19ebcf7 | 74 | assert_no_interrupts(); |
985892de | 75 | if (rc != 0) goto done; |
2fad97fd DB |
76 | |
77 | // Unpack and process the response. | |
01fb72a0 | 78 | rc = backend->unpack_response (); |
e19ebcf7 | 79 | assert_no_interrupts(); |
985892de | 80 | if (rc != 0) goto done; |
586c8666 | 81 | rc = process_response (); |
2fad97fd DB |
82 | |
83 | done: | |
aa4d21c0 DB |
84 | struct tms tms_after; |
85 | times (& tms_after); | |
86 | unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK); | |
87 | struct timeval tv_after; | |
88 | gettimeofday (&tv_after, NULL); | |
89 | ||
90 | #define TIMESPRINT "in " << \ | |
91 | (tms_after.tms_cutime + tms_after.tms_utime \ | |
92 | - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \ | |
93 | << (tms_after.tms_cstime + tms_after.tms_stime \ | |
94 | - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \ | |
95 | << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \ | |
96 | ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms." | |
97 | ||
da21dc88 DB |
98 | if (rc == 0) |
99 | { | |
100 | // Save the module, if necessary. | |
101 | if (s.last_pass == 4) | |
102 | s.save_module = true; | |
103 | ||
104 | // Copy module to the current directory. | |
105 | if (! pending_interrupts) | |
106 | { | |
107 | if (s.save_module) | |
108 | { | |
109 | string module_src_path = s.tmpdir + "/" + s.module_filename(); | |
110 | string module_dest_path = s.module_filename(); | |
111 | copy_file (module_src_path, module_dest_path, s.verbose >= 3); | |
112 | // Also copy the module signature, it it exists. | |
113 | module_src_path += ".sgn"; | |
114 | if (file_exists (module_src_path)) | |
115 | { | |
116 | module_dest_path += ".sgn"; | |
117 | copy_file(module_src_path, module_dest_path, s.verbose >= 3); | |
118 | } | |
119 | } | |
120 | // Print the name of the module | |
121 | if (s.last_pass == 4) | |
122 | { | |
123 | cout << s.module_filename() << endl; | |
124 | } | |
125 | } | |
126 | } | |
127 | ||
aa4d21c0 DB |
128 | // syntax errors, if any, are already printed |
129 | if (s.verbose) | |
130 | { | |
a46f9abe FCE |
131 | string ws = s.winning_server; |
132 | if (ws == "") ws = "?"; | |
133 | clog << _("Passes: via server ") << ws << " " | |
85007c04 | 134 | << getmemusage() |
aa4d21c0 DB |
135 | << TIMESPRINT |
136 | << endl; | |
137 | } | |
bba368c5 | 138 | if (rc && !s.dump_mode) |
a46f9abe FCE |
139 | { |
140 | clog << _("Passes: via server failed. Try again with another '-v' option.") << endl; | |
141 | } | |
aa4d21c0 | 142 | |
0f5d597d | 143 | PROBE1(stap, client__end, &s); |
aa4d21c0 DB |
144 | |
145 | return rc; | |
146 | } | |
147 | ||
2fad97fd DB |
148 | // Initialize a client/server session. |
149 | int | |
150 | compile_server_client::initialize () | |
151 | { | |
152 | int rc = 0; | |
153 | ||
2fad97fd DB |
154 | // Create a temporary directory to package things in. |
155 | client_tmpdir = s.tmpdir + "/client"; | |
156 | rc = create_dir (client_tmpdir.c_str ()); | |
157 | if (rc != 0) | |
158 | { | |
159 | const char* e = strerror (errno); | |
aeb9cc10 | 160 | clog << _("ERROR: cannot create temporary directory (\"") |
2fad97fd DB |
161 | << client_tmpdir << "\"): " << e |
162 | << endl; | |
01fb72a0 | 163 | return rc; |
2fad97fd | 164 | } |
01fb72a0 | 165 | backend->set_tmpdir(client_tmpdir); |
2fad97fd | 166 | |
01fb72a0 | 167 | return backend->initialize(); |
2fad97fd DB |
168 | } |
169 | ||
170 | // Create the request package. | |
171 | int | |
172 | compile_server_client::create_request () | |
173 | { | |
cc7c72cd | 174 | // Add the current protocol version. |
01fb72a0 | 175 | int rc = backend->add_protocol_version (CURRENT_CS_PROTOCOL_VERSION); |
cc7c72cd DB |
176 | if (rc != 0) |
177 | return rc; | |
2fad97fd DB |
178 | |
179 | // Add the script file or script option | |
180 | if (s.script_file != "") | |
181 | { | |
182 | if (s.script_file == "-") | |
183 | { | |
184 | // Copy the script from stdin | |
185 | string packaged_script_dir = client_tmpdir + "/script"; | |
186 | rc = create_dir (packaged_script_dir.c_str ()); | |
187 | if (rc != 0) | |
188 | { | |
189 | const char* e = strerror (errno); | |
aeb9cc10 | 190 | clog << _("ERROR: cannot create temporary directory ") |
2fad97fd DB |
191 | << packaged_script_dir << ": " << e |
192 | << endl; | |
193 | return rc; | |
194 | } | |
195 | rc = ! copy_file("/dev/stdin", packaged_script_dir + "/-"); | |
f3fbabf2 DB |
196 | if (rc != 0) |
197 | return rc; | |
2fad97fd | 198 | |
01fb72a0 DS |
199 | // Let the backend know the file is there. |
200 | rc = backend->add_tmpdir_file ("script/-"); | |
201 | if (rc != 0) | |
202 | return rc; | |
203 | ||
204 | // Name the script in the stap cmd arguments. | |
205 | rc = backend->add_cmd_arg ("script/-"); | |
f3fbabf2 DB |
206 | if (rc != 0) |
207 | return rc; | |
2fad97fd DB |
208 | } |
209 | else | |
01fb72a0 DS |
210 | { |
211 | // Add the script. | |
212 | rc = backend->include_file_or_directory ("script", s.script_file); | |
f3fbabf2 DB |
213 | if (rc != 0) |
214 | return rc; | |
2fad97fd DB |
215 | } |
216 | } | |
217 | ||
218 | // Add -I paths. Skip the default directory. | |
219 | if (s.include_arg_start != -1) | |
220 | { | |
221 | unsigned limit = s.include_path.size (); | |
222 | for (unsigned i = s.include_arg_start; i < limit; ++i) | |
223 | { | |
01fb72a0 | 224 | rc = backend->add_cmd_arg ("-I"); |
f3fbabf2 DB |
225 | if (rc != 0) |
226 | return rc; | |
50436433 DS |
227 | rc = backend->include_file_or_directory ("tapset", |
228 | s.include_path[i]); | |
f3fbabf2 DB |
229 | if (rc != 0) |
230 | return rc; | |
2fad97fd DB |
231 | } |
232 | } | |
233 | ||
234 | // Add other options. | |
01fb72a0 | 235 | rc = add_cmd_args (); |
f3fbabf2 DB |
236 | if (rc != 0) |
237 | return rc; | |
2fad97fd | 238 | |
01fb72a0 DS |
239 | // Add the sysinfo. |
240 | rc = backend->add_sysinfo (); | |
e4e3d6b7 CM |
241 | if (rc != 0) |
242 | return rc; | |
243 | ||
244 | // Add localization data | |
245 | rc = add_localization_variables(); | |
2fad97fd | 246 | |
01fb72a0 | 247 | // Add the machine owner key (MOK) fingerprints, if needed. |
cd1418c7 | 248 | if (! s.mok_fingerprints.empty()) |
b3367f63 DS |
249 | { |
250 | ostringstream fingerprints; | |
251 | vector<string>::const_iterator it; | |
cd1418c7 | 252 | for (it = s.mok_fingerprints.begin(); it != s.mok_fingerprints.end(); |
b3367f63 | 253 | it++) |
01fb72a0 DS |
254 | backend->add_mok_fingerprint(*it); |
255 | rc = backend->finalize_mok_fingerprints(); | |
b3367f63 | 256 | if (rc != 0) |
01fb72a0 | 257 | return rc; |
b3367f63 DS |
258 | } |
259 | ||
2fad97fd DB |
260 | return rc; |
261 | } | |
262 | ||
586c8666 DS |
263 | int |
264 | compile_server_client::process_response () | |
265 | { | |
266 | // Pick up the results of running stap on the server. | |
267 | string filename = backend->server_tmpdir + "/rc"; | |
268 | int stap_rc; | |
269 | int rc = read_from_file (filename, stap_rc); | |
270 | if (rc != 0) | |
271 | return rc; | |
272 | rc = stap_rc; | |
273 | ||
274 | if (s.last_pass >= 4) | |
275 | { | |
276 | // The server should have returned a module. | |
277 | string filespec = s.tmpdir + "/*.ko"; | |
278 | if (s.verbose >= 3) | |
279 | clog << _F("Searching \"%s\"\n", filespec.c_str()); | |
280 | ||
281 | glob_t globbuf; | |
282 | int r = glob(filespec.c_str (), 0, NULL, & globbuf); | |
283 | if (r != GLOB_NOSPACE && r != GLOB_ABORTED && r != GLOB_NOMATCH) | |
284 | { | |
285 | if (globbuf.gl_pathc > 1) | |
286 | clog << _("Incorrect number of modules in server response") << endl; | |
287 | else | |
288 | { | |
289 | assert (globbuf.gl_pathc == 1); | |
290 | string modname = globbuf.gl_pathv[0]; | |
291 | if (s.verbose >= 3) | |
292 | clog << _(" found ") << modname << endl; | |
293 | ||
294 | // If a module name was not specified by the user, then set it to | |
295 | // be the one generated by the server. | |
296 | if (! s.save_module) | |
297 | { | |
298 | vector<string> components; | |
299 | tokenize (modname, components, "/"); | |
300 | s.module_name = components.back (); | |
301 | s.module_name.erase(s.module_name.size() - 3); | |
302 | } | |
303 | ||
304 | // If a uprobes.ko module was returned, then make note of it. | |
305 | string uprobes_ko; | |
306 | if (backend->server_version < "1.6") | |
307 | uprobes_ko = s.tmpdir + "/server/uprobes.ko"; | |
308 | else | |
309 | uprobes_ko = s.tmpdir + "/uprobes/uprobes.ko"; | |
310 | ||
311 | if (file_exists (uprobes_ko)) | |
312 | { | |
313 | s.need_uprobes = true; | |
314 | s.uprobes_path = uprobes_ko; | |
315 | } | |
316 | } | |
317 | } | |
318 | else if (s.have_script) | |
319 | { | |
320 | if (rc == 0) | |
321 | { | |
322 | clog << _("No module was returned by the server.") << endl; | |
323 | rc = 1; | |
324 | } | |
325 | } | |
326 | globfree (& globbuf); | |
327 | } | |
328 | ||
329 | // If the server returned a MOK certificate, copy it to the user's | |
330 | // current directory. | |
331 | string server_MOK_public_cert = backend->server_tmpdir + "/" MOK_PUBLIC_CERT_NAME; | |
332 | if (file_exists (server_MOK_public_cert)) | |
333 | { | |
334 | string dst = MOK_PUBLIC_CERT_NAME; | |
335 | copy_file (server_MOK_public_cert, dst, (s.verbose >= 3)); | |
336 | } | |
337 | ||
338 | // Output stdout and stderr. | |
339 | filename = backend->server_tmpdir + "/stderr"; | |
340 | flush_to_stream (filename, clog); | |
341 | ||
342 | filename = backend->server_tmpdir + "/stdout"; | |
343 | flush_to_stream (filename, cout); | |
344 | ||
345 | return rc; | |
346 | } | |
347 | ||
2fad97fd DB |
348 | // Add the arguments specified on the command line to the server request |
349 | // package, as appropriate. | |
f3fbabf2 | 350 | int |
01fb72a0 | 351 | compile_server_client::add_cmd_args () |
2fad97fd | 352 | { |
fd20a70c | 353 | // stap arguments to be passed to the server. |
f3fbabf2 | 354 | int rc = 0; |
2fad97fd DB |
355 | unsigned limit = s.server_args.size(); |
356 | for (unsigned i = 0; i < limit; ++i) | |
f3fbabf2 | 357 | { |
01fb72a0 | 358 | rc = backend->add_cmd_arg (s.server_args[i]); |
f3fbabf2 DB |
359 | if (rc != 0) |
360 | return rc; | |
361 | } | |
fd20a70c DB |
362 | |
363 | // Script arguments. | |
364 | limit = s.args.size(); | |
365 | if (limit > 0) { | |
01fb72a0 | 366 | rc = backend->add_cmd_arg ("--"); |
fd20a70c DB |
367 | if (rc != 0) |
368 | return rc; | |
369 | for (unsigned i = 0; i < limit; ++i) | |
370 | { | |
01fb72a0 | 371 | rc = backend->add_cmd_arg (s.args[i]); |
fd20a70c DB |
372 | if (rc != 0) |
373 | return rc; | |
374 | } | |
375 | } | |
f3fbabf2 | 376 | return rc; |
2fad97fd DB |
377 | } |
378 | ||
e4e3d6b7 CM |
379 | // Add the localization variables to the server request |
380 | // package. | |
381 | int | |
382 | compile_server_client::add_localization_variables() | |
383 | { | |
e4e3d6b7 | 384 | const set<string> &locVars = localization_variables(); |
e4e3d6b7 CM |
385 | |
386 | /* Note: We don't have to check for the contents of the environment | |
387 | * variables here, since they will be checked extensively on the | |
388 | * server. | |
389 | */ | |
01fb72a0 | 390 | for (auto it = locVars.begin(); it != locVars.end(); it++) |
e4e3d6b7 CM |
391 | { |
392 | char* var = getenv((*it).c_str()); | |
393 | if (var) | |
01fb72a0 | 394 | backend->add_localization_variable(*it, var); |
e4e3d6b7 | 395 | } |
01fb72a0 | 396 | return backend->finalize_localization_variables(); |
e4e3d6b7 CM |
397 | } |
398 | ||
2e46c01a | 399 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |