[英]Handle signals and process writing my own shell
我正在嘗試制作一個提示命令並等待用戶輸入的 shell。 我希望我的 shell 在用戶按下ctrl-c
時打印另一個提示,並在他按下ctrl-d
時退出。
這是主循環:
int my_shell(char **env)
{
char *cmd_line;
while (true)
{
print_prompt();
cmd_line = get_cmd();
process(cmd_line);
}
return (0);
}
我能夠捕捉ctrl-c
和ctrl-d
信號,但我不知道如何構建主循環以在合適的地方退出。 我嘗試使用多個fork()
、 wait()
、 getpid()
但我做錯了。
這是我的嘗試之一:
int extern_pid;
int intern_pid;
int my_shell(char **env)
{
char *cmd_line;
extern_pid = getpid();
while (true)
{
if (fork() == 0)
{
intern_pid = getpid();
print_prompt();
cmd_line = get_cmd();
process(cmd_line);
exit(0);
}
else
{
wait(0);
}
}
return (0);
}
並使用這些信號處理程序:
void ctrlc_handler(int signal)
{
if (getpid() == intern_pid)
exit(0);
}
void ctrld_handler(int signal)
{
if (getpid() == extern_pid)
exit(0);
}
注意: ctrl-d
信號在get_cmd()
函數中處理。
不必使用 fork 創建子進程來處理自定義 shell 中的 Ctrl-C 信號。 一種可能性是將信號處理程序與 sigsetjmp/siglongjmp 一起使用。
程序如下:
由於信號處理程序總是可以被調用,甚至可能在調用 sigsetjmp() 之前,必須確保 siglongjmp() 已經可以被調用。 這是通過設置一個名為 jmp_set 的易失性變量 sig_atomic_t 來完成的。
函數process
只知道一個名為exit
內部命令。 正如在問題的評論中已經指出的那樣,如果用戶輸入 Ctrl-D 作為行首的第一個字符,這將自動導致 getchar 調用中的 EOF。 函數 get_cmd 然后在此處返回命令exit
。 或者,用戶可以輸入命令exit
來結束程序。
在函數process
該位置標有注釋,您可能希望在該位置使用 fork/exec 調用外部程序。 無論程序是否應該退出,它都會返回一個布爾值。 可能在這里也可以評估來自外部程序調用的狀態代碼。
這是一個小型的、自包含的示例程序,帶有您的 ctrlc_handler、get_cmd 和 process 函數布局,用 sigsetjmp()/siglongjmp() 擴展,當然不完整,但可能是一個起點:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <setjmp.h>
#define MAX_CMD_LENGTH 1024
static const char *const EXIT_CMD = "exit";
static sigjmp_buf env;
static volatile sig_atomic_t jmp_set;
static void ctrlc_handler(int signal) {
if (jmp_set == 0)
return;
if (signal == SIGINT) {
siglongjmp(env, 1);
}
}
static char *get_cmd(void) {
char *cmd_buf = calloc(MAX_CMD_LENGTH, sizeof(char));
if (!cmd_buf) {
perror("malloc failed\n");
exit(1);
}
char *ptr = cmd_buf;
int ch = getchar();
while (ch != EOF && ch != '\n' && ptr < cmd_buf + MAX_CMD_LENGTH - 1) {
*ptr++ = (char) ch;
ch = getchar();
}
if (ch == EOF) {
strcpy(cmd_buf, EXIT_CMD);
}
return cmd_buf;
}
static bool process(char *cmd) {
if (strcmp(cmd, EXIT_CMD) == 0) {
return true;
}
// a call to fork together with a function from the
// exec family could be used to call external programs
printf("process '%s'\n", cmd);
return false;
}
static int cnt = 0;
int main(void) {
if (signal(SIGINT, ctrlc_handler) == SIG_ERR) {
perror("signal error");
exit(1);
}
if (sigsetjmp(env, 1)) {
printf("\n");
cnt++;
}
jmp_set = 1;
bool exit;
do {
printf("%d> ", cnt);
char *cmd = get_cmd();
exit = process(cmd);
free(cmd);
} while (!exit);
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.