遨遊Unix–APUE課程筆記【1】

jasperyang發表於2019-05-12

寫在最前面:其實這是一個上課作業,我覺得我不能就這麼簡單的實現了而不給後人留下點什麼糟粕。所以下面有興趣的同學就跟著我誤入歧途吧。我沒想按著APUE這本書一章一章來,我認為既然是我自己讀完了這本書並要實現東西,就需要有我自己的節奏,這種節奏不僅僅讓我自己,也要讓各位看客感到輕鬆,並偶有所獲~我就十分開心了。

Preface

這學期報了一門課叫《Unix環境高階程式設計》,本來打算水水過去的,沒想到老師需要我們每個人完成一份大作業,作業內容就是艱深複雜的各種呼叫底層API實現的shell。

怎麼說呢?從嚴格意義上,作業系統可以定義為一種軟體,它控制計算機硬體資源,提供程式執行環境,我們將這種軟體成為核心(也就是kernel),核心的介面被稱為系統呼叫,公用函式庫構建在系統呼叫介面之上,應用程式既可以使用公用函式庫,也可以使用系統呼叫。shell是一個特殊的應用程式,為執行其他程式提供了一個介面。

我們要實現的shell就是這麼一個東西。

這麼大段的定義還不如說【oh-my-zsh ,zsh ,bash】 來的實在,以上三種就是我們常見的shell,我現在最喜歡的就是 oh-my-zsh 了,其優點太多了,tabtab可以自動提示引數,配色好看幾百倍等等等等。

廢話不多說,要開車了哦。

準備工作

首先

  1. 一臺Linux系統的計算機(比較方便,在windows下需要配置很多的環境,因為windows沒有Unix的很多庫函式,我使用的是 Ubuntu 16.04)

  2. 下載apue原始碼 傳送門

  3. 解壓原始碼檔案 tar -zxvf *.tar.gz

  4. cd apue.3e/ & make
    在這個過程中,你會看到最後由於can,t find-lbsd而不能make成功,解決辦法是新增libbsd.a的靜態連結庫
    sudo apt-get install libbsd-dev

5. 重新 make 然後再

     sudocp  ./include/apue.h   /usr/include/
     sudocp  ./lib/libapue.a   /usr/local/lib/
     

有時候以上步驟完成後就可以隨便找書上的例子開始裝逼了,但是我的電腦不行,因為裡面有很多err_sys之類的報錯函式未定義,那麼還需要再執行一步。

複製下面的程式碼,並儲存成 /usr/include/myerr.h
以後你寫的例子裡需要用到err_sys之類的函式,你需要 #include “myerr.h”

#include "apue.h"
#include <errno.h> /* for definition of errno */
#include <stdarg.h> /* ISO C variable aruments */
static void err_doit(int, int, const char *, va_list);
/*
* Nonfatal error related to a system call.
* Print a message and return.
*/
void
err_ret(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
}
/*
* Fatal error related to a system call.
* Print a message and terminate.
*/
void
err_sys(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    exit(1);
}
/*
* Fatal error unrelated to a system call.
* Error code passed as explict parameter.
* Print a message and terminate.
*/
void
err_exit(int error, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    err_doit(1, error, fmt, ap);
    va_end(ap);
    exit(1);
}
/*
* Fatal error related to a system call.
* Print a message, dump core, and terminate.
*/
void
err_dump(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    abort(); /* dump core and terminate */
    exit(1); /* shouldn`t get here */
}
/*
* Nonfatal error unrelated to a system call.
* Print a message and return.
*/
void
err_msg(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    err_doit(0, 0, fmt, ap);
    va_end(ap);
}
/*
* Fatal error unrelated to a system call.
* Print a message and terminate.
*/
void
err_quit(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    err_doit(0, 0, fmt, ap);
    va_end(ap);
    exit(1);
}
/*
* Print a message and return to caller.
* Caller specifies "errnoflag".
*/
static void
err_doit(int errnoflag, int error, const char *fmt, va_list ap)
{
    char buf[MAXLINE];
   vsnprintf(buf, MAXLINE, fmt, ap);
   if (errnoflag)
       snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s",
         strerror(error));
   strcat(buf, " ");
   fflush(stdout); /* in case stdout and stderr are the same */
   fputs(buf, stderr);
   fflush(NULL); /* flushes all stdio output streams */
}

尾聲

既然是第一章,當然我們輕鬆點,那麼就來一個最最開始的1-7程式吧,這個程式搭建了最基本的功能,也就是輸入,連命令也不是去解析調API而是直接用原始bash的命令~

//
// Created by jasperyang on 17-6-6.
//
#include "apue.h"
#include <sys/wait.h>
#include "myerr.h"

int main(void) {
    char buf[MAXLINE];  /* from apue.h */
    pid_t pid;
    int status;

    printf("%% ");  /* print prompt (printf requires %% to print %) */
    while(fgets(buf,MAXLINE,stdin) != NULL) {
        if(buf[strlen(buf) -1] == `
`){
            buf[strlen(buf)-1]=0;   /* replace newline with null */
        }
        if((pid = fork()) < 0) {
            err_sys("fork error");
        } else if (pid == 0){   /* child */
            execlp(buf,buf,(char*)0);
            err_ret("couldn`t execute: %s",buf);
            exit(127);
        }

        /* parent */
        if((pid = waitpid(pid,&status,0)) < 0)
            err_sys("waitpid error");
        printf("%% ");
    }
    exit(0);
}

簡單易懂老少皆宜,這段程式輸入命令,並fork一個child去執行命令,執行命令用的是execlp這個函式,執行失敗與否子程式都exit(127),127倒沒什麼特殊的含義。

相關文章