当命令行参数的个数不为1时,程序使用fork系统调用产生一个子进程。子进程通过系统调用getpid获得自己的进程标识符,然后调用exec执行命令行中用户提交的命令,如果exec执行失败,则子进程调用exit(5)终止。父进程使用wait系统调用等待子进程暂停或终止,然后输出从wait中返回的信息。下面以三种方式执行该程序: 1〕 不带命令行参数 % ./feew pid=-1, H_stat=0, L_stat=0 % 不产生子进程,从运行结果来看,当无子进程时,wait的返回值为-1。 2〕 带命令行参数,参数为合法的可执行命令 % ./feew /bin/date Child pid = 1725 1998年 2月16日(星期一) 15时59分14秒 CST pid=1725, H_stat=0, L_stat=0 % 产生子进程。子进程输出其进程标识符后,再调用exec执行从命令行中提交的命令(/bin/date),同时父进程等待子进程暂停或终止,然后输出从wait中得到的信息:子进程标识符或状态参数stat的高八位、低八位的内容。从中可以看到:子进程因调用一个隐含的exit(0)而终止,终止时传给父进程的值为0。 3〕 带命令行参数,但参数不合法 %./feew /etc/shudown Child pid = 1760 /etc/shutdown: 只有超级用户(root)能运行 /etc/shutdown。 pid=1760, H_stat=2, L_stat=0 % 子进程创建成功。但由于以普通用户的身份执行/etc/shutdown,因此exec失败,尔后调用exit(5)而终止;父进程调用wait得到返回值:子进程号和状态参数stat的高八位、低八位的内容。从执行结果可以看出:子进程因调用exit(5)而终止,终止时传给父进程的值为5。 5.3 进程管理 进程管理包括的面很广,诸如进程的用户标识符管理、进程标识符管理等。进程的用户标识符有两个:实际用户标识符(real user id)和有效用户标识符(effective user id),其对应的组标识符分别称为实际组标识符(real group id)和有效组标识符(effective groud id)。一般而言,进程的实际用户标识符为运行该进程的用户标识符,通常只用于系统记帐,其他功能由有效用户标识符来完成,如用有效用户标识符来完成对新创建文件赋予属性关系、检查文件的存取权限和利用kill系统调用向进程发送信号的权限。一般情况下,一进程的有效用户标识符和实际用户标识符是相等的,但系统允许改变进程的有效用户标识符。 1. 进程的用户标识符管理 UNIX系统提供了一组系统调用来管理进程的用户标识符,它们的使用形式是: #include <sys/types.h> #include <unistd.h> uid_t getuid (void); uid_t geteuid (void); gid_t getgid (void); gid_t getegid (void); int setuid(uid_t uid); int setgid(gid_t gid); 说明:前四个系统调用没有参数,分别返回调用进程的实际用户标识符、有效用户标识符、 实际用户组标识符和有效组标识符。这些系统调用的执行总能获得成功,不会发生任何错误。系统调用setuid和setgid用于设置进程的实际用户(组)标识符和有效用户(组)标识符,如调用进程的有效用户标识符是超级用户标识符,则将调用的进程实际用户(组)标识符和有效用户(组)标识符设置为uid或gid;如调用进程的有效用户标识符不是超级用户标识符,但其实际用户(组)标识符等于uid或gid时,则其有效用户(组)标识符被设置为uid或gid;否则setuid或setgid调用失败。系统调用setuid或setgid调用成功时返回0,失败时返回-1。 2. 进程标识符管理 UNIX系统使用进程标识符来管理当前系统中的进程。为对具有某类似特性的进程统一管理,系统又引入了进程组的概念,以组标识符来区别进程是否同组。进程的组标识符是从父进程继承下来的,所以,通常进程的组标识符就是和它相关联的注册进程的标识符。进程的标识符是由系统为之分配的,不能被修改;组标识符可通过setpgrp系统调用修改。 相关系统调用的格式如下: #include <sys/types.h> #include <unistd.h> pid_t getpid(void); pid_t getpgrp(void); pid_t getppid(void); pid_t getpgid(pid_t pid); 说明:前三个系统调用分别返回调用进程的进程标识符、进程组标识符和其父进程标识符。它们总能成功地返回。第四个调用置进程组标识符,它将调用进程的进程组标识符改为调用进程的进程标识符,使其成为进程组首进程,并返回这一新的进程组标识符。 下面我们来看一个实例: /* setuid.c */ main(argc, argv) int argc; char *argv[]; { int ret, uid; uid = atoi(argv[1]); printf("Before uid=%d, euid=%d\n", getuid(), geteuid()); ret = setuid(uid); printf("After uid=%d, euid=%d\n", getuid(), geteuid()); printf("ret = %d\n", ret); } 下面分三种情况讨论该程序的执行: 1、 如果执行该程序的用户为超级用户,则只要命令行所给的用户标识符大于0,无论所给的用户标识符是否存在,执行总能成功。 #./setuid 3434 Before uid=0, euid=0 After uid=3434, euid=3434 ret = 0 # 结果分析:将进程的实际和有效用户标识符均改为3434。 2、 如果执行该程序的用户为一般用户,用id命令得到用户uid和gid后,再调用该程序,过程如下: %id uid=1111(yds) gid=20(user) %./setuid 3434 Before uid=1111, euid=1111 After uid=1111, euid=1111 ret = -1 %./setuid 1111 Before uid=1111, euid=1111 After uid=1111, euid=1111 ret = 0 % 结果分析:当命令行参数为1111时,setuid执行成功,因为用户的uid就是1111。 值得注意的是:注册程序login 是个典型的setuid系统调用程序,login进程的有效用户是超级用户,该进程在建立用户的Shell进程前,调用setuid将实际和有效用户标识符调整为注册用户的用户实际和有效标识符。
第六章 设备输入/输出控制 6.1 概述 UNIX将设备看成文件,这是UNIX的一大特色。这里需要介绍一个设备号的概念。设备特别文件与两个设备号有关-主设备号和次设备号。主设备号告诉操作系统,当涉及文件名时,将使用哪种设备类型。对于每一种类型的设备都有一段驻留在操作系统中的程序代码,以控制相应类型的设备,这段代码被称为"设备驱动程序"。次设备号被传递给设备驱动程序,这个号码用来决定使用哪种物理设备。例如,决定在一块多重驱动控制卡上,哪个磁盘驱动器将被访问,以及该磁盘驱动器中哪一部分将被使用;或者,当一个磁盘驱动器所请求的操作已经完成后,应该被恢复原状。几个设备(如同类型的磁盘驱动器)可以用同一个主设备号,但它们将有不同的次设备号。看下面的例子: %ls -l /dev/ttyq* crw--w---- 2 yds user 15, 1 2月 17日 09时03分 ttyq1 crw--w---- 2 yds user 15, 14 2月 16日 17时00分 ttyq14 % 上例中15是主设备号,1和14是次设备号。 用户可以使用系统提供的统一而且独立于设备的界面-对文件进行操作的系统调用来操作设备,而没有必要涉及设备的具体细节。大部分对文件进行操作的系统调用对它们仍起作用,例如,用open打开设备,用read/write对设备进行读/写,设备操作完成后,用close关闭设备。但有的系统调用在对设备文件进行操作时,其功效有所不同。如create及open的创建方式都不能创建设备文件。 6.2 设备输入/输出控制-ioctl系统调用 ioctl是UNIX系统专门提供的用于设备控制的系统调用。该系统调用与设备类型(即主设备号)相关。不同的设备,系统提供了不同的控制命令。 ioctl的调用格式是: ioctl(int fd, int cmd,arg…) 说明:参数fd是一设备文件的文件描述字,cmd是控制命令,它与设备相关,不同类型的设备有不同的控制命令。参数arg没有固定的数据结构,它随cmd的不同而不同。
第七章 高级编程 7.1 处理信号 信号是UNIX进程间最基本的通讯手段,主要作用是实现进程间异步事件的通讯。信号是传送到进程的"软中断",它通知进程在它们的环境中出现了非正常事件。进程接收到信号后要进行处理,处理方式为以下四种之一: (1)缺省方式(SIG_DFL):这是进程对信号的一般处理方式,在无特殊情况下,进程在接收到信号后将终止执行。有一些信号,在终止进程运行前需将终止进程的正文段、数据段、user结构和栈段内容写到当前目录的core文件中,以备调试工具分析与使用。 (2)忽略方式(SIG_IGN):进程接收到一个已指明忽略的信号,则将该信号清除后,立即返回,不在任何工作。信号SIGKILL不能被忽略。 (3)保持方式(SIG_HOLD):当进程处于该方式时,将接收的信号保存起来,等该进程的保持方式解除后,再进行处理。 (4)捕获方式(设置信号处理函数):这是用户设置的信号处理方式,当进程接收到这种信号时
[1] [2] 下一页
(出处:http://www.sheup.com)
上一页 [1] [2]