左無題 右無題
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>   // fork, execvp #include <unistd.h>   // fork, execvp
#include <sys/wait.h> // waitpid #include <sys/wait.h> // waitpid
#include <glob.h>     // glob #include <glob.h>     // glob
#include <errno.h>    // errno #include <errno.h>    // errno
#include <limits.h>   // PATH_MAX #include <limits.h>   // PATH_MAX
   
#define MAX_CMD_LEN 1024 #define MAX_CMD_LEN 1024
#define MAX_ARGS 100 #define MAX_ARGS 100
   
// 組み込みコマンド関連の宣言 // 組み込みコマンド関連の宣言
int cd (char *argv[]); int cd (char *argv[]);
int pwd(char *argv[]); int pwd(char *argv[]);
struct builtin { struct builtin {
    char cmd[256];              // コマンド名     char cmd[256];              // コマンド名
    int (*func)(char *argv[]);  // 関数へのポインタ     int (*func)(char *argv[]);  // 関数へのポインタ
}; };
struct builtin blt_in[] = {{"cd",cd}, {"pwd",pwd}, {"",0}}; struct builtin blt_in[] = {{"cd",cd}, {"pwd",pwd}, {"",0}};
   
// コマンドをスペースで分割する関数 // コマンドをスペースで分割する関数
void parse_command(char *cmd, char *argv[]) { void parse_command(char *cmd, char *argv[]) {
    char *token = strtok(cmd, " \n");     char *token = strtok(cmd, " \n");
    int i = 0;     int i = 0;
    while (token != NULL) {     while (token != NULL) {
        argv[i++] = token;         argv[i++] = token;
        token = strtok(NULL, " \n");         token = strtok(NULL, " \n");
    }     }
    argv[i] = NULL; // 最後の引数をNULLで終わらせる     argv[i] = NULL; // 最後の引数をNULLで終わらせる
} }
   
// 引用符を削除する関数 // 引用符を削除する関数
void remove_quotes(char *str) { void remove_quotes(char *str) {
    char *src = str, *dst = str;     char *src = str, *dst = str;
    while (*src) {     while (*src) {
        if (*src == '"' || *src == '\'') {         if (*src == '"' || *src == '\'') {
            src++;  // 引用符をスキップ             src++;  // 引用符をスキップ
        } else {         } else {
            *dst++ = *src++;             *dst++ = *src++;
        }         }
    }     }
    *dst = '\0';  // 文字列の終端を追加     *dst = '\0';  // 文字列の終端を追加
} }
   
// 引数リストにパス名展開を適用する関数 // 引数リストにパス名展開を適用する関数
int expand_arguments(char *argv[], char **expanded_argv) { int expand_arguments(char *argv[], char **expanded_argv) {
    glob_t glob_result;     glob_t glob_result;
    int argc = 0; // 展開後の引数数     int argc = 0; // 展開後の引数数
   
    for (int i = 0; argv[i] != NULL; i++) {     for (int i = 0; argv[i] != NULL; i++) {
        // 引用符が含まれている場合は展開しない         // 引用符が含まれている場合は展開しない
        if ((strchr(argv[i], '*') || strchr(argv[i], '?') || strchr(argv[i], '[')) &&         if ((strchr(argv[i], '*') || strchr(argv[i], '?') || strchr(argv[i], '[')) &&
            (argv[i][0] != '"' && argv[i][0] != '\'')) { // 引用符外でパス名展開             (argv[i][0] != '"' && argv[i][0] != '\'')) { // 引用符外でパス名展開
            if (glob(argv[i], GLOB_NOCHECK | GLOB_TILDE, NULL, &glob_result) != 0) {             if (glob(argv[i], GLOB_NOCHECK | GLOB_TILDE, NULL, &glob_result) != 0) {
                perror("glob failed");                 perror("glob failed");
                return -1;                 return -1;
            }             }
            // 展開された結果を追加             // 展開された結果を追加
            for (size_t j = 0; j < glob_result.gl_pathc; j++) {             for (size_t j = 0; j < glob_result.gl_pathc; j++) {
                if (argc >= MAX_ARGS - 1) {                 if (argc >= MAX_ARGS - 1) {
                    fprintf(stderr, "Too many arguments after glob expansion\n");                     fprintf(stderr, "Too many arguments after glob expansion\n");
                    globfree(&glob_result);                     globfree(&glob_result);
                    return -1;                     return -1;
                }                 }
                expanded_argv[argc++] = strdup(glob_result.gl_pathv[j]);                 expanded_argv[argc++] = strdup(glob_result.gl_pathv[j]);
            }             }
            globfree(&glob_result); // メモリを解放             globfree(&glob_result); // メモリを解放
        } else {         } else {
            // 引用符を取り除く             // 引用符を取り除く
            remove_quotes(argv[i]);             remove_quotes(argv[i]);
   
            // パス名展開が不要な場合             // パス名展開が不要な場合
            if (argc >= MAX_ARGS - 1) {             if (argc >= MAX_ARGS - 1) {
                fprintf(stderr, "Too many arguments\n");                 fprintf(stderr, "Too many arguments\n");
                return -1;                 return -1;
            }             }
            expanded_argv[argc++] = strdup(argv[i]);             expanded_argv[argc++] = strdup(argv[i]);
        }         }
    }     }
    expanded_argv[argc] = NULL; // 最後にNULLを追加     expanded_argv[argc] = NULL; // 最後にNULLを追加
    return argc;     return argc;
} }
   
