System関数解析

3725 ワード

Linuxでのsystem関数の詳細分析


相関関数fork,execve,waitpid,popenヘッダファイル#include定義関数int system(const char*string);関数説明system()はfork()を呼び出してサブプロセスを生成し、サブプロセスによって/bin/sh-c stringを呼び出してパラメータstring文字列に代表されるコマンドを実行します.このコマンド>は、実行が完了すると元の呼び出しのプロセスに戻ります.システム()の呼び出し中にSIGCHLD信号は一時的に保留され、SIGINT信号とSIGQUIT信号は無視されます.戻り値=-1:エラー=0:呼び出しに成功したがサブプロセスが現れなかった>0:終了に成功したサブプロセスのid system()が/bin/shの呼び出しに失敗した場合は127、その他の失敗原因は-1を返す.パラメータstringが空のポインタ(NULL)の場合、ゼロ以外の値が返されます.system()呼び出しが成功すると、shellコマンドを実行した後の戻り値が最後に返されますが、この戻り値はsystem()呼び出し/bin/sh失敗で返された127である可能性もありますので、errnoを再確認して実行成功を確認することが望ましいです.追加の説明SUID/SGID権限を持つプログラムを作成するときはシステム()を使用しないでください.システム()は環境変数を継承し、環境変数によってシステムの安全上の問題を引き起こす可能性があります.例
#include<stdlib.h> 
main() 
{ 
system(“ls -al /etc/passwd /etc/shadow”); 
} 
 : 

-rw-r--r-- 1 root root 705 Sep 3 13 :52/etc/passwd 
-r--------- 1 root root 572 Sep 2 15 :34/etc/shado 

 2: 

char tmp[]; 
sprintf(tmp,"/bin/mount -t vfat %s/mnt/usb",dev); 
system(tmp); 
 dev /dev/sda1。

 
System()関数は機能が強く、多くの人がその原理をあまり知らないので、上記のように多くのレスがあります.systemの具体的な実現を知っていれば、多くのコンパイラの中で自分の希望の機能を表現できないことに理解できないと思います.私はlinuxの中の実現に対して比較的に理解して、具体的にこれを分析して、windowsの中の類似は詳しく分かりません.では、まずlinux版system関数のソースコードを見てみましょう.
 
int system(const char * cmdstring)
{
    pid_t pid;
    int status;

    if(cmdstring == NULL){
         return (1);
    }


    if((pid = fork())<0){

            status = -1;
    }
    else if(pid == 0){
        execl("/bin/sh","sh", "-c", cmdstring, (char *)0);
        -exit(127); // 
        }
    else{
            while(waitpid(pid,&status, 0) < 0){
                if(errno !=EINTER){
                   status = -1;
                   break;
                }
            }
        }
        return status;
}

道理で前回システムでスクリプトを呼び出したとき、バックグラウンドにsh-c***のプロセスが現れました.もし私が呼び出したスクリプトが遅々として実行できなければ、このプロセスも終了しません.
まず原理を分析してから、上のコードを見てみましょう.システムが受け入れたコマンドがNULLのときに直接戻ります.そうしないと、forkは2つのプロセス:親プロセスと子プロセスでforkが戻ってくるので、ここでは戻ってきたpidをチェックします.forkは子プロセスで0を返し、親プロセスで子プロセスのpidを返します.親プロセスはwaitpidを使って子プロセスが終わるのを待っています.サブプロセスはexeclを呼び出して自分の代わりにプログラムを起動し、execl("/bin/sh"、"sh"-c"、cmdstring、(char*)0)はshellを呼び出し、このshellの経路は/bin/shであり、後ろの文字列はパラメータであり、サブプロセスはshellプロセスになり、このshellのパラメータはcmdstringであり、systemが受け入れるパラメータである.Windowsのshellはcommandなので、shellが命令を受けてやったことをよく知っていると思います.もし上のあなたが理解していないならば、私は更にforkの原理を説明します:1つのプロセスAがforkを呼び出す時、システムのカーネルは1つの新しいプロセスBを作成して、そしてAのメモリのイメージをBのプロセス空間の中にコピーして、AとBは同じなので、それでは彼らはどのように自分が親のプロセスなのかそれとも子のプロセスなのかを知っていて、forkの戻り値を見て知っていて、上もforkが子のプロセスの中で0を返すと言って、親プロセスでサブプロセスのpidを返します.

Windowsで


Windowsの場合も似ていますが、execlは臭いし長い名前を変えて、パラメータ名も変えてめまいがしました.MSDNで原型を見つけました.HINSTANCE ShellExecute(HWND hwnd,LPCTSTR lpVerb,LPCTSTR lpFile,LPCTSTR lpParameters,LPCTSTR lpDirectory,INT nShowCmd);使用法は以下の通りである:ShellExecute(NULL,“open”,“c:\a.reg”,NULL,NULL,SW_SHOWNORMAL);ShellExecuteに親プロセス環境変数を渡すパラメータlpDirectoryがあるのは不思議かもしれませんが、linuxのexeclはありません.これはexeclがコンパイラの関数(特定のシステム実装をある程度隠す)であるためです.linuxではlinuxシステムの呼び出しexecveが生成されます.プロトタイプは、int execve(const char*file、const char**argv、const char**envp)です.ここを見るとsystem()が親プロセスの環境変数を受け入れる理由がわかりますが、systemで環境変数を変更すると、systemがメイン関数に戻ると変わらないことが22階で繰り返し強調されています.原因はsystemの実装から見ることができて、それは新しいプロセスを生成することによって実現して、私の分析から親プロセスと子プロセスの間にプロセス通信がなくて、子プロセスは自然に親プロセスの環境変数を変えることができません.おかずたちはtcやtcライブラリの他のコンパイラのsystemの呼び出し結果を使って私に反論しないでほしい.これは概念ではない.DOSはとっくに死んでいて、linuxを游んでいるだろう.ここまでです.私はbc-cnでこんなに長い間威望の精華を混ぜてまだすべて0で、今日手がけいれんすることを書いて、功労がなくても苦労があって、苦労がなくて疲労があって、版主は私に精を加えて、さもなくば私は後でやはり水区に行って水を入れて計算します