blob: 87d82532a8886750c715b7cb4d4642e3f7fa5ff6 [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}
38} // namespace {}
39
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070040uint32_t Subprocess::Exec(const std::vector<std::string>& cmd,
adlr@google.com3defe6a2009-12-04 20:57:17 +000041 ExecCallback callback,
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070042 void* p) {
adlr@google.com3defe6a2009-12-04 20:57:17 +000043 GPid child_pid;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070044 GError* err;
45 scoped_array<char*> argv(new char*[cmd.size() + 1]);
adlr@google.com3defe6a2009-12-04 20:57:17 +000046 for (unsigned int i = 0; i < cmd.size(); i++) {
47 argv[i] = strdup(cmd[i].c_str());
48 }
49 argv[cmd.size()] = NULL;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070050
51 scoped_array<char*> argp(new char*[2]);
52 argp[0] = argp[1] = NULL;
53 const char* kLdLibraryPathKey = "LD_LIBRARY_PATH";
54 if (getenv(kLdLibraryPathKey)) {
55 argp[0] = strdup(StringPrintf("%s=%s", kLdLibraryPathKey,
56 getenv(kLdLibraryPathKey)).c_str());
57 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000058
59 SubprocessCallbackRecord callback_record;
60 callback_record.callback = callback;
61 callback_record.callback_data = p;
62
63 bool success = g_spawn_async(NULL, // working directory
64 argv.get(),
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070065 argp.get(),
adlr@google.com3defe6a2009-12-04 20:57:17 +000066 G_SPAWN_DO_NOT_REAP_CHILD, // flags
67 NULL, // child setup function
68 NULL, // child setup data pointer
69 &child_pid,
70 &err);
71 FreeArgv(argv.get());
72 if (!success) {
73 LOG(ERROR) << "g_spawn_async failed";
74 return 0;
75 }
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070076 guint* tag = new guint;
adlr@google.com3defe6a2009-12-04 20:57:17 +000077 *tag = g_child_watch_add(child_pid, GChildExitedCallback, tag);
78 callback_records_[*tag] = callback_record;
79 return *tag;
80}
81
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070082void Subprocess::CancelExec(uint32_t tag) {
adlr@google.com3defe6a2009-12-04 20:57:17 +000083 if (callback_records_[tag].callback) {
84 callback_records_[tag].callback = NULL;
85 }
86}
87
88bool Subprocess::SynchronousExec(const std::vector<std::string>& cmd,
89 int* return_code) {
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070090 GError* err = NULL;
91 scoped_array<char*> argv(new char*[cmd.size() + 1]);
adlr@google.com3defe6a2009-12-04 20:57:17 +000092 for (unsigned int i = 0; i < cmd.size(); i++) {
93 argv[i] = strdup(cmd[i].c_str());
94 }
95 argv[cmd.size()] = NULL;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070096 char* argp[1];
adlr@google.com3defe6a2009-12-04 20:57:17 +000097 argp[0] = NULL;
98
99 bool success = g_spawn_sync(NULL, // working directory
100 argv.get(),
101 argp,
102 static_cast<GSpawnFlags>(NULL), // flags
103 NULL, // child setup function
104 NULL, // data for child setup function
105 NULL, // return location for stdout
106 NULL, // return location for stderr
107 return_code,
108 &err);
109 FreeArgv(argv.get());
Andrew de los Reyesb10320d2010-03-31 16:44:44 -0700110 if (err)
111 LOG(INFO) << "err is: " << err->code << ", " << err->message;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000112 return success;
113}
114
115Subprocess* Subprocess::subprocess_singleton_ = NULL;
116
117} // namespace chromeos_update_engine