// 組み込みコマンドの判定・実行 // 組み込みコマンドの判定・実行
.int built_in(char *argv[]){ int built_in(char *argv[], int bg){
    struct builtin *p;     struct builtin *p;
    // 組み込みコマンド配列(blt_in)の走査     // 組み込みコマンド配列(blt_in)の走査
    for (p = blt_in; *p->cmd != '\0'; p++) {     for (p = blt_in; *p->cmd != '\0'; p++) {
        // 組み込みコマンドでない場合は次をチェック         // 組み込みコマンドでない場合は次をチェック
        if (strcmp(p->cmd, argv[0]) != 0) continue;         if (strcmp(p->cmd, argv[0]) != 0) continue;
.          // バックグラウンド実行の場合
          if (bg) {
              pid_t pid = fork();
              if (pid == -1) {
                  perror("fork failed");
                  exit(1);
              }
              // 子プロセス
              if (pid == 0) exit ((p->func)(argv)); // 組み込みコマンドの関数を呼び出し
              // 親プロセス
              fprintf(stderr, "Background process started with PID: %d\n", pid);
              return 0;
          }
          // バックグラウンド実行でない場合
        // 組み込みコマンドの関数を呼び出し         // 組み込みコマンドの関数を呼び出し
        (p->func)(argv);         (p->func)(argv);
        return 0;         return 0;
    }     }
    return -1;     return -1;
} }
   
// cd コマンド // cd コマンド
int cd(char *argv[]) { int cd(char *argv[]) {
    if (argv[1] == NULL) {     if (argv[1] == NULL) {
        // 引数なしの場合はホームディレクトリに移動         // 引数なしの場合はホームディレクトリに移動
        const char *home_dir = getenv("HOME");         const char *home_dir = getenv("HOME");
        if (home_dir == NULL) {         if (home_dir == NULL) {
            perror("cd: HOME not set");             perror("cd: HOME not set");
            return -1;             return -1;
        } else {         } else {
            if (chdir(home_dir) != 0) {             if (chdir(home_dir) != 0) {
                perror("cd failed");                 perror("cd failed");
                return -1;                 return -1;
            }             }
        }         }
    } else {     } else {
        // 引数が指定された場合、そのディレクトリに移動         // 引数が指定された場合、そのディレクトリに移動
        if (chdir(argv[1]) != 0) {         if (chdir(argv[1]) != 0) {
            perror("cd failed");             perror("cd failed");
            return -1;             return -1;
        }         }
    }     }
    return 0;     return 0;
} }
   
// pwd コマンド // pwd コマンド
int pwd(char *argv[]){ int pwd(char *argv[]){
    char buf[PATH_MAX+1];     char buf[PATH_MAX+1];
    if (getcwd(buf, sizeof(buf)) == NULL) {     if (getcwd(buf, sizeof(buf)) == NULL) {
        perror("getcwd failed");         perror("getcwd failed");
        return -1;         return -1;
    }     }
    printf("%s\n", buf);     printf("%s\n", buf);
    return 0;     return 0;
} }
   
.  // バックグラウンド実行判定
  // コマンドの末尾が '&' かどうかを確認し、'&' を取り除いて戻り値として返す
  int is_background_command(char *argv[]) {
      int i = 0;
      while (argv[i] != NULL) i++;
      if (i > 0 && strcmp(argv[i - 1], "&") == 0) {
          argv[i - 1] = NULL; // '&' をコマンド引数から削除
          return 1;
      }
      return 0;
  }
   
