📄 base.c
字号:
struct files_struct * files; retval = 0; pid = p->pid; fd = filp->f_pos; switch (fd) { case 0: if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) goto out; filp->f_pos++; case 1: ino = fake_ino(pid, PROC_PID_INO); if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) goto out; filp->f_pos++; default: task_lock(p); files = p->files; if (files) atomic_inc(&files->count); task_unlock(p); if (!files) goto out; read_lock(&files->file_lock); for (fd = filp->f_pos-2; fd < files->max_fds; fd++, filp->f_pos++) { unsigned int i,j; if (!fcheck_files(files, fd)) continue; read_unlock(&files->file_lock); j = NUMBUF; i = fd; do { j--; buf[j] = '0' + (i % 10); i /= 10; } while (i); ino = fake_ino(pid, PROC_PID_FD_DIR + fd); if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) { read_lock(&files->file_lock); break; } read_lock(&files->file_lock); } read_unlock(&files->file_lock); put_files_struct(files); }out: return retval;}static int proc_base_readdir(struct file * filp, void * dirent, filldir_t filldir){ int i; int pid; struct inode *inode = filp->f_dentry->d_inode; struct pid_entry *p; pid = inode->u.proc_i.task->pid; if (!pid) return -ENOENT; i = filp->f_pos; switch (i) { case 0: if (filldir(dirent, ".", 1, i, inode->i_ino, DT_DIR) < 0) return 0; i++; filp->f_pos++; /* fall through */ case 1: if (filldir(dirent, "..", 2, i, PROC_ROOT_INO, DT_DIR) < 0) return 0; i++; filp->f_pos++; /* fall through */ default: i -= 2; if (i>=sizeof(base_stuff)/sizeof(base_stuff[0])) return 1; p = base_stuff + i; while (p->name) { if (filldir(dirent, p->name, p->len, filp->f_pos, fake_ino(pid, p->type), p->mode >> 12) < 0) return 0; filp->f_pos++; p++; } } return 1;}/* building an inode */static int task_dumpable(struct task_struct *task){ int dumpable = 0; struct mm_struct *mm; task_lock(task); mm = task->mm; if (mm) dumpable = mm->dumpable; task_unlock(task); return dumpable;}static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino){ struct inode * inode; /* We need a new inode */ inode = new_inode(sb); if (!inode) goto out; /* Common stuff */ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_ino = fake_ino(task->pid, ino); if (!task->pid) goto out_unlock; /* * grab the reference to task. */ get_task_struct(task); inode->u.proc_i.task = task; inode->i_uid = 0; inode->i_gid = 0; if (ino == PROC_PID_INO || task_dumpable(task)) { inode->i_uid = task->euid; inode->i_gid = task->egid; }out: return inode;out_unlock: iput(inode); return NULL;}/* dentry stuff */static int pid_fd_revalidate(struct dentry * dentry, int flags){ return 0;}/* * Exceptional case: normally we are not allowed to unhash a busy * directory. In this case, however, we can do it - no aliasing problems * due to the way we treat inodes. */static int pid_base_revalidate(struct dentry * dentry, int flags){ if (dentry->d_inode->u.proc_i.task->pid) return 1; d_drop(dentry); return 0;}static int pid_delete_dentry(struct dentry * dentry){ return 1;}static struct dentry_operations pid_fd_dentry_operations ={ d_revalidate: pid_fd_revalidate, d_delete: pid_delete_dentry,};static struct dentry_operations pid_dentry_operations ={ d_delete: pid_delete_dentry,};static struct dentry_operations pid_base_dentry_operations ={ d_revalidate: pid_base_revalidate, d_delete: pid_delete_dentry,};/* Lookups */#define MAX_MULBY10 ((~0U-9)/10)static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry){ unsigned int fd, c; struct task_struct *task = dir->u.proc_i.task; struct file * file; struct files_struct * files; struct inode *inode; const char *name; int len; fd = 0; len = dentry->d_name.len; name = dentry->d_name.name; if (len > 1 && *name == '0') goto out; while (len-- > 0) { c = *name - '0'; name++; if (c > 9) goto out; if (fd >= MAX_MULBY10) goto out; fd *= 10; fd += c; } inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_FD_DIR+fd); if (!inode) goto out; task_lock(task); files = task->files; if (files) atomic_inc(&files->count); task_unlock(task); if (!files) goto out_unlock; read_lock(&files->file_lock); file = inode->u.proc_i.file = fcheck_files(files, fd); if (!file) goto out_unlock2; get_file(file); read_unlock(&files->file_lock); put_files_struct(files); inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; inode->i_mode = S_IFLNK; inode->u.proc_i.op.proc_get_link = proc_fd_link; if (file->f_mode & 1) inode->i_mode |= S_IRUSR | S_IXUSR; if (file->f_mode & 2) inode->i_mode |= S_IWUSR | S_IXUSR; dentry->d_op = &pid_fd_dentry_operations; d_add(dentry, inode); return NULL;out_unlock2: put_files_struct(files); read_unlock(&files->file_lock);out_unlock: iput(inode);out: return ERR_PTR(-ENOENT);}static struct file_operations proc_fd_operations = { read: generic_read_dir, readdir: proc_readfd,};/* * proc directories can do almost nothing.. */static struct inode_operations proc_fd_inode_operations = { lookup: proc_lookupfd, permission: proc_permission,};static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry){ struct inode *inode; int error; struct task_struct *task = dir->u.proc_i.task; struct pid_entry *p; error = -ENOENT; inode = NULL; for (p = base_stuff; p->name; p++) { if (p->len != dentry->d_name.len) continue; if (!memcmp(dentry->d_name.name, p->name, p->len)) break; } if (!p->name) goto out; error = -EINVAL; inode = proc_pid_make_inode(dir->i_sb, task, p->type); if (!inode) goto out; inode->i_mode = p->mode; /* * Yes, it does not scale. And it should not. Don't add * new entries into /proc/<pid>/ without very good reasons. */ switch(p->type) { case PROC_PID_FD: inode->i_nlink = 2; inode->i_op = &proc_fd_inode_operations; inode->i_fop = &proc_fd_operations; break; case PROC_PID_EXE: inode->i_op = &proc_pid_link_inode_operations; inode->u.proc_i.op.proc_get_link = proc_exe_link; break; case PROC_PID_CWD: inode->i_op = &proc_pid_link_inode_operations; inode->u.proc_i.op.proc_get_link = proc_cwd_link; break; case PROC_PID_ROOT: inode->i_op = &proc_pid_link_inode_operations; inode->u.proc_i.op.proc_get_link = proc_root_link; break; case PROC_PID_ENVIRON: inode->i_fop = &proc_info_file_operations; inode->u.proc_i.op.proc_read = proc_pid_environ; break; case PROC_PID_STATUS: inode->i_fop = &proc_info_file_operations; inode->u.proc_i.op.proc_read = proc_pid_status; break; case PROC_PID_STAT: inode->i_fop = &proc_info_file_operations; inode->u.proc_i.op.proc_read = proc_pid_stat; break; case PROC_PID_CMDLINE: inode->i_fop = &proc_info_file_operations; inode->u.proc_i.op.proc_read = proc_pid_cmdline; break; case PROC_PID_STATM: inode->i_fop = &proc_info_file_operations; inode->u.proc_i.op.proc_read = proc_pid_statm; break; case PROC_PID_MAPS: inode->i_fop = &proc_maps_operations; break;#ifdef CONFIG_SMP case PROC_PID_CPU: inode->i_fop = &proc_info_file_operations; inode->u.proc_i.op.proc_read = proc_pid_cpu; break;#endif case PROC_PID_MEM: inode->i_op = &proc_mem_inode_operations; inode->i_fop = &proc_mem_operations; break; default: printk("procfs: impossible type (%d)",p->type); iput(inode); return ERR_PTR(-EINVAL); } dentry->d_op = &pid_dentry_operations; d_add(dentry, inode); return NULL;out: return ERR_PTR(error);}static struct file_operations proc_base_operations = { read: generic_read_dir, readdir: proc_base_readdir,};static struct inode_operations proc_base_inode_operations = { lookup: proc_base_lookup,};/* * /proc/self: */static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen){ char tmp[30]; sprintf(tmp, "%d", current->pid); return vfs_readlink(dentry,buffer,buflen,tmp);}static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd){ char tmp[30]; sprintf(tmp, "%d", current->pid); return vfs_follow_link(nd,tmp);} static struct inode_operations proc_self_inode_operations = { readlink: proc_self_readlink, follow_link: proc_self_follow_link,};struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry){ unsigned int pid, c; struct task_struct *task; const char *name; struct inode *inode; int len; pid = 0; name = dentry->d_name.name; len = dentry->d_name.len; if (len == 4 && !memcmp(name, "self", 4)) { inode = new_inode(dir->i_sb); if (!inode) return ERR_PTR(-ENOMEM); inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_ino = fake_ino(0, PROC_PID_INO); inode->u.proc_i.file = NULL; inode->u.proc_i.task = NULL; inode->i_mode = S_IFLNK|S_IRWXUGO; inode->i_uid = inode->i_gid = 0; inode->i_size = 64; inode->i_op = &proc_self_inode_operations; d_add(dentry, inode); return NULL; } while (len-- > 0) { c = *name - '0'; name++; if (c > 9) goto out; if (pid >= MAX_MULBY10) goto out; pid *= 10; pid += c; if (!pid) goto out; } read_lock(&tasklist_lock); task = find_task_by_pid(pid); if (task) get_task_struct(task); read_unlock(&tasklist_lock); if (!task) goto out; inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO); free_task_struct(task); if (!inode) goto out; inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_base_inode_operations; inode->i_fop = &proc_base_operations; inode->i_nlink = 3; inode->i_flags|=S_IMMUTABLE; dentry->d_op = &pid_base_dentry_operations; d_add(dentry, inode); return NULL;out: return ERR_PTR(-ENOENT);}void proc_pid_delete_inode(struct inode *inode){ if (inode->u.proc_i.file) fput(inode->u.proc_i.file); if (inode->u.proc_i.task) free_task_struct(inode->u.proc_i.task);}#define PROC_NUMBUF 10#define PROC_MAXPIDS 20/* * Get a few pid's to return for filldir - we need to hold the * tasklist lock while doing this, and we must release it before * we actually do the filldir itself, so we use a temp buffer.. */static int get_pid_list(int index, unsigned int *pids){ struct task_struct *p; int nr_pids = 0; index--; read_lock(&tasklist_lock); for_each_task(p) { int pid = p->pid; if (!pid) continue; if (--index >= 0) continue; pids[nr_pids] = pid; nr_pids++; if (nr_pids >= PROC_MAXPIDS) break; } read_unlock(&tasklist_lock); return nr_pids;}int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir){ unsigned int pid_array[PROC_MAXPIDS]; char buf[PROC_NUMBUF]; unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; unsigned int nr_pids, i; if (!nr) { ino_t ino = fake_ino(0,PROC_PID_INO); if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0) return 0; filp->f_pos++; nr++; } nr_pids = get_pid_list(nr, pid_array); for (i = 0; i < nr_pids; i++) { int pid = pid_array[i]; ino_t ino = fake_ino(pid,PROC_PID_INO); unsigned long j = PROC_NUMBUF; do buf[--j] = '0' + (pid % 10); while (pid/=10); if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino, DT_DIR) < 0) break; filp->f_pos++; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -