lsof.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright (c) 2010, The Android Open Source Project
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google, Inc. nor the names of its contributors
  15. * may be used to endorse or promote products derived from this
  16. * software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  22. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  24. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  25. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  26. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  27. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  28. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. */
  31. #include <dirent.h>
  32. #include <errno.h>
  33. #include <fcntl.h>
  34. #include <libgen.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <unistd.h>
  39. #include <pwd.h>
  40. #include <sys/stat.h>
  41. #define BUF_MAX 1024
  42. #define CMD_DISPLAY_MAX (9 + 1)
  43. #define USER_DISPLAY_MAX (10 + 1)
  44. struct pid_info_t {
  45. pid_t pid;
  46. char user[USER_DISPLAY_MAX];
  47. char cmdline[CMD_DISPLAY_MAX];
  48. char path[PATH_MAX];
  49. ssize_t parent_length;
  50. };
  51. static void print_header()
  52. {
  53. printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n",
  54. "COMMAND",
  55. "PID",
  56. "USER",
  57. "FD",
  58. "TYPE",
  59. "DEVICE",
  60. "SIZE/OFF",
  61. "NODE",
  62. "NAME");
  63. }
  64. static void print_type(char *type, struct pid_info_t* info)
  65. {
  66. static ssize_t link_dest_size;
  67. static char link_dest[PATH_MAX + 64];
  68. strlcat(info->path, type, sizeof(info->path));
  69. if ((link_dest_size = readlink(info->path, link_dest, sizeof(link_dest)-1)) < 0) {
  70. if (errno == ENOENT)
  71. goto out;
  72. snprintf(link_dest, sizeof(link_dest), "%s (readlink: %s)", info->path, strerror(errno));
  73. } else {
  74. link_dest[link_dest_size] = '\0';
  75. }
  76. // Things that are just the root filesystem are uninteresting (we already know)
  77. if (!strcmp(link_dest, "/"))
  78. goto out;
  79. printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
  80. info->cmdline, info->pid, info->user, type,
  81. "???", "???", "???", "???", link_dest);
  82. out:
  83. info->path[info->parent_length] = '\0';
  84. }
  85. // Prints out all file that have been memory mapped
  86. static void print_maps(struct pid_info_t* info)
  87. {
  88. FILE *maps;
  89. size_t offset;
  90. char device[10];
  91. long int inode;
  92. char file[PATH_MAX];
  93. strlcat(info->path, "maps", sizeof(info->path));
  94. maps = fopen(info->path, "r");
  95. if (!maps)
  96. goto out;
  97. while (fscanf(maps, "%*x-%*x %*s %zx %5s %ld %s\n", &offset, device, &inode,
  98. file) == 4) {
  99. // We don't care about non-file maps
  100. if (inode == 0 || !strcmp(device, "00:00"))
  101. continue;
  102. printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n",
  103. info->cmdline, info->pid, info->user, "mem",
  104. "???", device, offset, inode, file);
  105. }
  106. fclose(maps);
  107. out:
  108. info->path[info->parent_length] = '\0';
  109. }
  110. // Prints out all open file descriptors
  111. static void print_fds(struct pid_info_t* info)
  112. {
  113. static char* fd_path = "fd/";
  114. strlcat(info->path, fd_path, sizeof(info->path));
  115. int previous_length = info->parent_length;
  116. info->parent_length += strlen(fd_path);
  117. DIR *dir = opendir(info->path);
  118. if (dir == NULL) {
  119. char msg[PATH_MAX + 64];
  120. snprintf(msg, sizeof(msg), "%s (opendir: %s)", info->path, strerror(errno));
  121. printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
  122. info->cmdline, info->pid, info->user, "FDS",
  123. "", "", "", "", msg);
  124. goto out;
  125. }
  126. struct dirent* de;
  127. while ((de = readdir(dir))) {
  128. if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
  129. continue;
  130. print_type(de->d_name, info);
  131. }
  132. closedir(dir);
  133. out:
  134. info->parent_length = previous_length;
  135. info->path[info->parent_length] = '\0';
  136. }
  137. static void lsof_dumpinfo(pid_t pid)
  138. {
  139. int fd;
  140. struct pid_info_t info;
  141. struct stat pidstat;
  142. struct passwd *pw;
  143. info.pid = pid;
  144. snprintf(info.path, sizeof(info.path), "/proc/%d/", pid);
  145. info.parent_length = strlen(info.path);
  146. // Get the UID by calling stat on the proc/pid directory.
  147. if (!stat(info.path, &pidstat)) {
  148. pw = getpwuid(pidstat.st_uid);
  149. if (pw) {
  150. strlcpy(info.user, pw->pw_name, sizeof(info.user));
  151. } else {
  152. snprintf(info.user, USER_DISPLAY_MAX, "%d", (int)pidstat.st_uid);
  153. }
  154. } else {
  155. strcpy(info.user, "???");
  156. }
  157. // Read the command line information; each argument is terminated with NULL.
  158. strlcat(info.path, "cmdline", sizeof(info.path));
  159. fd = open(info.path, O_RDONLY);
  160. if (fd < 0) {
  161. fprintf(stderr, "Couldn't read %s\n", info.path);
  162. return;
  163. }
  164. char cmdline[PATH_MAX];
  165. int numRead = read(fd, cmdline, sizeof(cmdline) - 1);
  166. close(fd);
  167. if (numRead < 0) {
  168. fprintf(stderr, "Error reading cmdline: %s: %s\n", info.path, strerror(errno));
  169. return;
  170. }
  171. cmdline[numRead] = '\0';
  172. // We only want the basename of the cmdline
  173. strlcpy(info.cmdline, basename(cmdline), sizeof(info.cmdline));
  174. // Read each of these symlinks
  175. print_type("cwd", &info);
  176. print_type("exe", &info);
  177. print_type("root", &info);
  178. print_fds(&info);
  179. print_maps(&info);
  180. }
  181. int main(int argc, char *argv[])
  182. {
  183. long int pid = 0;
  184. char* endptr;
  185. if (argc == 2) {
  186. pid = strtol(argv[1], &endptr, 10);
  187. }
  188. print_header();
  189. if (pid) {
  190. lsof_dumpinfo(pid);
  191. } else {
  192. DIR *dir = opendir("/proc");
  193. if (dir == NULL) {
  194. fprintf(stderr, "Couldn't open /proc\n");
  195. return -1;
  196. }
  197. struct dirent* de;
  198. while ((de = readdir(dir))) {
  199. if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
  200. continue;
  201. // Only inspect directories that are PID numbers
  202. pid = strtol(de->d_name, &endptr, 10);
  203. if (*endptr != '\0')
  204. continue;
  205. lsof_dumpinfo(pid);
  206. }
  207. closedir(dir);
  208. }
  209. return 0;
  210. }