int main() { int main() {
    char cmd[MAX_CMD_LEN]; // コマンド入力用のバッファ     char cmd[MAX_CMD_LEN]; // コマンド入力用のバッファ
    char *argv[MAX_ARGS];  // コマンド引数     char *argv[MAX_ARGS];  // コマンド引数
    char *expanded_argv[MAX_ARGS]; // 展開後の引数     char *expanded_argv[MAX_ARGS]; // 展開後の引数
.    pid_t pid;     pid_t pid, wpid;
    int status;     int status, bg;
   
    // シェルのメインループ     // シェルのメインループ
    while (1) {     while (1) {
.          // ゾンビを消滅させる
          while ((wpid = waitpid(-1, &status, WNOHANG)) > 0)
              fprintf(stderr, "process %d done\n", wpid);
   
        // プロンプトを表示         // プロンプトを表示
        fprintf(stderr, "mysh> ");         fprintf(stderr, "mysh> ");
   
        // コマンドを読み込む         // コマンドを読み込む
        if (fgets(cmd, sizeof(cmd), stdin) == NULL) {         if (fgets(cmd, sizeof(cmd), stdin) == NULL) {
            if (feof(stdin)) {             if (feof(stdin)) {
                break; // EOFが入力された場合、終了                 break; // EOFが入力された場合、終了
            }             }
            perror("fgets failed");             perror("fgets failed");
            continue;             continue;
        }         }
   
        // コマンドを解析         // コマンドを解析
        parse_command(cmd, argv);         parse_command(cmd, argv);
   
        // 空のコマンドの場合は次の入力へスキップ         // 空のコマンドの場合は次の入力へスキップ
        if (argv[0] == NULL) {         if (argv[0] == NULL) {
            continue;             continue;
        }         }
   
        // 終了コマンドの場合         // 終了コマンドの場合
        if (strcmp(argv[0], "exit") == 0) {         if (strcmp(argv[0], "exit") == 0) {
            break;             break;
        }         }
   
.          // バックグラウンド実行判定
          bg = is_background_command(argv);
   
        // 引数を展開         // 引数を展開
        if (expand_arguments(argv, expanded_argv) == -1) {         if (expand_arguments(argv, expanded_argv) == -1) {
            fprintf(stderr, "Argument expansion failed\n");             fprintf(stderr, "Argument expansion failed\n");
            continue;             continue;
        }         }
   
        // 組み込みコマンド判定・実行         // 組み込みコマンド判定・実行
.        if (built_in(expanded_argv) == 0) {         if (built_in(expanded_argv, bg) == 0) {
            continue;             continue;
        }         }
   
        // 子プロセスを作成してコマンドを実行         // 子プロセスを作成してコマンドを実行
        pid = fork();         pid = fork();
        if (pid == -1) {         if (pid == -1) {
            perror("fork failed");             perror("fork failed");
            exit(1);             exit(1);
        }         }
   
        // 子プロセス         // 子プロセス
        if (pid == 0) {         if (pid == 0) {
            // execvpを使用してコマンドを実行             // execvpを使用してコマンドを実行
            if (execvp(expanded_argv[0], expanded_argv) == -1) {             if (execvp(expanded_argv[0], expanded_argv) == -1) {
                perror("exec failed");                 perror("exec failed");
                exit(1);                 exit(1);
            }             }
        }         }
   
        // 親プロセス         // 親プロセス
        while (1) {         while (1) {
.              // バックグラウンド実行の場合
              if (bg) {
                  fprintf(stderr, "Background process started with PID: %d\n", pid);
                  break; // バックグラウンド実行の場合は待機しない
              }
              // バックグラウンド実行でない場合
            if (waitpid(pid, &status, 0) == (pid_t)-1) { // 子プロセスの終了を待つ             if (waitpid(pid, &status, 0) == (pid_t)-1) { // 子プロセスの終了を待つ
                if (errno == EINTR) {                 if (errno == EINTR) {
                    continue; // 割り込み発生時はリトライする                     continue; // 割り込み発生時はリトライする
                } else {                 } else {
                    perror("waitpid failed");                     perror("waitpid failed");
                    exit(1);                     exit(1);
                }                 }
            }             }
            break;             break;
        }         }
   
        // メモリを解放         // メモリを解放
        for (int i = 0; expanded_argv[i] != NULL; i++) {         for (int i = 0; expanded_argv[i] != NULL; i++) {
            free(expanded_argv[i]);             free(expanded_argv[i]);
        }         }
    }     }
   
    printf("Exiting shell...\n");     printf("Exiting shell...\n");
    return 0;     return 0;
} }