去。这个时候,原来shell的进程就是getenv进程的父进程。envp的参数是从父进程中取得的。现在你知道上一节中为什么有那两个带p的函数了?
上一回做的ssh这个外壳的命令是带不了参数的。因为咱们的程序不知道要去读参数。这回不妨做一个能读参数的试试
#include #define SP 0 #define NOSP 1
void getarg( char *argv[] , char *p ); //取得各个参数 int main() {
static char prompt[64]=> ;
char command[256], *argv[256], *p; int st;
fprintf( stderr , %s , prompt );
while( (p=gets(command))!=NULL ) {
getarg( argv , p ); if( fork()==0 ) {
if( execv(argv[0],argv)==(-1) ) exit(1); } else {
wait( &st );
fprintf( stderr , %s , prompt); } }
return 0; }
void getarg( char *argv[] , char *p ) {
int i , sp_flag ;
sp_flag=SP; //SP代表空格,NOSP代表非空格的意思 for( i=0 ; *p!='\\0' ; p++ ) {
if( sp_flag==SP && *p!=' ' )
//如果现在状态是读过空格,但现在这个字母是非空格 //那很显然,读到一个新的参数 {
argv[i]=p; i++;
sp_flag=NOSP; }
if( *p==' ' ) {
*p='\\0'; sp_flag=SP; } }
argv[i]=(char *)0; }
这篇文章东西说得比较少。给大家出个问题吧:
看到了吧。C能做的事情很多。谁说C不支持多进程?那是因为DOS。呵呵
上回做的ssh,必须输入绝对路径才能执行。现在要求,咱们做一个只输入命令以及参数,程序自动在$PATH里定义的各路径查找这个命令。找到就执行,找不到就报错的外壳出来试试?有做出来的,请贴程序。
2003-7-27 关于进程状态的一些补足:
众所周知,UNIX是一个多用户多任务的操作系统。所谓多任务,就是指在同一个时间内,看上去有许多任务在同时执行。这一点是与DOS不同的。所以Turbo C下找不到fork()函数。当然。大家知道,实际上CPU同一个时间只能处理一件事。它是在轮流执行这些进程,由于速度很快。所以看起来像是所有进程在一起跑。同样,一个进程,它有使用CPU的时候,也有等待使用CPU的时候。这就决定了进程的几种状态。 进程大致可以分为“执行中”,“准备执行”,“睡眠中”三种状态。 执行中:进程在占用CPU。
准备执行:想要使用CPU,但是CPU被别的进程占用中,所以等待CPU空闲。 睡眠中:等待事件发生的进程。比方说,等待输入输出结束的进程。
我们用fork()生成一个新的进程,或者用exec函数组覆盖当前进程后。当这个子进程结束的时候要给父进程送去一个信号(signal,后述),然后转为zombie状态。zombie状态是指一个进程已经结束,所占内存空间等等已经返还给系统,但是在系统的进程列表中仍然存在的这么一个状态。当父进程执行wait()后,子进程才真正完全结束。如果父进程先一步结束了,那么由init代替父进程。所以,wait()不只是等待子进程结束。它还有上面所说的这个任务。 我们写个程序来看一下:
/* zombie */ #include int main() { int st;
if( fork()==0 ) {
exit(1); //子进程生成后直接结束 }
else {
sleep( 300 ); //休眠300秒 wait( &st );
printf(Return code=%d\\n,i); }
return 0; }
编译后执行 %./zombie &
这个时候,程序在后台运行 %ps -ef | grep zombie
看一下,是不是有一个进程处在zombie状态?
第四章:文件系统
UNIX所管理的机器一般是大型机而不是PC。所管理的硬盘一般也非常大。所以一般分成几个区,每个区都有其单独的文件系统。比方说你能大概能找到这样的一些文件 /dev/sd/c0t0d0s0 /dev/sd/c0t0d0s1 ... ...
当UNIX启动的时候,分区被挂装(mount)并统一成一个树状的文件系统 分区的物理构造咱们暂且放在一边,先写个程序,读一下分区信息试试。
/* ndf.c 计算参数所指定的分区的剩余空间比率 */ #include #include #include
int main(int argc , char *argv[]) {
struct statvfs buf[1]; sync();
if( statvfs(argv[1],buf)!=0 ) {
fprintf(stderr , Cannot read super block !\\n); exit(1); }
fprintf(stderr , %4.1f %% free\\n,
(float)buf[0].f_bfree / buf[0].f_blocks*100 ); return 0; }
编译执行: %./ndf / 49.8 % free
这里用了一个statvfs函数。其具体如下: #include #include
int statvfs( char *path , struct statvfs *buf ); 返回值: 成功时: 0 失败时: -1
还有一个sync()函数。用来更新分区的super block; void sync();
UNIX系统为了加快处理速度,将分区的super block信息读到内存中保存。sync()函数就是把在内存中保存的super block信息再写回到硬盘上去。
UNIX系统使用好几种文件系统。有S5,ufs,VxFS等等。虽然这些文件系统的构造非常不同,但一通百通,咱们在这几篇贴子里只讨论一下比较容易理解,而且“经典的”S5文件系统。(别的我也不会。呵呵) S5: 文件名最长14字节,构造简单
ufs: 文件名最长255字节,BSD所用的文件系统。
VxFS: Veritas Softwave公司开发的文件系统。出现错误时可以快速恢复。由于这种文件系统保证文件在硬盘上连续存放,所以处理速度很快。
现在说一下S5分区的构造
一个分区包含如下四部分(按顺序): [ boot block ] [ super block ] [ i node block ] [ data block ]
boot block :
这个部分在分区的最开始处,用来存放引导程序。就算是不能引导的分区一样有boot block,这个时候这部分就没有用了。不过一般这部分也不大。大多数只有512或者1024字节。
super block :
super block在boot block之后,用来存放这个分区全体的管理信息。上面那个ndf.c就是读的这部分所存储的信息。里边存放了i node block的大小,free block数组等等。根据这些信息可以得知data block的开始位置。 i node block :
i node是index node的缩写。i node block就是存放i node的部分 UNIX把一切都看成是个文件。包括目录以及设备等等的所有的文件都有一个i node号,作为这个文件的管理信息。文件本身存在于数据区,但是i node号存在i node block里。主要包含文件的模式,链接数,文件所有者,文件大小,在硬盘上的位置,最后读写时
间,最后更新时间等信息。
为了加快存储速度,系统会把一定数量的i node存至内存。UNIX系统不一样,存多少也就不一样。 data block :
这部分就是存放数据本身的了。这部分被分成一定大小的块,如同DOS的扇区一样。一般大小是1024字节,分到4096的也有。
解说到这里,我们再来写个程序。打开一个目录,然后把这个目录下所有的文件的i node号及文件名输出来。
/* nls.c */ #include
#define DIRSIZ 14
int main( int argc , char *argv[] ) {
struct dir {
int i_no;
char f_name; };
struct dir dir_data[1]; FILE *fp;
fp=fopen(argv[1],r);
while( fscanf(fp,%i%s,&(dir_data[0].i_no),dir_data[0].f_name)!=EOF ) {
printf(%i %s\\n , dir_data[0].i_no , dir_data[0].f_name ); }
fclose(fp); return 0; }
%./nls / ... ... 2048 usr 2049 home ... ...
别忘了,在UNIX下,目录也当成文件。 最近,为了使目录的格式变得通用而不再依赖于操作系统,程序中大多使用统一的格式。这种情况下,我们最好就不直接用fopen()打开目录,而使用opendir(),readdir()等函数比较好。重写一下上面的程序。
/* nls2.c */ #include
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库UNIX系统程序设计教程(2)在线全文阅读。
相关推荐: