ps.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2013-2018 K. Lange
  5. *
  6. * ps
  7. *
  8. * print a list of running processes
  9. */
  10. #include <sys/stat.h>
  11. #include <fcntl.h>
  12. #include <stdint.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <unistd.h>
  17. #include <dirent.h>
  18. #include <pwd.h>
  19. #include <toaru/list.h>
  20. #define LINE_LEN 4096
  21. static int show_all = 0;
  22. static int show_threads = 0;
  23. static int show_username = 0;
  24. static int show_mem = 0;
  25. static int collect_commandline = 0;
  26. static int widths[] = {3,3,4,3,3,4};
  27. struct process {
  28. int uid;
  29. int pid;
  30. int tid;
  31. int mem;
  32. int vsz;
  33. int shm;
  34. char * process;
  35. char * command_line;
  36. };
  37. void print_username(int uid) {
  38. struct passwd * p = getpwuid(uid);
  39. if (p) {
  40. printf("%-8s", p->pw_name);
  41. } else {
  42. printf("%-8d", uid);
  43. }
  44. endpwent();
  45. }
  46. struct process * process_entry(struct dirent *dent) {
  47. char tmp[256];
  48. FILE * f;
  49. char line[LINE_LEN];
  50. int pid = 0, uid = 0, tgid = 0, mem = 0, shm = 0, vsz = 0;
  51. char name[100];
  52. sprintf(tmp, "/proc/%s/status", dent->d_name);
  53. f = fopen(tmp, "r");
  54. if (!f) {
  55. return NULL;
  56. }
  57. line[0] = 0;
  58. while (fgets(line, LINE_LEN, f) != NULL) {
  59. char * n = strstr(line,"\n");
  60. if (n) { *n = '\0'; }
  61. char * tab = strstr(line,"\t");
  62. if (tab) {
  63. *tab = '\0';
  64. tab++;
  65. }
  66. if (strstr(line, "Pid:") == line) {
  67. pid = atoi(tab);
  68. } else if (strstr(line, "Uid:") == line) {
  69. uid = atoi(tab);
  70. } else if (strstr(line, "Tgid:") == line) {
  71. tgid = atoi(tab);
  72. } else if (strstr(line, "Name:") == line) {
  73. strcpy(name, tab);
  74. } else if (strstr(line, "VmSize:") == line) {
  75. vsz = atoi(tab);
  76. } else if (strstr(line, "RssShmem:") == line) {
  77. shm = atoi(tab);
  78. } else if (strstr(line, "MemPermille:") == line) {
  79. mem = atoi(tab);
  80. }
  81. }
  82. fclose(f);
  83. if (!show_all) {
  84. /* Filter not ours */
  85. if (uid != getuid()) return NULL;
  86. }
  87. if (!show_threads) {
  88. if (tgid != pid) return NULL;
  89. }
  90. struct process * out = malloc(sizeof(struct process));
  91. out->uid = uid;
  92. out->pid = tgid;
  93. out->tid = pid;
  94. out->mem = mem;
  95. out->shm = shm;
  96. out->vsz = vsz;
  97. out->process = strdup(name);
  98. out->command_line = NULL;
  99. char garbage[1024];
  100. int len;
  101. if ((len = sprintf(garbage, "%d", out->pid)) > widths[0]) widths[0] = len;
  102. if ((len = sprintf(garbage, "%d", out->tid)) > widths[1]) widths[1] = len;
  103. if ((len = sprintf(garbage, "%d", out->vsz)) > widths[3]) widths[3] = len;
  104. if ((len = sprintf(garbage, "%d", out->shm)) > widths[4]) widths[4] = len;
  105. if ((len = sprintf(garbage, "%d.%01d", out->mem / 10, out->mem % 10)) > widths[5]) widths[5] = len;
  106. struct passwd * p = getpwuid(out->uid);
  107. if (p) {
  108. if ((len = strlen(p->pw_name)) > widths[2]) widths[2] = len;
  109. } else {
  110. if ((len = sprintf(garbage, "%d", out->uid)) > widths[2]) widths[2] = len;
  111. }
  112. endpwent();
  113. if (collect_commandline) {
  114. sprintf(tmp, "/proc/%s/cmdline", dent->d_name);
  115. f = fopen(tmp, "r");
  116. char foo[1024];
  117. int s = fread(foo, 1, 1024, f);
  118. if (s > 0) {
  119. out->command_line = malloc(s + 1);
  120. memset(out->command_line, 0, s + 1);
  121. memcpy(out->command_line, foo, s);
  122. for (int i = 0; i < s; ++i) {
  123. if (out->command_line[i] == 30) {
  124. out->command_line[i] = ' ';
  125. }
  126. }
  127. }
  128. fclose(f);
  129. }
  130. return out;
  131. }
  132. void print_header(void) {
  133. if (show_username) {
  134. printf("%-*s ", widths[2], "USER");
  135. }
  136. printf("%*s ", widths[0], "PID");
  137. if (show_threads) {
  138. printf("%*s ", widths[1], "TID");
  139. }
  140. if (show_mem) {
  141. printf("%*s ", widths[5], "MEM%");
  142. printf("%*s ", widths[3], "VSZ");
  143. printf("%*s ", widths[4], "SHM");
  144. }
  145. printf("CMD\n");
  146. }
  147. void print_entry(struct process * out) {
  148. if (show_username) {
  149. struct passwd * p = getpwuid(out->uid);
  150. if (p) {
  151. printf("%-*s ", widths[2], p->pw_name);
  152. } else {
  153. printf("%-*d ", widths[2], out->uid);
  154. }
  155. endpwent();
  156. }
  157. printf("%*d ", widths[0], out->pid);
  158. if (show_threads) {
  159. printf("%*d ", widths[1], out->tid);
  160. }
  161. if (show_mem) {
  162. char tmp[6];
  163. sprintf(tmp, "%*d.%01d", widths[5]-2, out->mem / 10, out->mem % 10);
  164. printf("%*s ", widths[5], tmp);
  165. printf("%*d ", widths[3], out->vsz);
  166. printf("%*d ", widths[4], out->shm);
  167. }
  168. if (out->command_line) {
  169. printf("%s\n", out->command_line);
  170. } else {
  171. printf("%s\n", out->process);
  172. }
  173. }
  174. void show_usage(int argc, char * argv[]) {
  175. printf(
  176. "ps - list running processes\n"
  177. "\n"
  178. "usage: %s [-A] [format]\n"
  179. "\n"
  180. " -A \033[3mshow other users' processes\033[0m\n"
  181. " -T \033[3mshow threads\033[0m\n"
  182. " -? \033[3mshow this help text\033[0m\n"
  183. "\n"
  184. " [format] supports some BSD options:\n"
  185. "\n"
  186. " a \033[3mshow full command line\033[0m\n"
  187. " u \033[3muse 'user-oriented' format\033[0m\n"
  188. "\n", argv[0]);
  189. }
  190. int main (int argc, char * argv[]) {
  191. /* Parse arguments */
  192. char c;
  193. while ((c = getopt(argc, argv, "AT?")) != -1) {
  194. switch (c) {
  195. case 'A':
  196. show_all = 1;
  197. break;
  198. case 'T':
  199. show_threads = 1;
  200. break;
  201. case '?':
  202. show_usage(argc, argv);
  203. return 0;
  204. }
  205. }
  206. if (optind < argc) {
  207. char * show = argv[optind];
  208. while (*show) {
  209. switch (*show) {
  210. case 'u':
  211. show_username = 1;
  212. show_mem = 1;
  213. // fallthrough
  214. case 'a':
  215. collect_commandline = 1;
  216. break;
  217. default:
  218. break;
  219. }
  220. show++;
  221. }
  222. }
  223. /* Open the directory */
  224. DIR * dirp = opendir("/proc");
  225. /* Read the entries in the directory */
  226. list_t * ents_list = list_create();
  227. struct dirent * ent = readdir(dirp);
  228. while (ent != NULL) {
  229. if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') {
  230. struct process * p = process_entry(ent);
  231. if (p) {
  232. list_insert(ents_list, (void *)p);
  233. }
  234. }
  235. ent = readdir(dirp);
  236. }
  237. closedir(dirp);
  238. print_header();
  239. foreach(entry, ents_list) {
  240. print_entry(entry->value);
  241. }
  242. return 0;
  243. }
  244. /*
  245. * vim: tabstop=4
  246. * vim: shiftwidth=4
  247. * vim: noexpandtab
  248. */