質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.33%

  • C

    3991questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

簡易的なシェルプログラムを作りたい

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 470

C言語です
fork(),execv(),wait()などの関数を用いて簡易的なシェルを実装して見たいのですが、
execv()を呼び出すところで上手くいきません。
入力はパス名とコマンドを空白区切で実行します。
入力された1行を空白文字で区切り、文字列配列に格納。
その配列を用いてexecvを呼び出します。
コマンドラインの"0>>"の0はコマンドの実行結果に応じて変化します。

個人的な考察としては、execvに渡す配列の末尾にNULL文字が上手く格納されてないのが原因だと思いますが、詳しいところがよくわかりません。

ご教授のほどよろしくお願いします。

発生している問題・エラーメッセージ

$ ./test 
0>> /bin/ls -l
execv
: No such file or directory
0>> /bin/ls
execv
: No such file or directory
0>> 

該当のソースコード

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

char* gettoken(char **ptr) {
  char *tmp = *ptr; /* tmp[idx] の形で使用する */
  int idx = 0;
  while(tmp[idx]==' '){/* 先頭のスペースを読み飛ばす */
    idx++;
  }
  int start=idx; //start:start index of string
  while(tmp[idx]!=' ' && tmp[idx]!='\0'){/* 単語の終わりを見つける */
    idx++;
  }
  //単語の終りはこの行でのt-1
  if(start==idx){
    return NULL;
  }
  int n = idx-start; //idx-start:string size
  char *token = malloc(n+1); //+1:null character malloc で単語の領域を token に確保
  strncpy(token,&tmp[start],n);/* 単語の文字を token の指す領域にコピー */
  *ptr = &tmp[idx]; /* 次の呼び出し用に引数を更新 */
  return token; /* 単語を取り出せた場合 (他で NULL を返す) */
}

char **buildup_arg(char *str) {
  const int N = 10;
  int i=0,sz = 0;
  char **ptr = malloc(sizeof(char*)*N);
  if(ptr==NULL){perror("malloc\n"); return 0;}
  char *token = str;
  while (token != NULL) {
    token = gettoken(&str);
    if(i>=sz){
      sz+=N;
      ptr = realloc(ptr,sizeof(char*)*sz);
      if(ptr==NULL){ perror("realloc"); return 0; }
    }
    ptr[i++] = token;
  }
  ptr[i++]=(char*)NULL;
  return ptr;
}
int main() {
  size_t sz=0,n;
  char* str=NULL;
  int cret=0;
  while(printf("%d>> ",cret) &&(n=getline(&str,&sz,stdin)) != -1){
    if(str[0] == '\n'){
      continue;
    }
    char **arg = buildup_arg(str);
    pid_t pid = fork();
    if(pid<0){
      perror("fork\n");
      return 1;
    }else if(pid==0){
      execv(arg[0],arg);
      perror("execv\n");
      //return -1;
      //exit(-1);
    }else{
      if(wait(&cret)==-1){
        perror("wait\n");
      }
      printf("child exits with %d\n",WEXITSTATUS(cret));
    }
  }
  return 0;
}

試したこと

課題に対してアプローチしたことを記載してください

補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • A.Ichi

    2017/12/16 12:31

    コマンドの最後に\nが含まれています。ですので/bin/echo abcは行けるかも

    キャンセル

回答 1

+2

このプログラムに、gettokenの戻り値を確認するためデバッグプリントを入れてみました。

追加したデバッグプリント(36行目あたり)

     35   while (token != NULL) {
     36     token = gettoken(&str);
        // ここから
     37 for (int j = 0; token[j]; j++) {
     38   printf("buildup_arg[%d]: %02x\n", j, token[j]);
     39 }
        // ここまで

実行した結果は次のようになりました。

$ ./t
0>> ls
buildup_arg[0]: 6c       // 'l'
buildup_arg[1]: 73       // 's'
buildup_arg[2]: 0a       // '\n'
buildup_arg[3]: ffffffe2
buildup_arg[4]: ffffffb5
buildup_arg[5]: 15
buildup_arg[6]: 4f
buildup_arg[7]: 39
buildup_arg[8]: 01
buildup_arg[9]: 02
Segmentation fault (コアダンプ)

プログラムを動かすためにはこんな感じにデバッグをすることが最も大切だと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.33%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C

    3991questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。