| author | |
| committer | |
| log | cba4a9ad4a149766c650e3f3d71435cef14867a3 |
| tree | 2edcb1357482a548ae821109519118b51b1e5a0e |
| parent | 79400bfdfd1e90cf3a4d09f32de965b13796a44d |
* add std.os.ChildProcess.setUserName
* add std.os.getUserId10 files changed, 325 insertions(+), 150 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -548,6 +548,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}") |
| 548 | 548 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/child_process.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 549 | 549 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 550 | 550 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin_errno.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 551 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/get_user_id.zig" DESTINATION "${ZIG_STD_DEST}/os") | |
| 551 | 552 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/index.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 552 | 553 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 553 | 554 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_errno.zig" DESTINATION "${ZIG_STD_DEST}/os") |
example/mix_o_files/build.zig+1-1| ... | ... | @@ -12,7 +12,7 @@ pub fn build(b: &Builder) { |
| 12 | 12 | |
| 13 | 13 | b.default_step.dependOn(&exe.step); |
| 14 | 14 | |
| 15 | const run_cmd = b.addCommand(".", b.env_map, exe.getOutputPath(), [][]const u8{}); | |
| 15 | const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()}); | |
| 16 | 16 | run_cmd.step.dependOn(&exe.step); |
| 17 | 17 | |
| 18 | 18 | const test_step = b.step("test", "Test the program"); |
example/shared_library/build.zig+1-1| ... | ... | @@ -12,7 +12,7 @@ pub fn build(b: &Builder) { |
| 12 | 12 | |
| 13 | 13 | b.default_step.dependOn(&exe.step); |
| 14 | 14 | |
| 15 | const run_cmd = b.addCommand(".", b.env_map, exe.getOutputPath(), [][]const u8{}); | |
| 15 | const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()}); | |
| 16 | 16 | run_cmd.step.dependOn(&exe.step); |
| 17 | 17 | |
| 18 | 18 | const test_step = b.step("test", "Test the program"); |
std/build.zig+48-37| ... | ... | @@ -180,11 +180,11 @@ pub const Builder = struct { |
| 180 | 180 | return LibExeObjStep.createCObject(self, name, src); |
| 181 | 181 | } |
| 182 | 182 | |
| 183 | /// ::args are copied. | |
| 183 | /// ::argv is copied. | |
| 184 | 184 | pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, |
| 185 | path: []const u8, args: []const []const u8) -> &CommandStep | |
| 185 | argv: []const []const u8) -> &CommandStep | |
| 186 | 186 | { |
| 187 | return CommandStep.create(self, cwd, env_map, path, args); | |
| 187 | return CommandStep.create(self, cwd, env_map, argv); | |
| 188 | 188 | } |
| 189 | 189 | |
| 190 | 190 | pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) -> &WriteFileStep { |
| ... | ... | @@ -528,42 +528,41 @@ pub const Builder = struct { |
| 528 | 528 | return self.invalid_user_input; |
| 529 | 529 | } |
| 530 | 530 | |
| 531 | fn spawnChild(self: &Builder, exe_path: []const u8, args: []const []const u8) -> %void { | |
| 532 | return self.spawnChildEnvMap(null, &self.env_map, exe_path, args); | |
| 531 | fn spawnChild(self: &Builder, argv: []const []const u8) -> %void { | |
| 532 | return self.spawnChildEnvMap(null, &self.env_map, argv); | |
| 533 | 533 | } |
| 534 | 534 | |
| 535 | 535 | fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, |
| 536 | exe_path: []const u8, args: []const []const u8) -> %void | |
| 536 | argv: []const []const u8) -> %void | |
| 537 | 537 | { |
| 538 | 538 | if (self.verbose) { |
| 539 | 539 | if (cwd) |yes_cwd| %%io.stderr.print("cd {}; ", yes_cwd); |
| 540 | %%io.stderr.print("{}", exe_path); | |
| 541 | for (args) |arg| { | |
| 542 | %%io.stderr.print(" {}", arg); | |
| 540 | for (argv) |arg| { | |
| 541 | %%io.stderr.print("{} ", arg); | |
| 543 | 542 | } |
| 544 | 543 | %%io.stderr.printf("\n"); |
| 545 | 544 | } |
| 546 | 545 | |
| 547 | var child = os.ChildProcess.spawn(exe_path, args, cwd, env_map, | |
| 548 | StdIo.Inherit, StdIo.Inherit, StdIo.Inherit, null, self.allocator) %% |err| | |
| 549 | { | |
| 550 | %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err)); | |
| 551 | return err; | |
| 552 | }; | |
| 546 | const child = %%os.ChildProcess.init(argv, self.allocator); | |
| 547 | defer child.deinit(); | |
| 553 | 548 | |
| 554 | const term = child.wait() %% |err| { | |
| 555 | %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err)); | |
| 549 | child.cwd = cwd; | |
| 550 | child.env_map = env_map; | |
| 551 | ||
| 552 | const term = child.spawnAndWait() %% |err| { | |
| 553 | %%io.stderr.printf("Unable to spawn {}: {}\n", argv[0], @errorName(err)); | |
| 556 | 554 | return err; |
| 557 | 555 | }; |
| 556 | ||
| 558 | 557 | switch (term) { |
| 559 | 558 | Term.Exited => |code| { |
| 560 | 559 | if (code != 0) { |
| 561 | %%io.stderr.printf("Process {} exited with error code {}\n", exe_path, code); | |
| 560 | %%io.stderr.printf("Process {} exited with error code {}\n", argv[0], code); | |
| 562 | 561 | return error.UncleanExit; |
| 563 | 562 | } |
| 564 | 563 | }, |
| 565 | 564 | else => { |
| 566 | %%io.stderr.printf("Process {} terminated unexpectedly\n", exe_path); | |
| 565 | %%io.stderr.printf("Process {} terminated unexpectedly\n", argv[0]); | |
| 567 | 566 | return error.UncleanExit; |
| 568 | 567 | }, |
| 569 | 568 | }; |
| ... | ... | @@ -1063,6 +1062,8 @@ pub const LibExeObjStep = struct { |
| 1063 | 1062 | var zig_args = ArrayList([]const u8).init(builder.allocator); |
| 1064 | 1063 | defer zig_args.deinit(); |
| 1065 | 1064 | |
| 1065 | %%zig_args.append(builder.zig_exe); | |
| 1066 | ||
| 1066 | 1067 | const cmd = switch (self.kind) { |
| 1067 | 1068 | Kind.Lib => "build-lib", |
| 1068 | 1069 | Kind.Exe => "build-exe", |
| ... | ... | @@ -1193,7 +1194,7 @@ pub const LibExeObjStep = struct { |
| 1193 | 1194 | } |
| 1194 | 1195 | } |
| 1195 | 1196 | |
| 1196 | %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); | |
| 1197 | %return builder.spawnChild(zig_args.toSliceConst()); | |
| 1197 | 1198 | |
| 1198 | 1199 | if (self.kind == Kind.Lib and !self.static) { |
| 1199 | 1200 | %return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, |
| ... | ... | @@ -1255,6 +1256,8 @@ pub const LibExeObjStep = struct { |
| 1255 | 1256 | var cc_args = ArrayList([]const u8).init(builder.allocator); |
| 1256 | 1257 | defer cc_args.deinit(); |
| 1257 | 1258 | |
| 1259 | %%cc_args.append(cc); | |
| 1260 | ||
| 1258 | 1261 | const is_darwin = self.target.isDarwin(); |
| 1259 | 1262 | |
| 1260 | 1263 | switch (self.kind) { |
| ... | ... | @@ -1268,11 +1271,12 @@ pub const LibExeObjStep = struct { |
| 1268 | 1271 | |
| 1269 | 1272 | self.appendCompileFlags(&cc_args); |
| 1270 | 1273 | |
| 1271 | %return builder.spawnChild(cc, cc_args.toSliceConst()); | |
| 1274 | %return builder.spawnChild(cc_args.toSliceConst()); | |
| 1272 | 1275 | }, |
| 1273 | 1276 | Kind.Lib => { |
| 1274 | 1277 | for (self.source_files.toSliceConst()) |source_file| { |
| 1275 | 1278 | %%cc_args.resize(0); |
| 1279 | %%cc_args.append(cc); | |
| 1276 | 1280 | |
| 1277 | 1281 | if (!self.static) { |
| 1278 | 1282 | %%cc_args.append("-fPIC"); |
| ... | ... | @@ -1291,7 +1295,7 @@ pub const LibExeObjStep = struct { |
| 1291 | 1295 | |
| 1292 | 1296 | self.appendCompileFlags(&cc_args); |
| 1293 | 1297 | |
| 1294 | %return builder.spawnChild(cc, cc_args.toSliceConst()); | |
| 1298 | %return builder.spawnChild(cc_args.toSliceConst()); | |
| 1295 | 1299 | |
| 1296 | 1300 | %%self.object_files.append(cache_o_file); |
| 1297 | 1301 | } |
| ... | ... | @@ -1299,6 +1303,8 @@ pub const LibExeObjStep = struct { |
| 1299 | 1303 | if (self.static) { |
| 1300 | 1304 | // ar |
| 1301 | 1305 | %%cc_args.resize(0); |
| 1306 | %%cc_args.append("ar"); | |
| 1307 | ||
| 1302 | 1308 | %%cc_args.append("qc"); |
| 1303 | 1309 | |
| 1304 | 1310 | const output_path = builder.pathFromRoot(self.getOutputPath()); |
| ... | ... | @@ -1308,15 +1314,17 @@ pub const LibExeObjStep = struct { |
| 1308 | 1314 | %%cc_args.append(builder.pathFromRoot(object_file)); |
| 1309 | 1315 | } |
| 1310 | 1316 | |
| 1311 | %return builder.spawnChild("ar", cc_args.toSliceConst()); | |
| 1317 | %return builder.spawnChild(cc_args.toSliceConst()); | |
| 1312 | 1318 | |
| 1313 | 1319 | // ranlib |
| 1314 | 1320 | %%cc_args.resize(0); |
| 1321 | %%cc_args.append("ranlib"); | |
| 1315 | 1322 | %%cc_args.append(output_path); |
| 1316 | 1323 | |
| 1317 | %return builder.spawnChild("ranlib", cc_args.toSliceConst()); | |
| 1324 | %return builder.spawnChild(cc_args.toSliceConst()); | |
| 1318 | 1325 | } else { |
| 1319 | 1326 | %%cc_args.resize(0); |
| 1327 | %%cc_args.append(cc); | |
| 1320 | 1328 | |
| 1321 | 1329 | if (is_darwin) { |
| 1322 | 1330 | %%cc_args.append("-dynamiclib"); |
| ... | ... | @@ -1370,7 +1378,7 @@ pub const LibExeObjStep = struct { |
| 1370 | 1378 | } |
| 1371 | 1379 | } |
| 1372 | 1380 | |
| 1373 | %return builder.spawnChild(cc, cc_args.toSliceConst()); | |
| 1381 | %return builder.spawnChild(cc_args.toSliceConst()); | |
| 1374 | 1382 | |
| 1375 | 1383 | %return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, |
| 1376 | 1384 | self.name_only_filename); |
| ... | ... | @@ -1379,6 +1387,7 @@ pub const LibExeObjStep = struct { |
| 1379 | 1387 | Kind.Exe => { |
| 1380 | 1388 | for (self.source_files.toSliceConst()) |source_file| { |
| 1381 | 1389 | %%cc_args.resize(0); |
| 1390 | %%cc_args.append(cc); | |
| 1382 | 1391 | |
| 1383 | 1392 | const abs_source_file = builder.pathFromRoot(source_file); |
| 1384 | 1393 | %%cc_args.append("-c"); |
| ... | ... | @@ -1400,12 +1409,13 @@ pub const LibExeObjStep = struct { |
| 1400 | 1409 | %%cc_args.append(builder.pathFromRoot(dir)); |
| 1401 | 1410 | } |
| 1402 | 1411 | |
| 1403 | %return builder.spawnChild(cc, cc_args.toSliceConst()); | |
| 1412 | %return builder.spawnChild(cc_args.toSliceConst()); | |
| 1404 | 1413 | |
| 1405 | 1414 | %%self.object_files.append(cache_o_file); |
| 1406 | 1415 | } |
| 1407 | 1416 | |
| 1408 | 1417 | %%cc_args.resize(0); |
| 1418 | %%cc_args.append(cc); | |
| 1409 | 1419 | |
| 1410 | 1420 | for (self.object_files.toSliceConst()) |object_file| { |
| 1411 | 1421 | %%cc_args.append(builder.pathFromRoot(object_file)); |
| ... | ... | @@ -1441,7 +1451,7 @@ pub const LibExeObjStep = struct { |
| 1441 | 1451 | } |
| 1442 | 1452 | } |
| 1443 | 1453 | |
| 1444 | %return builder.spawnChild(cc, cc_args.toSliceConst()); | |
| 1454 | %return builder.spawnChild(cc_args.toSliceConst()); | |
| 1445 | 1455 | }, |
| 1446 | 1456 | } |
| 1447 | 1457 | } |
| ... | ... | @@ -1518,6 +1528,8 @@ pub const TestStep = struct { |
| 1518 | 1528 | var zig_args = ArrayList([]const u8).init(builder.allocator); |
| 1519 | 1529 | defer zig_args.deinit(); |
| 1520 | 1530 | |
| 1531 | %%zig_args.append(builder.zig_exe); | |
| 1532 | ||
| 1521 | 1533 | %%zig_args.append("test"); |
| 1522 | 1534 | %%zig_args.append(builder.pathFromRoot(self.root_src)); |
| 1523 | 1535 | |
| ... | ... | @@ -1590,32 +1602,31 @@ pub const TestStep = struct { |
| 1590 | 1602 | %%zig_args.append(lib_path); |
| 1591 | 1603 | } |
| 1592 | 1604 | |
| 1593 | %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); | |
| 1605 | %return builder.spawnChild(zig_args.toSliceConst()); | |
| 1594 | 1606 | } |
| 1595 | 1607 | }; |
| 1596 | 1608 | |
| 1597 | 1609 | pub const CommandStep = struct { |
| 1598 | 1610 | step: Step, |
| 1599 | 1611 | builder: &Builder, |
| 1600 | exe_path: []const u8, | |
| 1601 | args: [][]const u8, | |
| 1612 | argv: [][]const u8, | |
| 1602 | 1613 | cwd: ?[]const u8, |
| 1603 | 1614 | env_map: &const BufMap, |
| 1604 | 1615 | |
| 1605 | /// ::args are copied. | |
| 1616 | /// ::argv is copied. | |
| 1606 | 1617 | pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap, |
| 1607 | exe_path: []const u8, args: []const []const u8) -> &CommandStep | |
| 1618 | argv: []const []const u8) -> &CommandStep | |
| 1608 | 1619 | { |
| 1609 | 1620 | const self = %%builder.allocator.create(CommandStep); |
| 1610 | 1621 | *self = CommandStep { |
| 1611 | 1622 | .builder = builder, |
| 1612 | .step = Step.init(exe_path, builder.allocator, make), | |
| 1613 | .exe_path = exe_path, | |
| 1614 | .args = %%builder.allocator.alloc([]u8, args.len), | |
| 1623 | .step = Step.init(argv[0], builder.allocator, make), | |
| 1624 | .argv = %%builder.allocator.alloc([]u8, argv.len), | |
| 1615 | 1625 | .cwd = cwd, |
| 1616 | 1626 | .env_map = env_map, |
| 1617 | 1627 | }; |
| 1618 | mem.copy([]const u8, self.args, args); | |
| 1628 | mem.copy([]const u8, self.argv, argv); | |
| 1629 | self.step.name = self.argv[0]; | |
| 1619 | 1630 | return self; |
| 1620 | 1631 | } |
| 1621 | 1632 | |
| ... | ... | @@ -1623,7 +1634,7 @@ pub const CommandStep = struct { |
| 1623 | 1634 | const self = @fieldParentPtr(CommandStep, "step", step); |
| 1624 | 1635 | |
| 1625 | 1636 | const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else null; |
| 1626 | return self.builder.spawnChildEnvMap(cwd, self.env_map, self.exe_path, self.args); | |
| 1637 | return self.builder.spawnChildEnvMap(cwd, self.env_map, self.argv); | |
| 1627 | 1638 | } |
| 1628 | 1639 | }; |
| 1629 | 1640 |
std/os/child_process.zig+120-65| ... | ... | @@ -16,20 +16,35 @@ error ProcessNotFound; |
| 16 | 16 | var children_nodes = LinkedList(&ChildProcess).init(); |
| 17 | 17 | |
| 18 | 18 | pub const ChildProcess = struct { |
| 19 | pid: i32, | |
| 19 | pub pid: i32, | |
| 20 | pub allocator: &mem.Allocator, | |
| 20 | 21 | |
| 21 | err_pipe: [2]i32, | |
| 22 | llnode: LinkedList(&ChildProcess).Node, | |
| 23 | allocator: &mem.Allocator, | |
| 22 | pub stdin: ?&io.OutStream, | |
| 23 | pub stdout: ?&io.InStream, | |
| 24 | pub stderr: ?&io.InStream, | |
| 25 | ||
| 26 | pub term: ?%Term, | |
| 27 | ||
| 28 | pub argv: []const []const u8, | |
| 29 | ||
| 30 | /// Possibly called from a signal handler. Must set this before calling `spawn`. | |
| 31 | pub onTerm: ?fn(&ChildProcess), | |
| 32 | ||
| 33 | /// Leave as null to use the current env map using the supplied allocator. | |
| 34 | pub env_map: ?&const BufMap, | |
| 24 | 35 | |
| 25 | stdin: ?&io.OutStream, | |
| 26 | stdout: ?&io.InStream, | |
| 27 | stderr: ?&io.InStream, | |
| 36 | pub stdin_behavior: StdIo, | |
| 37 | pub stdout_behavior: StdIo, | |
| 38 | pub stderr_behavior: StdIo, | |
| 28 | 39 | |
| 29 | term: ?%Term, | |
| 40 | /// Set to change the user id when spawning the child process. | |
| 41 | pub uid: ?u32, | |
| 30 | 42 | |
| 31 | /// Possibly called from a signal handler. | |
| 32 | onTerm: ?fn(&ChildProcess), | |
| 43 | /// Set to change the current working directory when spawning the child process. | |
| 44 | pub cwd: ?[]const u8, | |
| 45 | ||
| 46 | err_pipe: [2]i32, | |
| 47 | llnode: LinkedList(&ChildProcess).Node, | |
| 33 | 48 | |
| 34 | 49 | pub const Term = enum { |
| 35 | 50 | Exited: i32, |
| ... | ... | @@ -45,18 +60,50 @@ pub const ChildProcess = struct { |
| 45 | 60 | Close, |
| 46 | 61 | }; |
| 47 | 62 | |
| 63 | /// First argument in argv is the executable. | |
| 64 | /// On success must call deinit. | |
| 65 | pub fn init(argv: []const []const u8, allocator: &Allocator) -> %&ChildProcess { | |
| 66 | const child = %return allocator.create(ChildProcess); | |
| 67 | %defer allocator.destroy(child); | |
| 68 | ||
| 69 | *child = ChildProcess { | |
| 70 | .allocator = allocator, | |
| 71 | .argv = argv, | |
| 72 | .pid = undefined, | |
| 73 | .err_pipe = undefined, | |
| 74 | .llnode = undefined, | |
| 75 | .term = null, | |
| 76 | .onTerm = null, | |
| 77 | .env_map = null, | |
| 78 | .cwd = null, | |
| 79 | .uid = null, | |
| 80 | .stdin = null, | |
| 81 | .stdout = null, | |
| 82 | .stderr = null, | |
| 83 | .stdin_behavior = StdIo.Inherit, | |
| 84 | .stdout_behavior = StdIo.Inherit, | |
| 85 | .stderr_behavior = StdIo.Inherit, | |
| 86 | }; | |
| 87 | ||
| 88 | return child; | |
| 89 | } | |
| 90 | ||
| 91 | pub fn setUserName(self: &ChildProcess, name: []const u8) -> %void { | |
| 92 | self.uid = %return os.getUserId(name); | |
| 93 | } | |
| 94 | ||
| 48 | 95 | /// onTerm can be called before `spawn` returns. |
| 49 | pub fn spawn(exe_path: []const u8, args: []const []const u8, | |
| 50 | cwd: ?[]const u8, env_map: &const BufMap, | |
| 51 | stdin: StdIo, stdout: StdIo, stderr: StdIo, | |
| 52 | onTerm: ?fn(&ChildProcess), allocator: &Allocator) -> %&ChildProcess | |
| 53 | { | |
| 54 | switch (builtin.os) { | |
| 55 | Os.linux, Os.macosx, Os.ios, Os.darwin => { | |
| 56 | return spawnPosix(exe_path, args, cwd, env_map, stdin, stdout, stderr, onTerm, allocator); | |
| 57 | }, | |
| 96 | /// On success must call `kill` or `wait`. | |
| 97 | pub fn spawn(self: &ChildProcess) -> %void { | |
| 98 | return switch (builtin.os) { | |
| 99 | Os.linux, Os.macosx, Os.ios, Os.darwin => self.spawnPosix(), | |
| 58 | 100 | else => @compileError("Unsupported OS"), |
| 59 | } | |
| 101 | }; | |
| 102 | } | |
| 103 | ||
| 104 | pub fn spawnAndWait(self: &ChildProcess) -> %Term { | |
| 105 | %return self.spawn(); | |
| 106 | return self.wait(); | |
| 60 | 107 | } |
| 61 | 108 | |
| 62 | 109 | /// Forcibly terminates child process and then cleans up all resources. |
| ... | ... | @@ -96,6 +143,10 @@ pub const ChildProcess = struct { |
| 96 | 143 | return ??self.term; |
| 97 | 144 | } |
| 98 | 145 | |
| 146 | pub fn deinit(self: &ChildProcess) { | |
| 147 | self.allocator.destroy(self); | |
| 148 | } | |
| 149 | ||
| 99 | 150 | fn waitUnwrapped(self: &ChildProcess) { |
| 100 | 151 | var status: i32 = undefined; |
| 101 | 152 | while (true) { |
| ... | ... | @@ -162,50 +213,56 @@ pub const ChildProcess = struct { |
| 162 | 213 | }; |
| 163 | 214 | } |
| 164 | 215 | |
| 165 | fn spawnPosix(exe_path: []const u8, args: []const []const u8, | |
| 166 | maybe_cwd: ?[]const u8, env_map: &const BufMap, | |
| 167 | stdin: StdIo, stdout: StdIo, stderr: StdIo, | |
| 168 | onTerm: ?fn(&ChildProcess), allocator: &Allocator) -> %&ChildProcess | |
| 169 | { | |
| 216 | fn spawnPosix(self: &ChildProcess) -> %void { | |
| 170 | 217 | // TODO atomically set a flag saying that we already did this |
| 171 | 218 | install_SIGCHLD_handler(); |
| 172 | 219 | |
| 173 | const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined; | |
| 174 | %defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); }; | |
| 220 | const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) %return makePipe() else undefined; | |
| 221 | %defer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); }; | |
| 175 | 222 | |
| 176 | const stdout_pipe = if (stdout == StdIo.Pipe) %return makePipe() else undefined; | |
| 177 | %defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); }; | |
| 223 | const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) %return makePipe() else undefined; | |
| 224 | %defer if (self.stdout_behavior == StdIo.Pipe) { destroyPipe(stdout_pipe); }; | |
| 178 | 225 | |
| 179 | const stderr_pipe = if (stderr == StdIo.Pipe) %return makePipe() else undefined; | |
| 180 | %defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); }; | |
| 226 | const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) %return makePipe() else undefined; | |
| 227 | %defer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); }; | |
| 181 | 228 | |
| 182 | const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore); | |
| 229 | const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore); | |
| 183 | 230 | const dev_null_fd = if (any_ignore) { |
| 184 | 231 | %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null) |
| 185 | 232 | } else { |
| 186 | 233 | undefined |
| 187 | 234 | }; |
| 235 | defer { if (any_ignore) os.posixClose(dev_null_fd); }; | |
| 236 | ||
| 237 | var env_map_owned: BufMap = undefined; | |
| 238 | var we_own_env_map: bool = undefined; | |
| 239 | const env_map = if (self.env_map) |env_map| { | |
| 240 | we_own_env_map = false; | |
| 241 | env_map | |
| 242 | } else { | |
| 243 | we_own_env_map = true; | |
| 244 | env_map_owned = %return os.getEnvMap(self.allocator); | |
| 245 | &env_map_owned | |
| 246 | }; | |
| 247 | defer { if (we_own_env_map) env_map_owned.deinit(); } | |
| 188 | 248 | |
| 189 | 249 | // This pipe is used to communicate errors between the time of fork |
| 190 | 250 | // and execve from the child process to the parent process. |
| 191 | 251 | const err_pipe = %return makePipe(); |
| 192 | 252 | %defer destroyPipe(err_pipe); |
| 193 | 253 | |
| 194 | const child = %return allocator.create(ChildProcess); | |
| 195 | %defer allocator.destroy(child); | |
| 196 | ||
| 197 | const stdin_ptr = if (stdin == StdIo.Pipe) { | |
| 198 | %return allocator.create(io.OutStream) | |
| 254 | const stdin_ptr = if (self.stdin_behavior == StdIo.Pipe) { | |
| 255 | %return self.allocator.create(io.OutStream) | |
| 199 | 256 | } else { |
| 200 | 257 | null |
| 201 | 258 | }; |
| 202 | const stdout_ptr = if (stdout == StdIo.Pipe) { | |
| 203 | %return allocator.create(io.InStream) | |
| 259 | const stdout_ptr = if (self.stdout_behavior == StdIo.Pipe) { | |
| 260 | %return self.allocator.create(io.InStream) | |
| 204 | 261 | } else { |
| 205 | 262 | null |
| 206 | 263 | }; |
| 207 | const stderr_ptr = if (stderr == StdIo.Pipe) { | |
| 208 | %return allocator.create(io.InStream) | |
| 264 | const stderr_ptr = if (self.stderr_behavior == StdIo.Pipe) { | |
| 265 | %return self.allocator.create(io.InStream) | |
| 209 | 266 | } else { |
| 210 | 267 | null |
| 211 | 268 | }; |
| ... | ... | @@ -224,19 +281,23 @@ pub const ChildProcess = struct { |
| 224 | 281 | // we are the child |
| 225 | 282 | restore_SIGCHLD(); |
| 226 | 283 | |
| 227 | setUpChildIo(stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %% | |
| 284 | setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %% | |
| 228 | 285 | |err| forkChildErrReport(err_pipe[1], err); |
| 229 | setUpChildIo(stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %% | |
| 286 | setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %% | |
| 230 | 287 | |err| forkChildErrReport(err_pipe[1], err); |
| 231 | setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% | |
| 288 | setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% | |
| 232 | 289 | |err| forkChildErrReport(err_pipe[1], err); |
| 233 | 290 | |
| 234 | if (maybe_cwd) |cwd| { | |
| 235 | os.changeCurDir(allocator, cwd) %% | |
| 291 | if (self.cwd) |cwd| { | |
| 292 | os.changeCurDir(self.allocator, cwd) %% | |
| 236 | 293 | |err| forkChildErrReport(err_pipe[1], err); |
| 237 | 294 | } |
| 238 | 295 | |
| 239 | os.posixExecve(exe_path, args, env_map, allocator) %% | |
| 296 | if (self.uid) |uid| { | |
| 297 | os.posix_setuid(uid) %% |err| forkChildErrReport(err_pipe[1], err); | |
| 298 | } | |
| 299 | ||
| 300 | os.posixExecve(self.argv, env_map, self.allocator) %% | |
| 240 | 301 | |err| forkChildErrReport(err_pipe[1], err); |
| 241 | 302 | } |
| 242 | 303 | |
| ... | ... | @@ -266,28 +327,22 @@ pub const ChildProcess = struct { |
| 266 | 327 | }; |
| 267 | 328 | } |
| 268 | 329 | |
| 269 | *child = ChildProcess { | |
| 270 | .allocator = allocator, | |
| 271 | .pid = pid, | |
| 272 | .err_pipe = err_pipe, | |
| 273 | .llnode = LinkedList(&ChildProcess).Node.init(child), | |
| 274 | .term = null, | |
| 275 | .onTerm = onTerm, | |
| 276 | .stdin = stdin_ptr, | |
| 277 | .stdout = stdout_ptr, | |
| 278 | .stderr = stderr_ptr, | |
| 279 | }; | |
| 330 | self.pid = pid; | |
| 331 | self.err_pipe = err_pipe; | |
| 332 | self.llnode = LinkedList(&ChildProcess).Node.init(self); | |
| 333 | self.term = null; | |
| 334 | self.stdin = stdin_ptr; | |
| 335 | self.stdout = stdout_ptr; | |
| 336 | self.stderr = stderr_ptr; | |
| 280 | 337 | |
| 281 | children_nodes.prepend(&child.llnode); | |
| 338 | // TODO make this atomic so it works even with threads | |
| 339 | children_nodes.prepend(&self.llnode); | |
| 282 | 340 | |
| 283 | 341 | restore_SIGCHLD(); |
| 284 | 342 | |
| 285 | if (stdin == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); } | |
| 286 | if (stdout == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); } | |
| 287 | if (stderr == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); } | |
| 288 | if (any_ignore) { os.posixClose(dev_null_fd); } | |
| 289 | ||
| 290 | return child; | |
| 343 | if (self.stdin_behavior == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); } | |
| 344 | if (self.stdout_behavior == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); } | |
| 345 | if (self.stderr_behavior == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); } | |
| 291 | 346 | } |
| 292 | 347 | |
| 293 | 348 | fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void { |
std/os/get_user_id.zig created+78| ... | ... | @@ -0,0 +1,78 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const Os = builtin.Os; | |
| 3 | const os = @import("index.zig"); | |
| 4 | const io = @import("../io.zig"); | |
| 5 | ||
| 6 | /// POSIX function which gets a uid from username. | |
| 7 | pub fn getUserId(name: []const u8) -> %u32 { | |
| 8 | return switch (builtin.os) { | |
| 9 | Os.linux, Os.darwin, Os.macosx, Os.ios => posixGetUserId(name), | |
| 10 | else => @compileError("Unsupported OS"), | |
| 11 | }; | |
| 12 | } | |
| 13 | ||
| 14 | const State = enum { | |
| 15 | Start, | |
| 16 | WaitForNextLine, | |
| 17 | SkipPassword, | |
| 18 | ReadId, | |
| 19 | }; | |
| 20 | ||
| 21 | error UserNotFound; | |
| 22 | error CorruptPasswordFile; | |
| 23 | ||
| 24 | pub fn posixGetUserId(name: []const u8) -> %u32 { | |
| 25 | var in_stream = %return io.InStream.open("/etc/passwd", null); | |
| 26 | defer in_stream.close(); | |
| 27 | ||
| 28 | var buf: [os.page_size]u8 = undefined; | |
| 29 | var name_index: usize = 0; | |
| 30 | var state = State.Start; | |
| 31 | var uid: u32 = 0; | |
| 32 | ||
| 33 | while (true) { | |
| 34 | const amt_read = %return in_stream.read(buf[0..]); | |
| 35 | for (buf[0..amt_read]) |byte| { | |
| 36 | switch (state) { | |
| 37 | State.Start => switch (byte) { | |
| 38 | ':' => { | |
| 39 | state = if (name_index == name.len) State.SkipPassword else State.WaitForNextLine; | |
| 40 | }, | |
| 41 | '\n' => return error.CorruptPasswordFile, | |
| 42 | else => { | |
| 43 | if (name_index == name.len or name[name_index] != byte) { | |
| 44 | state = State.WaitForNextLine; | |
| 45 | } | |
| 46 | name_index += 1; | |
| 47 | }, | |
| 48 | }, | |
| 49 | State.WaitForNextLine => switch (byte) { | |
| 50 | '\n' => { | |
| 51 | name_index = 0; | |
| 52 | state = State.Start; | |
| 53 | }, | |
| 54 | else => continue, | |
| 55 | }, | |
| 56 | State.SkipPassword => switch (byte) { | |
| 57 | '\n' => return error.CorruptPasswordFile, | |
| 58 | ':' => { | |
| 59 | state = State.ReadId; | |
| 60 | }, | |
| 61 | else => continue, | |
| 62 | }, | |
| 63 | State.ReadId => switch (byte) { | |
| 64 | '\n', ':' => return uid, | |
| 65 | else => { | |
| 66 | const digit = switch (byte) { | |
| 67 | '0' ... '9' => byte - '0', | |
| 68 | else => return error.CorruptPasswordFile, | |
| 69 | }; | |
| 70 | if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile; | |
| 71 | if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile; | |
| 72 | }, | |
| 73 | }, | |
| 74 | } | |
| 75 | } | |
| 76 | if (amt_read < buf.len) return error.UserNotFound; | |
| 77 | } | |
| 78 | } |
std/os/index.zig+28-21| ... | ... | @@ -20,6 +20,8 @@ pub const line_sep = switch (builtin.os) { |
| 20 | 20 | |
| 21 | 21 | pub const page_size = 4 * 1024; |
| 22 | 22 | |
| 23 | pub const getUserId = @import("get_user_id.zig").getUserId; | |
| 24 | ||
| 23 | 25 | const debug = @import("../debug.zig"); |
| 24 | 26 | const assert = debug.assert; |
| 25 | 27 | |
| ... | ... | @@ -321,12 +323,12 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { |
| 321 | 323 | /// This function must allocate memory to add a null terminating bytes on path and each arg. |
| 322 | 324 | /// It must also convert to KEY=VALUE\0 format for environment variables, and include null |
| 323 | 325 | /// pointers after the args and after the environment variables. |
| 324 | /// Also make the first arg equal to exe_path. | |
| 326 | /// `argv[0]` is the executable path. | |
| 325 | 327 | /// This function also uses the PATH environment variable to get the full path to the executable. |
| 326 | pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &const BufMap, | |
| 328 | pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, | |
| 327 | 329 | allocator: &Allocator) -> %void |
| 328 | 330 | { |
| 329 | const argv_buf = %return allocator.alloc(?&u8, argv.len + 2); | |
| 331 | const argv_buf = %return allocator.alloc(?&u8, argv.len + 1); | |
| 330 | 332 | mem.set(?&u8, argv_buf, null); |
| 331 | 333 | defer { |
| 332 | 334 | for (argv_buf) |arg| { |
| ... | ... | @@ -335,22 +337,14 @@ pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &con |
| 335 | 337 | } |
| 336 | 338 | allocator.free(argv_buf); |
| 337 | 339 | } |
| 338 | { | |
| 339 | // Add exe_path to the first argument. | |
| 340 | const arg_buf = %return allocator.alloc(u8, exe_path.len + 1); | |
| 341 | @memcpy(&arg_buf[0], exe_path.ptr, exe_path.len); | |
| 342 | arg_buf[exe_path.len] = 0; | |
| 343 | ||
| 344 | argv_buf[0] = arg_buf.ptr; | |
| 345 | } | |
| 346 | 340 | for (argv) |arg, i| { |
| 347 | 341 | const arg_buf = %return allocator.alloc(u8, arg.len + 1); |
| 348 | 342 | @memcpy(&arg_buf[0], arg.ptr, arg.len); |
| 349 | 343 | arg_buf[arg.len] = 0; |
| 350 | 344 | |
| 351 | argv_buf[i + 1] = arg_buf.ptr; | |
| 345 | argv_buf[i] = arg_buf.ptr; | |
| 352 | 346 | } |
| 353 | argv_buf[argv.len + 1] = null; | |
| 347 | argv_buf[argv.len] = null; | |
| 354 | 348 | |
| 355 | 349 | const envp_count = env_map.count(); |
| 356 | 350 | const envp_buf = %return allocator.alloc(?&u8, envp_count + 1); |
| ... | ... | @@ -378,14 +372,9 @@ pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &con |
| 378 | 372 | } |
| 379 | 373 | envp_buf[envp_count] = null; |
| 380 | 374 | |
| 381 | ||
| 375 | const exe_path = argv[0]; | |
| 382 | 376 | if (mem.indexOfScalar(u8, exe_path, '/') != null) { |
| 383 | // +1 for the null terminating byte | |
| 384 | const path_buf = %return allocator.alloc(u8, exe_path.len + 1); | |
| 385 | defer allocator.free(path_buf); | |
| 386 | @memcpy(&path_buf[0], &exe_path[0], exe_path.len); | |
| 387 | path_buf[exe_path.len] = 0; | |
| 388 | return posixExecveErrnoToErr(posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr))); | |
| 377 | return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr))); | |
| 389 | 378 | } |
| 390 | 379 | |
| 391 | 380 | const PATH = getEnv("PATH") ?? "/usr/local/bin:/bin/:/usr/bin"; |
| ... | ... | @@ -434,6 +423,7 @@ fn posixExecveErrnoToErr(err: usize) -> error { |
| 434 | 423 | |
| 435 | 424 | pub var environ_raw: []&u8 = undefined; |
| 436 | 425 | |
| 426 | /// Caller must free result when done. | |
| 437 | 427 | pub fn getEnvMap(allocator: &Allocator) -> %BufMap { |
| 438 | 428 | var result = BufMap.init(allocator); |
| 439 | 429 | %defer result.deinit(); |
| ... | ... | @@ -840,7 +830,7 @@ pub const Dir = struct { |
| 840 | 830 | start_over: |
| 841 | 831 | if (self.index >= self.end_index) { |
| 842 | 832 | if (self.buf.len == 0) { |
| 843 | self.buf = %return self.allocator.alloc(u8, 2); //page_size); | |
| 833 | self.buf = %return self.allocator.alloc(u8, page_size); | |
| 844 | 834 | } |
| 845 | 835 | |
| 846 | 836 | while (true) { |
| ... | ... | @@ -992,3 +982,20 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) { |
| 992 | 982 | test "os.sleep" { |
| 993 | 983 | sleep(0, 1); |
| 994 | 984 | } |
| 985 | ||
| 986 | ||
| 987 | error ResourceLimitReached; | |
| 988 | error InvalidUserId; | |
| 989 | error PermissionDenied; | |
| 990 | error Unexpected; | |
| 991 | ||
| 992 | pub fn posix_setuid(uid: u32) -> %void { | |
| 993 | const err = posix.getErrno(posix.setuid(uid)); | |
| 994 | if (err == 0) return; | |
| 995 | return switch (err) { | |
| 996 | posix.EAGAIN => error.ResourceLimitReached, | |
| 997 | posix.EINVAL => error.InvalidUserId, | |
| 998 | posix.EPERM => error.PermissionDenied, | |
| 999 | else => error.Unexpected, | |
| 1000 | }; | |
| 1001 | } |
std/os/linux.zig+4| ... | ... | @@ -480,6 +480,10 @@ pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize { |
| 480 | 480 | arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)) |
| 481 | 481 | } |
| 482 | 482 | |
| 483 | pub fn setuid(uid: u32) -> usize { | |
| 484 | arch.syscall1(arch.SYS_setuid, uid) | |
| 485 | } | |
| 486 | ||
| 483 | 487 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { |
| 484 | 488 | arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8) |
| 485 | 489 | } |
test/standalone/pkg_import/build.zig+1-1| ... | ... | @@ -9,7 +9,7 @@ pub fn build(b: &Builder) { |
| 9 | 9 | exe.setBuildMode(b.standardReleaseOptions()); |
| 10 | 10 | exe.setBuildMode(b.standardReleaseOptions()); |
| 11 | 11 | |
| 12 | const run = b.addCommand(".", b.env_map, exe.getOutputPath(), [][]const u8{}); | |
| 12 | const run = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()}); | |
| 13 | 13 | run.step.dependOn(&exe.step); |
| 14 | 14 | |
| 15 | 15 | const test_step = b.step("test", "Test it"); |
test/tests.zig+43-24| ... | ... | @@ -241,11 +241,15 @@ pub const CompareOutputContext = struct { |
| 241 | 241 | |
| 242 | 242 | %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); |
| 243 | 243 | |
| 244 | var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, null, &b.env_map, | |
| 245 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err| | |
| 246 | { | |
| 247 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | |
| 248 | }; | |
| 244 | const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator); | |
| 245 | defer child.deinit(); | |
| 246 | ||
| 247 | child.stdin_behavior = StdIo.Ignore; | |
| 248 | child.stdout_behavior = StdIo.Pipe; | |
| 249 | child.stderr_behavior = StdIo.Pipe; | |
| 250 | child.env_map = &b.env_map; | |
| 251 | ||
| 252 | child.spawn() %% |err| debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | |
| 249 | 253 | |
| 250 | 254 | var stdout = Buffer.initNull(b.allocator); |
| 251 | 255 | var stderr = Buffer.initNull(b.allocator); |
| ... | ... | @@ -316,13 +320,15 @@ pub const CompareOutputContext = struct { |
| 316 | 320 | |
| 317 | 321 | %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); |
| 318 | 322 | |
| 319 | var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, null, &b.env_map, | |
| 320 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err| | |
| 321 | { | |
| 322 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | |
| 323 | }; | |
| 323 | const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator); | |
| 324 | defer child.deinit(); | |
| 324 | 325 | |
| 325 | const term = child.wait() %% |err| { | |
| 326 | child.env_map = &b.env_map; | |
| 327 | child.stdin_behavior = StdIo.Ignore; | |
| 328 | child.stdout_behavior = StdIo.Ignore; | |
| 329 | child.stderr_behavior = StdIo.Ignore; | |
| 330 | ||
| 331 | const term = child.spawnAndWait() %% |err| { | |
| 326 | 332 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); |
| 327 | 333 | }; |
| 328 | 334 | |
| ... | ... | @@ -539,6 +545,8 @@ pub const CompileErrorContext = struct { |
| 539 | 545 | const obj_path = %%os.path.join(b.allocator, b.cache_root, "test.o"); |
| 540 | 546 | |
| 541 | 547 | var zig_args = ArrayList([]const u8).init(b.allocator); |
| 548 | %%zig_args.append(b.zig_exe); | |
| 549 | ||
| 542 | 550 | %%zig_args.append(if (self.case.is_exe) "build-exe" else "build-obj"); |
| 543 | 551 | %%zig_args.append(b.pathFromRoot(root_src)); |
| 544 | 552 | |
| ... | ... | @@ -560,11 +568,15 @@ pub const CompileErrorContext = struct { |
| 560 | 568 | printInvocation(b.zig_exe, zig_args.toSliceConst()); |
| 561 | 569 | } |
| 562 | 570 | |
| 563 | var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), null, &b.env_map, | |
| 564 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err| | |
| 565 | { | |
| 566 | debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); | |
| 567 | }; | |
| 571 | const child = %%os.ChildProcess.init(zig_args.toSliceConst(), b.allocator); | |
| 572 | defer child.deinit(); | |
| 573 | ||
| 574 | child.env_map = &b.env_map; | |
| 575 | child.stdin_behavior = StdIo.Ignore; | |
| 576 | child.stdout_behavior = StdIo.Pipe; | |
| 577 | child.stderr_behavior = StdIo.Pipe; | |
| 578 | ||
| 579 | child.spawn() %% |err| debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err)); | |
| 568 | 580 | |
| 569 | 581 | var stdout_buf = Buffer.initNull(b.allocator); |
| 570 | 582 | var stderr_buf = Buffer.initNull(b.allocator); |
| ... | ... | @@ -573,7 +585,7 @@ pub const CompileErrorContext = struct { |
| 573 | 585 | %%(??child.stderr).readAll(&stderr_buf); |
| 574 | 586 | |
| 575 | 587 | const term = child.wait() %% |err| { |
| 576 | debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); | |
| 588 | debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err)); | |
| 577 | 589 | }; |
| 578 | 590 | switch (term) { |
| 579 | 591 | Term.Exited => |code| { |
| ... | ... | @@ -712,6 +724,7 @@ pub const BuildExamplesContext = struct { |
| 712 | 724 | } |
| 713 | 725 | |
| 714 | 726 | var zig_args = ArrayList([]const u8).init(b.allocator); |
| 727 | %%zig_args.append(b.zig_exe); | |
| 715 | 728 | %%zig_args.append("build"); |
| 716 | 729 | |
| 717 | 730 | %%zig_args.append("--build-file"); |
| ... | ... | @@ -723,7 +736,7 @@ pub const BuildExamplesContext = struct { |
| 723 | 736 | %%zig_args.append("--verbose"); |
| 724 | 737 | } |
| 725 | 738 | |
| 726 | const run_cmd = b.addCommand(null, b.env_map, b.zig_exe, zig_args.toSliceConst()); | |
| 739 | const run_cmd = b.addCommand(null, b.env_map, zig_args.toSliceConst()); | |
| 727 | 740 | |
| 728 | 741 | const log_step = b.addLog("PASS {}\n", annotated_case_name); |
| 729 | 742 | log_step.step.dependOn(&run_cmd.step); |
| ... | ... | @@ -813,6 +826,8 @@ pub const ParseCContext = struct { |
| 813 | 826 | const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename); |
| 814 | 827 | |
| 815 | 828 | var zig_args = ArrayList([]const u8).init(b.allocator); |
| 829 | %%zig_args.append(b.zig_exe); | |
| 830 | ||
| 816 | 831 | %%zig_args.append("parsec"); |
| 817 | 832 | %%zig_args.append(b.pathFromRoot(root_src)); |
| 818 | 833 | |
| ... | ... | @@ -822,11 +837,15 @@ pub const ParseCContext = struct { |
| 822 | 837 | printInvocation(b.zig_exe, zig_args.toSliceConst()); |
| 823 | 838 | } |
| 824 | 839 | |
| 825 | var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), null, &b.env_map, | |
| 826 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err| | |
| 827 | { | |
| 828 | debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); | |
| 829 | }; | |
| 840 | const child = %%os.ChildProcess.init(zig_args.toSliceConst(), b.allocator); | |
| 841 | defer child.deinit(); | |
| 842 | ||
| 843 | child.env_map = &b.env_map; | |
| 844 | child.stdin_behavior = StdIo.Ignore; | |
| 845 | child.stdout_behavior = StdIo.Pipe; | |
| 846 | child.stderr_behavior = StdIo.Pipe; | |
| 847 | ||
| 848 | child.spawn() %% |err| debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err)); | |
| 830 | 849 | |
| 831 | 850 | var stdout_buf = Buffer.initNull(b.allocator); |
| 832 | 851 | var stderr_buf = Buffer.initNull(b.allocator); |
| ... | ... | @@ -835,7 +854,7 @@ pub const ParseCContext = struct { |
| 835 | 854 | %%(??child.stderr).readAll(&stderr_buf); |
| 836 | 855 | |
| 837 | 856 | const term = child.wait() %% |err| { |
| 838 | debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); | |
| 857 | debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err)); | |
| 839 | 858 | }; |
| 840 | 859 | switch (term) { |
| 841 | 860 | Term.Exited => |code| { |