第二讲 进程
内核跟踪进程的下列信息
运行的位置
访问的文件
信用状(安全机制)
当前目录
访问的内存空间
1.进程的属性
pid
基本属性pid(进程标识符)和ppid
pid_t getpid() // 获得本进程的进程id
pid_t getppid() // 在子进程中执行它,获得父进程的进程id
举例
#include <stdio.h>
#include <sys/types.h>
int main(int argc, char*argv[])
{
pid_t id = getpid();
printf("this id num %d/n",id);
return 0;
}
[root@localhost ch01]# gcc –o getpid getpid.c
[root@localhost ch01]# ./getpid
This id num 1991
信用状(安全机制)
etc/passwd、etc/group
int setgroups(size_t num, const gid_t *list)
int getgroups(size_t num, gid_t *lsit)
setuid/setgid和系统守护进程
什么是守护进程
real uid、saved uid、effective uid
int setreuid(uid_t ruid, uid_t euid) // BSD提出
int setuid(uid_t euid) // Posix标准
uid和gid总结
出错返回-1,正确执行时返回0
在大部分函数原形在unistd.h中定义
int setreuid(uid_t ruid,uid_t euid) // 设置当前进程的真实用户标示符为ruid,以及进程的有效// 用户标示符为euid
int setrgid(gid_t rgid, gid_t egid) // 设置当前进程的真实组标示符为ruid,以及进程的有效组
//标示符为euid
int setuid(uid_t uid) // 如果是普通用户调用,则将进程的有效用户标示符设置为uid
// 如果是root用户调用,则将真实、有效和已保存的用户标示符设置为uid
itn setgid(gid_t gid) // 如果是普通用户调用,则将进程的有效用户组标示符设置为uid
// 如果是root用户调用,则将真实、有效和已保存的用户组标示符设置为uid
int seteuid(uid_t gid) 等价于setreuid(-1,euid)
int setegid(gid_t gid) 等价于setrgid(-1,egid)
int setgroups(size_t num, const gid_t *list) // 把当前进程的补充组设为list
函数原型在grp.h中
uid_t getuid() // 返回进程的真实用户标示符
uid_t geteuid() // 返回进程的有效用户标示符
gid_t getgid() // 返回进程的真实组标示符
gid_t getegid() // 返回进程的有效组标示符
size_t getgroups(size_t size, gid_t list[]) // 将当前进程的补充组返回到list中
函数原形在grp.h中
2.进程相关信息
程序参数
int main(int argc ,char *argv[])
extern char *environ[] // 全局变量,指向环境变量中的每个元素。声明在<usrstd.h>中
const char *getenv(const char *name) // 如果这个值存在,返回指向全局变量中名字为
// name值的指针,否则返回NULL
int putenv(const char *string) // Posix标准定义,具有比较好的移植性
int setenv(const char *name, const char *value, int overwrite) // BSD定义
例:putenv(“PATH=/bin:/usr/bin”)
setenv(“PATH”,”/bin:/usr/bin”,1)
资源使用
int getruseage(int who ,strcut rusage *usage)
who–RUSAGE_SELF
RUSAGE_CHILDREN
RUSAGE_BOTH
#include <sys/resource.h>
struct rusage{
struct timeval ru_utime; // 执行用户代码所用的时间,包括运行用户代码指定的所有
//时间,不包括内核用来完成应用程序请求的
struct timeval ru_stime; //内核用于系统请求的全部时间,其中不包括在系统调用时
//进程阻塞所花的时间
long int ru_minflt; // 进程所造成的次要缺陷数
long int ru_majflt; // 进程照成的主要缺陷数
long int ru_nswap; // 进程的访问而从磁盘调用内存的页面数
……......
}
建立使用限制
int getrlimit(int resource ,struct rlimit *rlim)
int setrlimit(int resource,const struct rlimit *rlim)
struct rlimit
{
long int rlim_cur; // 软限制值是多少
long int rlim_max; // 应限制是多少
}
RLIMIT_AS // 进程处于内存的最大数量
RLIMIT_CORE // 由内核生成的core文件的最大大小
RLIMIT_CPU // 全部cpu时间
RLIMIT_DATA // 数据存储的最大容量
RLIMIT_FSIZE // 打开文件的最大数目
RLIMIT_MEMLOCK
RLIMIT_NOFILE // 打开文件的最大数
RLIMIT_NPROC // 进程可以产生的最大子进程数目
RLIMIT_RSS // 可以随时使用的内存容量
RLIMIT_STACK // 堆栈存储区的最大容量
3.进程基本元素
创建子进程
#include <unistd.h>
pid_t fork();
特别之处:返回两次
举例
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
pid_t child;
if (!(child=fork()))
{
printf("/nin child/n");
_exit(0);
}
printf("in parent -- child is %d/n",child);
return 0;
}
[root@localhost ch01]# gcc –o forkd forkd.c
[root@localhost ch01]# ./forkd
in child
in parent – child is 1918
等待子进程结束
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
WIFEXITED(status) //是否正常退出 WEXITSTATUS(status) //返回进程的退出代码
WISIGNALED(status) //是否被信号终止
WTERMSIG(status) // 终止进程的信号的号码
WIFSTOPPED(status)//进程已被信号终止 WSTOPSIG(status) //返回停止进程的信号
pid_t wait(int *status)
pid_t waitpid(pid_t pid, int *status, int options)
pid_t wait3(int *status, int options ,strcut rusage rusage)
运行新进程
int execl(const char *path, const char *arg0,….);
int execlp(const char *file, const char *arg0,…);
int execle(const char *path, const char *arg0,…);
int execv(const char *path, const char **argv);
int execvp(const char *file, const char **argv);
int execve(const char *file, const char **argv);
运行成功没有返回;失败返回-1
execl(“/bin/cat”,”/bin/cat”,”/etc/passwd”, ”/etc/group”, NULL);
char * argv[] = {“./cat”, ”/etc/passwd”, “/etc/group”, NULL};
execv(“/bin/cat”, argv);
char *newenv[] = {“PATH = /bin:/usr/bin”,”HOME=/home/sweethome”,NULL}
execle(“/usr/bin/env”, ”/usr/bin/env”, NULL, newenv);
char *argv[]={“/usr/bin/env”, NULL};
char *newenv[]={“PATH=/bin:usr/bin”, ”HOME=/home/sweethome”, NULL}
execve(“/usr/bin/env”, argv, newenv);
execlp(“cat”, “cat”, “/etc/passwd”, “/etc/group”, NULL);
char *argv[]={“./cat”, “/etc/passwd”, “/etc/group”, NULL};
execvp(“cat”, argv);
终止
void exit(int exitcode);
void _exit(int exitcode);
int kill(pid_t pid, int signum);
4.简单子进程
system()
int system(const char *cmd) // 首先fork一个exec系列的函数,在这个中运行了一个shell的子程序,然后用这个shell运行cmd命令。原来的程序等待子进程退出,然后返回类似于wait函数的返回。
/bin/sh
示例
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
int result;
result = system("exec ls -l");
if (!WIFEXITED(result)){
printf("abnormal exit/n");
}
return 0;
}
[root@localhost ch01]# gcc –o testsystem testsystem.c
[root@localhost ch01]# ./testsystem
总用量 304
-rwx------
1 root root 11791 5月 16 22:10 a.out
-rwx------
1 root root 162 5月 21 21:50 ~$ch02.doc
-rwx------
1 root root 95232 5月 21 21:57 ch02.doc
-rwx------
1 root root 11791 5月 16 22:11 forkd
-rwx------
1 root root 218 5月 16 22:09 forkd.c
-rwx------
1 root root 11649 5月 10 20:32 getpid
-rwx------
1 root root 144 5月 10 20:32 getpid.c
-rwx------
1 root root 11693 5月 21 22:05 testsystem
-rwx------
1 root root 211 5月 21 22:05 testsystem.c
-rwx------
1 root root 0 5月 21 22:06 test.tmp
-rwx------
1 root root 94720 5月 16 22:45 ~WRL0001.tmp
-rwx------
1 root root 94208 5月 21 21:50 ~WRL0003.tmp
-rwx------
1 root root 94208 5月 21 21:52 ~WRL0005.tmp
-rwx------
1 root root 95232 5月 21 21:56 ~WRL2785.tmp
-rwx------
1 root root 94208 5月 21 21:52 ~WRL4030.tmp
从进程读或写
FILE *popen(const char *cmd, const char *mode)
int pclose(FILE *stream);
5.会话和进程组
会话
控制终端
进程组
孤儿进程组