blob: f9282a8fde378fe6d9a20da0172d6bd80bb7b8a1 [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
7#include "shill/error.h"
8#include "shill/process_killer.h"
9
10namespace shill {
11
12using base::FilePath;
13using std::map;
14using std::string;
15using std::vector;
16
17ExternalTask::ExternalTask(
18 ControlInterface *control,
19 GLib *glib,
20 const base::WeakPtr<RPCTaskDelegate> &task_delegate,
21 const base::Callback<void(pid_t, int)> &death_callback)
22 : control_(control),
23 glib_(glib),
24 process_killer_(ProcessKiller::GetInstance()),
25 task_delegate_(task_delegate),
26 death_callback_(death_callback),
27 pid_(0),
28 child_watch_tag_(0) {
29 CHECK(task_delegate_);
30}
31
32ExternalTask::~ExternalTask() {
33 ExternalTask::Stop();
34}
35
36bool ExternalTask::Start(const FilePath &program,
37 const vector<string> &arguments,
38 const map<string, string> &environment,
39 Error *error) {
40 CHECK(!pid_);
41 CHECK(!child_watch_tag_);
42 CHECK(!rpc_task_);
43
44 scoped_ptr<RPCTask> local_rpc_task(new RPCTask(control_, this));
45
46 // const_cast is safe here, because exec*() (and SpawnAsync) do not
47 // modify the strings passed to them. This isn't captured in the
48 // exec*() prototypes, due to limitations in ISO C.
49 // http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html
50 vector<char *> process_args;
51 process_args.push_back(const_cast<char *>(program.value().c_str()));
52 for (const auto &option : arguments) {
53 process_args.push_back(const_cast<char *>(option.c_str()));
54 }
55 process_args.push_back(NULL);
56
57 vector<char *> process_env;
58 vector<string> env_vars(local_rpc_task->GetEnvironment());
59 for (const auto &env_pair : environment) {
60 env_vars.push_back(string(env_pair.first + "=" + env_pair.second));
61 }
62 for (const auto &env_var : env_vars) {
63 // See above regarding const_cast.
64 process_env.push_back(const_cast<char *>(env_var.c_str()));
65 }
66 process_env.push_back(NULL);
67
68 if (!glib_->SpawnAsync(NULL,
69 process_args.data(),
70 process_env.data(),
71 G_SPAWN_DO_NOT_REAP_CHILD,
72 NULL,
73 NULL,
74 &pid_,
75 NULL)) {
76 Error::PopulateAndLog(error, Error::kInternalError,
77 string("Unable to spawn: ") + process_args[0]);
78 return false;
79 }
80 child_watch_tag_ = glib_->ChildWatchAdd(pid_, OnTaskDied, this);
81 rpc_task_.reset(local_rpc_task.release());
82 return true;
83}
84
85void ExternalTask::Stop() {
86 if (child_watch_tag_) {
87 glib_->SourceRemove(child_watch_tag_);
88 child_watch_tag_ = 0;
89 }
90 if (pid_) {
91 process_killer_->Kill(pid_, base::Closure());
92 pid_ = 0;
93 }
94 rpc_task_.reset();
95}
96
97void ExternalTask::GetLogin(string *user, string *password) {
98 return task_delegate_->GetLogin(user, password);
99}
100
101void ExternalTask::Notify(const string &event,
102 const map<string, string> &details) {
103 return task_delegate_->Notify(event, details);
104}
105
106// static
107void ExternalTask::OnTaskDied(GPid pid, gint status, gpointer data) {
108 LOG(INFO) << __func__ << "(" << pid << ", " << status << ")";
109 ExternalTask *me = reinterpret_cast<ExternalTask *>(data);
110 me->child_watch_tag_ = 0;
111 CHECK_EQ(pid, me->pid_);
112 me->pid_ = 0;
113 me->death_callback_.Run(pid, status);
114}
115
116} // namespace shill