/* Warning : *** 09/24/2007 This file is provided as reference. The commands defined here have only been tested the 2.6.14 kernel version as this was the only kernel dump available to me for the crash port effort. *** Below is a simple mapping of a subset of the native "files" command. It was producedin a an attempt to minimally validate the crash port. Even the help text and actual supported functionality are out of sync... */ string sfiles_opt() { return "ld:R:"; } string sfiles_usage() { return "[-l | -d dentry] | [-R reference] [pid | taskp] ... \n"; } static void sfiles_showusage() { printf("usage : ps %s\n", sfiles_usage()); } string sfiles_help() { return " This command displays information about open files of a context.\n"+ " It prints the context's current root directory and current working\n"+ " directory, and then for each open file descriptor it prints a pointer\n"+ " to its file struct, a pointer to its dentry struct, a pointer to the\n"+ " inode, the file type, and the pathname. If no arguments are entered,\n"+ " the current context is used. The -R option typically invoked from\n"+ " 'foreach files', searches for references to a supplied number, address+\n"+ " or filename argument, and prints only the essential information leading\n"+ " up to and including the reference. The -l and -d options are not context\n"+ " specific, and only show the data requested.\n\n"+ " -l display files open by lockd server for client locks.\n"+ " -d dentry given a hexadecimal dentry address+ display its inode+\n"+ " super block+ file type+ and full pathname.\n"+ " -R reference search for references to this file descriptor number+\n"+ " filename+ or dentry+ inode+ or file structure address.\n"+ " pid a process PID.\n"+ " taskp a hexadecimal task_struct pointer.\n"+ "\nEXAMPLES\n"+ " Display the open files of the current context:\n\n"+ " %s> files\n"+ " PID: 720 TASK: c67f2000 CPU: 1 COMMAND: \"innd\"\n"+ " ROOT: / CWD: /var/spool/news/articles\n"+ " FD FILE DENTRY INODE TYPE PATH\n"+ " 0 c6b9c740 c7cc45a0 c7c939e0 CHR /dev/null\n"+ " 1 c6b9c800 c537bb20 c54d0000 REG /var/log/news/news\n"+ " 2 c6df9600 c537b420 c5c36360 REG /var/log/news/errlog\n"+ " 3 c74182c0 c6ede260 c6da3d40 PIPE\n"+ " 4 c6df9720 c696c620 c69398c0 SOCK\n"+ " 5 c6b9cc20 c68e7000 c6938d80 SOCK\n"+ " 6 c6b9c920 c7cc45a0 c7c939e0 CHR /dev/null\n"+ " 7 c6b9c680 c58fa5c0 c58a1200 REG /var/lib/news/history\n"+ " 8 c6df9f00 c6ede760 c6da3200 PIPE\n"+ " 9 c6b9c6e0 c58fa140 c5929560 REG /var/lib/news/history.dir\n"+ " 10 c7fa9320 c7fab160 c7fafd40 CHR /dev/console\n"+ " 11 c6b9c7a0 c58fa5c0 c58a1200 REG /var/lib/news/history\n"+ " 12 c377ec60 c58fa5c0 c58a1200 REG /var/lib/news/history\n"+ " 13 c4528aa0 c58fa6c0 c52fbb00 REG /var/lib/news/history.pag\n"+ " 14 c6df9420 c68e7700 c6938360 SOCK\n"+ " 15 c6df9360 c68e7780 c6938120 SOCK\n"+ " 16 c6b9c0e0 c68e7800 c6772000 SOCK\n"+ " 17 c6b9c200 c6b5f9c0 c6b5cea0 REG /var/lib/news/active\n"+ " 21 c6b9c080 c6ede760 c6da3200 PIPE\n"+ " \n"+ " Display the files opened by the \"crond\" daemon+ which is PID 462:\n\n"+ " %s> files 462\n"+ " PID: 462 TASK: f7220000 CPU: 2 COMMAND: \"crond\"\n"+ " ROOT: / CWD: /var/spool\n"+ " FD FILE DENTRY INODE TYPE PATH\n"+ " 0 f7534ae0 f7538de0 f7518dc0 CHR /dev/console\n"+ " 1 f7368f80 f72c7a40 f72f27e0 FIFO pipe:/[1456]\n"+ " 2 f74f3c80 f72c79c0 f72f2600 FIFO pipe:/[1457]\n"+ " 3 f7368b60 f72a5be0 f74300c0 REG /var/run/crond.pid\n"+ " 4 f7534360 f73408c0 f72c2840 REG /var/log/cron\n"+ " 7 f7368ce0 f72c7940 f72f2420 FIFO pipe:/[1458]\n"+ " 8 f7295de0 f72c7940 f72f2420 FIFO pipe:/[1458]\n"+ " 21 f74f36e0 f747cdc0 f747e840 CHR /dev/null\n"+ " \n"+ " The -R option is typically invoked from \"foreach files\". This example\n"+ " shows all tasks that have \"/dev/pts/4\" open:\n\n"+ " %s> foreach files -R pts/4\n"+ " PID: 18633 TASK: c310a000 CPU: 0 COMMAND: \"crash\"\n"+ " ROOT: / CWD: /home/CVS_pool/crash \n"+ " FD FILE DENTRY INODE TYPE PATH\n"+ " 0 c1412850 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " 1 c1412850 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " 2 c1412850 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " \n"+ " PID: 18664 TASK: c2392000 CPU: 1 COMMAND: \"less\"\n"+ " ROOT: / CWD: /home/CVS_pool/crash \n"+ " FD FILE DENTRY INODE TYPE PATH\n"+ " 1 c1412850 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " 2 c1412850 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " \n"+ " PID: 23162 TASK: c5088000 CPU: 1 COMMAND: \"bash\"\n"+ " ROOT: / CWD: /home/CVS_pool/crash \n"+ " FD FILE DENTRY INODE TYPE PATH\n"+ " 0 c1412850 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " 1 c1412850 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " 2 c1412850 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " 255 c1412850 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " \n"+ " PID: 23159 TASK: c10fc000 CPU: 1 COMMAND: \"xterm\"\n"+ " ROOT: / CWD: /homes/anderson/ \n"+ " FD FILE DENTRY INODE TYPE PATH\n"+ " 5 c1560da0 c2cb96d0 c2cad430 CHR /dev/pts/4\n"+ " \n"+ " Display information about the dentry at address f745fd60:\n\n"+ " %s> files -d f745fd60\n"+ " DENTRY INODE SUPERBLK TYPE PATH\n"+ " f745fd60 f7284640 f73a3e00 REG /var/spool/lpd/lpd.lock\n"; } #if LINUX_RELEASE > 0x020611 typedef struct task_struct task_t; #endif void print_task_header(unsigned long tval, int newline) { task_t *t=(task_t*)tval; printf("%sPID: %-5ld TASK: 0x%p CPU: %-2d COMMAND: \"%s\"\n", newline ? "\n" : "", t->pid, t, #if LINUX_RELEASE >= 0x020616 ((struct thread_info *)(t)->stack)->cpu, #else t->thread_info->cpu, #endif getstr(t->comm)); } /* Traditional mask definitions for st_mode. */ #define S_IFMT 0170000 /* type of file */ #define S_IFREG 0100000 /* regular */ #define S_IFBLK 0060000 /* block special */ #define S_IFDIR 0040000 /* directory */ #define S_IFCHR 0020000 /* character special */ #define S_IFIFO 0010000 /* this is a FIFO */ #define S_ISUID 0004000 /* set user id on execution */ #define S_ISGID 0002000 /* set group id on execution */ #define S_IFSOCK 0140000 /* Socket. */ #define S_IFLNK 0120000 /* POSIX masks for st_mode. */ #define S_IRWXU 00700 /* owner: rwx------ */ #define S_IRUSR 00400 /* owner: r-------- */ #define S_IWUSR 00200 /* owner: -w------- */ #define S_IXUSR 00100 /* owner: --x------ */ #define S_IRWXG 00070 /* group: ---rwx--- */ #define S_IRGRP 00040 /* group: ---r----- */ #define S_IWGRP 00020 /* group: ----w---- */ #define S_IXGRP 00010 /* group: -----x--- */ #define S_IRWXO 00007 /* others: ------rwx */ #define S_IROTH 00004 /* others: ------r-- */ #define S_IWOTH 00002 /* others: -------w- */ #define S_IXOTH 00001 /* others: --------x */ /* The following macros test st_mode (from POSIX Sec. 5.6.1.1. */ #define S_ISREG(m) ((m & S_IFMT) == S_IFREG) /* is a reg file */ #define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) /* is a directory */ #define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR) /* is a char spec */ #define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK) /* is a block spec */ #define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO) /* is a pipe/FIFO */ #define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK) /* is a socket */ #define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK) /* * Return a 4-character type string of an inode, modifying a previously * gathered pathname if necessary. */ static string pathParam; char * inode_type(struct inode *inode) { string type; unsigned int fmode; fmode = 0; fmode = inode->i_mode; type = "UNKN"; if (S_ISREG(fmode)) type = "REG "; if (S_ISLNK(fmode)) type = "LNK "; if (S_ISDIR(fmode)) type = "DIR "; if (S_ISCHR(fmode)) type = "CHR "; if (S_ISBLK(fmode)) type = "BLK "; if (S_ISFIFO(fmode)) { type = "FIFO"; if (exists("pipe_inode_operations")) { if (inode->i_op == pipe_inode_operations) { type = "PIPE"; pathParam=""; } } else { if (exists("rdwr_pipe_fops")) { if (inode->i_fop == rdwr_pipe_fops) { type = "PIPE"; pathParam=""; } } } } if (S_ISSOCK(fmode)) { type = "SOCK"; if (pathParam=="/") pathParam=""; } return type; } #define FILES_LOCKD 1 string get_pathname(struct dentry *dentry, int full, struct vfsmount *vfsmnt) { struct dentry *tmp_dentry, *parent; int d_name_len = 0; struct vfsmount *tmp_vfsmnt, *mnt_parent; string pathname, tmpname; parent = dentry; tmp_vfsmnt = vfsmnt; do { tmp_dentry = parent; if (!tmp_dentry->d_name.len) break; if (!tmp_dentry->d_name.name) break; tmpname=getstr(tmp_dentry->d_name.name); if (tmp_dentry != dentry) { if (tmpname != "/") { pathname=tmpname+"/"+pathname; } } else { pathname=tmpname; } parent = tmp_dentry->d_parent; if (tmp_dentry == parent && full) { if(member(tmp_vfsmnt, "mnt_mountpoint")) { if (tmp_vfsmnt) { parent = tmp_vfsmnt->mnt_mountpoint; mnt_parent = tmp_vfsmnt->mnt_parent; if (tmp_vfsmnt == mnt_parent) break; else tmp_vfsmnt = mnt_parent; } } else { parent = tmp_dentry->d_covers; } } } while (tmp_dentry != parent && parent); if(pathname != "/") pathname="/"+pathname; return pathname; } #define __NFDBITS (8 * sizeof(unsigned long )) #define DUMP_FULL_NAME 1 #define DUMP_INODE_ONLY 2 #define DUMP_DENTRY_ONLY 4 static void file_dump(struct file *file, struct dentry *dentry, struct inode *inode, int fd, int flags) { string pathname, type; if(file && !dentry && !(dentry=file->f_dentry)) return FALSE; if(!inode && !(inode=dentry->d_inode)) return FALSE; if (flags & DUMP_FULL_NAME) { if (member(file, "f_vfsmnt")) { pathname=get_pathname(dentry, 1, file->f_vfsmnt); } else { pathname=get_pathname(dentry, 1, 0); } } else pathname=get_pathname(dentry, 0, 0); pathParam=pathname; type = inode_type(inode); printf("%3d %p %p %p %-8s %s\n", fd, file, dentry, inode, type, pathParam); } void open_files_dump(unsigned long tv, int flags, string ref) { task_t *t=(task_t*)tv; string pwd, root; int max_fdset=0, max_fds=0, i, j, header_printed=0; fd_set *open_fds=0; struct file **fd=0; // get info on pwd and root of current task if(t->fs) { if(t->fs->root) { root=get_pathname(t->fs->root, 1, member(t->fs, "rootmnt")?t->fs->rootmnt:0); } if(t->fs->pwd) { pwd=get_pathname(t->fs->pwd, 1, member(t->fs, "pwdmnt")?t->fs->pwdmnt:0); } printf("ROOT: %s CWD: %s\n", root, pwd); } if(t->files) { if(member(t->files, "max_fdset")) { max_fdset = t->files->max_fdset; max_fds = t->files->max_fds; } } if(member(t->files, "fdt")) { if(t->files->fdt) { if(member(t->files->fdt, "max_fdset")) { max_fdset = t->files->fdt->max_fdset; } else max_fdset = -1; max_fds = t->files->fdt->max_fds; } } if (member(t->files->fdt, "open_fds")) open_fds = t->files->fdt->open_fds; else open_fds = t->files->open_fds; if(member(t->files->fdt, "fd")) fd = t->files->fdt->fd; else fd = t->files->fd; if(!open_fds && !fd) return; for(j=0;;) { unsigned long set; struct file *file; i = j * __NFDBITS; if (((max_fdset >= 0) && (i >= max_fdset)) || (i >= max_fds)) break; set = open_fds->fds_bits[j++]; while (set) { if (set & 1) { if(file=fd[i]) { if (!header_printed) { printf(" FD %-8s %> %-8s %> %-8s %> %-8s %s\n", "FILE","DENTRY","INODE","TYPE","PATH"); header_printed = 1; } file_dump(file, 0, 0, i, DUMP_FULL_NAME); } } i++; set >>= 1; } } } void sfiles() { int flag=0; string ref=""; if(lflag) { flag |= FILES_LOCKD; } else if(Rflag) { ref=Rarg; } else if(dflag) { display_dentry_info(atoi(darg)); return; } else { if (argc==1) { if (flag & FILES_LOCKD) { nlm_files_dump(); } else { if (!ref) print_task_header(curtask(), 0); open_files_dump(curtask(), 0, ref); } return; } } return; }