relauncher_linux.cc 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // Copyright (c) 2016 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/relauncher.h"
  5. #include <fcntl.h>
  6. #include <signal.h>
  7. #include <sys/prctl.h>
  8. #include <sys/signalfd.h>
  9. #include "base/files/file_util.h"
  10. #include "base/files/scoped_file.h"
  11. #include "base/logging.h"
  12. #include "base/process/launch.h"
  13. #include "base/synchronization/waitable_event.h"
  14. namespace relauncher {
  15. namespace internal {
  16. // this is global to be visible to the sa_handler
  17. base::WaitableEvent parentWaiter;
  18. void RelauncherSynchronizeWithParent() {
  19. base::ScopedFD relauncher_sync_fd(kRelauncherSyncFD);
  20. static const auto signum = SIGUSR2;
  21. // send signum to current process when parent process ends.
  22. if (HANDLE_EINTR(prctl(PR_SET_PDEATHSIG, signum)) != 0) {
  23. PLOG(ERROR) << "prctl";
  24. return;
  25. }
  26. // set up a signum handler
  27. struct sigaction action;
  28. memset(&action, 0, sizeof(action));
  29. action.sa_handler = [](int /*signum*/) { parentWaiter.Signal(); };
  30. if (sigaction(signum, &action, nullptr) != 0) {
  31. PLOG(ERROR) << "sigaction";
  32. return;
  33. }
  34. // write a '\0' character to the pipe to the parent process.
  35. // this is how the parent knows that we're ready for it to exit.
  36. if (HANDLE_EINTR(write(relauncher_sync_fd.get(), "", 1)) != 1) {
  37. PLOG(ERROR) << "write";
  38. return;
  39. }
  40. // Wait for the parent to exit
  41. parentWaiter.Wait();
  42. }
  43. int LaunchProgram(const StringVector& relauncher_args,
  44. const StringVector& argv) {
  45. // Redirect the stdout of child process to /dev/null, otherwise after
  46. // relaunch the child process will raise exception when writing to stdout.
  47. base::ScopedFD devnull(HANDLE_EINTR(open("/dev/null", O_WRONLY)));
  48. base::LaunchOptions options;
  49. options.allow_new_privs = true;
  50. options.new_process_group = true; // detach
  51. options.fds_to_remap.emplace_back(devnull.get(), STDERR_FILENO);
  52. options.fds_to_remap.emplace_back(devnull.get(), STDOUT_FILENO);
  53. base::Process process = base::LaunchProcess(argv, options);
  54. return process.IsValid() ? 0 : 1;
  55. }
  56. } // namespace internal
  57. } // namespace relauncher