2012-09-25 17:34:49 linuxheik 阅读数 2084

如何查看进程打开了哪些文件?---linux下的proc文件系统

分类: Linux操作系统 594人阅读 评论(0) 收藏 举报

procfs是一种伪文件系统。 记录了系统运行时的所有内核信息和配置信息。这样我们就可以简单直接的通过echo或cat这样的文件操作命令对系统信息进行查取。

procfs是一种文件系统,通常会挂载在/proc上。ls /proc 可以看到很多以进程ID命名的文件夹,每个进程运行时的信息都记录在相应的文件夹下,而内核运行时信息直接记录在/proc下,大多是只读文件,如meminfo,cpuinfo,cmdline等,非数字命名的文件夹,是内核各子系统相关部分,如bus 总线信息(只读)
drivers 驱动信息(只读) 
fs 文件系统特别信息(只读) 
ide IDE接口信息(只读) 
irq IRQ信息(只读) 
net 网络子系统信息(只读) 
scsi SCSI系统信息(只读) 
sysvipc IPC子系统信息(只读) 
tty tty子系统信息(只读) 
sys 系统内核可调参数 (可调)

 

通过访问这些文件和文件夹,我们可以实时查询到当前系统的运行信息,甚至是某一进程的运行时信息。
比如查看某个进程打开了哪些文件:ls -l /proc/5040/fd/
查看这个进程的工作路径:ls -l /proc/5040/cwd/
查看这个进程的二进制文件所在位置:ls -l /proc/5040/exe
查看进程的状态总览:cat /proc/5040/status
查看进程的内存使用状态: cat /proc/5040/statm

 

查看当前系统的内存使用情况:cat /proc/meminfo
查看当前系统的网络流量:cat /proc/net/dev
查看当前系统的负载:cat /proc/loadavg
查看当前系统的连接情况:cat /proc/net/snmp
查看当前系统的基本统计情况(cpu时间的消耗分布等):cat /proc/stat

 

如果对这些文件和文件夹的命名或内容意义并不清楚的话,可以使用 man proc 查看系统说明。

参考自http://apps.hi.baidu.com/share/detail/32689077

查看评论
2017-03-08 13:57:00 shjniu3000 阅读数 118
ps -ef | grep niu  --查看niu的进程号
pwdx 3912    --看3192这个进程在哪个目录
kill -9 3912 --杀死进程

du -h --max-depth=1 --查看文件夹的大小
du -sh  --查看当前文件夹下所有文件的大小,包括子文件夹
du -h ftp --查看指定文件夹下所有文件的大小
du -h ./package/compat-libstdc++-33-3.2.3-69.el6.x86_64.rpm  --查看指定文件的大小
du -hs ftp --查看文件夹的大小
df   -h --查看磁盘的大小
2015-10-09 11:39:26 jncpp 阅读数 823
  • Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。
  • /proc/N pid为N的进程信息
  • /proc/N/cmdline 进程启动命令
  • /proc/N/cwd 链接到进程当前工作目录
  • /proc/N/environ 进程环境变量列表
  • /proc/N/exe 链接到进程的执行命令文件
  • /proc/N/fd 包含进程相关的所有的文件描述符
  • /proc/N/maps 与进程相关的内存映射信息
  • /proc/N/mem 指代进程持有的内存,不可读
  • /proc/N/root 链接到进程的根目录
  • /proc/N/stat 进程的状态
  • /proc/N/statm 进程使用的内存的状态
  • /proc/N/status 进程状态信息,比stat/statm更具可读性
#!/bin/bash                                                                                                                                                                 

RES_COLOR="\E[0m"                                                                                                                                                           
RED_COLOR="\E[1;31m"                                                                                                                                                        
GREEN_COLOR="\E[1;32m"                                                                                                                                                      
YELOW_COLOR="\E[1;33m"                                                                                                                                                      
BLUE_COLOR="\E[1;34m"                                                                                                                                                       
PINK_COLOR="\E[1;35m"                                                                                                                                                       

