1*cf5a6c84SAndroid Build Coastguard Worker /* lsof.c - list open files.
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2015 The Android Open Source Project
4*cf5a6c84SAndroid Build Coastguard Worker
5*cf5a6c84SAndroid Build Coastguard Worker USE_LSOF(NEWTOY(lsof, "lp*t", TOYFLAG_USR|TOYFLAG_BIN))
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker config LSOF
8*cf5a6c84SAndroid Build Coastguard Worker bool "lsof"
9*cf5a6c84SAndroid Build Coastguard Worker default n
10*cf5a6c84SAndroid Build Coastguard Worker help
11*cf5a6c84SAndroid Build Coastguard Worker usage: lsof [-lt] [-p PID1,PID2,...] [FILE...]
12*cf5a6c84SAndroid Build Coastguard Worker
13*cf5a6c84SAndroid Build Coastguard Worker List all open files belonging to all active processes, or processes using
14*cf5a6c84SAndroid Build Coastguard Worker listed FILE(s).
15*cf5a6c84SAndroid Build Coastguard Worker
16*cf5a6c84SAndroid Build Coastguard Worker -l list uids numerically
17*cf5a6c84SAndroid Build Coastguard Worker -p for given comma-separated pids only (default all pids)
18*cf5a6c84SAndroid Build Coastguard Worker -t terse (pid only) output
19*cf5a6c84SAndroid Build Coastguard Worker */
20*cf5a6c84SAndroid Build Coastguard Worker
21*cf5a6c84SAndroid Build Coastguard Worker #define FOR_lsof
22*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
23*cf5a6c84SAndroid Build Coastguard Worker
24*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
25*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *p;
26*cf5a6c84SAndroid Build Coastguard Worker
27*cf5a6c84SAndroid Build Coastguard Worker struct stat *sought_files;
28*cf5a6c84SAndroid Build Coastguard Worker struct double_list *all_sockets, *files;
29*cf5a6c84SAndroid Build Coastguard Worker int last_shown_pid, shown_header;
30*cf5a6c84SAndroid Build Coastguard Worker )
31*cf5a6c84SAndroid Build Coastguard Worker
32*cf5a6c84SAndroid Build Coastguard Worker struct proc_info {
33*cf5a6c84SAndroid Build Coastguard Worker char cmd[17];
34*cf5a6c84SAndroid Build Coastguard Worker int pid, uid;
35*cf5a6c84SAndroid Build Coastguard Worker };
36*cf5a6c84SAndroid Build Coastguard Worker
37*cf5a6c84SAndroid Build Coastguard Worker struct file_info {
38*cf5a6c84SAndroid Build Coastguard Worker char *next, *prev;
39*cf5a6c84SAndroid Build Coastguard Worker
40*cf5a6c84SAndroid Build Coastguard Worker // For output.
41*cf5a6c84SAndroid Build Coastguard Worker struct proc_info pi;
42*cf5a6c84SAndroid Build Coastguard Worker char *name, fd[8], rw, locks, type[10], device[32], size_off[32], node[32];
43*cf5a6c84SAndroid Build Coastguard Worker
44*cf5a6c84SAndroid Build Coastguard Worker // For filtering.
45*cf5a6c84SAndroid Build Coastguard Worker struct dev_ino di;
46*cf5a6c84SAndroid Build Coastguard Worker };
47*cf5a6c84SAndroid Build Coastguard Worker
print_info(void * data)48*cf5a6c84SAndroid Build Coastguard Worker static void print_info(void *data)
49*cf5a6c84SAndroid Build Coastguard Worker {
50*cf5a6c84SAndroid Build Coastguard Worker struct file_info *fi = data;
51*cf5a6c84SAndroid Build Coastguard Worker
52*cf5a6c84SAndroid Build Coastguard Worker // Filter matches
53*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc) {
54*cf5a6c84SAndroid Build Coastguard Worker int i;
55*cf5a6c84SAndroid Build Coastguard Worker
56*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<toys.optc; i++)
57*cf5a6c84SAndroid Build Coastguard Worker if (same_dev_ino(TT.sought_files+i, &fi->di)) break;
58*cf5a6c84SAndroid Build Coastguard Worker if (i==toys.optc) return;
59*cf5a6c84SAndroid Build Coastguard Worker }
60*cf5a6c84SAndroid Build Coastguard Worker
61*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(t)) {
62*cf5a6c84SAndroid Build Coastguard Worker if (fi->pi.pid != TT.last_shown_pid)
63*cf5a6c84SAndroid Build Coastguard Worker printf("%d\n", TT.last_shown_pid = fi->pi.pid);
64*cf5a6c84SAndroid Build Coastguard Worker } else {
65*cf5a6c84SAndroid Build Coastguard Worker if (!TT.shown_header) {
66*cf5a6c84SAndroid Build Coastguard Worker // TODO: llist_traverse to measure the columns first.
67*cf5a6c84SAndroid Build Coastguard Worker printf("%-9s %5s %10.10s %4s %7s %18s %9s %10s %s\n", "COMMAND", "PID",
68*cf5a6c84SAndroid Build Coastguard Worker "USER", "FD", "TYPE", "DEVICE", "SIZE/OFF", "NODE", "NAME");
69*cf5a6c84SAndroid Build Coastguard Worker TT.shown_header = 1;
70*cf5a6c84SAndroid Build Coastguard Worker }
71*cf5a6c84SAndroid Build Coastguard Worker
72*cf5a6c84SAndroid Build Coastguard Worker printf("%-9s %5d %10.10s %4s%c%c %7s %18s %9s %10s %s\n",
73*cf5a6c84SAndroid Build Coastguard Worker fi->pi.cmd, fi->pi.pid, getusername(fi->pi.uid),
74*cf5a6c84SAndroid Build Coastguard Worker fi->fd, fi->rw, fi->locks, fi->type, fi->device, fi->size_off,
75*cf5a6c84SAndroid Build Coastguard Worker fi->node, fi->name);
76*cf5a6c84SAndroid Build Coastguard Worker }
77*cf5a6c84SAndroid Build Coastguard Worker }
78*cf5a6c84SAndroid Build Coastguard Worker
free_info(void * data)79*cf5a6c84SAndroid Build Coastguard Worker static void free_info(void *data)
80*cf5a6c84SAndroid Build Coastguard Worker {
81*cf5a6c84SAndroid Build Coastguard Worker free(((struct file_info *)data)->name);
82*cf5a6c84SAndroid Build Coastguard Worker free(data);
83*cf5a6c84SAndroid Build Coastguard Worker }
84*cf5a6c84SAndroid Build Coastguard Worker
fill_flags(struct file_info * fi)85*cf5a6c84SAndroid Build Coastguard Worker static void fill_flags(struct file_info *fi)
86*cf5a6c84SAndroid Build Coastguard Worker {
87*cf5a6c84SAndroid Build Coastguard Worker FILE* fp;
88*cf5a6c84SAndroid Build Coastguard Worker long long pos;
89*cf5a6c84SAndroid Build Coastguard Worker unsigned flags;
90*cf5a6c84SAndroid Build Coastguard Worker
91*cf5a6c84SAndroid Build Coastguard Worker snprintf(toybuf, sizeof(toybuf), "/proc/%d/fdinfo/%s", fi->pi.pid, fi->fd);
92*cf5a6c84SAndroid Build Coastguard Worker if (!(fp = fopen(toybuf, "r"))) return;
93*cf5a6c84SAndroid Build Coastguard Worker
94*cf5a6c84SAndroid Build Coastguard Worker if (fscanf(fp, "pos: %lld flags: %o", &pos, &flags) == 2) {
95*cf5a6c84SAndroid Build Coastguard Worker flags &= O_ACCMODE;
96*cf5a6c84SAndroid Build Coastguard Worker if (flags == O_RDONLY) fi->rw = 'r';
97*cf5a6c84SAndroid Build Coastguard Worker else if (flags == O_WRONLY) fi->rw = 'w';
98*cf5a6c84SAndroid Build Coastguard Worker else fi->rw = 'u';
99*cf5a6c84SAndroid Build Coastguard Worker
100*cf5a6c84SAndroid Build Coastguard Worker snprintf(fi->size_off, sizeof(fi->size_off), "0t%lld", pos);
101*cf5a6c84SAndroid Build Coastguard Worker }
102*cf5a6c84SAndroid Build Coastguard Worker fclose(fp);
103*cf5a6c84SAndroid Build Coastguard Worker }
104*cf5a6c84SAndroid Build Coastguard Worker
scan_proc_net_file(char * path,int family,char type,void (* fn)(char *,int,char))105*cf5a6c84SAndroid Build Coastguard Worker static void scan_proc_net_file(char *path, int family, char type,
106*cf5a6c84SAndroid Build Coastguard Worker void (*fn)(char *, int, char))
107*cf5a6c84SAndroid Build Coastguard Worker {
108*cf5a6c84SAndroid Build Coastguard Worker FILE *fp = fopen(path, "r");
109*cf5a6c84SAndroid Build Coastguard Worker char *line = NULL;
110*cf5a6c84SAndroid Build Coastguard Worker size_t line_length = 0;
111*cf5a6c84SAndroid Build Coastguard Worker
112*cf5a6c84SAndroid Build Coastguard Worker if (!fp) return;
113*cf5a6c84SAndroid Build Coastguard Worker
114*cf5a6c84SAndroid Build Coastguard Worker if (getline(&line, &line_length, fp) <= 0) return; // Skip header.
115*cf5a6c84SAndroid Build Coastguard Worker
116*cf5a6c84SAndroid Build Coastguard Worker while (getline(&line, &line_length, fp) > 0) {
117*cf5a6c84SAndroid Build Coastguard Worker fn(line, family, type);
118*cf5a6c84SAndroid Build Coastguard Worker }
119*cf5a6c84SAndroid Build Coastguard Worker
120*cf5a6c84SAndroid Build Coastguard Worker free(line);
121*cf5a6c84SAndroid Build Coastguard Worker fclose(fp);
122*cf5a6c84SAndroid Build Coastguard Worker }
123*cf5a6c84SAndroid Build Coastguard Worker
add_socket(ino_t inode,const char * type)124*cf5a6c84SAndroid Build Coastguard Worker static struct file_info *add_socket(ino_t inode, const char *type)
125*cf5a6c84SAndroid Build Coastguard Worker {
126*cf5a6c84SAndroid Build Coastguard Worker struct file_info *fi = xzalloc(sizeof(struct file_info));
127*cf5a6c84SAndroid Build Coastguard Worker
128*cf5a6c84SAndroid Build Coastguard Worker dlist_add_nomalloc(&TT.all_sockets, (struct double_list *)fi);
129*cf5a6c84SAndroid Build Coastguard Worker fi->di.ino = inode;
130*cf5a6c84SAndroid Build Coastguard Worker strcpy(fi->type, type);
131*cf5a6c84SAndroid Build Coastguard Worker return fi;
132*cf5a6c84SAndroid Build Coastguard Worker }
133*cf5a6c84SAndroid Build Coastguard Worker
scan_unix(char * line,int af,char type)134*cf5a6c84SAndroid Build Coastguard Worker static void scan_unix(char *line, int af, char type)
135*cf5a6c84SAndroid Build Coastguard Worker {
136*cf5a6c84SAndroid Build Coastguard Worker long inode;
137*cf5a6c84SAndroid Build Coastguard Worker int path_pos;
138*cf5a6c84SAndroid Build Coastguard Worker
139*cf5a6c84SAndroid Build Coastguard Worker if (sscanf(line, "%*p: %*X %*X %*X %*X %*X %lu %n", &inode, &path_pos) >= 1) {
140*cf5a6c84SAndroid Build Coastguard Worker struct file_info *fi = add_socket(inode, "unix");
141*cf5a6c84SAndroid Build Coastguard Worker char *name = chomp(line + path_pos);
142*cf5a6c84SAndroid Build Coastguard Worker
143*cf5a6c84SAndroid Build Coastguard Worker fi->name = strdup(*name ? name : "socket");
144*cf5a6c84SAndroid Build Coastguard Worker }
145*cf5a6c84SAndroid Build Coastguard Worker }
146*cf5a6c84SAndroid Build Coastguard Worker
scan_netlink(char * line,int af,char type)147*cf5a6c84SAndroid Build Coastguard Worker static void scan_netlink(char *line, int af, char type)
148*cf5a6c84SAndroid Build Coastguard Worker {
149*cf5a6c84SAndroid Build Coastguard Worker unsigned state;
150*cf5a6c84SAndroid Build Coastguard Worker long inode;
151*cf5a6c84SAndroid Build Coastguard Worker char *netlink_states[] = {
152*cf5a6c84SAndroid Build Coastguard Worker "ROUTE", "UNUSED", "USERSOCK", "FIREWALL", "SOCK_DIAG", "NFLOG", "XFRM",
153*cf5a6c84SAndroid Build Coastguard Worker "SELINUX", "ISCSI", "AUDIT", "FIB_LOOKUP", "CONNECTOR", "NETFILTER",
154*cf5a6c84SAndroid Build Coastguard Worker "IP6_FW", "DNRTMSG", "KOBJECT_UEVENT", "GENERIC", "DM", "SCSITRANSPORT",
155*cf5a6c84SAndroid Build Coastguard Worker "ENCRYPTFS", "RDMA", "CRYPTO"
156*cf5a6c84SAndroid Build Coastguard Worker };
157*cf5a6c84SAndroid Build Coastguard Worker
158*cf5a6c84SAndroid Build Coastguard Worker if (sscanf(line, "%*p %u %*u %*x %*u %*u %*u %*u %*u %lu", &state, &inode)<2)
159*cf5a6c84SAndroid Build Coastguard Worker return;
160*cf5a6c84SAndroid Build Coastguard Worker
161*cf5a6c84SAndroid Build Coastguard Worker struct file_info *fi = add_socket(inode, "netlink");
162*cf5a6c84SAndroid Build Coastguard Worker fi->name =
163*cf5a6c84SAndroid Build Coastguard Worker strdup(state < ARRAY_LEN(netlink_states) ? netlink_states[state] : "?");
164*cf5a6c84SAndroid Build Coastguard Worker }
165*cf5a6c84SAndroid Build Coastguard Worker
scan_ip(char * line,int af,char type)166*cf5a6c84SAndroid Build Coastguard Worker static void scan_ip(char *line, int af, char type)
167*cf5a6c84SAndroid Build Coastguard Worker {
168*cf5a6c84SAndroid Build Coastguard Worker char *tcp_states[] = {
169*cf5a6c84SAndroid Build Coastguard Worker "UNKNOWN", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2",
170*cf5a6c84SAndroid Build Coastguard Worker "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN", "CLOSING"
171*cf5a6c84SAndroid Build Coastguard Worker };
172*cf5a6c84SAndroid Build Coastguard Worker char local_ip[INET6_ADDRSTRLEN] = {0};
173*cf5a6c84SAndroid Build Coastguard Worker char remote_ip[INET6_ADDRSTRLEN] = {0};
174*cf5a6c84SAndroid Build Coastguard Worker struct in6_addr local, remote;
175*cf5a6c84SAndroid Build Coastguard Worker int local_port, remote_port, state;
176*cf5a6c84SAndroid Build Coastguard Worker long inode;
177*cf5a6c84SAndroid Build Coastguard Worker int ok;
178*cf5a6c84SAndroid Build Coastguard Worker
179*cf5a6c84SAndroid Build Coastguard Worker if (af == 4) {
180*cf5a6c84SAndroid Build Coastguard Worker ok = sscanf(line, " %*d: %x:%x %x:%x %x %*x:%*x %*X:%*X %*X %*d %*d %ld",
181*cf5a6c84SAndroid Build Coastguard Worker &(local.s6_addr32[0]), &local_port,
182*cf5a6c84SAndroid Build Coastguard Worker &(remote.s6_addr32[0]), &remote_port,
183*cf5a6c84SAndroid Build Coastguard Worker &state, &inode) == 6;
184*cf5a6c84SAndroid Build Coastguard Worker } else {
185*cf5a6c84SAndroid Build Coastguard Worker ok = sscanf(line, " %*d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x "
186*cf5a6c84SAndroid Build Coastguard Worker "%*x:%*x %*X:%*X %*X %*d %*d %ld",
187*cf5a6c84SAndroid Build Coastguard Worker &(local.s6_addr32[0]), &(local.s6_addr32[1]),
188*cf5a6c84SAndroid Build Coastguard Worker &(local.s6_addr32[2]), &(local.s6_addr32[3]),
189*cf5a6c84SAndroid Build Coastguard Worker &local_port,
190*cf5a6c84SAndroid Build Coastguard Worker &(remote.s6_addr32[0]), &(remote.s6_addr32[1]),
191*cf5a6c84SAndroid Build Coastguard Worker &(remote.s6_addr32[2]), &(remote.s6_addr32[3]),
192*cf5a6c84SAndroid Build Coastguard Worker &remote_port, &state, &inode) == 12;
193*cf5a6c84SAndroid Build Coastguard Worker }
194*cf5a6c84SAndroid Build Coastguard Worker if (!ok) return;
195*cf5a6c84SAndroid Build Coastguard Worker
196*cf5a6c84SAndroid Build Coastguard Worker struct file_info *fi = add_socket(inode, af == 4 ? "IPv4" : "IPv6");
197*cf5a6c84SAndroid Build Coastguard Worker inet_ntop(af, &local, local_ip, sizeof(local_ip));
198*cf5a6c84SAndroid Build Coastguard Worker inet_ntop(af, &remote, remote_ip, sizeof(remote_ip));
199*cf5a6c84SAndroid Build Coastguard Worker if (type == 't') {
200*cf5a6c84SAndroid Build Coastguard Worker if (state < 0 || state > TCP_CLOSING) state = 0;
201*cf5a6c84SAndroid Build Coastguard Worker fi->name = xmprintf(af == 4 ?
202*cf5a6c84SAndroid Build Coastguard Worker "TCP %s:%d->%s:%d (%s)" :
203*cf5a6c84SAndroid Build Coastguard Worker "TCP [%s]:%d->[%s]:%d (%s)",
204*cf5a6c84SAndroid Build Coastguard Worker local_ip, local_port, remote_ip, remote_port,
205*cf5a6c84SAndroid Build Coastguard Worker tcp_states[state]);
206*cf5a6c84SAndroid Build Coastguard Worker } else {
207*cf5a6c84SAndroid Build Coastguard Worker fi->name = xmprintf(af == 4 ? "%s %s:%d->%s:%d" : "%s [%s]:%d->[%s]:%d",
208*cf5a6c84SAndroid Build Coastguard Worker type == 'u' ? "UDP" : "RAW",
209*cf5a6c84SAndroid Build Coastguard Worker local_ip, local_port, remote_ip, remote_port);
210*cf5a6c84SAndroid Build Coastguard Worker }
211*cf5a6c84SAndroid Build Coastguard Worker }
212*cf5a6c84SAndroid Build Coastguard Worker
find_socket(struct file_info * fi,long inode)213*cf5a6c84SAndroid Build Coastguard Worker static int find_socket(struct file_info *fi, long inode)
214*cf5a6c84SAndroid Build Coastguard Worker {
215*cf5a6c84SAndroid Build Coastguard Worker static int cached;
216*cf5a6c84SAndroid Build Coastguard Worker if (!cached) {
217*cf5a6c84SAndroid Build Coastguard Worker scan_proc_net_file("/proc/net/tcp", 4, 't', scan_ip);
218*cf5a6c84SAndroid Build Coastguard Worker scan_proc_net_file("/proc/net/tcp6", 6, 't', scan_ip);
219*cf5a6c84SAndroid Build Coastguard Worker scan_proc_net_file("/proc/net/udp", 4, 'u', scan_ip);
220*cf5a6c84SAndroid Build Coastguard Worker scan_proc_net_file("/proc/net/udp6", 6, 'u', scan_ip);
221*cf5a6c84SAndroid Build Coastguard Worker scan_proc_net_file("/proc/net/raw", 4, 'r', scan_ip);
222*cf5a6c84SAndroid Build Coastguard Worker scan_proc_net_file("/proc/net/raw6", 6, 'r', scan_ip);
223*cf5a6c84SAndroid Build Coastguard Worker scan_proc_net_file("/proc/net/unix", 0, 0, scan_unix);
224*cf5a6c84SAndroid Build Coastguard Worker scan_proc_net_file("/proc/net/netlink", 0, 0, scan_netlink);
225*cf5a6c84SAndroid Build Coastguard Worker cached = 1;
226*cf5a6c84SAndroid Build Coastguard Worker }
227*cf5a6c84SAndroid Build Coastguard Worker void* list = TT.all_sockets;
228*cf5a6c84SAndroid Build Coastguard Worker
229*cf5a6c84SAndroid Build Coastguard Worker while (list) {
230*cf5a6c84SAndroid Build Coastguard Worker struct file_info *s = (struct file_info *)llist_pop(&list);
231*cf5a6c84SAndroid Build Coastguard Worker
232*cf5a6c84SAndroid Build Coastguard Worker if (s->di.ino == inode) {
233*cf5a6c84SAndroid Build Coastguard Worker fi->name = s->name ? strdup(s->name) : NULL;
234*cf5a6c84SAndroid Build Coastguard Worker strcpy(fi->type, s->type);
235*cf5a6c84SAndroid Build Coastguard Worker return 1;
236*cf5a6c84SAndroid Build Coastguard Worker }
237*cf5a6c84SAndroid Build Coastguard Worker if (list == TT.all_sockets) break;
238*cf5a6c84SAndroid Build Coastguard Worker }
239*cf5a6c84SAndroid Build Coastguard Worker
240*cf5a6c84SAndroid Build Coastguard Worker return 0;
241*cf5a6c84SAndroid Build Coastguard Worker }
242*cf5a6c84SAndroid Build Coastguard Worker
fill_stat(struct file_info * fi,const char * path)243*cf5a6c84SAndroid Build Coastguard Worker static void fill_stat(struct file_info *fi, const char *path)
244*cf5a6c84SAndroid Build Coastguard Worker {
245*cf5a6c84SAndroid Build Coastguard Worker struct stat sb;
246*cf5a6c84SAndroid Build Coastguard Worker long dev;
247*cf5a6c84SAndroid Build Coastguard Worker
248*cf5a6c84SAndroid Build Coastguard Worker if (stat(path, &sb)) return;
249*cf5a6c84SAndroid Build Coastguard Worker
250*cf5a6c84SAndroid Build Coastguard Worker // Fill TYPE.
251*cf5a6c84SAndroid Build Coastguard Worker switch ((sb.st_mode & S_IFMT)) {
252*cf5a6c84SAndroid Build Coastguard Worker case S_IFBLK: strcpy(fi->type, "BLK"); break;
253*cf5a6c84SAndroid Build Coastguard Worker case S_IFCHR: strcpy(fi->type, "CHR"); break;
254*cf5a6c84SAndroid Build Coastguard Worker case S_IFDIR: strcpy(fi->type, "DIR"); break;
255*cf5a6c84SAndroid Build Coastguard Worker case S_IFIFO: strcpy(fi->type, "FIFO"); break;
256*cf5a6c84SAndroid Build Coastguard Worker case S_IFLNK: strcpy(fi->type, "LINK"); break;
257*cf5a6c84SAndroid Build Coastguard Worker case S_IFREG: strcpy(fi->type, "REG"); break;
258*cf5a6c84SAndroid Build Coastguard Worker case S_IFSOCK: strcpy(fi->type, "sock"); break;
259*cf5a6c84SAndroid Build Coastguard Worker default:
260*cf5a6c84SAndroid Build Coastguard Worker snprintf(fi->type, sizeof(fi->type), "%04o", sb.st_mode & S_IFMT);
261*cf5a6c84SAndroid Build Coastguard Worker break;
262*cf5a6c84SAndroid Build Coastguard Worker }
263*cf5a6c84SAndroid Build Coastguard Worker
264*cf5a6c84SAndroid Build Coastguard Worker if (S_ISSOCK(sb.st_mode)) find_socket(fi, sb.st_ino);
265*cf5a6c84SAndroid Build Coastguard Worker
266*cf5a6c84SAndroid Build Coastguard Worker // Fill DEVICE.
267*cf5a6c84SAndroid Build Coastguard Worker dev = (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) ? sb.st_rdev : sb.st_dev;
268*cf5a6c84SAndroid Build Coastguard Worker if (!S_ISSOCK(sb.st_mode))
269*cf5a6c84SAndroid Build Coastguard Worker snprintf(fi->device, sizeof(fi->device), "%d,%d",
270*cf5a6c84SAndroid Build Coastguard Worker dev_major(dev), dev_minor(dev));
271*cf5a6c84SAndroid Build Coastguard Worker
272*cf5a6c84SAndroid Build Coastguard Worker // Fill SIZE/OFF.
273*cf5a6c84SAndroid Build Coastguard Worker if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
274*cf5a6c84SAndroid Build Coastguard Worker snprintf(fi->size_off, sizeof(fi->size_off), "%lld",
275*cf5a6c84SAndroid Build Coastguard Worker (long long)sb.st_size);
276*cf5a6c84SAndroid Build Coastguard Worker
277*cf5a6c84SAndroid Build Coastguard Worker // Fill NODE.
278*cf5a6c84SAndroid Build Coastguard Worker snprintf(fi->node, sizeof(fi->node), "%ld", (long)sb.st_ino);
279*cf5a6c84SAndroid Build Coastguard Worker
280*cf5a6c84SAndroid Build Coastguard Worker // Stash st_dev and st_ino for filtering.
281*cf5a6c84SAndroid Build Coastguard Worker fi->di.dev = sb.st_dev;
282*cf5a6c84SAndroid Build Coastguard Worker fi->di.ino = sb.st_ino;
283*cf5a6c84SAndroid Build Coastguard Worker }
284*cf5a6c84SAndroid Build Coastguard Worker
new_file_info(struct proc_info * pi,const char * fd)285*cf5a6c84SAndroid Build Coastguard Worker struct file_info *new_file_info(struct proc_info *pi, const char *fd)
286*cf5a6c84SAndroid Build Coastguard Worker {
287*cf5a6c84SAndroid Build Coastguard Worker struct file_info *fi = xzalloc(sizeof(struct file_info));
288*cf5a6c84SAndroid Build Coastguard Worker
289*cf5a6c84SAndroid Build Coastguard Worker dlist_add_nomalloc(&TT.files, (struct double_list *)fi);
290*cf5a6c84SAndroid Build Coastguard Worker
291*cf5a6c84SAndroid Build Coastguard Worker fi->pi = *pi;
292*cf5a6c84SAndroid Build Coastguard Worker
293*cf5a6c84SAndroid Build Coastguard Worker // Defaults.
294*cf5a6c84SAndroid Build Coastguard Worker strcpy(fi->fd, fd);
295*cf5a6c84SAndroid Build Coastguard Worker strcpy(fi->type, "unknown");
296*cf5a6c84SAndroid Build Coastguard Worker fi->rw = fi->locks = ' ';
297*cf5a6c84SAndroid Build Coastguard Worker
298*cf5a6c84SAndroid Build Coastguard Worker return fi;
299*cf5a6c84SAndroid Build Coastguard Worker }
300*cf5a6c84SAndroid Build Coastguard Worker
visit_symlink(struct proc_info * pi,char * name,char * path)301*cf5a6c84SAndroid Build Coastguard Worker static void visit_symlink(struct proc_info *pi, char *name, char *path)
302*cf5a6c84SAndroid Build Coastguard Worker {
303*cf5a6c84SAndroid Build Coastguard Worker struct file_info *fi = new_file_info(pi, "");
304*cf5a6c84SAndroid Build Coastguard Worker
305*cf5a6c84SAndroid Build Coastguard Worker // Get NAME.
306*cf5a6c84SAndroid Build Coastguard Worker if (name) { // "/proc/pid/[cwd]".
307*cf5a6c84SAndroid Build Coastguard Worker snprintf(fi->fd, sizeof(fi->fd), "%s", name);
308*cf5a6c84SAndroid Build Coastguard Worker snprintf(toybuf, sizeof(toybuf), "/proc/%d/%s", pi->pid, path);
309*cf5a6c84SAndroid Build Coastguard Worker } else { // "/proc/pid/fd/[3]"
310*cf5a6c84SAndroid Build Coastguard Worker snprintf(fi->fd, sizeof(fi->fd), "%s", path);
311*cf5a6c84SAndroid Build Coastguard Worker fill_flags(fi); // Clobbers toybuf.
312*cf5a6c84SAndroid Build Coastguard Worker snprintf(toybuf, sizeof(toybuf), "/proc/%d/fd/%s", pi->pid, path);
313*cf5a6c84SAndroid Build Coastguard Worker }
314*cf5a6c84SAndroid Build Coastguard Worker // TODO: code called by fill_stat would be easier to write if we didn't
315*cf5a6c84SAndroid Build Coastguard Worker // rely on toybuf being preserved here.
316*cf5a6c84SAndroid Build Coastguard Worker fill_stat(fi, toybuf);
317*cf5a6c84SAndroid Build Coastguard Worker if (!fi->name) { // We already have a name for things like sockets.
318*cf5a6c84SAndroid Build Coastguard Worker fi->name = xreadlink(toybuf);
319*cf5a6c84SAndroid Build Coastguard Worker if (!fi->name) {
320*cf5a6c84SAndroid Build Coastguard Worker fi->name = xmprintf("%s (readlink: %s)", toybuf, strerror(errno));
321*cf5a6c84SAndroid Build Coastguard Worker }
322*cf5a6c84SAndroid Build Coastguard Worker }
323*cf5a6c84SAndroid Build Coastguard Worker }
324*cf5a6c84SAndroid Build Coastguard Worker
visit_maps(struct proc_info * pi)325*cf5a6c84SAndroid Build Coastguard Worker static void visit_maps(struct proc_info *pi)
326*cf5a6c84SAndroid Build Coastguard Worker {
327*cf5a6c84SAndroid Build Coastguard Worker FILE *fp;
328*cf5a6c84SAndroid Build Coastguard Worker unsigned long long offset;
329*cf5a6c84SAndroid Build Coastguard Worker long inode;
330*cf5a6c84SAndroid Build Coastguard Worker char *line = NULL, device[10]; // xxx:xxxxx\0
331*cf5a6c84SAndroid Build Coastguard Worker size_t line_length = 0;
332*cf5a6c84SAndroid Build Coastguard Worker struct file_info *fi;
333*cf5a6c84SAndroid Build Coastguard Worker
334*cf5a6c84SAndroid Build Coastguard Worker snprintf(toybuf, sizeof(toybuf), "/proc/%d/maps", pi->pid);
335*cf5a6c84SAndroid Build Coastguard Worker fp = fopen(toybuf, "r");
336*cf5a6c84SAndroid Build Coastguard Worker if (!fp) return;
337*cf5a6c84SAndroid Build Coastguard Worker
338*cf5a6c84SAndroid Build Coastguard Worker while (getline(&line, &line_length, fp) > 0) {
339*cf5a6c84SAndroid Build Coastguard Worker int name_pos;
340*cf5a6c84SAndroid Build Coastguard Worker
341*cf5a6c84SAndroid Build Coastguard Worker if (sscanf(line, "%*x-%*x %*s %llx %9s %ld %n",
342*cf5a6c84SAndroid Build Coastguard Worker &offset, device, &inode, &name_pos) >= 3) {
343*cf5a6c84SAndroid Build Coastguard Worker // Ignore non-file maps.
344*cf5a6c84SAndroid Build Coastguard Worker if (inode == 0 || !strcmp(device, "00:00")) continue;
345*cf5a6c84SAndroid Build Coastguard Worker // TODO: show unique maps even if they have a non-zero offset?
346*cf5a6c84SAndroid Build Coastguard Worker if (offset != 0) continue;
347*cf5a6c84SAndroid Build Coastguard Worker
348*cf5a6c84SAndroid Build Coastguard Worker fi = new_file_info(pi, "mem");
349*cf5a6c84SAndroid Build Coastguard Worker fi->name = strdup(chomp(line + name_pos));
350*cf5a6c84SAndroid Build Coastguard Worker fill_stat(fi, fi->name);
351*cf5a6c84SAndroid Build Coastguard Worker }
352*cf5a6c84SAndroid Build Coastguard Worker }
353*cf5a6c84SAndroid Build Coastguard Worker free(line);
354*cf5a6c84SAndroid Build Coastguard Worker fclose(fp);
355*cf5a6c84SAndroid Build Coastguard Worker }
356*cf5a6c84SAndroid Build Coastguard Worker
visit_fds(struct proc_info * pi)357*cf5a6c84SAndroid Build Coastguard Worker static void visit_fds(struct proc_info *pi)
358*cf5a6c84SAndroid Build Coastguard Worker {
359*cf5a6c84SAndroid Build Coastguard Worker DIR *dir;
360*cf5a6c84SAndroid Build Coastguard Worker struct dirent *de;
361*cf5a6c84SAndroid Build Coastguard Worker
362*cf5a6c84SAndroid Build Coastguard Worker snprintf(toybuf, sizeof(toybuf), "/proc/%d/fd", pi->pid);
363*cf5a6c84SAndroid Build Coastguard Worker if (!(dir = opendir(toybuf))) {
364*cf5a6c84SAndroid Build Coastguard Worker struct file_info *fi = new_file_info(pi, "NOFD");
365*cf5a6c84SAndroid Build Coastguard Worker
366*cf5a6c84SAndroid Build Coastguard Worker fi->name = xmprintf("%s (opendir: %s)", toybuf, strerror(errno));
367*cf5a6c84SAndroid Build Coastguard Worker return;
368*cf5a6c84SAndroid Build Coastguard Worker }
369*cf5a6c84SAndroid Build Coastguard Worker
370*cf5a6c84SAndroid Build Coastguard Worker while ((de = readdir(dir))) {
371*cf5a6c84SAndroid Build Coastguard Worker if (*de->d_name == '.') continue;
372*cf5a6c84SAndroid Build Coastguard Worker visit_symlink(pi, NULL, de->d_name);
373*cf5a6c84SAndroid Build Coastguard Worker }
374*cf5a6c84SAndroid Build Coastguard Worker
375*cf5a6c84SAndroid Build Coastguard Worker closedir(dir);
376*cf5a6c84SAndroid Build Coastguard Worker }
377*cf5a6c84SAndroid Build Coastguard Worker
lsof_pid(int pid,struct stat * st)378*cf5a6c84SAndroid Build Coastguard Worker static void lsof_pid(int pid, struct stat *st)
379*cf5a6c84SAndroid Build Coastguard Worker {
380*cf5a6c84SAndroid Build Coastguard Worker struct proc_info pi;
381*cf5a6c84SAndroid Build Coastguard Worker struct stat sb;
382*cf5a6c84SAndroid Build Coastguard Worker char *s;
383*cf5a6c84SAndroid Build Coastguard Worker
384*cf5a6c84SAndroid Build Coastguard Worker pi.pid = pid;
385*cf5a6c84SAndroid Build Coastguard Worker
386*cf5a6c84SAndroid Build Coastguard Worker // Skip nonexistent pids
387*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "/proc/%d/stat", pid);
388*cf5a6c84SAndroid Build Coastguard Worker if (!readfile(toybuf, toybuf, sizeof(toybuf)-1) || !(s = strchr(toybuf, '(')))
389*cf5a6c84SAndroid Build Coastguard Worker return;
390*cf5a6c84SAndroid Build Coastguard Worker memcpy(pi.cmd, s+1, sizeof(pi.cmd)-1);
391*cf5a6c84SAndroid Build Coastguard Worker pi.cmd[sizeof(pi.cmd)-1] = 0;
392*cf5a6c84SAndroid Build Coastguard Worker if ((s = strrchr(pi.cmd, ')'))) *s = 0;
393*cf5a6c84SAndroid Build Coastguard Worker
394*cf5a6c84SAndroid Build Coastguard Worker // Get USER.
395*cf5a6c84SAndroid Build Coastguard Worker if (!st) {
396*cf5a6c84SAndroid Build Coastguard Worker snprintf(toybuf, sizeof(toybuf), "/proc/%d", pid);
397*cf5a6c84SAndroid Build Coastguard Worker if (stat(toybuf, st = &sb)) return;
398*cf5a6c84SAndroid Build Coastguard Worker }
399*cf5a6c84SAndroid Build Coastguard Worker pi.uid = st->st_uid;
400*cf5a6c84SAndroid Build Coastguard Worker
401*cf5a6c84SAndroid Build Coastguard Worker visit_symlink(&pi, "cwd", "cwd");
402*cf5a6c84SAndroid Build Coastguard Worker visit_symlink(&pi, "rtd", "root");
403*cf5a6c84SAndroid Build Coastguard Worker visit_symlink(&pi, "txt", "exe");
404*cf5a6c84SAndroid Build Coastguard Worker visit_maps(&pi);
405*cf5a6c84SAndroid Build Coastguard Worker visit_fds(&pi);
406*cf5a6c84SAndroid Build Coastguard Worker }
407*cf5a6c84SAndroid Build Coastguard Worker
scan_proc(struct dirtree * node)408*cf5a6c84SAndroid Build Coastguard Worker static int scan_proc(struct dirtree *node)
409*cf5a6c84SAndroid Build Coastguard Worker {
410*cf5a6c84SAndroid Build Coastguard Worker int pid;
411*cf5a6c84SAndroid Build Coastguard Worker
412*cf5a6c84SAndroid Build Coastguard Worker if (!node->parent) return DIRTREE_RECURSE|DIRTREE_SHUTUP;
413*cf5a6c84SAndroid Build Coastguard Worker if ((pid = atol(node->name))) lsof_pid(pid, &node->st);
414*cf5a6c84SAndroid Build Coastguard Worker
415*cf5a6c84SAndroid Build Coastguard Worker return 0;
416*cf5a6c84SAndroid Build Coastguard Worker }
417*cf5a6c84SAndroid Build Coastguard Worker
lsof_main(void)418*cf5a6c84SAndroid Build Coastguard Worker void lsof_main(void)
419*cf5a6c84SAndroid Build Coastguard Worker {
420*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *pp;
421*cf5a6c84SAndroid Build Coastguard Worker int i, pid;
422*cf5a6c84SAndroid Build Coastguard Worker
423*cf5a6c84SAndroid Build Coastguard Worker // lsof will only filter on paths it can stat (because it filters by inode).
424*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc) {
425*cf5a6c84SAndroid Build Coastguard Worker TT.sought_files = xmalloc(toys.optc*sizeof(struct stat));
426*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<toys.optc; ++i) xstat(toys.optargs[i], TT.sought_files+i);
427*cf5a6c84SAndroid Build Coastguard Worker }
428*cf5a6c84SAndroid Build Coastguard Worker
429*cf5a6c84SAndroid Build Coastguard Worker if (!TT.p) dirtree_read("/proc", scan_proc);
430*cf5a6c84SAndroid Build Coastguard Worker else for (pp = TT.p; pp; pp = pp->next) {
431*cf5a6c84SAndroid Build Coastguard Worker char *start, *end, *next = pp->arg;
432*cf5a6c84SAndroid Build Coastguard Worker
433*cf5a6c84SAndroid Build Coastguard Worker while ((start = comma_iterate(&next, &i))) {
434*cf5a6c84SAndroid Build Coastguard Worker if ((pid = strtol(start, &end, 10))<1 || (*end && *end!=','))
435*cf5a6c84SAndroid Build Coastguard Worker error_msg("bad -p '%.*s'", (int)(end-start), start);
436*cf5a6c84SAndroid Build Coastguard Worker lsof_pid(pid, 0);
437*cf5a6c84SAndroid Build Coastguard Worker }
438*cf5a6c84SAndroid Build Coastguard Worker }
439*cf5a6c84SAndroid Build Coastguard Worker
440*cf5a6c84SAndroid Build Coastguard Worker llist_traverse(TT.files, print_info);
441*cf5a6c84SAndroid Build Coastguard Worker
442*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) {
443*cf5a6c84SAndroid Build Coastguard Worker llist_traverse(TT.files, free_info);
444*cf5a6c84SAndroid Build Coastguard Worker llist_traverse(TT.all_sockets, free_info);
445*cf5a6c84SAndroid Build Coastguard Worker }
446*cf5a6c84SAndroid Build Coastguard Worker }
447