前提・実現したいこと
自作シェルでリダイレクト(>>)を実装したいのですが
以下のコードを実行すると無限ループに陥ってしまいます。
このコードのどこが無限ループの原因となっているのか教えていただきたいです。
【追記1】
指摘を受けて:
getCommand
の他、省略していた関数やデバッグ文を記述しました。
リダイレクトのみ機能していない状態だったので該当のコードのみ載せたのですが誤解を招いてしまいすみません。
以下のコードをコンパイルして動かすとパイプ、リダイレクトを含まないコマンド及びパイプコマンドは問題なく動くのですが、リダイレクトの場合にプロセスが無限に作られてしまいCTRL+C
等でプログラムを終了できない状態になってしまいます。
【追記2】
239行目にexit(1)
を追加した所正常に動くようになりました。なぜここにexit(1)
がないと無限プロセス作成エラーになるのか教えていただける方がいたらお願いしたいです。
該当のソースコード
C
1 2#include <stdio.h> 3#include <stdlib.h> 4#include <unistd.h> 5#include <string.h> 6#include <errno.h> 7#include <sys/wait.h> 8#include <sys/stat.h> 9#include <sys/types.h> 10#include <fcntl.h> 11#define MAX_ARG 50 12#define READ 0 13#define WRITE 1 14 15/* @戻り値 0 => 普通のコマンド, 1 => パイプコマンド, 2 => リダイレクトコマンド */ 16void Type(char* command, int* type, int* splitPosition){ 17 int pos = 0; 18 19 (*type) = 0; 20 21 while(command[pos] != '\0'){ 22 23 if(command[pos] == '|'){ 24 (*type) = 1; 25 (*splitPosition) = pos; 26 } 27 else if(command[pos] == '>' && command[pos+1] == '>'){ 28 (*type) = 2; 29 (*splitPosition) = pos; 30 } 31 32 pos++; 33 } 34} 35 36int substr(char* S1, char* S2, int P, int L){ 37 if( P < 0 || L < 0 || L > strlen(S1) ){ 38 return -1; 39 } 40 41 for( S1 += P; *S1 != '\0' && L > 0; L--){ 42 *S2++ = *S1++; 43 } 44 45 *S2 = '\0'; 46 47 return 0; 48} 49 50 51void split(char* command, char* part1, char* part2, int* type){ 52 int splitPosition = 0; 53 54 Type(command, type, &splitPosition); 55 56 #ifndef DEBUG 57 printf("splitPosition = %d\n", splitPosition); 58 #endif 59 60 if( (*type) != 0 ){ 61 int start = ( (*type) == 1 )? splitPosition + 1 : splitPosition + 2; /* 修正:>> or | の前後にスペース無しに対応 */ 62 int len = strlen(command) - start; 63 64 if( substr(command, part1, 0, splitPosition) < 0 || 65 substr(command, part2, start, len) < 0){ 66 perror("substr\n"); 67 exit(1); 68 } 69 } else { 70 strcpy(part1, command); 71 } 72 73 #ifndef DEBUG 74 printf("part1 = %s\n", part1); 75 printf("part2 = %s\n", part2); 76 #endif 77} 78 79void getCommand(char* command){ 80 81 scanf("%255[^\n]%*[^\n]", command); 82 scanf("%*c"); 83 84 #ifndef DEBUG 85 printf("command = %s\n", command); 86 #endif 87} 88 89 90int to_token(char* command, char** tokens){ 91 int argc = 0; 92 93 tokens[argc] = strtok(command, " "); 94 95 while(argc < MAX_ARG){ 96 tokens[++argc] = strtok(NULL, " "); 97 98 if(tokens[argc] == NULL){ 99 break; 100 } 101 } 102 103 return argc; 104} 105 106 107int Parse(char* command, char** parsedCommand){ 108 int argc = to_token(command, parsedCommand); 109 int ret; 110 111 if(strcmp( parsedCommand[argc - 1], "&") == 0){ 112 parsedCommand[argc - 1] = NULL; 113 ret = 1; 114 } else { 115 ret = 0; 116 } 117 118 return ret; 119} 120 121 122void RegCmd(char* part1){ 123 char* parsedCommand[20]; 124 int background; 125 pid_t pid; 126 127 background = Parse(part1, parsedCommand); 128 129 if( (pid = fork()) == 0){ 130 execvp(parsedCommand[0], parsedCommand); 131 perror("execvp failed\n"); 132 exit(1); 133 } else { 134 if(!background){ 135 waitpid(pid, NULL, 0); 136 } 137 } 138} 139 140void PipeCmd(char* part1, char* part2){ 141 char* cmd_left[20]; 142 char* cmd_right[20]; 143 int fds[2]; 144 pid_t pid1, pid2; 145 int background; 146 147 if( pipe(fds) < 0){ 148 perror("pipe failed\n"); 149 exit(1); 150 } 151 152 153 background = Parse(part1, cmd_left) || 154 Parse(part2, cmd_right); 155 156 if( (pid1 = fork()) < 0){ 157 perror("fork failed\n"); 158 exit(1); 159 } 160 161 if( pid1 == 0 ){ 162 dup2(fds[READ], 0); 163 close(fds[WRITE]); 164 execvp(cmd_right[0], cmd_right); 165 perror("execvp failed\n"); 166 } 167 168 if( (pid2 = fork()) < 0){ 169 perror("fork failed\n"); 170 exit(1); 171 } 172 173 if( pid2 == 0 ){ 174 dup2(fds[WRITE], 1); 175 close(fds[READ]); 176 execvp(cmd_left[0], cmd_left); 177 perror("execvp failed\n"); 178 } 179 else { 180 close(fds[0]); 181 close(fds[1]); 182 183 if(!background){ 184 waitpid(pid1, NULL, 0); 185 waitpid(pid2, NULL, 0); 186 } 187 } 188} 189 190void RedirectCmd(char* part1, char* part2){ 191 char* cmd_left[20]; 192 char* cmd_right[20]; 193 int fds[2]; 194 int fd; 195 int count; 196 pid_t pid1, pid2; 197 int background; 198 char c; 199 200 if( pipe(fds) < 0){ 201 perror("pipe failed\n"); 202 exit(1); 203 } 204 205 206 background = Parse(part1, cmd_left) || 207 Parse(part2, cmd_right); 208 209 210 if( (pid1 = fork()) < 0){ 211 perror("fork failed\n"); 212 exit(1); 213 } 214 215 if( pid1 == 0 ){ 216 dup2(fds[WRITE], 1); 217 close(fds[READ]); 218 execvp(cmd_left[0], cmd_left); 219 perror("execvp failed\n"); 220 exit(1); 221 } 222 223 if( (pid2 = fork()) < 0){ 224 perror("fork failed\n"); 225 exit(1); 226 } 227 228 if( pid2 == 0 ){ 229 if( (fd = open(cmd_right[0], O_RDWR | O_CREAT | O_APPEND, 0600)) < 0){ 230 perror("open failed\n"); 231 close(fd); 232 exit(1); 233 } 234 235 dup2(fds[READ], 0); 236 close(fds[WRITE]); 237 238 while( (count = read(0, &c, 1)) > 0){ 239 write(fd, &c, 1); 240 } 241 242 close(fd); 243 244 /**** 追記2 : exit(1)がないと無限プロセスになるため追加 ****/ 245 exit(1); 246 } 247 else { 248 close(fds[READ]); 249 close(fds[WRITE]); 250 waitpid(pid1, NULL, 0); 251 waitpid(pid2, NULL, 0); 252 } 253 254} 255 256int main(void){ 257 char cmd[256]; 258 char part1[128]; 259 char part2[128]; 260 int type = -1; 261 262 printf("\n> "); 263 getCommand(cmd); 264 265 while( (strcmp(cmd, "quit")!=0) && 266 (strcmp(cmd, "exit")!=0) ){ 267 split(cmd, part1, part2, &type); 268 269 if(type == 0){ 270 RegCmd(part1); 271 } 272 else if(type == 1){ 273 PipeCmd(part1, part2); 274 } 275 else if(type == 2){ 276 RedirectCmd(part1, part2); 277 } 278 279 #ifndef DEBUG 280 printf("\nType = %d", type); 281 #endif 282 283 printf("\n> "); 284 getCommand(cmd); 285 } 286 return 0; 287} 288 289