10f66f451Sopenharmony_ci/* lsof.c - list open files. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2015 The Android Open Source Project 40f66f451Sopenharmony_ci 50f66f451Sopenharmony_ciUSE_LSOF(NEWTOY(lsof, "lp*t", TOYFLAG_USR|TOYFLAG_BIN)) 60f66f451Sopenharmony_ci 70f66f451Sopenharmony_ciconfig LSOF 80f66f451Sopenharmony_ci bool "lsof" 90f66f451Sopenharmony_ci default n 100f66f451Sopenharmony_ci help 110f66f451Sopenharmony_ci usage: lsof [-lt] [-p PID1,PID2,...] [FILE...] 120f66f451Sopenharmony_ci 130f66f451Sopenharmony_ci List all open files belonging to all active processes, or processes using 140f66f451Sopenharmony_ci listed FILE(s). 150f66f451Sopenharmony_ci 160f66f451Sopenharmony_ci -l list uids numerically 170f66f451Sopenharmony_ci -p for given comma-separated pids only (default all pids) 180f66f451Sopenharmony_ci -t terse (pid only) output 190f66f451Sopenharmony_ci*/ 200f66f451Sopenharmony_ci 210f66f451Sopenharmony_ci#define FOR_lsof 220f66f451Sopenharmony_ci#include "toys.h" 230f66f451Sopenharmony_ci 240f66f451Sopenharmony_ciGLOBALS( 250f66f451Sopenharmony_ci struct arg_list *p; 260f66f451Sopenharmony_ci 270f66f451Sopenharmony_ci struct stat *sought_files; 280f66f451Sopenharmony_ci struct double_list *all_sockets, *files; 290f66f451Sopenharmony_ci int last_shown_pid, shown_header; 300f66f451Sopenharmony_ci) 310f66f451Sopenharmony_ci 320f66f451Sopenharmony_cistruct proc_info { 330f66f451Sopenharmony_ci char cmd[17]; 340f66f451Sopenharmony_ci int pid, uid; 350f66f451Sopenharmony_ci}; 360f66f451Sopenharmony_ci 370f66f451Sopenharmony_cistruct file_info { 380f66f451Sopenharmony_ci char *next, *prev; 390f66f451Sopenharmony_ci 400f66f451Sopenharmony_ci // For output. 410f66f451Sopenharmony_ci struct proc_info pi; 420f66f451Sopenharmony_ci char *name, fd[8], rw, locks, type[10], device[32], size_off[32], node[32]; 430f66f451Sopenharmony_ci 440f66f451Sopenharmony_ci // For filtering. 450f66f451Sopenharmony_ci dev_t st_dev; 460f66f451Sopenharmony_ci ino_t st_ino; 470f66f451Sopenharmony_ci}; 480f66f451Sopenharmony_ci 490f66f451Sopenharmony_cistatic void print_info(void *data) 500f66f451Sopenharmony_ci{ 510f66f451Sopenharmony_ci struct file_info *fi = data; 520f66f451Sopenharmony_ci 530f66f451Sopenharmony_ci // Filter matches 540f66f451Sopenharmony_ci if (toys.optc) { 550f66f451Sopenharmony_ci int i; 560f66f451Sopenharmony_ci 570f66f451Sopenharmony_ci for (i = 0; i<toys.optc; i++) 580f66f451Sopenharmony_ci if (TT.sought_files[i].st_dev==fi->st_dev) 590f66f451Sopenharmony_ci if (TT.sought_files[i].st_ino==fi->st_ino) break; 600f66f451Sopenharmony_ci 610f66f451Sopenharmony_ci if (i==toys.optc) return; 620f66f451Sopenharmony_ci } 630f66f451Sopenharmony_ci 640f66f451Sopenharmony_ci if (toys.optflags&FLAG_t) { 650f66f451Sopenharmony_ci if (fi->pi.pid != TT.last_shown_pid) 660f66f451Sopenharmony_ci printf("%d\n", TT.last_shown_pid = fi->pi.pid); 670f66f451Sopenharmony_ci } else { 680f66f451Sopenharmony_ci if (!TT.shown_header) { 690f66f451Sopenharmony_ci // TODO: llist_traverse to measure the columns first. 700f66f451Sopenharmony_ci printf("%-9s %5s %10.10s %4s %7s %18s %9s %10s %s\n", "COMMAND", "PID", 710f66f451Sopenharmony_ci "USER", "FD", "TYPE", "DEVICE", "SIZE/OFF", "NODE", "NAME"); 720f66f451Sopenharmony_ci TT.shown_header = 1; 730f66f451Sopenharmony_ci } 740f66f451Sopenharmony_ci 750f66f451Sopenharmony_ci printf("%-9s %5d %10.10s %4s%c%c %7s %18s %9s %10s %s\n", 760f66f451Sopenharmony_ci fi->pi.cmd, fi->pi.pid, getusername(fi->pi.uid), 770f66f451Sopenharmony_ci fi->fd, fi->rw, fi->locks, fi->type, fi->device, fi->size_off, 780f66f451Sopenharmony_ci fi->node, fi->name); 790f66f451Sopenharmony_ci } 800f66f451Sopenharmony_ci} 810f66f451Sopenharmony_ci 820f66f451Sopenharmony_cistatic void free_info(void *data) 830f66f451Sopenharmony_ci{ 840f66f451Sopenharmony_ci free(((struct file_info *)data)->name); 850f66f451Sopenharmony_ci free(data); 860f66f451Sopenharmony_ci} 870f66f451Sopenharmony_ci 880f66f451Sopenharmony_cistatic void fill_flags(struct file_info *fi) 890f66f451Sopenharmony_ci{ 900f66f451Sopenharmony_ci FILE* fp; 910f66f451Sopenharmony_ci long long pos; 920f66f451Sopenharmony_ci unsigned flags; 930f66f451Sopenharmony_ci 940f66f451Sopenharmony_ci snprintf(toybuf, sizeof(toybuf), "/proc/%d/fdinfo/%s", fi->pi.pid, fi->fd); 950f66f451Sopenharmony_ci fp = fopen(toybuf, "r"); 960f66f451Sopenharmony_ci if (!fp) return; 970f66f451Sopenharmony_ci 980f66f451Sopenharmony_ci if (fscanf(fp, "pos: %lld flags: %o", &pos, &flags) == 2) { 990f66f451Sopenharmony_ci flags &= O_ACCMODE; 1000f66f451Sopenharmony_ci if (flags == O_RDONLY) fi->rw = 'r'; 1010f66f451Sopenharmony_ci else if (flags == O_WRONLY) fi->rw = 'w'; 1020f66f451Sopenharmony_ci else fi->rw = 'u'; 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_ci snprintf(fi->size_off, sizeof(fi->size_off), "0t%lld", pos); 1050f66f451Sopenharmony_ci } 1060f66f451Sopenharmony_ci fclose(fp); 1070f66f451Sopenharmony_ci} 1080f66f451Sopenharmony_ci 1090f66f451Sopenharmony_cistatic void scan_proc_net_file(char *path, int family, char type, 1100f66f451Sopenharmony_ci void (*fn)(char *, int, char)) 1110f66f451Sopenharmony_ci{ 1120f66f451Sopenharmony_ci FILE *fp = fopen(path, "r"); 1130f66f451Sopenharmony_ci char *line = NULL; 1140f66f451Sopenharmony_ci size_t line_length = 0; 1150f66f451Sopenharmony_ci 1160f66f451Sopenharmony_ci if (!fp) return; 1170f66f451Sopenharmony_ci 1180f66f451Sopenharmony_ci if (getline(&line, &line_length, fp) <= 0) return; // Skip header. 1190f66f451Sopenharmony_ci 1200f66f451Sopenharmony_ci while (getline(&line, &line_length, fp) > 0) { 1210f66f451Sopenharmony_ci fn(line, family, type); 1220f66f451Sopenharmony_ci } 1230f66f451Sopenharmony_ci 1240f66f451Sopenharmony_ci free(line); 1250f66f451Sopenharmony_ci fclose(fp); 1260f66f451Sopenharmony_ci} 1270f66f451Sopenharmony_ci 1280f66f451Sopenharmony_cistatic struct file_info *add_socket(ino_t inode, const char *type) 1290f66f451Sopenharmony_ci{ 1300f66f451Sopenharmony_ci struct file_info *fi = xzalloc(sizeof(struct file_info)); 1310f66f451Sopenharmony_ci 1320f66f451Sopenharmony_ci dlist_add_nomalloc(&TT.all_sockets, (struct double_list *)fi); 1330f66f451Sopenharmony_ci fi->st_ino = inode; 1340f66f451Sopenharmony_ci strcpy(fi->type, type); 1350f66f451Sopenharmony_ci return fi; 1360f66f451Sopenharmony_ci} 1370f66f451Sopenharmony_ci 1380f66f451Sopenharmony_cistatic void scan_unix(char *line, int af, char type) 1390f66f451Sopenharmony_ci{ 1400f66f451Sopenharmony_ci long inode; 1410f66f451Sopenharmony_ci int path_pos; 1420f66f451Sopenharmony_ci 1430f66f451Sopenharmony_ci if (sscanf(line, "%*p: %*X %*X %*X %*X %*X %lu %n", &inode, &path_pos) >= 1) { 1440f66f451Sopenharmony_ci struct file_info *fi = add_socket(inode, "unix"); 1450f66f451Sopenharmony_ci char *name = chomp(line + path_pos); 1460f66f451Sopenharmony_ci 1470f66f451Sopenharmony_ci fi->name = strdup(*name ? name : "socket"); 1480f66f451Sopenharmony_ci } 1490f66f451Sopenharmony_ci} 1500f66f451Sopenharmony_ci 1510f66f451Sopenharmony_cistatic void scan_netlink(char *line, int af, char type) 1520f66f451Sopenharmony_ci{ 1530f66f451Sopenharmony_ci unsigned state; 1540f66f451Sopenharmony_ci long inode; 1550f66f451Sopenharmony_ci char *netlink_states[] = { 1560f66f451Sopenharmony_ci "ROUTE", "UNUSED", "USERSOCK", "FIREWALL", "SOCK_DIAG", "NFLOG", "XFRM", 1570f66f451Sopenharmony_ci "SELINUX", "ISCSI", "AUDIT", "FIB_LOOKUP", "CONNECTOR", "NETFILTER", 1580f66f451Sopenharmony_ci "IP6_FW", "DNRTMSG", "KOBJECT_UEVENT", "GENERIC", "DM", "SCSITRANSPORT", 1590f66f451Sopenharmony_ci "ENCRYPTFS", "RDMA", "CRYPTO" 1600f66f451Sopenharmony_ci }; 1610f66f451Sopenharmony_ci 1620f66f451Sopenharmony_ci if (sscanf(line, "%*p %u %*u %*x %*u %*u %*u %*u %*u %lu", &state, &inode)<2) 1630f66f451Sopenharmony_ci return; 1640f66f451Sopenharmony_ci 1650f66f451Sopenharmony_ci struct file_info *fi = add_socket(inode, "netlink"); 1660f66f451Sopenharmony_ci fi->name = 1670f66f451Sopenharmony_ci strdup(state < ARRAY_LEN(netlink_states) ? netlink_states[state] : "?"); 1680f66f451Sopenharmony_ci} 1690f66f451Sopenharmony_ci 1700f66f451Sopenharmony_cistatic void scan_ip(char *line, int af, char type) 1710f66f451Sopenharmony_ci{ 1720f66f451Sopenharmony_ci char *tcp_states[] = { 1730f66f451Sopenharmony_ci "UNKNOWN", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2", 1740f66f451Sopenharmony_ci "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN", "CLOSING" 1750f66f451Sopenharmony_ci }; 1760f66f451Sopenharmony_ci char local_ip[INET6_ADDRSTRLEN] = {0}; 1770f66f451Sopenharmony_ci char remote_ip[INET6_ADDRSTRLEN] = {0}; 1780f66f451Sopenharmony_ci struct in6_addr local, remote; 1790f66f451Sopenharmony_ci int local_port, remote_port, state; 1800f66f451Sopenharmony_ci long inode; 1810f66f451Sopenharmony_ci int ok; 1820f66f451Sopenharmony_ci 1830f66f451Sopenharmony_ci if (af == 4) { 1840f66f451Sopenharmony_ci ok = sscanf(line, " %*d: %x:%x %x:%x %x %*x:%*x %*X:%*X %*X %*d %*d %ld", 1850f66f451Sopenharmony_ci &(local.s6_addr32[0]), &local_port, 1860f66f451Sopenharmony_ci &(remote.s6_addr32[0]), &remote_port, 1870f66f451Sopenharmony_ci &state, &inode) == 6; 1880f66f451Sopenharmony_ci } else { 1890f66f451Sopenharmony_ci ok = sscanf(line, " %*d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x " 1900f66f451Sopenharmony_ci "%*x:%*x %*X:%*X %*X %*d %*d %ld", 1910f66f451Sopenharmony_ci &(local.s6_addr32[0]), &(local.s6_addr32[1]), 1920f66f451Sopenharmony_ci &(local.s6_addr32[2]), &(local.s6_addr32[3]), 1930f66f451Sopenharmony_ci &local_port, 1940f66f451Sopenharmony_ci &(remote.s6_addr32[0]), &(remote.s6_addr32[1]), 1950f66f451Sopenharmony_ci &(remote.s6_addr32[2]), &(remote.s6_addr32[3]), 1960f66f451Sopenharmony_ci &remote_port, &state, &inode) == 12; 1970f66f451Sopenharmony_ci } 1980f66f451Sopenharmony_ci if (!ok) return; 1990f66f451Sopenharmony_ci 2000f66f451Sopenharmony_ci struct file_info *fi = add_socket(inode, af == 4 ? "IPv4" : "IPv6"); 2010f66f451Sopenharmony_ci inet_ntop(af, &local, local_ip, sizeof(local_ip)); 2020f66f451Sopenharmony_ci inet_ntop(af, &remote, remote_ip, sizeof(remote_ip)); 2030f66f451Sopenharmony_ci if (type == 't') { 2040f66f451Sopenharmony_ci if (state < 0 || state > TCP_CLOSING) state = 0; 2050f66f451Sopenharmony_ci fi->name = xmprintf(af == 4 ? 2060f66f451Sopenharmony_ci "TCP %s:%d->%s:%d (%s)" : 2070f66f451Sopenharmony_ci "TCP [%s]:%d->[%s]:%d (%s)", 2080f66f451Sopenharmony_ci local_ip, local_port, remote_ip, remote_port, 2090f66f451Sopenharmony_ci tcp_states[state]); 2100f66f451Sopenharmony_ci } else { 2110f66f451Sopenharmony_ci fi->name = xmprintf(af == 4 ? "%s %s:%d->%s:%d" : "%s [%s]:%d->[%s]:%d", 2120f66f451Sopenharmony_ci type == 'u' ? "UDP" : "RAW", 2130f66f451Sopenharmony_ci local_ip, local_port, remote_ip, remote_port); 2140f66f451Sopenharmony_ci } 2150f66f451Sopenharmony_ci} 2160f66f451Sopenharmony_ci 2170f66f451Sopenharmony_cistatic int find_socket(struct file_info *fi, long inode) 2180f66f451Sopenharmony_ci{ 2190f66f451Sopenharmony_ci static int cached; 2200f66f451Sopenharmony_ci if (!cached) { 2210f66f451Sopenharmony_ci scan_proc_net_file("/proc/net/tcp", 4, 't', scan_ip); 2220f66f451Sopenharmony_ci scan_proc_net_file("/proc/net/tcp6", 6, 't', scan_ip); 2230f66f451Sopenharmony_ci scan_proc_net_file("/proc/net/udp", 4, 'u', scan_ip); 2240f66f451Sopenharmony_ci scan_proc_net_file("/proc/net/udp6", 6, 'u', scan_ip); 2250f66f451Sopenharmony_ci scan_proc_net_file("/proc/net/raw", 4, 'r', scan_ip); 2260f66f451Sopenharmony_ci scan_proc_net_file("/proc/net/raw6", 6, 'r', scan_ip); 2270f66f451Sopenharmony_ci scan_proc_net_file("/proc/net/unix", 0, 0, scan_unix); 2280f66f451Sopenharmony_ci scan_proc_net_file("/proc/net/netlink", 0, 0, scan_netlink); 2290f66f451Sopenharmony_ci cached = 1; 2300f66f451Sopenharmony_ci } 2310f66f451Sopenharmony_ci void* list = TT.all_sockets; 2320f66f451Sopenharmony_ci 2330f66f451Sopenharmony_ci while (list) { 2340f66f451Sopenharmony_ci struct file_info *s = (struct file_info*) llist_pop(&list); 2350f66f451Sopenharmony_ci 2360f66f451Sopenharmony_ci if (s->st_ino == inode) { 2370f66f451Sopenharmony_ci fi->name = s->name ? strdup(s->name) : NULL; 2380f66f451Sopenharmony_ci strcpy(fi->type, s->type); 2390f66f451Sopenharmony_ci return 1; 2400f66f451Sopenharmony_ci } 2410f66f451Sopenharmony_ci if (list == TT.all_sockets) break; 2420f66f451Sopenharmony_ci } 2430f66f451Sopenharmony_ci 2440f66f451Sopenharmony_ci return 0; 2450f66f451Sopenharmony_ci} 2460f66f451Sopenharmony_ci 2470f66f451Sopenharmony_cistatic void fill_stat(struct file_info *fi, const char *path) 2480f66f451Sopenharmony_ci{ 2490f66f451Sopenharmony_ci struct stat sb; 2500f66f451Sopenharmony_ci long dev; 2510f66f451Sopenharmony_ci 2520f66f451Sopenharmony_ci if (stat(path, &sb)) return; 2530f66f451Sopenharmony_ci 2540f66f451Sopenharmony_ci // Fill TYPE. 2550f66f451Sopenharmony_ci switch ((sb.st_mode & S_IFMT)) { 2560f66f451Sopenharmony_ci case S_IFBLK: strcpy(fi->type, "BLK"); break; 2570f66f451Sopenharmony_ci case S_IFCHR: strcpy(fi->type, "CHR"); break; 2580f66f451Sopenharmony_ci case S_IFDIR: strcpy(fi->type, "DIR"); break; 2590f66f451Sopenharmony_ci case S_IFIFO: strcpy(fi->type, "FIFO"); break; 2600f66f451Sopenharmony_ci case S_IFLNK: strcpy(fi->type, "LINK"); break; 2610f66f451Sopenharmony_ci case S_IFREG: strcpy(fi->type, "REG"); break; 2620f66f451Sopenharmony_ci case S_IFSOCK: strcpy(fi->type, "sock"); break; 2630f66f451Sopenharmony_ci default: 2640f66f451Sopenharmony_ci snprintf(fi->type, sizeof(fi->type), "%04o", sb.st_mode & S_IFMT); 2650f66f451Sopenharmony_ci break; 2660f66f451Sopenharmony_ci } 2670f66f451Sopenharmony_ci 2680f66f451Sopenharmony_ci if (S_ISSOCK(sb.st_mode)) find_socket(fi, sb.st_ino); 2690f66f451Sopenharmony_ci 2700f66f451Sopenharmony_ci // Fill DEVICE. 2710f66f451Sopenharmony_ci dev = (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) ? sb.st_rdev : sb.st_dev; 2720f66f451Sopenharmony_ci if (!S_ISSOCK(sb.st_mode)) 2730f66f451Sopenharmony_ci snprintf(fi->device, sizeof(fi->device), "%d,%d", 2740f66f451Sopenharmony_ci dev_major(dev), dev_minor(dev)); 2750f66f451Sopenharmony_ci 2760f66f451Sopenharmony_ci // Fill SIZE/OFF. 2770f66f451Sopenharmony_ci if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode)) 2780f66f451Sopenharmony_ci snprintf(fi->size_off, sizeof(fi->size_off), "%lld", 2790f66f451Sopenharmony_ci (long long)sb.st_size); 2800f66f451Sopenharmony_ci 2810f66f451Sopenharmony_ci // Fill NODE. 2820f66f451Sopenharmony_ci snprintf(fi->node, sizeof(fi->node), "%ld", (long)sb.st_ino); 2830f66f451Sopenharmony_ci 2840f66f451Sopenharmony_ci // Stash st_dev and st_ino for filtering. 2850f66f451Sopenharmony_ci fi->st_dev = sb.st_dev; 2860f66f451Sopenharmony_ci fi->st_ino = sb.st_ino; 2870f66f451Sopenharmony_ci} 2880f66f451Sopenharmony_ci 2890f66f451Sopenharmony_cistruct file_info *new_file_info(struct proc_info *pi, const char *fd) 2900f66f451Sopenharmony_ci{ 2910f66f451Sopenharmony_ci struct file_info *fi = xzalloc(sizeof(struct file_info)); 2920f66f451Sopenharmony_ci 2930f66f451Sopenharmony_ci dlist_add_nomalloc(&TT.files, (struct double_list *)fi); 2940f66f451Sopenharmony_ci 2950f66f451Sopenharmony_ci fi->pi = *pi; 2960f66f451Sopenharmony_ci 2970f66f451Sopenharmony_ci // Defaults. 2980f66f451Sopenharmony_ci strcpy(fi->fd, fd); 2990f66f451Sopenharmony_ci strcpy(fi->type, "unknown"); 3000f66f451Sopenharmony_ci fi->rw = fi->locks = ' '; 3010f66f451Sopenharmony_ci 3020f66f451Sopenharmony_ci return fi; 3030f66f451Sopenharmony_ci} 3040f66f451Sopenharmony_ci 3050f66f451Sopenharmony_cistatic void visit_symlink(struct proc_info *pi, char *name, char *path) 3060f66f451Sopenharmony_ci{ 3070f66f451Sopenharmony_ci struct file_info *fi = new_file_info(pi, ""); 3080f66f451Sopenharmony_ci 3090f66f451Sopenharmony_ci // Get NAME. 3100f66f451Sopenharmony_ci if (name) { // "/proc/pid/[cwd]". 3110f66f451Sopenharmony_ci snprintf(fi->fd, sizeof(fi->fd), "%s", name); 3120f66f451Sopenharmony_ci snprintf(toybuf, sizeof(toybuf), "/proc/%d/%s", pi->pid, path); 3130f66f451Sopenharmony_ci } else { // "/proc/pid/fd/[3]" 3140f66f451Sopenharmony_ci snprintf(fi->fd, sizeof(fi->fd), "%s", path); 3150f66f451Sopenharmony_ci fill_flags(fi); // Clobbers toybuf. 3160f66f451Sopenharmony_ci snprintf(toybuf, sizeof(toybuf), "/proc/%d/fd/%s", pi->pid, path); 3170f66f451Sopenharmony_ci } 3180f66f451Sopenharmony_ci // TODO: code called by fill_stat would be easier to write if we didn't 3190f66f451Sopenharmony_ci // rely on toybuf being preserved here. 3200f66f451Sopenharmony_ci fill_stat(fi, toybuf); 3210f66f451Sopenharmony_ci if (!fi->name) { // We already have a name for things like sockets. 3220f66f451Sopenharmony_ci fi->name = xreadlink(toybuf); 3230f66f451Sopenharmony_ci if (!fi->name) { 3240f66f451Sopenharmony_ci fi->name = xmprintf("%s (readlink: %s)", toybuf, strerror(errno)); 3250f66f451Sopenharmony_ci } 3260f66f451Sopenharmony_ci } 3270f66f451Sopenharmony_ci} 3280f66f451Sopenharmony_ci 3290f66f451Sopenharmony_cistatic void visit_maps(struct proc_info *pi) 3300f66f451Sopenharmony_ci{ 3310f66f451Sopenharmony_ci FILE *fp; 3320f66f451Sopenharmony_ci unsigned long long offset; 3330f66f451Sopenharmony_ci long inode; 3340f66f451Sopenharmony_ci char *line = NULL, device[10]; // xxx:xxxxx\0 3350f66f451Sopenharmony_ci size_t line_length = 0; 3360f66f451Sopenharmony_ci struct file_info *fi; 3370f66f451Sopenharmony_ci 3380f66f451Sopenharmony_ci snprintf(toybuf, sizeof(toybuf), "/proc/%d/maps", pi->pid); 3390f66f451Sopenharmony_ci fp = fopen(toybuf, "r"); 3400f66f451Sopenharmony_ci if (!fp) return; 3410f66f451Sopenharmony_ci 3420f66f451Sopenharmony_ci while (getline(&line, &line_length, fp) > 0) { 3430f66f451Sopenharmony_ci int name_pos; 3440f66f451Sopenharmony_ci 3450f66f451Sopenharmony_ci if (sscanf(line, "%*x-%*x %*s %llx %9s %ld %n", 3460f66f451Sopenharmony_ci &offset, device, &inode, &name_pos) >= 3) { 3470f66f451Sopenharmony_ci // Ignore non-file maps. 3480f66f451Sopenharmony_ci if (inode == 0 || !strcmp(device, "00:00")) continue; 3490f66f451Sopenharmony_ci // TODO: show unique maps even if they have a non-zero offset? 3500f66f451Sopenharmony_ci if (offset != 0) continue; 3510f66f451Sopenharmony_ci 3520f66f451Sopenharmony_ci fi = new_file_info(pi, "mem"); 3530f66f451Sopenharmony_ci fi->name = strdup(chomp(line + name_pos)); 3540f66f451Sopenharmony_ci fill_stat(fi, fi->name); 3550f66f451Sopenharmony_ci } 3560f66f451Sopenharmony_ci } 3570f66f451Sopenharmony_ci free(line); 3580f66f451Sopenharmony_ci fclose(fp); 3590f66f451Sopenharmony_ci} 3600f66f451Sopenharmony_ci 3610f66f451Sopenharmony_cistatic void visit_fds(struct proc_info *pi) 3620f66f451Sopenharmony_ci{ 3630f66f451Sopenharmony_ci DIR *dir; 3640f66f451Sopenharmony_ci struct dirent *de; 3650f66f451Sopenharmony_ci 3660f66f451Sopenharmony_ci snprintf(toybuf, sizeof(toybuf), "/proc/%d/fd", pi->pid); 3670f66f451Sopenharmony_ci if (!(dir = opendir(toybuf))) { 3680f66f451Sopenharmony_ci struct file_info *fi = new_file_info(pi, "NOFD"); 3690f66f451Sopenharmony_ci 3700f66f451Sopenharmony_ci fi->name = xmprintf("%s (opendir: %s)", toybuf, strerror(errno)); 3710f66f451Sopenharmony_ci return; 3720f66f451Sopenharmony_ci } 3730f66f451Sopenharmony_ci 3740f66f451Sopenharmony_ci while ((de = readdir(dir))) { 3750f66f451Sopenharmony_ci if (*de->d_name == '.') continue; 3760f66f451Sopenharmony_ci visit_symlink(pi, NULL, de->d_name); 3770f66f451Sopenharmony_ci } 3780f66f451Sopenharmony_ci 3790f66f451Sopenharmony_ci closedir(dir); 3800f66f451Sopenharmony_ci} 3810f66f451Sopenharmony_ci 3820f66f451Sopenharmony_cistatic void lsof_pid(int pid, struct stat *st) 3830f66f451Sopenharmony_ci{ 3840f66f451Sopenharmony_ci struct proc_info pi; 3850f66f451Sopenharmony_ci struct stat sb; 3860f66f451Sopenharmony_ci char *s; 3870f66f451Sopenharmony_ci 3880f66f451Sopenharmony_ci pi.pid = pid; 3890f66f451Sopenharmony_ci 3900f66f451Sopenharmony_ci // Skip nonexistent pids 3910f66f451Sopenharmony_ci sprintf(toybuf, "/proc/%d/stat", pid); 3920f66f451Sopenharmony_ci if (!readfile(toybuf, toybuf, sizeof(toybuf)-1) || !(s = strchr(toybuf, '('))) 3930f66f451Sopenharmony_ci return; 3940f66f451Sopenharmony_ci memcpy(pi.cmd, s+1, sizeof(pi.cmd)-1); 3950f66f451Sopenharmony_ci pi.cmd[sizeof(pi.cmd)-1] = 0; 3960f66f451Sopenharmony_ci if ((s = strrchr(pi.cmd, ')'))) *s = 0; 3970f66f451Sopenharmony_ci 3980f66f451Sopenharmony_ci // Get USER. 3990f66f451Sopenharmony_ci if (!st) { 4000f66f451Sopenharmony_ci snprintf(toybuf, sizeof(toybuf), "/proc/%d", pid); 4010f66f451Sopenharmony_ci if (stat(toybuf, st = &sb)) return; 4020f66f451Sopenharmony_ci } 4030f66f451Sopenharmony_ci pi.uid = st->st_uid; 4040f66f451Sopenharmony_ci 4050f66f451Sopenharmony_ci visit_symlink(&pi, "cwd", "cwd"); 4060f66f451Sopenharmony_ci visit_symlink(&pi, "rtd", "root"); 4070f66f451Sopenharmony_ci visit_symlink(&pi, "txt", "exe"); 4080f66f451Sopenharmony_ci visit_maps(&pi); 4090f66f451Sopenharmony_ci visit_fds(&pi); 4100f66f451Sopenharmony_ci} 4110f66f451Sopenharmony_ci 4120f66f451Sopenharmony_cistatic int scan_proc(struct dirtree *node) 4130f66f451Sopenharmony_ci{ 4140f66f451Sopenharmony_ci int pid; 4150f66f451Sopenharmony_ci 4160f66f451Sopenharmony_ci if (!node->parent) return DIRTREE_RECURSE|DIRTREE_SHUTUP; 4170f66f451Sopenharmony_ci if ((pid = atol(node->name))) lsof_pid(pid, &node->st); 4180f66f451Sopenharmony_ci 4190f66f451Sopenharmony_ci return 0; 4200f66f451Sopenharmony_ci} 4210f66f451Sopenharmony_ci 4220f66f451Sopenharmony_civoid lsof_main(void) 4230f66f451Sopenharmony_ci{ 4240f66f451Sopenharmony_ci struct arg_list *pp; 4250f66f451Sopenharmony_ci int i, pid; 4260f66f451Sopenharmony_ci 4270f66f451Sopenharmony_ci // lsof will only filter on paths it can stat (because it filters by inode). 4280f66f451Sopenharmony_ci if (toys.optc) { 4290f66f451Sopenharmony_ci TT.sought_files = xmalloc(toys.optc*sizeof(struct stat)); 4300f66f451Sopenharmony_ci for (i = 0; i<toys.optc; ++i) xstat(toys.optargs[i], TT.sought_files+i); 4310f66f451Sopenharmony_ci } 4320f66f451Sopenharmony_ci 4330f66f451Sopenharmony_ci if (!TT.p) dirtree_read("/proc", scan_proc); 4340f66f451Sopenharmony_ci else for (pp = TT.p; pp; pp = pp->next) { 4350f66f451Sopenharmony_ci char *start, *end, *next = pp->arg; 4360f66f451Sopenharmony_ci 4370f66f451Sopenharmony_ci while ((start = comma_iterate(&next, &i))) { 4380f66f451Sopenharmony_ci if ((pid = strtol(start, &end, 10))<1 || (*end && *end!=',')) 4390f66f451Sopenharmony_ci error_msg("bad -p '%.*s'", (int)(end-start), start); 4400f66f451Sopenharmony_ci lsof_pid(pid, 0); 4410f66f451Sopenharmony_ci } 4420f66f451Sopenharmony_ci } 4430f66f451Sopenharmony_ci 4440f66f451Sopenharmony_ci llist_traverse(TT.files, print_info); 4450f66f451Sopenharmony_ci 4460f66f451Sopenharmony_ci if (CFG_TOYBOX_FREE) { 4470f66f451Sopenharmony_ci llist_traverse(TT.files, free_info); 4480f66f451Sopenharmony_ci llist_traverse(TT.all_sockets, free_info); 4490f66f451Sopenharmony_ci } 4500f66f451Sopenharmony_ci} 451