| 1 | #include <errno.h> |
| 2 | #include <fcntl.h> |
| 3 | #include <signal.h> |
| 4 | #include <stdio.h> |
| 5 | #include <stdlib.h> |
| 6 | #include <string.h> |
| 7 | #include <unistd.h> |
| 8 | |
| 9 | #include <sys/types.h> |
| 10 | #include <sys/ptrace.h> |
| 11 | #include <sys/stat.h> |
| 12 | #include <sys/wait.h> |
| 13 | |
| 14 | #if defined(PTRACE_ATTACH) |
| 15 | #define ATTACH_REQUEST PTRACE_ATTACH |
| 16 | #define DETACH_REQUEST PTRACE_DETACH |
| 17 | #elif defined(PT_ATTACH) |
| 18 | #define ATTACH_REQUEST PT_ATTACH |
| 19 | #define DETACH_REQUEST PT_DETACH |
| 20 | #else |
| 21 | #error "Unsupported platform" |
| 22 | #endif |
| 23 | |
| 24 | bool writePid (const char* file_name, const pid_t pid) |
| 25 | { |
| 26 | char *tmp_file_name = (char *)malloc(size: strlen(s: file_name) + 16); |
| 27 | strcpy(dest: tmp_file_name, src: file_name); |
| 28 | strcat(dest: tmp_file_name, src: "_tmp" ); |
| 29 | int fd = open (file: tmp_file_name, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); |
| 30 | if (fd == -1) |
| 31 | { |
| 32 | fprintf (stderr, format: "open(%s) failed: %s\n" , tmp_file_name, strerror (errno)); |
| 33 | free(ptr: tmp_file_name); |
| 34 | return false; |
| 35 | } |
| 36 | char buffer[64]; |
| 37 | snprintf (s: buffer, maxlen: sizeof(buffer), format: "%ld" , (long)pid); |
| 38 | |
| 39 | bool res = true; |
| 40 | if (write (fd: fd, buf: buffer, n: strlen (s: buffer)) == -1) |
| 41 | { |
| 42 | fprintf (stderr, format: "write(%s) failed: %s\n" , buffer, strerror (errno)); |
| 43 | res = false; |
| 44 | } |
| 45 | close (fd: fd); |
| 46 | |
| 47 | if (rename (old: tmp_file_name, new: file_name) == -1) |
| 48 | { |
| 49 | fprintf (stderr, format: "rename(%s, %s) failed: %s\n" , tmp_file_name, file_name, strerror (errno)); |
| 50 | res = false; |
| 51 | } |
| 52 | free(ptr: tmp_file_name); |
| 53 | |
| 54 | return res; |
| 55 | } |
| 56 | |
| 57 | void signal_handler (int) |
| 58 | { |
| 59 | } |
| 60 | |
| 61 | int main (int argc, char const *argv[]) |
| 62 | { |
| 63 | if (argc < 2) |
| 64 | { |
| 65 | fprintf (stderr, format: "invalid number of command line arguments\n" ); |
| 66 | return 1; |
| 67 | } |
| 68 | |
| 69 | const pid_t pid = fork (); |
| 70 | if (pid == -1) |
| 71 | { |
| 72 | fprintf (stderr, format: "fork failed: %s\n" , strerror (errno)); |
| 73 | return 1; |
| 74 | } |
| 75 | |
| 76 | if (pid > 0) |
| 77 | { |
| 78 | // Make pause call to return when a signal is received. Normally this happens when the |
| 79 | // test runner tries to terminate us. |
| 80 | signal (SIGHUP, handler: signal_handler); |
| 81 | signal (SIGTERM, handler: signal_handler); |
| 82 | if (ptrace (ATTACH_REQUEST, pid, NULL, 0) == -1) |
| 83 | { |
| 84 | fprintf (stderr, format: "ptrace(ATTACH) failed: %s\n" , strerror (errno)); |
| 85 | } |
| 86 | else |
| 87 | { |
| 88 | if (writePid (file_name: argv[1], pid)) |
| 89 | pause (); // Waiting for the debugger trying attach to the child. |
| 90 | |
| 91 | if (ptrace (DETACH_REQUEST, pid, NULL, 0) != 0) |
| 92 | fprintf (stderr, format: "ptrace(DETACH) failed: %s\n" , strerror (errno)); |
| 93 | } |
| 94 | |
| 95 | kill (pid: pid, SIGTERM); |
| 96 | int status = 0; |
| 97 | if (waitpid (pid: pid, stat_loc: &status, options: 0) == -1) |
| 98 | fprintf (stderr, format: "waitpid failed: %s\n" , strerror (errno)); |
| 99 | } |
| 100 | else |
| 101 | { |
| 102 | // child inferior. |
| 103 | pause (); |
| 104 | } |
| 105 | |
| 106 | printf (format: "Exiting now\n" ); |
| 107 | return 0; |
| 108 | } |
| 109 | |