4.1 NFS安裝與測試
安裝NFS網絡文件系統的時候,需要用到portmap,portmap將遠程調用(RPC)的程序號轉化為Internet端口號,NFS我們認為它是一個RPC服務,在啟動RPC服務之前要做好端口的對應工作,自然portmap就需要安裝。

接下來安裝nfs,在服務器端:

安裝成功的標志:

服務器端配置:

在末尾添加:/tftpboot 192.168.0.*(rw,sync,no_root_squash),其中*表示“所有”,如果,在末尾添加的是:/tftpboot *( rw,sync,no_root_squash),表示所有網段都可以用,可以增加匹配的成功率。我用的是后一句。

重啟portmap,

重啟成功的標志:

服務器端重啟nfs:

重啟成功的標志:

在客戶端(同一個terminal下),下載nfs-common

測試nfs。我們將虛擬機自身tftpboot目錄下的文件掛載(mount)到mnt目錄下。首先我們得知道虛擬機自身的IP地址,用命令Ifconfig,找到inet addr,對應的就是IP地址。如下圖,

接下來用命令:sudo mount 192.168.230.128:/tftpboot /mnt,意思是:將IP地址為192.168.230.128的主機根目錄下有一個文件夾叫tftpboot里的文件掛載到自己的/mnt目錄下。

然后我們轉到/mnt目錄下用ls -l命令可以看到多出來一些文件,而這些文件正好是/tftpboot下的文件,說明我們的nfs可以用了。

當然在linux下測試可以用了,在uClinux下呢?接下來需要做第一節課第二節課做的事情,首先,需要對內核和用戶設置,同樣是在/work/uClinux-dist目錄下,執行sudo make xconfig,調出Target Platform Selection。選擇下圖紅框里的兩項為“Yes”,

接下來File system->Network File System->NFS file system support和Provide NFSv3 client support。如下圖。

點擊OK,並且保存退出以后,就會進入application configuration如下圖,選擇Network Applications->portmap。如下圖,

再選擇BusyBox->mount:support NFS mount->save and exit。如下圖,

到/work/uClinux-dist路徑下執行sudo make dep

執行完成以后,執行sudo make

Make完成以后的標志:

接下來,將他下載到開發板,第二節課的內容,就不累述了,參看下圖。

掉電重啟,cd命令轉到mnt目錄下,可以看到此時的目錄下是空的,然后使用mount命令(mount 192.168.0.222:/tftpboot /mnt),然后再到mnt目錄下,此時多了幾個文件,這幾個文件正好是/tftpboot目錄下的文件,說明掛載成功。如下圖,

4.2 自訂開機啟動程序
開發板如果上電的時候要它自動運行某些程序,我們可以腳本文件里添加某些命令,具體的路徑以及命令如下:
路徑:/work/uClinux-dist/vendor/Marvell/Firefox,
命令:sudo gedit rc
在文件的最后一行添加“/bin/hello”,表示在開機以后,系統會先運行bin目錄下的hello文件,從而在重啟開發板時打印出“Hello,uClinux!”(第二節課的程序,也可以是其他程序),如下圖:

然后下載到開發板試一下,在燒錄之前要到/work/uClinux-dist目錄下執行一下語句:
Sudo make
燒錄的命令如下:(具體步驟第2課的2.3小節)
1) tftp 20000 zRomfs
2)fburn 20000 fff70000 length(in hex)
3) tftp 20000 zImage
4)fburn 20000 fff00000 lrngth(in hex)
5)掉電重啟
重啟以后截圖如下:

說明,在開機的時候,系統運行了etc/rc腳本里面的內容。
4.3 登錄程序
在開發板上模擬linux的登錄:用戶輸入正確的用戶名和密碼以后,才能進入shell,如果輸錯,就會提醒用戶再次輸入,直到輸入正確為止。首先,該程序應該寫在哪里面?答案是在/work/uClinux-dist/user/sash的sash.c文件里,打開該文件,有許多的代碼,但是,main()函數還是比較好找的,肯定是在mian()函數里加入一個循環,用於登錄程序,回憶一下之前每次在下載程序到板子里的時候,重啟,最后一句是:“Sash command shell(version 1.1.1)”,然后,我們才進行操作,所以登錄程序應該加在用printf()函數打印出這段話的前面,果不其然,在第二個if的else語句里面我們找到這條語句,如下:
else
printf("Sash command shell (version %s)\n", version);
所以,我們的登錄程序加在else語句里面,
既然是登錄程序,肯定要有真實的用戶名(user)和密碼(passwd),用輸入的用戶名和密碼與其進行對比,如果一樣,就表示登錄成功,不一樣,肯定登錄失敗。所以真實的用戶名(user)和密碼(passwd)保存在哪里?答案是可以自己隨便在/work/uClinux-dist/romfs下定義,一般在romfs/etc目錄下,所以/work/uClinux-dist/romfs/etc下新建一個文件,
命令:sudo gedit PsWd
設置的用戶名為:LiuFarrell
密碼:12345678
內容如下:

