lsof.c 12 KB

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