199 lines
5.3 KiB
Zig
199 lines
5.3 KiB
Zig
const std = @import("std");
|
|
const cmsghdr = @import("cmsghdr.zig");
|
|
|
|
pub const Facility = enum(u5) {
|
|
KERN = 0,
|
|
USER = 1,
|
|
MAIL = 2,
|
|
DAEMON = 3,
|
|
AUTH = 4,
|
|
SYSLOG = 5,
|
|
LPR = 6,
|
|
NEWS = 7,
|
|
UUCP = 8,
|
|
CRON = 9,
|
|
AUTHPRIV = 10,
|
|
FTP = 11,
|
|
LOCAL0 = 16,
|
|
LOCAL1 = 17,
|
|
LOCAL2 = 18,
|
|
LOCAL3 = 19,
|
|
LOCAL4 = 20,
|
|
LOCAL5 = 21,
|
|
LOCAL6 = 22,
|
|
LOCAL7 = 23,
|
|
};
|
|
|
|
pub const Priority = enum(u3) {
|
|
EMERG = 0,
|
|
ALERT = 1,
|
|
CRIT = 2,
|
|
ERR = 3,
|
|
WARNING = 4,
|
|
NOTICE = 5,
|
|
INFO = 6,
|
|
DEBUG = 7,
|
|
};
|
|
|
|
const JOURNAL_SOCKET: []const u8 = "/run/systemd/journal/socket";
|
|
|
|
const SCM_RIGHTS = 1;
|
|
|
|
const F_ADD_SEALS = 1033;
|
|
|
|
const F_SEAL_SEAL = 0x0001;
|
|
const F_SEAL_SHRINK = 0x0002;
|
|
const F_SEAL_GROW = 0x0004;
|
|
const F_SEAL_WRITE = 0x0008;
|
|
const F_SEAL_FUTURE_WRITE = 0x0010;
|
|
const F_SEAL_EXEC = 0x0020;
|
|
|
|
const MFD_NOEXEC_SEAL = 0x0008;
|
|
|
|
pub const Logger = struct {
|
|
const Self = @This();
|
|
|
|
identifier: ?[]const u8,
|
|
socket: std.os.socket_t,
|
|
path: std.os.sockaddr.un = undefined,
|
|
|
|
pub fn init(identifier: ?[]const u8) !Logger {
|
|
var logger = Logger{
|
|
.identifier = identifier,
|
|
.socket = try std.os.socket(std.os.AF.UNIX, std.os.SOCK.DGRAM | std.os.SOCK.CLOEXEC, 0),
|
|
};
|
|
errdefer std.os.close(logger.socket);
|
|
|
|
logger.path.family = std.os.AF.UNIX;
|
|
@memset(logger.path.path[0..logger.path.path.len], 0);
|
|
@memcpy(logger.path.path[0..JOURNAL_SOCKET.len], JOURNAL_SOCKET);
|
|
|
|
return logger;
|
|
}
|
|
|
|
pub fn deinit(self: Self) void {
|
|
std.os.close(self.socket);
|
|
}
|
|
|
|
const Message = struct {
|
|
logger: Logger,
|
|
priority: Priority,
|
|
memfd: std.os.fd_t,
|
|
|
|
fn _writeString(self: Message, str: []const u8) !void {
|
|
const len = try std.os.write(self.memfd, str);
|
|
if (len != str.len) return error.ShortWrite;
|
|
}
|
|
|
|
fn _writeU64(self: Message, native: u64) !void {
|
|
const le = std.mem.nativeToLittle(u64, native);
|
|
const msg = std.mem.asBytes(&le);
|
|
try self._writeString(msg);
|
|
}
|
|
|
|
pub fn string(self: Message, key: []const u8, value: []const u8) !void {
|
|
try self._writeString(key);
|
|
try self._writeString("\n");
|
|
try self._writeU64(value.len);
|
|
try self._writeString(value);
|
|
try self._writeString("\n");
|
|
}
|
|
|
|
pub fn int(self: Message, key: []const u8, value: anytype) !void {
|
|
if (@typeInfo(@TypeOf(value)) != .Int) @compileError("type " ++ @typeName(@TypeOf(value)) ++ " is not an integer type");
|
|
|
|
var buf: [32]u8 = undefined;
|
|
var fbs = std.io.fixedBufferStream(&buf);
|
|
const writer = fbs.writer();
|
|
try std.fmt.formatInt(value, 10, .lower, .{}, writer);
|
|
try self.string(key, fbs.getWritten());
|
|
}
|
|
|
|
pub fn identifier(self: Message, value: []const u8) !void {
|
|
try self.string("SYSLOG_IDENTIFIER", value);
|
|
}
|
|
|
|
pub fn facility(self: Message, value: Facility) !void {
|
|
try self.int("SYSLOG_FACILITY", @intFromEnum(value));
|
|
}
|
|
|
|
pub fn src(self: Message, loc: std.builtin.SourceLocation) !void {
|
|
try self.string("CODE_FILE", loc.file);
|
|
try self.string("CODE_FUNC", loc.fn_name);
|
|
try self.int("CODE_LINE", loc.line);
|
|
}
|
|
|
|
pub fn send(self: *const Message) !void {
|
|
_ = try std.os.fcntl(
|
|
self.memfd,
|
|
F_ADD_SEALS,
|
|
F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_EXEC,
|
|
);
|
|
|
|
var cmsg = cmsghdr.cmsghdr(std.os.fd_t).init(
|
|
.{
|
|
.level = std.os.SOL.SOCKET,
|
|
.type = SCM_RIGHTS,
|
|
.data = self.memfd,
|
|
},
|
|
);
|
|
|
|
var msghdr = std.os.msghdr_const{
|
|
.name = @ptrCast(&self.logger.path),
|
|
.namelen = @sizeOf(@TypeOf(self.logger.path)),
|
|
.iov = undefined,
|
|
.iovlen = 0,
|
|
.control = &cmsg,
|
|
.controllen = @sizeOf(@TypeOf(cmsg)),
|
|
.flags = 0,
|
|
};
|
|
|
|
const result = try std.os.sendmsg(
|
|
self.logger.socket,
|
|
&msghdr,
|
|
0,
|
|
);
|
|
|
|
std.debug.assert(result == 0);
|
|
|
|
std.os.close(self.memfd);
|
|
}
|
|
|
|
pub fn cancel(self: Message) void {
|
|
std.os.close(self.memfd);
|
|
}
|
|
};
|
|
|
|
fn message(self: Logger, priority: Priority) !Message {
|
|
const memfd = try std.os.memfd_create(
|
|
"zig",
|
|
std.os.MFD.CLOEXEC | std.os.MFD.ALLOW_SEALING | MFD_NOEXEC_SEAL,
|
|
);
|
|
|
|
const msg = Message{
|
|
.logger = self,
|
|
.priority = priority,
|
|
.memfd = memfd,
|
|
};
|
|
|
|
if (self.identifier) |i| try msg.identifier(i);
|
|
try msg.int("PRIORITY", @intFromEnum(priority));
|
|
|
|
return msg;
|
|
}
|
|
};
|
|
|
|
test "test" {
|
|
const logger = try Logger.init("library test");
|
|
defer logger.deinit();
|
|
|
|
const message = try logger.message(.INFO);
|
|
errdefer message.cancel();
|
|
|
|
try message.facility(.LOCAL0);
|
|
try message.string("MESSAGE", "hello");
|
|
try message.src(@src());
|
|
|
|
try message.send();
|
|
}
|