userspace: Implement kill utility

This commit is contained in:
Bananymous 2025-11-04 19:19:46 +02:00
parent acd792d8b4
commit c6ef4b5840
3 changed files with 184 additions and 0 deletions

View File

@ -20,6 +20,7 @@ set(USERSPACE_PROGRAMS
id id
image image
init init
kill
less less
ln ln
loadfont loadfont

View File

@ -0,0 +1,9 @@
set(SOURCES
main.cpp
)
add_executable(kill ${SOURCES})
banan_link_library(kill ban)
banan_link_library(kill libc)
install(TARGETS kill OPTIONAL)

View File

@ -0,0 +1,174 @@
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct signal_t
{
const char* name;
int value;
};
static constexpr signal_t s_signals[] {
#define SIGNAL(name) { #name, name }
SIGNAL(SIGABRT),
SIGNAL(SIGALRM),
SIGNAL(SIGBUS),
SIGNAL(SIGCHLD),
SIGNAL(SIGCONT),
SIGNAL(SIGFPE),
SIGNAL(SIGHUP),
SIGNAL(SIGILL),
SIGNAL(SIGINT),
SIGNAL(SIGKILL),
SIGNAL(SIGPIPE),
SIGNAL(SIGQUIT),
SIGNAL(SIGSEGV),
SIGNAL(SIGSTOP),
SIGNAL(SIGTERM),
SIGNAL(SIGTSTP),
SIGNAL(SIGTTIN),
SIGNAL(SIGTTOU),
SIGNAL(SIGUSR1),
SIGNAL(SIGUSR2),
SIGNAL(SIGPOLL),
SIGNAL(SIGPROF),
SIGNAL(SIGSYS),
SIGNAL(SIGTRAP),
SIGNAL(SIGURG),
SIGNAL(SIGVTALRM),
SIGNAL(SIGXCPU),
SIGNAL(SIGXFSZ),
SIGNAL(SIGWINCH),
SIGNAL(SIGCANCEL),
#undef SIGNAL
};
[[noreturn]] static void exit_with_error(const char* format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(1);
__builtin_unreachable();
}
static int signal_name_to_number(const char* name)
{
for (const auto& signal : s_signals)
if (strcasecmp(signal.name + 3, name) == 0 || strcasecmp(signal.name, name) == 0)
return signal.value;
exit_with_error("unknown signal '%s'\n", name);
}
static int parse_int(const char* string)
{
errno = 0;
char* endptr;
const int result = strtol(string, &endptr, 0);
if (*endptr != '\0' || errno)
exit_with_error("invalid integer '%s'\n", string);
return result;
}
static int list_signals(char** signals)
{
if (signals[0] == nullptr)
{
for (const auto& signal : s_signals)
{
if (&signal != s_signals)
printf(" ");
printf("%s", signal.name);
}
printf("\n");
return 0;
}
int ret = 0;
while (*signals)
{
bool found = false;
if (isdigit(**signals))
{
const int sig = parse_int(*signals);
for (const auto& signal : s_signals)
{
if (signal.value != sig)
continue;
printf("%s\n", signal.name + 3);
found = true;
break;
}
}
else
{
for (const auto& signal : s_signals)
{
if (strcasecmp(signal.name, *signals) != 0 && strcasecmp(signal.name + 3, *signals) != 0)
continue;
printf("%d\n", signal.value);
found = true;
break;
}
}
if (!found)
fprintf(stderr, "unknown signal: %s\n", *signals);
signals++;
}
return ret;
}
int main(int argc, char** argv)
{
if (argc >= 2 && strcmp(argv[1], "-l") == 0)
return list_signals(argv + 2);
int sig = SIGTERM;
int i = 1;
for (; i < argc; i++)
{
if (argv[i][0] != '-')
break;
if (argv[i][1] == '-' && argv[i][2] == '\0')
{
i++;
break;
}
if (argv[i][1] == 's' && argv[i][2] == '\0')
{
if (i + 1 >= argc)
exit_with_error("missing signal name\n");
sig = signal_name_to_number(argv[i + 1]);
i++;
}
else if (argv[i][2] == '-' || isdigit(argv[i][1]))
{
sig = parse_int(argv[i] + 1);
}
else
{
sig = signal_name_to_number(argv[i] + 1);
}
}
if (i >= argc)
exit_with_error("missing pids\n");
for (; i < argc; i++)
if (kill(parse_int(argv[i]), sig) == -1)
perror("kill");
return 0;
}