if [ $# -ne 1 ] ; then                                                                                                                                                      
        echo -e ${RED_COLOR} "Usage: pwatch exe" ${RES_COLOR}                                                                                                               
        exit 1                                                                                                                                                              
fi                                                                                                                                                                          

for pid in `ps aux | grep $1 | awk '{print $2}'` ;                                                                                                                          
do                                                                                                                                                                          
        if [ -d "/proc/${pid}" ]; then                                                                                                                                      
                echo -ne "${pid} "                                                                                                                                          
                # echo -e ${BLUE_COLOR} `cat -v /proc/${pid}/cmdline` ${RES_COLOR}                                                                                          
                echo -e ${BLUE_COLOR} `ps aux | awk '{if($2=="'${pid}'") for(i=11;i<=NF;i++) printf("%s ", $i)}'` ${RES_COLOR}                                              
                echo -e ${GREEN_COLOR} EXE: `ls -l /proc/${pid}/exe 2>/dev/null | awk '{print $NF}'` ${RES_COLOR}                                                           
                echo -e ${GREEN_COLOR} PWD: `ls -l /proc/${pid}/cwd 2>/dev/null | awk '{print $NF}'` ${RES_COLOR}                                                           
        fi                                                                                                                                                                  
done 

➜ ~ ./pwatch.sh vim
27609 vim log.cpp
EXE: /usr/bin/vim
PWD: /home/service/common
35772 vim worker.cpp
EXE: /usr/bin/vim
PWD: /home/service/app/src

2014-08-09 11:08:52 u011401496 阅读数 3648

之前实现了用文件IO的方式可以实现文件的拷贝,那么对于进程而言,我们是否也可以实现呢?

答案是肯定的。

进程资源:

首先我们先回顾一下,进程的运行需要哪些资源呢?其资源包括CPU资源,内存资源,当然还有时间片资源,我们都知道进程是有 栈, 堆,  只读数据段,  数据段(已初始化的全局变量静态变量),bss段(未初始化的),   代码段还有一组寄存器值。

进程命令:

另外我们也可以通过 ps  -ef |grep 进程名命令来查看进程号(PID)和父进程号(PPID),之后还可以通过  

ps aux |grep 进程名或进程号来查看进程的状态(R,T,S,Z,(+)...).通过 kill -信号的序号或宏  PID来对信号发各种信号,注意这里面的kill可不是杀死进程的意思,我们可以通过给进程发信号来杀死进程kill -SIGKILL PID  ,当然我们可以通过 kill -l 来获取宏名,其次我们通过nice 或renice来给我们的进程设置不同的优先级,等等等等。

进程创建:

我们会用fork函数来创建进程,以前我们都很清除的知道,一个函数只可以返回一个返回值,那么进程创建的函数也只返回一个么?答案是不对的,因为通过fork函数创建的进程,如果成功的话我们向父进程返回子进程的PID号,向子进程返回0,如果创建失败,则向父进程返回-1。创建完子进程后,父进程从fork()的下一条语句开始执行,子进程也是从下一条语句执行么?

是的,因为创建子进程的时候拷贝父进程的pc寄存器值,而pc寄存器的值决定了你的进程是从什么地方开始的,所以当创建完子进程后,我们的子进程的执行与父进程的执行系一样的方式,但是注意他们两个不是一块进行的,也有先后关系,只是先后关系不确定,如果用vfork函数创建进程的话,那么我们的子进程是先进行的。

那么上面说了fork()函数与vfork()函数都可以创建进程,有什么区别呢?

<1>fork创建子进程后,父子进程执行的顺序是不确定的,父子进程的地址空间是独立的。

<2>vfork创建完子进程后,保证子进先执行,父进程在子进程结束,或调用exec函数族后才开始执行,

并且父子进程共享同一地址空间【如果子进程调用了exec函数则子进程会独立出来】。

那么怎样利用进程来进行文件的拷贝呢?以及怎样拷贝呢?具体实现的要求如下,父进程拷贝文件的前一半子进程拷贝文件的后一半,那么效率上面我们肯定比一个进程高得多了,以上就是对进程知识的相关回顾,知识点有了,思路有了,那么剩下的就只是代码实现的问题了,也就是体力劳动了:

请看下面代码的实现:


  

#include <head.h>

int child_copy(int fd_src,int fd_dest,int file_size)
{
	int ret;
	int n;
	char buf[1024];
	ret = lseek(fd_src,file_size/2,SEEK_SET);
	if(ret < 0)
	{
		perror("Fail to src_file lseek");
		exit(EXIT_FAILURE);
	}
	ret = lseek(fd_dest,file_size/2,SEEK_SET);
	if(ret < 0)
	{
		perror("Fail to dest_file lseek");
		exit(EXIT_FAILURE);
	}
	while(1)
	{
		n = read(fd_src,buf,sizeof(buf));
		if(n == 0)
			break;
		write(fd_dest,buf,n);
	}
	return 0;
}
int parent_copy(int fd_src,int fd_dest,int size)
{
	int n;
	int count = 0;
	char buf[1024];
	while(1)
	{
	//	lseek(fd_src,0,SEEK_SET);
	//	lseek(fd_dest,0,SEEK_SET);
		n = read(fd_src,buf,sizeof(buf));
		write(fd_dest,buf,n);
		count += n;
		if(count >= size/2)
			break;
	}
	return 0;
}
// ./a.out src_file dest_file
int main(int argc, const char *argv[])
{
	pid_t pid;
	int file_size;  //the size of file
	int fd_src,fd_dest; 
	struct stat f_info;

	if(argc < 3)
	{
		fprintf(stderr,"Usage :%s argv[1] argv[2]\n",argv[0]);
		exit(EXIT_FAILURE);
	}
	if(stat(argv[1],&f_info) < 0)
	{
		fprintf(stderr,"Fail to stat %s: %s",argv[1],strerror(errno));
		exit(EXIT_FAILURE);
	}
	file_size = f_info.st_size; //get the size of file
	
	fd_src = open(argv[1],O_RDONLY);//open the file
	if(fd_src < 0)
	{
		fprintf(stderr,"Fail to open %s : %s\n",argv[1],strerror(errno));
		exit(EXIT_FAILURE);
	}

	fd_dest = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666);
	if(fd_src < 0)
	{
		fprintf(stderr,"Fail to open %s : %s\n",argv[2],strerror(errno));
		exit(EXIT_FAILURE);
	}
	
	if(ftruncate(fd_dest,file_size) < 0)  //create a empty file
	{
		perror("fail to ftruncate");
		exit(EXIT_FAILURE);
	}

	pid = fork();
	if(pid < 0)
	{
		fprintf(stderr,"Fail to fork\n",strerror(errno));
		exit(EXIT_FAILURE);
	}
	if(pid == 0)
	{
		close(fd_src);
		close(fd_dest);
		fd_src = open(argv[1],O_RDONLY);//open the file again
		if(fd_src < 0)
		{
			fprintf(stderr,"Fail to open %s : %s\n",argv[1],strerror(errno));
			exit(EXIT_FAILURE);
		}

		fd_dest = open(argv[2],O_WRONLY);
		if(fd_src < 0)
		{
			fprintf(stderr,"Fail to open %s : %s\n",argv[2],strerror(errno));
			exit(EXIT_FAILURE);
		}
		
		child_copy(fd_src,fd_dest,file_size);
	}
	if(pid > 0)
	{
//		getchar();
		parent_copy(fd_src,fd_dest,file_size);
	}

	return 0;
}

    


