Rewrite system(3) to use posix_spawn(3).

We saw crashes from pthread_exit+debuggerd on LP32
(https://issuetracker.google.com/72291624), and it seems like the
equivalent problem should exist with system(3). I fixed posix_spawn(3)
as part of that bug, so the easiest fix is probably to reuse that.

Bug: http://b/72470344
Test: ran tests
Change-Id: I05f838706f2b4a14ac3ee21292833e6c8579b0d4
diff --git a/libc/private/ScopedSignalBlocker.h b/libc/private/ScopedSignalBlocker.h
index 7582068..d1cf629 100644
--- a/libc/private/ScopedSignalBlocker.h
+++ b/libc/private/ScopedSignalBlocker.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SCOPED_SIGNAL_BLOCKER_H
-#define SCOPED_SIGNAL_BLOCKER_H
+#pragma once
 
 #include <signal.h>
 
@@ -23,10 +22,18 @@
 
 class ScopedSignalBlocker {
  public:
+  // Block all signals.
   explicit ScopedSignalBlocker() {
     sigset64_t set;
     sigfillset64(&set);
-    sigprocmask64(SIG_SETMASK, &set, &old_set_);
+    sigprocmask64(SIG_BLOCK, &set, &old_set_);
+  }
+
+  // Block just the specified signal.
+  explicit ScopedSignalBlocker(int signal) {
+    sigset64_t set = {};
+    sigaddset64(&set, signal);
+    sigprocmask64(SIG_BLOCK, &set, &old_set_);
   }
 
   ~ScopedSignalBlocker() {
@@ -37,10 +44,7 @@
     sigprocmask64(SIG_SETMASK, &old_set_, nullptr);
   }
 
- private:
   sigset64_t old_set_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedSignalBlocker);
 };
-
-#endif
diff --git a/libc/private/ScopedSignalHandler.h b/libc/private/ScopedSignalHandler.h
new file mode 100644
index 0000000..dd5823f
--- /dev/null
+++ b/libc/private/ScopedSignalHandler.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <signal.h>
+
+class ScopedSignalHandler {
+ public:
+  ScopedSignalHandler(int signal_number, void (*handler)(int), int sa_flags = 0)
+      : signal_number_(signal_number) {
+    action_ = { .sa_flags = sa_flags, .sa_handler = handler };
+    sigaction64(signal_number_, &action_, &old_action_);
+  }
+
+  ScopedSignalHandler(int signal_number, void (*action)(int, siginfo_t*, void*),
+                      int sa_flags = SA_SIGINFO)
+      : signal_number_(signal_number) {
+    action_ = { .sa_flags = sa_flags, .sa_sigaction = action };
+    sigaction64(signal_number_, &action_, &old_action_);
+  }
+
+  ScopedSignalHandler(int signal_number) : signal_number_(signal_number) {
+    sigaction64(signal_number, nullptr, &old_action_);
+  }
+
+  ~ScopedSignalHandler() {
+    sigaction64(signal_number_, &old_action_, nullptr);
+  }
+
+  struct sigaction64 action_;
+  struct sigaction64 old_action_;
+  const int signal_number_;
+};