私は自分のシェルを書いています。redirection
(>
および)を実装したいです>>
。これにはdup2()
システムコールを使用しました。しかし、私が入力したコマンドにリダイレクトがある場合、他のコマンドは私が使用していないか含まれていなくても以前の>
リダイレクト>>
に従います。古いファイル記述子を閉じることがありませんか?また、>を使用しても出力は常にファイルに追加されます。
以下は私のコードです。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <setjmp.h>
#include <signal.h>
#include <fcntl.h>
#include <stdbool.h>
#define MAXLINE 259
#define PROMPT "> "
#define MAX_ARG_LIST 200
//-Wno-write-strings to g++ compiler to supress warnings
extern char **environ;
#define MAX_CMD_SIZE 50
#define SEARCH_FOR_CMD -1
typedef void (*buildInFunc) (char **);
typedef struct {
char cmd[MAX_CMD_SIZE];
buildInFunc func;
} builtInCmd;
// built-in commands
void execExit(char *cmd[]);
void execCd(char *cmd[]);
builtInCmd builtInCmds[] = {
{"exit", execExit },
{"cd", execCd }
};
int builtInCnt = sizeof(builtInCmds)/sizeof(builtInCmd);
int isBuiltIn(char *cmd);
void execBuiltIn(int i, char *cmd[]);
// capture SIG_INT and recover
sigjmp_buf ctrlc_buf;
void ctrl_hndlr(int signo) {
siglongjmp(ctrlc_buf, 1);
}
int main(int argc, char *argv[]) {
char line[MAXLINE];
pid_t childPID;
int argn; char *args[MAX_ARG_LIST];
int cmdn;
char *in_file,*out_file;
char *gt=">"; //truncate redirection char pointer
char *gtgt=">>"; //append redirection char pointer
int in_fd,out_fd; //
bool out_fd_present=false; //checks if > or >> string is present
// setup SIG_INT handler
if (signal(SIGINT, ctrl_hndlr) == SIG_ERR)
fputs("ERROR: failed to register interrupts in kernel.\n", stderr);
// setup longjmp buffer
while (sigsetjmp(ctrlc_buf, 1) != 0) ;
for(;;) {
// prompt and get commandline
fputs(PROMPT, stdout);
fgets(line, MAXLINE, stdin);
if (feof(stdin)) break; // exit on end of input
// process commandline
if (line[strlen(line)-1] == '\n')
line[strlen(line)-1] = '\0';
// build argument list
args[argn=0]=strtok(line, " \t");
while(args[argn]!=NULL && argn<MAX_ARG_LIST){
args[++argn]=strtok(NULL," \t");
//if append >> redirection present
if(strcmp( args[argn-1],gtgt ) == 0){
out_fd_present=true;
out_file=args[argn];
argn=argn-2;
out_fd = open(out_file, O_WRONLY | O_APPEND | O_CREAT,S_IRWXG | S_IRWXO | S_IRWXU);
//printf("\n >> found\n");
}
//if trncate > redirection present
else if(strcmp( args[argn-1],gt ) == 0){
out_fd_present=true;
out_file=args[argn];
argn=argn-2;
out_fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXG | S_IRWXO | S_IRWXU);
//printf("\n > found\n");
}
printf("args[%d]=%s\n",argn-1,args[argn-1]);
}
// execute commandline
if ((cmdn = isBuiltIn(args[0]))>-1) {
execBuiltIn(cmdn, args);
} else {
childPID = fork();
int save_out;
if (childPID == 0) {
if(out_fd_present){
int a;
save_out = dup(STDOUT_FILENO);
dup2(out_fd,1);
close(out_fd);
}
execvp(args[0], args);
fputs("ERROR: can't execute command.\n", stderr);
_exit(1);
} else {
waitpid(childPID, NULL, 0);
}
}
// cleanup
fflush(stderr);
fflush(stdout);
}
return 0;
}
int isBuiltIn(char *cmd) {
int i = 0;
while (i<builtInCnt) {
if (strcmp(cmd,builtInCmds[i].cmd)==0)
break;
++i;
}
return i<builtInCnt?i:-1;
}
void execBuiltIn(int i, char *cmd[]) {
if (i == SEARCH_FOR_CMD)
i = isBuiltIn(cmd[0]);
if (i >= 0 && i < builtInCnt)
builtInCmds[i].func(cmd);
else
fprintf(stderr, "ERROR: unknown built-in command\n");
}
void execExit(char *cmd[]) {
exit(0);
}
void execCd(char *cmd[]){
chdir(cmd[1]);
}
答え1
単純な論理エラーがあります。またはを検出すると、決してout_fd_present
リセットされません(たとえば、ループの上部で)。true
>
>>
false
私はあなたの「殻」がおもちゃの殻であると推測していますが、他の質問もたくさんあることに言及する必要があります。たとえば、out_fd
親プロセスとsave_out
子プロセスでリークが発生します(これは何のためですか?)。strcmp
文字列を呼び出すことができるバグがありますNULL
。これに関する別の図がありますchdir
。構文と機能も、シェルが「必要とする」操作(リダイレクト演算子の位置、umask、間隔、トークン化など)とは異なります。文体上の不一致は言うまでもなく(醜いラクダ箱とヘビ箱の両方が使用されました)。シェルを実装するには、おもちゃのシェルでも最初に良いデザインから始める必要があります。