注:

本程序用到的头文件本人直接封装在了head.h中。如果有哪里需要改进希望留言给我哈



2018-08-06 21:50:27 qq_38410730 阅读数 7812

作为文件的使用者,进程理所当然地将要使用的文件记录于自己的控制块。另外,由于进程所对应的程序也是一个文件,因此进程控制块还必须记录这个文件的相关信息。由于操作系统要对系统所以进程提供服务,因此操作系统还要维护一个记录所有进程打开文件的总表。

 

进程与其打开文件的关系

如果说文件管理系统是文件的管理者与提供者,那么进程就是文件系统中文件的使用者。即,文件管理系统与进程之间是服务与客户之间的关系。

文件对象

当进程通过系统调用open()打开一个文件时,该系统调用找到这个文件后,会把文件封装到一个file结构的实例中提供给进程,这个实例称为file对象。

file结构的定义如下:

struct file {
	union {
		struct list_head	fu_list;        //所有打开文件的链表
		struct rcu_head 	fu_rcuhead;
	} f_u;
	struct vfsmount     *f_vfsmnt;            //文件目录的VFS安装点指针
	struct dentry     *f_dentry;            //文件的dentry
#define f_dentry	f_path.dentry
#define f_vfsmnt	f_path.mnt
	const struct file_operations	*f_op;    //指向文件操作函数集的这孩子很
	spinlock_t		f_lock;          /* f_ep_links, f_flags, no IRQ */
	atomic_long_t		f_count;        //记录访问本文件的进程数目的计数器
	unsigned int 		f_flags;        //访问类型
	fmode_t			f_mode;            //访问模式
	loff_t			f_pos;            //文件的当前读写位置
	struct fown_struct	f_owner;
	const struct cred	*f_cred;        //id信息
	struct file_ra_state	f_ra;