上圖和想設置的數據不一樣,這么回事?其實是為了保護數據的安全性加密了的。加密函數crypt();在linux中簡單的寫一個加密以后的數據測試,如下:

上圖中,cry(infor,key)應該改為crypt(infor,key)..................................寫錯了的。
其中infor變量第一次用“LiuFarrell”,第二次改為“12345678”,就可以分別的到“LiuFarrell”和“12345678”加密以后的數據,如下:

將紅框里面的內容分別對應寫進PsWd里面就得到了我們想要的數據。
真實的用戶名和密碼數據已經准備好了,自然就該進入sash.c里面編寫代碼了。
進入/work/uClinux-dist/user/sash下,打開 sash.c程序,命令:sudo gedit sash.c,在main()函數之前添加如下代碼:
#define PATHFILE "passwd"
#if defined(CONFIG_USER_FLATFSD_FLATFSD)
#define PATH_PASSWD "/etc/config/config"
#else
#define PATH_PASSWD "/etc/PsWd" //定義存放真實用戶名和密碼的路徑
#endif
char usernamebuf[128]; //緩沖區
//獲取登錄user的字符串函數
char *getrealuser(char *pfile)
{
static char tmpline[128];
FILE *fp;
char *sUser;
int len;
if ((fp = fopen(pfile, "r")) == NULL)
{
fprintf(stderr, "ERROR: failed to open(%s), errno=%d \n",
pfile, errno);
return((char *) NULL);
}
while (fgets(tmpline, sizeof(tmpline), fp))
{
sUser = strchr(tmpline, '=');
if (sUser)
{
*sUser++ = 0;
if (strcmp(tmpline, "user") == 0)
{
len = strlen(sUser);
if (sUser[len-1] == '\n')
sUser[len-1] = 0;
return(sUser);
}
}
}
fclose(fp);
return((char *) NULL);
}
獲取登錄user的密碼函數
char *getrealpass(char *pfile)
{
static char tmpline[128];
FILE *fp;
char *spass;
int len;
if ((fp = fopen(pfile, "r")) == NULL)
{
fprintf(stderr, "ERROR: failed to open(%s), errno=%d \n",
pfile, errno);
return((char *) NULL);
}
while (fgets(tmpline, sizeof(tmpline), fp))
{
spass = strchr(tmpline, '=');
if (spass)
{
*spass++ = 0;
if (strcmp(tmpline, "passwd") == 0)
{
len = strlen(spass);
if (spass[len-1] == '\n')
spass[len-1] = 0;
return(spass);
}
}
}
fclose(fp);
return((char *) NULL);
}
在main()函數的第二個if條件語句的else里添加加粗部分的代碼,也就是說在登錄進入shell以前,要先進行用戶名和密碼的判定。
else
{
printf("###############-Please Login!-###################\n");
for(;;)
{
char *cryptmode;
char *realuser,*inputuser;
char *realpasswd,*inputpasswd;
char *p;
cryptmode = "ab";
printf("User: ");
fflush(stdout);
fgets(usernamebuf, sizeof(usernamebuf), stdin);
p = strchr(usernamebuf, '\n');
if( p != 0 )
*p=0;
realuser = getrealuser(PATH_PASSWD);
if(usernamebuf)
{
if(strcmp(crypt(usernamebuf,cryptmode),realuser) == 0)
{
inputpasswd = getpass("Passwd: ");
realpasswd = getrealpass(PATH_PASSWD);
if(strcmp(crypt(inputpasswd,cryptmode),realpasswd) == 0)
{
printf("Login successfully!\n");
break;
}
}
else printf("The user name is invaild!\n");
}
else printf("Wrong input!\n");
}
printf("Sash command shell (version %s)\n", version);
}
下載到開發板運行如下,

只有在正確輸入用戶名和密碼以后才能進入shell,說明實驗成功。
4.4 總結
本次課對我來說是有一定難度的,主要難在不知道程序或者命令應該寫在哪里,網上也有許多教程,但都不是關於uClinux的,所以就不想看,通過和同學交流,才慢慢的完成了本次的練習,受益匪淺。
