MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C言語の基礎 - 外部コマンドのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C言語の基礎 - 外部コマンド
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == 異なるプロセスを生成して外部コマンドプログラムを実行する場合、<code>system</code>関数 (シェルの機能を使用してコマンドを実行) および<code>exec</code>関数ファミリーを使用する。<br> 他にも、<code>popen</code>関数 (パイプで通信可能) 等がある。<br> <br> ただし、これらの関数を実行する時、制御はそのプログラムへ移行するため自身のプログラムには戻らない。 (実行に失敗した場合だけ戻る)<br> そのため、処理を続行する場合は、<code>fork</code>関数と組み合わせて使用する必要がある。<br> <br><br> == system関数 == <code>system</code>関数はセキュリティ上の懸念があり、外部からの入力を直接実行することにより、悪意のあるコマンドインジェクション攻撃に対する脆弱性を持つ。 特に、外部からの入力を含む場合、その入力が信頼できるかどうかを確認する。<br> <br> <syntaxhighlight lang="c"> #include <stdio.h> #include <stdlib.h> int main() { // lsコマンドを実行する int result = system("ls non_existent_directory"); if (result != 0) { fprintf(stderr, "Command execution failed with error code: %d", result); } else { fprintf(stdout, "Command executed successfully"); } return 0; } </syntaxhighlight> <br><br> == exec関数ファミリー == ==== exec関数ファミリーとは ==== <code>system</code>関数の代わりに、外部コマンドを実行するためのより安全な方法が<code>execl</code>関数および<code>execv</code>関数である。<br> <br> <code>exec</code>関数ファミリーは、現在のプロセスを指定したプログラムに置き換えて実行する。<br> そのため呼び出し元へ制御が戻ることはない。<br> <br> 関数に渡される第1引数は実行されるプログラムのパスである。<br> 第2引数以降は、その実行されるプログラムのパスへ引数を指定する。<br> 第2引数において、<code>execl</code>関数は可変長の引数、<code>execv</code>関数は引数として配列が渡す。<br> <br> また、<code>exec</code>関数ファミリーの最後の引数は<code>NULL</code>または<code>nullptr</code>にする必要があり、<code>(char*)NULL</code>または<code>(char*)nullptr</code>とすべきである。<br> <br> ==== 戻り値 ==== エラーが起きた場合のみ呼び出し元に<code>-1</code>を返す。<br> それ以外の場合は復帰せず、戻り値も存在しない。<br> <br> ==== execl関数の使用例 ==== <syntaxhighlight lang="c"> #include <stdio.h> #include <unistd.h> #include <errno.h> int main() { // lsコマンドを実行する execl("/bin/ls", "ls", "-l", (char*)nullptr); if(errno != 0) { // エラーが発生した場合 perror("exec"); } return 0; } </syntaxhighlight> <br> ==== execv関数の使用例 ==== <syntaxhighlight lang="c"> #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> int main() { const char *str[] = {"/bin/echo", "hoge", "piyo", NULL}; // echoコマンドを実行する execv("/bin/echo", str); if(errno != 0) { // エラーが発生した場合 perror(strerror(errno)); } return 0; } </syntaxhighlight> <br> ==== fork関数の使用例 ==== <code>exec</code>関数ファミリーは制御が戻らないため、メインプロセスの処理を続行させる場合、<code>fork</code>関数により子プロセスを生成して、<code>exec</code>関数ファミリーを実行する。<br> <syntaxhighlight lang="c"> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid = fork(); if (pid < 0) { perror("fork"); exit(-1); } else if (pid == 0) { // 子プロセスで外部コマンドを実行する execlp("/usr/bin/echo", "echo", "abc", "def", NULL); perror("echo"); exit(-1); } // 親プロセス int status = 0; pid_t p = waitpid(pid, &status, 0); // 子プロセスの終了を待つ if (p < 0) { perror("waitpid"); exit(-1); } if (WIFEXITED(status)) { // 子プロセスが正常終了した場合 printf("child exit-code=%d\n", WEXITSTATUS(status)); } else { printf("child status=%04x\n", status); } return 0; } </syntaxhighlight> <br><br> == popen関数 == <code>popen</code>関数の引数に外部コマンドのパスを渡して実行することができる。<br> <code>popen</code>関数が返すファイルポインタを読み込むことにより、外部コマンドの出力を取得することができる。<br> <br> <code>popen</code>関数の実装は、<code>fork</code>関数、<code>pipe</code>関数、<code>dup2</code>関数、<code>execv</code>関数等のシステムコールを利用して実装されている。<br> <br> <syntaxhighlight lang="c"> #include <stdio.h> #include <stdlib.h> #include <err.h> int main() { FILE *fp = nullptr; char buf[256] = {}; char *pcmd = "/bin/ls /bin"; if ((fp = popen(pcmd, "r")) == nullptr) { err(EXIT_FAILURE, "%s", pcmd); } while(fgets(buf, BUF, fp) != nullptr) { (void)fputs(buf, stdout); } (void)pclose(fp); exit (EXIT_SUCCESS); } </syntaxhighlight> <br><br> __FORCETOC__ [[カテゴリ:C]]
C言語の基礎 - 外部コマンド
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse