2022-05-25 09:42:42 +03:00
|
|
|
const std = @import("std");
|
2022-06-05 23:56:45 +03:00
|
|
|
const fs = std.fs;
|
|
|
|
const io = std.io;
|
|
|
|
const mem = std.mem;
|
|
|
|
const os = std.os;
|
|
|
|
const ArrayList = std.ArrayList;
|
|
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator;
|
|
|
|
|
2022-05-25 09:42:42 +03:00
|
|
|
const flags = @import("../flags.zig");
|
2022-06-05 23:56:45 +03:00
|
|
|
const User = @import("../User.zig");
|
2022-06-07 05:32:21 +03:00
|
|
|
const Group = @import("../Group.zig");
|
2022-06-07 05:59:00 +03:00
|
|
|
const Corpus = @import("../Corpus.zig");
|
|
|
|
const DB = @import("../DB.zig");
|
2022-06-05 23:56:45 +03:00
|
|
|
|
|
|
|
const usage =
|
|
|
|
\\usage: turbonss-unix2db [options]
|
|
|
|
\\
|
|
|
|
\\ -h Print this help message and exit
|
|
|
|
\\ --passwd Path to passwd file (default: ./passwd)
|
|
|
|
\\ --group Path to group file (default: ./group)
|
|
|
|
\\
|
|
|
|
;
|
|
|
|
|
|
|
|
pub fn main() !void {
|
|
|
|
// This line is here because of https://github.com/ziglang/zig/issues/7807
|
|
|
|
const argv: []const [*:0]const u8 = os.argv;
|
|
|
|
const gpa = GeneralPurposeAllocator(.{});
|
|
|
|
|
|
|
|
const return_code = execute(gpa, argv[1..]) catch |err| {
|
|
|
|
try io.getStdErr().writeAll("uncaught error: {s}\n", @intToError(err));
|
|
|
|
os.exit(1);
|
|
|
|
};
|
|
|
|
|
|
|
|
os.exit(return_code);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn execute(
|
|
|
|
allocator: Allocator,
|
|
|
|
stderr: anytype,
|
|
|
|
argv: []const [*:0]const u8,
|
|
|
|
) !u8 {
|
|
|
|
const result = flags.parse(argv, &[_]flags.Flag{
|
|
|
|
.{ .name = "-h", .kind = .boolean },
|
|
|
|
.{ .name = "--passwd", .kind = .arg },
|
|
|
|
.{ .name = "--group", .kind = .arg },
|
2022-06-07 05:59:00 +03:00
|
|
|
.{ .name = "--output", .kind = .arg },
|
2022-06-05 23:56:45 +03:00
|
|
|
}) catch {
|
|
|
|
try stderr.writeAll(usage);
|
|
|
|
return 1;
|
|
|
|
};
|
2022-05-25 09:42:42 +03:00
|
|
|
|
2022-06-05 23:56:45 +03:00
|
|
|
if (result.boolFlag("-h")) {
|
|
|
|
try io.getStdOut().writeAll(usage);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.args.len != 0) {
|
|
|
|
try stderr.print("ERROR: unknown option '{s}'\n", .{result.args[0]});
|
|
|
|
try stderr.writeAll(usage);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-07 05:59:00 +03:00
|
|
|
const passwdFname = result.argFlag("--passwd") orelse "./passwd";
|
|
|
|
const groupFname = result.argFlag("--group") orelse "./group";
|
|
|
|
const outFile = result.argFlag("--output") orelse "./db.turbo";
|
2022-06-05 23:56:45 +03:00
|
|
|
|
2022-06-07 13:14:50 +03:00
|
|
|
std.debug.print("passwd file name: {s}\n", .{passwdFname});
|
2022-06-07 05:59:00 +03:00
|
|
|
var passwdFile = try fs.cwd().openFile(passwdFname, .{ .mode = .read_only });
|
2022-06-05 23:56:45 +03:00
|
|
|
defer passwdFile.close();
|
2022-06-07 05:59:00 +03:00
|
|
|
var groupFile = try fs.cwd().openFile(groupFname, .{ .mode = .read_only });
|
2022-06-05 23:56:45 +03:00
|
|
|
defer groupFile.close();
|
|
|
|
|
|
|
|
var users = try User.fromReader(allocator, passwdFile.reader());
|
2022-06-07 05:59:00 +03:00
|
|
|
defer for (users) |*user| user.deinit(allocator);
|
2022-06-12 13:38:10 +03:00
|
|
|
defer allocator.free(users);
|
2022-06-07 05:32:21 +03:00
|
|
|
var groups = try Group.fromReader(allocator, groupFile.reader());
|
2022-06-07 05:59:00 +03:00
|
|
|
defer for (groups) |*group| group.deinit(allocator);
|
2022-06-12 13:38:10 +03:00
|
|
|
defer allocator.free(groups);
|
2022-06-05 23:56:45 +03:00
|
|
|
|
2022-06-07 05:59:00 +03:00
|
|
|
var corpus = try Corpus.init(allocator, users, groups);
|
|
|
|
defer corpus.deinit();
|
|
|
|
var db = try DB.fromCorpus(allocator, &corpus);
|
|
|
|
defer db.deinit(allocator);
|
|
|
|
|
2022-06-07 13:14:50 +03:00
|
|
|
const fd = try os.open(outFile, os.O.WRONLY | os.O.TRUNC | os.O.CREAT, 0644);
|
2022-06-07 05:59:00 +03:00
|
|
|
errdefer os.close(fd);
|
|
|
|
|
|
|
|
const len = try os.writev(fd, db.iov().constSlice());
|
|
|
|
try os.fsync(fd);
|
|
|
|
os.close(fd);
|
|
|
|
|
|
|
|
try stderr.print("total {d} bytes. groups={d} users={d}\n", .{
|
|
|
|
len,
|
|
|
|
users.len,
|
|
|
|
groups.len,
|
|
|
|
});
|
2022-06-05 23:56:45 +03:00
|
|
|
return 0;
|
|
|
|
}
|
2022-05-25 09:42:42 +03:00
|
|
|
|
|
|
|
const testing = std.testing;
|
|
|
|
|
2022-06-05 23:56:45 +03:00
|
|
|
test "invalid argument" {
|
|
|
|
const allocator = testing.allocator;
|
|
|
|
const args = &[_][*:0]const u8{"--invalid-argument"};
|
|
|
|
var stderr = ArrayList(u8).init(allocator);
|
|
|
|
defer stderr.deinit();
|
|
|
|
|
|
|
|
const exit_code = try execute(allocator, stderr.writer(), args[0..]);
|
|
|
|
try testing.expectEqual(@as(u8, 1), exit_code);
|
2022-06-07 05:59:00 +03:00
|
|
|
try testing.expect(mem.startsWith(
|
|
|
|
u8,
|
|
|
|
stderr.items,
|
|
|
|
"ERROR: unknown option '--invalid-argument'",
|
|
|
|
));
|
2022-05-25 09:42:42 +03:00
|
|
|
}
|
2022-06-07 05:59:00 +03:00
|
|
|
|
2022-06-07 06:30:18 +03:00
|
|
|
test "smoke test" {
|
2022-06-12 13:27:12 +03:00
|
|
|
if (true) return error.SkipZigTest;
|
|
|
|
|
2022-06-07 06:30:18 +03:00
|
|
|
const allocator = testing.allocator;
|
|
|
|
var stderr = ArrayList(u8).init(allocator);
|
|
|
|
defer stderr.deinit();
|
2022-06-07 13:14:50 +03:00
|
|
|
|
|
|
|
var corpus = try Corpus.testCorpus(allocator);
|
|
|
|
defer corpus.deinit();
|
|
|
|
|
|
|
|
var tmp = testing.tmpDir(.{});
|
2022-06-12 13:27:12 +03:00
|
|
|
errdefer tmp.cleanup();
|
2022-06-07 13:14:50 +03:00
|
|
|
|
|
|
|
const tmp_path = blk: {
|
|
|
|
const relative_path = try fs.path.join(allocator, &[_][]const u8{
|
|
|
|
"zig-cache",
|
|
|
|
"tmp",
|
|
|
|
tmp.sub_path[0..],
|
|
|
|
});
|
|
|
|
const real_path = try fs.realpathAlloc(allocator, relative_path);
|
|
|
|
allocator.free(relative_path);
|
|
|
|
break :blk real_path;
|
|
|
|
};
|
|
|
|
defer allocator.free(tmp_path);
|
|
|
|
|
|
|
|
const passwdPath = try fs.path.joinZ(allocator, &[_][]const u8{ tmp_path, "passwd" });
|
|
|
|
defer allocator.free(passwdPath);
|
|
|
|
const groupPath = try fs.path.joinZ(allocator, &[_][]const u8{ tmp_path, "group" });
|
|
|
|
defer allocator.free(groupPath);
|
|
|
|
const outPath = try fs.path.joinZ(allocator, &[_][]const u8{ tmp_path, "tmp.turbo" });
|
|
|
|
defer allocator.free(outPath);
|
|
|
|
|
|
|
|
const passwd_fd = try os.open(passwdPath, os.O.CREAT | os.O.WRONLY, 0o644);
|
|
|
|
const group_fd = try os.open(groupPath, os.O.CREAT | os.O.WRONLY, 0o644);
|
|
|
|
|
|
|
|
var i: usize = 0;
|
|
|
|
while (i < corpus.users.len) : (i += 1) {
|
|
|
|
const user = corpus.users.get(i);
|
|
|
|
const line = user.toLine();
|
|
|
|
_ = try os.write(passwd_fd, line.constSlice());
|
|
|
|
}
|
|
|
|
os.close(passwd_fd);
|
|
|
|
|
|
|
|
var group_writer = (fs.File{ .handle = group_fd }).writer();
|
|
|
|
i = 0;
|
|
|
|
while (i < corpus.groups.len) : (i += 1)
|
|
|
|
try corpus.groups.get(i).writeTo(group_writer);
|
|
|
|
os.close(group_fd);
|
|
|
|
|
|
|
|
const args = &[_][*:0]const u8{
|
|
|
|
"--passwd", passwdPath,
|
|
|
|
"--group", groupPath,
|
|
|
|
"--output", outPath,
|
|
|
|
};
|
|
|
|
const exit_code = try execute(allocator, stderr.writer(), args);
|
|
|
|
|
|
|
|
try testing.expectEqual(@as(u8, 0), exit_code);
|
2022-06-07 06:30:18 +03:00
|
|
|
}
|