	u64			f_version;
#ifdef CONFIG_SECURITY
	void			*f_security;
#endif
	void			*private_data;

#ifdef CONFIG_EPOLL
	struct list_head	f_ep_links;
#endif
	struct address_space	*f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
	unsigned long f_mnt_write_state;
#endif
};

其中,指针f_cred是记录文件所有者ID,文件所有者所在用户组ID的。其cred的结构如下:

struct cred {
	atomic_t	usage;
	uid_t		uid;		/* real UID of the task */
	gid_t		gid;		/* real GID of the task */
	uid_t		suid;		/* saved UID of the task */
	gid_t		sgid;		/* saved GID of the task */
	uid_t		euid;		/* effective UID of the task */
	gid_t		egid;		/* effective GID of the task */
	uid_t		fsuid;		/* UID for VFS ops */
	gid_t		fsgid;		/* GID for VFS ops */
	unsigned	securebits;	/* SUID-less security management */
	kernel_cap_t	cap_inheritable; /* caps our children can inherit */
	kernel_cap_t	cap_permitted;	/* caps we're permitted */
	kernel_cap_t	cap_effective;	/* caps we can actually use */
	kernel_cap_t	cap_bset;	/* capability bounding set */
#ifdef CONFIG_KEYS
	unsigned char	jit_keyring;	/* default keyring to attach requested
					 * keys to */
	struct key	*thread_keyring; /* keyring private to this thread */
	struct key	*request_key_auth; /* assumed request_key authority */
	struct thread_group_cred *tgcred; /* thread-group shared credentials */
#endif
#ifdef CONFIG_SECURITY
	void		*security;	/* subjective LSM security */
#endif
	struct user_struct *user;	/* real user ID subscription */
	struct group_info *group_info;	/* supplementary groups for euid/fsgid */
	struct rcu_head	rcu;		/* RCU deletion hook */
};

这就使得一个文件可能面临三种用户的访问:文件所有者、同组用户、其他用户。内核在处理一个进程或用户访问某一个文件的请求时,要根据进程的uid、fid和访问模式来确定该进程是否具有访问这个文件的权限。对于一个文件的用户来说,有读、写和执行三种文件操作,因此形成了三种权限,这三种权限与三种用户就共有9种组合,即文件的访问权限可以用9个二进制来表示,并将其保存在文件的dentry中。

结构中的f_ops记录了进程对文件读写位置的当前值,它可以通过调用函数llseek()进行移动。

