blob: 778fa659846d27fe0037b90690778e716541a6f9 [file] [log] [blame]
mukesh agrawalae30e9e2013-05-28 14:09:16 -07001// Copyright (c) 2013 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
5#include "shill/external_task.h"
6
mukesh agrawalc4f9aa02013-08-15 19:23:13 -07007#include <signal.h>
8#include <sys/prctl.h>
9
mukesh agrawal9da07772013-05-15 14:15:17 -070010#include <base/bind.h>
11#include <base/bind_helpers.h>
12
mukesh agrawalae30e9e2013-05-28 14:09:16 -070013#include "shill/error.h"
mukesh agrawal9da07772013-05-15 14:15:17 -070014#include "shill/event_dispatcher.h"
mukesh agrawalae30e9e2013-05-28 14:09:16 -070015#include "shill/process_killer.h"
16
17namespace shill {
18
19using base::FilePath;
20using std::map;
21using std::string;
22using std::vector;
23
24ExternalTask::ExternalTask(
Paul Stewarta794cd62015-06-16 13:13:10 -070025 ControlInterface* control,
26 GLib* glib,
27 const base::WeakPtr<RPCTaskDelegate>& task_delegate,
28 const base::Callback<void(pid_t, int)>& death_callback)
mukesh agrawalae30e9e2013-05-28 14:09:16 -070029 : control_(control),
30 glib_(glib),
31 process_killer_(ProcessKiller::GetInstance()),
32 task_delegate_(task_delegate),
33 death_callback_(death_callback),
34 pid_(0),
35 child_watch_tag_(0) {
36 CHECK(task_delegate_);
37}
38
39ExternalTask::~ExternalTask() {
40 ExternalTask::Stop();
41}
42
Paul Stewarta794cd62015-06-16 13:13:10 -070043void ExternalTask::DestroyLater(EventDispatcher* dispatcher) {
mukesh agrawal9da07772013-05-15 14:15:17 -070044 // Passes ownership of |this| to Destroy.
45 dispatcher->PostTask(base::Bind(&Destroy, this));
46}
47
Paul Stewarta794cd62015-06-16 13:13:10 -070048bool ExternalTask::Start(const FilePath& program,
49 const vector<string>& arguments,
50 const map<string, string>& environment,
mukesh agrawalc4f9aa02013-08-15 19:23:13 -070051 bool terminate_with_parent,
Paul Stewarta794cd62015-06-16 13:13:10 -070052 Error* error) {
mukesh agrawalae30e9e2013-05-28 14:09:16 -070053 CHECK(!pid_);
54 CHECK(!child_watch_tag_);
55 CHECK(!rpc_task_);
56
Ben Chancd477322014-10-17 14:19:30 -070057 std::unique_ptr<RPCTask> local_rpc_task(new RPCTask(control_, this));
mukesh agrawalae30e9e2013-05-28 14:09:16 -070058
59 // const_cast is safe here, because exec*() (and SpawnAsync) do not
60 // modify the strings passed to them. This isn't captured in the
61 // exec*() prototypes, due to limitations in ISO C.
62 // http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html
Paul Stewarta794cd62015-06-16 13:13:10 -070063 vector<char*> process_args;
64 process_args.push_back(const_cast<char*>(program.value().c_str()));
65 for (const auto& option : arguments) {
66 process_args.push_back(const_cast<char*>(option.c_str()));
mukesh agrawalae30e9e2013-05-28 14:09:16 -070067 }
Ben Chancc225ef2014-09-30 13:26:51 -070068 process_args.push_back(nullptr);
mukesh agrawalae30e9e2013-05-28 14:09:16 -070069
Paul Stewarta794cd62015-06-16 13:13:10 -070070 vector<char*> process_env;
mukesh agrawalae30e9e2013-05-28 14:09:16 -070071 vector<string> env_vars(local_rpc_task->GetEnvironment());
Paul Stewarta794cd62015-06-16 13:13:10 -070072 for (const auto& env_pair : environment) {
mukesh agrawalae30e9e2013-05-28 14:09:16 -070073 env_vars.push_back(string(env_pair.first + "=" + env_pair.second));
74 }
Paul Stewarta794cd62015-06-16 13:13:10 -070075 for (const auto& env_var : env_vars) {
mukesh agrawalae30e9e2013-05-28 14:09:16 -070076 // See above regarding const_cast.
Paul Stewarta794cd62015-06-16 13:13:10 -070077 process_env.push_back(const_cast<char*>(env_var.c_str()));
mukesh agrawalae30e9e2013-05-28 14:09:16 -070078 }
Ben Chancc225ef2014-09-30 13:26:51 -070079 process_env.push_back(nullptr);
mukesh agrawalae30e9e2013-05-28 14:09:16 -070080
mukesh agrawalc4f9aa02013-08-15 19:23:13 -070081 GSpawnChildSetupFunc child_setup_func =
Ben Chancc225ef2014-09-30 13:26:51 -070082 terminate_with_parent ? SetupTermination : nullptr;
mukesh agrawalc4f9aa02013-08-15 19:23:13 -070083
Ben Chancc225ef2014-09-30 13:26:51 -070084 if (!glib_->SpawnAsync(nullptr,
mukesh agrawalae30e9e2013-05-28 14:09:16 -070085 process_args.data(),
86 process_env.data(),
87 G_SPAWN_DO_NOT_REAP_CHILD,
mukesh agrawalc4f9aa02013-08-15 19:23:13 -070088 child_setup_func,
Ben Chancc225ef2014-09-30 13:26:51 -070089 nullptr,
mukesh agrawalae30e9e2013-05-28 14:09:16 -070090 &pid_,
Ben Chancc225ef2014-09-30 13:26:51 -070091 nullptr)) {
Paul Stewart34f424e2015-01-16 15:30:20 -080092 Error::PopulateAndLog(FROM_HERE, error, Error::kInternalError,
mukesh agrawalae30e9e2013-05-28 14:09:16 -070093 string("Unable to spawn: ") + process_args[0]);
94 return false;
95 }
96 child_watch_tag_ = glib_->ChildWatchAdd(pid_, OnTaskDied, this);
97 rpc_task_.reset(local_rpc_task.release());
98 return true;
99}
100
101void ExternalTask::Stop() {
102 if (child_watch_tag_) {
103 glib_->SourceRemove(child_watch_tag_);
104 child_watch_tag_ = 0;
105 }
106 if (pid_) {
107 process_killer_->Kill(pid_, base::Closure());
108 pid_ = 0;
109 }
110 rpc_task_.reset();
111}
112
Paul Stewarta794cd62015-06-16 13:13:10 -0700113void ExternalTask::GetLogin(string* user, string* password) {
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700114 return task_delegate_->GetLogin(user, password);
115}
116
Paul Stewarta794cd62015-06-16 13:13:10 -0700117void ExternalTask::Notify(const string& event,
118 const map<string, string>& details) {
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700119 return task_delegate_->Notify(event, details);
120}
121
122// static
123void ExternalTask::OnTaskDied(GPid pid, gint status, gpointer data) {
124 LOG(INFO) << __func__ << "(" << pid << ", " << status << ")";
Paul Stewarta794cd62015-06-16 13:13:10 -0700125 ExternalTask* me = reinterpret_cast<ExternalTask*>(data);
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700126 me->child_watch_tag_ = 0;
127 CHECK_EQ(pid, me->pid_);
128 me->pid_ = 0;
129 me->death_callback_.Run(pid, status);
130}
131
mukesh agrawal9da07772013-05-15 14:15:17 -0700132// static
Paul Stewarta794cd62015-06-16 13:13:10 -0700133void ExternalTask::Destroy(ExternalTask* task) {
mukesh agrawal9da07772013-05-15 14:15:17 -0700134 delete task;
135}
136
mukesh agrawalc4f9aa02013-08-15 19:23:13 -0700137// static
138void ExternalTask::SetupTermination(gpointer /*glib_user_data*/) {
139 prctl(PR_SET_PDEATHSIG, SIGTERM);
140}
141
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700142} // namespace shill