summaryrefslogtreecommitdiffstats
path: root/usr.bin/gcore/gcore.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/gcore/gcore.c')
-rw-r--r--usr.bin/gcore/gcore.c60
1 files changed, 29 insertions, 31 deletions
diff --git a/usr.bin/gcore/gcore.c b/usr.bin/gcore/gcore.c
index 7005e83..b02a4a9 100644
--- a/usr.bin/gcore/gcore.c
+++ b/usr.bin/gcore/gcore.c
@@ -61,19 +61,19 @@ __FBSDID("$FreeBSD$");
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/linker_set.h>
+#include <sys/sysctl.h>
#include <err.h>
#include <fcntl.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
+int sflag;
static void killed(int);
-static void restart_target(void);
static void usage(void) __dead2;
static pid_t pid;
@@ -83,10 +83,11 @@ SET_DECLARE(dumpset, struct dumpers);
int
main(int argc, char *argv[])
{
- int ch, efd, fd, sflag;
+ int ch, efd, fd, name[4];
char *binfile, *corefile;
- char fname[MAXPATHLEN];
+ char passpath[MAXPATHLEN], fname[MAXPATHLEN];
struct dumpers **d, *dumper;
+ size_t len;
sflag = 0;
corefile = NULL;
@@ -109,9 +110,14 @@ main(int argc, char *argv[])
switch (argc) {
case 1:
pid = atoi(argv[0]);
- asprintf(&binfile, "/proc/%d/file", pid);
- if (binfile == NULL)
- errx(1, "allocation failure");
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_PATHNAME;
+ name[3] = pid;
+ len = sizeof(passpath);
+ if (sysctl(name, 4, passpath, &len, NULL, 0) == -1)
+ errx(1, "kern.proc.pathname failure");
+ binfile = passpath;
break;
case 2:
pid = atoi(argv[1]);
@@ -141,36 +147,28 @@ main(int argc, char *argv[])
fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
if (fd < 0)
err(1, "%s", corefile);
- if (sflag) {
- signal(SIGHUP, killed);
- signal(SIGINT, killed);
- signal(SIGTERM, killed);
- if (kill(pid, SIGSTOP) == -1)
- err(1, "%d: stop signal", pid);
- atexit(restart_target);
- }
+ /*
+ * The semantics of the 's' flag is to stop the target process.
+ * Previous versions of gcore would manage this by trapping SIGHUP,
+ * SIGINT and SIGTERM (to be passed to the target pid), and then
+ * signal the child to stop.
+ *
+ * However, this messes up if the selected dumper uses ptrace calls
+ * that leave the child already stopped. The waitpid call in elfcore
+ * never returns.
+ *
+ * The best thing to do here is to externalize the 's' flag and let
+ * each dumper dispose of what that means, if anything. For the elfcore
+ * dumper, the 's' flag is a no-op since the ptrace attach stops the
+ * process in question already.
+ */
+
dumper->dump(efd, fd, pid);
(void)close(fd);
(void)close(efd);
exit(0);
}
-static void
-killed(int sig)
-{
-
- restart_target();
- signal(sig, SIG_DFL);
- kill(getpid(), sig);
-}
-
-static void
-restart_target(void)
-{
-
- kill(pid, SIGCONT);
-}
-
void
usage(void)
{
OpenPOWER on IntegriCloud