blob: 4ea88d4a6feac1bad9397ca2753766e2755d7843 [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(
25 ControlInterface *control,
26 GLib *glib,
27 const base::WeakPtr<RPCTaskDelegate> &task_delegate,
28 const base::Callback<void(pid_t, int)> &death_callback)
29 : 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
mukesh agrawal9da07772013-05-15 14:15:17 -070043void ExternalTask::DestroyLater(EventDispatcher *dispatcher) {
44 // Passes ownership of |this| to Destroy.
45 dispatcher->PostTask(base::Bind(&Destroy, this));
46}
47
mukesh agrawalae30e9e2013-05-28 14:09:16 -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,
mukesh agrawalae30e9e2013-05-28 14:09:16 -070052 Error *error) {
53 CHECK(!pid_);
54 CHECK(!child_watch_tag_);
55 CHECK(!rpc_task_);
56
57 scoped_ptr<RPCTask> local_rpc_task(new RPCTask(control_, this));
58
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
63 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()));
67 }
68 process_args.push_back(NULL);
69
70 vector<char *> process_env;
71 vector<string> env_vars(local_rpc_task->GetEnvironment());
72 for (const auto &env_pair : environment) {
73 env_vars.push_back(string(env_pair.first + "=" + env_pair.second));
74 }
75 for (const auto &env_var : env_vars) {
76 // See above regarding const_cast.
77 process_env.push_back(const_cast<char *>(env_var.c_str()));
78 }
79 process_env.push_back(NULL);
80
mukesh agrawalc4f9aa02013-08-15 19:23:13 -070081 GSpawnChildSetupFunc child_setup_func =
82 terminate_with_parent ? SetupTermination : NULL;
83
mukesh agrawalae30e9e2013-05-28 14:09:16 -070084 if (!glib_->SpawnAsync(NULL,
85 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,
mukesh agrawalae30e9e2013-05-28 14:09:16 -070089 NULL,
90 &pid_,
91 NULL)) {
92 Error::PopulateAndLog(error, Error::kInternalError,
93 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
113void ExternalTask::GetLogin(string *user, string *password) {
114 return task_delegate_->GetLogin(user, password);
115}
116
117void ExternalTask::Notify(const string &event,
118 const map<string, string> &details) {
119 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 << ")";
125 ExternalTask *me = reinterpret_cast<ExternalTask *>(data);
126 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
133void ExternalTask::Destroy(ExternalTask *task) {
134 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