]> sourceware.org Git - systemtap.git/blob - csclient.cxx
Update nfsderrno.stp to work with Linux 6.10
[systemtap.git] / csclient.cxx
1 /*
2 Compile server client functions
3 Copyright (C) 2010-2018 Red Hat Inc.
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 */
10
11 // Completely disable the client if NSS is not available.
12 #include "config.h"
13 #include "session.h"
14 #include "cscommon.h"
15 #include "csclient.h"
16 #include "client-nss.h"
17 #ifdef HAVE_HTTP_SUPPORT
18 #include "client-http.h"
19 #endif
20 #include "util.h"
21 #include "stap-probe.h"
22
23 #include <unistd.h>
24 #include <iostream>
25
26 extern "C" {
27 #include <sys/times.h>
28 #include <sys/time.h>
29 #include <glob.h>
30 }
31
32 using namespace std;
33
34 client_backend *
35 nss_get_client_backend (systemtap_session &s)
36 {
37 // Use the correct backend.
38 #ifdef HAVE_HTTP_SUPPORT
39 if (! s.http_servers.empty())
40 return new http_client_backend (s);
41 #endif
42 #if HAVE_NSS
43 return new nss_client_backend (s);
44 #endif
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);
53 if (backend == NULL)
54 {
55 clog << _("Using a compile server backend failed.") << endl;
56 return 1;
57 }
58
59 PROBE1(stap, client__start, &s);
60
61 // arguments parsed; get down to business
62 if (s.verbose || ! s.auto_server_msgs.empty ())
63 clog << _("Using a compile server.") << endl;
64
65 struct tms tms_before;
66 times (& tms_before);
67 struct timeval tv_before;
68 gettimeofday (&tv_before, NULL);
69
70 // Create the request package.
71 int rc = initialize ();
72 assert_no_interrupts();
73 if (rc != 0) goto done;
74 rc = create_request ();
75 assert_no_interrupts();
76 if (rc != 0) goto done;
77 rc = backend->package_request ();
78 assert_no_interrupts();
79 if (rc != 0) goto done;
80
81 // Submit it to the server.
82 rc = backend->find_and_connect_to_server ();
83 assert_no_interrupts();
84 if (rc != 0) goto done;
85
86 // Unpack and process the response.
87 rc = backend->unpack_response ();
88 assert_no_interrupts();
89 if (rc != 0) goto done;
90 rc = process_response ();
91
92 done:
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
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
137 // syntax errors, if any, are already printed
138 if (s.verbose)
139 {
140 string ws = s.winning_server;
141 if (ws == "") ws = "?";
142 clog << _("Passes: via server ") << ws << " "
143 << getmemusage()
144 << TIMESPRINT
145 << endl;
146 }
147 if (rc && !s.dump_mode)
148 {
149 clog << _("Passes: via server failed. Try again with another '-v' option.") << endl;
150 }
151
152 PROBE1(stap, client__end, &s);
153
154 return rc;
155 }
156
157 // Initialize a client/server session.
158 int
159 compile_server_client::initialize ()
160 {
161 int rc = 0;
162
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);
169 clog << _("ERROR: cannot create temporary directory (\"")
170 << client_tmpdir << "\"): " << e
171 << endl;
172 return rc;
173 }
174 backend->set_tmpdir(client_tmpdir);
175
176 return backend->initialize();
177 }
178
179 // Create the request package.
180 int
181 compile_server_client::create_request ()
182 {
183 // Add the current protocol version.
184 int rc = backend->add_protocol_version (CURRENT_CS_PROTOCOL_VERSION);
185 if (rc != 0)
186 return rc;
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);
199 clog << _("ERROR: cannot create temporary directory ")
200 << packaged_script_dir << ": " << e
201 << endl;
202 return rc;
203 }
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());
208 if (rc != 0)
209 return rc;
210
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/-");
218 if (rc != 0)
219 return rc;
220 }
221 else
222 {
223 // Add the script.
224 rc = backend->include_file_or_directory ("script", s.script_file);
225 if (rc != 0)
226 return rc;
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 {
236 rc = backend->add_cmd_arg ("-I");
237 if (rc != 0)
238 return rc;
239 rc = backend->include_file_or_directory ("tapset",
240 s.include_path[i]);
241 if (rc != 0)
242 return rc;
243 }
244 }
245
246 // Add other options.
247 rc = add_cmd_args ();
248 if (rc != 0)
249 return rc;
250
251 // Add the sysinfo.
252 rc = backend->add_sysinfo ();
253 if (rc != 0)
254 return rc;
255
256 // Add localization data
257 rc = add_localization_variables();
258
259 // Add the machine owner key (MOK) fingerprints, if needed.
260 if (! s.mok_fingerprints.empty())
261 {
262 ostringstream fingerprints;
263 vector<string>::const_iterator it;
264 for (it = s.mok_fingerprints.begin(); it != s.mok_fingerprints.end();
265 it++)
266 backend->add_mok_fingerprint(*it);
267 rc = backend->finalize_mok_fingerprints();
268 if (rc != 0)
269 return rc;
270 }
271
272 return rc;
273 }
274
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.
351 filename = backend->server_tmpdir + "/stdout";
352 flush_to_stream (filename, cout);
353
354 filename = backend->server_tmpdir + "/stderr";
355 flush_to_stream (filename, clog);
356
357 return rc;
358 }
359
360 // Add the arguments specified on the command line to the server request
361 // package, as appropriate.
362 int
363 compile_server_client::add_cmd_args ()
364 {
365 // stap arguments to be passed to the server.
366 int rc = 0;
367 unsigned limit = s.server_args.size();
368 for (unsigned i = 0; i < limit; ++i)
369 {
370 rc = backend->add_cmd_arg (s.server_args[i]);
371 if (rc != 0)
372 return rc;
373 }
374
375 // Script arguments.
376 limit = s.args.size();
377 if (limit > 0) {
378 rc = backend->add_cmd_arg ("--");
379 if (rc != 0)
380 return rc;
381 for (unsigned i = 0; i < limit; ++i)
382 {
383 rc = backend->add_cmd_arg (s.args[i]);
384 if (rc != 0)
385 return rc;
386 }
387 }
388 return rc;
389 }
390
391 // Add the localization variables to the server request
392 // package.
393 int
394 compile_server_client::add_localization_variables()
395 {
396 const set<string> &locVars = localization_variables();
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 */
402 for (auto it = locVars.begin(); it != locVars.end(); it++)
403 {
404 char* var = getenv((*it).c_str());
405 if (var)
406 backend->add_localization_variable(*it, var);
407 }
408 return backend->finalize_localization_variables();
409 }
410
411 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.050877 seconds and 5 git commands to generate.