blob: fa970cf5f24fdc7ffac22d9cc4a7f47f450e07f3 [file] [log] [blame]
Ben Chan1e5a0cb2012-03-22 00:41:52 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Chan5ccd9fe2013-11-13 18:28:27 -08005#include "cros-disks/device_ejector.h"
Ben Chan1e5a0cb2012-03-22 00:41:52 -07006
Mattias Nissler6df1b1b2018-10-10 15:26:10 +02007#include <linux/capability.h>
8
Ben Chan15232cf2017-09-26 22:58:03 -07009#include <memory>
10
Ben Chan1e5a0cb2012-03-22 00:41:52 -070011#include <base/bind.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090012#include <base/check.h>
Ben Chan1e5a0cb2012-03-22 00:41:52 -070013#include <base/logging.h>
Ben Chan1e5a0cb2012-03-22 00:41:52 -070014
François Degros8b4e31e2019-07-29 11:39:19 +100015#include "cros-disks/quote.h"
16
Anand K Mistry40cff452019-07-30 10:24:48 +100017namespace cros_disks {
Ben Chan1e5a0cb2012-03-22 00:41:52 -070018namespace {
19
20// Expected location of the 'eject' program.
21const char kEjectProgram[] = "/usr/bin/eject";
22
23} // namespace
24
Ben Chan445852f2017-10-02 23:00:16 -070025DeviceEjector::DeviceEjector(brillo::ProcessReaper* process_reaper)
26 : process_reaper_(process_reaper), weak_ptr_factory_(this) {}
Ben Chan1e5a0cb2012-03-22 00:41:52 -070027
Ben Chanfc77d712019-06-20 12:45:56 -070028DeviceEjector::~DeviceEjector() = default;
Ben Chan1e5a0cb2012-03-22 00:41:52 -070029
Ben Chan445852f2017-10-02 23:00:16 -070030bool DeviceEjector::Eject(const std::string& device_path) {
Ben Chan1e5a0cb2012-03-22 00:41:52 -070031 CHECK(!device_path.empty()) << "Invalid device path";
32
François Degros8b4e31e2019-07-29 11:39:19 +100033 LOG(INFO) << "Eject device " << quote(device_path);
Qijiang Fan52439042020-06-17 15:34:38 +090034 if (base::Contains(eject_process_, device_path)) {
François Degros8b4e31e2019-07-29 11:39:19 +100035 LOG(WARNING) << "Device " << quote(device_path)
36 << " is already being ejected";
Ben Chan445852f2017-10-02 23:00:16 -070037 return false;
38 }
Ben Chan1e5a0cb2012-03-22 00:41:52 -070039
Ben Chan445852f2017-10-02 23:00:16 -070040 SandboxedProcess* process = &eject_process_[device_path];
41 process->SetNoNewPrivileges();
42 process->NewIpcNamespace();
43 process->NewNetworkNamespace();
Ben Chan1e5a0cb2012-03-22 00:41:52 -070044 process->AddArgument(kEjectProgram);
45 process->AddArgument(device_path);
Mattias Nissler6df1b1b2018-10-10 15:26:10 +020046 process->SetCapabilities(CAP_TO_MASK(CAP_SYS_ADMIN));
Ben Chan445852f2017-10-02 23:00:16 -070047
Ben Chan1e5a0cb2012-03-22 00:41:52 -070048 // TODO(benchan): Set up a timeout to kill a hanging process.
Anand K Mistry57340372018-08-22 17:12:23 +100049 bool started = process->Start();
50 if (started) {
51 process_reaper_->WatchForChild(
52 FROM_HERE, process->pid(),
Anand K Mistry44b77d42019-09-27 11:03:20 +100053 base::BindOnce(&DeviceEjector::OnEjectProcessTerminated,
54 weak_ptr_factory_.GetWeakPtr(), device_path));
Anand K Mistry57340372018-08-22 17:12:23 +100055 } else {
56 eject_process_.erase(device_path);
François Degros8b4e31e2019-07-29 11:39:19 +100057 LOG(WARNING) << "Cannot eject media from device " << quote(device_path);
Anand K Mistry57340372018-08-22 17:12:23 +100058 }
59 return started;
Ben Chan1e5a0cb2012-03-22 00:41:52 -070060}
61
Ben Chan445852f2017-10-02 23:00:16 -070062void DeviceEjector::OnEjectProcessTerminated(const std::string& device_path,
63 const siginfo_t& info) {
64 eject_process_.erase(device_path);
65 switch (info.si_code) {
66 case CLD_EXITED:
67 if (info.si_status == 0) {
François Degros8b4e31e2019-07-29 11:39:19 +100068 LOG(INFO) << "Process " << info.si_pid << " for ejecting "
69 << quote(device_path) << " completed successfully";
Ben Chan445852f2017-10-02 23:00:16 -070070 } else {
François Degros8b4e31e2019-07-29 11:39:19 +100071 LOG(ERROR) << "Process " << info.si_pid << " for ejecting "
72 << quote(device_path) << " exited with a status "
Ben Chan445852f2017-10-02 23:00:16 -070073 << info.si_status;
74 }
Ben Chanbba00ef2017-01-05 13:26:04 -080075 break;
Ben Chan445852f2017-10-02 23:00:16 -070076
77 case CLD_DUMPED:
78 case CLD_KILLED:
François Degros8b4e31e2019-07-29 11:39:19 +100079 LOG(ERROR) << "Process " << info.si_pid << " for ejecting "
80 << quote(device_path) << " killed by a signal "
81 << info.si_status;
Ben Chan445852f2017-10-02 23:00:16 -070082 break;
83
84 default:
85 break;
Ben Chanbba00ef2017-01-05 13:26:04 -080086 }
Ben Chan1e5a0cb2012-03-22 00:41:52 -070087}
88
89} // namespace cros_disks