天天看點

資訊安全系統設計基礎第十一周學習總結

第八章代碼學習

exec1

#include<stdio.h>

#include<unistd.h>

int main()

{

    char  *arglist[3];

    arglist[0] = "ls";

    arglist[1] = "-l";

    arglist[2] = 0 ;//NULL

    printf("* * * About to exec ls -l\n");

    execvp( "ls" , arglist );

    printf("* * * ls is done. bye");

    return 0;

}

execvp()會從PATH 環境變量所指的目錄中查找符合參數file 的檔案名,找到後便執行該檔案,然後将第二個參數argv傳給該欲執行的檔案。如果執行成功則函數不會傳回,執行失敗則直接傳回-1,失敗原因存于errno中。在結果中我們可以看出exevp函數調用成功沒有傳回,是以沒有列印出“* * * ls is done. bye”。

exec2

exec1的差別就在于exevp函數的第一個參數,exec1傳的是ls,exec2直接用的arglist[0],不過由定義可得這兩個等價,運作結果相同。

exec3

int main()

    char   *arglist[3];

    char   *myenv[3];

    myenv[0] = "PATH=:/bin:";

    myenv[1] = NULL;

    arglist[0] = "ls";

    arglist[1] = "-l";

    arglist[2] = 0 ;

    printf("* * * About to exec ls -l\n");

//    execv( "/bin/ls" , arglist );

//    execvp( "ls" , arglist );

//  execvpe("ls" , arglist, myenv);

    execlp("ls", "ls", "-l", NULL);

    printf("* * * ls is done. bye\n");

execlp()會從PATH 環境變量所指的目錄中查找符合參數file的檔案名,找到後便執行該檔案,然後将第二個以後的參數當做該檔案的argv[0]、argv[1]……,最後一個參數必須用空指針(NULL)作結束。如果用常數0來表示一個空指針,則必須将它強制轉換為一個字元指針,否則将它解釋為整形參數,如果一個整形數的長度與char * 的長度不同,那麼exec函數的實際參數就将出錯。如果函數調用成功,程序自己的執行代碼就會變成加載程式的代碼,execlp()後邊的代碼也就不會執行了。是以運作結果同exec1。

forkdemo1

#include<sys/types.h>

    int    ret_from_fork, mypid;

    mypid = getpid();              

    printf("Before: my pid is %d\n", mypid);

    ret_from_fork = fork();

    sleep(1);

    printf("After: my pid is %d, fork() said %d\n",getpid(), ret_from_fork);

    return 0;

列印程序pid,然後調用fork函數生成子程序,休眠一秒後再次列印程序id,這時父程序列印子程序pid,子程序傳回0。

forkdemo2

    printf("before:my pid is %d\n", getpid() );

    fork();

    printf("aftre:my pid is %d\n", getpid() );

兩次調用fork,産生四個子程序,會列印四個after輸出。

forkdemo3

#include<stdlib.h>

    int    fork_rv;

    printf("Before: my pid is %d\n", getpid());

    fork_rv = fork();        /* create new process    */

    if ( fork_rv == -1 )        /* check for error    */

        perror("fork");

    else if ( fork_rv == 0 ){

        printf("I am the child.  my pid=%d\n", getpid());

        exit(0);

    }

    else{

        printf("I am the parent. my child is %d\n", fork_rv);

    }

fork産生子程序,父程序傳回子程序pid,不為0,是以輸出父程序的那句話,子程序傳回0,是以會輸出子程序語句。

forkdemo4

        printf("parent pid= %d, my pid=%d\n", getppid(), getpid());

        sleep(10);

先列印程序pid,然後fork建立子程序,父程序傳回子程序pid,是以輸出parent一句,休眠十秒;子程序傳回0,是以輸出child之後的語句。

forkgdb

