procps.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Utility routines.
  4. *
  5. * Copyright 1998 by Albert Cahalan; all rights reserved.
  6. * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>
  7. *
  8. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  9. */
  10. #include "libbb.h"
  11. typedef struct unsigned_to_name_map_t {
  12. unsigned id;
  13. char name[12];
  14. } unsigned_to_name_map_t;
  15. typedef struct cache_t {
  16. unsigned_to_name_map_t *cache;
  17. int size;
  18. } cache_t;
  19. static cache_t username, groupname;
  20. static void clear_cache(cache_t *cp)
  21. {
  22. free(cp->cache);
  23. cp->cache = NULL;
  24. cp->size = 0;
  25. }
  26. void clear_username_cache(void)
  27. {
  28. clear_cache(&username);
  29. clear_cache(&groupname);
  30. }
  31. #if 0 /* more generic, but we don't need that yet */
  32. /* Returns -N-1 if not found. */
  33. /* cp->cache[N] is allocated and must be filled in this case */
  34. static int get_cached(cache_t *cp, unsigned id)
  35. {
  36. int i;
  37. for (i = 0; i < cp->size; i++)
  38. if (cp->cache[i].id == id)
  39. return i;
  40. i = cp->size++;
  41. cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
  42. cp->cache[i++].id = id;
  43. return -i;
  44. }
  45. #endif
  46. typedef char* ug_func(char *name, long uid, int bufsize);
  47. static char* get_cached(cache_t *cp, unsigned id, ug_func* fp)
  48. {
  49. int i;
  50. for (i = 0; i < cp->size; i++)
  51. if (cp->cache[i].id == id)
  52. return cp->cache[i].name;
  53. i = cp->size++;
  54. cp->cache = xrealloc(cp->cache, cp->size * sizeof(*cp->cache));
  55. cp->cache[i].id = id;
  56. fp(cp->cache[i].name, id, sizeof(cp->cache[i].name));
  57. return cp->cache[i].name;
  58. }
  59. const char* get_cached_username(uid_t uid)
  60. {
  61. return get_cached(&username, uid, bb_getpwuid);
  62. }
  63. const char* get_cached_groupname(gid_t gid)
  64. {
  65. return get_cached(&groupname, gid, bb_getgrgid);
  66. }
  67. #define PROCPS_BUFSIZE 1024
  68. static int read_to_buf(const char *filename, void *buf)
  69. {
  70. ssize_t ret;
  71. ret = open_read_close(filename, buf, PROCPS_BUFSIZE-1);
  72. ((char *)buf)[ret > 0 ? ret : 0] = '\0';
  73. return ret;
  74. }
  75. procps_status_t* alloc_procps_scan(int flags)
  76. {
  77. procps_status_t* sp = xzalloc(sizeof(procps_status_t));
  78. sp->dir = xopendir("/proc");
  79. return sp;
  80. }
  81. void free_procps_scan(procps_status_t* sp)
  82. {
  83. closedir(sp->dir);
  84. free(sp->cmd);
  85. free(sp);
  86. }
  87. void BUG_comm_size(void);
  88. procps_status_t* procps_scan(procps_status_t* sp, int flags)
  89. {
  90. struct dirent *entry;
  91. char buf[PROCPS_BUFSIZE];
  92. char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
  93. char *filename_tail;
  94. long tasknice;
  95. unsigned pid;
  96. int n;
  97. struct stat sb;
  98. if (!sp)
  99. sp = alloc_procps_scan(flags);
  100. for (;;) {
  101. entry = readdir(sp->dir);
  102. if (entry == NULL) {
  103. free_procps_scan(sp);
  104. return NULL;
  105. }
  106. pid = bb_strtou(entry->d_name, NULL, 10);
  107. if (errno)
  108. continue;
  109. /* After this point we have to break, not continue
  110. * ("continue" would mean that current /proc/NNN
  111. * is not a valid process info) */
  112. memset(&sp->rss, 0, sizeof(*sp) - offsetof(procps_status_t, rss));
  113. sp->pid = pid;
  114. if (!(flags & ~PSSCAN_PID)) break;
  115. filename_tail = filename + sprintf(filename, "/proc/%d", pid);
  116. if (flags & PSSCAN_UIDGID) {
  117. if (stat(filename, &sb))
  118. break;
  119. /* Need comment - is this effective or read UID/GID? */
  120. sp->uid = sb.st_uid;
  121. sp->gid = sb.st_gid;
  122. }
  123. if (flags & PSSCAN_STAT) {
  124. char *cp;
  125. /* see proc(5) for some details on this */
  126. strcpy(filename_tail, "/stat");
  127. n = read_to_buf(filename, buf);
  128. if (n < 0)
  129. break;
  130. cp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
  131. if (!cp || cp[1] != ' ')
  132. break;
  133. cp[0] = '\0';
  134. if (sizeof(sp->comm) < 16)
  135. BUG_comm_size();
  136. sscanf(buf, "%*s (%15c", sp->comm);
  137. n = sscanf(cp+2,
  138. "%c %u " /* state, ppid */
  139. "%u %u %*s %*s " /* pgid, sid, tty, tpgid */
  140. "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
  141. "%lu %lu " /* utime, stime */
  142. "%*s %*s %*s " /* cutime, cstime, priority */
  143. "%ld " /* nice */
  144. "%*s %*s %*s " /* timeout, it_real_value, start_time */
  145. "%*s " /* vsize */
  146. "%lu", /* rss */
  147. sp->state, &sp->ppid,
  148. &sp->pgid, &sp->sid,
  149. &sp->utime, &sp->stime,
  150. &tasknice,
  151. &sp->rss);
  152. if (n != 8)
  153. break;
  154. if (sp->rss == 0 && sp->state[0] != 'Z')
  155. sp->state[1] = 'W';
  156. else
  157. sp->state[1] = ' ';
  158. if (tasknice < 0)
  159. sp->state[2] = '<';
  160. else if (tasknice > 0)
  161. sp->state[2] = 'N';
  162. else
  163. sp->state[2] = ' ';
  164. #ifdef PAGE_SHIFT
  165. sp->rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */
  166. #else
  167. sp->rss *= (getpagesize() >> 10); /* 2**10 = 1kb */
  168. #endif
  169. }
  170. if (flags & PSSCAN_CMD) {
  171. free(sp->cmd);
  172. sp->cmd = NULL;
  173. strcpy(filename_tail, "/cmdline");
  174. n = read_to_buf(filename, buf);
  175. if (n <= 0)
  176. break;
  177. if (buf[n-1] == '\n') {
  178. if (!--n)
  179. break;
  180. buf[n] = '\0';
  181. }
  182. do {
  183. n--;
  184. if ((unsigned char)(buf[n]) < ' ')
  185. buf[n] = ' ';
  186. } while (n);
  187. sp->cmd = strdup(buf);
  188. }
  189. break;
  190. }
  191. return sp;
  192. }
  193. /* from kernel:
  194. // pid comm S ppid pgid sid tty_nr tty_pgrp flg
  195. sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
  196. %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
  197. %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n",
  198. task->pid,
  199. tcomm,
  200. state,
  201. ppid,
  202. pgid,
  203. sid,
  204. tty_nr,
  205. tty_pgrp,
  206. task->flags,
  207. min_flt,
  208. cmin_flt,
  209. maj_flt,
  210. cmaj_flt,
  211. cputime_to_clock_t(utime),
  212. cputime_to_clock_t(stime),
  213. cputime_to_clock_t(cutime),
  214. cputime_to_clock_t(cstime),
  215. priority,
  216. nice,
  217. num_threads,
  218. // 0,
  219. start_time,
  220. vsize,
  221. mm ? get_mm_rss(mm) : 0,
  222. rsslim,
  223. mm ? mm->start_code : 0,
  224. mm ? mm->end_code : 0,
  225. mm ? mm->start_stack : 0,
  226. esp,
  227. eip,
  228. the rest is some obsolete cruft
  229. */