2 Compile server client functions
3 Copyright (C) 2010-2018 Red Hat Inc.
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
11 // Completely disable the client if NSS is not available.
16 #include "client-nss.h"
17 #ifdef HAVE_HTTP_SUPPORT
18 #include "client-http.h"
21 #include "stap-probe.h"
27 #include <sys/times.h>
35 nss_get_client_backend (systemtap_session
&s
)
37 // Use the correct backend.
38 #ifdef HAVE_HTTP_SUPPORT
39 if (! s
.http_servers
.empty())
40 return new http_client_backend (s
);
43 return new nss_client_backend (s
);
49 compile_server_client::passes_0_4 ()
51 // Use the correct backend.
52 backend
= nss_get_client_backend (s
);
55 clog
<< _("Using a compile server backend failed.") << endl
;
59 PROBE1(stap
, client__start
, &s
);
61 // arguments parsed; get down to business
62 if (s
.verbose
|| ! s
.auto_server_msgs
.empty ())
63 clog
<< _("Using a compile server.") << endl
;
65 struct tms tms_before
;
67 struct timeval tv_before
;
68 gettimeofday (&tv_before
, NULL
);
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
;
81 // Submit it to the server.
82 rc
= backend
->find_and_connect_to_server ();
83 assert_no_interrupts();
84 if (rc
!= 0) goto done
;
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 ();
95 unsigned _sc_clk_tck
= sysconf (_SC_CLK_TCK
);
96 struct timeval tv_after
;
97 gettimeofday (&tv_after
, NULL
);
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."
109 // Save the module, if necessary.
110 if (s
.last_pass
== 4)
111 s
.save_module
= true;
113 // Copy module to the current directory.
114 if (! pending_interrupts
)
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
))
125 module_dest_path
+= ".sgn";
126 copy_file(module_src_path
, module_dest_path
, s
.verbose
>= 3);
129 // Print the name of the module
130 if (s
.last_pass
== 4)
132 cout
<< s
.module_filename() << endl
;
137 // syntax errors, if any, are already printed
140 string ws
= s
.winning_server
;
141 if (ws
== "") ws
= "?";
142 clog
<< _("Passes: via server ") << ws
<< " "
147 if (rc
&& !s
.dump_mode
)
149 clog
<< _("Passes: via server failed. Try again with another '-v' option.") << endl
;
152 PROBE1(stap
, client__end
, &s
);
157 // Initialize a client/server session.
159 compile_server_client::initialize ()
163 // Create a temporary directory to package things in.
164 client_tmpdir
= s
.tmpdir
+ "/client";
165 rc
= create_dir (client_tmpdir
.c_str ());
168 const char* e
= strerror (errno
);
169 clog
<< _("ERROR: cannot create temporary directory (\"")
170 << client_tmpdir
<< "\"): " << e
174 backend
->set_tmpdir(client_tmpdir
);
176 return backend
->initialize();
179 // Create the request package.
181 compile_server_client::create_request ()
183 // Add the current protocol version.
184 int rc
= backend
->add_protocol_version (CURRENT_CS_PROTOCOL_VERSION
);
188 // Add the script file or script option
189 if (s
.script_file
!= "")
191 if (s
.script_file
== "-")
193 // Copy the script from stdin
194 string packaged_script_dir
= client_tmpdir
+ "/script";
195 rc
= create_dir (packaged_script_dir
.c_str ());
198 const char* e
= strerror (errno
);
199 clog
<< _("ERROR: cannot create temporary directory ")
200 << packaged_script_dir
<< ": " << e
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());
211 // Let the backend know the file is there.
212 rc
= backend
->add_tmpdir_file ("script/-");
216 // Name the script in the stap cmd arguments.
217 rc
= backend
->add_cmd_arg ("script/-");
224 rc
= backend
->include_file_or_directory ("script", s
.script_file
);
230 // Add -I paths. Skip the default directory.
231 if (s
.include_arg_start
!= -1)
233 unsigned limit
= s
.include_path
.size ();
234 for (unsigned i
= s
.include_arg_start
; i
< limit
; ++i
)
236 rc
= backend
->add_cmd_arg ("-I");
239 rc
= backend
->include_file_or_directory ("tapset",
246 // Add other options.
247 rc
= add_cmd_args ();
252 rc
= backend
->add_sysinfo ();
256 // Add localization data
257 rc
= add_localization_variables();
259 // Add the machine owner key (MOK) fingerprints, if needed.
260 if (! s
.mok_fingerprints
.empty())
262 ostringstream fingerprints
;
263 vector
<string
>::const_iterator it
;
264 for (it
= s
.mok_fingerprints
.begin(); it
!= s
.mok_fingerprints
.end();
266 backend
->add_mok_fingerprint(*it
);
267 rc
= backend
->finalize_mok_fingerprints();
276 compile_server_client::process_response ()
278 // Pick up the results of running stap on the server.
279 string filename
= backend
->server_tmpdir
+ "/rc";
281 int rc
= read_from_file (filename
, stap_rc
);
286 if (s
.last_pass
>= 4)
288 // The server should have returned a module.
289 string filespec
= s
.tmpdir
+ "/*.ko";
291 clog
<< _F("Searching \"%s\"\n", filespec
.c_str());
294 int r
= glob(filespec
.c_str (), 0, NULL
, & globbuf
);
295 if (r
!= GLOB_NOSPACE
&& r
!= GLOB_ABORTED
&& r
!= GLOB_NOMATCH
)
297 if (globbuf
.gl_pathc
> 1)
298 clog
<< _("Incorrect number of modules in server response") << endl
;
301 assert (globbuf
.gl_pathc
== 1);
302 string modname
= globbuf
.gl_pathv
[0];
304 clog
<< _(" found ") << modname
<< endl
;
306 // If a module name was not specified by the user, then set it to
307 // be the one generated by the server.
310 vector
<string
> components
;
311 tokenize (modname
, components
, "/");
312 s
.module_name
= components
.back ();
313 s
.module_name
.erase(s
.module_name
.size() - 3);
316 // If a uprobes.ko module was returned, then make note of it.
318 if (backend
->server_version
< "1.6")
319 uprobes_ko
= s
.tmpdir
+ "/server/uprobes.ko";
321 uprobes_ko
= s
.tmpdir
+ "/uprobes/uprobes.ko";
323 if (file_exists (uprobes_ko
))
325 s
.need_uprobes
= true;
326 s
.uprobes_path
= uprobes_ko
;
330 else if (s
.have_script
)
334 clog
<< _("No module was returned by the server.") << endl
;
338 globfree (& globbuf
);
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
))
346 string dst
= MOK_PUBLIC_CERT_NAME
;
347 copy_file (server_MOK_public_cert
, dst
, (s
.verbose
>= 3));
350 // Output stdout and stderr.
351 filename
= backend
->server_tmpdir
+ "/stderr";
352 flush_to_stream (filename
, clog
);
354 filename
= backend
->server_tmpdir
+ "/stdout";
355 flush_to_stream (filename
, cout
);
360 // Add the arguments specified on the command line to the server request
361 // package, as appropriate.
363 compile_server_client::add_cmd_args ()
365 // stap arguments to be passed to the server.
367 unsigned limit
= s
.server_args
.size();
368 for (unsigned i
= 0; i
< limit
; ++i
)
370 rc
= backend
->add_cmd_arg (s
.server_args
[i
]);
376 limit
= s
.args
.size();
378 rc
= backend
->add_cmd_arg ("--");
381 for (unsigned i
= 0; i
< limit
; ++i
)
383 rc
= backend
->add_cmd_arg (s
.args
[i
]);
391 // Add the localization variables to the server request
394 compile_server_client::add_localization_variables()
396 const set
<string
> &locVars
= localization_variables();
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
402 for (auto it
= locVars
.begin(); it
!= locVars
.end(); it
++)
404 char* var
= getenv((*it
).c_str());
406 backend
->add_localization_variable(*it
, var
);
408 return backend
->finalize_localization_variables();
411 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */