blob: 696779f6473e659cee53c6055cf3ae7dbdfdceca [file] [log] [blame]
adlr@google.com3defe6a2009-12-04 20:57:17 +00001// Copyright (c) 2009 The Chromium 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 "update_engine/subprocess.h"
6#include <stdlib.h>
7#include <string.h>
8#include <string>
9#include <vector>
10#include "chromeos/obsolete_logging.h"
11#include "base/scoped_ptr.h"
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070012#include "base/string_util.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000013
14using std::string;
15using std::vector;
16
17namespace chromeos_update_engine {
18
19void Subprocess::GChildExitedCallback(GPid pid, gint status, gpointer data) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070020 COMPILE_ASSERT(sizeof(guint) == sizeof(uint32_t),
adlr@google.com3defe6a2009-12-04 20:57:17 +000021 guint_uint32_size_mismatch);
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070022 guint* tag = reinterpret_cast<guint*>(data);
adlr@google.com3defe6a2009-12-04 20:57:17 +000023 const SubprocessCallbackRecord& record = Get().callback_records_[*tag];
24 if (record.callback)
25 record.callback(status, record.callback_data);
26 g_spawn_close_pid(pid);
27 Get().callback_records_.erase(*tag);
28 delete tag;
29}
30
31namespace {
32void FreeArgv(char** argv) {
33 for (int i = 0; argv[i]; i++) {
34 free(argv[i]);
35 argv[i] = NULL;
36 }
37}
Andrew de los Reyes3270f742010-07-15 22:28:14 -070038
39// Note: Caller responsible for free()ing the returned value!
40char** ArgPointer() {
41 const char* keys[] = {"LD_LIBRARY_PATH", "PATH"};
42 char** ret = new char*[arraysize(keys) + 1];
43 int pointer = 0;
44 for (size_t i = 0; i < arraysize(keys); i++) {
45 ret[i] = NULL;
46 if (getenv(keys[i])) {
47 ret[pointer] = strdup(StringPrintf("%s=%s", keys[i],
48 getenv(keys[i])).c_str());
49 pointer++;
50 }
51 }
52 return ret;
53}
54
55class ScopedFreeArgPointer {
56 public:
57 ScopedFreeArgPointer(char** arr) : arr_(arr) {}
58 ~ScopedFreeArgPointer() {
59 if (!arr_)
60 return;
61 for (int i = 0; arr_[i]; i++)
62 free(arr_[i]);
63 delete[] arr_;
64 }
65 private:
66 char** arr_;
67 DISALLOW_COPY_AND_ASSIGN(ScopedFreeArgPointer);
68};
adlr@google.com3defe6a2009-12-04 20:57:17 +000069} // namespace {}
70
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070071uint32_t Subprocess::Exec(const std::vector<std::string>& cmd,
Andrew de los Reyes3270f742010-07-15 22:28:14 -070072 ExecCallback callback,
73 void* p) {
adlr@google.com3defe6a2009-12-04 20:57:17 +000074 GPid child_pid;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070075 GError* err;
76 scoped_array<char*> argv(new char*[cmd.size() + 1]);
adlr@google.com3defe6a2009-12-04 20:57:17 +000077 for (unsigned int i = 0; i < cmd.size(); i++) {
78 argv[i] = strdup(cmd[i].c_str());
79 }
80 argv[cmd.size()] = NULL;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070081
Andrew de los Reyes3270f742010-07-15 22:28:14 -070082 char** argp = ArgPointer();
83 ScopedFreeArgPointer argp_free(argp);
adlr@google.com3defe6a2009-12-04 20:57:17 +000084
85 SubprocessCallbackRecord callback_record;
86 callback_record.callback = callback;
87 callback_record.callback_data = p;
88
89 bool success = g_spawn_async(NULL, // working directory
90 argv.get(),
Andrew de los Reyes3270f742010-07-15 22:28:14 -070091 argp,
adlr@google.com3defe6a2009-12-04 20:57:17 +000092 G_SPAWN_DO_NOT_REAP_CHILD, // flags
93 NULL, // child setup function
94 NULL, // child setup data pointer
95 &child_pid,
96 &err);
97 FreeArgv(argv.get());
98 if (!success) {
99 LOG(ERROR) << "g_spawn_async failed";
100 return 0;
101 }
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700102 guint* tag = new guint;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000103 *tag = g_child_watch_add(child_pid, GChildExitedCallback, tag);
104 callback_records_[*tag] = callback_record;
105 return *tag;
106}
107
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700108void Subprocess::CancelExec(uint32_t tag) {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000109 if (callback_records_[tag].callback) {
110 callback_records_[tag].callback = NULL;
111 }
112}
113
114bool Subprocess::SynchronousExec(const std::vector<std::string>& cmd,
115 int* return_code) {
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700116 GError* err = NULL;
117 scoped_array<char*> argv(new char*[cmd.size() + 1]);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000118 for (unsigned int i = 0; i < cmd.size(); i++) {
119 argv[i] = strdup(cmd[i].c_str());
120 }
121 argv[cmd.size()] = NULL;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700122
123 char** argp = ArgPointer();
124 ScopedFreeArgPointer argp_free(argp);
125
126 char* child_stdout;
127 char* child_stderr;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000128
129 bool success = g_spawn_sync(NULL, // working directory
130 argv.get(),
131 argp,
132 static_cast<GSpawnFlags>(NULL), // flags
133 NULL, // child setup function
134 NULL, // data for child setup function
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700135 &child_stdout,
136 &child_stderr,
adlr@google.com3defe6a2009-12-04 20:57:17 +0000137 return_code,
138 &err);
139 FreeArgv(argv.get());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700140 if (err)
141 LOG(INFO) << "err is: " << err->code << ", " << err->message;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700142 if (child_stdout)
143 LOG(INFO) << "Postinst stdout:" << child_stdout;
144 if (child_stderr)
145 LOG(INFO) << "Postinst stderr:" << child_stderr;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000146 return success;
147}
148
149Subprocess* Subprocess::subprocess_singleton_ = NULL;
150
151} // namespace chromeos_update_engine