Chinaunix首页 | 论坛 | 博客
  • 博客访问: 137394
  • 博文数量: 24
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 590
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-18 08:29
文章分类

全部博文(24)

文章存档

2011年(1)

2009年(5)

2008年(18)

我的朋友

分类: LINUX

2009-03-04 19:11:22

[gaowei@localhost ~]$ sh -e
sh-3.2$ exit
exit
[gaowei@localhost ~]$ man sh
-e参数指定“\"不用做转义字符。
当shell启动时,会读取默认的配置文件/profile。
[gaowei@localhost ~]$ \ls这样可以但是[gaowei@localhost ~]$ ls\ls 就bash: lsls: command not found
[gaowei@localhost ~]$ sh \ ls
sh: ls: 没有那个文件或目录
[gaowei@localhost ~]$ sh \
>
[gaowei@localhost ~]$ sh
sh-3.2$ \
>
[gaowei@localhost ~]$ "ls" kernel/
book C kang kernel linux-0.11 man-pages-3.10
当执行shell时,用户键入一个命令,shell首先除去所有的"\"字符之前的字符(如果没有使用-e参数)和所有的引号中的字符。然后,shell按照如下的规则处理"!"引起的shell命令历史代替:
!! 代表前一个执行的命令
! 代表前个执行的命令
! 代表字符串开始的命令
然后,shell会将输入的命令字符串切换成为令牌(token)字符串。在引导中的所有字符串成为一个令牌。空格是隔开各个令牌的分割符。
然后,shell使用如下的规则处理命令行的通配符:
包含通配符(当前设定为*)的令牌被假定成文件名,通配符被扩展成为匹配的文件名(*匹配任何字符)。
shell执行I/O重定向(I/O readirections):
'> word' 重定向标准输出(redirect stdout)
'>> word' 重定向标准输出,添加在指定的文件后
'>& amp;word' 重定向标准输出和标准错误输出(redirects stdout and stderr)
'< word' 重定向标准输入(redirects stdin)

shell处理的文件描述符一般有三个:文件句柄0(stdin,标准输入),文件句柄1(stdout,标准输出),文件句柄2(stderr,标准错误输出)。

dup ()系统调用的功能是返回一个新的文件描述符,它指向传入参数文件描述符指向的文件流。dup()使用进程文件分配表中的第一个没有使用的文件句柄复制为 新的文件句柄。dup()经常使用的一个功能就是完成标准I/O的重定向。使用dup()进行I/O重定向的代码片段如下:
int fd,pid;
fd = open(path,mode);
if((pid=fork())==0) {
close(0);/*Close stdin.*/
/* Make stdin come from fd.Dup() will reuse the lowest.
*number unused file descriptor,0 in this case.*/

dup(fd);
close(fd); /*No longer needed.*/
execve(...); /*Run command,with input from fd..*/
} else {
/*Parent.Wait for child processes to exit.*/
while(wait(NULL)>0);
}
pipe ()函数可以创建一个FIFO流(First In First Out stream,先进先出流)来完成进程间的通信。pipe()系统调用生成俩个文件句柄,一个可以向FIFO流中写入,一个可以从FIFO流中读取。可以 通过在父进程中使用pipe()函数来创建管道,然后再生成fork()子进程,每一个生成的子进程中都有父进程调用pipe()函数生成的文件句柄的复 制。在子进程中,>可以把父进程中通过pipe()生成的句柄使用dup()函数来重定向子进程的标准输入(stdin),标准输出 (stdout)和标准错误输出,这样父进程就可以控制子进程的标准I/O了。
int i,pid,mypipe[2];/*Two fds,for pipe ends.*/
pipe(mypipe); /*Create pipe.*/
/*Create reader.*/
if((pid=fork())==0) {
close(0); /*Close stdin.*/
dup(pipe[0]); /*Stdin comes from pipe.*/
close(pipe[0]); /*No longer needed.*/
close(pipe[1]); /*Not needed.*/
execve(...); /*Run command,with input from pipe.*/
}
/*Create write.*/
if((pid=fork())==0) {
close(1); /*Close stout.*/
dup(pipe[1]); /*stdout goes to pipe.*/
close(pipe[1]); /*No longer needed.*/
close(pipe[0]); /*Not needed.*/
execve(...); /*Run command,with output to pipe.*/
}
/*Parent.*/
close(pipe[0]);
close(pipe[1]);
while(wait(NULL)>0); /*Wait for child processes to exit.*/
一个例子:
[gaowei@localhost 10SHELL编程技术和实例]$ gcc -o dup dup.c
[gaowei@localhost 10SHELL编程技术和实例]$ ls
10 a.out dup dup.c sh1.c sh2 sh2.c
[gaowei@localhost 10SHELL编程技术和实例]$ ./dup
This is to stdout
This is to stderr
[gaowei@localhost 10SHELL编程技术和实例]$ ls
10 a.out dup dup.c err out sh1.c sh2 sh2.c
[gaowei@localhost 10SHELL编程技术和实例]$ cat ./out
This is to stdout
[gaowei@localhost 10SHELL编程技术和实例]$ cat ./err
This is to stderr
[gaowei@localhost 10SHELL编程技术和实例]$ ls -a
. .. 10 .10.swp a.out dup dup.c err out sh1.c sh2 sh2.c
[gaowei@localhost 10SHELL编程技术和实例]$ ls
10 a.out dup dup.c err out sh1.c sh2 sh2.c
[gaowei@localhost 10SHELL编程技术和实例]$
一个成熟的shell应该支持管道操作总体结构如下:
(cmd1 | cmd2) /* cmd1的标准输出为cmd2的标准输入 */
pipe[fdarr]; /*定义管道 */
if((pid1 = fork()) == 0) {
close(1); /*关闭cmd1的stdout */
dup(fdarr[1]); /* 设置fdarr[1]为cmd1的stdout */
close(fdarr[0]);

aptr[0]="cmd1"; aptr[1]=NULL;
execve("cmd1",aptr,eptr);
}
if((pid2=fork()) ==0) {
close(0); /*关闭cmd2的stdin */
dup(fdarr[0]); /*设置fdarr[0]为cmd2的stdin */
close(fdarr[0]);
close(fdarr[1]);

aptr[0]="cmd2";aptr[1]=NULL;
execve("cmd2",aptr,eptr);
}
close(fdarr[0]);
close(fdarr[1]);
wait() for both pid1 and pid2;
shell程序的主程序组成如下:
#include "def.h"
main(void)
{
int i;
initcold();
for(;;) {
initwarm();
if(getline())
if(i=parse())
execute(i);
}
}

