xref: /inferno-os/appl/cmd/kill.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Kill;
2
3include "sys.m";
4	sys: Sys;
5include "draw.m";
6include "arg.m";
7
8Kill: module {
9	init: fn(nil: ref Draw->Context, args: list of string);
10};
11
12stderr: ref Sys->FD;
13
14usage()
15{
16	sys->fprint(stderr, "usage: kill [-g] pid|module [...]\n");
17	raise "fail: usage";
18}
19
20init(nil: ref Draw->Context, args: list of string)
21{
22	sys = load Sys Sys->PATH;
23	stderr = sys->fildes(2);
24
25	arg := load Arg Arg->PATH;
26	if(arg == nil){
27		sys->fprint(stderr, "kill: cannot load %s: %r\n", Arg->PATH);
28		raise "fail:load";
29	}
30
31	msg := array of byte "kill";
32	arg->init(args);
33	while((o := arg->opt()) != 0)
34		case o {
35		'g' =>
36			msg = array of byte "killgrp";
37		* =>
38			usage();
39		}
40
41	argv := arg->argv();
42	arg = nil;
43	if(argv == nil)
44		usage();
45	n := 0;
46	for(v := argv; v != nil; v = tl v) {
47		s := hd v;
48		if (s == nil)
49			usage();
50		if(s[0] >= '0' && s[0] <= '9')
51			n += killpid(s, msg, 1);
52		else
53			n += killmod(s, msg);
54	}
55	if (n == 0 && argv != nil)
56		raise "fail:nothing killed";
57}
58
59killpid(pid: string, msg: array of byte, sbok: int): int
60{
61	fd := sys->open("/prog/"+pid+"/ctl", sys->OWRITE);
62	if(fd == nil) {
63		err := sys->sprint("%r");
64		elen := len err;
65		if(sbok || err != "thread exited" && elen >= 14 && err[elen-14:] != "does not exist")
66			sys->fprint(stderr, "kill: cannot open /prog/%s/ctl: %r\n", pid);
67		return 0;
68	}
69
70	n := sys->write(fd, msg, len msg);
71	if(n < 0) {
72		err := sys->sprint("%r");
73		elen := len err;
74		if(sbok || err != "thread exited")
75			sys->fprint(stderr, "kill: cannot kill %s: %r\n", pid);
76		return 0;
77	}
78	return 1;
79}
80
81killmod(mod: string, msg: array of byte): int
82{
83	fd := sys->open("/prog", sys->OREAD);
84	if(fd == nil) {
85		sys->fprint(stderr, "kill: open /prog: %r\n");
86		return 0;
87	}
88
89	pids: list of string;
90	for(;;) {
91		(n, d) := sys->dirread(fd);
92		if(n <= 0) {
93			if (n < 0)
94				sys->fprint(stderr, "kill: read /prog: %r\n");
95			break;
96		}
97
98		for(i := 0; i < n; i++)
99			if (killmatch(d[i].name, mod))
100				pids = d[i].name :: pids;
101	}
102	if (pids == nil) {
103		sys->fprint(stderr, "kill: cannot find %s\n", mod);
104		return 0;
105	}
106	n := 0;
107	for (; pids != nil; pids = tl pids)
108		if (killpid(hd pids, msg, 0)) {
109			sys->print("%s ", hd pids);
110			n++;
111		}
112	if (n > 0)
113		sys->print("\n");
114	return n;
115}
116
117killmatch(dir, mod: string): int
118{
119	status := "/prog/"+dir+"/status";
120	fd := sys->open(status, sys->OREAD);
121	if(fd == nil)
122		return 0;
123	buf := array[512] of byte;
124	n := sys->read(fd, buf, len buf);
125	if(n < 0) {
126		err := sys->sprint("%r");
127		if(err != "thread exited")
128			sys->fprint(stderr, "kill: cannot read %s: %s\n", status, err);
129		return 0;
130	}
131
132	# module name is last field
133	(nil, fields) := sys->tokenize(string buf[0:n], " ");
134	for(s := ""; fields != nil; fields = tl fields)
135		s = hd fields;
136
137	# strip builtin module, e.g. Sh[$Sys]
138	for(i := 0; i < len s; i++) {
139		if(s[i] == '[') {
140			s = s[0:i];
141			break;
142		}
143	}
144
145	return s == mod;
146}
147