| 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,6 +548,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}") |
| 548 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/child_process.zig" DESTINATION "${ZIG_STD_DEST}/os") | 548 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/child_process.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 549 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os") | 549 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 550 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin_errno.zig" DESTINATION "${ZIG_STD_DEST}/os") | 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 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/index.zig" DESTINATION "${ZIG_STD_DEST}/os") | 552 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/index.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 552 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux.zig" DESTINATION "${ZIG_STD_DEST}/os") | 553 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 553 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_errno.zig" DESTINATION "${ZIG_STD_DEST}/os") | 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,7 +12,7 @@ pub fn build(b: &Builder) { |
| 12 | 12 | ||
| 13 | b.default_step.dependOn(&exe.step); | 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 | run_cmd.step.dependOn(&exe.step); | 16 | run_cmd.step.dependOn(&exe.step); |
| 17 | 17 | ||
| 18 | const test_step = b.step("test", "Test the program"); | 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,7 +12,7 @@ pub fn build(b: &Builder) { |
| 12 | 12 | ||
| 13 | b.default_step.dependOn(&exe.step); | 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 | run_cmd.step.dependOn(&exe.step); | 16 | run_cmd.step.dependOn(&exe.step); |
| 17 | 17 | ||
| 18 | const test_step = b.step("test", "Test the program"); | 18 | const test_step = b.step("test", "Test the program"); |
std/build.zig+48-37| ... | @@ -180,11 +180,11 @@ pub const Builder = struct { | ... | @@ -180,11 +180,11 @@ pub const Builder = struct { |
| 180 | return LibExeObjStep.createCObject(self, name, src); | 180 | return LibExeObjStep.createCObject(self, name, src); |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | /// ::args are copied. | 183 | /// ::argv is copied. |
| 184 | pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, | 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 | pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) -> &WriteFileStep { | 190 | pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) -> &WriteFileStep { |
| ... | @@ -528,42 +528,41 @@ pub const Builder = struct { | ... | @@ -528,42 +528,41 @@ pub const Builder = struct { |
| 528 | return self.invalid_user_input; | 528 | return self.invalid_user_input; |
| 529 | } | 529 | } |
| 530 | 530 | ||
| 531 | fn spawnChild(self: &Builder, exe_path: []const u8, args: []const []const u8) -> %void { | 531 | fn spawnChild(self: &Builder, argv: []const []const u8) -> %void { |
| 532 | return self.spawnChildEnvMap(null, &self.env_map, exe_path, args); | 532 | return self.spawnChildEnvMap(null, &self.env_map, argv); |
| 533 | } | 533 | } |
| 534 | 534 | ||
| 535 | fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap, | 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 | if (self.verbose) { | 538 | if (self.verbose) { |
| 539 | if (cwd) |yes_cwd| %%io.stderr.print("cd {}; ", yes_cwd); | 539 | if (cwd) |yes_cwd| %%io.stderr.print("cd {}; ", yes_cwd); |
| 540 | %%io.stderr.print("{}", exe_path); | 540 | for (argv) |arg| { |
| 541 | for (args) |arg| { | 541 | %%io.stderr.print("{} ", arg); |
| 542 | %%io.stderr.print(" {}", arg); | ||
| 543 | } | 542 | } |
| 544 | %%io.stderr.printf("\n"); | 543 | %%io.stderr.printf("\n"); |
| 545 | } | 544 | } |
| 546 | 545 | ||
| 547 | var child = os.ChildProcess.spawn(exe_path, args, cwd, env_map, | 546 | const child = %%os.ChildProcess.init(argv, self.allocator); |
| 548 | StdIo.Inherit, StdIo.Inherit, StdIo.Inherit, null, self.allocator) %% |err| | 547 | defer child.deinit(); |
| 549 | { | ||
| 550 | %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err)); | ||
| 551 | return err; | ||
| 552 | }; | ||
| 553 | 548 | ||
| 554 | const term = child.wait() %% |err| { | 549 | child.cwd = cwd; |
| 555 | %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err)); | 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 | return err; | 554 | return err; |
| 557 | }; | 555 | }; |
| 556 | |||
| 558 | switch (term) { | 557 | switch (term) { |
| 559 | Term.Exited => |code| { | 558 | Term.Exited => |code| { |
| 560 | if (code != 0) { | 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 | return error.UncleanExit; | 561 | return error.UncleanExit; |
| 563 | } | 562 | } |
| 564 | }, | 563 | }, |
| 565 | else => { | 564 | else => { |
| 566 | %%io.stderr.printf("Process {} terminated unexpectedly\n", exe_path); | 565 | %%io.stderr.printf("Process {} terminated unexpectedly\n", argv[0]); |
| 567 | return error.UncleanExit; | 566 | return error.UncleanExit; |
| 568 | }, | 567 | }, |
| 569 | }; | 568 | }; |
| ... | @@ -1063,6 +1062,8 @@ pub const LibExeObjStep = struct { | ... | @@ -1063,6 +1062,8 @@ pub const LibExeObjStep = struct { |
| 1063 | var zig_args = ArrayList([]const u8).init(builder.allocator); | 1062 | var zig_args = ArrayList([]const u8).init(builder.allocator); |
| 1064 | defer zig_args.deinit(); | 1063 | defer zig_args.deinit(); |
| 1065 | 1064 | ||
| 1065 | %%zig_args.append(builder.zig_exe); | ||
| 1066 | |||
| 1066 | const cmd = switch (self.kind) { | 1067 | const cmd = switch (self.kind) { |
| 1067 | Kind.Lib => "build-lib", | 1068 | Kind.Lib => "build-lib", |
| 1068 | Kind.Exe => "build-exe", | 1069 | Kind.Exe => "build-exe", |
| ... | @@ -1193,7 +1194,7 @@ pub const LibExeObjStep = struct { | ... | @@ -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 | if (self.kind == Kind.Lib and !self.static) { | 1199 | if (self.kind == Kind.Lib and !self.static) { |
| 1199 | %return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, | 1200 | %return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, |
| ... | @@ -1255,6 +1256,8 @@ pub const LibExeObjStep = struct { | ... | @@ -1255,6 +1256,8 @@ pub const LibExeObjStep = struct { |
| 1255 | var cc_args = ArrayList([]const u8).init(builder.allocator); | 1256 | var cc_args = ArrayList([]const u8).init(builder.allocator); |
| 1256 | defer cc_args.deinit(); | 1257 | defer cc_args.deinit(); |
| 1257 | 1258 | ||
| 1259 | %%cc_args.append(cc); | ||
| 1260 | |||
| 1258 | const is_darwin = self.target.isDarwin(); | 1261 | const is_darwin = self.target.isDarwin(); |
| 1259 | 1262 | ||
| 1260 | switch (self.kind) { | 1263 | switch (self.kind) { |
| ... | @@ -1268,11 +1271,12 @@ pub const LibExeObjStep = struct { | ... | @@ -1268,11 +1271,12 @@ pub const LibExeObjStep = struct { |
| 1268 | 1271 | ||
| 1269 | self.appendCompileFlags(&cc_args); | 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 | Kind.Lib => { | 1276 | Kind.Lib => { |
| 1274 | for (self.source_files.toSliceConst()) |source_file| { | 1277 | for (self.source_files.toSliceConst()) |source_file| { |
| 1275 | %%cc_args.resize(0); | 1278 | %%cc_args.resize(0); |
| 1279 | %%cc_args.append(cc); | ||
| 1276 | 1280 | ||
| 1277 | if (!self.static) { | 1281 | if (!self.static) { |
| 1278 | %%cc_args.append("-fPIC"); | 1282 | %%cc_args.append("-fPIC"); |
| ... | @@ -1291,7 +1295,7 @@ pub const LibExeObjStep = struct { | ... | @@ -1291,7 +1295,7 @@ pub const LibExeObjStep = struct { |
| 1291 | 1295 | ||
| 1292 | self.appendCompileFlags(&cc_args); | 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 | %%self.object_files.append(cache_o_file); | 1300 | %%self.object_files.append(cache_o_file); |
| 1297 | } | 1301 | } |
| ... | @@ -1299,6 +1303,8 @@ pub const LibExeObjStep = struct { | ... | @@ -1299,6 +1303,8 @@ pub const LibExeObjStep = struct { |
| 1299 | if (self.static) { | 1303 | if (self.static) { |
| 1300 | // ar | 1304 | // ar |
| 1301 | %%cc_args.resize(0); | 1305 | %%cc_args.resize(0); |
| 1306 | %%cc_args.append("ar"); | ||
| 1307 | |||
| 1302 | %%cc_args.append("qc"); | 1308 | %%cc_args.append("qc"); |
| 1303 | 1309 | ||
| 1304 | const output_path = builder.pathFromRoot(self.getOutputPath()); | 1310 | const output_path = builder.pathFromRoot(self.getOutputPath()); |
| ... | @@ -1308,15 +1314,17 @@ pub const LibExeObjStep = struct { | ... | @@ -1308,15 +1314,17 @@ pub const LibExeObjStep = struct { |
| 1308 | %%cc_args.append(builder.pathFromRoot(object_file)); | 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 | // ranlib | 1319 | // ranlib |
| 1314 | %%cc_args.resize(0); | 1320 | %%cc_args.resize(0); |
| 1321 | %%cc_args.append("ranlib"); | ||
| 1315 | %%cc_args.append(output_path); | 1322 | %%cc_args.append(output_path); |
| 1316 | 1323 | ||
| 1317 | %return builder.spawnChild("ranlib", cc_args.toSliceConst()); | 1324 | %return builder.spawnChild(cc_args.toSliceConst()); |
| 1318 | } else { | 1325 | } else { |
| 1319 | %%cc_args.resize(0); | 1326 | %%cc_args.resize(0); |
| 1327 | %%cc_args.append(cc); | ||
| 1320 | 1328 | ||
| 1321 | if (is_darwin) { | 1329 | if (is_darwin) { |
| 1322 | %%cc_args.append("-dynamiclib"); | 1330 | %%cc_args.append("-dynamiclib"); |
| ... | @@ -1370,7 +1378,7 @@ pub const LibExeObjStep = struct { | ... | @@ -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 | %return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, | 1383 | %return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, |
| 1376 | self.name_only_filename); | 1384 | self.name_only_filename); |
| ... | @@ -1379,6 +1387,7 @@ pub const LibExeObjStep = struct { | ... | @@ -1379,6 +1387,7 @@ pub const LibExeObjStep = struct { |
| 1379 | Kind.Exe => { | 1387 | Kind.Exe => { |
| 1380 | for (self.source_files.toSliceConst()) |source_file| { | 1388 | for (self.source_files.toSliceConst()) |source_file| { |
| 1381 | %%cc_args.resize(0); | 1389 | %%cc_args.resize(0); |
| 1390 | %%cc_args.append(cc); | ||
| 1382 | 1391 | ||
| 1383 | const abs_source_file = builder.pathFromRoot(source_file); | 1392 | const abs_source_file = builder.pathFromRoot(source_file); |
| 1384 | %%cc_args.append("-c"); | 1393 | %%cc_args.append("-c"); |
| ... | @@ -1400,12 +1409,13 @@ pub const LibExeObjStep = struct { | ... | @@ -1400,12 +1409,13 @@ pub const LibExeObjStep = struct { |
| 1400 | %%cc_args.append(builder.pathFromRoot(dir)); | 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 | %%self.object_files.append(cache_o_file); | 1414 | %%self.object_files.append(cache_o_file); |
| 1406 | } | 1415 | } |
| 1407 | 1416 | ||
| 1408 | %%cc_args.resize(0); | 1417 | %%cc_args.resize(0); |
| 1418 | %%cc_args.append(cc); | ||
| 1409 | 1419 | ||
| 1410 | for (self.object_files.toSliceConst()) |object_file| { | 1420 | for (self.object_files.toSliceConst()) |object_file| { |
| 1411 | %%cc_args.append(builder.pathFromRoot(object_file)); | 1421 | %%cc_args.append(builder.pathFromRoot(object_file)); |
| ... | @@ -1441,7 +1451,7 @@ pub const LibExeObjStep = struct { | ... | @@ -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,6 +1528,8 @@ pub const TestStep = struct { |
| 1518 | var zig_args = ArrayList([]const u8).init(builder.allocator); | 1528 | var zig_args = ArrayList([]const u8).init(builder.allocator); |
| 1519 | defer zig_args.deinit(); | 1529 | defer zig_args.deinit(); |
| 1520 | 1530 | ||
| 1531 | %%zig_args.append(builder.zig_exe); | ||
| 1532 | |||
| 1521 | %%zig_args.append("test"); | 1533 | %%zig_args.append("test"); |
| 1522 | %%zig_args.append(builder.pathFromRoot(self.root_src)); | 1534 | %%zig_args.append(builder.pathFromRoot(self.root_src)); |
| 1523 | 1535 | ||
| ... | @@ -1590,32 +1602,31 @@ pub const TestStep = struct { | ... | @@ -1590,32 +1602,31 @@ pub const TestStep = struct { |
| 1590 | %%zig_args.append(lib_path); | 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 | pub const CommandStep = struct { | 1609 | pub const CommandStep = struct { |
| 1598 | step: Step, | 1610 | step: Step, |
| 1599 | builder: &Builder, | 1611 | builder: &Builder, |
| 1600 | exe_path: []const u8, | 1612 | argv: [][]const u8, |
| 1601 | args: [][]const u8, | ||
| 1602 | cwd: ?[]const u8, | 1613 | cwd: ?[]const u8, |
| 1603 | env_map: &const BufMap, | 1614 | env_map: &const BufMap, |
| 1604 | 1615 | ||
| 1605 | /// ::args are copied. | 1616 | /// ::argv is copied. |
| 1606 | pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap, | 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 | const self = %%builder.allocator.create(CommandStep); | 1620 | const self = %%builder.allocator.create(CommandStep); |
| 1610 | *self = CommandStep { | 1621 | *self = CommandStep { |
| 1611 | .builder = builder, | 1622 | .builder = builder, |
| 1612 | .step = Step.init(exe_path, builder.allocator, make), | 1623 | .step = Step.init(argv[0], builder.allocator, make), |
| 1613 | .exe_path = exe_path, | 1624 | .argv = %%builder.allocator.alloc([]u8, argv.len), |
| 1614 | .args = %%builder.allocator.alloc([]u8, args.len), | ||
| 1615 | .cwd = cwd, | 1625 | .cwd = cwd, |
| 1616 | .env_map = env_map, | 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 | return self; | 1630 | return self; |
| 1620 | } | 1631 | } |
| 1621 | 1632 | ||
| ... | @@ -1623,7 +1634,7 @@ pub const CommandStep = struct { | ... | @@ -1623,7 +1634,7 @@ pub const CommandStep = struct { |
| 1623 | const self = @fieldParentPtr(CommandStep, "step", step); | 1634 | const self = @fieldParentPtr(CommandStep, "step", step); |
| 1624 | 1635 | ||
| 1625 | const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else null; | 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,20 +16,35 @@ error ProcessNotFound; |
| 16 | var children_nodes = LinkedList(&ChildProcess).init(); | 16 | var children_nodes = LinkedList(&ChildProcess).init(); |
| 17 | 17 | ||
| 18 | pub const ChildProcess = struct { | 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 | pub stdin: ?&io.OutStream, |
| 22 | llnode: LinkedList(&ChildProcess).Node, | 23 | pub stdout: ?&io.InStream, |
| 23 | allocator: &mem.Allocator, | 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, | 36 | pub stdin_behavior: StdIo, |
| 26 | stdout: ?&io.InStream, | 37 | pub stdout_behavior: StdIo, |
| 27 | stderr: ?&io.InStream, | 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. | 43 | /// Set to change the current working directory when spawning the child process. |
| 32 | onTerm: ?fn(&ChildProcess), | 44 | pub cwd: ?[]const u8, |
| 45 | |||
| 46 | err_pipe: [2]i32, | ||
| 47 | llnode: LinkedList(&ChildProcess).Node, | ||
| 33 | 48 | ||
| 34 | pub const Term = enum { | 49 | pub const Term = enum { |
| 35 | Exited: i32, | 50 | Exited: i32, |
| ... | @@ -45,18 +60,50 @@ pub const ChildProcess = struct { | ... | @@ -45,18 +60,50 @@ pub const ChildProcess = struct { |
| 45 | Close, | 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 | /// onTerm can be called before `spawn` returns. | 95 | /// onTerm can be called before `spawn` returns. |
| 49 | pub fn spawn(exe_path: []const u8, args: []const []const u8, | 96 | /// On success must call `kill` or `wait`. |
| 50 | cwd: ?[]const u8, env_map: &const BufMap, | 97 | pub fn spawn(self: &ChildProcess) -> %void { |
| 51 | stdin: StdIo, stdout: StdIo, stderr: StdIo, | 98 | return switch (builtin.os) { |
| 52 | onTerm: ?fn(&ChildProcess), allocator: &Allocator) -> %&ChildProcess | 99 | Os.linux, Os.macosx, Os.ios, Os.darwin => self.spawnPosix(), |
| 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 | }, | ||
| 58 | else => @compileError("Unsupported OS"), | 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 | /// Forcibly terminates child process and then cleans up all resources. | 109 | /// Forcibly terminates child process and then cleans up all resources. |
| ... | @@ -96,6 +143,10 @@ pub const ChildProcess = struct { | ... | @@ -96,6 +143,10 @@ pub const ChildProcess = struct { |
| 96 | return ??self.term; | 143 | return ??self.term; |
| 97 | } | 144 | } |
| 98 | 145 | ||
| 146 | pub fn deinit(self: &ChildProcess) { | ||
| 147 | self.allocator.destroy(self); | ||
| 148 | } | ||
| 149 | |||
| 99 | fn waitUnwrapped(self: &ChildProcess) { | 150 | fn waitUnwrapped(self: &ChildProcess) { |
| 100 | var status: i32 = undefined; | 151 | var status: i32 = undefined; |
| 101 | while (true) { | 152 | while (true) { |
| ... | @@ -162,50 +213,56 @@ pub const ChildProcess = struct { | ... | @@ -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, | 216 | fn spawnPosix(self: &ChildProcess) -> %void { |
| 166 | maybe_cwd: ?[]const u8, env_map: &const BufMap, | ||
| 167 | stdin: StdIo, stdout: StdIo, stderr: StdIo, | ||
| 168 | onTerm: ?fn(&ChildProcess), allocator: &Allocator) -> %&ChildProcess | ||
| 169 | { | ||
| 170 | // TODO atomically set a flag saying that we already did this | 217 | // TODO atomically set a flag saying that we already did this |
| 171 | install_SIGCHLD_handler(); | 218 | install_SIGCHLD_handler(); |
| 172 | 219 | ||
| 173 | const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined; | 220 | const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) %return makePipe() else undefined; |
| 174 | %defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); }; | 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; | 223 | const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) %return makePipe() else undefined; |
| 177 | %defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); }; | 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; | 226 | const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) %return makePipe() else undefined; |
| 180 | %defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); }; | 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 | const dev_null_fd = if (any_ignore) { | 230 | const dev_null_fd = if (any_ignore) { |
| 184 | %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null) | 231 | %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null) |
| 185 | } else { | 232 | } else { |
| 186 | undefined | 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 | // This pipe is used to communicate errors between the time of fork | 249 | // This pipe is used to communicate errors between the time of fork |
| 190 | // and execve from the child process to the parent process. | 250 | // and execve from the child process to the parent process. |
| 191 | const err_pipe = %return makePipe(); | 251 | const err_pipe = %return makePipe(); |
| 192 | %defer destroyPipe(err_pipe); | 252 | %defer destroyPipe(err_pipe); |
| 193 | 253 | ||
| 194 | const child = %return allocator.create(ChildProcess); | 254 | const stdin_ptr = if (self.stdin_behavior == StdIo.Pipe) { |
| 195 | %defer allocator.destroy(child); | 255 | %return self.allocator.create(io.OutStream) |
| 196 | |||
| 197 | const stdin_ptr = if (stdin == StdIo.Pipe) { | ||
| 198 | %return allocator.create(io.OutStream) | ||
| 199 | } else { | 256 | } else { |
| 200 | null | 257 | null |
| 201 | }; | 258 | }; |
| 202 | const stdout_ptr = if (stdout == StdIo.Pipe) { | 259 | const stdout_ptr = if (self.stdout_behavior == StdIo.Pipe) { |
| 203 | %return allocator.create(io.InStream) | 260 | %return self.allocator.create(io.InStream) |
| 204 | } else { | 261 | } else { |
| 205 | null | 262 | null |
| 206 | }; | 263 | }; |
| 207 | const stderr_ptr = if (stderr == StdIo.Pipe) { | 264 | const stderr_ptr = if (self.stderr_behavior == StdIo.Pipe) { |
| 208 | %return allocator.create(io.InStream) | 265 | %return self.allocator.create(io.InStream) |
| 209 | } else { | 266 | } else { |
| 210 | null | 267 | null |
| 211 | }; | 268 | }; |
| ... | @@ -224,19 +281,23 @@ pub const ChildProcess = struct { | ... | @@ -224,19 +281,23 @@ pub const ChildProcess = struct { |
| 224 | // we are the child | 281 | // we are the child |
| 225 | restore_SIGCHLD(); | 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 | |err| forkChildErrReport(err_pipe[1], err); | 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 | |err| forkChildErrReport(err_pipe[1], err); | 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 | |err| forkChildErrReport(err_pipe[1], err); | 289 | |err| forkChildErrReport(err_pipe[1], err); |
| 233 | 290 | ||
| 234 | if (maybe_cwd) |cwd| { | 291 | if (self.cwd) |cwd| { |
| 235 | os.changeCurDir(allocator, cwd) %% | 292 | os.changeCurDir(self.allocator, cwd) %% |
| 236 | |err| forkChildErrReport(err_pipe[1], err); | 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 | |err| forkChildErrReport(err_pipe[1], err); | 301 | |err| forkChildErrReport(err_pipe[1], err); |
| 241 | } | 302 | } |
| 242 | 303 | ||
| ... | @@ -266,28 +327,22 @@ pub const ChildProcess = struct { | ... | @@ -266,28 +327,22 @@ pub const ChildProcess = struct { |
| 266 | }; | 327 | }; |
| 267 | } | 328 | } |
| 268 | 329 | ||
| 269 | *child = ChildProcess { | 330 | self.pid = pid; |
| 270 | .allocator = allocator, | 331 | self.err_pipe = err_pipe; |
| 271 | .pid = pid, | 332 | self.llnode = LinkedList(&ChildProcess).Node.init(self); |
| 272 | .err_pipe = err_pipe, | 333 | self.term = null; |
| 273 | .llnode = LinkedList(&ChildProcess).Node.init(child), | 334 | self.stdin = stdin_ptr; |
| 274 | .term = null, | 335 | self.stdout = stdout_ptr; |
| 275 | .onTerm = onTerm, | 336 | self.stderr = stderr_ptr; |
| 276 | .stdin = stdin_ptr, | ||
| 277 | .stdout = stdout_ptr, | ||
| 278 | .stderr = stderr_ptr, | ||
| 279 | }; | ||
| 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 | restore_SIGCHLD(); | 341 | restore_SIGCHLD(); |
| 284 | 342 | ||
| 285 | if (stdin == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); } | 343 | if (self.stdin_behavior == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); } |
| 286 | if (stdout == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); } | 344 | if (self.stdout_behavior == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); } |
| 287 | if (stderr == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); } | 345 | if (self.stderr_behavior == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); } |
| 288 | if (any_ignore) { os.posixClose(dev_null_fd); } | ||
| 289 | |||
| 290 | return child; | ||
| 291 | } | 346 | } |
| 292 | 347 | ||
| 293 | fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void { | 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,6 +20,8 @@ pub const line_sep = switch (builtin.os) { |
| 20 | 20 | ||
| 21 | pub const page_size = 4 * 1024; | 21 | pub const page_size = 4 * 1024; |
| 22 | 22 | ||
| 23 | pub const getUserId = @import("get_user_id.zig").getUserId; | ||
| 24 | |||
| 23 | const debug = @import("../debug.zig"); | 25 | const debug = @import("../debug.zig"); |
| 24 | const assert = debug.assert; | 26 | const assert = debug.assert; |
| 25 | 27 | ||
| ... | @@ -321,12 +323,12 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { | ... | @@ -321,12 +323,12 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { |
| 321 | /// This function must allocate memory to add a null terminating bytes on path and each arg. | 323 | /// This function must allocate memory to add a null terminating bytes on path and each arg. |
| 322 | /// It must also convert to KEY=VALUE\0 format for environment variables, and include null | 324 | /// It must also convert to KEY=VALUE\0 format for environment variables, and include null |
| 323 | /// pointers after the args and after the environment variables. | 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 | /// This function also uses the PATH environment variable to get the full path to the executable. | 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 | allocator: &Allocator) -> %void | 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 | mem.set(?&u8, argv_buf, null); | 332 | mem.set(?&u8, argv_buf, null); |
| 331 | defer { | 333 | defer { |
| 332 | for (argv_buf) |arg| { | 334 | for (argv_buf) |arg| { |
| ... | @@ -335,22 +337,14 @@ pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &con | ... | @@ -335,22 +337,14 @@ pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &con |
| 335 | } | 337 | } |
| 336 | allocator.free(argv_buf); | 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 | for (argv) |arg, i| { | 340 | for (argv) |arg, i| { |
| 347 | const arg_buf = %return allocator.alloc(u8, arg.len + 1); | 341 | const arg_buf = %return allocator.alloc(u8, arg.len + 1); |
| 348 | @memcpy(&arg_buf[0], arg.ptr, arg.len); | 342 | @memcpy(&arg_buf[0], arg.ptr, arg.len); |
| 349 | arg_buf[arg.len] = 0; | 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 | const envp_count = env_map.count(); | 349 | const envp_count = env_map.count(); |
| 356 | const envp_buf = %return allocator.alloc(?&u8, envp_count + 1); | 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,14 +372,9 @@ pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &con |
| 378 | } | 372 | } |
| 379 | envp_buf[envp_count] = null; | 373 | envp_buf[envp_count] = null; |
| 380 | 374 | ||
| 381 | 375 | const exe_path = argv[0]; | |
| 382 | if (mem.indexOfScalar(u8, exe_path, '/') != null) { | 376 | if (mem.indexOfScalar(u8, exe_path, '/') != null) { |
| 383 | // +1 for the null terminating byte | 377 | return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr))); |
| 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))); | ||
| 389 | } | 378 | } |
| 390 | 379 | ||
| 391 | const PATH = getEnv("PATH") ?? "/usr/local/bin:/bin/:/usr/bin"; | 380 | const PATH = getEnv("PATH") ?? "/usr/local/bin:/bin/:/usr/bin"; |
| ... | @@ -434,6 +423,7 @@ fn posixExecveErrnoToErr(err: usize) -> error { | ... | @@ -434,6 +423,7 @@ fn posixExecveErrnoToErr(err: usize) -> error { |
| 434 | 423 | ||
| 435 | pub var environ_raw: []&u8 = undefined; | 424 | pub var environ_raw: []&u8 = undefined; |
| 436 | 425 | ||
| 426 | /// Caller must free result when done. | ||
| 437 | pub fn getEnvMap(allocator: &Allocator) -> %BufMap { | 427 | pub fn getEnvMap(allocator: &Allocator) -> %BufMap { |
| 438 | var result = BufMap.init(allocator); | 428 | var result = BufMap.init(allocator); |
| 439 | %defer result.deinit(); | 429 | %defer result.deinit(); |
| ... | @@ -840,7 +830,7 @@ pub const Dir = struct { | ... | @@ -840,7 +830,7 @@ pub const Dir = struct { |
| 840 | start_over: | 830 | start_over: |
| 841 | if (self.index >= self.end_index) { | 831 | if (self.index >= self.end_index) { |
| 842 | if (self.buf.len == 0) { | 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 | while (true) { | 836 | while (true) { |
| ... | @@ -992,3 +982,20 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) { | ... | @@ -992,3 +982,20 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) { |
| 992 | test "os.sleep" { | 982 | test "os.sleep" { |
| 993 | sleep(0, 1); | 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,6 +480,10 @@ pub fn nanosleep(req: &const timespec, rem: ?&timespec) -> usize { |
| 480 | arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)) | 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 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { | 487 | pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { |
| 484 | arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8) | 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,7 +9,7 @@ pub fn build(b: &Builder) { |
| 9 | exe.setBuildMode(b.standardReleaseOptions()); | 9 | exe.setBuildMode(b.standardReleaseOptions()); |
| 10 | exe.setBuildMode(b.standardReleaseOptions()); | 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 | run.step.dependOn(&exe.step); | 13 | run.step.dependOn(&exe.step); |
| 14 | 14 | ||
| 15 | const test_step = b.step("test", "Test it"); | 15 | const test_step = b.step("test", "Test it"); |
test/tests.zig+43-24| ... | @@ -241,11 +241,15 @@ pub const CompareOutputContext = struct { | ... | @@ -241,11 +241,15 @@ pub const CompareOutputContext = struct { |
| 241 | 241 | ||
| 242 | %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); | 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, | 244 | const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator); |
| 245 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err| | 245 | defer child.deinit(); |
| 246 | { | 246 | |
| 247 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | 247 | child.stdin_behavior = StdIo.Ignore; |
| 248 | }; | 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 | var stdout = Buffer.initNull(b.allocator); | 254 | var stdout = Buffer.initNull(b.allocator); |
| 251 | var stderr = Buffer.initNull(b.allocator); | 255 | var stderr = Buffer.initNull(b.allocator); |
| ... | @@ -316,13 +320,15 @@ pub const CompareOutputContext = struct { | ... | @@ -316,13 +320,15 @@ pub const CompareOutputContext = struct { |
| 316 | 320 | ||
| 317 | %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); | 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, | 323 | const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator); |
| 320 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err| | 324 | defer child.deinit(); |
| 321 | { | ||
| 322 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | ||
| 323 | }; | ||
| 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 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | 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,6 +545,8 @@ pub const CompileErrorContext = struct { |
| 539 | const obj_path = %%os.path.join(b.allocator, b.cache_root, "test.o"); | 545 | const obj_path = %%os.path.join(b.allocator, b.cache_root, "test.o"); |
| 540 | 546 | ||
| 541 | var zig_args = ArrayList([]const u8).init(b.allocator); | 547 | var zig_args = ArrayList([]const u8).init(b.allocator); |
| 548 | %%zig_args.append(b.zig_exe); | ||
| 549 | |||
| 542 | %%zig_args.append(if (self.case.is_exe) "build-exe" else "build-obj"); | 550 | %%zig_args.append(if (self.case.is_exe) "build-exe" else "build-obj"); |
| 543 | %%zig_args.append(b.pathFromRoot(root_src)); | 551 | %%zig_args.append(b.pathFromRoot(root_src)); |
| 544 | 552 | ||
| ... | @@ -560,11 +568,15 @@ pub const CompileErrorContext = struct { | ... | @@ -560,11 +568,15 @@ pub const CompileErrorContext = struct { |
| 560 | printInvocation(b.zig_exe, zig_args.toSliceConst()); | 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, | 571 | const child = %%os.ChildProcess.init(zig_args.toSliceConst(), b.allocator); |
| 564 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err| | 572 | defer child.deinit(); |
| 565 | { | 573 | |
| 566 | debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); | 574 | child.env_map = &b.env_map; |
| 567 | }; | 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 | var stdout_buf = Buffer.initNull(b.allocator); | 581 | var stdout_buf = Buffer.initNull(b.allocator); |
| 570 | var stderr_buf = Buffer.initNull(b.allocator); | 582 | var stderr_buf = Buffer.initNull(b.allocator); |
| ... | @@ -573,7 +585,7 @@ pub const CompileErrorContext = struct { | ... | @@ -573,7 +585,7 @@ pub const CompileErrorContext = struct { |
| 573 | %%(??child.stderr).readAll(&stderr_buf); | 585 | %%(??child.stderr).readAll(&stderr_buf); |
| 574 | 586 | ||
| 575 | const term = child.wait() %% |err| { | 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 | switch (term) { | 590 | switch (term) { |
| 579 | Term.Exited => |code| { | 591 | Term.Exited => |code| { |
| ... | @@ -712,6 +724,7 @@ pub const BuildExamplesContext = struct { | ... | @@ -712,6 +724,7 @@ pub const BuildExamplesContext = struct { |
| 712 | } | 724 | } |
| 713 | 725 | ||
| 714 | var zig_args = ArrayList([]const u8).init(b.allocator); | 726 | var zig_args = ArrayList([]const u8).init(b.allocator); |
| 727 | %%zig_args.append(b.zig_exe); | ||
| 715 | %%zig_args.append("build"); | 728 | %%zig_args.append("build"); |
| 716 | 729 | ||
| 717 | %%zig_args.append("--build-file"); | 730 | %%zig_args.append("--build-file"); |
| ... | @@ -723,7 +736,7 @@ pub const BuildExamplesContext = struct { | ... | @@ -723,7 +736,7 @@ pub const BuildExamplesContext = struct { |
| 723 | %%zig_args.append("--verbose"); | 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 | const log_step = b.addLog("PASS {}\n", annotated_case_name); | 741 | const log_step = b.addLog("PASS {}\n", annotated_case_name); |
| 729 | log_step.step.dependOn(&run_cmd.step); | 742 | log_step.step.dependOn(&run_cmd.step); |
| ... | @@ -813,6 +826,8 @@ pub const ParseCContext = struct { | ... | @@ -813,6 +826,8 @@ pub const ParseCContext = struct { |
| 813 | const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename); | 826 | const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename); |
| 814 | 827 | ||
| 815 | var zig_args = ArrayList([]const u8).init(b.allocator); | 828 | var zig_args = ArrayList([]const u8).init(b.allocator); |
| 829 | %%zig_args.append(b.zig_exe); | ||
| 830 | |||
| 816 | %%zig_args.append("parsec"); | 831 | %%zig_args.append("parsec"); |
| 817 | %%zig_args.append(b.pathFromRoot(root_src)); | 832 | %%zig_args.append(b.pathFromRoot(root_src)); |
| 818 | 833 | ||
| ... | @@ -822,11 +837,15 @@ pub const ParseCContext = struct { | ... | @@ -822,11 +837,15 @@ pub const ParseCContext = struct { |
| 822 | printInvocation(b.zig_exe, zig_args.toSliceConst()); | 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, | 840 | const child = %%os.ChildProcess.init(zig_args.toSliceConst(), b.allocator); |
| 826 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err| | 841 | defer child.deinit(); |
| 827 | { | 842 | |
| 828 | debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); | 843 | child.env_map = &b.env_map; |
| 829 | }; | 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 | var stdout_buf = Buffer.initNull(b.allocator); | 850 | var stdout_buf = Buffer.initNull(b.allocator); |
| 832 | var stderr_buf = Buffer.initNull(b.allocator); | 851 | var stderr_buf = Buffer.initNull(b.allocator); |
| ... | @@ -835,7 +854,7 @@ pub const ParseCContext = struct { | ... | @@ -835,7 +854,7 @@ pub const ParseCContext = struct { |
| 835 | %%(??child.stderr).readAll(&stderr_buf); | 854 | %%(??child.stderr).readAll(&stderr_buf); |
| 836 | 855 | ||
| 837 | const term = child.wait() %% |err| { | 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 | switch (term) { | 859 | switch (term) { |
| 841 | Term.Exited => |code| { | 860 | Term.Exited => |code| { |