第十一章
分析Linux0.01中实现系统调用的俩个文件system_call.s和sys.c来展示Linux0.01的系统调用的实现方式。标准的C语言库函数,在不同的操作系统上有不同的内部实现。
应用程序可以通过一个固定的过程,从而调用内核提供的功能,在Intel体系结构的计算机中,这是通过执行中断0x80h实现的。
应 用程序通常是一个进程,进程在调用内核时,跳转到内核代码中的位置一般标记为system_call(在Linux0.01中,system_call是 汇编程序system_call.s中的一段代码的入口点的标记)。在system_call位置的代码将检查系统调用号,依据系统调用号告诉系统内核进 程请求的系统服务是什么。然后,它再查找系统调用表sys_call_table[],找到希望调用的内核函数的地址,并调用此函数,最后将控制权返回应 用程序。编写一个自己的函数,然后改变sys_call_table[]中的指针并指向该函数。
Linux用于实现系统调用异常的实际指令是:int $0x80
定义系统调用的预定义宏为: _syscallN(parameters)
在include/unistd.h中可以找到_syscallN(parameters)还有__NR_name的形式定义了66个常数,这些常数就是系统调用函数name的函数指针在系统的调用表中的偏移量。
系统调用表是一张表格,按照顺序定义了系统中所有的系统调用的入口函数地址。在Linux0.01中,系统调用表定义在include/linux/sys.h中,如下所示:
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp,sys_setsid};
在 数组sys_call_table[]中的每一个元素都是一个函数指针(在C语言中,函数名代表指向函数入口的指针),按系统调用号(即前面提到的 _NR_name)排列了所有系统调用函数的指针,以供系统调用入口函数查找。从这张表可以看出,Linux给它所支持的系统调用函数取名叫 sys_name。
系统调用入口函数定义在/linux/kernel/system_call.s文件中。是使用汇编语言书写的,包含了系统调用的主要处理程序,同时也包含了时钟中断处理程序,硬盘中断处理程序也包含在本文件中。
从system_call入口的汇编程序的主要功能是:
检查是否为合法的系统调用。
保存寄存器的当前值。
根 据系统调用表_sys_call_table和EAX寄存器持有的系统调用号找出并转入系统调用响应函数。从该响应函数返回后,让EAX寄存器保存函数返 回值,跳转至ret_from_sys_call,>当ret_from_sys_call结束后,将执行进程调度。
在执行位于用户程序中系统调用命令后面余下的指令之前,若INT 0x80h的返回值非负,则直接按类型type返回;否则,将INT 0x80h的返回值取绝对值,保留在errno变量中,返回-

第十二章
关于这一章我记录的比较少
尽管在Linux0.01中没有写网络的部分,但是现在是个网络的时代,这本书中也讲了关于网络的部分,而且我又是学习网络的,所以就在写一写了。
Linux是一个网络操作系统。
TCP/IP协议是一套数据通信协议,其名字是由这些协议中的俩个主要的协议组成的,即传输控制协议(Transmission Control Protocol,TCP)和网间协议(Internet Protocol,IP)。
阅读(2195) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~