A CLI tool to edit dinit service files with ease
1const std = @import("std");
2
3const a = std.heap.smp_allocator;
4
5var service_dirs: std.ArrayListUnmanaged([:0]const u8) = .empty;
6
7var services: std.StringArrayHashMapUnmanaged([:0]const u8) = .empty;
8
9pub fn main() !void {
10 try load_definitions();
11
12 if (std.os.argv.len == 1) try list_all();
13 if (std.os.argv.len == 2) try edit(std.mem.span(std.os.argv[1]));
14}
15
16pub fn load_definitions() !void {
17 const uid = std.posix.system.getuid();
18
19 if (uid == 0) {
20 var default_system = [_][:0]const u8{ "/etc/dinit.d", "/run/dinit.d", "/usr/local/lib/dinit.d", "/lib/dinit.d" };
21 service_dirs = .fromOwnedSlice(&default_system);
22 } else {
23 service_dirs = try .initCapacity(a, 5);
24 if (std.posix.getenv("XDG_CONFIG_HOME")) |prefix| {
25 service_dirs.appendAssumeCapacity(try std.fmt.allocPrintZ(a, "{s}/dinit.d", .{prefix}));
26 }
27 if (std.posix.getenv("HOME")) |prefix| {
28 service_dirs.appendAssumeCapacity(try std.fmt.allocPrintZ(a, "{s}/.config/dinit.d", .{prefix}));
29 }
30 service_dirs.appendSliceAssumeCapacity(&.{ "/etc/dinit.d/user", "/usr/lib/dinit.d/user", "/usr/local/lib/dinit.d/user" });
31 }
32
33 for (service_dirs.items) |dir_path| {
34 const dir = std.fs.openDirAbsoluteZ(dir_path, .{ .iterate = true }) catch |e| {
35 if (e == error.FileNotFound) continue;
36 return e;
37 };
38 var iter = dir.iterate();
39 while (try iter.next()) |entry| {
40 // std.log.info("{s}/{s}", .{ dir_path, entry.name });
41 if (entry.kind == .file and !services.contains(entry.name)) {
42 try services.put(a, try a.dupe(u8, entry.name), try std.fmt.allocPrintZ(a, "{s}/{s}", .{ dir_path, entry.name }));
43 }
44 }
45 }
46}
47
48fn list_all() !void {
49 const stdout = std.io.getStdOut();
50 var longest: usize = 0;
51 var iter = services.iterator();
52 while (iter.next()) |entry| {
53 longest = @max(longest, entry.key_ptr.len);
54 }
55 const pad_buffer: [36]u8 = @splat(' ');
56 iter = services.iterator();
57 while (iter.next()) |entry| {
58 const pad = pad_buffer[0 .. longest + 4 - entry.key_ptr.len];
59 try stdout.writer().print("{s}{s}{s}\n", .{ entry.key_ptr.*, pad, entry.value_ptr.* });
60 }
61}
62
63fn edit(service_name: []const u8) !void {
64 const editor = std.posix.getenvZ("EDITOR") orelse "/usr/bin/kak";
65 var iter = services.iterator();
66 while (iter.next()) |entry| {
67 if (std.mem.eql(u8, entry.key_ptr.*, service_name)) {
68 const command = try std.fmt.allocPrintZ(a, "{s} {s}", .{ editor, entry.value_ptr.* });
69 return std.posix.execveZ("/bin/sh", &.{ "sh", "-c", command }, @ptrCast(std.os.environ));
70 }
71 }
72 std.debug.print("Cannot find service file\n", .{});
73 std.process.exit(1);
74}