finish(?) turbonss-getent
This commit is contained in:
parent
c4e84be1a9
commit
abf7edf14c
11
build.zig
11
build.zig
@ -80,6 +80,17 @@ pub fn build(b: *zbs.Builder) void {
|
||||
exe.install();
|
||||
}
|
||||
|
||||
{
|
||||
const exe = b.addExecutable("turbo-getent", "src/turbo-getent.zig");
|
||||
exe.strip = strip;
|
||||
exe.linkLibC();
|
||||
exe.linkLibrary(bdz);
|
||||
exe.addIncludeDir("deps/cmph/src");
|
||||
exe.setTarget(target);
|
||||
exe.setBuildMode(mode);
|
||||
exe.install();
|
||||
}
|
||||
|
||||
{
|
||||
const so = b.addSharedLibrary("nss_turbo", "src/libnss.zig", .{
|
||||
.versioned = builtin.Version{
|
||||
|
@ -36,7 +36,7 @@ members_offset: u64,
|
||||
|
||||
pub const Entry = struct {
|
||||
group: PackedGroup,
|
||||
next: ?[]const u8,
|
||||
end: usize,
|
||||
};
|
||||
|
||||
pub fn fromBytes(bytes: []const u8) Entry {
|
||||
@ -47,11 +47,6 @@ pub fn fromBytes(bytes: []const u8) Entry {
|
||||
error.Overflow => unreachable,
|
||||
};
|
||||
const end_blob = end_strings + members_offset.bytes_read;
|
||||
const next_start = pad.roundUp(usize, alignment_bits, end_blob);
|
||||
|
||||
var next: ?[]const u8 = null;
|
||||
if (next_start < bytes.len)
|
||||
next = bytes[next_start..];
|
||||
|
||||
return Entry{
|
||||
.group = PackedGroup{
|
||||
@ -59,7 +54,7 @@ pub fn fromBytes(bytes: []const u8) Entry {
|
||||
.groupdata = bytes[start_blob..end_strings],
|
||||
.members_offset = members_offset.value,
|
||||
},
|
||||
.next = next,
|
||||
.end = pad.roundUp(usize, alignment_bits, end_blob),
|
||||
};
|
||||
}
|
||||
|
||||
@ -69,20 +64,26 @@ fn validateUtf8(s: []const u8) InvalidRecord!void {
|
||||
}
|
||||
|
||||
pub const Iterator = struct {
|
||||
section: ?[]const u8,
|
||||
section: []const u8,
|
||||
nextStart: usize = 0,
|
||||
idx: u32 = 0,
|
||||
total: u32,
|
||||
|
||||
pub fn next(it: *Iterator) ?PackedGroup {
|
||||
if (it.section) |section| {
|
||||
const entry = fromBytes(section);
|
||||
it.section = entry.next;
|
||||
return entry.group;
|
||||
}
|
||||
return null;
|
||||
if (it.idx == it.total) return null;
|
||||
|
||||
const entry = fromBytes(it.section[it.nextStart..]);
|
||||
it.nextStart += entry.end;
|
||||
it.idx += 1;
|
||||
return entry.group;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn iterator(section: []const u8) Iterator {
|
||||
return Iterator{ .section = section };
|
||||
pub fn iterator(section: []const u8, total: u32) Iterator {
|
||||
return Iterator{
|
||||
.section = section,
|
||||
.total = total,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn gid(self: *const PackedGroup) u32 {
|
||||
@ -139,7 +140,7 @@ test "PackedGroup construct" {
|
||||
}
|
||||
|
||||
var i: u29 = 0;
|
||||
var it = PackedGroup.iterator(buf.items);
|
||||
var it = PackedGroup.iterator(buf.items, groups.len);
|
||||
while (it.next()) |group| : (i += 1) {
|
||||
try testing.expectEqual(groups[i].gid, group.gid());
|
||||
try testing.expectEqualStrings(groups[i].name, group.name());
|
||||
|
@ -111,8 +111,7 @@ pub const Iterator = struct {
|
||||
total: u32,
|
||||
|
||||
pub fn next(it: *Iterator) ?PackedUser {
|
||||
if (it.idx == it.total)
|
||||
return null;
|
||||
if (it.idx == it.total) return null;
|
||||
|
||||
const entry = PackedUser.fromBytes(it.section[it.nextStart..]);
|
||||
it.nextStart += entry.end;
|
||||
|
@ -296,6 +296,7 @@ fn setgrent(state: *State) void {
|
||||
defer state.getgrent_iterator_mu.unlock();
|
||||
state.getgrent_iterator = PackedGroup.iterator(
|
||||
state.file.db.groups,
|
||||
state.file.db.header.num_groups,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ const flags = @import("flags.zig");
|
||||
const DB = @import("DB.zig");
|
||||
const File = @import("File.zig");
|
||||
const PackedUser = @import("PackedUser.zig");
|
||||
const PackedGroup = @import("PackedGroup.zig");
|
||||
const User = @import("User.zig");
|
||||
|
||||
const Mode = enum { group, passwd };
|
||||
@ -100,7 +101,7 @@ fn execute(
|
||||
|
||||
fn passwd(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) u8 {
|
||||
if (keys.len == 0)
|
||||
return passwd_all(stdout, db);
|
||||
return passwdAll(stdout, db);
|
||||
var some_notfound = false;
|
||||
const shell_reader = db.shellReader();
|
||||
for (keys) |key| {
|
||||
@ -122,7 +123,7 @@ fn passwd(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) u8 {
|
||||
return if (some_notfound) 2 else 0;
|
||||
}
|
||||
|
||||
fn passwd_all(stdout: anytype, db: *const DB) u8 {
|
||||
fn passwdAll(stdout: anytype, db: *const DB) u8 {
|
||||
const shell_reader = db.shellReader();
|
||||
var it = PackedUser.iterator(db.users, db.header.num_users, shell_reader);
|
||||
while (it.next()) |packed_user| {
|
||||
@ -134,7 +135,7 @@ fn passwd_all(stdout: anytype, db: *const DB) u8 {
|
||||
|
||||
fn group(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) u8 {
|
||||
if (keys.len == 0)
|
||||
return group_all(stdout, db);
|
||||
return groupAll(stdout, db);
|
||||
var some_notfound = false;
|
||||
|
||||
for (keys) |key| {
|
||||
@ -149,38 +150,48 @@ fn group(stdout: anytype, db: *const DB, keys: []const [*:0]const u8) u8 {
|
||||
continue;
|
||||
};
|
||||
|
||||
// not converting to Group to save a few memory allocations.
|
||||
stdout.print("{s}:x:{d}:", .{ g.name(), g.gid() }) catch return 3;
|
||||
|
||||
// TODO: move member iteration from here and DB.packCGroup
|
||||
// to a common place.
|
||||
const members_slice = db.groupmembers[g.members_offset..];
|
||||
var vit = compress.varintSliceIteratorMust(members_slice);
|
||||
var it = compress.deltaDecompressionIterator(&vit);
|
||||
|
||||
// lines will be buffered, but flushed on every EOL.
|
||||
var line_writer = io.bufferedWriter(stdout);
|
||||
var i: usize = 0;
|
||||
while (it.nextMust()) |member_offset| : (i += 1) {
|
||||
const puser = PackedUser.fromBytes(db.users[member_offset << 3 ..]);
|
||||
const name = puser.user.name();
|
||||
if (i != 0)
|
||||
_ = line_writer.write(",") catch return 3;
|
||||
_ = line_writer.write(name) catch return 3;
|
||||
}
|
||||
_ = line_writer.write("\n") catch return 3;
|
||||
line_writer.flush() catch return 3;
|
||||
if (printGroup(stdout, db, &g)) |exit_code|
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
return if (some_notfound) 2 else 0;
|
||||
}
|
||||
|
||||
fn group_all(stdout: anytype, db: *const DB) u8 {
|
||||
_ = stdout;
|
||||
_ = db;
|
||||
fn groupAll(stdout: anytype, db: *const DB) u8 {
|
||||
var it = PackedGroup.iterator(db.groups, db.header.num_groups);
|
||||
while (it.next()) |g|
|
||||
if (printGroup(stdout, db, &g)) |exit_code|
|
||||
return exit_code;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn printGroup(stdout: anytype, db: *const DB, g: *const PackedGroup) ?u8 {
|
||||
// not converting to Group to save a few memory allocations.
|
||||
stdout.print("{s}:x:{d}:", .{ g.name(), g.gid() }) catch return 3;
|
||||
|
||||
// TODO: move member iteration from here and DB.packCGroup
|
||||
// to a common place.
|
||||
const members_slice = db.groupmembers[g.members_offset..];
|
||||
var vit = compress.varintSliceIteratorMust(members_slice);
|
||||
var it = compress.deltaDecompressionIterator(&vit);
|
||||
|
||||
// lines will be buffered, but flushed on every EOL.
|
||||
var line_writer = io.bufferedWriter(stdout);
|
||||
var i: usize = 0;
|
||||
while (it.nextMust()) |member_offset| : (i += 1) {
|
||||
const puser = PackedUser.fromBytes(db.users[member_offset << 3 ..]);
|
||||
const name = puser.user.name();
|
||||
if (i != 0)
|
||||
_ = line_writer.write(",") catch return 3;
|
||||
_ = line_writer.write(name) catch return 3;
|
||||
}
|
||||
_ = line_writer.write("\n") catch return 3;
|
||||
line_writer.flush() catch return 3;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const testing = std.testing;
|
||||
|
||||
test "turbo-getent passwd" {
|
||||
@ -213,7 +224,7 @@ test "turbo-getent passwd" {
|
||||
}
|
||||
}
|
||||
|
||||
test "turbo-getent passwd_all" {
|
||||
test "turbo-getent passwdAll" {
|
||||
var tf = try File.TestDB.init(testing.allocator);
|
||||
defer tf.deinit();
|
||||
var stdout = ArrayList(u8).init(testing.allocator);
|
||||
@ -278,3 +289,30 @@ test "turbo-getent group" {
|
||||
try testing.expectEqualStrings(want, stdout.items);
|
||||
}
|
||||
}
|
||||
|
||||
test "turbo-getent groupAll" {
|
||||
var tf = try File.TestDB.init(testing.allocator);
|
||||
defer tf.deinit();
|
||||
var stdout = ArrayList(u8).init(testing.allocator);
|
||||
defer stdout.deinit();
|
||||
var stderr = ArrayList(u8).init(testing.allocator);
|
||||
defer stderr.deinit();
|
||||
|
||||
{
|
||||
const args = &[_][*:0]const u8{
|
||||
"--db",
|
||||
tf.path,
|
||||
"group",
|
||||
};
|
||||
const got = execute(stdout.writer(), stderr.writer(), args);
|
||||
try testing.expectEqual(got, 0);
|
||||
const want =
|
||||
\\root:x:0:
|
||||
\\vidmantas:x:128:
|
||||
\\all:x:9999:NameNameNameNameNameNameNameName,root,svc-bar,vidmantas
|
||||
\\service-group:x:100000:root,vidmantas
|
||||
\\
|
||||
;
|
||||
try testing.expectEqualStrings(want, stdout.items);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user