mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 18:44:01 +00:00
Stage 13
This commit is contained in:
@@ -2,9 +2,24 @@
|
|||||||
#include <cleonos_syscall.h>
|
#include <cleonos_syscall.h>
|
||||||
|
|
||||||
#define SHELL_CMD_MAX 24ULL
|
#define SHELL_CMD_MAX 24ULL
|
||||||
#define SHELL_ARG_MAX 128ULL
|
#define SHELL_ARG_MAX 160ULL
|
||||||
#define SHELL_LINE_MAX 256ULL
|
#define SHELL_LINE_MAX 320ULL
|
||||||
#define SHELL_CAT_MAX 224ULL
|
#define SHELL_CAT_MAX 224ULL
|
||||||
|
#define SHELL_SCRIPT_MAX 1024ULL
|
||||||
|
|
||||||
|
static u64 shell_strlen(const char *str) {
|
||||||
|
u64 len = 0ULL;
|
||||||
|
|
||||||
|
if (str == (const char *)0) {
|
||||||
|
return 0ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (str[len] != '\0') {
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
static int shell_streq(const char *left, const char *right) {
|
static int shell_streq(const char *left, const char *right) {
|
||||||
u64 i = 0ULL;
|
u64 i = 0ULL;
|
||||||
@@ -89,6 +104,35 @@ static void shell_log_hex_prefixed(const char *prefix, u64 value) {
|
|||||||
shell_log_text(line);
|
shell_log_text(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void shell_trim_line(char *line) {
|
||||||
|
u64 start = 0ULL;
|
||||||
|
u64 i = 0ULL;
|
||||||
|
u64 len;
|
||||||
|
|
||||||
|
if (line == (char *)0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (line[start] != '\0' && shell_is_space(line[start]) != 0) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start > 0ULL) {
|
||||||
|
while (line[start + i] != '\0') {
|
||||||
|
line[i] = line[start + i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
line[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
len = shell_strlen(line);
|
||||||
|
|
||||||
|
while (len > 0ULL && shell_is_space(line[len - 1ULL]) != 0) {
|
||||||
|
line[len - 1ULL] = '\0';
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void shell_parse_line(const char *line, char *out_cmd, u64 cmd_size, char *out_arg, u64 arg_size) {
|
static void shell_parse_line(const char *line, char *out_cmd, u64 cmd_size, char *out_arg, u64 arg_size) {
|
||||||
u64 i = 0ULL;
|
u64 i = 0ULL;
|
||||||
u64 cmd_pos = 0ULL;
|
u64 cmd_pos = 0ULL;
|
||||||
@@ -126,7 +170,7 @@ static void shell_parse_line(const char *line, char *out_cmd, u64 cmd_size, char
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void shell_cmd_help(void) {
|
static void shell_cmd_help(void) {
|
||||||
shell_log_text("[USER][SHELL] commands: help ls <dir> cat <file> run <elf>");
|
shell_log_text("[USER][SHELL] commands: help ls <dir> cat <file> run <elf> stats");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shell_cmd_ls(const char *arg) {
|
static void shell_cmd_ls(const char *arg) {
|
||||||
@@ -149,7 +193,7 @@ static void shell_cmd_ls(const char *arg) {
|
|||||||
shell_log_hex_prefixed("[USER][SHELL] ls count: ", count);
|
shell_log_hex_prefixed("[USER][SHELL] ls count: ", count);
|
||||||
|
|
||||||
for (i = 0ULL; i < count; i++) {
|
for (i = 0ULL; i < count; i++) {
|
||||||
char name[96];
|
char name[CLEONOS_FS_NAME_MAX];
|
||||||
|
|
||||||
name[0] = '\0';
|
name[0] = '\0';
|
||||||
|
|
||||||
@@ -204,15 +248,50 @@ static void shell_cmd_run(const char *arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void shell_cmd_stats(void) {
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] fs nodes: ", cleonos_sys_fs_node_count());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] task count: ", cleonos_sys_task_count());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] service count: ", cleonos_sys_service_count());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] service ready: ", cleonos_sys_service_ready_count());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] context switches: ", cleonos_sys_context_switches());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] kelf count: ", cleonos_sys_kelf_count());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] kelf runs: ", cleonos_sys_kelf_runs());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] user shell ready: ", cleonos_sys_user_shell_ready());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] user exec requested: ", cleonos_sys_user_exec_requested());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] user launch tries: ", cleonos_sys_user_launch_tries());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] user launch ok: ", cleonos_sys_user_launch_ok());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] user launch fail: ", cleonos_sys_user_launch_fail());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] exec requests: ", cleonos_sys_exec_request_count());
|
||||||
|
shell_log_hex_prefixed("[USER][SHELL] exec success: ", cleonos_sys_exec_success_count());
|
||||||
|
}
|
||||||
|
|
||||||
static void shell_execute_line(const char *line) {
|
static void shell_execute_line(const char *line) {
|
||||||
char cmd[SHELL_CMD_MAX];
|
char cmd[SHELL_CMD_MAX];
|
||||||
char arg[SHELL_ARG_MAX];
|
char arg[SHELL_ARG_MAX];
|
||||||
|
char line_buf[SHELL_LINE_MAX];
|
||||||
|
u64 i = 0ULL;
|
||||||
|
|
||||||
cmd[0] = '\0';
|
cmd[0] = '\0';
|
||||||
arg[0] = '\0';
|
arg[0] = '\0';
|
||||||
|
|
||||||
shell_log_prefixed("[USER][SHELL]$ ", line);
|
if (line == (const char *)0) {
|
||||||
shell_parse_line(line, cmd, (u64)sizeof(cmd), arg, (u64)sizeof(arg));
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (line[i] != '\0' && i + 1ULL < (u64)sizeof(line_buf)) {
|
||||||
|
line_buf[i] = line[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_buf[i] = '\0';
|
||||||
|
shell_trim_line(line_buf);
|
||||||
|
|
||||||
|
if (line_buf[0] == '\0' || line_buf[0] == '#') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_log_prefixed("[USER][SHELL]$ ", line_buf);
|
||||||
|
shell_parse_line(line_buf, cmd, (u64)sizeof(cmd), arg, (u64)sizeof(arg));
|
||||||
|
|
||||||
if (shell_streq(cmd, "help") != 0) {
|
if (shell_streq(cmd, "help") != 0) {
|
||||||
shell_cmd_help();
|
shell_cmd_help();
|
||||||
@@ -234,12 +313,18 @@ static void shell_execute_line(const char *line) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shell_streq(cmd, "stats") != 0) {
|
||||||
|
shell_cmd_stats();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
shell_log_prefixed("[USER][SHELL] unknown command: ", cmd);
|
shell_log_prefixed("[USER][SHELL] unknown command: ", cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cleonos_app_main(void) {
|
static void shell_run_default_script(void) {
|
||||||
static const char *script[] = {
|
static const char *script[] = {
|
||||||
"help",
|
"help",
|
||||||
|
"stats",
|
||||||
"ls /",
|
"ls /",
|
||||||
"ls /system",
|
"ls /system",
|
||||||
"cat /README.txt",
|
"cat /README.txt",
|
||||||
@@ -248,15 +333,65 @@ int cleonos_app_main(void) {
|
|||||||
};
|
};
|
||||||
u64 i;
|
u64 i;
|
||||||
|
|
||||||
shell_log_text("[USER][SHELL] shell.elf command framework online");
|
|
||||||
shell_log_hex_prefixed("[USER][SHELL] fs nodes: ", cleonos_sys_fs_node_count());
|
|
||||||
shell_log_hex_prefixed("[USER][SHELL] task count: ", cleonos_sys_task_count());
|
|
||||||
|
|
||||||
for (i = 0ULL; i < (u64)(sizeof(script) / sizeof(script[0])); i++) {
|
for (i = 0ULL; i < (u64)(sizeof(script) / sizeof(script[0])); i++) {
|
||||||
shell_execute_line(script[i]);
|
shell_execute_line(script[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
shell_log_hex_prefixed("[USER][SHELL] exec requests: ", cleonos_sys_exec_request_count());
|
static int shell_run_script_file(const char *path) {
|
||||||
shell_log_hex_prefixed("[USER][SHELL] exec success: ", cleonos_sys_exec_success_count());
|
char script[SHELL_SCRIPT_MAX + 1ULL];
|
||||||
|
char line[SHELL_LINE_MAX];
|
||||||
|
u64 got;
|
||||||
|
u64 i;
|
||||||
|
u64 line_pos = 0ULL;
|
||||||
|
|
||||||
|
if (path == (const char *)0 || path[0] == '\0') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
got = cleonos_sys_fs_read(path, script, SHELL_SCRIPT_MAX);
|
||||||
|
|
||||||
|
if (got == 0ULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (got > SHELL_SCRIPT_MAX) {
|
||||||
|
got = SHELL_SCRIPT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
script[got] = '\0';
|
||||||
|
shell_log_prefixed("[USER][SHELL] script ", path);
|
||||||
|
|
||||||
|
for (i = 0ULL; i <= got; i++) {
|
||||||
|
char ch = script[i];
|
||||||
|
|
||||||
|
if (ch == '\r') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '\n' || ch == '\0') {
|
||||||
|
line[line_pos] = '\0';
|
||||||
|
shell_execute_line(line);
|
||||||
|
line_pos = 0ULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line_pos + 1ULL < (u64)sizeof(line)) {
|
||||||
|
line[line_pos++] = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cleonos_app_main(void) {
|
||||||
|
shell_log_text("[USER][SHELL] shell.elf command framework online");
|
||||||
|
|
||||||
|
if (shell_run_script_file("/shell/init.cmd") == 0) {
|
||||||
|
shell_log_text("[USER][SHELL] /shell/init.cmd missing, using default script");
|
||||||
|
shell_run_default_script();
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_log_text("[USER][SHELL] script done");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
|||||||
u64 cleonos_sys_log_write(const char *message, u64 length);
|
u64 cleonos_sys_log_write(const char *message, u64 length);
|
||||||
u64 cleonos_sys_timer_ticks(void);
|
u64 cleonos_sys_timer_ticks(void);
|
||||||
u64 cleonos_sys_task_count(void);
|
u64 cleonos_sys_task_count(void);
|
||||||
|
u64 cleonos_sys_service_count(void);
|
||||||
|
u64 cleonos_sys_service_ready_count(void);
|
||||||
|
u64 cleonos_sys_context_switches(void);
|
||||||
|
u64 cleonos_sys_kelf_count(void);
|
||||||
|
u64 cleonos_sys_kelf_runs(void);
|
||||||
u64 cleonos_sys_fs_node_count(void);
|
u64 cleonos_sys_fs_node_count(void);
|
||||||
u64 cleonos_sys_fs_child_count(const char *dir_path);
|
u64 cleonos_sys_fs_child_count(const char *dir_path);
|
||||||
u64 cleonos_sys_fs_get_child_name(const char *dir_path, u64 index, char *out_name);
|
u64 cleonos_sys_fs_get_child_name(const char *dir_path, u64 index, char *out_name);
|
||||||
|
|||||||
@@ -25,6 +25,26 @@ u64 cleonos_sys_task_count(void) {
|
|||||||
return cleonos_syscall(CLEONOS_SYSCALL_TASK_COUNT, 0ULL, 0ULL, 0ULL);
|
return cleonos_syscall(CLEONOS_SYSCALL_TASK_COUNT, 0ULL, 0ULL, 0ULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_service_count(void) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_SERVICE_COUNT, 0ULL, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_service_ready_count(void) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_SERVICE_READY_COUNT, 0ULL, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_context_switches(void) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_CONTEXT_SWITCHES, 0ULL, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_kelf_count(void) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_KELF_COUNT, 0ULL, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_kelf_runs(void) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_KELF_RUNS, 0ULL, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
u64 cleonos_sys_fs_node_count(void) {
|
u64 cleonos_sys_fs_node_count(void) {
|
||||||
return cleonos_syscall(CLEONOS_SYSCALL_FS_NODE_COUNT, 0ULL, 0ULL, 0ULL);
|
return cleonos_syscall(CLEONOS_SYSCALL_FS_NODE_COUNT, 0ULL, 0ULL, 0ULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ static void clks_task_usrd(u64 tick) {
|
|||||||
clks_userland_tick(tick);
|
clks_userland_tick(tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clks_stage12_syscall_probe(void) {
|
static void clks_stage13_syscall_probe(void) {
|
||||||
char child_name[96];
|
char child_name[96];
|
||||||
char read_buf[160];
|
char read_buf[160];
|
||||||
u64 root_children;
|
u64 root_children;
|
||||||
@@ -162,7 +162,7 @@ void clks_kernel_main(void) {
|
|||||||
clks_tty_init();
|
clks_tty_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE12 START");
|
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE13 START");
|
||||||
|
|
||||||
if (boot_fb == CLKS_NULL) {
|
if (boot_fb == CLKS_NULL) {
|
||||||
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
|
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
|
||||||
@@ -271,7 +271,7 @@ void clks_kernel_main(void) {
|
|||||||
syscall_ticks = clks_syscall_invoke_kernel(CLKS_SYSCALL_TIMER_TICKS, 0ULL, 0ULL, 0ULL);
|
syscall_ticks = clks_syscall_invoke_kernel(CLKS_SYSCALL_TIMER_TICKS, 0ULL, 0ULL, 0ULL);
|
||||||
clks_log_hex(CLKS_LOG_INFO, "SYSCALL", "TICKS", syscall_ticks);
|
clks_log_hex(CLKS_LOG_INFO, "SYSCALL", "TICKS", syscall_ticks);
|
||||||
|
|
||||||
clks_stage12_syscall_probe();
|
clks_stage13_syscall_probe();
|
||||||
|
|
||||||
clks_log(CLKS_LOG_INFO, "TTY", "VIRTUAL TTY0 READY");
|
clks_log(CLKS_LOG_INFO, "TTY", "VIRTUAL TTY0 READY");
|
||||||
clks_log(CLKS_LOG_DEBUG, "KERNEL", "IDLE LOOP ENTER");
|
clks_log(CLKS_LOG_DEBUG, "KERNEL", "IDLE LOOP ENTER");
|
||||||
@@ -279,3 +279,4 @@ void clks_kernel_main(void) {
|
|||||||
clks_cpu_halt_forever();
|
clks_cpu_halt_forever();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,21 @@ static clks_bool clks_userland_probe_elf(const char *path, const char *tag) {
|
|||||||
return CLKS_TRUE;
|
return CLKS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void clks_userland_probe_init_script(void) {
|
||||||
|
const void *data;
|
||||||
|
u64 size = 0ULL;
|
||||||
|
|
||||||
|
data = clks_fs_read_all("/shell/init.cmd", &size);
|
||||||
|
|
||||||
|
if (data == CLKS_NULL || size == 0ULL) {
|
||||||
|
clks_log(CLKS_LOG_WARN, "USER", "INIT SCRIPT NOT FOUND /SHELL/INIT.CMD");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_log(CLKS_LOG_INFO, "USER", "INIT SCRIPT READY /SHELL/INIT.CMD");
|
||||||
|
clks_log_hex(CLKS_LOG_INFO, "USER", "INIT_SCRIPT_SIZE", size);
|
||||||
|
}
|
||||||
|
|
||||||
static clks_bool clks_userland_request_shell_exec(void) {
|
static clks_bool clks_userland_request_shell_exec(void) {
|
||||||
u64 status = (u64)-1;
|
u64 status = (u64)-1;
|
||||||
|
|
||||||
@@ -78,6 +93,7 @@ clks_bool clks_userland_init(void) {
|
|||||||
|
|
||||||
clks_user_shell_ready = CLKS_TRUE;
|
clks_user_shell_ready = CLKS_TRUE;
|
||||||
clks_log(CLKS_LOG_INFO, "USER", "SHELL COMMAND ABI READY");
|
clks_log(CLKS_LOG_INFO, "USER", "SHELL COMMAND ABI READY");
|
||||||
|
clks_userland_probe_init_script();
|
||||||
|
|
||||||
if (clks_userland_probe_elf("/system/elfrunner.elf", "ELFRUNNER ELF READY") == CLKS_FALSE) {
|
if (clks_userland_probe_elf("/system/elfrunner.elf", "ELFRUNNER ELF READY") == CLKS_FALSE) {
|
||||||
return CLKS_FALSE;
|
return CLKS_FALSE;
|
||||||
|
|||||||
39
docs/stage13.md
Normal file
39
docs/stage13.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# CLeonOS Stage13
|
||||||
|
|
||||||
|
## Stage Goal
|
||||||
|
- Upgrade shell command framework from hardcoded commands to script-driven execution.
|
||||||
|
- Add `/shell/init.cmd` startup script support with comment/blank-line handling.
|
||||||
|
- Extend user C syscall wrappers for runtime observability commands (`stats`).
|
||||||
|
- Keep Stage12 user execution manager stable while improving shell orchestration.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
- Kernel boots and prints `CLEONOS STAGE13 START`.
|
||||||
|
- Userland logs include init script detection:
|
||||||
|
- `INIT SCRIPT READY /SHELL/INIT.CMD` and script size.
|
||||||
|
- Shell logs show script mode:
|
||||||
|
- `[USER][SHELL] script /shell/init.cmd`
|
||||||
|
- command lines executed from script (`$ help`, `$ stats`, etc.).
|
||||||
|
- `stats` command prints runtime counters via syscall wrappers.
|
||||||
|
- System remains stable in idle loop.
|
||||||
|
|
||||||
|
## Build Targets
|
||||||
|
- `make setup`
|
||||||
|
- `make userapps`
|
||||||
|
- `make iso`
|
||||||
|
- `make run`
|
||||||
|
- `make debug`
|
||||||
|
|
||||||
|
## QEMU Command
|
||||||
|
- `qemu-system-x86_64 -M q35 -m 1024M -cdrom build/CLeonOS-x86_64.iso -serial stdio`
|
||||||
|
|
||||||
|
## Common Bugs and Debugging
|
||||||
|
- Shell falls back to default script:
|
||||||
|
- Check `ramdisk/shell/init.cmd` exists and is packed into ramdisk.
|
||||||
|
- `stats` values not updated:
|
||||||
|
- Confirm syscall IDs and wrappers remain aligned between kernel/user headers.
|
||||||
|
- Script command ignored unexpectedly:
|
||||||
|
- Verify command is not prefixed with `#` and does not exceed line buffer.
|
||||||
|
- `cat` output truncated:
|
||||||
|
- Current stage intentionally limits `cat` output to `SHELL_CAT_MAX` bytes.
|
||||||
|
- Boot regression after Stage13 merge:
|
||||||
|
- Re-check sequence: exec init -> userland init -> scheduler/services -> interrupts.
|
||||||
12
ramdisk/shell/init.cmd
Normal file
12
ramdisk/shell/init.cmd
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Stage13 shell init script for CLeonOS
|
||||||
|
# Lines starting with # are comments.
|
||||||
|
|
||||||
|
help
|
||||||
|
stats
|
||||||
|
ls /
|
||||||
|
ls /shell
|
||||||
|
ls /system
|
||||||
|
cat /README.txt
|
||||||
|
run /system/elfrunner.elf
|
||||||
|
run /system/memc.elf
|
||||||
|
stats
|
||||||
Reference in New Issue
Block a user