about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2023-01-11 01:12:48 +0000
committerEric Wong <mwrap-perl@80x24.org>2023-01-11 04:23:31 +0000
commit64a55ae0ba1d09ccda458eb895d849e7d38cab81 (patch)
tree10f5f5d99c49de5ba17277540a786a477f9e9c5c
parent86d350a3854af1a5a292972d4f70154e61ce5e80 (diff)
downloadmwrap-64a55ae0ba1d09ccda458eb895d849e7d38cab81.tar.gz
%p => PID expansion for dump_path + dump_csv
This makes it possible to dump per-PID files for processes which
fork.  `%p' matches what the Linux sys.kernel.core_pattern
sysctl understands.
-rw-r--r--mwrap_core.h15
-rw-r--r--script/mwrap-perl6
-rw-r--r--t/mwrap.t15
3 files changed, 36 insertions, 0 deletions
diff --git a/mwrap_core.h b/mwrap_core.h
index fff0538..86e4498 100644
--- a/mwrap_core.h
+++ b/mwrap_core.h
@@ -895,12 +895,27 @@ __attribute__ ((destructor)) static void mwrap_dtor(void)
         if (dump_path) {
                 char *end = strchr(dump_path, ',');
                 char buf[PATH_MAX];
+                AUTO_FREE char *pid_path = NULL;
                 if (end) {
                         mwrap_assert((end - dump_path) < (intptr_t)sizeof(buf));
                         end = mempcpy(buf, dump_path, end - dump_path);
                         *end = 0;
                         dump_path = buf;
                 }
+
+                /* %p => PID expansion (Linux core_pattern uses %p, too) */
+                if ((s = strchr(dump_path, '%')) && s[1] == 'p' &&
+                                /* don't allow injecting extra formats: */
+                                !strchr(s + 2, '%')) {
+                        s[1] = 'd'; /* s/%p/%d/ to make asprintf happy */
+                        int n = asprintf(&pid_path, dump_path, (int)getpid());
+                        if (n < 0)
+                                fprintf(stderr,
+                                        "asprintf failed: %m, dumping to %s\n",
+                                        dump_path);
+                        else
+                                dump_path = pid_path;
+                }
                 dump_fd = open(dump_path, O_CLOEXEC|O_WRONLY|O_APPEND|O_CREAT,
                                 0666);
                 if (dump_fd < 0) {
diff --git a/script/mwrap-perl b/script/mwrap-perl
index eb29176..371aee6 100644
--- a/script/mwrap-perl
+++ b/script/mwrap-perl
@@ -76,6 +76,10 @@ Dumps the output at exit to a given filename:
 
         total_bytes        call_count        location
 
+C<$FILENAME> may contain C<%p> where C<%p> is a placeholder for
+the PID being dumped.  No other use of C<%> is accepted, and
+multiple C<%> means all C<%> (including C<%p>) are handled as-is.
+
 =item dump_fd:$DESCRIPTOR
 
 As with dump_path, but dumps the output to a given file descriptor.
@@ -90,6 +94,8 @@ but is subject to change in future releases.
 C<dump_csv> without the C<:> may also be used in conjunction with
 C<dump_fd>, such as C<MWRAP=dump_fd:2,dump_csv>.
 
+Expands C<%p> to the PID in C<$FILENAME> as described for C<dump_path:>
+
 =back
 
 =head1 HTTP POST API
diff --git a/t/mwrap.t b/t/mwrap.t
index ccd739b..783f6e7 100644
--- a/t/mwrap.t
+++ b/t/mwrap.t
@@ -42,6 +42,21 @@ my $dump = "$mwrap_tmp/dump";
         $nr_comma = ($s =~ tr/,/,/);
         $nr_cr = ($s =~ tr/\n/\n/);
         ok($nr_comma > ($nr_cr * 4), 'CSV has more commas than CR');
+
+        $env->{MWRAP} = "dump_path:$dump.%p";
+        mwrap_run('dump_path PID expansion', $env, '-e', $script);
+        my @d = grep(/\.\d+\z/, glob("$dump.*"));
+        is(scalar(@d), 1, 'got PID file') or diag explain([glob("$dump*")]);
+        unlink(@d) or BAIL_OUT "unlink: $!";
+
+        # don't allow injecting random formats
+        for my $fmt ('%p.%m', '%m.%p') {
+                my $fn = $dump.$fmt;
+                $env->{MWRAP} = "dump_path:$fn";
+                mwrap_run("PID expansion fails on $fmt", $env, '-e', $script);
+                ok($fn, "$fmt used as-is");
+                unlink($fn) or BAIL_OUT "unlink: $!";
+        }
 }
 
 SKIP: { # C++ program which uses malloc via "new"