Make print_clogs
only print clogs
Externalize matching functionality between user port spec and found clogs (socket + process information).
This commit is contained in:
parent
85f097eb3b
commit
37f51c6002
4 changed files with 160 additions and 78 deletions
74
src/main.zig
74
src/main.zig
|
@ -2,6 +2,7 @@ const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const sockets = @import("sockets.zig");
|
const sockets = @import("sockets.zig");
|
||||||
const process = @import("process.zig");
|
const process = @import("process.zig");
|
||||||
|
const match = @import("match.zig");
|
||||||
const c = @cImport({
|
const c = @cImport({
|
||||||
@cInclude("pwd.h");
|
@cInclude("pwd.h");
|
||||||
@cInclude("arpa/inet.h");
|
@cInclude("arpa/inet.h");
|
||||||
|
@ -26,16 +27,19 @@ pub fn main() !u8 {
|
||||||
};
|
};
|
||||||
defer alloc.free(ports);
|
defer alloc.free(ports);
|
||||||
|
|
||||||
const pids = try print_clogs(alloc, ports);
|
const clogs = try match.match(alloc, ports);
|
||||||
defer alloc.free(pids);
|
defer clogs.deinit();
|
||||||
|
|
||||||
if (pids.len == 0) {
|
if (clogs.items.len == 0) {
|
||||||
|
try std.io.getStdOut().writeAll("Ports look unclogged\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try print_clogs(clogs);
|
||||||
|
|
||||||
var kills: []u16 = undefined;
|
var kills: []u16 = undefined;
|
||||||
while(true) {
|
while(true) {
|
||||||
kills = choose_kill(alloc, pids.len) catch |err| {
|
kills = choose_kill(alloc, clogs.items.len) catch |err| {
|
||||||
if (builtin.mode == std.builtin.Mode.Debug) {
|
if (builtin.mode == std.builtin.Mode.Debug) {
|
||||||
try kill_usage();
|
try kill_usage();
|
||||||
return err;
|
return err;
|
||||||
|
@ -49,7 +53,16 @@ pub fn main() !u8 {
|
||||||
defer alloc.free(kills);
|
defer alloc.free(kills);
|
||||||
|
|
||||||
for(kills) |k| {
|
for(kills) |k| {
|
||||||
kill(pids[k-1]);
|
// go find the kill
|
||||||
|
var procnum: usize = 0;
|
||||||
|
for(clogs.items) |clog| {
|
||||||
|
if(clog.procs.items.len < (k-procnum)) { // kill is in a process in the next clog
|
||||||
|
procnum += clog.procs.items.len;
|
||||||
|
} else { // kill is in this clog - the # of clog process we passed
|
||||||
|
kill(clog.procs.items[k-procnum-1].pid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -125,85 +138,60 @@ fn choose_kill(alloc: std.mem.Allocator, choices: usize) ![]u16 {
|
||||||
return kills;
|
return kills;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_clogs(alloc: std.mem.Allocator, ports: []u16) ![]std.posix.pid_t {
|
fn print_clogs(clogs: match.Clogs) !void {
|
||||||
var writer = std.io.getStdOut().writer();
|
var writer = std.io.getStdOut().writer();
|
||||||
var pids = std.ArrayList(std.posix.pid_t).init(alloc);
|
|
||||||
defer pids.deinit(); // noop after re-owning memory at end
|
|
||||||
|
|
||||||
const clog_sockets = try sockets.parse(alloc, null);
|
|
||||||
defer alloc.free(clog_sockets);
|
|
||||||
|
|
||||||
var any: bool = false;
|
|
||||||
for (clog_sockets) |cs| {
|
|
||||||
if(std.mem.indexOfScalar(u16, ports, cs.port)) |_| {
|
|
||||||
any = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!any) {
|
|
||||||
try writer.writeAll("Ports look unclogged\n");
|
|
||||||
return &[_]std.posix.pid_t{};
|
|
||||||
}
|
|
||||||
|
|
||||||
try writer.print("{s: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {s: <6} {s: <5}\n", .{ "#", "Command", "Path", "Protocol", "Address", "User", "Inode", "Port" });
|
try writer.print("{s: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {s: <6} {s: <5}\n", .{ "#", "Command", "Path", "Protocol", "Address", "User", "Inode", "Port" });
|
||||||
var idx: usize = 1;
|
var idx: usize = 1;
|
||||||
|
|
||||||
for (clog_sockets) |cs| {
|
|
||||||
if (std.mem.indexOfScalar(u16, ports, cs.port)) |_| {
|
|
||||||
const clogs = try process.find_by_inode(alloc, cs.inode, null);
|
|
||||||
defer clogs.deinit();
|
|
||||||
|
|
||||||
const user = c.getpwuid(cs.uid);
|
|
||||||
|
|
||||||
for (clogs.items) |clog| {
|
for (clogs.items) |clog| {
|
||||||
switch (cs.protocol_data) {
|
const user = c.getpwuid(clog.sock.uid);
|
||||||
|
|
||||||
|
for (clog.procs.items) |proc| {
|
||||||
|
switch (clog.sock.protocol_data) {
|
||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
.tcp_v4 => |proto| {
|
.tcp_v4 => |proto| {
|
||||||
var addr: [c.INET_ADDRSTRLEN:0]u8 = undefined;
|
var addr: [c.INET_ADDRSTRLEN:0]u8 = undefined;
|
||||||
_ = c.inet_ntop(c.AF_INET, &proto.addr, &addr, c.INET_ADDRSTRLEN);
|
_ = c.inet_ntop(c.AF_INET, &proto.addr, &addr, c.INET_ADDRSTRLEN);
|
||||||
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
||||||
idx,
|
idx,
|
||||||
clog.comm[0..@min(10, clog.comm.len)], clog.exe[0..@min(30, clog.exe.len)],
|
proc.comm[0..@min(10, proc.comm.len)], proc.exe[0..@min(30, proc.exe.len)],
|
||||||
"TCP/IPv4", std.mem.sliceTo(&addr, 0),
|
"TCP/IPv4", std.mem.sliceTo(&addr, 0),
|
||||||
user.*.pw_name, cs.inode, cs.port });
|
user.*.pw_name, clog.sock.inode, clog.port });
|
||||||
},
|
},
|
||||||
.tcp_v6 => |proto| {
|
.tcp_v6 => |proto| {
|
||||||
var addr: [c.INET6_ADDRSTRLEN:0]u8 = undefined;
|
var addr: [c.INET6_ADDRSTRLEN:0]u8 = undefined;
|
||||||
_ = c.inet_ntop(c.AF_INET6, &proto.addr, &addr, c.INET6_ADDRSTRLEN);
|
_ = c.inet_ntop(c.AF_INET6, &proto.addr, &addr, c.INET6_ADDRSTRLEN);
|
||||||
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
||||||
idx,
|
idx,
|
||||||
clog.comm[0..@min(10, clog.comm.len)], clog.exe[0..@min(30, clog.exe.len)],
|
proc.comm[0..@min(10, proc.comm.len)], proc.exe[0..@min(30, proc.exe.len)],
|
||||||
"TCP/IPv6", std.mem.sliceTo(&addr, 0),
|
"TCP/IPv6", std.mem.sliceTo(&addr, 0),
|
||||||
user.*.pw_name, cs.inode, cs.port });
|
user.*.pw_name, clog.sock.inode, clog.port });
|
||||||
},
|
},
|
||||||
.udp_v4 => |proto| {
|
.udp_v4 => |proto| {
|
||||||
var addr: [c.INET_ADDRSTRLEN:0]u8 = undefined;
|
var addr: [c.INET_ADDRSTRLEN:0]u8 = undefined;
|
||||||
_ = c.inet_ntop(c.AF_INET, &proto.addr, &addr, c.INET_ADDRSTRLEN);
|
_ = c.inet_ntop(c.AF_INET, &proto.addr, &addr, c.INET_ADDRSTRLEN);
|
||||||
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
||||||
idx,
|
idx,
|
||||||
clog.comm[0..@min(10, clog.comm.len)], clog.exe[0..@min(30, clog.exe.len)],
|
proc.comm[0..@min(10, proc.comm.len)], proc.exe[0..@min(30, proc.exe.len)],
|
||||||
"UDP/IPv4", std.mem.sliceTo(&addr, 0),
|
"UDP/IPv4", std.mem.sliceTo(&addr, 0),
|
||||||
user.*.pw_name, cs.inode, cs.port });
|
user.*.pw_name, clog.sock.inode, clog.port });
|
||||||
},
|
},
|
||||||
.udp_v6 => |proto| {
|
.udp_v6 => |proto| {
|
||||||
var addr: [c.INET6_ADDRSTRLEN:0]u8 = undefined;
|
var addr: [c.INET6_ADDRSTRLEN:0]u8 = undefined;
|
||||||
_ = c.inet_ntop(c.AF_INET6, &proto.addr, &addr, c.INET6_ADDRSTRLEN);
|
_ = c.inet_ntop(c.AF_INET6, &proto.addr, &addr, c.INET6_ADDRSTRLEN);
|
||||||
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
||||||
idx,
|
idx,
|
||||||
clog.comm[0..@min(10, clog.comm.len)], clog.exe[0..@min(30, clog.exe.len)],
|
proc.comm[0..@min(10, proc.comm.len)], proc.exe[0..@min(30, proc.exe.len)],
|
||||||
"UDP/IPv6", std.mem.sliceTo(&addr, 0),
|
"UDP/IPv6", std.mem.sliceTo(&addr, 0),
|
||||||
user.*.pw_name, cs.inode, cs.port });
|
user.*.pw_name, clog.sock.inode, clog.port });
|
||||||
},
|
},
|
||||||
// zig fmt: on
|
// zig fmt: on
|
||||||
}
|
}
|
||||||
|
|
||||||
try pids.append(clog.pid);
|
|
||||||
idx += 1;
|
idx += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return pids.toOwnedSlice();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() !void {
|
fn usage() !void {
|
||||||
|
|
55
src/match.zig
Normal file
55
src/match.zig
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const process = @import("process.zig");
|
||||||
|
const sockets = @import("sockets.zig");
|
||||||
|
|
||||||
|
pub const Clogs = struct {
|
||||||
|
items: []Clog,
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
pub fn deinit(self: @This()) void {
|
||||||
|
for(self.items) |clog| {
|
||||||
|
clog.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.alloc.free(self.items);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Clog = struct {
|
||||||
|
port: u16,
|
||||||
|
sock: sockets.ClogSocket,
|
||||||
|
procs: process.ClogProcesses,
|
||||||
|
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
pub fn deinit(self: @This()) void {
|
||||||
|
self.procs.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn match(alloc: std.mem.Allocator, ports: []u16) !Clogs {
|
||||||
|
var buf = std.ArrayList(Clog).init(alloc);
|
||||||
|
defer(buf.deinit()); // noop after re-owned at end
|
||||||
|
|
||||||
|
const socks = try sockets.parse(alloc, null);
|
||||||
|
defer alloc.free(socks);
|
||||||
|
|
||||||
|
for (socks) |sock| {
|
||||||
|
if (std.mem.indexOfScalar(u16, ports, sock.port) == null) continue;
|
||||||
|
|
||||||
|
const procs = try process.find_by_inode(alloc, sock.inode, null);
|
||||||
|
defer procs.deinit();
|
||||||
|
|
||||||
|
try buf.append(Clog {
|
||||||
|
.port = sock.port,
|
||||||
|
.sock = sock.clone(),
|
||||||
|
.procs = try procs.clone(alloc),
|
||||||
|
.alloc = alloc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Clogs{
|
||||||
|
.items = try buf.toOwnedSlice(),
|
||||||
|
.alloc = alloc,
|
||||||
|
};
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ const std = @import("std");
|
||||||
/// handling deallocation correctly. Call `deinit` to deallocate the memory.
|
/// handling deallocation correctly. Call `deinit` to deallocate the memory.
|
||||||
///
|
///
|
||||||
/// Processes can be accessed via `.items`
|
/// Processes can be accessed via `.items`
|
||||||
pub const Clogs = struct {
|
pub const ClogProcesses = struct {
|
||||||
items: []ClogProcess,
|
items: []ClogProcess,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
@ -14,6 +14,18 @@ pub const Clogs = struct {
|
||||||
try writer.print("{any}", .{value.items});
|
try writer.print("{any}", .{value.items});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clone(self: @This(), alloc: std.mem.Allocator) !ClogProcesses {
|
||||||
|
var items = try alloc.alloc(ClogProcess, self.items.len);
|
||||||
|
for(self.items, 0..) |item, idx| {
|
||||||
|
items[idx] = try item.clone(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClogProcesses {
|
||||||
|
.items = items,
|
||||||
|
.alloc = alloc
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: @This()) void {
|
pub fn deinit(self: @This()) void {
|
||||||
for (self.items) |item| {
|
for (self.items) |item| {
|
||||||
item.deinit();
|
item.deinit();
|
||||||
|
@ -44,6 +56,24 @@ pub const ClogProcess = struct {
|
||||||
try writer.writeAll("}");
|
try writer.writeAll("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clone(self: @This(), alloc: std.mem.Allocator) !ClogProcess {
|
||||||
|
var cmdline: [][]u8 = try alloc.alloc([]u8, self.cmdline.len);
|
||||||
|
for(self.cmdline, 0..) |line, idx| {
|
||||||
|
cmdline[idx] = try alloc.dupe(u8, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClogProcess {
|
||||||
|
.pid = self.pid,
|
||||||
|
.inode = self.inode,
|
||||||
|
.fd = self.fd,
|
||||||
|
.comm = try alloc.dupe(u8, self.comm),
|
||||||
|
.exe = try alloc.dupe(u8, self.exe),
|
||||||
|
.cmdline = cmdline,
|
||||||
|
|
||||||
|
.alloc = alloc
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn deinit(self: @This()) void {
|
fn deinit(self: @This()) void {
|
||||||
self.alloc.free(self.comm);
|
self.alloc.free(self.comm);
|
||||||
self.alloc.free(self.exe);
|
self.alloc.free(self.exe);
|
||||||
|
@ -55,7 +85,7 @@ pub const ClogProcess = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Find clogging processes that hold a file handle on an inode
|
/// Find clogging processes that hold a file handle on an inode
|
||||||
pub fn find_by_inode(alloc: std.mem.Allocator, inode: std.posix.ino_t, proc_path: ?[]const u8) !Clogs {
|
pub fn find_by_inode(alloc: std.mem.Allocator, inode: std.posix.ino_t, proc_path: ?[]const u8) !ClogProcesses {
|
||||||
const base = proc_path orelse "/proc";
|
const base = proc_path orelse "/proc";
|
||||||
|
|
||||||
var clogs = std.ArrayList(ClogProcess).init(alloc);
|
var clogs = std.ArrayList(ClogProcess).init(alloc);
|
||||||
|
@ -112,7 +142,7 @@ pub fn find_by_inode(alloc: std.mem.Allocator, inode: std.posix.ino_t, proc_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Clogs{ .items = try clogs.toOwnedSlice(), .alloc = alloc };
|
return ClogProcesses{ .items = try clogs.toOwnedSlice(), .alloc = alloc };
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProcessFileData = struct {
|
const ProcessFileData = struct {
|
||||||
|
|
|
@ -11,6 +11,15 @@ pub const ClogSocket = struct {
|
||||||
inode: std.posix.ino_t,
|
inode: std.posix.ino_t,
|
||||||
uid: std.posix.uid_t,
|
uid: std.posix.uid_t,
|
||||||
protocol_data: ProtocolData,
|
protocol_data: ProtocolData,
|
||||||
|
|
||||||
|
pub fn clone(self: @This()) ClogSocket {
|
||||||
|
return ClogSocket {
|
||||||
|
.port = self.port,
|
||||||
|
.inode = self.inode,
|
||||||
|
.uid = self.uid,
|
||||||
|
.protocol_data = self.protocol_data
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Known protocols
|
/// Known protocols
|
||||||
|
|
Loading…
Reference in a new issue