File: | jdk/src/hotspot/os/linux/attachListener_linux.cpp |
Warning: | line 314, column 9 Value stored to 'v' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | #include "precompiled.hpp" |
26 | #include "logging/log.hpp" |
27 | #include "memory/allocation.inline.hpp" |
28 | #include "runtime/interfaceSupport.inline.hpp" |
29 | #include "runtime/os.inline.hpp" |
30 | #include "services/attachListener.hpp" |
31 | #include "services/dtraceAttacher.hpp" |
32 | |
33 | #include <unistd.h> |
34 | #include <signal.h> |
35 | #include <sys/types.h> |
36 | #include <sys/socket.h> |
37 | #include <sys/un.h> |
38 | #include <sys/stat.h> |
39 | |
40 | #ifndef UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path) |
41 | #define UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path) sizeof(((struct sockaddr_un *)0)->sun_path) |
42 | #endif |
43 | |
44 | // The attach mechanism on Linux uses a UNIX domain socket. An attach listener |
45 | // thread is created at startup or is created on-demand via a signal from |
46 | // the client tool. The attach listener creates a socket and binds it to a file |
47 | // in the filesystem. The attach listener then acts as a simple (single- |
48 | // threaded) server - it waits for a client to connect, reads the request, |
49 | // executes it, and returns the response to the client via the socket |
50 | // connection. |
51 | // |
52 | // As the socket is a UNIX domain socket it means that only clients on the |
53 | // local machine can connect. In addition there are two other aspects to |
54 | // the security: |
55 | // 1. The well known file that the socket is bound to has permission 400 |
56 | // 2. When a client connect, the SO_PEERCRED socket option is used to |
57 | // obtain the credentials of client. We check that the effective uid |
58 | // of the client matches this process. |
59 | |
60 | // forward reference |
61 | class LinuxAttachOperation; |
62 | |
63 | class LinuxAttachListener: AllStatic { |
64 | private: |
65 | // the path to which we bind the UNIX domain socket |
66 | static char _path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; |
67 | static bool _has_path; |
68 | |
69 | // the file descriptor for the listening socket |
70 | static volatile int _listener; |
71 | |
72 | static bool _atexit_registered; |
73 | |
74 | // reads a request from the given connected socket |
75 | static LinuxAttachOperation* read_request(int s); |
76 | |
77 | public: |
78 | enum { |
79 | ATTACH_PROTOCOL_VER = 1 // protocol version |
80 | }; |
81 | enum { |
82 | ATTACH_ERROR_BADVERSION = 101 // error codes |
83 | }; |
84 | |
85 | static void set_path(char* path) { |
86 | if (path == NULL__null) { |
87 | _path[0] = '\0'; |
88 | _has_path = false; |
89 | } else { |
90 | strncpy(_path, path, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)); |
91 | _path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)-1] = '\0'; |
92 | _has_path = true; |
93 | } |
94 | } |
95 | |
96 | static void set_listener(int s) { _listener = s; } |
97 | |
98 | // initialize the listener, returns 0 if okay |
99 | static int init(); |
100 | |
101 | static char* path() { return _path; } |
102 | static bool has_path() { return _has_path; } |
103 | static int listener() { return _listener; } |
104 | |
105 | // write the given buffer to a socket |
106 | static int write_fully(int s, char* buf, int len); |
107 | |
108 | static LinuxAttachOperation* dequeue(); |
109 | }; |
110 | |
111 | class LinuxAttachOperation: public AttachOperation { |
112 | private: |
113 | // the connection to the client |
114 | int _socket; |
115 | |
116 | public: |
117 | void complete(jint res, bufferedStream* st); |
118 | |
119 | void set_socket(int s) { _socket = s; } |
120 | int socket() const { return _socket; } |
121 | |
122 | LinuxAttachOperation(char* name) : AttachOperation(name) { |
123 | set_socket(-1); |
124 | } |
125 | }; |
126 | |
127 | // statics |
128 | char LinuxAttachListener::_path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; |
129 | bool LinuxAttachListener::_has_path; |
130 | volatile int LinuxAttachListener::_listener = -1; |
131 | bool LinuxAttachListener::_atexit_registered = false; |
132 | |
133 | // Supporting class to help split a buffer into individual components |
134 | class ArgumentIterator : public StackObj { |
135 | private: |
136 | char* _pos; |
137 | char* _end; |
138 | public: |
139 | ArgumentIterator(char* arg_buffer, size_t arg_size) { |
140 | _pos = arg_buffer; |
141 | _end = _pos + arg_size - 1; |
142 | } |
143 | char* next() { |
144 | if (*_pos == '\0') { |
145 | // advance the iterator if possible (null arguments) |
146 | if (_pos < _end) { |
147 | _pos += 1; |
148 | } |
149 | return NULL__null; |
150 | } |
151 | char* res = _pos; |
152 | char* next_pos = strchr(_pos, '\0'); |
153 | if (next_pos < _end) { |
154 | next_pos++; |
155 | } |
156 | _pos = next_pos; |
157 | return res; |
158 | } |
159 | }; |
160 | |
161 | |
162 | // atexit hook to stop listener and unlink the file that it is |
163 | // bound too. |
164 | extern "C" { |
165 | static void listener_cleanup() { |
166 | int s = LinuxAttachListener::listener(); |
167 | if (s != -1) { |
168 | LinuxAttachListener::set_listener(-1); |
169 | ::shutdown(s, SHUT_RDWRSHUT_RDWR); |
170 | ::close(s); |
171 | } |
172 | if (LinuxAttachListener::has_path()) { |
173 | ::unlink(LinuxAttachListener::path()); |
174 | LinuxAttachListener::set_path(NULL__null); |
175 | } |
176 | } |
177 | } |
178 | |
179 | // Initialization - create a listener socket and bind it to a file |
180 | |
181 | int LinuxAttachListener::init() { |
182 | char path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; // socket file |
183 | char initial_path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; // socket file during setup |
184 | int listener; // listener socket (file descriptor) |
185 | |
186 | // register function to cleanup |
187 | if (!_atexit_registered) { |
188 | _atexit_registered = true; |
189 | ::atexit(listener_cleanup); |
190 | } |
191 | |
192 | int n = snprintf(path, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path), "%s/.java_pid%d", |
193 | os::get_temp_directory(), os::current_process_id()); |
194 | if (n < (int)UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)) { |
195 | n = snprintf(initial_path, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path), "%s.tmp", path); |
196 | } |
197 | if (n >= (int)UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)) { |
198 | return -1; |
199 | } |
200 | |
201 | // create the listener socket |
202 | listener = ::socket(PF_UNIX1, SOCK_STREAMSOCK_STREAM, 0); |
203 | if (listener == -1) { |
204 | return -1; |
205 | } |
206 | |
207 | // bind socket |
208 | struct sockaddr_un addr; |
209 | memset((void *)&addr, 0, sizeof(addr)); |
210 | addr.sun_family = AF_UNIX1; |
211 | strcpy(addr.sun_path, initial_path); |
212 | ::unlink(initial_path); |
213 | int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); |
214 | if (res == -1) { |
215 | ::close(listener); |
216 | return -1; |
217 | } |
218 | |
219 | // put in listen mode, set permissions, and rename into place |
220 | res = ::listen(listener, 5); |
221 | if (res == 0) { |
222 | RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res)do { res = ::chmod(initial_path, 0400|0200); } while(((int)res == OS_ERR) && ((*__errno_location ()) == 4)); |
223 | if (res == 0) { |
224 | // make sure the file is owned by the effective user and effective group |
225 | // e.g. the group could be inherited from the directory in case the s bit is set |
226 | RESTARTABLE(::chown(initial_path, geteuid(), getegid()), res)do { res = ::chown(initial_path, geteuid(), getegid()); } while (((int)res == OS_ERR) && ((*__errno_location ()) == 4 )); |
227 | if (res == 0) { |
228 | res = ::rename(initial_path, path); |
229 | } |
230 | } |
231 | } |
232 | if (res == -1) { |
233 | ::close(listener); |
234 | ::unlink(initial_path); |
235 | return -1; |
236 | } |
237 | set_path(path); |
238 | set_listener(listener); |
239 | |
240 | return 0; |
241 | } |
242 | |
243 | // Given a socket that is connected to a peer we read the request and |
244 | // create an AttachOperation. As the socket is blocking there is potential |
245 | // for a denial-of-service if the peer does not response. However this happens |
246 | // after the peer credentials have been checked and in the worst case it just |
247 | // means that the attach listener thread is blocked. |
248 | // |
249 | LinuxAttachOperation* LinuxAttachListener::read_request(int s) { |
250 | char ver_str[8]; |
251 | sprintf(ver_str, "%d", ATTACH_PROTOCOL_VER); |
252 | |
253 | // The request is a sequence of strings so we first figure out the |
254 | // expected count and the maximum possible length of the request. |
255 | // The request is: |
256 | // <ver>0<cmd>0<arg>0<arg>0<arg>0 |
257 | // where <ver> is the protocol version (1), <cmd> is the command |
258 | // name ("load", "datadump", ...), and <arg> is an argument |
259 | int expected_str_count = 2 + AttachOperation::arg_count_max; |
260 | const int max_len = (sizeof(ver_str) + 1) + (AttachOperation::name_length_max + 1) + |
261 | AttachOperation::arg_count_max*(AttachOperation::arg_length_max + 1); |
262 | |
263 | char buf[max_len]; |
264 | int str_count = 0; |
265 | |
266 | // Read until all (expected) strings have been read, the buffer is |
267 | // full, or EOF. |
268 | |
269 | int off = 0; |
270 | int left = max_len; |
271 | |
272 | do { |
273 | int n; |
274 | RESTARTABLE(read(s, buf+off, left), n)do { n = read(s, buf+off, left); } while(((int)n == OS_ERR) && ((*__errno_location ()) == 4)); |
275 | assert(n <= left, "buffer was too small, impossible!")do { if (!(n <= left)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/os/linux/attachListener_linux.cpp" , 275, "assert(" "n <= left" ") failed", "buffer was too small, impossible!" ); ::breakpoint(); } } while (0); |
276 | buf[max_len - 1] = '\0'; |
277 | if (n == -1) { |
278 | return NULL__null; // reset by peer or other error |
279 | } |
280 | if (n == 0) { |
281 | break; |
282 | } |
283 | for (int i=0; i<n; i++) { |
284 | if (buf[off+i] == 0) { |
285 | // EOS found |
286 | str_count++; |
287 | |
288 | // The first string is <ver> so check it now to |
289 | // check for protocol mis-match |
290 | if (str_count == 1) { |
291 | if ((strlen(buf) != strlen(ver_str)) || |
292 | (atoi(buf) != ATTACH_PROTOCOL_VER)) { |
293 | char msg[32]; |
294 | sprintf(msg, "%d\n", ATTACH_ERROR_BADVERSION); |
295 | write_fully(s, msg, strlen(msg)); |
296 | return NULL__null; |
297 | } |
298 | } |
299 | } |
300 | } |
301 | off += n; |
302 | left -= n; |
303 | } while (left > 0 && str_count < expected_str_count); |
304 | |
305 | if (str_count != expected_str_count) { |
306 | return NULL__null; // incomplete request |
307 | } |
308 | |
309 | // parse request |
310 | |
311 | ArgumentIterator args(buf, (max_len)-left); |
312 | |
313 | // version already checked |
314 | char* v = args.next(); |
Value stored to 'v' during its initialization is never read | |
315 | |
316 | char* name = args.next(); |
317 | if (name == NULL__null || strlen(name) > AttachOperation::name_length_max) { |
318 | return NULL__null; |
319 | } |
320 | |
321 | LinuxAttachOperation* op = new LinuxAttachOperation(name); |
322 | |
323 | for (int i=0; i<AttachOperation::arg_count_max; i++) { |
324 | char* arg = args.next(); |
325 | if (arg == NULL__null) { |
326 | op->set_arg(i, NULL__null); |
327 | } else { |
328 | if (strlen(arg) > AttachOperation::arg_length_max) { |
329 | delete op; |
330 | return NULL__null; |
331 | } |
332 | op->set_arg(i, arg); |
333 | } |
334 | } |
335 | |
336 | op->set_socket(s); |
337 | return op; |
338 | } |
339 | |
340 | |
341 | // Dequeue an operation |
342 | // |
343 | // In the Linux implementation there is only a single operation and clients |
344 | // cannot queue commands (except at the socket level). |
345 | // |
346 | LinuxAttachOperation* LinuxAttachListener::dequeue() { |
347 | for (;;) { |
348 | int s; |
349 | |
350 | // wait for client to connect |
351 | struct sockaddr addr; |
352 | socklen_t len = sizeof(addr); |
353 | RESTARTABLE(::accept(listener(), &addr, &len), s)do { s = ::accept(listener(), &addr, &len); } while(( (int)s == OS_ERR) && ((*__errno_location ()) == 4)); |
354 | if (s == -1) { |
355 | return NULL__null; // log a warning? |
356 | } |
357 | |
358 | // get the credentials of the peer and check the effective uid/guid |
359 | struct ucred cred_info; |
360 | socklen_t optlen = sizeof(cred_info); |
361 | if (::getsockopt(s, SOL_SOCKET1, SO_PEERCRED17, (void*)&cred_info, &optlen) == -1) { |
362 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("Failed to get socket option SO_PEERCRED"); |
363 | ::close(s); |
364 | continue; |
365 | } |
366 | |
367 | if (!os::Posix::matches_effective_uid_and_gid_or_root(cred_info.uid, cred_info.gid)) { |
368 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("euid/egid check failed (%d/%d vs %d/%d)", |
369 | cred_info.uid, cred_info.gid, geteuid(), getegid()); |
370 | ::close(s); |
371 | continue; |
372 | } |
373 | |
374 | // peer credential look okay so we read the request |
375 | LinuxAttachOperation* op = read_request(s); |
376 | if (op == NULL__null) { |
377 | ::close(s); |
378 | continue; |
379 | } else { |
380 | return op; |
381 | } |
382 | } |
383 | } |
384 | |
385 | // write the given buffer to the socket |
386 | int LinuxAttachListener::write_fully(int s, char* buf, int len) { |
387 | do { |
388 | int n = ::write(s, buf, len); |
389 | if (n == -1) { |
390 | if (errno(*__errno_location ()) != EINTR4) return -1; |
391 | } else { |
392 | buf += n; |
393 | len -= n; |
394 | } |
395 | } |
396 | while (len > 0); |
397 | return 0; |
398 | } |
399 | |
400 | // Complete an operation by sending the operation result and any result |
401 | // output to the client. At this time the socket is in blocking mode so |
402 | // potentially we can block if there is a lot of data and the client is |
403 | // non-responsive. For most operations this is a non-issue because the |
404 | // default send buffer is sufficient to buffer everything. In the future |
405 | // if there are operations that involves a very big reply then it the |
406 | // socket could be made non-blocking and a timeout could be used. |
407 | |
408 | void LinuxAttachOperation::complete(jint result, bufferedStream* st) { |
409 | JavaThread* thread = JavaThread::current(); |
410 | ThreadBlockInVM tbivm(thread); |
411 | |
412 | // write operation result |
413 | char msg[32]; |
414 | sprintf(msg, "%d\n", result); |
415 | int rc = LinuxAttachListener::write_fully(this->socket(), msg, strlen(msg)); |
416 | |
417 | // write any result data |
418 | if (rc == 0) { |
419 | LinuxAttachListener::write_fully(this->socket(), (char*) st->base(), st->size()); |
420 | ::shutdown(this->socket(), 2); |
421 | } |
422 | |
423 | // done |
424 | ::close(this->socket()); |
425 | |
426 | delete this; |
427 | } |
428 | |
429 | |
430 | // AttachListener functions |
431 | |
432 | AttachOperation* AttachListener::dequeue() { |
433 | JavaThread* thread = JavaThread::current(); |
434 | ThreadBlockInVM tbivm(thread); |
435 | |
436 | AttachOperation* op = LinuxAttachListener::dequeue(); |
437 | |
438 | return op; |
439 | } |
440 | |
441 | // Performs initialization at vm startup |
442 | // For Linux we remove any stale .java_pid file which could cause |
443 | // an attaching process to think we are ready to receive on the |
444 | // domain socket before we are properly initialized |
445 | |
446 | void AttachListener::vm_start() { |
447 | char fn[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; |
448 | struct stat64 st; |
449 | int ret; |
450 | |
451 | int n = snprintf(fn, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path), "%s/.java_pid%d", |
452 | os::get_temp_directory(), os::current_process_id()); |
453 | assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow")do { if (!(n < (int)sizeof(((struct sockaddr_un *)0)->sun_path ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/os/linux/attachListener_linux.cpp" , 453, "assert(" "n < (int)sizeof(((struct sockaddr_un *)0)->sun_path)" ") failed", "java_pid file name buffer overflow"); ::breakpoint (); } } while (0); |
454 | |
455 | RESTARTABLE(::stat64(fn, &st), ret)do { ret = ::stat64(fn, &st); } while(((int)ret == OS_ERR ) && ((*__errno_location ()) == 4)); |
456 | if (ret == 0) { |
457 | ret = ::unlink(fn); |
458 | if (ret == -1) { |
459 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("Failed to remove stale attach pid file at %s", fn); |
460 | } |
461 | } |
462 | } |
463 | |
464 | int AttachListener::pd_init() { |
465 | JavaThread* thread = JavaThread::current(); |
466 | ThreadBlockInVM tbivm(thread); |
467 | |
468 | int ret_code = LinuxAttachListener::init(); |
469 | |
470 | return ret_code; |
471 | } |
472 | |
473 | bool AttachListener::check_socket_file() { |
474 | int ret; |
475 | struct stat64 st; |
476 | ret = stat64(LinuxAttachListener::path(), &st); |
477 | if (ret == -1) { // need to restart attach listener. |
478 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("Socket file %s does not exist - Restart Attach Listener", |
479 | LinuxAttachListener::path()); |
480 | |
481 | listener_cleanup(); |
482 | |
483 | // wait to terminate current attach listener instance... |
484 | { |
485 | // avoid deadlock if AttachListener thread is blocked at safepoint |
486 | ThreadBlockInVM tbivm(JavaThread::current()); |
487 | while (AttachListener::transit_state(AL_INITIALIZING, |
488 | AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) { |
489 | os::naked_yield(); |
490 | } |
491 | } |
492 | return is_init_trigger(); |
493 | } |
494 | return false; |
495 | } |
496 | |
497 | // Attach Listener is started lazily except in the case when |
498 | // +ReduseSignalUsage is used |
499 | bool AttachListener::init_at_startup() { |
500 | if (ReduceSignalUsage) { |
501 | return true; |
502 | } else { |
503 | return false; |
504 | } |
505 | } |
506 | |
507 | // If the file .attach_pid<pid> exists in the working directory |
508 | // or /tmp then this is the trigger to start the attach mechanism |
509 | bool AttachListener::is_init_trigger() { |
510 | if (init_at_startup() || is_initialized()) { |
511 | return false; // initialized at startup or already initialized |
512 | } |
513 | char fn[PATH_MAX4096 + 1]; |
514 | int ret; |
515 | struct stat64 st; |
516 | sprintf(fn, ".attach_pid%d", os::current_process_id()); |
517 | RESTARTABLE(::stat64(fn, &st), ret)do { ret = ::stat64(fn, &st); } while(((int)ret == OS_ERR ) && ((*__errno_location ()) == 4)); |
518 | if (ret == -1) { |
519 | log_trace(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Trace>("Failed to find attach file: %s, trying alternate", fn); |
520 | snprintf(fn, sizeof(fn), "%s/.attach_pid%d", |
521 | os::get_temp_directory(), os::current_process_id()); |
522 | RESTARTABLE(::stat64(fn, &st), ret)do { ret = ::stat64(fn, &st); } while(((int)ret == OS_ERR ) && ((*__errno_location ()) == 4)); |
523 | if (ret == -1) { |
524 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("Failed to find attach file: %s", fn); |
525 | } |
526 | } |
527 | if (ret == 0) { |
528 | // simple check to avoid starting the attach mechanism when |
529 | // a bogus non-root user creates the file |
530 | if (os::Posix::matches_effective_uid_or_root(st.st_uid)) { |
531 | init(); |
532 | log_trace(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Trace>("Attach triggered by %s", fn); |
533 | return true; |
534 | } else { |
535 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid()); |
536 | } |
537 | } |
538 | return false; |
539 | } |
540 | |
541 | // if VM aborts then remove listener |
542 | void AttachListener::abort() { |
543 | listener_cleanup(); |
544 | } |
545 | |
546 | void AttachListener::pd_data_dump() { |
547 | os::signal_notify(SIGQUIT3); |
548 | } |
549 | |
550 | AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* n) { |
551 | return NULL__null; |
552 | } |
553 | |
554 | jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { |
555 | out->print_cr("flag '%s' cannot be changed", op->arg(0)); |
556 | return JNI_ERR(-1); |
557 | } |
558 | |
559 | void AttachListener::pd_detachall() { |
560 | // do nothing for now |
561 | } |