值得注意的是,结构体中的指针f_op指向结构file_operations,该结构中封装了对于文件进行操作函数。该结构在文件include/linux/fs.h的定义如下:

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	int (*readdir) (struct file *, void *, filldir_t);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, struct dentry *, int datasync);
	int (*aio_fsync) (struct kiocb *, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	int (*setlease)(struct file *, long, struct file_lock **);
};

从结构中可以看到,结构中是一系列函数的指针,这里有熟悉的read()、write()、open()、close()等函数的指针。进程就是通过调用这些函数来访问一个文件的,所以有人说file_operations结构是Linux虚拟文件系统与进程之间的主要接口。

文件描述符

弄清楚了系统管理file对象的方法之后,下面就进一步介绍每个进程对它自己访问的file对象的管理方法。

Linux用一个数组来管理进程打开的文件的file对象,数组中的每一个元素都存放在一个指向进程所打开的文件的file对象。既然用一个数组来存放file对象,那么用数组的下标来访问文件就是一个顺理成章的方法,于是Linux就把数组元素的下标叫做该数组元素所对应的文件的文件描述符,该描述符就是系统对文件的标识,这个数组也叫做文件描述符数组,其示意图如下:

内核通过调用系统调用函数dup()、dup2()和fctl()可以使数组中的多个元素指向同一个文件的file对象。也就是说,在Linux中,同一个文件可以有多个文件描述符。

进程打开文件表

前面看到,文件描述符数组中存放了一个进程所访问的所有文件,把这个文件描述符数组和这个数组在系统中的一些动态信息组合在一起,就会形成一个新的数据结构——进程打开文件表。

进程打开文件表files_struct结构在文件include/linux/fdtable.h中的定义如下:

struct files_struct {
	atomic_t count;            //引用计数
	struct fdtable *fdt;
	struct fdtable fdtab;

	spinlock_t file_lock ____cacheline_aligned_in_smp;
	int next_fd;
	struct embedded_fd_set close_on_exec_init;
	struct embedded_fd_set open_fds_init;
	struct file * fd_array[NR_OPEN_DEFAULT];        //文件描述符表指针
};

显然,这个结构应该属于进程的数据,所以进程控制块用指针files指向它。

struct task_struct{
        ...
        struct files_struct *files;
        ...
}

进程与其打开文件之间的关系如下图所示:

因为进程对于的程序也是一个文件,这个文件的位置在哪呢?

进程在文件系统所在的位置叫做进程与文件系统的关系。Linux用结构fs_struct来描述进程在文件系统中的位置。结构fs_struct在文件include/linux.fs_struct.h中的定义如下:

struct fs_struct {
	int users;
	rwlock_t lock;
	int umask;
	int in_exec; 
	struct vfsmount *rootmnt, *pwdmnt, *altrootmnt;        //与安装有关的指针
	struct dentry *root, *pwd, *altroot;           //与进程位置有关的指针
};

其中,pwd指向进程的当前所在目录;root指向进程的根目录;altroot是进程的替换目录。如下所示:

另外三个指针rootmnt、pwdmnt和altrootmnt则对应地指向上面三个目录的结构vfsmount,该结构存放了目录的一些安装信息。

 

系统打开和关闭文件表

作为文件对象的提供者,操作系统必须对已经打开和使用过后已被关闭的文件进行记录。内核通过维护两个双向循环链表来管理这些被打开的文件和被关闭的文件:一个专门记录打开文件,另一个专门记录关闭文件。凡是file对象的f_count域不为NULL的文件,都被链入打开系统文件链表;而为NULL的文件,都被链入系统关闭文件链表。

当VFS需要一个file对象时,将调用函数get_empty_file()优先在系统关闭文件链表中摘取,如果链表中file对象的数目已经为限制的底线NR_RESERVED_FILES,则系统就另行分配file对象所需要的内存空间。

 

总结起来,就是:

 

没有更多推荐了,返回首页