Add CGroupPtr

This commit is contained in:
Motiejus Jakštys 2022-04-19 07:18:41 +03:00 committed by Motiejus Jakštys
parent 3c507ffe08
commit d4ba5a9a58
6 changed files with 74 additions and 31 deletions

View File

@ -1,7 +0,0 @@
const CGroup = @This();
gid: u32,
name: [:0]const u8,
// Should be a sentinel-terminated array.
// https://github.com/ziglang/zig/issues/7517
members: []align(1) const ?[*:0]const u8,

View File

@ -46,12 +46,12 @@ pub fn init(
var getgr_bufsize: usize = 0;
for (groupsConst) |*group, i| {
groups_arr[i] = try group.clone(allocator);
getgr_bufsize = math.max(getgr_bufsize, groups_arr[i].strlenZ());
getgr_bufsize = math.max(getgr_bufsize, group.strlenZ());
}
var getpw_bufsize: usize = 0;
for (usersConst) |*user, i| {
users_arr[i] = try user.clone(allocator);
getpw_bufsize = math.max(getpw_bufsize, users_arr[i].strlenZ());
getpw_bufsize = math.max(getpw_bufsize, user.strlenZ());
}
sort.sort(User, users_arr, {}, cmpUser);

View File

@ -16,7 +16,7 @@ const pad = @import("padding.zig");
const compress = @import("compress.zig");
const PackedUser = @import("PackedUser.zig");
const User = @import("User.zig");
const CGroup = @import("CGroup.zig");
const CGroup = @import("cgroup.zig").CGroup;
const Group = @import("Group.zig");
const PackedGroup = @import("PackedGroup.zig");
const GroupStored = PackedGroup.GroupStored;
@ -267,13 +267,8 @@ fn getGroup(
};
}
// getgrtnam returns a Group entry by name. The Group must be
// deinit'ed by caller.
fn getgrnam(
self: *const DB,
name: []const u8,
buf: *[]u8,
) error{OutOfMemory}!?CGroup {
// get a CGroup entry by name.
fn getgrnam(self: *const DB, name: []const u8, buf: *[]u8) error{OutOfMemory}!?CGroup {
const idx = bdz.search(self.bdz_groupname, name);
const offset = self.idx_groupname2group[idx];
const group = PackedGroup.fromBytes(self.groups[offset << 3 ..]).group;
@ -591,26 +586,43 @@ test "read/write via iovec" {
}
test "high-level API" {
const allocator = testing.allocator;
var corpus = try Corpus.testCorpus(allocator);
var corpus = try Corpus.testCorpus(testing.allocator);
defer corpus.deinit();
var db = try DB.fromCorpus(testing.allocator, &corpus);
defer db.deinit(testing.allocator);
var buf = try testing.allocator.alloc(u8, db.header.getgr_bufsize);
defer testing.allocator.free(buf);
var db = try DB.fromCorpus(allocator, &corpus);
defer db.deinit(allocator);
// TODO: should accept a buffer instead of an allocator instead.
var buf = try allocator.alloc(u8, db.header.getgr_bufsize);
defer allocator.free(buf);
const all = try db.getgrnam("all", &buf);
try testing.expect(all != null);
try testing.expectEqual(all.?.gid, 9999);
try testing.expectEqualStrings(all.?.name, "all");
try testing.expectEqualStrings(mem.sliceTo(all.?.name, 0), "all");
const members = all.?.members;
try testing.expectEqualStrings(mem.sliceTo(members[0].?, 0), "Name" ** 8);
try testing.expectEqualStrings(mem.sliceTo(members[1].?, 0), "root");
try testing.expectEqualStrings(mem.sliceTo(members[2].?, 0), "svc-bar");
try testing.expectEqualStrings(mem.sliceTo(members[3].?, 0), "vidmantas");
try testing.expectEqual(members[4], null);
const cgroup = all.?.ptr();
try testing.expectEqual(cgroup.gid, all.?.gid);
try testing.expectEqual(cgroup.name[0], 'a');
try testing.expectEqual(cgroup.name[1], 'l');
try testing.expectEqual(cgroup.name[2], 'l');
try testing.expectEqual(cgroup.name[3], 0);
}
test "getgr_bufsize" {
var corpus = try Corpus.testCorpus(testing.allocator);
defer corpus.deinit();
var db = try DB.fromCorpus(testing.allocator, &corpus);
defer db.deinit(testing.allocator);
var buf = try testing.allocator.alloc(u8, db.header.getgr_bufsize);
defer testing.allocator.free(buf);
_ = try db.getgrnam("all", &buf);
buf.len -= 1;
try testing.expectError(error.OutOfMemory, db.getgrnam("all", &buf));
}
test "additionalGids" {

View File

@ -1,6 +1,8 @@
const std = @import("std");
const ptr_size = @import("cgroup.zig").ptr_size;
const mem = std.mem;
const meta = std.meta;
const Allocator = mem.Allocator;
const Group = @This();
@ -56,9 +58,12 @@ pub fn deinit(self: *Group, allocator: Allocator) void {
// buffer size in bytes if all strings were zero-terminated.
pub fn strlenZ(self: *const Group) usize {
return self._buf.len +
self.members.len + // each membername sentinel
1; // name sentinel
var count: usize = 0;
for (self.members) |member|
count += member.len + 1;
count += ptr_size * (self.members.len + 1);
count += self.name.len + 1;
return count;
}
const testing = std.testing;

32
lib/cgroup.zig Normal file
View File

@ -0,0 +1,32 @@
const meta = @import("std").meta;
// All string fields are 0-terminated, but that's not part of the type.
// members field is null-terminated, but that's also not part of the type.
// Making it part of the type crashes zig compiler in pre-0.10.
// https://github.com/ziglang/zig/issues/7517
pub const CGroup = struct {
gid: u32,
// should be [*:0]const u8
name: []const u8,
// Should be [*:null]align(1) const ?[*:0]const u8
members: []align(1) const ?[*:0]const u8,
pub fn ptr(self: *const CGroup) CGroupPtr {
return CGroupPtr{
.gid = self.gid,
.name = self.name.ptr,
.members = @intToPtr([*]const u8, @ptrToInt(self.members.ptr)),
};
}
};
// size of the pointer to a single member.
pub const ptr_size = @sizeOf(meta.Child(meta.fieldInfo(CGroup, .members).field_type));
// a workaround of not having sentinel-terminated `name` and `members`.
pub const CGroupPtr = extern struct {
gid: u32,
name: [*]const u8,
members: [*]const u8,
};

View File

@ -2,6 +2,7 @@ const std = @import("std");
const mem = std.mem;
const math = std.math;
const native_endian = @import("builtin").target.cpu.arch.endian();
const ptr_size = @import("cgroup.zig").ptr_size;
const max_shells = @import("shell.zig").max_shells;
const magic = [4]u8{ 0xf0, 0x9f, 0xa4, 0xb7 };
@ -33,7 +34,7 @@ pub const Header = packed struct {
magic: [4]u8 = magic,
version: u8 = version,
endian: Endian = Endian.native(),
ptr_size: u4 = @sizeOf(?[*:0]const u8),
ptr_size: u4 = ptr_size,
nblocks_shell_blob: u8,
num_shells: u8,
num_groups: u32,
@ -65,7 +66,7 @@ pub const Header = packed struct {
// when ptr size is larger than on the host that constructed it the DB,
// getgr_bufsize/getpw_bufsize may return insufficient values, causing
// OutOfMemory for getgr* and getpw* calls.
if (self.ptr_size < @sizeOf(?[*:0]const u8))
if (self.ptr_size < ptr_size)
return error.InvalidPointerSize;
return self;