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