wip libnss
This commit is contained in:
parent
4e9f609131
commit
efdc919195
@ -178,6 +178,6 @@ test "trivial error: db file" {
|
|||||||
try testing.expectEqual(@as(u8, 1), exit_code);
|
try testing.expectEqual(@as(u8, 1), exit_code);
|
||||||
try testing.expectEqualStrings(
|
try testing.expectEqualStrings(
|
||||||
stderr.items,
|
stderr.items,
|
||||||
"ERROR: failed to open './db.turbo': FileNotFound\n",
|
"ERROR: failed to open 'db.turbo': FileNotFound\n",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
123
src/libnss.zig
123
src/libnss.zig
@ -1,8 +1,10 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const os = std.os;
|
const os = std.os;
|
||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
|
const log = std.log;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const process = std.process;
|
const process = std.process;
|
||||||
|
const once = std.once;
|
||||||
|
|
||||||
const DB = @import("DB.zig");
|
const DB = @import("DB.zig");
|
||||||
const File = @import("File.zig");
|
const File = @import("File.zig");
|
||||||
@ -16,92 +18,61 @@ const c = @cImport({
|
|||||||
@cInclude("nss.h");
|
@cInclude("nss.h");
|
||||||
});
|
});
|
||||||
|
|
||||||
const TURBONSS_DB = "DB";
|
const ENV_DB = "TURBONSS_DB";
|
||||||
const TURBONSS_VERBOSE = "TURBONSS_VERBOSE";
|
const ENV_VERBOSE = "TURBONSS__VERBOSE";
|
||||||
const TURBONSS_OMIT_MEMBERS = "TURBONSS_OMIT_MEMBERS";
|
const ENV_OMIT_MEMBERS = "TURBONSS_OMIT_MEMBERS";
|
||||||
|
|
||||||
extern fn putenv(name: [*:0]const u8, value: [*:0]const u8, overwrite: c_int) c_int;
|
|
||||||
extern fn getenv(name: [*:0]const u8) ?[*:0]const u8;
|
|
||||||
|
|
||||||
export const turbonss_default_path: [:0]const u8 = "/etc/turbonss/db.turbo";
|
export const turbonss_default_path: [:0]const u8 = "/etc/turbonss/db.turbo";
|
||||||
|
|
||||||
|
pub var log_level: std.log.Level = .err;
|
||||||
|
|
||||||
// State is a type of the global variable holding the process state:
|
// State is a type of the global variable holding the process state:
|
||||||
// the DB handle and all the iterators.
|
// the DB handle and all the iterators.
|
||||||
const State = struct {
|
const State = struct {
|
||||||
file: ?File,
|
file: ?File,
|
||||||
getpwent_iterator: ?PackedUser.Iterator,
|
getpwent_iterator: ?PackedUser.Iterator = null,
|
||||||
getgrent_iterator: ?PackedGroup.Iterator,
|
getgrent_iterator: ?PackedGroup.Iterator = null,
|
||||||
omit_members: bool,
|
omit_members: bool,
|
||||||
verbose: bool = false,
|
|
||||||
|
|
||||||
fn debug(self: *const State, comptime format: []const u8, args: anytype) void {
|
|
||||||
self.log(.debug, format, args);
|
|
||||||
}
|
|
||||||
fn info(self: *const State, comptime format: []const u8, args: anytype) void {
|
|
||||||
self.log(.info, format, args);
|
|
||||||
}
|
|
||||||
fn err(self: *const State, comptime format: []const u8, args: anytype) void {
|
|
||||||
self.log(.err, format, args);
|
|
||||||
}
|
|
||||||
fn log(
|
|
||||||
self: *const State,
|
|
||||||
comptime level: std.log.Level,
|
|
||||||
comptime format: []const u8,
|
|
||||||
args: anytype,
|
|
||||||
) void {
|
|
||||||
if (!self.verbose) return;
|
|
||||||
const stderr = std.io.getStdErr().writer();
|
|
||||||
std.debug.getStderrMutex().lock();
|
|
||||||
defer std.debug.getStderrMutex().unlock();
|
|
||||||
stderr.print("[" ++ level.asText() ++ "] " ++ format ++ "\n", args) catch return;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// state is initialized on library startup.
|
// global_state is initialized on first call to an nss function
|
||||||
var state: State = undefined;
|
var global_state: State = undefined;
|
||||||
|
var global_start = once(init);
|
||||||
|
|
||||||
// constructor
|
// assigns State from environment variables et al
|
||||||
export fn _turbo_init() void {
|
fn init() void {
|
||||||
//if (os.getenvZ(TURBONSS_VERBOSE)) |env|
|
if (os.getenvZ(ENV_VERBOSE)) |env|
|
||||||
// state.verbose = mem.eql(u8, env, "1");
|
log_level = if (mem.eql(u8, mem.sliceTo(env, 0), "1"))
|
||||||
|
.debug
|
||||||
|
else
|
||||||
|
.err;
|
||||||
|
|
||||||
if (getenv(TURBONSS_VERBOSE)) |env| {
|
const fname = os.getenvZ(ENV_DB) orelse turbonss_default_path[0..];
|
||||||
const envZ = mem.sliceTo(env, 0);
|
log.debug("opening {s}", .{fname});
|
||||||
state.verbose = mem.eql(u8, envZ, "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
//std.debug.print("TURBONSS_VERBOSE: {s}\n", .{os.getenv(TURBONSS_VERBOSE)});
|
const env_omit_members = os.getenvZ(ENV_OMIT_MEMBERS) orelse "auto";
|
||||||
std.debug.print("TURBONSS_VERBOSE: {s}\n", .{getenv(TURBONSS_VERBOSE)});
|
const omit_members = shouldOmitMembers(env_omit_members, os.argv);
|
||||||
|
log.debug("omitting members from getgr* calls: {any}\n", .{omit_members});
|
||||||
|
|
||||||
const fname = os.getenvZ(TURBONSS_DB) orelse turbonss_default_path[0..];
|
const file = File.open(fname) catch |err| {
|
||||||
state.debug("opening {s}", .{fname});
|
log.warn("open '{s}': {s}", .{ fname, @errorName(err) });
|
||||||
state.file = File.open(fname) catch |err| {
|
|
||||||
state.err("open {s}: {s}", .{ fname, @errorName(err) });
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
state.debug("turbonss database opened", .{});
|
log.debug("turbonss database opened", .{});
|
||||||
|
|
||||||
const omit_members_env = os.getenvZ(TURBONSS_OMIT_MEMBERS) orelse "auto";
|
global_state = State{
|
||||||
state.omit_members = shouldOmitMembers(omit_members_env, os.argv);
|
.file = file,
|
||||||
state.debug("omitting members from getgr* calls: {any}\n", .{state.omit_members});
|
.omit_members = omit_members,
|
||||||
|
};
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shouldOmitMembers(env: []const u8, argv: [][*:0]u8) bool {
|
fn shouldOmitMembers(envvar: []const u8, argv: [][*:0]u8) bool {
|
||||||
if (mem.eql(u8, env, "1")) return true;
|
if (mem.eql(u8, envvar, "1")) return true;
|
||||||
if (mem.eql(u8, env, "0")) return false;
|
if (mem.eql(u8, envvar, "0")) return false;
|
||||||
if (argv.len == 0) return false;
|
if (argv.len == 0) return false;
|
||||||
|
|
||||||
return mem.eql(u8, mem.sliceTo(argv[0], 0), "id");
|
return mem.eql(u8, mem.sliceTo(argv[0], 0), "id");
|
||||||
}
|
}
|
||||||
|
|
||||||
// destructor
|
|
||||||
export fn _turbo_fini() void {
|
|
||||||
if (state.file) |*fooo|
|
|
||||||
fooo.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn _nss_turbo_getpwuid_r(
|
export fn _nss_turbo_getpwuid_r(
|
||||||
uid: c_uint,
|
uid: c_uint,
|
||||||
res: *CUser,
|
res: *CUser,
|
||||||
@ -109,11 +80,16 @@ export fn _nss_turbo_getpwuid_r(
|
|||||||
len: usize,
|
len: usize,
|
||||||
errnop: *c_int,
|
errnop: *c_int,
|
||||||
) c.enum_nss_status {
|
) c.enum_nss_status {
|
||||||
if (state.file == null) {
|
global_start.call();
|
||||||
|
|
||||||
|
if (global_state.file == null) {
|
||||||
errnop.* = @enumToInt(os.E.AGAIN);
|
errnop.* = @enumToInt(os.E.AGAIN);
|
||||||
return c.NSS_STATUS_UNAVAIL;
|
return c.NSS_STATUS_UNAVAIL;
|
||||||
}
|
}
|
||||||
const cuser = state.file.?.db.getpwuid(uid, buf[0..len]) catch |err| switch (err) {
|
|
||||||
|
const db = global_state.file.?.db;
|
||||||
|
|
||||||
|
const cuser = db.getpwuid(uid, buf[0..len]) catch |err| switch (err) {
|
||||||
error.OutOfMemory => {
|
error.OutOfMemory => {
|
||||||
errnop.* = @enumToInt(os.E.RANGE);
|
errnop.* = @enumToInt(os.E.RANGE);
|
||||||
return c.NSS_STATUS_TRYAGAIN;
|
return c.NSS_STATUS_TRYAGAIN;
|
||||||
@ -135,21 +111,4 @@ test "nss_turbo_getpwuid_r" {
|
|||||||
var errc = ErrCtx{};
|
var errc = ErrCtx{};
|
||||||
var tf = try File.TestDB.init(testing.allocator, &errc);
|
var tf = try File.TestDB.init(testing.allocator, &errc);
|
||||||
defer tf.deinit();
|
defer tf.deinit();
|
||||||
|
|
||||||
var env = try process.getEnvMap(testing.allocator);
|
|
||||||
defer env.deinit();
|
|
||||||
|
|
||||||
if (true)
|
|
||||||
return error.SkipZigTest;
|
|
||||||
|
|
||||||
try testing.expectEqual(putenv(TURBONSS_VERBOSE, "1", 1), 0);
|
|
||||||
try testing.expectEqual(putenv(TURBONSS_DB, tf.path, 1), 0);
|
|
||||||
_turbo_init();
|
|
||||||
try testing.expect(state.file != null);
|
|
||||||
|
|
||||||
var buf = try testing.allocator.alloc(u8, state.file.?.db.getpwBufsize());
|
|
||||||
var user: CUser = undefined;
|
|
||||||
var errno: c_int = undefined;
|
|
||||||
const ret = _nss_turbo_getpwuid_r(128, &user, buf.ptr, buf.len, &errno);
|
|
||||||
try testing.expectEqual(ret, c.NSS_STATUS_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ test "trivial error: missing passwd file" {
|
|||||||
|
|
||||||
const exit_code = execute(allocator, stdout.writer(), stderr.writer(), args[0..]);
|
const exit_code = execute(allocator, stdout.writer(), stderr.writer(), args[0..]);
|
||||||
try testing.expectEqual(@as(u8, 1), exit_code);
|
try testing.expectEqual(@as(u8, 1), exit_code);
|
||||||
try testing.expectEqualStrings(stderr.items, "ERROR FileNotFound: open './passwd'\n");
|
try testing.expectEqualStrings(stderr.items, "ERROR FileNotFound: open 'passwd'\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fail" {
|
test "fail" {
|
||||||
|
Loading…
Reference in New Issue
Block a user