-JATTACH_VERSION=2.0
+JATTACH_VERSION=2.2
ifneq ($(findstring Windows,$(OS)),)
CL=cl.exe
JATTACH_EXE=jattach.exe
JATTACH_DLL=jattach.dll
else
- CFLAGS ?= -O3
JATTACH_EXE=jattach
UNAME_S:=$(shell uname -s)
ifeq ($(UNAME_S),Darwin)
+ CFLAGS ?= -O3 -arch x86_64 -arch arm64 -mmacos-version-min=10.12
JATTACH_DLL=libjattach.dylib
else
+ CFLAGS ?= -O3
JATTACH_DLL=libjattach.so
endif
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -DJATTACH_VERSION=\"$(JATTACH_VERSION)\" -o $@ src/posix/*.c
build/$(JATTACH_DLL): src/posix/*.c src/posix/*.h
- $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -DJATTACH_VERSION=\"$(JATTACH_VERSION)\" -fPIC -shared -fvisibility=hidden -o $@ src/posix/*.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -fPIC -shared -fvisibility=hidden -o $@ src/posix/*.c
build/jattach.exe: src/windows/jattach.c
$(CL) $(CFLAGS) /DJATTACH_VERSION=\"$(JATTACH_VERSION)\" /Fobuild/jattach.obj /Fe$@ $^ advapi32.lib /link /SUBSYSTEM:CONSOLE,5.02
### JVM Dynamic Attach utility
-The utility to send commands to remote JVM via Dynamic Attach mechanism.
+The utility to send commands to a JVM process via Dynamic Attach mechanism.
All-in-one **jmap + jstack + jcmd + jinfo** functionality in a single tiny program.
No installed JDK required, works with just JRE. Supports Linux containers.
### Download
-Binaries are available on the [Releases](https://github.com/apangin/jattach/releases) page.
+Binaries are available on the [Releases](https://github.com/jattach/jattach/releases) page.
On some platforms, you can also [install](#installation) jattach with a package manager.
#### List available jcmd commands
- $ jattach <pid> jcmd "help -all"
+ $ jattach <pid> jcmd help -all
### Installation
-#### FreeBSD
+#### Debian, Ubuntu
-On FreeBSD, you can use the following command to install `jattach` package:
+On Debian and Ubuntu, you can install `jattach` from the official repository:
- $ pkg install jattach
+ # apt install jattach
#### Alpine Linux
-On Alpine Linux, you can use the following command to install `jattach` package from the edge/community repository:
+On Alpine Linux, you can install `jattach` package from the edge/community repository:
- $ apk add --no-cache jattach --repository http://dl-cdn.alpinelinux.org/alpine/edge/community/
+ # apk add --no-cache jattach --repository http://dl-cdn.alpinelinux.org/alpine/edge/community/
#### Archlinux
[jattach](https://aur.archlinux.org/packages/jattach/) package can be installed from [AUR](https://wiki.archlinux.org/index.php/Arch_User_Repository) using one of [AUR helpers](https://wiki.archlinux.org/index.php/AUR_helpers), e.g., `yay`:
- $ yay -S jattach
+ # yay -S jattach
+
+#### FreeBSD
+
+On FreeBSD, you can use the following command to install `jattach`:
+
+ # pkg install jattach
+
-jattach (2.0-1) UNRELEASED; urgency=medium
+jattach (2.2-1) unstable; urgency=medium
+
+ * New upstream release.
+ * Update Standards-Version to 4.6.2 no changes required.
+ * Update debian/copyright, remove years for debian/* content.
+
+ -- Sven Hoexter <hoexter@debian.org> Tue, 16 Jan 2024 13:49:13 +0100
+
+jattach (2.1-1) unstable; urgency=medium
+
+ [ Sven Hoexter ]
+ * New upstream release.
+ * Update Standards-Version to 4.6.1 - no changes required.
+ * Drop additional LDFLAGS -Wl,--as-needed.
+ * Update dates to 2022 in debian/copyright.
+ * Set Rules-Requires-Root: no in debian/control.
+
+ -- Sven Hoexter <hoexter@debian.org> Mon, 25 Jul 2022 21:01:27 +0200
+
+jattach (2.0-1) unstable; urgency=medium
* New upstream release.
+ Adds OpenJ9 support.
* Update Standards-Version to 4.5.1 - no changes required.
* Raise debhelper-compat level from 12 to 13.
- -- Sven Hoexter <sven@stormbind.net> Mon, 16 Aug 2021 10:50:52 +0200
+ -- Sven Hoexter <hoexter@debian.org> Mon, 16 Aug 2021 20:06:29 +0200
jattach (1.5-2) unstable; urgency=medium
Priority: optional
Maintainer: Sven Hoexter <hoexter@debian.org>
Build-Depends: debhelper-compat (=13)
-Standards-Version: 4.5.1
+Standards-Version: 4.6.2
Homepage: https://github.com/apangin/jattach
Vcs-Browser: https://git.sven.stormbind.net/?p=sven/jattach.git
Vcs-Git: https://git.sven.stormbind.net/jattach.git
+Rules-Requires-Root: no
Package: jattach
Architecture: any
Source: https://github.com/apangin/jattach/releases
Files: *
-Copyright: 2016-2019 Andrei Pangin
+Copyright: 2016-2024 Andrei Pangin, jattach authors
License: Apache
Files: debian/*
-Copyright: 2019 Sven Hoexter <sven@stormbind.net>
+Copyright: Sven Hoexter <sven@stormbind.net>
License: Apache
License: Apache
.\" Hey, EMACS: -*- nroff -*-
-.\" (C) Copyright 2019-2020 Sven Hoexter <sven@stormbind.net>,
+.\" (C) Copyright 2019-2024 Sven Hoexter <sven@stormbind.net>,
.\"
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
-.TH JATTACH 1 "February 28 2020"
+.TH JATTACH 1 "January 16 2024"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.B jattach
.RI "pid [load|properties|agentProperties|datadump|threaddump|dumpheap|inspectheap|setflag|printflag|jcmd] [args]"
.SH DESCRIPTION
-jattach is an all in one jamp, jstack, jcmd, jinfo implementation as a tiny single C program.
+jattach is an all in one jmap, jstack, jcmd, jinfo implementation as a tiny single C program.
.SH OPTIONS
.B load
load agent library
#!/usr/bin/make -f
#export DH_VERBOSE = 1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
-export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
%:
dh $@
Name: jattach
-Version: 2.0
+Version: 2.2
Release: 1
Summary: JVM Dynamic Attach utility
Group: Development/Tools
License: ASL 2.0
-URL: https://github.com/apangin/jattach
+URL: https://github.com/jattach/jattach
Vendor: Andrei Pangin
Packager: Vadim Tsesko <incubos@yandex.com>
/usr/bin/jattach
%changelog
+* Wed Jan 10 2024 Andrei Pangin <noreply@pangin.pro> - 2.2-1
+- Automatically concatenate jcmd arguments
+- Fixed attach to OpenJ9 on macOS
+- Fixed container support on Linux 3.x
+
+* Mon Jul 25 2022 Vadim Tsesko <incubos@yandex.com> - 2.1-1
+- Handle both tabs and spaces when parsing /proc/pid/status
+- Socket timeout while reading response from OpenJ9 VM
+
* Wed Aug 11 2021 Vadim Tsesko <incubos@yandex.com> - 2.0-1
- Attach to OpenJ9 VMs
- Pass agent error codes
/*
- * Copyright 2021 Andrei Pangin
+ * Copyright jattach authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
extern int is_openj9_process(int pid);
-extern int jattach_openj9(int pid, int nspid, int argc, char** argv);
-extern int jattach_hotspot(int pid, int nspid, int argc, char** argv);
+extern int jattach_openj9(int pid, int nspid, int argc, char** argv, int print_output);
+extern int jattach_hotspot(int pid, int nspid, int argc, char** argv, int print_output);
+
+int mnt_changed = 0;
__attribute__((visibility("default")))
-int jattach(int pid, int argc, char** argv) {
+int jattach(int pid, int argc, char** argv, int print_output) {
uid_t my_uid = geteuid();
gid_t my_gid = getegid();
uid_t target_uid = my_uid;
// Network and IPC namespaces are essential for OpenJ9 connection.
enter_ns(pid, "net");
enter_ns(pid, "ipc");
- int mnt_changed = enter_ns(pid, "mnt");
+ mnt_changed = enter_ns(pid, "mnt");
// In HotSpot, dynamic attach is allowed only for the clients with the same euid/egid.
// If we are running under root, switch to the required euid/egid automatically.
signal(SIGPIPE, SIG_IGN);
if (is_openj9_process(nspid)) {
- return jattach_openj9(pid, nspid, argc, argv);
+ return jattach_openj9(pid, nspid, argc, argv, print_output);
} else {
- return jattach_hotspot(pid, nspid, argc, argv);
+ return jattach_hotspot(pid, nspid, argc, argv, print_output);
}
}
+#ifdef JATTACH_VERSION
+
int main(int argc, char** argv) {
if (argc < 3) {
printf("jattach " JATTACH_VERSION " built on " __DATE__ "\n"
- "Copyright 2021 Andrei Pangin\n"
"\n"
"Usage: jattach <pid> <cmd> [args ...]\n"
"\n"
return 1;
}
- return jattach(pid, argc - 2, argv + 2);
+ return jattach(pid, argc - 2, argv + 2, 1);
}
+
+#endif // JATTACH_VERSION
/*
- * Copyright 2021 Andrei Pangin
+ * Copyright jattach authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "psutil.h"
+extern int mnt_changed;
+
// Check if remote JVM has already opened socket for Dynamic Attach
static int check_socket(int pid) {
char path[MAX_PATH];
// HotSpot will start Attach listener in response to SIGQUIT if it sees .attach_pid file
static int start_attach_mechanism(int pid, int nspid) {
char path[MAX_PATH];
- snprintf(path, sizeof(path), "/proc/%d/cwd/.attach_pid%d", nspid, nspid);
+ snprintf(path, sizeof(path), "/proc/%d/cwd/.attach_pid%d", mnt_changed > 0 ? nspid : pid, nspid);
int fd = creat(path, 0660);
if (fd == -1 || (close(fd) == 0 && get_file_owner(path) != geteuid())) {
// Send command with arguments to socket
static int write_command(int fd, int argc, char** argv) {
+ char buf[8192];
+ const char* const limit = buf + sizeof(buf);
+
+ // jcmd has 2 arguments maximum; merge excessive arguments into one
+ int cmd_args = argc >= 2 && strcmp(argv[0], "jcmd") == 0 ? 2 : argc >= 4 ? 4 : argc;
+
// Protocol version
- if (write(fd, "1", 2) <= 0) {
- return -1;
- }
+ char* p = stpncpy(buf, "1", sizeof(buf)) + 1;
int i;
- for (i = 0; i < 4; i++) {
- const char* arg = i < argc ? argv[i] : "";
- if (write(fd, arg, strlen(arg) + 1) <= 0) {
+ for (i = 0; i < argc && p < limit; i++) {
+ if (i >= cmd_args) p[-1] = ' ';
+ p = stpncpy(p, argv[i], limit - p) + 1;
+ }
+ for (i = cmd_args; i < 4 && p < limit; i++) {
+ *p++ = 0;
+ }
+
+ const char* q = p < limit ? p : limit;
+ for (p = buf; p < q; ) {
+ ssize_t bytes = write(fd, p, q - p);
+ if (bytes <= 0) {
return -1;
}
+ p += (size_t)bytes;
}
return 0;
}
// Mirror response from remote JVM to stdout
-static int read_response(int fd, int argc, char** argv) {
+static int read_response(int fd, int argc, char** argv, int print_output) {
char buf[8192];
ssize_t bytes = read(fd, buf, sizeof(buf) - 1);
if (bytes == 0) {
result = atoi(strncmp(buf + 2, "return code: ", 13) == 0 ? buf + 15 : buf + 2);
}
- // Mirror JVM response to stdout
- printf("JVM response code = ");
- do {
- fwrite(buf, 1, bytes, stdout);
- bytes = read(fd, buf, sizeof(buf));
- } while (bytes > 0);
- printf("\n");
+ if (print_output) {
+ // Mirror JVM response to stdout
+ printf("JVM response code = ");
+ do {
+ fwrite(buf, 1, bytes, stdout);
+ bytes = read(fd, buf, sizeof(buf));
+ } while (bytes > 0);
+ printf("\n");
+ }
return result;
}
-int jattach_hotspot(int pid, int nspid, int argc, char** argv) {
+int jattach_hotspot(int pid, int nspid, int argc, char** argv, int print_output) {
if (check_socket(nspid) != 0 && start_attach_mechanism(pid, nspid) != 0) {
perror("Could not start attach mechanism");
return 1;
return 1;
}
- printf("Connected to remote JVM\n");
+ if (print_output) {
+ printf("Connected to remote JVM\n");
+ }
if (write_command(fd, argc, argv) != 0) {
perror("Error writing to socket");
return 1;
}
- int result = read_response(fd, argc, argv);
+ int result = read_response(fd, argc, argv, print_output);
close(fd);
return result;
/*
- * Copyright 2021 Andrei Pangin
+ * Copyright jattach authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
} else if (strcmp(cmd, "jcmd") == 0) {
- snprintf(buf, bufsize, "ATTACH_DIAGNOSTICS:%s,%s", argc > 1 ? argv[1] : "help", argc > 2 ? argv[2] : "");
+ size_t n = snprintf(buf, bufsize, "ATTACH_DIAGNOSTICS:%s", argc > 1 ? argv[1] : "help");
+ int i;
+ for (i = 2; i < argc && n < bufsize; i++) {
+ n += snprintf(buf + n, bufsize - n, ",%s", argv[i]);
+ }
} else if (strcmp(cmd, "threaddump") == 0) {
snprintf(buf, bufsize, "ATTACH_DIAGNOSTICS:Thread.print,%s", argc > 1 ? argv[1] : "");
}
// Mirror response from remote JVM to stdout
-static int read_response(int fd, const char* cmd) {
+static int read_response(int fd, const char* cmd, int print_output) {
size_t size = 8192;
char* buf = malloc(size);
// AgentOnLoad error code comes right after AgentInitializationException
result = strncmp(buf, "ATTACH_ERR AgentInitializationException", 39) == 0 ? atoi(buf + 39) : -1;
}
- } else if (strncmp(cmd, "ATTACH_DIAGNOSTICS:", 19) == 0) {
+ } else if (strncmp(cmd, "ATTACH_DIAGNOSTICS:", 19) == 0 && print_output) {
char* p = strstr(buf, "openj9_diagnostics.string_result=");
if (p != NULL) {
// The result of a diagnostic command is encoded in Java Properties format
}
}
- buf[off - 1] = '\n';
- fwrite(buf, 1, off, stdout);
+ if (print_output) {
+ buf[off - 1] = '\n';
+ fwrite(buf, 1, off, stdout);
+ }
free(buf);
return result;
// Try IPv6 socket first, then fall back to IPv4
int s = socket(AF_INET6, SOCK_STREAM, 0);
if (s != -1) {
- struct sockaddr_in6 addr = {AF_INET6, 0};
+ struct sockaddr_in6 addr = {0};
+ addr.sin6_family = AF_INET6;
socklen_t addrlen = sizeof(addr);
if (bind(s, (struct sockaddr*)&addr, addrlen) == 0 && listen(s, 0) == 0
&& getsockname(s, (struct sockaddr*)&addr, &addrlen) == 0) {
return s;
}
} else if ((s = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
- struct sockaddr_in addr = {AF_INET, 0};
+ struct sockaddr_in addr = {0};
+ addr.sin_family = AF_INET;
socklen_t addrlen = sizeof(addr);
if (bind(s, (struct sockaddr*)&addr, addrlen) == 0 && listen(s, 0) == 0
&& getsockname(s, (struct sockaddr*)&addr, &addrlen) == 0) {
}
int chars = snprintf(path, sizeof(path), "%016llx\n%d\n", key, port);
- write(fd, path, chars);
+ ssize_t r = write(fd, path, chars);
+ (void)r;
close(fd);
return 0;
return -1;
}
+ // Reset the timeout, as the command execution may take arbitrary long time
+ struct timeval tv0 = {0, 0};
+ setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, &tv0, sizeof(tv0));
+
return client;
}
return stat(path, &stats) == 0;
}
-int jattach_openj9(int pid, int nspid, int argc, char** argv) {
+int jattach_openj9(int pid, int nspid, int argc, char** argv, int print_output) {
int attach_lock = acquire_lock("", "_attachlock");
if (attach_lock < 0) {
perror("Could not acquire attach lock");
notify_semaphore(-1, notif_count);
release_lock(attach_lock);
- printf("Connected to remote JVM\n");
+ if (print_output) {
+ printf("Connected to remote JVM\n");
+ }
char cmd[8192];
translate_command(cmd, sizeof(cmd), argc, argv);
return 1;
}
- int result = read_response(fd, cmd);
+ int result = read_response(fd, cmd, print_output);
if (result != 1) {
detach(fd);
}
/*
- * Copyright 2021 Andrei Pangin
+ * Copyright jattach authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// Check if /proc/<container-pid>/sched points back to <host-pid>
snprintf(path, sizeof(path), "/proc/%d/root/proc/%s/sched", pid, entry->d_name);
if (sched_get_host_pid(path) == pid) {
- closedir(dir);
- return atoi(entry->d_name);
+ pid = atoi(entry->d_name);
+ break;
}
}
}
closedir(dir);
}
- // Could not find container pid; return host pid as the last resort
return pid;
}
int nspid_found = 0;
while (getline(&line, &size, status_file) != -1) {
- if (strncmp(line, "Uid:", 4) == 0) {
+ if (strncmp(line, "Uid:", 4) == 0 && strtok(line + 4, "\t ") != NULL) {
// Get the effective UID, which is the second value in the line
- *uid = (uid_t)atoi(strchr(line + 5, '\t'));
- } else if (strncmp(line, "Gid:", 4) == 0) {
+ *uid = (uid_t)atoi(strtok(NULL, "\t "));
+ } else if (strncmp(line, "Gid:", 4) == 0 && strtok(line + 4, "\t ") != NULL) {
// Get the effective GID, which is the second value in the line
- *gid = (gid_t)atoi(strchr(line + 5, '\t'));
+ *gid = (gid_t)atoi(strtok(NULL, "\t "));
} else if (strncmp(line, "NStgid:", 7) == 0) {
// PID namespaces can be nested; the last one is the innermost one
- *nspid = atoi(strrchr(line, '\t'));
+ char* s;
+ for (s = strtok(line + 7, "\t "); s != NULL; s = strtok(NULL, "\t ")) {
+ *nspid = atoi(s);
+ }
nspid_found = 1;
}
}
/*
- * Copyright 2021 Andrei Pangin
+ * Copyright jattach authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <sys/types.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define MAX_PATH 1024
extern char tmp_path[];
// -1, if the attempt failed.
int enter_ns(int pid, const char* type);
+#ifdef __cplusplus
+}
+#endif
+
#endif // _PSUTIL_H
/*
- * Copyright 2016 Andrei Pangin
+ * Copyright jattach authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stdio.h>
#include <stdlib.h>
-#include <Windows.h>
+#include <windows.h>
+#include <sddl.h>
typedef HMODULE (WINAPI *GetModuleHandle_t)(LPCTSTR lpModuleName);
typedef FARPROC (WINAPI *GetProcAddress_t)(HMODULE hModule, LPCSTR lpProcName);
strcpy(data.strJvm, "jvm");
strcpy(data.strEnqueue, "_JVM_EnqueueOperation");
strcpy(data.pipeName, pipeName);
+ data.args[0][0] = data.args[1][0] = data.args[2][0] = data.args[3][0] = 0;
+ // jcmd has 2 arguments maximum; merge excessive arguments into one
+ int cmd_args = argc >= 2 && strcmp(argv[0], "jcmd") == 0 ? 2 : argc >= 4 ? 4 : argc;
+
+ size_t n = 0;
int i;
- for (i = 0; i < 4; i++) {
- strcpy(data.args[i], i < argc ? argv[i] : "");
+ for (i = 0; i < argc; i++) {
+ if (i < cmd_args) {
+ n = snprintf(data.args[i], sizeof(data.args[i]), "%s", argv[i]);
+ } else if (n < sizeof(data.args[cmd_args - 1])) {
+ n += snprintf(data.args[cmd_args - 1] + n, sizeof(data.args[cmd_args - 1]) - n, " %s", argv[i]);
+ }
}
LPVOID remoteData = VirtualAllocEx(hProcess, NULL, sizeof(CallData), MEM_COMMIT, PAGE_READWRITE);
}
// JVM response is read from the pipe and mirrored to stdout
-static int read_response(HANDLE hPipe) {
+static int read_response(HANDLE hPipe, int print_output) {
ConnectNamedPipe(hPipe, NULL);
char buf[8192];
buf[bytesRead] = 0;
int result = atoi(buf);
- do {
- fwrite(buf, 1, bytesRead, stdout);
- } while (ReadFile(hPipe, buf, sizeof(buf), &bytesRead, NULL));
+ if (print_output) {
+ // Mirror JVM response to stdout
+ printf("JVM response code = ");
+ do {
+ fwrite(buf, 1, bytesRead, stdout);
+ } while (ReadFile(hPipe, buf, sizeof(buf), &bytesRead, NULL));
+ printf("\n");
+ }
return result;
}
+int jattach(int pid, int argc, char** argv, int print_output) {
+ // When attaching as an Administrator, make sure the target process can connect to our pipe,
+ // i.e. allow read-write access to everyone. For the complete format description, see
+ // https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format
+ SECURITY_ATTRIBUTES sec = {sizeof(SECURITY_ATTRIBUTES), NULL, FALSE};
+ ConvertStringSecurityDescriptorToSecurityDescriptor("D:(A;;GRGW;;;WD)", SDDL_REVISION_1,
+ &sec.lpSecurityDescriptor, NULL);
+
+ char pipeName[MAX_PATH];
+ sprintf(pipeName, "\\\\.\\pipe\\javatool%d", GetTickCount());
+ HANDLE hPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ 1, 4096, 8192, NMPWAIT_USE_DEFAULT_WAIT, &sec);
+ if (hPipe == INVALID_HANDLE_VALUE) {
+ print_error("Could not create pipe", GetLastError());
+ LocalFree(sec.lpSecurityDescriptor);
+ return 1;
+ }
+
+ LocalFree(sec.lpSecurityDescriptor);
+
+ if (!inject_thread(pid, pipeName, argc, argv)) {
+ CloseHandle(hPipe);
+ return 1;
+ }
+
+ int result = read_response(hPipe, print_output);
+ CloseHandle(hPipe);
+
+ return result;
+}
+
+#ifdef JATTACH_VERSION
+
int main(int argc, char** argv) {
if (argc < 3) {
printf("jattach " JATTACH_VERSION " built on " __DATE__ "\n"
- "Copyright 2021 Andrei Pangin\n"
"\n"
"Usage: jattach <pid> <cmd> [args ...]\n"
"\n"
}
int pid = atoi(argv[1]);
-
- char pipeName[MAX_PATH];
- sprintf(pipeName, "\\\\.\\pipe\\javatool%d", GetTickCount());
- HANDLE hPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- 1, 4096, 8192, NMPWAIT_USE_DEFAULT_WAIT, NULL);
- if (hPipe == NULL) {
- print_error("Could not create pipe", GetLastError());
+ if (pid <= 0) {
+ fprintf(stderr, "%s is not a valid process ID\n", argv[1]);
return 1;
}
- if (!inject_thread(pid, pipeName, argc - 2, argv + 2)) {
- CloseHandle(hPipe);
- return 1;
- }
-
- printf("Response code = ");
- fflush(stdout);
-
- int result = read_response(hPipe);
- printf("\n");
- CloseHandle(hPipe);
-
- return result;
+ return jattach(pid, argc - 2, argv + 2, 1);
}
+
+#endif // JATTACH_VERSION