int  gi=0;

    int li=0;

    static int si=0;

    int i=0;

    pid_t pid = fork();

    if(pid == -1){

        exit(-1);

    else if(pid == 0){

        for(i=0; i<5; i++){

            printf("child li:%d\n", li++);

            sleep(1);

            printf("child gi:%d\n", gi++);

            printf("child si:%d\n", si++);

        }

        exit(0);  

            printf("parent li:%d\n", li++);

            printf("parent gi:%d\n", gi++);

            printf("parent si:%d\n", si++);

    exit(0);   

父程序列印是先列印兩句,然後休眠一秒,然後列印一句,子程序先列印一句,然後休眠一秒,然後列印兩句。并且這兩個線程是并發的,是以可以看到在一個線程休眠的那一秒,另一個線程在執行,并且線程之間互相獨立互不幹擾。

psh1

#include<string.h>

#define   MAXARGS        20               

#define   ARGLEN        100               

int execute( char *arglist[] )

    execvp(arglist[0], arglist);       

    perror("execvp failed");

    exit(1);

char * makestring( char *buf )

    char    *cp;

    buf[strlen(buf)-1] = '\0';       

    cp = malloc( strlen(buf)+1 );       

    if ( cp == NULL ){           

        fprintf(stderr,"no memory\n");

        exit(1);

    strcpy(cp, buf);       

    return cp;           

    char  *arglist[MAXARGS+1];       

    int      numargs;           

    char    argbuf[ARGLEN];           

    numargs = 0;

    while ( numargs < MAXARGS )

    {                   

        printf("Arg[%d]? ", numargs);

        if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )

            arglist[numargs++] = makestring(argbuf);

        else

        {

            if ( numargs > 0 ){       

                arglist[numargs]=NULL;   

                execute( arglist );   

                numargs = 0;       

            }

輸入要執行的指令,回車表示輸入結束,然後輸入的每個參數對應到函數中,再調用對應的指令。

psh2

#include<sys/wait.h>

#include<signal.h>

char *makestring( char *buf )

void execute( char *arglist[] )

    int    pid,exitstatus;               

    pid = fork();                   

    switch( pid ){

        case -1:   

            perror("fork failed");

            exit(1);

        case 0:

            execvp(arglist[0], arglist);       

            perror("execvp failed");

        default:

            while( wait(&exitstatus) != pid )

            printf("child exited with status %d,%d\n",

                    exitstatus>>8, exitstatus&0377);

    char    *arglist[MAXARGS+1];       

    int        numargs;           

        else

多了循環判斷,不退出的話就會一直要你輸入指令,并且對于子程式存在的狀态條件。

testbuf1

    printf("hello");

    fflush(stdout);

    while(1);

效果是先輸出hello,然後換行不退出。

testbuf2

    printf("hello\n");

testbuf3

    fprintf(stdout, "1234", 5);

    fprintf(stderr, "abcd", 4);

将内容格式化輸出到标準錯誤、輸出流中。

testpid

    printf("my pid: %d \n", getpid());

    printf("my parent's pid: %d \n", getppid());

輸出目前程序pid和目前程序的父程序的pid。

testpp

    char **pp;

    pp[0] = malloc(20);

testsystem

int main ( int argc, char *argv[] )

    system(argv[1]);

    system(argv[2]);

    return EXIT_SUCCESS;

}   

執行shell指令,也就是向dos發送一條指令。這裡是後面可以跟兩個參數,然後向dos發送這兩個指令,分别執行。輸入ls和dir兩個指令後分别執行。

waitdemo1

#define    DELAY    4

void child_code(int delay)

    printf("child %d here. will sleep for %d seconds\n", getpid(), delay);

    sleep(delay);

    printf("child done. about to exit\n");

    exit(17);

void parent_code(int childpid)

    int wait_rv=0;        /* return value from wait() */

    wait_rv = wait(NULL);

    printf("done waiting for %d. Wait returned: %d\n",

            childpid, wait_rv);

    int  newpid;

    printf("before: mypid is %d\n", getpid());

    if ( (newpid = fork()) == -1 )

    else if ( newpid == 0 )

        child_code(DELAY);

    else

        parent_code(newpid);

如果有子程序,則終止子程序,成功傳回子程序pid。

waitdemo2

#define    DELAY    10

    exit(27);

    int wait_rv;   

    int child_status;

    int high_8, low_7, bit_7;

    wait_rv = wait(&child_status);

    printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rv);

    high_8 = child_status >> 8;     /* 1111 1111 0000 0000 */

    low_7  = child_status & 0x7F;   /* 0000 0000 0111 1111 */

    bit_7  = child_status & 0x80;   /* 0000 0000 1000 0000 */

    printf("status: exit=%d, sig=%d, core=%d\n", high_8, low_7, bit_7);

相對于上一個程式而言多了一個子程序的狀态區分,把狀态拆分成三塊,exit,sig和core。

參考資料:

老師群裡上傳的代碼、課本《深入了解計算機系統》、上網查資料以及闫佳歆同學的部落格。

實驗體會:

這章的代碼不是很了解,在上星期的基礎上又看了一遍課本,一些不懂的上網查了一下,同學的部落格也借鑒了一些。