The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / src / process_wrap.cc @ 31c510ca

History | View | Annotate | Download (10.2 KB)

1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21

    
22
#include "node.h"
23
#include "handle_wrap.h"
24
#include "pipe_wrap.h"
25
#include "tty_wrap.h"
26
#include "tcp_wrap.h"
27
#include "udp_wrap.h"
28

    
29
#include <string.h>
30
#include <stdlib.h>
31

    
32
namespace node {
33

    
34
using v8::Object;
35
using v8::Handle;
36
using v8::Local;
37
using v8::Persistent;
38
using v8::Value;
39
using v8::HandleScope;
40
using v8::FunctionTemplate;
41
using v8::String;
42
using v8::Array;
43
using v8::Number;
44
using v8::Function;
45
using v8::TryCatch;
46
using v8::Context;
47
using v8::Arguments;
48
using v8::Integer;
49
using v8::Exception;
50
using v8::ThrowException;
51

    
52
static Persistent<String> onexit_sym;
53

    
54
class ProcessWrap : public HandleWrap {
55
 public:
56
  static void Initialize(Handle<Object> target) {
57
    HandleScope scope;
58

    
59
    HandleWrap::Initialize(target);
60

    
61
    Local<FunctionTemplate> constructor = FunctionTemplate::New(New);
62
    constructor->InstanceTemplate()->SetInternalFieldCount(1);
63
    constructor->SetClassName(String::NewSymbol("Process"));
64

    
65
    NODE_SET_PROTOTYPE_METHOD(constructor, "close", HandleWrap::Close);
66

    
67
    NODE_SET_PROTOTYPE_METHOD(constructor, "spawn", Spawn);
68
    NODE_SET_PROTOTYPE_METHOD(constructor, "kill", Kill);
69

    
70
    NODE_SET_PROTOTYPE_METHOD(constructor, "ref", HandleWrap::Ref);
71
    NODE_SET_PROTOTYPE_METHOD(constructor, "unref", HandleWrap::Unref);
72

    
73
    target->Set(String::NewSymbol("Process"), constructor->GetFunction());
74
  }
75

    
76
 private:
77
  static Handle<Value> New(const Arguments& args) {
78
    // This constructor should not be exposed to public javascript.
79
    // Therefore we assert that we are not trying to call this as a
80
    // normal function.
81
    assert(args.IsConstructCall());
82

    
83
    HandleScope scope;
84
    ProcessWrap *wrap = new ProcessWrap(args.This());
85
    assert(wrap);
86

    
87
    return scope.Close(args.This());
88
  }
89

    
90
  ProcessWrap(Handle<Object> object) : HandleWrap(object, NULL) { }
91
  ~ProcessWrap() { }
92

    
93
  static void ParseStdioOptions(Local<Object> js_options,
94
                                uv_process_options_t* options) {
95
    Local<Array> stdios = js_options
96
        ->Get(String::NewSymbol("stdio")).As<Array>();
97
    int len = stdios->Length();
98
    options->stdio = new uv_stdio_container_t[len];
99
    options->stdio_count = len;
100

    
101
    for (int i = 0; i < len; i++) {
102
      Local<Object> stdio = stdios
103
          ->Get(Number::New(static_cast<double>(i))).As<Object>();
104
      Local<Value> type = stdio->Get(String::NewSymbol("type"));
105

    
106
      if (type->Equals(String::NewSymbol("ignore"))) {
107
        options->stdio[i].flags = UV_IGNORE;
108
      } else if (type->Equals(String::NewSymbol("pipe"))) {
109
        options->stdio[i].flags = static_cast<uv_stdio_flags>(
110
            UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE);
111
        options->stdio[i].data.stream = reinterpret_cast<uv_stream_t*>(
112
            PipeWrap::Unwrap(stdio
113
                ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle());
114
      } else if (type->Equals(String::NewSymbol("wrap"))) {
115
        uv_stream_t* stream = NULL;
116
        Local<Value> wrapType = stdio->Get(String::NewSymbol("wrapType"));
117
        if (wrapType->Equals(String::NewSymbol("pipe"))) {
118
          stream = reinterpret_cast<uv_stream_t*>(PipeWrap::Unwrap(stdio
119
              ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle());
120
        } else if (wrapType->Equals(String::NewSymbol("tty"))) {
121
          stream = reinterpret_cast<uv_stream_t*>(TTYWrap::Unwrap(stdio
122
              ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle());
123
        } else if (wrapType->Equals(String::NewSymbol("tcp"))) {
124
          stream = reinterpret_cast<uv_stream_t*>(TCPWrap::Unwrap(stdio
125
              ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle());
126
        } else if (wrapType->Equals(String::NewSymbol("udp"))) {
127
          stream = reinterpret_cast<uv_stream_t*>(UDPWrap::Unwrap(stdio
128
              ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle());
129
        }
130
        assert(stream != NULL);
131

    
132
        options->stdio[i].flags = UV_INHERIT_STREAM;
133
        options->stdio[i].data.stream = stream;
134
      } else {
135
        int fd = static_cast<int>(
136
            stdio->Get(String::NewSymbol("fd"))->IntegerValue());
137

    
138
        options->stdio[i].flags = UV_INHERIT_FD;
139
        options->stdio[i].data.fd = fd;
140
      }
141
    }
142
  }
143

    
144
  static Handle<Value> Spawn(const Arguments& args) {
145
    HandleScope scope;
146

    
147
    UNWRAP(ProcessWrap)
148

    
149
    Local<Object> js_options = args[0]->ToObject();
150

    
151
    uv_process_options_t options;
152
    memset(&options, 0, sizeof(uv_process_options_t));
153

    
154
    options.exit_cb = OnExit;
155

    
156
    // options.uid
157
    Local<Value> uid_v = js_options->Get(String::NewSymbol("uid"));
158
    if (uid_v->IsInt32()) {
159
      int32_t uid = uid_v->Int32Value();
160
      if (uid & ~((uv_uid_t) ~0)) {
161
        return ThrowException(Exception::RangeError(
162
            String::New("options.uid is out of range")));
163
      }
164
      options.flags |= UV_PROCESS_SETUID;
165
      options.uid = (uv_uid_t) uid;
166
    } else if (!uid_v->IsUndefined() && !uid_v->IsNull()) {
167
      return ThrowException(Exception::TypeError(
168
          String::New("options.uid should be a number")));
169
    }
170

    
171
    // options.gid
172
    Local<Value> gid_v = js_options->Get(String::NewSymbol("gid"));
173
    if (gid_v->IsInt32()) {
174
      int32_t gid = gid_v->Int32Value();
175
      if (gid & ~((uv_gid_t) ~0)) {
176
        return ThrowException(Exception::RangeError(
177
           String::New("options.gid is out of range")));
178
      }
179
      options.flags |= UV_PROCESS_SETGID;
180
      options.gid = (uv_gid_t) gid;
181
    } else if (!gid_v->IsUndefined() && !gid_v->IsNull()) {
182
      return ThrowException(Exception::TypeError(
183
          String::New("options.gid should be a number")));
184
    }
185

    
186
    // TODO is this possible to do without mallocing ?
187

    
188
    // options.file
189
    Local<Value> file_v = js_options->Get(String::NewSymbol("file"));
190
    String::Utf8Value file(file_v->IsString() ? file_v : Local<Value>());
191
    if (file.length() > 0) {
192
      options.file = *file;
193
    } else {
194
      return ThrowException(Exception::TypeError(String::New("Bad argument")));
195
    }
196

    
197
    // options.args
198
    Local<Value> argv_v = js_options->Get(String::NewSymbol("args"));
199
    if (!argv_v.IsEmpty() && argv_v->IsArray()) {
200
      Local<Array> js_argv = Local<Array>::Cast(argv_v);
201
      int argc = js_argv->Length();
202
      // Heap allocate to detect errors. +1 is for NULL.
203
      options.args = new char*[argc + 1];
204
      for (int i = 0; i < argc; i++) {
205
        String::Utf8Value arg(js_argv->Get(i));
206
        options.args[i] = strdup(*arg);
207
      }
208
      options.args[argc] = NULL;
209
    }
210

    
211
    // options.cwd
212
    Local<Value> cwd_v = js_options->Get(String::NewSymbol("cwd"));
213
    String::Utf8Value cwd(cwd_v->IsString() ? cwd_v : Local<Value>());
214
    if (cwd.length() > 0) {
215
      options.cwd = *cwd;
216
    }
217

    
218
    // options.env
219
    Local<Value> env_v = js_options->Get(String::NewSymbol("envPairs"));
220
    if (!env_v.IsEmpty() && env_v->IsArray()) {
221
      Local<Array> env = Local<Array>::Cast(env_v);
222
      int envc = env->Length();
223
      options.env = new char*[envc + 1]; // Heap allocated to detect errors.
224
      for (int i = 0; i < envc; i++) {
225
        String::Utf8Value pair(env->Get(i));
226
        options.env[i] = strdup(*pair);
227
      }
228
      options.env[envc] = NULL;
229
    }
230

    
231
    // options.stdio
232
    ParseStdioOptions(js_options, &options);
233

    
234
    // options.windows_verbatim_arguments
235
    if (js_options->Get(String::NewSymbol("windowsVerbatimArguments"))->
236
          IsTrue()) {
237
      options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
238
    }
239

    
240
    //options.detached
241
    if (js_options->Get(String::NewSymbol("detached"))->IsTrue()) {
242
      options.flags |= UV_PROCESS_DETACHED;
243
    }
244

    
245
    int r = uv_spawn(uv_default_loop(), &wrap->process_, options);
246

    
247
    if (r) {
248
      SetErrno(uv_last_error(uv_default_loop()));
249
    }
250
    else {
251
      wrap->SetHandle((uv_handle_t*)&wrap->process_);
252
      assert(wrap->process_.data == wrap);
253
      wrap->object_->Set(String::New("pid"),
254
                         Integer::New(wrap->process_.pid));
255
    }
256

    
257
    if (options.args) {
258
      for (int i = 0; options.args[i]; i++) free(options.args[i]);
259
      delete [] options.args;
260
    }
261

    
262
    if (options.env) {
263
      for (int i = 0; options.env[i]; i++) free(options.env[i]);
264
      delete [] options.env;
265
    }
266

    
267
    delete[] options.stdio;
268

    
269
    return scope.Close(Integer::New(r));
270
  }
271

    
272
  static Handle<Value> Kill(const Arguments& args) {
273
    HandleScope scope;
274

    
275
    UNWRAP(ProcessWrap)
276

    
277
    int signal = args[0]->Int32Value();
278

    
279
    int r = uv_process_kill(&wrap->process_, signal);
280

    
281
    if (r) SetErrno(uv_last_error(uv_default_loop()));
282

    
283
    return scope.Close(Integer::New(r));
284
  }
285

    
286
  static void OnExit(uv_process_t* handle, int exit_status, int term_signal) {
287
    HandleScope scope;
288

    
289
    ProcessWrap* wrap = static_cast<ProcessWrap*>(handle->data);
290
    assert(wrap);
291
    assert(&wrap->process_ == handle);
292

    
293
    Local<Value> argv[2] = {
294
      Integer::New(exit_status),
295
      String::New(signo_string(term_signal))
296
    };
297

    
298
    if (exit_status == -1) {
299
      SetErrno(uv_last_error(uv_default_loop()));
300
    }
301

    
302
    if (onexit_sym.IsEmpty()) {
303
      onexit_sym = NODE_PSYMBOL("onexit");
304
    }
305

    
306
    MakeCallback(wrap->object_, onexit_sym, ARRAY_SIZE(argv), argv);
307
  }
308

    
309
  uv_process_t process_;
310
};
311

    
312

    
313
}  // namespace node
314

    
315
NODE_MODULE(node_process_wrap, node::ProcessWrap::Initialize)