Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/wapython
Path: blob/main/core/posix-node/src/unistd.zig
1067 views
1
const c = @import("c.zig");
2
const node = @import("node.zig");
3
const unistd = @cImport({
4
@cInclude("unistd.h");
5
@cInclude("fcntl.h");
6
@cInclude("grp.h"); // getgrouplist on linux
7
});
8
const builtin = @import("builtin");
9
const util = @import("util.zig");
10
const std = @import("std");
11
12
const BUF_SIZE = 4 * 1024;
13
var BUFFER: [BUF_SIZE]u8 = undefined;
14
15
pub fn register(env: c.napi_env, exports: c.napi_value) !void {
16
try node.registerFunction(env, exports, "chroot", chroot);
17
try node.registerFunction(env, exports, "getegid", getegid);
18
try node.registerFunction(env, exports, "geteuid", geteuid);
19
try node.registerFunction(env, exports, "gethostname", gethostname);
20
try node.registerFunction(env, exports, "getpgid", getpgid);
21
try node.registerFunction(env, exports, "getppid", getppid);
22
try node.registerFunction(env, exports, "getpgrp", getpgrp);
23
try node.registerFunction(env, exports, "setpgid", setpgid);
24
try node.registerFunction(env, exports, "setegid", setegid);
25
try node.registerFunction(env, exports, "seteuid", seteuid);
26
try node.registerFunction(env, exports, "sethostname", sethostname);
27
try node.registerFunction(env, exports, "setregid", setregid);
28
try node.registerFunction(env, exports, "setreuid", setreuid);
29
try node.registerFunction(env, exports, "setsid", setsid);
30
try node.registerFunction(env, exports, "ttyname", ttyname);
31
try node.registerFunction(env, exports, "alarm", alarm);
32
try node.registerFunction(env, exports, "sleep", sleep);
33
try node.registerFunction(env, exports, "usleep", usleep);
34
35
try node.registerFunction(env, exports, "execv", execv);
36
try node.registerFunction(env, exports, "execvp", execvp);
37
try node.registerFunction(env, exports, "_execve", execve);
38
try node.registerFunction(env, exports, "_fexecve", fexecve);
39
40
try node.registerFunction(env, exports, "fork", fork);
41
try node.registerFunction(env, exports, "close_event_loop", close_event_loop);
42
try node.registerFunction(env, exports, "pipe", pipe);
43
if (builtin.target.os.tag == .linux) {
44
try node.registerFunction(env, exports, "pipe2", pipe2_impl);
45
}
46
47
try node.registerFunction(env, exports, "lockf", lockf);
48
try node.registerFunction(env, exports, "pause", pause);
49
try node.registerFunction(env, exports, "getgrouplist", getgrouplist);
50
51
try node.registerFunction(env, exports, "dup", dup);
52
try node.registerFunction(env, exports, "dup2", dup2);
53
54
try node.registerFunction(env, exports, "chdir", chdir);
55
try node.registerFunction(env, exports, "getcwd", getcwd);
56
}
57
58
pub const constants = .{
59
.c_import = unistd,
60
.names = [_][:0]const u8{ "O_CLOEXEC", "O_NONBLOCK", "O_APPEND", "O_ASYNC", "F_ULOCK", "F_LOCK", "F_TLOCK", "F_TEST" },
61
};
62
63
// int chroot(const char *path);
64
fn chroot(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
65
const argv = node.getArgv(env, info, 1) catch return null;
66
node.stringFromValue(env, argv[0], "path", BUF_SIZE, &BUFFER) catch return null;
67
if (unistd.chroot(&BUFFER) == -1) {
68
node.throwErrno(env, "chroot failed");
69
}
70
return null;
71
}
72
73
// uid_t getegid(void);
74
fn getegid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
75
_ = info;
76
const pid = unistd.getegid();
77
return node.create_u32(env, pid, "pid") catch return null;
78
}
79
80
// uid_t geteuid(void);
81
fn geteuid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
82
_ = info;
83
const pid = unistd.geteuid();
84
return node.create_u32(env, pid, "pid") catch return null;
85
}
86
87
// int gethostname(char *name, size_t namelen);
88
fn gethostname(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
89
_ = info;
90
if (unistd.gethostname(&BUFFER, BUF_SIZE) == -1) {
91
node.throwErrno(env, "error in gethostname");
92
return null;
93
}
94
// cast because we know name is null terminated.
95
return node.createStringFromPtr(env, @ptrCast([*:0]const u8, &BUFFER), "hostname") catch return null;
96
}
97
98
// pid_t getpgid(pid_t pid);
99
fn getpgid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
100
const argv = node.getArgv(env, info, 1) catch return null;
101
const pid = node.i32FromValue(env, argv[0], "pid") catch return null;
102
const pgid = unistd.getpgid(pid);
103
if (pgid == -1) {
104
node.throwErrno(env, "error in getpgid");
105
return null;
106
}
107
return node.create_i32(env, pgid, "pgid") catch return null;
108
}
109
110
// pid_t getpgrp(void);
111
fn getpgrp(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
112
_ = info;
113
const pid = unistd.getppid();
114
return node.create_i32(env, pid, "pid") catch return null;
115
}
116
117
// pid_t getppid(void);
118
fn getppid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
119
_ = info;
120
const pid = unistd.getppid();
121
return node.create_i32(env, pid, "pid") catch return null;
122
}
123
124
// int setegid(gid_t gid);
125
fn setegid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
126
const argv = node.getArgv(env, info, 1) catch return null;
127
const gid = node.u32FromValue(env, argv[0], "gid") catch return null;
128
if (unistd.setegid(gid) == -1) {
129
node.throwErrno(env, "error in setegid");
130
}
131
return null;
132
}
133
134
// int seteuid(uid_t uid);
135
fn seteuid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
136
const argv = node.getArgv(env, info, 1) catch return null;
137
const uid = node.u32FromValue(env, argv[0], "uid") catch return null;
138
if (unistd.seteuid(uid) == -1) {
139
node.throwErrno(env, "error in seteuid");
140
}
141
return null;
142
}
143
144
// int sethostname(const char *name, size_t len);
145
fn sethostname(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
146
const argv = node.getArgv(env, info, 1) catch return null;
147
node.stringFromValue(env, argv[0], "name", BUF_SIZE, &BUFFER) catch return null;
148
const len = node.strlen(@ptrCast([*:0]const u8, &BUFFER));
149
// Interestingly the type of second argument sethostname depends on the operating system.
150
if (builtin.target.os.tag == .linux) {
151
if (unistd.sethostname(&BUFFER, len) == -1) {
152
node.throwErrno(env, "error setting host name");
153
}
154
} else {
155
if (unistd.sethostname(&BUFFER, @intCast(c_int, len)) == -1) {
156
node.throwErrno(env, "error setting host name");
157
}
158
}
159
return null;
160
}
161
162
// int setpgid(pid_t pid, pid_t pgid);
163
fn setpgid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
164
const argv = node.getArgv(env, info, 2) catch return null;
165
const pid = node.i32FromValue(env, argv[0], "pid") catch return null;
166
const pgid = node.i32FromValue(env, argv[1], "pgid") catch return null;
167
if (unistd.setpgid(pid, pgid) == -1) {
168
node.throwErrno(env, "error in setpgid");
169
}
170
return null;
171
}
172
173
// int setregid(gid_t rgid, gid_t egid);
174
fn setregid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
175
const argv = node.getArgv(env, info, 2) catch return null;
176
const rgid = node.u32FromValue(env, argv[0], "rgid") catch return null;
177
const egid = node.u32FromValue(env, argv[1], "egid") catch return null;
178
if (unistd.setregid(rgid, egid) == -1) {
179
node.throwErrno(env, "error in setregid");
180
}
181
return null;
182
}
183
184
// int setreuid(uid_t ruid, uid_t euid);
185
fn setreuid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
186
const argv = node.getArgv(env, info, 2) catch return null;
187
const ruid = node.u32FromValue(env, argv[0], "ruid") catch return null;
188
const euid = node.u32FromValue(env, argv[1], "euid") catch return null;
189
if (unistd.setreuid(ruid, euid) == -1) {
190
node.throwErrno(env, "error in setreuid");
191
}
192
return null;
193
}
194
195
// pid_t setsid(void);
196
fn setsid(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
197
_ = info;
198
const pid = unistd.setsid();
199
if (pid == -1) {
200
node.throwErrno(env, "error in setsid");
201
return null;
202
}
203
return node.create_i32(env, pid, "pid") catch return null;
204
}
205
206
// char *ttyname(int fd);
207
fn ttyname(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
208
const argv = node.getArgv(env, info, 1) catch return null;
209
const fd = node.i32FromValue(env, argv[0], "fd") catch return null;
210
const name = unistd.ttyname(fd);
211
if (name == null) {
212
node.throwErrno(env, "invalid file descriptor");
213
return null;
214
}
215
return node.createStringFromPtr(env, name, "ttyname") catch return null;
216
}
217
218
// unsigned alarm(unsigned seconds);
219
fn alarm(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
220
const argv = node.getArgv(env, info, 1) catch return null;
221
const seconds = node.u32FromValue(env, argv[0], "seconds") catch return null;
222
const ret = unistd.alarm(seconds); // doesn't return any error no matter what.
223
return node.create_u32(env, ret, "ret") catch return null;
224
}
225
226
// unsigned sleep(unsigned seconds);
227
fn sleep(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
228
const argv = node.getArgv(env, info, 1) catch return null;
229
const seconds = node.u32FromValue(env, argv[0], "seconds") catch return null;
230
const ret = unistd.sleep(seconds); // return value involves how much time left if returned early due to a signal.
231
return node.create_u32(env, ret, "ret") catch return null;
232
}
233
234
// int usleep(unsigned microseconds);
235
fn usleep(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
236
const argv = node.getArgv(env, info, 1) catch return null;
237
const microseconds = node.u32FromValue(env, argv[0], "microseconds") catch return null;
238
const ret = unistd.usleep(microseconds);
239
return node.create_i32(env, ret, "ret") catch return null;
240
}
241
242
const UnistdError = error{ Dup2Fail, FcntlFail, CloseStream };
243
fn dupStream(env: c.napi_env, comptime name: [:0]const u8, number: i32) !void {
244
const stream = try node.getStreamFd(env, name);
245
if (unistd.dup2(stream, number) == -1) {
246
node.throwError(env, "dup2 failed on " ++ name);
247
return UnistdError.Dup2Fail;
248
}
249
if (unistd.close(stream) == -1) {
250
node.throwError(env, "closing fd failed " ++ name);
251
return UnistdError.Dup2Fail;
252
}
253
}
254
255
fn dupStreams(env: c.napi_env) !void {
256
try dupStream(env, "stdin", 0);
257
try dupStream(env, "stdout", 1);
258
try dupStream(env, "stderr", 2);
259
}
260
261
fn closeStream(env: c.napi_env, comptime name: [:0]const u8) !void {
262
const stream = try node.getStreamFd(env, name);
263
if (unistd.close(stream) == -1) {
264
node.throwError(env, "closing stream failed " ++ name);
265
return UnistdError.CloseStream;
266
}
267
}
268
269
fn makeNonblocking(env: c.napi_env, desc: c_int) !c_int {
270
// make nonblocking
271
var flags = unistd.fcntl(desc, unistd.F_GETFL, @intCast(c_int, 0));
272
flags |= unistd.O_NONBLOCK;
273
var status = unistd.fcntl(desc, unistd.F_SETFL, flags);
274
if (status == -1) {
275
node.throwError(env, "O_NONBLOCK failed");
276
return UnistdError.FcntlFail;
277
}
278
return status;
279
}
280
281
fn clearCLOEXEC(env: c.napi_env, desc: c_int) !c_int {
282
var flags = unistd.fcntl(desc, unistd.F_GETFD, @intCast(c_int, 0));
283
if (flags < 0) {
284
return flags; // return if reading failed
285
}
286
flags &= ~unistd.FD_CLOEXEC; // clear FD_CLOEXEC bit
287
var status = unistd.fcntl(desc, unistd.F_SETFD, flags);
288
if (status == -1) {
289
node.throwError(env, "clearCLOEXEC failed");
290
return UnistdError.FcntlFail;
291
}
292
293
return status;
294
}
295
296
fn execv(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
297
const args = node.getArgv(env, info, 2) catch return null;
298
299
var pathname = node.valueToString(env, args[0], "pathname") catch return null;
300
defer std.c.free(pathname);
301
302
var argv = node.valueToArrayOfStrings(env, args[1], "argv") catch return null;
303
defer util.freeArrayOfStrings(argv);
304
305
// The projects linked from https://github.com/nodejs/node/issues/21664 do
306
// the following. It seems like node currently only sets FD_CLOEXEC for
307
// stderr (not stdin or stdout), but we unset the flag for all just
308
// in case. We don't want these to all just get closed automatically
309
// the moment we fork since clients might not want that.
310
_ = clearCLOEXEC(env, 0) catch return null;
311
_ = clearCLOEXEC(env, 1) catch return null;
312
_ = clearCLOEXEC(env, 2) catch return null;
313
314
const ret = unistd.execv(pathname, argv);
315
if (ret == -1) {
316
node.throwErrno(env, "error in execv");
317
return null;
318
}
319
// This can't ever happen, of course.
320
return node.create_i32(env, ret, "ret") catch return null;
321
}
322
323
// int execvp(const char *file, char *const argv[]);
324
fn execvp(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
325
const args = node.getArgv(env, info, 2) catch return null;
326
327
var file = node.valueToString(env, args[0], "file") catch return null;
328
defer std.c.free(file);
329
330
var argv = node.valueToArrayOfStrings(env, args[1], "argv") catch return null;
331
defer util.freeArrayOfStrings(argv);
332
333
// The projects linked from https://github.com/nodejs/node/issues/21664 do
334
// the following. It seems like node currently only sets FD_CLOEXEC for
335
// stderr (not stdin or stdout), but we unset the flag for all just
336
// in case. We don't want these to all just get closed automatically
337
// the moment we fork since clients might not want that.
338
_ = clearCLOEXEC(env, 0) catch return null;
339
_ = clearCLOEXEC(env, 1) catch return null;
340
_ = clearCLOEXEC(env, 2) catch return null;
341
342
const ret = unistd.execvp(file, argv);
343
if (ret == -1) {
344
node.throwErrno(env, "error in execvp");
345
return null;
346
}
347
// This can't ever happen, of course.
348
return node.create_i32(env, ret, "ret") catch return null;
349
}
350
351
// int execve(const char *pathname, char *const argv[], char *const envp[]);
352
// execve: (pathname: string, argv: string[], envp: string[]) => number;
353
fn execve(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
354
const args = node.getArgv(env, info, 3) catch return null;
355
356
var pathname = node.valueToString(env, args[0], "pathname") catch return null;
357
defer std.c.free(pathname);
358
359
var argv = node.valueToArrayOfStrings(env, args[1], "argv") catch return null;
360
defer util.freeArrayOfStrings(argv);
361
362
var envp = node.valueToArrayOfStrings(env, args[2], "envp") catch return null;
363
defer util.freeArrayOfStrings(envp);
364
365
_ = clearCLOEXEC(env, 0) catch return null;
366
_ = clearCLOEXEC(env, 1) catch return null;
367
_ = clearCLOEXEC(env, 2) catch return null;
368
369
// NOTE: On success, execve() does not return (!), on error -1 is returned,
370
// and errno is set to indicate the error.
371
// **TODO: this is working but is very annoying because node isn't surrendering stdout/stdout/etc., so
372
// it silently appears to die.** But a simple example writing to a file shows this works.
373
const ret = unistd.execve(pathname, argv, envp);
374
if (ret == -1) {
375
node.throwErrno(env, "error in execve");
376
return null;
377
}
378
// This can't ever happen, of course.
379
return node.create_i32(env, ret, "ret") catch return null;
380
}
381
382
// int fexecve(int fd, char *const argv[], char *const envp[]);
383
fn fexecve(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
384
if (builtin.target.os.tag != .linux) {
385
node.throwError(env, "fexecve is only supported on linux");
386
return null;
387
}
388
389
const args = node.getArgv(env, info, 3) catch return null;
390
391
var fd = node.i32FromValue(env, args[0], "fd") catch return null;
392
393
var argv = node.valueToArrayOfStrings(env, args[1], "argv") catch return null;
394
defer util.freeArrayOfStrings(argv);
395
396
var envp = node.valueToArrayOfStrings(env, args[2], "envp") catch return null;
397
defer util.freeArrayOfStrings(envp);
398
399
// Critical to dup2 these are we'll see nothing after running execve:
400
// dupStreams(env) catch return null;
401
402
const ret = unistd.fexecve(fd, argv, envp);
403
if (ret == -1) {
404
node.throwErrno(env, "error in fexecve");
405
return null;
406
}
407
// This can't ever happen, of course.
408
return node.create_i32(env, ret, "ret") catch return null;
409
}
410
411
// pid_t fork(void);
412
fn fork(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
413
_ = info;
414
const pid = unistd.fork();
415
if (pid == -1) {
416
node.throwErrno(env, "error in fork");
417
return null;
418
}
419
return node.create_i32(env, pid, "pid") catch return null;
420
}
421
422
fn close_event_loop(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
423
_ = info;
424
node.closeEventLoop(env) catch return null;
425
return null;
426
}
427
428
// int pipe(int pipefd[2]);
429
fn pipe(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
430
_ = info;
431
var pipefd: [2]c_int = undefined;
432
if (unistd.pipe(&pipefd) == -1) {
433
node.throwErrno(env, "error in pipe");
434
}
435
return pipefdToObject(env, pipefd) catch return null;
436
}
437
438
// pipe2 is linux only
439
extern fn pipe2(pipefd: [*]c_int, flags: c_int) c_int;
440
fn pipe2_impl(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
441
if (builtin.target.os.tag != .linux) {
442
node.throwError(env, "pipe2 is only supported on linux");
443
return null;
444
}
445
const argv = node.getArgv(env, info, 1) catch return null;
446
const flags = node.i32FromValue(env, argv[0], "flags") catch return null;
447
var pipefd: [2]c_int = undefined;
448
if (pipe2(&pipefd, flags) == -1) {
449
node.throwErrno(env, "error in pipe2");
450
}
451
return pipefdToObject(env, pipefd) catch return null;
452
}
453
454
fn pipefdToObject(env: c.napi_env, pipefd: [2]c_int) !c.napi_value {
455
const obj = node.createObject(env, "pipefd") catch return null;
456
const readfd = node.create_i32(env, pipefd[0], "pipefd[0]") catch return null;
457
node.setNamedProperty(env, obj, "readfd", readfd, "setting readfd") catch return null;
458
const writefd = node.create_i32(env, pipefd[1], "pipefd[1]") catch return null;
459
node.setNamedProperty(env, obj, "writefd", writefd, "setting writefd") catch return null;
460
return obj;
461
}
462
463
// Record locking on files:
464
// int lockf(int fd, int cmd, off_t size);
465
// NOTE: off_t is i64 on wasi and macos.
466
// cmd is one of the constants F_ULOCK, F_LOCK, F_TLOCK, or F_TEST.
467
fn lockf(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
468
const argv = node.getArgv(env, info, 3) catch return null;
469
const fd = node.i32FromValue(env, argv[0], "fd") catch return null;
470
const cmd = node.i32FromValue(env, argv[1], "cmd") catch return null;
471
const size = node.i64FromBigIntValue(env, argv[2], "size") catch return null;
472
if (unistd.lockf(fd, cmd, size) == -1) {
473
node.throwErrno(env, "error in lockf");
474
}
475
return null;
476
}
477
478
// int pause(void);
479
fn pause(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
480
_ = info;
481
const res = unistd.pause(); // this actually always returns -1, according to docs
482
return node.create_i32(env, res, "res") catch return null;
483
}
484
485
// int getgrouplist(const char *user, gid_t group,
486
// gid_t *groups, int *ngroups);
487
fn getgrouplist(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
488
const argv = node.getArgv(env, info, 2) catch return null;
489
node.stringFromValue(env, argv[0], "user", BUF_SIZE, &BUFFER) catch return null;
490
const group =
491
if (builtin.target.os.tag == .linux)
492
node.u32FromValue(env, argv[1], "group") catch return null
493
else
494
node.i32FromValue(env, argv[1], "group") catch return null;
495
496
var ngroups: c_int = 50;
497
const ptr0 = std.c.malloc(@sizeOf(c_int) * @intCast(usize, ngroups)) orelse {
498
node.throwError(env, "error allocating memory");
499
return null;
500
};
501
defer std.c.free(ptr0);
502
var groups = if (builtin.target.os.tag == .linux)
503
@ptrCast([*]c_uint, @alignCast(std.meta.alignment([*]c_uint), ptr0))
504
else
505
@ptrCast([*]c_int, @alignCast(std.meta.alignment([*]c_int), ptr0));
506
507
const r = unistd.getgrouplist(@ptrCast([*:0]u8, &BUFFER), group, groups, &ngroups);
508
if (r == -1) {
509
const ptr = std.c.malloc(@sizeOf(c_int) * @intCast(usize, ngroups)) orelse {
510
node.throwError(env, "error allocating memory");
511
return null;
512
};
513
defer std.c.free(ptr);
514
groups = if (builtin.target.os.tag == .linux)
515
@ptrCast([*]c_uint, @alignCast(std.meta.alignment([*]c_uint), ptr))
516
else
517
@ptrCast([*]c_int, @alignCast(std.meta.alignment([*]c_int), ptr));
518
519
if (unistd.getgrouplist(@ptrCast([*:0]u8, &BUFFER), group, groups, &ngroups) == -1) {
520
node.throwErrno(env, "failed to get group list");
521
return null;
522
}
523
}
524
const array = node.createArray(env, @intCast(u32, ngroups), "getgrouplist output array") catch return null;
525
var i: u32 = 0;
526
while (i < ngroups) : (i += 1) {
527
const gid = if (builtin.target.os.tag == .linux)
528
node.create_u32(env, groups[i], "ith group") catch return null
529
else
530
node.create_i32(env, groups[i], "ith group") catch return null;
531
532
node.setElement(env, array, i, gid, "setting ith group") catch return null;
533
}
534
return array;
535
}
536
537
// int dup(int oldfd);
538
fn dup(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
539
const argv = node.getArgv(env, info, 1) catch return null;
540
const oldfd = node.i32FromValue(env, argv[0], "oldfd") catch return null;
541
const newfd = unistd.dup(oldfd);
542
if (newfd == -1) {
543
node.throwErrno(env, "error in dup");
544
return null;
545
}
546
return node.create_i32(env, newfd, "newfd") catch return null;
547
}
548
549
// int dup2(int oldfd, int newfd);
550
fn dup2(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
551
const argv = node.getArgv(env, info, 2) catch return null;
552
const oldfd = node.i32FromValue(env, argv[0], "oldfd") catch return null;
553
const newfd = node.i32FromValue(env, argv[1], "newfd") catch return null;
554
const ret = unistd.dup2(oldfd, newfd);
555
if (ret == -1) {
556
node.throwErrno(env, "error in dup2");
557
return null;
558
}
559
return node.create_i32(env, ret, "ret") catch return null;
560
}
561
562
// We implement this since node.js doesn't let workers chdir, but
563
// we absolutely need to chdir. Also, this is the actual working directory
564
// at the C level, which is different than process.cwd().
565
// int chdir(const char *path);
566
fn chdir(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
567
const argv = node.getArgv(env, info, 1) catch return null;
568
node.stringFromValue(env, argv[0], "path", BUF_SIZE, &BUFFER) catch return null;
569
if (unistd.chdir(&BUFFER) == -1) {
570
node.throwErrno(env, "chdir failed");
571
}
572
return null;
573
}
574
575
// char* getcwd(char* buf, size_t size);
576
fn getcwd(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
577
_ = info;
578
if (unistd.getcwd(&BUFFER, BUF_SIZE) == null) {
579
node.throwErrno(env, "unable to get current working directory");
580
return null;
581
}
582
return node.createStringFromPtr(env, @ptrCast([*:0]const u8, &BUFFER), "cwd") catch return null;
583
}
584
585